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"
31 #include "ntvfs/ntvfs.h"
34 /* we over allocate the data buffer to prevent too many realloc calls */
35 #define REQ_OVER_ALLOCATION 0
37 /* destroy a request structure */
38 void req_destroy(struct smbsrv_request *req)
40 /* ahh, its so nice to destroy a complex structure in such a
45 /****************************************************************************
46 construct a basic request packet, mostly used to construct async packets
47 such as change notify and oplock break requests
48 ****************************************************************************/
49 struct smbsrv_request *init_smb_request(struct smbsrv_connection *smb_conn)
51 struct smbsrv_request *req;
53 req = talloc(smb_conn, struct smbsrv_request);
60 /* setup the request context */
61 req->smb_conn = smb_conn;
63 req->async_states = talloc(req, struct ntvfs_async_state);
64 if (!req->async_states) {
68 req->async_states->state = 0;
75 setup a chained reply in req->out with the given word count and initial data buffer size.
77 static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
79 uint32_t chain_base_size = req->out.size;
81 /* we need room for the wct value, the words, the buffer length and the buffer */
82 req->out.size += 1 + VWV(wct) + 2 + buflen;
84 /* over allocate by a small amount */
85 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
87 req->out.buffer = talloc_realloc(req, req->out.buffer,
88 uint8_t, req->out.allocated);
89 if (!req->out.buffer) {
90 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
94 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
95 req->out.vwv = req->out.buffer + chain_base_size + 1;
97 req->out.data = req->out.vwv + VWV(wct) + 2;
98 req->out.data_size = buflen;
99 req->out.ptr = req->out.data;
101 SCVAL(req->out.buffer, chain_base_size, wct);
102 SSVAL(req->out.vwv, VWV(wct), buflen);
107 setup a reply in req->out with the given word count and initial data buffer size.
108 the caller will then fill in the command words and data before calling req_send_reply() to
109 send the reply on its way
111 void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
115 if (req->chain_count != 0) {
116 req_setup_chain_reply(req, wct, buflen);
120 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen;
122 /* over allocate by a small amount */
123 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
125 req->out.buffer = talloc_size(req, req->out.allocated);
126 if (!req->out.buffer) {
127 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
131 flags2 = FLAGS2_LONG_PATH_COMPONENTS |
132 FLAGS2_EXTENDED_ATTRIBUTES |
134 flags2 |= (req->flags2 & (FLAGS2_UNICODE_STRINGS|FLAGS2_EXTENDED_SECURITY));
135 if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
136 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
139 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
140 req->out.vwv = req->out.hdr + HDR_VWV;
142 req->out.data = req->out.vwv + VWV(wct) + 2;
143 req->out.data_size = buflen;
144 req->out.ptr = req->out.data;
146 SIVAL(req->out.hdr, HDR_RCLS, 0);
148 SCVAL(req->out.hdr, HDR_WCT, wct);
149 SSVAL(req->out.vwv, VWV(wct), buflen);
151 memcpy(req->out.hdr, "\377SMB", 4);
152 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
153 SSVAL(req->out.hdr,HDR_FLG2, flags2);
154 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
155 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
158 /* copy the cmd, tid, pid, uid and mid from the request */
159 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
160 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
161 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
162 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
163 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
165 SSVAL(req->out.hdr,HDR_TID,0);
166 SSVAL(req->out.hdr,HDR_PID,0);
167 SSVAL(req->out.hdr,HDR_UID,0);
168 SSVAL(req->out.hdr,HDR_MID,0);
174 setup a copy of a request, used when the server needs to send
175 more than one reply for a single request packet
177 struct smbsrv_request *req_setup_secondary(struct smbsrv_request *old_req)
179 struct smbsrv_request *req;
182 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
187 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
188 if (req->out.buffer == NULL) {
193 diff = req->out.buffer - old_req->out.buffer;
195 req->out.hdr += diff;
196 req->out.vwv += diff;
197 req->out.data += diff;
198 req->out.ptr += diff;
204 work out the maximum data size we will allow for this reply, given
205 the negotiated max_xmit. The basic reply packet must be setup before
208 note that this is deliberately a signed integer reply
210 int req_max_data(struct smbsrv_request *req)
213 ret = req->smb_conn->negotiate.max_send;
214 ret -= PTR_DIFF(req->out.data, req->out.hdr);
215 if (ret < 0) ret = 0;
221 grow the allocation of the data buffer portion of a reply
222 packet. Note that as this can reallocate the packet buffer this
223 invalidates any local pointers into the packet.
225 To cope with this req->out.ptr is supplied. This will be updated to
226 point at the same offset into the packet as before this call
228 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
233 delta = new_size - req->out.data_size;
234 if (delta + req->out.size <= req->out.allocated) {
235 /* it fits in the preallocation */
239 /* we need to realloc */
240 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
241 buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
243 smb_panic("out of memory in req_grow_allocation");
246 if (buf2 == req->out.buffer) {
247 /* the malloc library gave us the same pointer */
251 /* update the pointers into the packet */
252 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
253 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
254 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
255 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
257 req->out.buffer = buf2;
262 grow the data buffer portion of a reply packet. Note that as this
263 can reallocate the packet buffer this invalidates any local pointers
266 To cope with this req->out.ptr is supplied. This will be updated to
267 point at the same offset into the packet as before this call
269 void req_grow_data(struct smbsrv_request *req, uint_t new_size)
273 if (!(req->control_flags & REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
274 smb_panic("reply buffer too large!");
277 req_grow_allocation(req, new_size);
279 delta = new_size - req->out.data_size;
281 req->out.size += delta;
282 req->out.data_size += delta;
284 /* set the BCC to the new data size */
285 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
289 send a reply and destroy the request buffer
291 note that this only looks at req->out.buffer and req->out.size, allowing manually
292 constructed packets to be sent
294 void req_send_reply_nosign(struct smbsrv_request *req)
299 if (req->out.size > NBT_HDR_SIZE) {
300 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
303 blob = data_blob_const(req->out.buffer, req->out.size);
304 status = packet_send(req->smb_conn->packet, blob);
305 if (!NT_STATUS_IS_OK(status)) {
306 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
312 possibly sign a message then send a reply and destroy the request buffer
314 note that this only looks at req->out.buffer and req->out.size, allowing manually
315 constructed packets to be sent
317 void req_send_reply(struct smbsrv_request *req)
319 req_sign_packet(req);
321 req_send_reply_nosign(req);
327 construct and send an error packet with a forced DOS error code
328 this is needed to match win2000 behaviour for some parts of the protocol
330 void req_reply_dos_error(struct smbsrv_request *req, uint8_t eclass, uint16_t ecode)
332 /* if the basic packet hasn't been setup yet then do it now */
333 if (req->out.buffer == NULL) {
334 req_setup_reply(req, 0, 0);
337 SCVAL(req->out.hdr, HDR_RCLS, eclass);
338 SSVAL(req->out.hdr, HDR_ERR, ecode);
339 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
344 setup the header of a reply to include an NTSTATUS code
346 void req_setup_error(struct smbsrv_request *req, NTSTATUS status)
348 if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
349 /* convert to DOS error codes */
352 ntstatus_to_dos(status, &eclass, &ecode);
353 SCVAL(req->out.hdr, HDR_RCLS, eclass);
354 SSVAL(req->out.hdr, HDR_ERR, ecode);
355 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
359 if (NT_STATUS_IS_DOS(status)) {
360 /* its a encoded DOS error, using the reserved range */
361 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
362 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
363 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
365 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
366 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
371 construct and send an error packet, then destroy the request
372 auto-converts to DOS error format when appropriate
374 void req_reply_error(struct smbsrv_request *req, NTSTATUS status)
376 if (req->smb_conn->connection->event.fde == NULL) {
377 /* the socket has been destroyed - no point trying to send an error! */
381 req_setup_reply(req, 0, 0);
383 /* error returns never have any data */
384 req_grow_data(req, 0);
386 req_setup_error(req, status);
392 push a string into the data portion of the request packet, growing it if necessary
393 this gets quite tricky - please be very careful to cover all cases when modifying this
395 if dest is NULL, then put the string at the end of the data portion of the packet
397 if dest_len is -1 then no limit applies
399 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, uint_t flags)
404 const int max_bytes_per_char = 3;
406 if (!(flags & (STR_ASCII|STR_UNICODE))) {
407 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
411 dest = req->out.data + req->out.data_size;
414 if (dest_len != -1) {
417 len = (strlen(str)+2) * max_bytes_per_char;
420 grow_size = len + PTR_DIFF(dest, req->out.data);
421 buf0 = req->out.buffer;
423 req_grow_allocation(req, grow_size);
425 if (buf0 != req->out.buffer) {
426 dest = req->out.buffer + PTR_DIFF(dest, buf0);
429 len = push_string(dest, str, len, flags);
431 grow_size = len + PTR_DIFF(dest, req->out.data);
433 if (grow_size > req->out.data_size) {
434 req_grow_data(req, grow_size);
441 append raw bytes into the data portion of the request packet
442 return the number of bytes added
444 size_t req_append_bytes(struct smbsrv_request *req,
445 const uint8_t *bytes, size_t byte_len)
447 req_grow_allocation(req, byte_len + req->out.data_size);
448 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
449 req_grow_data(req, byte_len + req->out.data_size);
453 append variable block (type 5 buffer) into the data portion of the request packet
454 return the number of bytes added
456 size_t req_append_var_block(struct smbsrv_request *req,
457 const uint8_t *bytes, uint16_t byte_len)
459 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
460 SCVAL(req->out.data + req->out.data_size, 0, 5);
461 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
463 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
465 req_grow_data(req, byte_len + 3 + req->out.data_size);
469 pull a UCS2 string from a request packet, returning a talloced unix string
471 the string length is limited by the 3 things:
472 - the data size in the request (end of packet)
473 - the passed 'byte_len' if it is not -1
474 - the end of string (null termination)
476 Note that 'byte_len' is the number of bytes in the packet
478 on failure zero is returned and *dest is set to NULL, otherwise the number
479 of bytes consumed in the packet is returned
481 static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
483 int src_len, src_len2, alignment=0;
487 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
490 if (byte_len != -1) {
495 if (flags & STR_NO_RANGE_CHECK) {
498 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
499 if (byte_len != -1 && src_len > byte_len) {
509 src_len2 = utf16_len_n(src, src_len);
511 *dest = talloc_strdup(req, "");
512 return src_len2 + alignment;
515 ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
523 return src_len2 + alignment;
527 pull a ascii string from a request packet, returning a talloced string
529 the string length is limited by the 3 things:
530 - the data size in the request (end of packet)
531 - the passed 'byte_len' if it is not -1
532 - the end of string (null termination)
534 Note that 'byte_len' is the number of bytes in the packet
536 on failure zero is returned and *dest is set to NULL, otherwise the number
537 of bytes consumed in the packet is returned
539 static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
541 int src_len, src_len2;
545 if (flags & STR_NO_RANGE_CHECK) {
548 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
553 if (byte_len != -1 && src_len > byte_len) {
558 src_len2 = strnlen((const char *)src, src_len);
559 if (src_len2 <= src_len - 1) {
560 /* include the termination if we didn't reach the end of the packet */
564 ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
576 pull a string from a request packet, returning a talloced string
578 the string length is limited by the 3 things:
579 - the data size in the request (end of packet)
580 - the passed 'byte_len' if it is not -1
581 - the end of string (null termination)
583 Note that 'byte_len' is the number of bytes in the packet
585 on failure zero is returned and *dest is set to NULL, otherwise the number
586 of bytes consumed in the packet is returned
588 size_t req_pull_string(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
590 if (!(flags & STR_ASCII) &&
591 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
592 return req_pull_ucs2(req, dest, src, byte_len, flags);
595 return req_pull_ascii(req, dest, src, byte_len, flags);
600 pull a ASCII4 string buffer from a request packet, returning a talloced string
602 an ASCII4 buffer is a null terminated string that has a prefix
603 of the character 0x4. It tends to be used in older parts of the protocol.
605 on failure *dest is set to the zero length string. This seems to
606 match win2000 behaviour
608 size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const uint8_t *src, uint_t flags)
612 if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
613 /* win2000 treats this as the NULL string! */
614 (*dest) = talloc_strdup(req, "");
618 /* this consumes the 0x4 byte. We don't check whether the byte
619 is actually 0x4 or not. This matches win2000 server
623 ret = req_pull_string(req, dest, src, -1, flags);
625 (*dest) = talloc_strdup(req, "");
633 pull a DATA_BLOB from a request packet, returning a talloced blob
635 return False if any part is outside the data portion of the packet
637 BOOL req_pull_blob(struct smbsrv_request *req, const uint8_t *src, int len, DATA_BLOB *blob)
639 if (len != 0 && req_data_oob(req, src, len)) {
643 (*blob) = data_blob_talloc(req, src, len);
648 /* check that a lump of data in a request is within the bounds of the data section of
650 BOOL req_data_oob(struct smbsrv_request *req, const uint8_t *ptr, uint32_t count)
656 /* be careful with wraparound! */
657 if (ptr < req->in.data ||
658 ptr >= req->in.data + req->in.data_size ||
659 count > req->in.data_size ||
660 ptr + count > req->in.data + req->in.data_size) {
668 pull an open file handle from a packet, taking account of the chained_fnum
670 uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
672 if (req->chained_fnum != -1) {
673 return req->chained_fnum;
675 return SVAL(base, offset);