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 "lib/events/events.h"
27 #include "dlinklist.h"
28 #include "smb_server/smb_server.h"
29 #include "smbd/service_stream.h"
30 #include "lib/stream/packet.h"
33 /* we over allocate the data buffer to prevent too many realloc calls */
34 #define REQ_OVER_ALLOCATION 0
36 /* destroy a request structure */
37 void req_destroy(struct smbsrv_request *req)
39 /* ahh, its so nice to destroy a complex structure in such a
44 /****************************************************************************
45 construct a basic request packet, mostly used to construct async packets
46 such as change notify and oplock break requests
47 ****************************************************************************/
48 struct smbsrv_request *init_smb_request(struct smbsrv_connection *smb_conn)
50 struct smbsrv_request *req;
52 req = talloc(smb_conn, struct smbsrv_request);
59 /* setup the request context */
60 req->smb_conn = smb_conn;
62 req->async_states = talloc(req, struct ntvfs_async_state);
63 if (!req->async_states) {
67 req->async_states->state = 0;
74 setup a chained reply in req->out with the given word count and initial data buffer size.
76 static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
78 uint32_t chain_base_size = req->out.size;
80 /* we need room for the wct value, the words, the buffer length and the buffer */
81 req->out.size += 1 + VWV(wct) + 2 + buflen;
83 /* over allocate by a small amount */
84 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
86 req->out.buffer = talloc_realloc(req, req->out.buffer,
87 uint8_t, req->out.allocated);
88 if (!req->out.buffer) {
89 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
93 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
94 req->out.vwv = req->out.buffer + chain_base_size + 1;
96 req->out.data = req->out.vwv + VWV(wct) + 2;
97 req->out.data_size = buflen;
98 req->out.ptr = req->out.data;
100 SCVAL(req->out.buffer, chain_base_size, wct);
101 SSVAL(req->out.vwv, VWV(wct), buflen);
106 setup a reply in req->out with the given word count and initial data buffer size.
107 the caller will then fill in the command words and data before calling req_send_reply() to
108 send the reply on its way
110 void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
114 if (req->chain_count != 0) {
115 req_setup_chain_reply(req, wct, buflen);
119 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen;
121 /* over allocate by a small amount */
122 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
124 req->out.buffer = talloc_size(req, req->out.allocated);
125 if (!req->out.buffer) {
126 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
130 flags2 = FLAGS2_LONG_PATH_COMPONENTS |
131 FLAGS2_EXTENDED_ATTRIBUTES |
133 flags2 |= (req->flags2 & (FLAGS2_UNICODE_STRINGS|FLAGS2_EXTENDED_SECURITY));
134 if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
135 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
138 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
139 req->out.vwv = req->out.hdr + HDR_VWV;
141 req->out.data = req->out.vwv + VWV(wct) + 2;
142 req->out.data_size = buflen;
143 req->out.ptr = req->out.data;
145 SIVAL(req->out.hdr, HDR_RCLS, 0);
147 SCVAL(req->out.hdr, HDR_WCT, wct);
148 SSVAL(req->out.vwv, VWV(wct), buflen);
150 memcpy(req->out.hdr, "\377SMB", 4);
151 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
152 SSVAL(req->out.hdr,HDR_FLG2, flags2);
153 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
154 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
157 /* copy the cmd, tid, pid, uid and mid from the request */
158 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
159 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
160 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
161 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
162 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
164 SSVAL(req->out.hdr,HDR_TID,0);
165 SSVAL(req->out.hdr,HDR_PID,0);
166 SSVAL(req->out.hdr,HDR_UID,0);
167 SSVAL(req->out.hdr,HDR_MID,0);
173 setup a copy of a request, used when the server needs to send
174 more than one reply for a single request packet
176 struct smbsrv_request *req_setup_secondary(struct smbsrv_request *old_req)
178 struct smbsrv_request *req;
181 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
186 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
187 if (req->out.buffer == NULL) {
192 diff = req->out.buffer - old_req->out.buffer;
194 req->out.hdr += diff;
195 req->out.vwv += diff;
196 req->out.data += diff;
197 req->out.ptr += diff;
203 work out the maximum data size we will allow for this reply, given
204 the negotiated max_xmit. The basic reply packet must be setup before
207 note that this is deliberately a signed integer reply
209 int req_max_data(struct smbsrv_request *req)
212 ret = req->smb_conn->negotiate.max_send;
213 ret -= PTR_DIFF(req->out.data, req->out.hdr);
214 if (ret < 0) ret = 0;
220 grow the allocation of the data buffer portion of a reply
221 packet. Note that as this can reallocate the packet buffer this
222 invalidates any local pointers into the packet.
224 To cope with this req->out.ptr is supplied. This will be updated to
225 point at the same offset into the packet as before this call
227 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
232 delta = new_size - req->out.data_size;
233 if (delta + req->out.size <= req->out.allocated) {
234 /* it fits in the preallocation */
238 /* we need to realloc */
239 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
240 buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
242 smb_panic("out of memory in req_grow_allocation");
245 if (buf2 == req->out.buffer) {
246 /* the malloc library gave us the same pointer */
250 /* update the pointers into the packet */
251 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
252 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
253 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
254 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
256 req->out.buffer = buf2;
261 grow the data buffer portion of a reply packet. Note that as this
262 can reallocate the packet buffer this invalidates any local pointers
265 To cope with this req->out.ptr is supplied. This will be updated to
266 point at the same offset into the packet as before this call
268 void req_grow_data(struct smbsrv_request *req, uint_t new_size)
272 if (!(req->control_flags & REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
273 smb_panic("reply buffer too large!");
276 req_grow_allocation(req, new_size);
278 delta = new_size - req->out.data_size;
280 req->out.size += delta;
281 req->out.data_size += delta;
283 /* set the BCC to the new data size */
284 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
288 send a reply and destroy the request buffer
290 note that this only looks at req->out.buffer and req->out.size, allowing manually
291 constructed packets to be sent
293 void req_send_reply_nosign(struct smbsrv_request *req)
298 if (req->out.size > NBT_HDR_SIZE) {
299 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
302 blob = data_blob_const(req->out.buffer, req->out.size);
303 status = packet_send(req->smb_conn->packet, blob);
304 if (!NT_STATUS_IS_OK(status)) {
305 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
311 possibly sign a message then send a reply and destroy the request buffer
313 note that this only looks at req->out.buffer and req->out.size, allowing manually
314 constructed packets to be sent
316 void req_send_reply(struct smbsrv_request *req)
318 req_sign_packet(req);
320 req_send_reply_nosign(req);
326 construct and send an error packet with a forced DOS error code
327 this is needed to match win2000 behaviour for some parts of the protocol
329 void req_reply_dos_error(struct smbsrv_request *req, uint8_t eclass, uint16_t ecode)
331 /* if the basic packet hasn't been setup yet then do it now */
332 if (req->out.buffer == NULL) {
333 req_setup_reply(req, 0, 0);
336 SCVAL(req->out.hdr, HDR_RCLS, eclass);
337 SSVAL(req->out.hdr, HDR_ERR, ecode);
338 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
343 setup the header of a reply to include an NTSTATUS code
345 void req_setup_error(struct smbsrv_request *req, NTSTATUS status)
347 if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
348 /* convert to DOS error codes */
351 ntstatus_to_dos(status, &eclass, &ecode);
352 SCVAL(req->out.hdr, HDR_RCLS, eclass);
353 SSVAL(req->out.hdr, HDR_ERR, ecode);
354 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
358 if (NT_STATUS_IS_DOS(status)) {
359 /* its a encoded DOS error, using the reserved range */
360 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
361 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
362 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
364 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
365 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
370 construct and send an error packet, then destroy the request
371 auto-converts to DOS error format when appropriate
373 void req_reply_error(struct smbsrv_request *req, NTSTATUS status)
375 if (req->smb_conn->connection->event.fde == NULL) {
376 /* the socket has been destroyed - no point trying to send an error! */
380 req_setup_reply(req, 0, 0);
382 /* error returns never have any data */
383 req_grow_data(req, 0);
385 req_setup_error(req, status);
391 push a string into the data portion of the request packet, growing it if necessary
392 this gets quite tricky - please be very careful to cover all cases when modifying this
394 if dest is NULL, then put the string at the end of the data portion of the packet
396 if dest_len is -1 then no limit applies
398 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, uint_t flags)
403 const int max_bytes_per_char = 3;
405 if (!(flags & (STR_ASCII|STR_UNICODE))) {
406 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
410 dest = req->out.data + req->out.data_size;
413 if (dest_len != -1) {
416 len = (strlen(str)+2) * max_bytes_per_char;
419 grow_size = len + PTR_DIFF(dest, req->out.data);
420 buf0 = req->out.buffer;
422 req_grow_allocation(req, grow_size);
424 if (buf0 != req->out.buffer) {
425 dest = req->out.buffer + PTR_DIFF(dest, buf0);
428 len = push_string(dest, str, len, flags);
430 grow_size = len + PTR_DIFF(dest, req->out.data);
432 if (grow_size > req->out.data_size) {
433 req_grow_data(req, grow_size);
440 append raw bytes into the data portion of the request packet
441 return the number of bytes added
443 size_t req_append_bytes(struct smbsrv_request *req,
444 const uint8_t *bytes, size_t byte_len)
446 req_grow_allocation(req, byte_len + req->out.data_size);
447 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
448 req_grow_data(req, byte_len + req->out.data_size);
452 append variable block (type 5 buffer) into the data portion of the request packet
453 return the number of bytes added
455 size_t req_append_var_block(struct smbsrv_request *req,
456 const uint8_t *bytes, uint16_t byte_len)
458 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
459 SCVAL(req->out.data + req->out.data_size, 0, 5);
460 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
462 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
464 req_grow_data(req, byte_len + 3 + req->out.data_size);
468 pull a UCS2 string from a request packet, returning a talloced unix string
470 the string length is limited by the 3 things:
471 - the data size in the request (end of packet)
472 - the passed 'byte_len' if it is not -1
473 - the end of string (null termination)
475 Note that 'byte_len' is the number of bytes in the packet
477 on failure zero is returned and *dest is set to NULL, otherwise the number
478 of bytes consumed in the packet is returned
480 static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
482 int src_len, src_len2, alignment=0;
486 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
489 if (byte_len != -1) {
494 if (flags & STR_NO_RANGE_CHECK) {
497 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
498 if (byte_len != -1 && src_len > byte_len) {
508 src_len2 = utf16_len_n(src, src_len);
510 *dest = talloc_strdup(req, "");
511 return src_len2 + alignment;
514 ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
522 return src_len2 + alignment;
526 pull a ascii string from a request packet, returning a talloced string
528 the string length is limited by the 3 things:
529 - the data size in the request (end of packet)
530 - the passed 'byte_len' if it is not -1
531 - the end of string (null termination)
533 Note that 'byte_len' is the number of bytes in the packet
535 on failure zero is returned and *dest is set to NULL, otherwise the number
536 of bytes consumed in the packet is returned
538 static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
540 int src_len, src_len2;
544 if (flags & STR_NO_RANGE_CHECK) {
547 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
552 if (byte_len != -1 && src_len > byte_len) {
557 src_len2 = strnlen((const char *)src, src_len);
558 if (src_len2 <= src_len - 1) {
559 /* include the termination if we didn't reach the end of the packet */
563 ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
575 pull a string from a request packet, returning a talloced string
577 the string length is limited by the 3 things:
578 - the data size in the request (end of packet)
579 - the passed 'byte_len' if it is not -1
580 - the end of string (null termination)
582 Note that 'byte_len' is the number of bytes in the packet
584 on failure zero is returned and *dest is set to NULL, otherwise the number
585 of bytes consumed in the packet is returned
587 size_t req_pull_string(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
589 if (!(flags & STR_ASCII) &&
590 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
591 return req_pull_ucs2(req, dest, src, byte_len, flags);
594 return req_pull_ascii(req, dest, src, byte_len, flags);
599 pull a ASCII4 string buffer from a request packet, returning a talloced string
601 an ASCII4 buffer is a null terminated string that has a prefix
602 of the character 0x4. It tends to be used in older parts of the protocol.
604 on failure *dest is set to the zero length string. This seems to
605 match win2000 behaviour
607 size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const uint8_t *src, uint_t flags)
611 if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
612 /* win2000 treats this as the NULL string! */
613 (*dest) = talloc_strdup(req, "");
617 /* this consumes the 0x4 byte. We don't check whether the byte
618 is actually 0x4 or not. This matches win2000 server
622 ret = req_pull_string(req, dest, src, -1, flags);
624 (*dest) = talloc_strdup(req, "");
632 pull a DATA_BLOB from a request packet, returning a talloced blob
634 return False if any part is outside the data portion of the packet
636 BOOL req_pull_blob(struct smbsrv_request *req, const uint8_t *src, int len, DATA_BLOB *blob)
638 if (len != 0 && req_data_oob(req, src, len)) {
642 (*blob) = data_blob_talloc(req, src, len);
647 /* check that a lump of data in a request is within the bounds of the data section of
649 BOOL req_data_oob(struct smbsrv_request *req, const uint8_t *ptr, uint32_t count)
655 /* be careful with wraparound! */
656 if (ptr < req->in.data ||
657 ptr >= req->in.data + req->in.data_size ||
658 count > req->in.data_size ||
659 ptr + count > req->in.data + req->in.data_size) {
667 pull an open file handle from a packet, taking account of the chained_fnum
669 uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
671 if (req->chained_fnum != -1) {
672 return req->chained_fnum;
674 return SVAL(base, offset);