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 static int smbsrv_request_destructor(struct smbsrv_request *req)
38 DLIST_REMOVE(req->smb_conn->requests, req);
42 /****************************************************************************
43 construct a basic request packet, mostly used to construct async packets
44 such as change notify and oplock break requests
45 ****************************************************************************/
46 struct smbsrv_request *smbsrv_init_request(struct smbsrv_connection *smb_conn)
48 struct smbsrv_request *req;
50 req = talloc_zero(smb_conn, struct smbsrv_request);
55 /* setup the request context */
56 req->smb_conn = smb_conn;
58 talloc_set_destructor(req, smbsrv_request_destructor);
65 setup a chained reply in req->out with the given word count and initial data buffer size.
67 static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
69 uint32_t chain_base_size = req->out.size;
71 /* we need room for the wct value, the words, the buffer length and the buffer */
72 req->out.size += 1 + VWV(wct) + 2 + buflen;
74 /* over allocate by a small amount */
75 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
77 req->out.buffer = talloc_realloc(req, req->out.buffer,
78 uint8_t, req->out.allocated);
79 if (!req->out.buffer) {
80 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
84 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
85 req->out.vwv = req->out.buffer + chain_base_size + 1;
87 req->out.data = req->out.vwv + VWV(wct) + 2;
88 req->out.data_size = buflen;
89 req->out.ptr = req->out.data;
91 SCVAL(req->out.buffer, chain_base_size, wct);
92 SSVAL(req->out.vwv, VWV(wct), buflen);
97 setup a reply in req->out with the given word count and initial data buffer size.
98 the caller will then fill in the command words and data before calling req_send_reply() to
99 send the reply on its way
101 void smbsrv_setup_reply(struct smbsrv_request *req, uint_t wct, size_t buflen)
105 if (req->chain_count != 0) {
106 req_setup_chain_reply(req, wct, buflen);
110 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + buflen;
112 /* over allocate by a small amount */
113 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
115 req->out.buffer = talloc_size(req, req->out.allocated);
116 if (!req->out.buffer) {
117 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
121 flags2 = FLAGS2_LONG_PATH_COMPONENTS |
122 FLAGS2_EXTENDED_ATTRIBUTES |
124 flags2 |= (req->flags2 & (FLAGS2_UNICODE_STRINGS|FLAGS2_EXTENDED_SECURITY));
125 if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
126 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
129 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
130 req->out.vwv = req->out.hdr + HDR_VWV;
132 req->out.data = req->out.vwv + VWV(wct) + 2;
133 req->out.data_size = buflen;
134 req->out.ptr = req->out.data;
136 SIVAL(req->out.hdr, HDR_RCLS, 0);
138 SCVAL(req->out.hdr, HDR_WCT, wct);
139 SSVAL(req->out.vwv, VWV(wct), buflen);
141 memcpy(req->out.hdr, "\377SMB", 4);
142 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
143 SSVAL(req->out.hdr,HDR_FLG2, flags2);
144 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
145 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
148 /* copy the cmd, tid, pid, uid and mid from the request */
149 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
150 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
151 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
152 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
153 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
155 SCVAL(req->out.hdr,HDR_COM,0);
156 SSVAL(req->out.hdr,HDR_TID,0);
157 SSVAL(req->out.hdr,HDR_PID,0);
158 SSVAL(req->out.hdr,HDR_UID,0);
159 SSVAL(req->out.hdr,HDR_MID,0);
165 setup a copy of a request, used when the server needs to send
166 more than one reply for a single request packet
168 struct smbsrv_request *smbsrv_setup_secondary_request(struct smbsrv_request *old_req)
170 struct smbsrv_request *req;
173 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
178 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
179 if (req->out.buffer == NULL) {
184 diff = req->out.buffer - old_req->out.buffer;
186 req->out.hdr += diff;
187 req->out.vwv += diff;
188 req->out.data += diff;
189 req->out.ptr += diff;
195 work out the maximum data size we will allow for this reply, given
196 the negotiated max_xmit. The basic reply packet must be setup before
199 note that this is deliberately a signed integer reply
201 int req_max_data(struct smbsrv_request *req)
204 ret = req->smb_conn->negotiate.max_send;
205 ret -= PTR_DIFF(req->out.data, req->out.hdr);
206 if (ret < 0) ret = 0;
212 grow the allocation of the data buffer portion of a reply
213 packet. Note that as this can reallocate the packet buffer this
214 invalidates any local pointers into the packet.
216 To cope with this req->out.ptr is supplied. This will be updated to
217 point at the same offset into the packet as before this call
219 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
224 delta = new_size - req->out.data_size;
225 if (delta + req->out.size <= req->out.allocated) {
226 /* it fits in the preallocation */
230 /* we need to realloc */
231 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
232 buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
234 smb_panic("out of memory in req_grow_allocation");
237 if (buf2 == req->out.buffer) {
238 /* the malloc library gave us the same pointer */
242 /* update the pointers into the packet */
243 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
244 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
245 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
246 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
248 req->out.buffer = buf2;
253 grow the data buffer portion of a reply packet. Note that as this
254 can reallocate the packet buffer this invalidates any local pointers
257 To cope with this req->out.ptr is supplied. This will be updated to
258 point at the same offset into the packet as before this call
260 void req_grow_data(struct smbsrv_request *req, size_t new_size)
264 if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
265 smb_panic("reply buffer too large!");
268 req_grow_allocation(req, new_size);
270 delta = new_size - req->out.data_size;
272 req->out.size += delta;
273 req->out.data_size += delta;
275 /* set the BCC to the new data size */
276 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
280 send a reply and destroy the request buffer
282 note that this only looks at req->out.buffer and req->out.size, allowing manually
283 constructed packets to be sent
285 void smbsrv_send_reply_nosign(struct smbsrv_request *req)
290 if (req->smb_conn->connection->event.fde == NULL) {
291 /* we are in the process of shutting down this connection */
296 if (req->out.size > NBT_HDR_SIZE) {
297 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
300 blob = data_blob_const(req->out.buffer, req->out.size);
301 status = packet_send(req->smb_conn->packet, blob);
302 if (!NT_STATUS_IS_OK(status)) {
303 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
309 possibly sign a message then send a reply and destroy the request buffer
311 note that this only looks at req->out.buffer and req->out.size, allowing manually
312 constructed packets to be sent
314 void smbsrv_send_reply(struct smbsrv_request *req)
316 if (req->smb_conn->connection->event.fde == NULL) {
317 /* we are in the process of shutting down this connection */
321 smbsrv_sign_packet(req);
323 smbsrv_send_reply_nosign(req);
327 setup the header of a reply to include an NTSTATUS code
329 void smbsrv_setup_error(struct smbsrv_request *req, NTSTATUS status)
331 if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
332 /* convert to DOS error codes */
335 ntstatus_to_dos(status, &eclass, &ecode);
336 SCVAL(req->out.hdr, HDR_RCLS, eclass);
337 SSVAL(req->out.hdr, HDR_ERR, ecode);
338 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
342 if (NT_STATUS_IS_DOS(status)) {
343 /* its a encoded DOS error, using the reserved range */
344 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
345 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
346 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
348 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
349 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
354 construct and send an error packet, then destroy the request
355 auto-converts to DOS error format when appropriate
357 void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status)
359 if (req->smb_conn->connection->event.fde == NULL) {
360 /* the socket has been destroyed - no point trying to send an error! */
364 smbsrv_setup_reply(req, 0, 0);
366 /* error returns never have any data */
367 req_grow_data(req, 0);
369 smbsrv_setup_error(req, status);
370 smbsrv_send_reply(req);
375 push a string into the data portion of the request packet, growing it if necessary
376 this gets quite tricky - please be very careful to cover all cases when modifying this
378 if dest is NULL, then put the string at the end of the data portion of the packet
380 if dest_len is -1 then no limit applies
382 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, size_t flags)
387 const int max_bytes_per_char = 3;
389 if (!(flags & (STR_ASCII|STR_UNICODE))) {
390 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
394 dest = req->out.data + req->out.data_size;
397 if (dest_len != -1) {
400 len = (strlen(str)+2) * max_bytes_per_char;
403 grow_size = len + PTR_DIFF(dest, req->out.data);
404 buf0 = req->out.buffer;
406 req_grow_allocation(req, grow_size);
408 if (buf0 != req->out.buffer) {
409 dest = req->out.buffer + PTR_DIFF(dest, buf0);
412 len = push_string(lp_iconv_convenience(global_loadparm), dest, str, len, flags);
414 grow_size = len + PTR_DIFF(dest, req->out.data);
416 if (grow_size > req->out.data_size) {
417 req_grow_data(req, grow_size);
424 append raw bytes into the data portion of the request packet
425 return the number of bytes added
427 size_t req_append_bytes(struct smbsrv_request *req,
428 const uint8_t *bytes, size_t byte_len)
430 req_grow_allocation(req, byte_len + req->out.data_size);
431 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
432 req_grow_data(req, byte_len + req->out.data_size);
436 append variable block (type 5 buffer) into the data portion of the request packet
437 return the number of bytes added
439 size_t req_append_var_block(struct smbsrv_request *req,
440 const uint8_t *bytes, uint16_t byte_len)
442 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
443 SCVAL(req->out.data + req->out.data_size, 0, 5);
444 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
446 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
448 req_grow_data(req, byte_len + 3 + req->out.data_size);
452 pull a UCS2 string from a request packet, returning a talloced unix string
454 the string length is limited by the 3 things:
455 - the data size in the request (end of packet)
456 - the passed 'byte_len' if it is not -1
457 - the end of string (null termination)
459 Note that 'byte_len' is the number of bytes in the packet
461 on failure zero is returned and *dest is set to NULL, otherwise the number
462 of bytes consumed in the packet is returned
464 static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
466 int src_len, src_len2, alignment=0;
470 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
473 if (byte_len != -1) {
478 if (flags & STR_NO_RANGE_CHECK) {
481 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
482 if (byte_len != -1 && src_len > byte_len) {
492 src_len2 = utf16_len_n(src, src_len);
494 *dest = talloc_strdup(req, "");
495 return src_len2 + alignment;
498 ret = convert_string_talloc(req, lp_iconv_convenience(global_loadparm), CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
506 return src_len2 + alignment;
510 pull a ascii string from a request packet, returning a talloced string
512 the string length is limited by the 3 things:
513 - the data size in the request (end of packet)
514 - the passed 'byte_len' if it is not -1
515 - the end of string (null termination)
517 Note that 'byte_len' is the number of bytes in the packet
519 on failure zero is returned and *dest is set to NULL, otherwise the number
520 of bytes consumed in the packet is returned
522 static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
524 int src_len, src_len2;
528 if (flags & STR_NO_RANGE_CHECK) {
531 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
536 if (byte_len != -1 && src_len > byte_len) {
541 src_len2 = strnlen((const char *)src, src_len);
542 if (src_len2 <= src_len - 1) {
543 /* include the termination if we didn't reach the end of the packet */
547 ret = convert_string_talloc(req, lp_iconv_convenience(global_loadparm), CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
559 pull a string from a request packet, returning a talloced string
561 the string length is limited by the 3 things:
562 - the data size in the request (end of packet)
563 - the passed 'byte_len' if it is not -1
564 - the end of string (null termination)
566 Note that 'byte_len' is the number of bytes in the packet
568 on failure zero is returned and *dest is set to NULL, otherwise the number
569 of bytes consumed in the packet is returned
571 size_t req_pull_string(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
573 if (!(flags & STR_ASCII) &&
574 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
575 return req_pull_ucs2(req, dest, src, byte_len, flags);
578 return req_pull_ascii(req, dest, src, byte_len, flags);
583 pull a ASCII4 string buffer from a request packet, returning a talloced string
585 an ASCII4 buffer is a null terminated string that has a prefix
586 of the character 0x4. It tends to be used in older parts of the protocol.
588 on failure *dest is set to the zero length string. This seems to
589 match win2000 behaviour
591 size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const uint8_t *src, uint_t flags)
595 if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
596 /* win2000 treats this as the empty string! */
597 (*dest) = talloc_strdup(req, "");
601 /* this consumes the 0x4 byte. We don't check whether the byte
602 is actually 0x4 or not. This matches win2000 server
606 ret = req_pull_string(req, dest, src, -1, flags);
608 (*dest) = talloc_strdup(req, "");
616 pull a DATA_BLOB from a request packet, returning a talloced blob
618 return false if any part is outside the data portion of the packet
620 bool req_pull_blob(struct smbsrv_request *req, const uint8_t *src, int len, DATA_BLOB *blob)
622 if (len != 0 && req_data_oob(req, src, len)) {
626 (*blob) = data_blob_talloc(req, src, len);
631 /* check that a lump of data in a request is within the bounds of the data section of
633 bool req_data_oob(struct smbsrv_request *req, const uint8_t *ptr, uint32_t count)
639 /* be careful with wraparound! */
640 if (ptr < req->in.data ||
641 ptr >= req->in.data + req->in.data_size ||
642 count > req->in.data_size ||
643 ptr + count > req->in.data + req->in.data_size) {
651 pull an open file handle from a packet, taking account of the chained_fnum
653 static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
655 if (req->chained_fnum != -1) {
656 return req->chained_fnum;
658 return SVAL(base, offset);
661 struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
663 struct smbsrv_handle *handle;
664 uint16_t fnum = req_fnum(req, base, offset);
666 handle = smbsrv_smb_handle_find(req->tcon, fnum, req->request_time);
672 * For SMB tcons and sessions can be mixed!
673 * But we need to make sure that file handles
674 * are only accessed by the opening session!
676 * So check if the handle is valid for the given session!
678 if (handle->session != req->session) {
682 return handle->ntvfs;
685 void smbsrv_push_fnum(uint8_t *base, uint_t offset, struct ntvfs_handle *ntvfs)
687 struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
688 struct smbsrv_handle);
689 SSVAL(base, offset, handle->hid);
692 NTSTATUS smbsrv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
694 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
695 struct smbsrv_request);
696 struct smbsrv_handle *handle;
697 struct ntvfs_handle *h;
699 handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
700 if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
702 h = talloc_zero(handle, struct ntvfs_handle);
706 * note: we don't set handle->ntvfs yet,
707 * this will be done by smbsrv_handle_make_valid()
708 * this makes sure the handle is invalid for clients
709 * until the ntvfs subsystem has made it valid
712 h->session_info = ntvfs->session_info;
713 h->smbpid = ntvfs->smbpid;
715 h->frontend_data.private_data = handle;
721 return NT_STATUS_NO_MEMORY;
724 NTSTATUS smbsrv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
726 struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
727 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
728 struct smbsrv_handle);
729 /* this tells the frontend that the handle is valid */
731 /* this moves the smbsrv_request to the smbsrv_tcon memory context */
732 talloc_steal(tcon, handle);
736 void smbsrv_handle_destroy(void *private_data, struct ntvfs_handle *h)
738 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
739 struct smbsrv_handle);
743 struct ntvfs_handle *smbsrv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
745 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
746 struct smbsrv_request);
748 if (key->length != 2) return NULL;
750 return smbsrv_pull_fnum(req, key->data, 0);
753 DATA_BLOB smbsrv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
757 smbsrv_push_fnum(key, 0, handle);
759 return data_blob_talloc(mem_ctx, key, sizeof(key));