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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 this file implements functions for manipulating the 'struct smbsrv_request' structure in smbd
26 #include "smb_server/smb_server.h"
27 #include "smb_server/service_smb_proto.h"
28 #include "smbd/service_stream.h"
29 #include "lib/stream/packet.h"
30 #include "ntvfs/ntvfs.h"
33 /* we over allocate the data buffer to prevent too many realloc calls */
34 #define REQ_OVER_ALLOCATION 0
36 /****************************************************************************
37 construct a basic request packet, mostly used to construct async packets
38 such as change notify and oplock break requests
39 ****************************************************************************/
40 struct smbsrv_request *smbsrv_init_request(struct smbsrv_connection *smb_conn)
42 struct smbsrv_request *req;
44 req = talloc_zero(smb_conn, struct smbsrv_request);
49 /* setup the request context */
50 req->smb_conn = smb_conn;
57 setup a chained reply in req->out with the given word count and initial data buffer size.
59 static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
61 uint32_t chain_base_size = req->out.size;
63 /* we need room for the wct value, the words, the buffer length and the buffer */
64 req->out.size += 1 + VWV(wct) + 2 + buflen;
66 /* over allocate by a small amount */
67 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
69 req->out.buffer = talloc_realloc(req, req->out.buffer,
70 uint8_t, req->out.allocated);
71 if (!req->out.buffer) {
72 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
76 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
77 req->out.vwv = req->out.buffer + chain_base_size + 1;
79 req->out.data = req->out.vwv + VWV(wct) + 2;
80 req->out.data_size = buflen;
81 req->out.ptr = req->out.data;
83 SCVAL(req->out.buffer, chain_base_size, wct);
84 SSVAL(req->out.vwv, VWV(wct), buflen);
89 setup a reply in req->out with the given word count and initial data buffer size.
90 the caller will then fill in the command words and data before calling req_send_reply() to
91 send the reply on its way
93 void smbsrv_setup_reply(struct smbsrv_request *req, uint_t wct, size_t buflen)
97 if (req->chain_count != 0) {
98 req_setup_chain_reply(req, wct, buflen);
102 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + buflen;
104 /* over allocate by a small amount */
105 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
107 req->out.buffer = talloc_size(req, req->out.allocated);
108 if (!req->out.buffer) {
109 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
113 flags2 = FLAGS2_LONG_PATH_COMPONENTS |
114 FLAGS2_EXTENDED_ATTRIBUTES |
116 flags2 |= (req->flags2 & (FLAGS2_UNICODE_STRINGS|FLAGS2_EXTENDED_SECURITY));
117 if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
118 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
121 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
122 req->out.vwv = req->out.hdr + HDR_VWV;
124 req->out.data = req->out.vwv + VWV(wct) + 2;
125 req->out.data_size = buflen;
126 req->out.ptr = req->out.data;
128 SIVAL(req->out.hdr, HDR_RCLS, 0);
130 SCVAL(req->out.hdr, HDR_WCT, wct);
131 SSVAL(req->out.vwv, VWV(wct), buflen);
133 memcpy(req->out.hdr, "\377SMB", 4);
134 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
135 SSVAL(req->out.hdr,HDR_FLG2, flags2);
136 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
137 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
140 /* copy the cmd, tid, pid, uid and mid from the request */
141 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
142 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
143 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
144 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
145 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
147 SCVAL(req->out.hdr,HDR_COM,0);
148 SSVAL(req->out.hdr,HDR_TID,0);
149 SSVAL(req->out.hdr,HDR_PID,0);
150 SSVAL(req->out.hdr,HDR_UID,0);
151 SSVAL(req->out.hdr,HDR_MID,0);
157 setup a copy of a request, used when the server needs to send
158 more than one reply for a single request packet
160 struct smbsrv_request *smbsrv_setup_secondary_request(struct smbsrv_request *old_req)
162 struct smbsrv_request *req;
165 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
170 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
171 if (req->out.buffer == NULL) {
176 diff = req->out.buffer - old_req->out.buffer;
178 req->out.hdr += diff;
179 req->out.vwv += diff;
180 req->out.data += diff;
181 req->out.ptr += diff;
187 work out the maximum data size we will allow for this reply, given
188 the negotiated max_xmit. The basic reply packet must be setup before
191 note that this is deliberately a signed integer reply
193 int req_max_data(struct smbsrv_request *req)
196 ret = req->smb_conn->negotiate.max_send;
197 ret -= PTR_DIFF(req->out.data, req->out.hdr);
198 if (ret < 0) ret = 0;
204 grow the allocation of the data buffer portion of a reply
205 packet. Note that as this can reallocate the packet buffer this
206 invalidates any local pointers into the packet.
208 To cope with this req->out.ptr is supplied. This will be updated to
209 point at the same offset into the packet as before this call
211 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
216 delta = new_size - req->out.data_size;
217 if (delta + req->out.size <= req->out.allocated) {
218 /* it fits in the preallocation */
222 /* we need to realloc */
223 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
224 buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
226 smb_panic("out of memory in req_grow_allocation");
229 if (buf2 == req->out.buffer) {
230 /* the malloc library gave us the same pointer */
234 /* update the pointers into the packet */
235 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
236 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
237 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
238 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
240 req->out.buffer = buf2;
245 grow the data buffer portion of a reply packet. Note that as this
246 can reallocate the packet buffer this invalidates any local pointers
249 To cope with this req->out.ptr is supplied. This will be updated to
250 point at the same offset into the packet as before this call
252 void req_grow_data(struct smbsrv_request *req, size_t new_size)
256 if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
257 smb_panic("reply buffer too large!");
260 req_grow_allocation(req, new_size);
262 delta = new_size - req->out.data_size;
264 req->out.size += delta;
265 req->out.data_size += delta;
267 /* set the BCC to the new data size */
268 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
272 send a reply and destroy the request buffer
274 note that this only looks at req->out.buffer and req->out.size, allowing manually
275 constructed packets to be sent
277 void smbsrv_send_reply_nosign(struct smbsrv_request *req)
282 if (req->smb_conn->connection->event.fde == NULL) {
283 /* we are in the process of shutting down this connection */
287 if (req->out.size > NBT_HDR_SIZE) {
288 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
291 blob = data_blob_const(req->out.buffer, req->out.size);
292 status = packet_send(req->smb_conn->packet, blob);
293 if (!NT_STATUS_IS_OK(status)) {
294 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
300 possibly sign a message then send a reply and destroy the request buffer
302 note that this only looks at req->out.buffer and req->out.size, allowing manually
303 constructed packets to be sent
305 void smbsrv_send_reply(struct smbsrv_request *req)
307 smbsrv_sign_packet(req);
309 smbsrv_send_reply_nosign(req);
313 setup the header of a reply to include an NTSTATUS code
315 void smbsrv_setup_error(struct smbsrv_request *req, NTSTATUS status)
317 if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
318 /* convert to DOS error codes */
321 ntstatus_to_dos(status, &eclass, &ecode);
322 SCVAL(req->out.hdr, HDR_RCLS, eclass);
323 SSVAL(req->out.hdr, HDR_ERR, ecode);
324 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
328 if (NT_STATUS_IS_DOS(status)) {
329 /* its a encoded DOS error, using the reserved range */
330 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
331 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
332 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
334 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
335 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
340 construct and send an error packet, then destroy the request
341 auto-converts to DOS error format when appropriate
343 void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status)
345 if (req->smb_conn->connection->event.fde == NULL) {
346 /* the socket has been destroyed - no point trying to send an error! */
350 smbsrv_setup_reply(req, 0, 0);
352 /* error returns never have any data */
353 req_grow_data(req, 0);
355 smbsrv_setup_error(req, status);
356 smbsrv_send_reply(req);
361 push a string into the data portion of the request packet, growing it if necessary
362 this gets quite tricky - please be very careful to cover all cases when modifying this
364 if dest is NULL, then put the string at the end of the data portion of the packet
366 if dest_len is -1 then no limit applies
368 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, size_t flags)
373 const int max_bytes_per_char = 3;
375 if (!(flags & (STR_ASCII|STR_UNICODE))) {
376 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
380 dest = req->out.data + req->out.data_size;
383 if (dest_len != -1) {
386 len = (strlen(str)+2) * max_bytes_per_char;
389 grow_size = len + PTR_DIFF(dest, req->out.data);
390 buf0 = req->out.buffer;
392 req_grow_allocation(req, grow_size);
394 if (buf0 != req->out.buffer) {
395 dest = req->out.buffer + PTR_DIFF(dest, buf0);
398 len = push_string(dest, str, len, flags);
400 grow_size = len + PTR_DIFF(dest, req->out.data);
402 if (grow_size > req->out.data_size) {
403 req_grow_data(req, grow_size);
410 append raw bytes into the data portion of the request packet
411 return the number of bytes added
413 size_t req_append_bytes(struct smbsrv_request *req,
414 const uint8_t *bytes, size_t byte_len)
416 req_grow_allocation(req, byte_len + req->out.data_size);
417 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
418 req_grow_data(req, byte_len + req->out.data_size);
422 append variable block (type 5 buffer) into the data portion of the request packet
423 return the number of bytes added
425 size_t req_append_var_block(struct smbsrv_request *req,
426 const uint8_t *bytes, uint16_t byte_len)
428 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
429 SCVAL(req->out.data + req->out.data_size, 0, 5);
430 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
432 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
434 req_grow_data(req, byte_len + 3 + req->out.data_size);
438 pull a UCS2 string from a request packet, returning a talloced unix string
440 the string length is limited by the 3 things:
441 - the data size in the request (end of packet)
442 - the passed 'byte_len' if it is not -1
443 - the end of string (null termination)
445 Note that 'byte_len' is the number of bytes in the packet
447 on failure zero is returned and *dest is set to NULL, otherwise the number
448 of bytes consumed in the packet is returned
450 static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
452 int src_len, src_len2, alignment=0;
456 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
459 if (byte_len != -1) {
464 if (flags & STR_NO_RANGE_CHECK) {
467 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
468 if (byte_len != -1 && src_len > byte_len) {
478 src_len2 = utf16_len_n(src, src_len);
480 *dest = talloc_strdup(req, "");
481 return src_len2 + alignment;
484 ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
492 return src_len2 + alignment;
496 pull a ascii string from a request packet, returning a talloced string
498 the string length is limited by the 3 things:
499 - the data size in the request (end of packet)
500 - the passed 'byte_len' if it is not -1
501 - the end of string (null termination)
503 Note that 'byte_len' is the number of bytes in the packet
505 on failure zero is returned and *dest is set to NULL, otherwise the number
506 of bytes consumed in the packet is returned
508 static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
510 int src_len, src_len2;
514 if (flags & STR_NO_RANGE_CHECK) {
517 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
522 if (byte_len != -1 && src_len > byte_len) {
527 src_len2 = strnlen((const char *)src, src_len);
528 if (src_len2 <= src_len - 1) {
529 /* include the termination if we didn't reach the end of the packet */
533 ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
545 pull a string from a request packet, returning a talloced string
547 the string length is limited by the 3 things:
548 - the data size in the request (end of packet)
549 - the passed 'byte_len' if it is not -1
550 - the end of string (null termination)
552 Note that 'byte_len' is the number of bytes in the packet
554 on failure zero is returned and *dest is set to NULL, otherwise the number
555 of bytes consumed in the packet is returned
557 size_t req_pull_string(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
559 if (!(flags & STR_ASCII) &&
560 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
561 return req_pull_ucs2(req, dest, src, byte_len, flags);
564 return req_pull_ascii(req, dest, src, byte_len, flags);
569 pull a ASCII4 string buffer from a request packet, returning a talloced string
571 an ASCII4 buffer is a null terminated string that has a prefix
572 of the character 0x4. It tends to be used in older parts of the protocol.
574 on failure *dest is set to the zero length string. This seems to
575 match win2000 behaviour
577 size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const uint8_t *src, uint_t flags)
581 if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
582 /* win2000 treats this as the empty string! */
583 (*dest) = talloc_strdup(req, "");
587 /* this consumes the 0x4 byte. We don't check whether the byte
588 is actually 0x4 or not. This matches win2000 server
592 ret = req_pull_string(req, dest, src, -1, flags);
594 (*dest) = talloc_strdup(req, "");
602 pull a DATA_BLOB from a request packet, returning a talloced blob
604 return False if any part is outside the data portion of the packet
606 BOOL req_pull_blob(struct smbsrv_request *req, const uint8_t *src, int len, DATA_BLOB *blob)
608 if (len != 0 && req_data_oob(req, src, len)) {
612 (*blob) = data_blob_talloc(req, src, len);
617 /* check that a lump of data in a request is within the bounds of the data section of
619 BOOL req_data_oob(struct smbsrv_request *req, const uint8_t *ptr, uint32_t count)
625 /* be careful with wraparound! */
626 if (ptr < req->in.data ||
627 ptr >= req->in.data + req->in.data_size ||
628 count > req->in.data_size ||
629 ptr + count > req->in.data + req->in.data_size) {
637 pull an open file handle from a packet, taking account of the chained_fnum
639 static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
641 if (req->chained_fnum != -1) {
642 return req->chained_fnum;
644 return SVAL(base, offset);
647 struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
649 struct smbsrv_handle *handle;
650 uint16_t fnum = req_fnum(req, base, offset);
652 handle = smbsrv_smb_handle_find(req->tcon, fnum, req->request_time);
657 return handle->ntvfs;
660 void smbsrv_push_fnum(uint8_t *base, uint_t offset, struct ntvfs_handle *ntvfs)
662 struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
663 struct smbsrv_handle);
664 SSVAL(base, offset, handle->hid);
667 NTSTATUS smbsrv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
669 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
670 struct smbsrv_request);
671 struct smbsrv_handle *handle;
672 struct ntvfs_handle *h;
674 handle = smbsrv_handle_new(req);
675 if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
677 h = talloc_zero(handle, struct ntvfs_handle);
681 * note: we don't set handle->ntvfs yet,
682 * this will be done by smbsrv_handle_make_valid()
683 * this makes sure the handle is invalid for clients
684 * until the ntvfs subsystem has made it valid
687 h->session_info = ntvfs->session_info;
688 h->smbpid = ntvfs->smbpid;
690 h->frontend_data.private_data = handle;
696 return NT_STATUS_NO_MEMORY;
699 NTSTATUS smbsrv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
701 struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
702 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
703 struct smbsrv_handle);
704 /* this tells the frontend that the handle is valid */
706 /* this moves the smbsrv_request to the smbsrv_tcon memory context */
707 talloc_steal(tcon, handle);
711 void smbsrv_handle_destroy(void *private_data, struct ntvfs_handle *h)
713 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
714 struct smbsrv_handle);
718 struct ntvfs_handle *smbsrv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
720 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
721 struct smbsrv_request);
723 if (key->length != 2) return NULL;
725 return smbsrv_pull_fnum(req, key->data, 0);
728 DATA_BLOB smbsrv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
732 smbsrv_push_fnum(key, 0, handle);
734 return data_blob_talloc(mem_ctx, key, sizeof(key));