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 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
144 req->out.vwv = req->out.hdr + HDR_VWV;
146 req->out.data = req->out.vwv + VWV(wct) + 2;
147 req->out.data_size = buflen;
148 req->out.ptr = req->out.data;
150 SIVAL(req->out.hdr, HDR_RCLS, 0);
152 SCVAL(req->out.hdr, HDR_WCT, wct);
153 SSVAL(req->out.vwv, VWV(wct), buflen);
155 memcpy(req->out.hdr, "\377SMB", 4);
156 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
157 SSVAL(req->out.hdr,HDR_FLG2, flags2);
158 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
159 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
162 /* copy the cmd, tid, pid, uid and mid from the request */
163 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
164 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
165 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
166 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
167 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
169 SCVAL(req->out.hdr,HDR_COM,0);
170 SSVAL(req->out.hdr,HDR_TID,0);
171 SSVAL(req->out.hdr,HDR_PID,0);
172 SSVAL(req->out.hdr,HDR_UID,0);
173 SSVAL(req->out.hdr,HDR_MID,0);
179 setup a copy of a request, used when the server needs to send
180 more than one reply for a single request packet
182 struct smbsrv_request *smbsrv_setup_secondary_request(struct smbsrv_request *old_req)
184 struct smbsrv_request *req;
187 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
192 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
193 if (req->out.buffer == NULL) {
198 diff = req->out.buffer - old_req->out.buffer;
200 req->out.hdr += diff;
201 req->out.vwv += diff;
202 req->out.data += diff;
203 req->out.ptr += diff;
209 work out the maximum data size we will allow for this reply, given
210 the negotiated max_xmit. The basic reply packet must be setup before
213 note that this is deliberately a signed integer reply
215 int req_max_data(struct smbsrv_request *req)
218 ret = req->smb_conn->negotiate.max_send;
219 ret -= PTR_DIFF(req->out.data, req->out.hdr);
220 if (ret < 0) ret = 0;
226 grow the allocation of the data buffer portion of a reply
227 packet. Note that as this can reallocate the packet buffer this
228 invalidates any local pointers into the packet.
230 To cope with this req->out.ptr is supplied. This will be updated to
231 point at the same offset into the packet as before this call
233 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
238 delta = new_size - req->out.data_size;
239 if (delta + req->out.size <= req->out.allocated) {
240 /* it fits in the preallocation */
244 /* we need to realloc */
245 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
246 buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
248 smb_panic("out of memory in req_grow_allocation");
251 if (buf2 == req->out.buffer) {
252 /* the malloc library gave us the same pointer */
256 /* update the pointers into the packet */
257 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
258 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
259 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
260 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
262 req->out.buffer = buf2;
267 grow the data buffer portion of a reply packet. Note that as this
268 can reallocate the packet buffer this invalidates any local pointers
271 To cope with this req->out.ptr is supplied. This will be updated to
272 point at the same offset into the packet as before this call
274 void req_grow_data(struct smbsrv_request *req, size_t new_size)
278 if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
279 smb_panic("reply buffer too large!");
282 req_grow_allocation(req, new_size);
284 delta = new_size - req->out.data_size;
286 req->out.size += delta;
287 req->out.data_size += delta;
289 /* set the BCC to the new data size */
290 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
294 send a reply and destroy the request buffer
296 note that this only looks at req->out.buffer and req->out.size, allowing manually
297 constructed packets to be sent
299 void smbsrv_send_reply_nosign(struct smbsrv_request *req)
304 if (req->smb_conn->connection->event.fde == NULL) {
305 /* we are in the process of shutting down this connection */
310 if (req->out.size > NBT_HDR_SIZE) {
311 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
314 blob = data_blob_const(req->out.buffer, req->out.size);
315 status = packet_send(req->smb_conn->packet, blob);
316 if (!NT_STATUS_IS_OK(status)) {
317 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
323 possibly sign a message then send a reply and destroy the request buffer
325 note that this only looks at req->out.buffer and req->out.size, allowing manually
326 constructed packets to be sent
328 void smbsrv_send_reply(struct smbsrv_request *req)
330 if (req->smb_conn->connection->event.fde == NULL) {
331 /* we are in the process of shutting down this connection */
335 smbsrv_sign_packet(req);
337 smbsrv_send_reply_nosign(req);
341 setup the header of a reply to include an NTSTATUS code
343 void smbsrv_setup_error(struct smbsrv_request *req, NTSTATUS status)
345 if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
346 /* convert to DOS error codes */
349 ntstatus_to_dos(status, &eclass, &ecode);
350 SCVAL(req->out.hdr, HDR_RCLS, eclass);
351 SSVAL(req->out.hdr, HDR_ERR, ecode);
352 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
356 if (NT_STATUS_IS_DOS(status)) {
357 /* its a encoded DOS error, using the reserved range */
358 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
359 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
360 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
362 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
363 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
368 construct and send an error packet, then destroy the request
369 auto-converts to DOS error format when appropriate
371 void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status)
373 if (req->smb_conn->connection->event.fde == NULL) {
374 /* the socket has been destroyed - no point trying to send an error! */
378 smbsrv_setup_reply(req, 0, 0);
380 /* error returns never have any data */
381 req_grow_data(req, 0);
383 smbsrv_setup_error(req, status);
384 smbsrv_send_reply(req);
389 push a string into the data portion of the request packet, growing it if necessary
390 this gets quite tricky - please be very careful to cover all cases when modifying this
392 if dest is NULL, then put the string at the end of the data portion of the packet
394 if dest_len is -1 then no limit applies
396 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, size_t flags)
401 const int max_bytes_per_char = 3;
403 if (!(flags & (STR_ASCII|STR_UNICODE))) {
404 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
408 dest = req->out.data + req->out.data_size;
411 if (dest_len != -1) {
414 len = (strlen(str)+2) * max_bytes_per_char;
417 grow_size = len + PTR_DIFF(dest, req->out.data);
418 buf0 = req->out.buffer;
420 req_grow_allocation(req, grow_size);
422 if (buf0 != req->out.buffer) {
423 dest = req->out.buffer + PTR_DIFF(dest, buf0);
426 len = push_string(lp_iconv_convenience(req->smb_conn->lp_ctx), dest, str, len, flags);
428 grow_size = len + PTR_DIFF(dest, req->out.data);
430 if (grow_size > req->out.data_size) {
431 req_grow_data(req, grow_size);
438 append raw bytes into the data portion of the request packet
439 return the number of bytes added
441 size_t req_append_bytes(struct smbsrv_request *req,
442 const uint8_t *bytes, size_t byte_len)
444 req_grow_allocation(req, byte_len + req->out.data_size);
445 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
446 req_grow_data(req, byte_len + req->out.data_size);
450 append variable block (type 5 buffer) into the data portion of the request packet
451 return the number of bytes added
453 size_t req_append_var_block(struct smbsrv_request *req,
454 const uint8_t *bytes, uint16_t byte_len)
456 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
457 SCVAL(req->out.data + req->out.data_size, 0, 5);
458 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
460 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
462 req_grow_data(req, byte_len + 3 + req->out.data_size);
466 pull a UCS2 string from a request packet, returning a talloced unix string
468 the string length is limited by the 3 things:
469 - the data size in the request (end of packet)
470 - the passed 'byte_len' if it is not -1
471 - the end of string (null termination)
473 Note that 'byte_len' is the number of bytes in the packet
475 on failure zero is returned and *dest is set to NULL, otherwise the number
476 of bytes consumed in the packet is returned
478 static size_t req_pull_ucs2(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
480 int src_len, src_len2, alignment=0;
484 if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
487 if (byte_len != -1) {
492 if (flags & STR_NO_RANGE_CHECK) {
495 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
496 if (byte_len != -1 && src_len > byte_len) {
506 src_len2 = utf16_len_n(src, src_len);
508 *dest = talloc_strdup(bufinfo->mem_ctx, "");
509 return src_len2 + alignment;
512 ret = convert_string_talloc(bufinfo->mem_ctx, lp_iconv_convenience(global_loadparm), CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
520 return src_len2 + alignment;
524 pull a ascii string from a request packet, returning a talloced string
526 the string length is limited by the 3 things:
527 - the data size in the request (end of packet)
528 - the passed 'byte_len' if it is not -1
529 - the end of string (null termination)
531 Note that 'byte_len' is the number of bytes in the packet
533 on failure zero is returned and *dest is set to NULL, otherwise the number
534 of bytes consumed in the packet is returned
536 static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
538 int src_len, src_len2;
542 if (flags & STR_NO_RANGE_CHECK) {
545 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
550 if (byte_len != -1 && src_len > byte_len) {
555 src_len2 = strnlen((const char *)src, src_len);
556 if (src_len2 <= src_len - 1) {
557 /* include the termination if we didn't reach the end of the packet */
561 ret = convert_string_talloc(bufinfo->mem_ctx, lp_iconv_convenience(global_loadparm), CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
573 pull a string from a request packet, returning a talloced string
575 the string length is limited by the 3 things:
576 - the data size in the request (end of packet)
577 - the passed 'byte_len' if it is not -1
578 - the end of string (null termination)
580 Note that 'byte_len' is the number of bytes in the packet
582 on failure zero is returned and *dest is set to NULL, otherwise the number
583 of bytes consumed in the packet is returned
585 size_t req_pull_string(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
587 if (!(flags & STR_ASCII) &&
588 (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) {
589 return req_pull_ucs2(bufinfo, dest, src, byte_len, flags);
592 return req_pull_ascii(bufinfo, dest, src, byte_len, flags);
597 pull a ASCII4 string buffer from a request packet, returning a talloced string
599 an ASCII4 buffer is a null terminated string that has a prefix
600 of the character 0x4. It tends to be used in older parts of the protocol.
602 on failure *dest is set to the zero length string. This seems to
603 match win2000 behaviour
605 size_t req_pull_ascii4(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, uint_t flags)
609 if (PTR_DIFF(src, bufinfo->data) + 1 > bufinfo->data_size) {
610 /* win2000 treats this as the empty string! */
611 (*dest) = talloc_strdup(bufinfo->mem_ctx, "");
615 /* this consumes the 0x4 byte. We don't check whether the byte
616 is actually 0x4 or not. This matches win2000 server
620 ret = req_pull_string(bufinfo, dest, src, -1, flags);
622 (*dest) = talloc_strdup(bufinfo->mem_ctx, "");
630 pull a DATA_BLOB from a request packet, returning a talloced blob
632 return false if any part is outside the data portion of the packet
634 bool req_pull_blob(struct request_bufinfo *bufinfo, const uint8_t *src, int len, DATA_BLOB *blob)
636 if (len != 0 && req_data_oob(bufinfo, src, len)) {
640 (*blob) = data_blob_talloc(bufinfo->mem_ctx, src, len);
645 /* check that a lump of data in a request is within the bounds of the data section of
647 bool req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count)
653 /* be careful with wraparound! */
654 if ((uintptr_t)ptr < (uintptr_t)bufinfo->data ||
655 (uintptr_t)ptr >= (uintptr_t)bufinfo->data + bufinfo->data_size ||
656 count > bufinfo->data_size ||
657 (uintptr_t)ptr + count > (uintptr_t)bufinfo->data + bufinfo->data_size) {
665 pull an open file handle from a packet, taking account of the chained_fnum
667 static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
669 if (req->chained_fnum != -1) {
670 return req->chained_fnum;
672 return SVAL(base, offset);
675 struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
677 struct smbsrv_handle *handle;
678 uint16_t fnum = req_fnum(req, base, offset);
680 handle = smbsrv_smb_handle_find(req->tcon, fnum, req->request_time);
686 * For SMB tcons and sessions can be mixed!
687 * But we need to make sure that file handles
688 * are only accessed by the opening session!
690 * So check if the handle is valid for the given session!
692 if (handle->session != req->session) {
696 return handle->ntvfs;
699 void smbsrv_push_fnum(uint8_t *base, uint_t offset, struct ntvfs_handle *ntvfs)
701 struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
702 struct smbsrv_handle);
703 SSVAL(base, offset, handle->hid);
706 NTSTATUS smbsrv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
708 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
709 struct smbsrv_request);
710 struct smbsrv_handle *handle;
711 struct ntvfs_handle *h;
713 handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
714 if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
716 h = talloc_zero(handle, struct ntvfs_handle);
720 * note: we don't set handle->ntvfs yet,
721 * this will be done by smbsrv_handle_make_valid()
722 * this makes sure the handle is invalid for clients
723 * until the ntvfs subsystem has made it valid
726 h->session_info = ntvfs->session_info;
727 h->smbpid = ntvfs->smbpid;
729 h->frontend_data.private_data = handle;
735 return NT_STATUS_NO_MEMORY;
738 NTSTATUS smbsrv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
740 struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
741 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
742 struct smbsrv_handle);
743 /* this tells the frontend that the handle is valid */
745 /* this moves the smbsrv_request to the smbsrv_tcon memory context */
746 talloc_steal(tcon, handle);
750 void smbsrv_handle_destroy(void *private_data, struct ntvfs_handle *h)
752 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
753 struct smbsrv_handle);
757 struct ntvfs_handle *smbsrv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
759 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
760 struct smbsrv_request);
762 if (key->length != 2) return NULL;
764 return smbsrv_pull_fnum(req, key->data, 0);
767 DATA_BLOB smbsrv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
771 smbsrv_push_fnum(key, 0, handle);
773 return data_blob_talloc(mem_ctx, key, sizeof(key));