2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 this file implements functions for manipulating the 'struct smbsrv_request' structure in smbd
25 #include "smb_server/smb_server.h"
26 #include "smb_server/service_smb_proto.h"
27 #include "smbd/service_stream.h"
28 #include "lib/stream/packet.h"
29 #include "ntvfs/ntvfs.h"
30 #include "param/param.h"
33 /* we over allocate the data buffer to prevent too many realloc calls */
34 #define REQ_OVER_ALLOCATION 0
36 /* setup the bufinfo used for strings and range checking */
37 void smbsrv_setup_bufinfo(struct smbsrv_request *req)
39 req->in.bufinfo.mem_ctx = req;
40 req->in.bufinfo.flags = 0;
41 if (req->flags2 & FLAGS2_UNICODE_STRINGS) {
42 req->in.bufinfo.flags |= BUFINFO_FLAG_UNICODE;
44 req->in.bufinfo.align_base = req->in.buffer;
45 req->in.bufinfo.data = req->in.data;
46 req->in.bufinfo.data_size = req->in.data_size;
50 static int smbsrv_request_destructor(struct smbsrv_request *req)
52 DLIST_REMOVE(req->smb_conn->requests, req);
56 /****************************************************************************
57 construct a basic request packet, mostly used to construct async packets
58 such as change notify and oplock break requests
59 ****************************************************************************/
60 struct smbsrv_request *smbsrv_init_request(struct smbsrv_connection *smb_conn)
62 struct smbsrv_request *req;
64 req = talloc_zero(smb_conn, struct smbsrv_request);
69 /* setup the request context */
70 req->smb_conn = smb_conn;
72 talloc_set_destructor(req, smbsrv_request_destructor);
79 setup a chained reply in req->out with the given word count and initial data buffer size.
81 static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
83 uint32_t chain_base_size = req->out.size;
85 /* we need room for the wct value, the words, the buffer length and the buffer */
86 req->out.size += 1 + VWV(wct) + 2 + buflen;
88 /* over allocate by a small amount */
89 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
91 req->out.buffer = talloc_realloc(req, req->out.buffer,
92 uint8_t, req->out.allocated);
93 if (!req->out.buffer) {
94 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
98 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
99 req->out.vwv = req->out.buffer + chain_base_size + 1;
101 req->out.data = req->out.vwv + VWV(wct) + 2;
102 req->out.data_size = buflen;
103 req->out.ptr = req->out.data;
105 SCVAL(req->out.buffer, chain_base_size, wct);
106 SSVAL(req->out.vwv, VWV(wct), buflen);
111 setup a reply in req->out with the given word count and initial data buffer size.
112 the caller will then fill in the command words and data before calling req_send_reply() to
113 send the reply on its way
115 void smbsrv_setup_reply(struct smbsrv_request *req, uint_t wct, size_t buflen)
119 if (req->chain_count != 0) {
120 req_setup_chain_reply(req, wct, buflen);
124 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + buflen;
126 /* over allocate by a small amount */
127 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
129 req->out.buffer = talloc_size(req, req->out.allocated);
130 if (!req->out.buffer) {
131 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
135 flags2 = FLAGS2_LONG_PATH_COMPONENTS |
136 FLAGS2_EXTENDED_ATTRIBUTES |
138 flags2 |= (req->flags2 & (FLAGS2_UNICODE_STRINGS|FLAGS2_EXTENDED_SECURITY));
139 if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
140 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
143 if (req->smb_conn->signing.allow_smb_signing || req->smb_conn->signing.mandatory_signing) {
144 flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
147 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
148 req->out.vwv = req->out.hdr + HDR_VWV;
150 req->out.data = req->out.vwv + VWV(wct) + 2;
151 req->out.data_size = buflen;
152 req->out.ptr = req->out.data;
154 SIVAL(req->out.hdr, HDR_RCLS, 0);
156 SCVAL(req->out.hdr, HDR_WCT, wct);
157 SSVAL(req->out.vwv, VWV(wct), buflen);
159 memcpy(req->out.hdr, "\377SMB", 4);
160 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
161 SSVAL(req->out.hdr,HDR_FLG2, flags2);
162 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
163 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
166 /* copy the cmd, tid, pid, uid and mid from the request */
167 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
168 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
169 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
170 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
171 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
173 SCVAL(req->out.hdr,HDR_COM,0);
174 SSVAL(req->out.hdr,HDR_TID,0);
175 SSVAL(req->out.hdr,HDR_PID,0);
176 SSVAL(req->out.hdr,HDR_UID,0);
177 SSVAL(req->out.hdr,HDR_MID,0);
183 setup a copy of a request, used when the server needs to send
184 more than one reply for a single request packet
186 struct smbsrv_request *smbsrv_setup_secondary_request(struct smbsrv_request *old_req)
188 struct smbsrv_request *req;
191 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
196 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
197 if (req->out.buffer == NULL) {
202 diff = req->out.buffer - old_req->out.buffer;
204 req->out.hdr += diff;
205 req->out.vwv += diff;
206 req->out.data += diff;
207 req->out.ptr += diff;
213 work out the maximum data size we will allow for this reply, given
214 the negotiated max_xmit. The basic reply packet must be setup before
217 note that this is deliberately a signed integer reply
219 int req_max_data(struct smbsrv_request *req)
222 ret = req->smb_conn->negotiate.max_send;
223 ret -= PTR_DIFF(req->out.data, req->out.hdr);
224 if (ret < 0) ret = 0;
230 grow the allocation of the data buffer portion of a reply
231 packet. Note that as this can reallocate the packet buffer this
232 invalidates any local pointers into the packet.
234 To cope with this req->out.ptr is supplied. This will be updated to
235 point at the same offset into the packet as before this call
237 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
242 delta = new_size - req->out.data_size;
243 if (delta + req->out.size <= req->out.allocated) {
244 /* it fits in the preallocation */
248 /* we need to realloc */
249 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
250 buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
252 smb_panic("out of memory in req_grow_allocation");
255 if (buf2 == req->out.buffer) {
256 /* the malloc library gave us the same pointer */
260 /* update the pointers into the packet */
261 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
262 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
263 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
264 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
266 req->out.buffer = buf2;
271 grow the data buffer portion of a reply packet. Note that as this
272 can reallocate the packet buffer this invalidates any local pointers
275 To cope with this req->out.ptr is supplied. This will be updated to
276 point at the same offset into the packet as before this call
278 void req_grow_data(struct smbsrv_request *req, size_t new_size)
282 if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
283 smb_panic("reply buffer too large!");
286 req_grow_allocation(req, new_size);
288 delta = new_size - req->out.data_size;
290 req->out.size += delta;
291 req->out.data_size += delta;
293 /* set the BCC to the new data size */
294 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
298 send a reply and destroy the request buffer
300 note that this only looks at req->out.buffer and req->out.size, allowing manually
301 constructed packets to be sent
303 void smbsrv_send_reply_nosign(struct smbsrv_request *req)
308 if (req->smb_conn->connection->event.fde == NULL) {
309 /* we are in the process of shutting down this connection */
314 if (req->out.size > NBT_HDR_SIZE) {
315 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
318 blob = data_blob_const(req->out.buffer, req->out.size);
319 status = packet_send(req->smb_conn->packet, blob);
320 if (!NT_STATUS_IS_OK(status)) {
321 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
327 possibly sign a message then send a reply and destroy the request buffer
329 note that this only looks at req->out.buffer and req->out.size, allowing manually
330 constructed packets to be sent
332 void smbsrv_send_reply(struct smbsrv_request *req)
334 if (req->smb_conn->connection->event.fde == NULL) {
335 /* we are in the process of shutting down this connection */
339 smbsrv_sign_packet(req);
341 smbsrv_send_reply_nosign(req);
345 setup the header of a reply to include an NTSTATUS code
347 void smbsrv_setup_error(struct smbsrv_request *req, NTSTATUS status)
349 if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
350 /* convert to DOS error codes */
353 ntstatus_to_dos(status, &eclass, &ecode);
354 SCVAL(req->out.hdr, HDR_RCLS, eclass);
355 SSVAL(req->out.hdr, HDR_ERR, ecode);
356 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
360 if (NT_STATUS_IS_DOS(status)) {
361 /* its a encoded DOS error, using the reserved range */
362 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
363 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
364 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
366 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
367 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
372 construct and send an error packet, then destroy the request
373 auto-converts to DOS error format when appropriate
375 void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status)
377 if (req->smb_conn->connection->event.fde == NULL) {
378 /* the socket has been destroyed - no point trying to send an error! */
382 smbsrv_setup_reply(req, 0, 0);
384 /* error returns never have any data */
385 req_grow_data(req, 0);
387 smbsrv_setup_error(req, status);
388 smbsrv_send_reply(req);
393 push a string into the data portion of the request packet, growing it if necessary
394 this gets quite tricky - please be very careful to cover all cases when modifying this
396 if dest is NULL, then put the string at the end of the data portion of the packet
398 if dest_len is -1 then no limit applies
400 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, size_t flags)
405 const int max_bytes_per_char = 3;
407 if (!(flags & (STR_ASCII|STR_UNICODE))) {
408 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
412 dest = req->out.data + req->out.data_size;
415 if (dest_len != -1) {
418 len = (strlen(str)+2) * max_bytes_per_char;
421 grow_size = len + PTR_DIFF(dest, req->out.data);
422 buf0 = req->out.buffer;
424 req_grow_allocation(req, grow_size);
426 if (buf0 != req->out.buffer) {
427 dest = req->out.buffer + PTR_DIFF(dest, buf0);
430 len = push_string(lp_iconv_convenience(req->smb_conn->lp_ctx), dest, str, len, flags);
432 grow_size = len + PTR_DIFF(dest, req->out.data);
434 if (grow_size > req->out.data_size) {
435 req_grow_data(req, grow_size);
442 append raw bytes into the data portion of the request packet
443 return the number of bytes added
445 size_t req_append_bytes(struct smbsrv_request *req,
446 const uint8_t *bytes, size_t byte_len)
448 req_grow_allocation(req, byte_len + req->out.data_size);
449 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
450 req_grow_data(req, byte_len + req->out.data_size);
454 append variable block (type 5 buffer) into the data portion of the request packet
455 return the number of bytes added
457 size_t req_append_var_block(struct smbsrv_request *req,
458 const uint8_t *bytes, uint16_t byte_len)
460 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
461 SCVAL(req->out.data + req->out.data_size, 0, 5);
462 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
464 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
466 req_grow_data(req, byte_len + 3 + req->out.data_size);
470 pull a UCS2 string from a request packet, returning a talloced unix string
472 the string length is limited by the 3 things:
473 - the data size in the request (end of packet)
474 - the passed 'byte_len' if it is not -1
475 - the end of string (null termination)
477 Note that 'byte_len' is the number of bytes in the packet
479 on failure zero is returned and *dest is set to NULL, otherwise the number
480 of bytes consumed in the packet is returned
482 static size_t req_pull_ucs2(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
484 int src_len, src_len2, alignment=0;
488 if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
491 if (byte_len != -1) {
496 if (flags & STR_NO_RANGE_CHECK) {
499 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
500 if (byte_len != -1 && src_len > byte_len) {
510 src_len2 = utf16_len_n(src, src_len);
512 *dest = talloc_strdup(bufinfo->mem_ctx, "");
513 return src_len2 + alignment;
516 ret = convert_string_talloc(bufinfo->mem_ctx, lp_iconv_convenience(global_loadparm), CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
524 return src_len2 + alignment;
528 pull a ascii string from a request packet, returning a talloced string
530 the string length is limited by the 3 things:
531 - the data size in the request (end of packet)
532 - the passed 'byte_len' if it is not -1
533 - the end of string (null termination)
535 Note that 'byte_len' is the number of bytes in the packet
537 on failure zero is returned and *dest is set to NULL, otherwise the number
538 of bytes consumed in the packet is returned
540 static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
542 int src_len, src_len2;
546 if (flags & STR_NO_RANGE_CHECK) {
549 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
554 if (byte_len != -1 && src_len > byte_len) {
559 src_len2 = strnlen((const char *)src, src_len);
560 if (src_len2 <= src_len - 1) {
561 /* include the termination if we didn't reach the end of the packet */
565 ret = convert_string_talloc(bufinfo->mem_ctx, lp_iconv_convenience(global_loadparm), CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
577 pull a string from a request packet, returning a talloced string
579 the string length is limited by the 3 things:
580 - the data size in the request (end of packet)
581 - the passed 'byte_len' if it is not -1
582 - the end of string (null termination)
584 Note that 'byte_len' is the number of bytes in the packet
586 on failure zero is returned and *dest is set to NULL, otherwise the number
587 of bytes consumed in the packet is returned
589 size_t req_pull_string(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
591 if (!(flags & STR_ASCII) &&
592 (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) {
593 return req_pull_ucs2(bufinfo, dest, src, byte_len, flags);
596 return req_pull_ascii(bufinfo, dest, src, byte_len, flags);
601 pull a ASCII4 string buffer from a request packet, returning a talloced string
603 an ASCII4 buffer is a null terminated string that has a prefix
604 of the character 0x4. It tends to be used in older parts of the protocol.
606 on failure *dest is set to the zero length string. This seems to
607 match win2000 behaviour
609 size_t req_pull_ascii4(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, uint_t flags)
613 if (PTR_DIFF(src, bufinfo->data) + 1 > bufinfo->data_size) {
614 /* win2000 treats this as the empty string! */
615 (*dest) = talloc_strdup(bufinfo->mem_ctx, "");
619 /* this consumes the 0x4 byte. We don't check whether the byte
620 is actually 0x4 or not. This matches win2000 server
624 ret = req_pull_string(bufinfo, dest, src, -1, flags);
626 (*dest) = talloc_strdup(bufinfo->mem_ctx, "");
634 pull a DATA_BLOB from a request packet, returning a talloced blob
636 return false if any part is outside the data portion of the packet
638 bool req_pull_blob(struct request_bufinfo *bufinfo, const uint8_t *src, int len, DATA_BLOB *blob)
640 if (len != 0 && req_data_oob(bufinfo, src, len)) {
644 (*blob) = data_blob_talloc(bufinfo->mem_ctx, src, len);
649 /* check that a lump of data in a request is within the bounds of the data section of
651 bool req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count)
657 /* be careful with wraparound! */
658 if ((uintptr_t)ptr < (uintptr_t)bufinfo->data ||
659 (uintptr_t)ptr >= (uintptr_t)bufinfo->data + bufinfo->data_size ||
660 count > bufinfo->data_size ||
661 (uintptr_t)ptr + count > (uintptr_t)bufinfo->data + bufinfo->data_size) {
669 pull an open file handle from a packet, taking account of the chained_fnum
671 static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
673 if (req->chained_fnum != -1) {
674 return req->chained_fnum;
676 return SVAL(base, offset);
679 struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
681 struct smbsrv_handle *handle;
682 uint16_t fnum = req_fnum(req, base, offset);
684 handle = smbsrv_smb_handle_find(req->tcon, fnum, req->request_time);
690 * For SMB tcons and sessions can be mixed!
691 * But we need to make sure that file handles
692 * are only accessed by the opening session!
694 * So check if the handle is valid for the given session!
696 if (handle->session != req->session) {
700 return handle->ntvfs;
703 void smbsrv_push_fnum(uint8_t *base, uint_t offset, struct ntvfs_handle *ntvfs)
705 struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
706 struct smbsrv_handle);
707 SSVAL(base, offset, handle->hid);
710 NTSTATUS smbsrv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
712 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
713 struct smbsrv_request);
714 struct smbsrv_handle *handle;
715 struct ntvfs_handle *h;
717 handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
718 if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
720 h = talloc_zero(handle, struct ntvfs_handle);
724 * note: we don't set handle->ntvfs yet,
725 * this will be done by smbsrv_handle_make_valid()
726 * this makes sure the handle is invalid for clients
727 * until the ntvfs subsystem has made it valid
730 h->session_info = ntvfs->session_info;
731 h->smbpid = ntvfs->smbpid;
733 h->frontend_data.private_data = handle;
739 return NT_STATUS_NO_MEMORY;
742 NTSTATUS smbsrv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
744 struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
745 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
746 struct smbsrv_handle);
747 /* this tells the frontend that the handle is valid */
749 /* this moves the smbsrv_request to the smbsrv_tcon memory context */
750 talloc_steal(tcon, handle);
754 void smbsrv_handle_destroy(void *private_data, struct ntvfs_handle *h)
756 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
757 struct smbsrv_handle);
761 struct ntvfs_handle *smbsrv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
763 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
764 struct smbsrv_request);
766 if (key->length != 2) return NULL;
768 return smbsrv_pull_fnum(req, key->data, 0);
771 DATA_BLOB smbsrv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
775 smbsrv_push_fnum(key, 0, handle);
777 return data_blob_talloc(mem_ctx, key, sizeof(key));