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 #define _SMB_FLAGS2_ECHOED_FLAGS ( \
139 FLAGS2_UNICODE_STRINGS | \
140 FLAGS2_EXTENDED_SECURITY | \
141 FLAGS2_SMB_SECURITY_SIGNATURES \
143 flags2 |= (req->flags2 & _SMB_FLAGS2_ECHOED_FLAGS);
144 if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
145 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
148 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
149 req->out.vwv = req->out.hdr + HDR_VWV;
151 req->out.data = req->out.vwv + VWV(wct) + 2;
152 req->out.data_size = buflen;
153 req->out.ptr = req->out.data;
155 SIVAL(req->out.hdr, HDR_RCLS, 0);
157 SCVAL(req->out.hdr, HDR_WCT, wct);
158 SSVAL(req->out.vwv, VWV(wct), buflen);
160 memcpy(req->out.hdr, "\377SMB", 4);
161 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
162 SSVAL(req->out.hdr,HDR_FLG2, flags2);
163 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
164 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
167 /* copy the cmd, tid, pid, uid and mid from the request */
168 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
169 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
170 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
171 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
172 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
174 SCVAL(req->out.hdr,HDR_COM,0);
175 SSVAL(req->out.hdr,HDR_TID,0);
176 SSVAL(req->out.hdr,HDR_PID,0);
177 SSVAL(req->out.hdr,HDR_UID,0);
178 SSVAL(req->out.hdr,HDR_MID,0);
184 setup a copy of a request, used when the server needs to send
185 more than one reply for a single request packet
187 struct smbsrv_request *smbsrv_setup_secondary_request(struct smbsrv_request *old_req)
189 struct smbsrv_request *req;
192 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
197 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
198 if (req->out.buffer == NULL) {
203 diff = req->out.buffer - old_req->out.buffer;
205 req->out.hdr += diff;
206 req->out.vwv += diff;
207 req->out.data += diff;
208 req->out.ptr += diff;
214 work out the maximum data size we will allow for this reply, given
215 the negotiated max_xmit. The basic reply packet must be setup before
218 note that this is deliberately a signed integer reply
220 int req_max_data(struct smbsrv_request *req)
223 ret = req->smb_conn->negotiate.max_send;
224 ret -= PTR_DIFF(req->out.data, req->out.hdr);
225 if (ret < 0) ret = 0;
231 grow the allocation of the data buffer portion of a reply
232 packet. Note that as this can reallocate the packet buffer this
233 invalidates any local pointers into the packet.
235 To cope with this req->out.ptr is supplied. This will be updated to
236 point at the same offset into the packet as before this call
238 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
243 delta = new_size - req->out.data_size;
244 if (delta + req->out.size <= req->out.allocated) {
245 /* it fits in the preallocation */
249 /* we need to realloc */
250 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
251 buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
253 smb_panic("out of memory in req_grow_allocation");
256 if (buf2 == req->out.buffer) {
257 /* the malloc library gave us the same pointer */
261 /* update the pointers into the packet */
262 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
263 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
264 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
265 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
267 req->out.buffer = buf2;
272 grow the data buffer portion of a reply packet. Note that as this
273 can reallocate the packet buffer this invalidates any local pointers
276 To cope with this req->out.ptr is supplied. This will be updated to
277 point at the same offset into the packet as before this call
279 void req_grow_data(struct smbsrv_request *req, size_t new_size)
283 if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
284 smb_panic("reply buffer too large!");
287 req_grow_allocation(req, new_size);
289 delta = new_size - req->out.data_size;
291 req->out.size += delta;
292 req->out.data_size += delta;
294 /* set the BCC to the new data size */
295 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
299 send a reply and destroy the request buffer
301 note that this only looks at req->out.buffer and req->out.size, allowing manually
302 constructed packets to be sent
304 void smbsrv_send_reply_nosign(struct smbsrv_request *req)
309 if (req->smb_conn->connection->event.fde == NULL) {
310 /* we are in the process of shutting down this connection */
315 if (req->out.size > NBT_HDR_SIZE) {
316 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
319 blob = data_blob_const(req->out.buffer, req->out.size);
320 status = packet_send(req->smb_conn->packet, blob);
321 if (!NT_STATUS_IS_OK(status)) {
322 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
328 possibly sign a message then send a reply and destroy the request buffer
330 note that this only looks at req->out.buffer and req->out.size, allowing manually
331 constructed packets to be sent
333 void smbsrv_send_reply(struct smbsrv_request *req)
335 if (req->smb_conn->connection->event.fde == NULL) {
336 /* we are in the process of shutting down this connection */
340 smbsrv_sign_packet(req);
342 smbsrv_send_reply_nosign(req);
346 setup the header of a reply to include an NTSTATUS code
348 void smbsrv_setup_error(struct smbsrv_request *req, NTSTATUS status)
350 if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
351 /* convert to DOS error codes */
354 ntstatus_to_dos(status, &eclass, &ecode);
355 SCVAL(req->out.hdr, HDR_RCLS, eclass);
356 SSVAL(req->out.hdr, HDR_ERR, ecode);
357 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
361 if (NT_STATUS_IS_DOS(status)) {
362 /* its a encoded DOS error, using the reserved range */
363 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
364 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
365 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
367 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
368 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
373 construct and send an error packet, then destroy the request
374 auto-converts to DOS error format when appropriate
376 void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status)
378 if (req->smb_conn->connection->event.fde == NULL) {
379 /* the socket has been destroyed - no point trying to send an error! */
383 smbsrv_setup_reply(req, 0, 0);
385 /* error returns never have any data */
386 req_grow_data(req, 0);
388 smbsrv_setup_error(req, status);
389 smbsrv_send_reply(req);
394 push a string into the data portion of the request packet, growing it if necessary
395 this gets quite tricky - please be very careful to cover all cases when modifying this
397 if dest is NULL, then put the string at the end of the data portion of the packet
399 if dest_len is -1 then no limit applies
401 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, size_t flags)
406 const int max_bytes_per_char = 3;
408 if (!(flags & (STR_ASCII|STR_UNICODE))) {
409 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
413 dest = req->out.data + req->out.data_size;
416 if (dest_len != -1) {
419 len = (strlen(str)+2) * max_bytes_per_char;
422 grow_size = len + PTR_DIFF(dest, req->out.data);
423 buf0 = req->out.buffer;
425 req_grow_allocation(req, grow_size);
427 if (buf0 != req->out.buffer) {
428 dest = req->out.buffer + PTR_DIFF(dest, buf0);
431 len = push_string(dest, str, len, flags);
433 grow_size = len + PTR_DIFF(dest, req->out.data);
435 if (grow_size > req->out.data_size) {
436 req_grow_data(req, grow_size);
443 append raw bytes into the data portion of the request packet
444 return the number of bytes added
446 size_t req_append_bytes(struct smbsrv_request *req,
447 const uint8_t *bytes, size_t byte_len)
449 req_grow_allocation(req, byte_len + req->out.data_size);
450 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
451 req_grow_data(req, byte_len + req->out.data_size);
455 append variable block (type 5 buffer) into the data portion of the request packet
456 return the number of bytes added
458 size_t req_append_var_block(struct smbsrv_request *req,
459 const uint8_t *bytes, uint16_t byte_len)
461 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
462 SCVAL(req->out.data + req->out.data_size, 0, 5);
463 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
465 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
467 req_grow_data(req, byte_len + 3 + req->out.data_size);
471 pull a UCS2 string from a request packet, returning a talloced unix string
473 the string length is limited by the 3 things:
474 - the data size in the request (end of packet)
475 - the passed 'byte_len' if it is not -1
476 - the end of string (null termination)
478 Note that 'byte_len' is the number of bytes in the packet
480 on failure zero is returned and *dest is set to NULL, otherwise the number
481 of bytes consumed in the packet is returned
483 static size_t req_pull_ucs2(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
485 int src_len, src_len2, alignment=0;
489 if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
492 if (byte_len != -1) {
497 if (flags & STR_NO_RANGE_CHECK) {
500 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
501 if (byte_len != -1 && src_len > byte_len) {
511 src_len2 = utf16_len_n(src, src_len);
513 *dest = talloc_strdup(bufinfo->mem_ctx, "");
514 return src_len2 + alignment;
517 ret = convert_string_talloc(bufinfo->mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
525 return src_len2 + alignment;
529 pull a ascii string from a request packet, returning a talloced string
531 the string length is limited by the 3 things:
532 - the data size in the request (end of packet)
533 - the passed 'byte_len' if it is not -1
534 - the end of string (null termination)
536 Note that 'byte_len' is the number of bytes in the packet
538 on failure zero is returned and *dest is set to NULL, otherwise the number
539 of bytes consumed in the packet is returned
541 static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
543 int src_len, src_len2;
547 if (flags & STR_NO_RANGE_CHECK) {
550 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
555 if (byte_len != -1 && src_len > byte_len) {
560 src_len2 = strnlen((const char *)src, src_len);
561 if (src_len2 <= src_len - 1) {
562 /* include the termination if we didn't reach the end of the packet */
566 ret = convert_string_talloc(bufinfo->mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
578 pull a string from a request packet, returning a talloced string
580 the string length is limited by the 3 things:
581 - the data size in the request (end of packet)
582 - the passed 'byte_len' if it is not -1
583 - the end of string (null termination)
585 Note that 'byte_len' is the number of bytes in the packet
587 on failure zero is returned and *dest is set to NULL, otherwise the number
588 of bytes consumed in the packet is returned
590 size_t req_pull_string(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
592 if (!(flags & STR_ASCII) &&
593 (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) {
594 return req_pull_ucs2(bufinfo, dest, src, byte_len, flags);
597 return req_pull_ascii(bufinfo, dest, src, byte_len, flags);
602 pull a ASCII4 string buffer from a request packet, returning a talloced string
604 an ASCII4 buffer is a null terminated string that has a prefix
605 of the character 0x4. It tends to be used in older parts of the protocol.
607 on failure *dest is set to the zero length string. This seems to
608 match win2000 behaviour
610 size_t req_pull_ascii4(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, uint_t flags)
614 if (PTR_DIFF(src, bufinfo->data) + 1 > bufinfo->data_size) {
615 /* win2000 treats this as the empty string! */
616 (*dest) = talloc_strdup(bufinfo->mem_ctx, "");
620 /* this consumes the 0x4 byte. We don't check whether the byte
621 is actually 0x4 or not. This matches win2000 server
625 ret = req_pull_string(bufinfo, dest, src, -1, flags);
627 (*dest) = talloc_strdup(bufinfo->mem_ctx, "");
635 pull a DATA_BLOB from a request packet, returning a talloced blob
637 return false if any part is outside the data portion of the packet
639 bool req_pull_blob(struct request_bufinfo *bufinfo, const uint8_t *src, int len, DATA_BLOB *blob)
641 if (len != 0 && req_data_oob(bufinfo, src, len)) {
645 (*blob) = data_blob_talloc(bufinfo->mem_ctx, src, len);
650 /* check that a lump of data in a request is within the bounds of the data section of
652 bool req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count)
658 /* be careful with wraparound! */
659 if ((uintptr_t)ptr < (uintptr_t)bufinfo->data ||
660 (uintptr_t)ptr >= (uintptr_t)bufinfo->data + bufinfo->data_size ||
661 count > bufinfo->data_size ||
662 (uintptr_t)ptr + count > (uintptr_t)bufinfo->data + bufinfo->data_size) {
670 pull an open file handle from a packet, taking account of the chained_fnum
672 static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
674 if (req->chained_fnum != -1) {
675 return req->chained_fnum;
677 return SVAL(base, offset);
680 struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
682 struct smbsrv_handle *handle;
683 uint16_t fnum = req_fnum(req, base, offset);
685 handle = smbsrv_smb_handle_find(req->tcon, fnum, req->request_time);
691 * For SMB tcons and sessions can be mixed!
692 * But we need to make sure that file handles
693 * are only accessed by the opening session!
695 * So check if the handle is valid for the given session!
697 if (handle->session != req->session) {
701 return handle->ntvfs;
704 void smbsrv_push_fnum(uint8_t *base, uint_t offset, struct ntvfs_handle *ntvfs)
706 struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
707 struct smbsrv_handle);
708 SSVAL(base, offset, handle->hid);
711 NTSTATUS smbsrv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
713 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
714 struct smbsrv_request);
715 struct smbsrv_handle *handle;
716 struct ntvfs_handle *h;
718 handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
719 if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
721 h = talloc_zero(handle, struct ntvfs_handle);
725 * note: we don't set handle->ntvfs yet,
726 * this will be done by smbsrv_handle_make_valid()
727 * this makes sure the handle is invalid for clients
728 * until the ntvfs subsystem has made it valid
731 h->session_info = ntvfs->session_info;
732 h->smbpid = ntvfs->smbpid;
734 h->frontend_data.private_data = handle;
740 return NT_STATUS_NO_MEMORY;
743 NTSTATUS smbsrv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
745 struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
746 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
747 struct smbsrv_handle);
748 /* this tells the frontend that the handle is valid */
750 /* this moves the smbsrv_request to the smbsrv_tcon memory context */
751 talloc_steal(tcon, handle);
755 void smbsrv_handle_destroy(void *private_data, struct ntvfs_handle *h)
757 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
758 struct smbsrv_handle);
762 struct ntvfs_handle *smbsrv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
764 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
765 struct smbsrv_request);
767 if (key->length != 2) return NULL;
769 return smbsrv_pull_fnum(req, key->data, 0);
772 DATA_BLOB smbsrv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
776 smbsrv_push_fnum(key, 0, handle);
778 return data_blob_talloc(mem_ctx, key, sizeof(key));