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"
32 /* we over allocate the data buffer to prevent too many realloc calls */
33 #define REQ_OVER_ALLOCATION 0
35 static int smbsrv_request_destructor(struct smbsrv_request *req)
37 DLIST_REMOVE(req->smb_conn->requests, req);
41 /****************************************************************************
42 construct a basic request packet, mostly used to construct async packets
43 such as change notify and oplock break requests
44 ****************************************************************************/
45 struct smbsrv_request *smbsrv_init_request(struct smbsrv_connection *smb_conn)
47 struct smbsrv_request *req;
49 req = talloc_zero(smb_conn, struct smbsrv_request);
54 /* setup the request context */
55 req->smb_conn = smb_conn;
57 talloc_set_destructor(req, smbsrv_request_destructor);
64 setup a chained reply in req->out with the given word count and initial data buffer size.
66 static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
68 uint32_t chain_base_size = req->out.size;
70 /* we need room for the wct value, the words, the buffer length and the buffer */
71 req->out.size += 1 + VWV(wct) + 2 + buflen;
73 /* over allocate by a small amount */
74 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
76 req->out.buffer = talloc_realloc(req, req->out.buffer,
77 uint8_t, req->out.allocated);
78 if (!req->out.buffer) {
79 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
83 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
84 req->out.vwv = req->out.buffer + chain_base_size + 1;
86 req->out.data = req->out.vwv + VWV(wct) + 2;
87 req->out.data_size = buflen;
88 req->out.ptr = req->out.data;
90 SCVAL(req->out.buffer, chain_base_size, wct);
91 SSVAL(req->out.vwv, VWV(wct), buflen);
96 setup a reply in req->out with the given word count and initial data buffer size.
97 the caller will then fill in the command words and data before calling req_send_reply() to
98 send the reply on its way
100 void smbsrv_setup_reply(struct smbsrv_request *req, uint_t wct, size_t buflen)
104 if (req->chain_count != 0) {
105 req_setup_chain_reply(req, wct, buflen);
109 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + buflen;
111 /* over allocate by a small amount */
112 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
114 req->out.buffer = talloc_size(req, req->out.allocated);
115 if (!req->out.buffer) {
116 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
120 flags2 = FLAGS2_LONG_PATH_COMPONENTS |
121 FLAGS2_EXTENDED_ATTRIBUTES |
123 flags2 |= (req->flags2 & (FLAGS2_UNICODE_STRINGS|FLAGS2_EXTENDED_SECURITY));
124 if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
125 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
128 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
129 req->out.vwv = req->out.hdr + HDR_VWV;
131 req->out.data = req->out.vwv + VWV(wct) + 2;
132 req->out.data_size = buflen;
133 req->out.ptr = req->out.data;
135 SIVAL(req->out.hdr, HDR_RCLS, 0);
137 SCVAL(req->out.hdr, HDR_WCT, wct);
138 SSVAL(req->out.vwv, VWV(wct), buflen);
140 memcpy(req->out.hdr, "\377SMB", 4);
141 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
142 SSVAL(req->out.hdr,HDR_FLG2, flags2);
143 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
144 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
147 /* copy the cmd, tid, pid, uid and mid from the request */
148 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
149 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
150 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
151 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
152 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
154 SCVAL(req->out.hdr,HDR_COM,0);
155 SSVAL(req->out.hdr,HDR_TID,0);
156 SSVAL(req->out.hdr,HDR_PID,0);
157 SSVAL(req->out.hdr,HDR_UID,0);
158 SSVAL(req->out.hdr,HDR_MID,0);
164 setup a copy of a request, used when the server needs to send
165 more than one reply for a single request packet
167 struct smbsrv_request *smbsrv_setup_secondary_request(struct smbsrv_request *old_req)
169 struct smbsrv_request *req;
172 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
177 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
178 if (req->out.buffer == NULL) {
183 diff = req->out.buffer - old_req->out.buffer;
185 req->out.hdr += diff;
186 req->out.vwv += diff;
187 req->out.data += diff;
188 req->out.ptr += diff;
194 work out the maximum data size we will allow for this reply, given
195 the negotiated max_xmit. The basic reply packet must be setup before
198 note that this is deliberately a signed integer reply
200 int req_max_data(struct smbsrv_request *req)
203 ret = req->smb_conn->negotiate.max_send;
204 ret -= PTR_DIFF(req->out.data, req->out.hdr);
205 if (ret < 0) ret = 0;
211 grow the allocation of the data buffer portion of a reply
212 packet. Note that as this can reallocate the packet buffer this
213 invalidates any local pointers into the packet.
215 To cope with this req->out.ptr is supplied. This will be updated to
216 point at the same offset into the packet as before this call
218 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
223 delta = new_size - req->out.data_size;
224 if (delta + req->out.size <= req->out.allocated) {
225 /* it fits in the preallocation */
229 /* we need to realloc */
230 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
231 buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
233 smb_panic("out of memory in req_grow_allocation");
236 if (buf2 == req->out.buffer) {
237 /* the malloc library gave us the same pointer */
241 /* update the pointers into the packet */
242 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
243 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
244 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
245 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
247 req->out.buffer = buf2;
252 grow the data buffer portion of a reply packet. Note that as this
253 can reallocate the packet buffer this invalidates any local pointers
256 To cope with this req->out.ptr is supplied. This will be updated to
257 point at the same offset into the packet as before this call
259 void req_grow_data(struct smbsrv_request *req, size_t new_size)
263 if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
264 smb_panic("reply buffer too large!");
267 req_grow_allocation(req, new_size);
269 delta = new_size - req->out.data_size;
271 req->out.size += delta;
272 req->out.data_size += delta;
274 /* set the BCC to the new data size */
275 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
279 send a reply and destroy the request buffer
281 note that this only looks at req->out.buffer and req->out.size, allowing manually
282 constructed packets to be sent
284 void smbsrv_send_reply_nosign(struct smbsrv_request *req)
289 if (req->smb_conn->connection->event.fde == NULL) {
290 /* we are in the process of shutting down this connection */
295 if (req->out.size > NBT_HDR_SIZE) {
296 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
299 blob = data_blob_const(req->out.buffer, req->out.size);
300 status = packet_send(req->smb_conn->packet, blob);
301 if (!NT_STATUS_IS_OK(status)) {
302 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
308 possibly sign a message then send a reply and destroy the request buffer
310 note that this only looks at req->out.buffer and req->out.size, allowing manually
311 constructed packets to be sent
313 void smbsrv_send_reply(struct smbsrv_request *req)
315 if (req->smb_conn->connection->event.fde == NULL) {
316 /* we are in the process of shutting down this connection */
320 smbsrv_sign_packet(req);
322 smbsrv_send_reply_nosign(req);
326 setup the header of a reply to include an NTSTATUS code
328 void smbsrv_setup_error(struct smbsrv_request *req, NTSTATUS status)
330 if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
331 /* convert to DOS error codes */
334 ntstatus_to_dos(status, &eclass, &ecode);
335 SCVAL(req->out.hdr, HDR_RCLS, eclass);
336 SSVAL(req->out.hdr, HDR_ERR, ecode);
337 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
341 if (NT_STATUS_IS_DOS(status)) {
342 /* its a encoded DOS error, using the reserved range */
343 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
344 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
345 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
347 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
348 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
353 construct and send an error packet, then destroy the request
354 auto-converts to DOS error format when appropriate
356 void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status)
358 if (req->smb_conn->connection->event.fde == NULL) {
359 /* the socket has been destroyed - no point trying to send an error! */
363 smbsrv_setup_reply(req, 0, 0);
365 /* error returns never have any data */
366 req_grow_data(req, 0);
368 smbsrv_setup_error(req, status);
369 smbsrv_send_reply(req);
374 push a string into the data portion of the request packet, growing it if necessary
375 this gets quite tricky - please be very careful to cover all cases when modifying this
377 if dest is NULL, then put the string at the end of the data portion of the packet
379 if dest_len is -1 then no limit applies
381 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, size_t flags)
386 const int max_bytes_per_char = 3;
388 if (!(flags & (STR_ASCII|STR_UNICODE))) {
389 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
393 dest = req->out.data + req->out.data_size;
396 if (dest_len != -1) {
399 len = (strlen(str)+2) * max_bytes_per_char;
402 grow_size = len + PTR_DIFF(dest, req->out.data);
403 buf0 = req->out.buffer;
405 req_grow_allocation(req, grow_size);
407 if (buf0 != req->out.buffer) {
408 dest = req->out.buffer + PTR_DIFF(dest, buf0);
411 len = push_string(dest, str, len, flags);
413 grow_size = len + PTR_DIFF(dest, req->out.data);
415 if (grow_size > req->out.data_size) {
416 req_grow_data(req, grow_size);
423 append raw bytes into the data portion of the request packet
424 return the number of bytes added
426 size_t req_append_bytes(struct smbsrv_request *req,
427 const uint8_t *bytes, size_t byte_len)
429 req_grow_allocation(req, byte_len + req->out.data_size);
430 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
431 req_grow_data(req, byte_len + req->out.data_size);
435 append variable block (type 5 buffer) into the data portion of the request packet
436 return the number of bytes added
438 size_t req_append_var_block(struct smbsrv_request *req,
439 const uint8_t *bytes, uint16_t byte_len)
441 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
442 SCVAL(req->out.data + req->out.data_size, 0, 5);
443 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
445 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
447 req_grow_data(req, byte_len + 3 + req->out.data_size);
451 pull a UCS2 string from a request packet, returning a talloced unix string
453 the string length is limited by the 3 things:
454 - the data size in the request (end of packet)
455 - the passed 'byte_len' if it is not -1
456 - the end of string (null termination)
458 Note that 'byte_len' is the number of bytes in the packet
460 on failure zero is returned and *dest is set to NULL, otherwise the number
461 of bytes consumed in the packet is returned
463 static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
465 int src_len, src_len2, alignment=0;
469 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
472 if (byte_len != -1) {
477 if (flags & STR_NO_RANGE_CHECK) {
480 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
481 if (byte_len != -1 && src_len > byte_len) {
491 src_len2 = utf16_len_n(src, src_len);
493 *dest = talloc_strdup(req, "");
494 return src_len2 + alignment;
497 ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
505 return src_len2 + alignment;
509 pull a ascii string from a request packet, returning a talloced string
511 the string length is limited by the 3 things:
512 - the data size in the request (end of packet)
513 - the passed 'byte_len' if it is not -1
514 - the end of string (null termination)
516 Note that 'byte_len' is the number of bytes in the packet
518 on failure zero is returned and *dest is set to NULL, otherwise the number
519 of bytes consumed in the packet is returned
521 static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
523 int src_len, src_len2;
527 if (flags & STR_NO_RANGE_CHECK) {
530 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
535 if (byte_len != -1 && src_len > byte_len) {
540 src_len2 = strnlen((const char *)src, src_len);
541 if (src_len2 <= src_len - 1) {
542 /* include the termination if we didn't reach the end of the packet */
546 ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
558 pull a string from a request packet, returning a talloced string
560 the string length is limited by the 3 things:
561 - the data size in the request (end of packet)
562 - the passed 'byte_len' if it is not -1
563 - the end of string (null termination)
565 Note that 'byte_len' is the number of bytes in the packet
567 on failure zero is returned and *dest is set to NULL, otherwise the number
568 of bytes consumed in the packet is returned
570 size_t req_pull_string(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
572 if (!(flags & STR_ASCII) &&
573 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
574 return req_pull_ucs2(req, dest, src, byte_len, flags);
577 return req_pull_ascii(req, dest, src, byte_len, flags);
582 pull a ASCII4 string buffer from a request packet, returning a talloced string
584 an ASCII4 buffer is a null terminated string that has a prefix
585 of the character 0x4. It tends to be used in older parts of the protocol.
587 on failure *dest is set to the zero length string. This seems to
588 match win2000 behaviour
590 size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const uint8_t *src, uint_t flags)
594 if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
595 /* win2000 treats this as the empty string! */
596 (*dest) = talloc_strdup(req, "");
600 /* this consumes the 0x4 byte. We don't check whether the byte
601 is actually 0x4 or not. This matches win2000 server
605 ret = req_pull_string(req, dest, src, -1, flags);
607 (*dest) = talloc_strdup(req, "");
615 pull a DATA_BLOB from a request packet, returning a talloced blob
617 return False if any part is outside the data portion of the packet
619 BOOL req_pull_blob(struct smbsrv_request *req, const uint8_t *src, int len, DATA_BLOB *blob)
621 if (len != 0 && req_data_oob(req, src, len)) {
625 (*blob) = data_blob_talloc(req, src, len);
630 /* check that a lump of data in a request is within the bounds of the data section of
632 BOOL req_data_oob(struct smbsrv_request *req, const uint8_t *ptr, uint32_t count)
638 /* be careful with wraparound! */
639 if (ptr < req->in.data ||
640 ptr >= req->in.data + req->in.data_size ||
641 count > req->in.data_size ||
642 ptr + count > req->in.data + req->in.data_size) {
650 pull an open file handle from a packet, taking account of the chained_fnum
652 static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
654 if (req->chained_fnum != -1) {
655 return req->chained_fnum;
657 return SVAL(base, offset);
660 struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
662 struct smbsrv_handle *handle;
663 uint16_t fnum = req_fnum(req, base, offset);
665 handle = smbsrv_smb_handle_find(req->tcon, fnum, req->request_time);
671 * For SMB tcons and sessions can be mixed!
672 * But we need to make sure that file handles
673 * are only accessed by the opening session!
675 * So check if the handle is valid for the given session!
677 if (handle->session != req->session) {
681 return handle->ntvfs;
684 void smbsrv_push_fnum(uint8_t *base, uint_t offset, struct ntvfs_handle *ntvfs)
686 struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
687 struct smbsrv_handle);
688 SSVAL(base, offset, handle->hid);
691 NTSTATUS smbsrv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
693 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
694 struct smbsrv_request);
695 struct smbsrv_handle *handle;
696 struct ntvfs_handle *h;
698 handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
699 if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
701 h = talloc_zero(handle, struct ntvfs_handle);
705 * note: we don't set handle->ntvfs yet,
706 * this will be done by smbsrv_handle_make_valid()
707 * this makes sure the handle is invalid for clients
708 * until the ntvfs subsystem has made it valid
711 h->session_info = ntvfs->session_info;
712 h->smbpid = ntvfs->smbpid;
714 h->frontend_data.private_data = handle;
720 return NT_STATUS_NO_MEMORY;
723 NTSTATUS smbsrv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
725 struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
726 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
727 struct smbsrv_handle);
728 /* this tells the frontend that the handle is valid */
730 /* this moves the smbsrv_request to the smbsrv_tcon memory context */
731 talloc_steal(tcon, handle);
735 void smbsrv_handle_destroy(void *private_data, struct ntvfs_handle *h)
737 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
738 struct smbsrv_handle);
742 struct ntvfs_handle *smbsrv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
744 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
745 struct smbsrv_request);
747 if (key->length != 2) return NULL;
749 return smbsrv_pull_fnum(req, key->data, 0);
752 DATA_BLOB smbsrv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
756 smbsrv_push_fnum(key, 0, handle);
758 return data_blob_talloc(mem_ctx, key, sizeof(key));