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.unicode = (req->flags2 & FLAGS2_UNICODE_STRINGS)?true:false;
41 req->in.bufinfo.align_base = req->in.buffer;
42 req->in.bufinfo.data = req->in.data;
43 req->in.bufinfo.data_size = req->in.data_size;
47 static int smbsrv_request_destructor(struct smbsrv_request *req)
49 DLIST_REMOVE(req->smb_conn->requests, req);
53 /****************************************************************************
54 construct a basic request packet, mostly used to construct async packets
55 such as change notify and oplock break requests
56 ****************************************************************************/
57 struct smbsrv_request *smbsrv_init_request(struct smbsrv_connection *smb_conn)
59 struct smbsrv_request *req;
61 req = talloc_zero(smb_conn, struct smbsrv_request);
66 /* setup the request context */
67 req->smb_conn = smb_conn;
69 talloc_set_destructor(req, smbsrv_request_destructor);
76 setup a chained reply in req->out with the given word count and initial data buffer size.
78 static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
80 uint32_t chain_base_size = req->out.size;
82 /* we need room for the wct value, the words, the buffer length and the buffer */
83 req->out.size += 1 + VWV(wct) + 2 + buflen;
85 /* over allocate by a small amount */
86 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
88 req->out.buffer = talloc_realloc(req, req->out.buffer,
89 uint8_t, req->out.allocated);
90 if (!req->out.buffer) {
91 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
95 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
96 req->out.vwv = req->out.buffer + chain_base_size + 1;
98 req->out.data = req->out.vwv + VWV(wct) + 2;
99 req->out.data_size = buflen;
100 req->out.ptr = req->out.data;
102 SCVAL(req->out.buffer, chain_base_size, wct);
103 SSVAL(req->out.vwv, VWV(wct), buflen);
108 setup a reply in req->out with the given word count and initial data buffer size.
109 the caller will then fill in the command words and data before calling req_send_reply() to
110 send the reply on its way
112 void smbsrv_setup_reply(struct smbsrv_request *req, uint_t wct, size_t buflen)
116 if (req->chain_count != 0) {
117 req_setup_chain_reply(req, wct, buflen);
121 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + buflen;
123 /* over allocate by a small amount */
124 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
126 req->out.buffer = talloc_size(req, req->out.allocated);
127 if (!req->out.buffer) {
128 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
132 flags2 = FLAGS2_LONG_PATH_COMPONENTS |
133 FLAGS2_EXTENDED_ATTRIBUTES |
135 flags2 |= (req->flags2 & (FLAGS2_UNICODE_STRINGS|FLAGS2_EXTENDED_SECURITY));
136 if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
137 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
140 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
141 req->out.vwv = req->out.hdr + HDR_VWV;
143 req->out.data = req->out.vwv + VWV(wct) + 2;
144 req->out.data_size = buflen;
145 req->out.ptr = req->out.data;
147 SIVAL(req->out.hdr, HDR_RCLS, 0);
149 SCVAL(req->out.hdr, HDR_WCT, wct);
150 SSVAL(req->out.vwv, VWV(wct), buflen);
152 memcpy(req->out.hdr, "\377SMB", 4);
153 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
154 SSVAL(req->out.hdr,HDR_FLG2, flags2);
155 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
156 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
159 /* copy the cmd, tid, pid, uid and mid from the request */
160 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
161 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
162 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
163 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
164 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
166 SCVAL(req->out.hdr,HDR_COM,0);
167 SSVAL(req->out.hdr,HDR_TID,0);
168 SSVAL(req->out.hdr,HDR_PID,0);
169 SSVAL(req->out.hdr,HDR_UID,0);
170 SSVAL(req->out.hdr,HDR_MID,0);
176 setup a copy of a request, used when the server needs to send
177 more than one reply for a single request packet
179 struct smbsrv_request *smbsrv_setup_secondary_request(struct smbsrv_request *old_req)
181 struct smbsrv_request *req;
184 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
189 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
190 if (req->out.buffer == NULL) {
195 diff = req->out.buffer - old_req->out.buffer;
197 req->out.hdr += diff;
198 req->out.vwv += diff;
199 req->out.data += diff;
200 req->out.ptr += diff;
206 work out the maximum data size we will allow for this reply, given
207 the negotiated max_xmit. The basic reply packet must be setup before
210 note that this is deliberately a signed integer reply
212 int req_max_data(struct smbsrv_request *req)
215 ret = req->smb_conn->negotiate.max_send;
216 ret -= PTR_DIFF(req->out.data, req->out.hdr);
217 if (ret < 0) ret = 0;
223 grow the allocation of the data buffer portion of a reply
224 packet. Note that as this can reallocate the packet buffer this
225 invalidates any local pointers into the packet.
227 To cope with this req->out.ptr is supplied. This will be updated to
228 point at the same offset into the packet as before this call
230 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
235 delta = new_size - req->out.data_size;
236 if (delta + req->out.size <= req->out.allocated) {
237 /* it fits in the preallocation */
241 /* we need to realloc */
242 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
243 buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
245 smb_panic("out of memory in req_grow_allocation");
248 if (buf2 == req->out.buffer) {
249 /* the malloc library gave us the same pointer */
253 /* update the pointers into the packet */
254 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
255 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
256 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
257 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
259 req->out.buffer = buf2;
264 grow the data buffer portion of a reply packet. Note that as this
265 can reallocate the packet buffer this invalidates any local pointers
268 To cope with this req->out.ptr is supplied. This will be updated to
269 point at the same offset into the packet as before this call
271 void req_grow_data(struct smbsrv_request *req, size_t new_size)
275 if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
276 smb_panic("reply buffer too large!");
279 req_grow_allocation(req, new_size);
281 delta = new_size - req->out.data_size;
283 req->out.size += delta;
284 req->out.data_size += delta;
286 /* set the BCC to the new data size */
287 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
291 send a reply and destroy the request buffer
293 note that this only looks at req->out.buffer and req->out.size, allowing manually
294 constructed packets to be sent
296 void smbsrv_send_reply_nosign(struct smbsrv_request *req)
301 if (req->smb_conn->connection->event.fde == NULL) {
302 /* we are in the process of shutting down this connection */
307 if (req->out.size > NBT_HDR_SIZE) {
308 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
311 blob = data_blob_const(req->out.buffer, req->out.size);
312 status = packet_send(req->smb_conn->packet, blob);
313 if (!NT_STATUS_IS_OK(status)) {
314 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
320 possibly sign a message then send a reply and destroy the request buffer
322 note that this only looks at req->out.buffer and req->out.size, allowing manually
323 constructed packets to be sent
325 void smbsrv_send_reply(struct smbsrv_request *req)
327 if (req->smb_conn->connection->event.fde == NULL) {
328 /* we are in the process of shutting down this connection */
332 smbsrv_sign_packet(req);
334 smbsrv_send_reply_nosign(req);
338 setup the header of a reply to include an NTSTATUS code
340 void smbsrv_setup_error(struct smbsrv_request *req, NTSTATUS status)
342 if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
343 /* convert to DOS error codes */
346 ntstatus_to_dos(status, &eclass, &ecode);
347 SCVAL(req->out.hdr, HDR_RCLS, eclass);
348 SSVAL(req->out.hdr, HDR_ERR, ecode);
349 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
353 if (NT_STATUS_IS_DOS(status)) {
354 /* its a encoded DOS error, using the reserved range */
355 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
356 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
357 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
359 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
360 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
365 construct and send an error packet, then destroy the request
366 auto-converts to DOS error format when appropriate
368 void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status)
370 if (req->smb_conn->connection->event.fde == NULL) {
371 /* the socket has been destroyed - no point trying to send an error! */
375 smbsrv_setup_reply(req, 0, 0);
377 /* error returns never have any data */
378 req_grow_data(req, 0);
380 smbsrv_setup_error(req, status);
381 smbsrv_send_reply(req);
386 push a string into the data portion of the request packet, growing it if necessary
387 this gets quite tricky - please be very careful to cover all cases when modifying this
389 if dest is NULL, then put the string at the end of the data portion of the packet
391 if dest_len is -1 then no limit applies
393 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, size_t flags)
398 const int max_bytes_per_char = 3;
400 if (!(flags & (STR_ASCII|STR_UNICODE))) {
401 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
405 dest = req->out.data + req->out.data_size;
408 if (dest_len != -1) {
411 len = (strlen(str)+2) * max_bytes_per_char;
414 grow_size = len + PTR_DIFF(dest, req->out.data);
415 buf0 = req->out.buffer;
417 req_grow_allocation(req, grow_size);
419 if (buf0 != req->out.buffer) {
420 dest = req->out.buffer + PTR_DIFF(dest, buf0);
423 len = push_string(lp_iconv_convenience(global_loadparm), dest, str, len, flags);
425 grow_size = len + PTR_DIFF(dest, req->out.data);
427 if (grow_size > req->out.data_size) {
428 req_grow_data(req, grow_size);
435 append raw bytes into the data portion of the request packet
436 return the number of bytes added
438 size_t req_append_bytes(struct smbsrv_request *req,
439 const uint8_t *bytes, size_t byte_len)
441 req_grow_allocation(req, byte_len + req->out.data_size);
442 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
443 req_grow_data(req, byte_len + req->out.data_size);
447 append variable block (type 5 buffer) into the data portion of the request packet
448 return the number of bytes added
450 size_t req_append_var_block(struct smbsrv_request *req,
451 const uint8_t *bytes, uint16_t byte_len)
453 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
454 SCVAL(req->out.data + req->out.data_size, 0, 5);
455 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
457 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
459 req_grow_data(req, byte_len + 3 + req->out.data_size);
463 pull a UCS2 string from a request packet, returning a talloced unix string
465 the string length is limited by the 3 things:
466 - the data size in the request (end of packet)
467 - the passed 'byte_len' if it is not -1
468 - the end of string (null termination)
470 Note that 'byte_len' is the number of bytes in the packet
472 on failure zero is returned and *dest is set to NULL, otherwise the number
473 of bytes consumed in the packet is returned
475 static size_t req_pull_ucs2(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
477 int src_len, src_len2, alignment=0;
481 if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
484 if (byte_len != -1) {
489 if (flags & STR_NO_RANGE_CHECK) {
492 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
493 if (byte_len != -1 && src_len > byte_len) {
503 src_len2 = utf16_len_n(src, src_len);
505 *dest = talloc_strdup(bufinfo->mem_ctx, "");
506 return src_len2 + alignment;
509 ret = convert_string_talloc(bufinfo->mem_ctx, lp_iconv_convenience(global_loadparm), CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
517 return src_len2 + alignment;
521 pull a ascii string from a request packet, returning a talloced string
523 the string length is limited by the 3 things:
524 - the data size in the request (end of packet)
525 - the passed 'byte_len' if it is not -1
526 - the end of string (null termination)
528 Note that 'byte_len' is the number of bytes in the packet
530 on failure zero is returned and *dest is set to NULL, otherwise the number
531 of bytes consumed in the packet is returned
533 static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
535 int src_len, src_len2;
539 if (flags & STR_NO_RANGE_CHECK) {
542 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
547 if (byte_len != -1 && src_len > byte_len) {
552 src_len2 = strnlen((const char *)src, src_len);
553 if (src_len2 <= src_len - 1) {
554 /* include the termination if we didn't reach the end of the packet */
558 ret = convert_string_talloc(bufinfo->mem_ctx, lp_iconv_convenience(global_loadparm), CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
570 pull a string from a request packet, returning a talloced string
572 the string length is limited by the 3 things:
573 - the data size in the request (end of packet)
574 - the passed 'byte_len' if it is not -1
575 - the end of string (null termination)
577 Note that 'byte_len' is the number of bytes in the packet
579 on failure zero is returned and *dest is set to NULL, otherwise the number
580 of bytes consumed in the packet is returned
582 size_t req_pull_string(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
584 if (!(flags & STR_ASCII) &&
585 (((flags & STR_UNICODE) || bufinfo->unicode))) {
586 return req_pull_ucs2(bufinfo, dest, src, byte_len, flags);
589 return req_pull_ascii(bufinfo, dest, src, byte_len, flags);
594 pull a ASCII4 string buffer from a request packet, returning a talloced string
596 an ASCII4 buffer is a null terminated string that has a prefix
597 of the character 0x4. It tends to be used in older parts of the protocol.
599 on failure *dest is set to the zero length string. This seems to
600 match win2000 behaviour
602 size_t req_pull_ascii4(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, uint_t flags)
606 if (PTR_DIFF(src, bufinfo->data) + 1 > bufinfo->data_size) {
607 /* win2000 treats this as the empty string! */
608 (*dest) = talloc_strdup(bufinfo->mem_ctx, "");
612 /* this consumes the 0x4 byte. We don't check whether the byte
613 is actually 0x4 or not. This matches win2000 server
617 ret = req_pull_string(bufinfo, dest, src, -1, flags);
619 (*dest) = talloc_strdup(bufinfo->mem_ctx, "");
627 pull a DATA_BLOB from a request packet, returning a talloced blob
629 return false if any part is outside the data portion of the packet
631 bool req_pull_blob(struct request_bufinfo *bufinfo, const uint8_t *src, int len, DATA_BLOB *blob)
633 if (len != 0 && req_data_oob(bufinfo, src, len)) {
637 (*blob) = data_blob_talloc(bufinfo->mem_ctx, src, len);
642 /* check that a lump of data in a request is within the bounds of the data section of
644 bool req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count)
650 /* be careful with wraparound! */
651 if (ptr < bufinfo->data ||
652 ptr >= bufinfo->data + bufinfo->data_size ||
653 count > bufinfo->data_size ||
654 ptr + count > bufinfo->data + bufinfo->data_size) {
662 pull an open file handle from a packet, taking account of the chained_fnum
664 static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
666 if (req->chained_fnum != -1) {
667 return req->chained_fnum;
669 return SVAL(base, offset);
672 struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
674 struct smbsrv_handle *handle;
675 uint16_t fnum = req_fnum(req, base, offset);
677 handle = smbsrv_smb_handle_find(req->tcon, fnum, req->request_time);
683 * For SMB tcons and sessions can be mixed!
684 * But we need to make sure that file handles
685 * are only accessed by the opening session!
687 * So check if the handle is valid for the given session!
689 if (handle->session != req->session) {
693 return handle->ntvfs;
696 void smbsrv_push_fnum(uint8_t *base, uint_t offset, struct ntvfs_handle *ntvfs)
698 struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
699 struct smbsrv_handle);
700 SSVAL(base, offset, handle->hid);
703 NTSTATUS smbsrv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
705 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
706 struct smbsrv_request);
707 struct smbsrv_handle *handle;
708 struct ntvfs_handle *h;
710 handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
711 if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
713 h = talloc_zero(handle, struct ntvfs_handle);
717 * note: we don't set handle->ntvfs yet,
718 * this will be done by smbsrv_handle_make_valid()
719 * this makes sure the handle is invalid for clients
720 * until the ntvfs subsystem has made it valid
723 h->session_info = ntvfs->session_info;
724 h->smbpid = ntvfs->smbpid;
726 h->frontend_data.private_data = handle;
732 return NT_STATUS_NO_MEMORY;
735 NTSTATUS smbsrv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
737 struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
738 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
739 struct smbsrv_handle);
740 /* this tells the frontend that the handle is valid */
742 /* this moves the smbsrv_request to the smbsrv_tcon memory context */
743 talloc_steal(tcon, handle);
747 void smbsrv_handle_destroy(void *private_data, struct ntvfs_handle *h)
749 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
750 struct smbsrv_handle);
754 struct ntvfs_handle *smbsrv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
756 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
757 struct smbsrv_request);
759 if (key->length != 2) return NULL;
761 return smbsrv_pull_fnum(req, key->data, 0);
764 DATA_BLOB smbsrv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
768 smbsrv_push_fnum(key, 0, handle);
770 return data_blob_talloc(mem_ctx, key, sizeof(key));