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 /****************************************************************************
36 construct a basic request packet, mostly used to construct async packets
37 such as change notify and oplock break requests
38 ****************************************************************************/
39 struct smbsrv_request *smbsrv_init_request(struct smbsrv_connection *smb_conn)
41 struct smbsrv_request *req;
43 req = talloc_zero(smb_conn, struct smbsrv_request);
48 /* setup the request context */
49 req->smb_conn = smb_conn;
56 setup a chained reply in req->out with the given word count and initial data buffer size.
58 static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
60 uint32_t chain_base_size = req->out.size;
62 /* we need room for the wct value, the words, the buffer length and the buffer */
63 req->out.size += 1 + VWV(wct) + 2 + buflen;
65 /* over allocate by a small amount */
66 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
68 req->out.buffer = talloc_realloc(req, req->out.buffer,
69 uint8_t, req->out.allocated);
70 if (!req->out.buffer) {
71 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
75 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
76 req->out.vwv = req->out.buffer + chain_base_size + 1;
78 req->out.data = req->out.vwv + VWV(wct) + 2;
79 req->out.data_size = buflen;
80 req->out.ptr = req->out.data;
82 SCVAL(req->out.buffer, chain_base_size, wct);
83 SSVAL(req->out.vwv, VWV(wct), buflen);
88 setup a reply in req->out with the given word count and initial data buffer size.
89 the caller will then fill in the command words and data before calling req_send_reply() to
90 send the reply on its way
92 void smbsrv_setup_reply(struct smbsrv_request *req, uint_t wct, size_t buflen)
96 if (req->chain_count != 0) {
97 req_setup_chain_reply(req, wct, buflen);
101 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + buflen;
103 /* over allocate by a small amount */
104 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
106 req->out.buffer = talloc_size(req, req->out.allocated);
107 if (!req->out.buffer) {
108 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
112 flags2 = FLAGS2_LONG_PATH_COMPONENTS |
113 FLAGS2_EXTENDED_ATTRIBUTES |
115 flags2 |= (req->flags2 & (FLAGS2_UNICODE_STRINGS|FLAGS2_EXTENDED_SECURITY));
116 if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
117 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
120 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
121 req->out.vwv = req->out.hdr + HDR_VWV;
123 req->out.data = req->out.vwv + VWV(wct) + 2;
124 req->out.data_size = buflen;
125 req->out.ptr = req->out.data;
127 SIVAL(req->out.hdr, HDR_RCLS, 0);
129 SCVAL(req->out.hdr, HDR_WCT, wct);
130 SSVAL(req->out.vwv, VWV(wct), buflen);
132 memcpy(req->out.hdr, "\377SMB", 4);
133 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
134 SSVAL(req->out.hdr,HDR_FLG2, flags2);
135 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
136 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
139 /* copy the cmd, tid, pid, uid and mid from the request */
140 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
141 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
142 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
143 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
144 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
146 SCVAL(req->out.hdr,HDR_COM,0);
147 SSVAL(req->out.hdr,HDR_TID,0);
148 SSVAL(req->out.hdr,HDR_PID,0);
149 SSVAL(req->out.hdr,HDR_UID,0);
150 SSVAL(req->out.hdr,HDR_MID,0);
156 setup a copy of a request, used when the server needs to send
157 more than one reply for a single request packet
159 struct smbsrv_request *smbsrv_setup_secondary_request(struct smbsrv_request *old_req)
161 struct smbsrv_request *req;
164 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
169 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
170 if (req->out.buffer == NULL) {
175 diff = req->out.buffer - old_req->out.buffer;
177 req->out.hdr += diff;
178 req->out.vwv += diff;
179 req->out.data += diff;
180 req->out.ptr += diff;
186 work out the maximum data size we will allow for this reply, given
187 the negotiated max_xmit. The basic reply packet must be setup before
190 note that this is deliberately a signed integer reply
192 int req_max_data(struct smbsrv_request *req)
195 ret = req->smb_conn->negotiate.max_send;
196 ret -= PTR_DIFF(req->out.data, req->out.hdr);
197 if (ret < 0) ret = 0;
203 grow the allocation of the data buffer portion of a reply
204 packet. Note that as this can reallocate the packet buffer this
205 invalidates any local pointers into the packet.
207 To cope with this req->out.ptr is supplied. This will be updated to
208 point at the same offset into the packet as before this call
210 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
215 delta = new_size - req->out.data_size;
216 if (delta + req->out.size <= req->out.allocated) {
217 /* it fits in the preallocation */
221 /* we need to realloc */
222 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
223 buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
225 smb_panic("out of memory in req_grow_allocation");
228 if (buf2 == req->out.buffer) {
229 /* the malloc library gave us the same pointer */
233 /* update the pointers into the packet */
234 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
235 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
236 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
237 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
239 req->out.buffer = buf2;
244 grow the data buffer portion of a reply packet. Note that as this
245 can reallocate the packet buffer this invalidates any local pointers
248 To cope with this req->out.ptr is supplied. This will be updated to
249 point at the same offset into the packet as before this call
251 void req_grow_data(struct smbsrv_request *req, size_t new_size)
255 if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
256 smb_panic("reply buffer too large!");
259 req_grow_allocation(req, new_size);
261 delta = new_size - req->out.data_size;
263 req->out.size += delta;
264 req->out.data_size += delta;
266 /* set the BCC to the new data size */
267 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
271 send a reply and destroy the request buffer
273 note that this only looks at req->out.buffer and req->out.size, allowing manually
274 constructed packets to be sent
276 void smbsrv_send_reply_nosign(struct smbsrv_request *req)
281 if (req->smb_conn->connection->event.fde == NULL) {
282 /* we are in the process of shutting down this connection */
286 if (req->out.size > NBT_HDR_SIZE) {
287 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
290 blob = data_blob_const(req->out.buffer, req->out.size);
291 status = packet_send(req->smb_conn->packet, blob);
292 if (!NT_STATUS_IS_OK(status)) {
293 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
299 possibly sign a message then send a reply and destroy the request buffer
301 note that this only looks at req->out.buffer and req->out.size, allowing manually
302 constructed packets to be sent
304 void smbsrv_send_reply(struct smbsrv_request *req)
306 smbsrv_sign_packet(req);
308 smbsrv_send_reply_nosign(req);
312 setup the header of a reply to include an NTSTATUS code
314 void smbsrv_setup_error(struct smbsrv_request *req, NTSTATUS status)
316 if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
317 /* convert to DOS error codes */
320 ntstatus_to_dos(status, &eclass, &ecode);
321 SCVAL(req->out.hdr, HDR_RCLS, eclass);
322 SSVAL(req->out.hdr, HDR_ERR, ecode);
323 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
327 if (NT_STATUS_IS_DOS(status)) {
328 /* its a encoded DOS error, using the reserved range */
329 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
330 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
331 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
333 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
334 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
339 construct and send an error packet, then destroy the request
340 auto-converts to DOS error format when appropriate
342 void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status)
344 if (req->smb_conn->connection->event.fde == NULL) {
345 /* the socket has been destroyed - no point trying to send an error! */
349 smbsrv_setup_reply(req, 0, 0);
351 /* error returns never have any data */
352 req_grow_data(req, 0);
354 smbsrv_setup_error(req, status);
355 smbsrv_send_reply(req);
360 push a string into the data portion of the request packet, growing it if necessary
361 this gets quite tricky - please be very careful to cover all cases when modifying this
363 if dest is NULL, then put the string at the end of the data portion of the packet
365 if dest_len is -1 then no limit applies
367 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, size_t flags)
372 const int max_bytes_per_char = 3;
374 if (!(flags & (STR_ASCII|STR_UNICODE))) {
375 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
379 dest = req->out.data + req->out.data_size;
382 if (dest_len != -1) {
385 len = (strlen(str)+2) * max_bytes_per_char;
388 grow_size = len + PTR_DIFF(dest, req->out.data);
389 buf0 = req->out.buffer;
391 req_grow_allocation(req, grow_size);
393 if (buf0 != req->out.buffer) {
394 dest = req->out.buffer + PTR_DIFF(dest, buf0);
397 len = push_string(dest, str, len, flags);
399 grow_size = len + PTR_DIFF(dest, req->out.data);
401 if (grow_size > req->out.data_size) {
402 req_grow_data(req, grow_size);
409 append raw bytes into the data portion of the request packet
410 return the number of bytes added
412 size_t req_append_bytes(struct smbsrv_request *req,
413 const uint8_t *bytes, size_t byte_len)
415 req_grow_allocation(req, byte_len + req->out.data_size);
416 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
417 req_grow_data(req, byte_len + req->out.data_size);
421 append variable block (type 5 buffer) into the data portion of the request packet
422 return the number of bytes added
424 size_t req_append_var_block(struct smbsrv_request *req,
425 const uint8_t *bytes, uint16_t byte_len)
427 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
428 SCVAL(req->out.data + req->out.data_size, 0, 5);
429 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
431 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
433 req_grow_data(req, byte_len + 3 + req->out.data_size);
437 pull a UCS2 string from a request packet, returning a talloced unix string
439 the string length is limited by the 3 things:
440 - the data size in the request (end of packet)
441 - the passed 'byte_len' if it is not -1
442 - the end of string (null termination)
444 Note that 'byte_len' is the number of bytes in the packet
446 on failure zero is returned and *dest is set to NULL, otherwise the number
447 of bytes consumed in the packet is returned
449 static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
451 int src_len, src_len2, alignment=0;
455 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
458 if (byte_len != -1) {
463 if (flags & STR_NO_RANGE_CHECK) {
466 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
467 if (byte_len != -1 && src_len > byte_len) {
477 src_len2 = utf16_len_n(src, src_len);
479 *dest = talloc_strdup(req, "");
480 return src_len2 + alignment;
483 ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
491 return src_len2 + alignment;
495 pull a ascii string from a request packet, returning a talloced string
497 the string length is limited by the 3 things:
498 - the data size in the request (end of packet)
499 - the passed 'byte_len' if it is not -1
500 - the end of string (null termination)
502 Note that 'byte_len' is the number of bytes in the packet
504 on failure zero is returned and *dest is set to NULL, otherwise the number
505 of bytes consumed in the packet is returned
507 static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
509 int src_len, src_len2;
513 if (flags & STR_NO_RANGE_CHECK) {
516 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
521 if (byte_len != -1 && src_len > byte_len) {
526 src_len2 = strnlen((const char *)src, src_len);
527 if (src_len2 <= src_len - 1) {
528 /* include the termination if we didn't reach the end of the packet */
532 ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
544 pull a string from a request packet, returning a talloced string
546 the string length is limited by the 3 things:
547 - the data size in the request (end of packet)
548 - the passed 'byte_len' if it is not -1
549 - the end of string (null termination)
551 Note that 'byte_len' is the number of bytes in the packet
553 on failure zero is returned and *dest is set to NULL, otherwise the number
554 of bytes consumed in the packet is returned
556 size_t req_pull_string(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
558 if (!(flags & STR_ASCII) &&
559 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
560 return req_pull_ucs2(req, dest, src, byte_len, flags);
563 return req_pull_ascii(req, dest, src, byte_len, flags);
568 pull a ASCII4 string buffer from a request packet, returning a talloced string
570 an ASCII4 buffer is a null terminated string that has a prefix
571 of the character 0x4. It tends to be used in older parts of the protocol.
573 on failure *dest is set to the zero length string. This seems to
574 match win2000 behaviour
576 size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const uint8_t *src, uint_t flags)
580 if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
581 /* win2000 treats this as the empty string! */
582 (*dest) = talloc_strdup(req, "");
586 /* this consumes the 0x4 byte. We don't check whether the byte
587 is actually 0x4 or not. This matches win2000 server
591 ret = req_pull_string(req, dest, src, -1, flags);
593 (*dest) = talloc_strdup(req, "");
601 pull a DATA_BLOB from a request packet, returning a talloced blob
603 return False if any part is outside the data portion of the packet
605 BOOL req_pull_blob(struct smbsrv_request *req, const uint8_t *src, int len, DATA_BLOB *blob)
607 if (len != 0 && req_data_oob(req, src, len)) {
611 (*blob) = data_blob_talloc(req, src, len);
616 /* check that a lump of data in a request is within the bounds of the data section of
618 BOOL req_data_oob(struct smbsrv_request *req, const uint8_t *ptr, uint32_t count)
624 /* be careful with wraparound! */
625 if (ptr < req->in.data ||
626 ptr >= req->in.data + req->in.data_size ||
627 count > req->in.data_size ||
628 ptr + count > req->in.data + req->in.data_size) {
636 pull an open file handle from a packet, taking account of the chained_fnum
638 uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
640 if (req->chained_fnum != -1) {
641 return req->chained_fnum;
643 return SVAL(base, offset);