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 "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 /* destroy a request structure */
36 void req_destroy(struct smbsrv_request *req)
38 /* ahh, its so nice to destroy a complex structure in such a
43 /****************************************************************************
44 construct a basic request packet, mostly used to construct async packets
45 such as change notify and oplock break requests
46 ****************************************************************************/
47 struct smbsrv_request *init_smb_request(struct smbsrv_connection *smb_conn)
49 struct smbsrv_request *req;
51 req = talloc(smb_conn, struct smbsrv_request);
58 /* setup the request context */
59 req->smb_conn = smb_conn;
61 req->async_states = talloc(req, struct ntvfs_async_state);
62 if (!req->async_states) {
66 req->async_states->state = 0;
73 setup a chained reply in req->out with the given word count and initial data buffer size.
75 static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
77 uint32_t chain_base_size = req->out.size;
79 /* we need room for the wct value, the words, the buffer length and the buffer */
80 req->out.size += 1 + VWV(wct) + 2 + buflen;
82 /* over allocate by a small amount */
83 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
85 req->out.buffer = talloc_realloc(req, req->out.buffer,
86 uint8_t, req->out.allocated);
87 if (!req->out.buffer) {
88 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
92 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
93 req->out.vwv = req->out.buffer + chain_base_size + 1;
95 req->out.data = req->out.vwv + VWV(wct) + 2;
96 req->out.data_size = buflen;
97 req->out.ptr = req->out.data;
99 SCVAL(req->out.buffer, chain_base_size, wct);
100 SSVAL(req->out.vwv, VWV(wct), buflen);
105 setup a reply in req->out with the given word count and initial data buffer size.
106 the caller will then fill in the command words and data before calling req_send_reply() to
107 send the reply on its way
109 void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
113 if (req->chain_count != 0) {
114 req_setup_chain_reply(req, wct, buflen);
118 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen;
120 /* over allocate by a small amount */
121 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
123 req->out.buffer = talloc_size(req, req->out.allocated);
124 if (!req->out.buffer) {
125 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
129 flags2 = FLAGS2_LONG_PATH_COMPONENTS |
130 FLAGS2_EXTENDED_ATTRIBUTES |
132 flags2 |= (req->flags2 & (FLAGS2_UNICODE_STRINGS|FLAGS2_EXTENDED_SECURITY));
133 if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
134 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
137 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
138 req->out.vwv = req->out.hdr + HDR_VWV;
140 req->out.data = req->out.vwv + VWV(wct) + 2;
141 req->out.data_size = buflen;
142 req->out.ptr = req->out.data;
144 SIVAL(req->out.hdr, HDR_RCLS, 0);
146 SCVAL(req->out.hdr, HDR_WCT, wct);
147 SSVAL(req->out.vwv, VWV(wct), buflen);
149 memcpy(req->out.hdr, "\377SMB", 4);
150 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
151 SSVAL(req->out.hdr,HDR_FLG2, flags2);
152 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
153 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
156 /* copy the cmd, tid, pid, uid and mid from the request */
157 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
158 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
159 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
160 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
161 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
163 SSVAL(req->out.hdr,HDR_TID,0);
164 SSVAL(req->out.hdr,HDR_PID,0);
165 SSVAL(req->out.hdr,HDR_UID,0);
166 SSVAL(req->out.hdr,HDR_MID,0);
172 setup a copy of a request, used when the server needs to send
173 more than one reply for a single request packet
175 struct smbsrv_request *req_setup_secondary(struct smbsrv_request *old_req)
177 struct smbsrv_request *req;
180 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
185 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
186 if (req->out.buffer == NULL) {
191 diff = req->out.buffer - old_req->out.buffer;
193 req->out.hdr += diff;
194 req->out.vwv += diff;
195 req->out.data += diff;
196 req->out.ptr += diff;
202 work out the maximum data size we will allow for this reply, given
203 the negotiated max_xmit. The basic reply packet must be setup before
206 note that this is deliberately a signed integer reply
208 int req_max_data(struct smbsrv_request *req)
211 ret = req->smb_conn->negotiate.max_send;
212 ret -= PTR_DIFF(req->out.data, req->out.hdr);
213 if (ret < 0) ret = 0;
219 grow the allocation of the data buffer portion of a reply
220 packet. Note that as this can reallocate the packet buffer this
221 invalidates any local pointers into the packet.
223 To cope with this req->out.ptr is supplied. This will be updated to
224 point at the same offset into the packet as before this call
226 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
231 delta = new_size - req->out.data_size;
232 if (delta + req->out.size <= req->out.allocated) {
233 /* it fits in the preallocation */
237 /* we need to realloc */
238 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
239 buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
241 smb_panic("out of memory in req_grow_allocation");
244 if (buf2 == req->out.buffer) {
245 /* the malloc library gave us the same pointer */
249 /* update the pointers into the packet */
250 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
251 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
252 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
253 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
255 req->out.buffer = buf2;
260 grow the data buffer portion of a reply packet. Note that as this
261 can reallocate the packet buffer this invalidates any local pointers
264 To cope with this req->out.ptr is supplied. This will be updated to
265 point at the same offset into the packet as before this call
267 void req_grow_data(struct smbsrv_request *req, uint_t new_size)
271 if (!(req->control_flags & REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
272 smb_panic("reply buffer too large!");
275 req_grow_allocation(req, new_size);
277 delta = new_size - req->out.data_size;
279 req->out.size += delta;
280 req->out.data_size += delta;
282 /* set the BCC to the new data size */
283 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
287 send a reply and destroy the request buffer
289 note that this only looks at req->out.buffer and req->out.size, allowing manually
290 constructed packets to be sent
292 void req_send_reply_nosign(struct smbsrv_request *req)
297 if (req->out.size > NBT_HDR_SIZE) {
298 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
301 blob = data_blob_const(req->out.buffer, req->out.size);
302 status = packet_send(req->smb_conn->packet, blob);
303 if (!NT_STATUS_IS_OK(status)) {
304 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
310 possibly sign a message then send a reply and destroy the request buffer
312 note that this only looks at req->out.buffer and req->out.size, allowing manually
313 constructed packets to be sent
315 void req_send_reply(struct smbsrv_request *req)
317 req_sign_packet(req);
319 req_send_reply_nosign(req);
325 construct and send an error packet with a forced DOS error code
326 this is needed to match win2000 behaviour for some parts of the protocol
328 void req_reply_dos_error(struct smbsrv_request *req, uint8_t eclass, uint16_t ecode)
330 /* if the basic packet hasn't been setup yet then do it now */
331 if (req->out.buffer == NULL) {
332 req_setup_reply(req, 0, 0);
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);
342 setup the header of a reply to include an NTSTATUS code
344 void req_setup_error(struct smbsrv_request *req, NTSTATUS status)
346 if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
347 /* convert to DOS error codes */
350 ntstatus_to_dos(status, &eclass, &ecode);
351 SCVAL(req->out.hdr, HDR_RCLS, eclass);
352 SSVAL(req->out.hdr, HDR_ERR, ecode);
353 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
357 if (NT_STATUS_IS_DOS(status)) {
358 /* its a encoded DOS error, using the reserved range */
359 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
360 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
361 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
363 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
364 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
369 construct and send an error packet, then destroy the request
370 auto-converts to DOS error format when appropriate
372 void req_reply_error(struct smbsrv_request *req, NTSTATUS status)
374 if (req->smb_conn->connection->event.fde == NULL) {
375 /* the socket has been destroyed - no point trying to send an error! */
379 req_setup_reply(req, 0, 0);
381 /* error returns never have any data */
382 req_grow_data(req, 0);
384 req_setup_error(req, status);
390 push a string into the data portion of the request packet, growing it if necessary
391 this gets quite tricky - please be very careful to cover all cases when modifying this
393 if dest is NULL, then put the string at the end of the data portion of the packet
395 if dest_len is -1 then no limit applies
397 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, uint_t flags)
402 const int max_bytes_per_char = 3;
404 if (!(flags & (STR_ASCII|STR_UNICODE))) {
405 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
409 dest = req->out.data + req->out.data_size;
412 if (dest_len != -1) {
415 len = (strlen(str)+2) * max_bytes_per_char;
418 grow_size = len + PTR_DIFF(dest, req->out.data);
419 buf0 = req->out.buffer;
421 req_grow_allocation(req, grow_size);
423 if (buf0 != req->out.buffer) {
424 dest = req->out.buffer + PTR_DIFF(dest, buf0);
427 len = push_string(dest, str, len, flags);
429 grow_size = len + PTR_DIFF(dest, req->out.data);
431 if (grow_size > req->out.data_size) {
432 req_grow_data(req, grow_size);
439 append raw bytes into the data portion of the request packet
440 return the number of bytes added
442 size_t req_append_bytes(struct smbsrv_request *req,
443 const uint8_t *bytes, size_t byte_len)
445 req_grow_allocation(req, byte_len + req->out.data_size);
446 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
447 req_grow_data(req, byte_len + req->out.data_size);
451 append variable block (type 5 buffer) into the data portion of the request packet
452 return the number of bytes added
454 size_t req_append_var_block(struct smbsrv_request *req,
455 const uint8_t *bytes, uint16_t byte_len)
457 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
458 SCVAL(req->out.data + req->out.data_size, 0, 5);
459 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
461 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
463 req_grow_data(req, byte_len + 3 + req->out.data_size);
467 pull a UCS2 string from a request packet, returning a talloced unix string
469 the string length is limited by the 3 things:
470 - the data size in the request (end of packet)
471 - the passed 'byte_len' if it is not -1
472 - the end of string (null termination)
474 Note that 'byte_len' is the number of bytes in the packet
476 on failure zero is returned and *dest is set to NULL, otherwise the number
477 of bytes consumed in the packet is returned
479 static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
481 int src_len, src_len2, alignment=0;
485 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
488 if (byte_len != -1) {
493 if (flags & STR_NO_RANGE_CHECK) {
496 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
497 if (byte_len != -1 && src_len > byte_len) {
507 src_len2 = utf16_len_n(src, src_len);
509 *dest = talloc_strdup(req, "");
510 return src_len2 + alignment;
513 ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
521 return src_len2 + alignment;
525 pull a ascii string from a request packet, returning a talloced string
527 the string length is limited by the 3 things:
528 - the data size in the request (end of packet)
529 - the passed 'byte_len' if it is not -1
530 - the end of string (null termination)
532 Note that 'byte_len' is the number of bytes in the packet
534 on failure zero is returned and *dest is set to NULL, otherwise the number
535 of bytes consumed in the packet is returned
537 static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
539 int src_len, src_len2;
543 if (flags & STR_NO_RANGE_CHECK) {
546 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
551 if (byte_len != -1 && src_len > byte_len) {
556 src_len2 = strnlen((const char *)src, src_len);
557 if (src_len2 <= src_len - 1) {
558 /* include the termination if we didn't reach the end of the packet */
562 ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
574 pull a string from a request packet, returning a talloced string
576 the string length is limited by the 3 things:
577 - the data size in the request (end of packet)
578 - the passed 'byte_len' if it is not -1
579 - the end of string (null termination)
581 Note that 'byte_len' is the number of bytes in the packet
583 on failure zero is returned and *dest is set to NULL, otherwise the number
584 of bytes consumed in the packet is returned
586 size_t req_pull_string(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
588 if (!(flags & STR_ASCII) &&
589 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
590 return req_pull_ucs2(req, dest, src, byte_len, flags);
593 return req_pull_ascii(req, dest, src, byte_len, flags);
598 pull a ASCII4 string buffer from a request packet, returning a talloced string
600 an ASCII4 buffer is a null terminated string that has a prefix
601 of the character 0x4. It tends to be used in older parts of the protocol.
603 on failure *dest is set to the zero length string. This seems to
604 match win2000 behaviour
606 size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const uint8_t *src, uint_t flags)
610 if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
611 /* win2000 treats this as the NULL string! */
612 (*dest) = talloc_strdup(req, "");
616 /* this consumes the 0x4 byte. We don't check whether the byte
617 is actually 0x4 or not. This matches win2000 server
621 ret = req_pull_string(req, dest, src, -1, flags);
623 (*dest) = talloc_strdup(req, "");
631 pull a DATA_BLOB from a request packet, returning a talloced blob
633 return False if any part is outside the data portion of the packet
635 BOOL req_pull_blob(struct smbsrv_request *req, const uint8_t *src, int len, DATA_BLOB *blob)
637 if (len != 0 && req_data_oob(req, src, len)) {
641 (*blob) = data_blob_talloc(req, src, len);
646 /* check that a lump of data in a request is within the bounds of the data section of
648 BOOL req_data_oob(struct smbsrv_request *req, const uint8_t *ptr, uint32_t count)
654 /* be careful with wraparound! */
655 if (ptr < req->in.data ||
656 ptr >= req->in.data + req->in.data_size ||
657 count > req->in.data_size ||
658 ptr + count > req->in.data + req->in.data_size) {
666 pull an open file handle from a packet, taking account of the chained_fnum
668 uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
670 if (req->chained_fnum != -1) {
671 return req->chained_fnum;
673 return SVAL(base, offset);