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
27 #include "dlinklist.h"
28 #include "smb_server/smb_server.h"
31 /* we over allocate the data buffer to prevent too many realloc calls */
32 #define REQ_OVER_ALLOCATION 0
34 /* destroy a request structure */
35 void req_destroy(struct smbsrv_request *req)
37 /* ahh, its so nice to destroy a complex structure in such a
42 /****************************************************************************
43 construct a basic request packet, mostly used to construct async packets
44 such as change notify and oplock break requests
45 ****************************************************************************/
46 struct smbsrv_request *init_smb_request(struct smbsrv_connection *smb_conn)
48 struct smbsrv_request *req;
50 smb_conn->pkt_count++;
52 req = talloc_p(smb_conn, struct smbsrv_request);
59 /* setup the request context */
60 req->smb_conn = smb_conn;
62 req->async_states = talloc_p(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, 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)
111 if (req->chain_count != 0) {
112 req_setup_chain_reply(req, wct, buflen);
116 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen;
118 /* over allocate by a small amount */
119 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
121 req->out.buffer = talloc(req, req->out.allocated);
122 if (!req->out.buffer) {
123 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
127 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
128 req->out.vwv = req->out.hdr + HDR_VWV;
130 req->out.data = req->out.vwv + VWV(wct) + 2;
131 req->out.data_size = buflen;
132 req->out.ptr = req->out.data;
134 SIVAL(req->out.hdr, HDR_RCLS, 0);
136 SCVAL(req->out.hdr, HDR_WCT, wct);
137 SSVAL(req->out.vwv, VWV(wct), buflen);
140 memcpy(req->out.hdr, "\377SMB", 4);
141 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
142 SSVAL(req->out.hdr,HDR_FLG2,
143 (req->flags2 & FLAGS2_UNICODE_STRINGS) |
144 FLAGS2_LONG_PATH_COMPONENTS | FLAGS2_32_BIT_ERROR_CODES | FLAGS2_EXTENDED_SECURITY);
146 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
147 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
150 /* copy the cmd, tid, pid, uid and mid from the request */
151 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
152 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
153 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
154 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
155 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
157 SSVAL(req->out.hdr,HDR_TID,0);
158 SSVAL(req->out.hdr,HDR_PID,0);
159 SSVAL(req->out.hdr,HDR_UID,0);
160 SSVAL(req->out.hdr,HDR_MID,0);
166 setup a copy of a request, used when the server needs to send
167 more than one reply for a single request packet
169 struct smbsrv_request *req_setup_secondary(struct smbsrv_request *old_req)
171 struct smbsrv_request *req;
174 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
179 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
180 if (req->out.buffer == NULL) {
185 diff = req->out.buffer - old_req->out.buffer;
187 req->out.hdr += diff;
188 req->out.vwv += diff;
189 req->out.data += diff;
190 req->out.ptr += diff;
196 work out the maximum data size we will allow for this reply, given
197 the negotiated max_xmit. The basic reply packet must be setup before
200 note that this is deliberately a signed integer reply
202 int req_max_data(struct smbsrv_request *req)
205 ret = req->smb_conn->negotiate.max_send;
206 ret -= PTR_DIFF(req->out.data, req->out.hdr);
207 if (ret < 0) ret = 0;
213 grow the allocation of the data buffer portion of a reply
214 packet. Note that as this can reallocate the packet buffer this
215 invalidates any local pointers into the packet.
217 To cope with this req->out.ptr is supplied. This will be updated to
218 point at the same offset into the packet as before this call
220 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
225 delta = new_size - req->out.data_size;
226 if (delta + req->out.size <= req->out.allocated) {
227 /* it fits in the preallocation */
231 /* we need to realloc */
232 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
233 buf2 = talloc_realloc(req, req->out.buffer, req->out.allocated);
235 smb_panic("out of memory in req_grow_allocation");
238 if (buf2 == req->out.buffer) {
239 /* the malloc library gave us the same pointer */
243 /* update the pointers into the packet */
244 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
245 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
246 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
247 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
249 req->out.buffer = buf2;
254 grow the data buffer portion of a reply packet. Note that as this
255 can reallocate the packet buffer this invalidates any local pointers
258 To cope with this req->out.ptr is supplied. This will be updated to
259 point at the same offset into the packet as before this call
261 void req_grow_data(struct smbsrv_request *req, uint_t new_size)
265 if (!(req->control_flags & REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
266 smb_panic("reply buffer too large!");
269 req_grow_allocation(req, new_size);
271 delta = new_size - req->out.data_size;
273 req->out.size += delta;
274 req->out.data_size += delta;
276 /* set the BCC to the new data size */
277 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
281 send a reply and destroy the request buffer
283 note that this only looks at req->out.buffer and req->out.size, allowing manually
284 constructed packets to be sent
286 void req_send_reply_nosign(struct smbsrv_request *req)
288 if (req->out.size > NBT_HDR_SIZE) {
289 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
292 /* add the request to the list of requests that need to be
293 sent to the client, then mark the socket event structure
294 ready for write events */
295 DLIST_ADD_END(req->smb_conn->pending_send, req, struct smbsrv_request *);
297 req->smb_conn->connection->event.fde->flags |= EVENT_FD_WRITE;
301 possibly sign a message then send a reply and destroy the request buffer
303 note that this only looks at req->out.buffer and req->out.size, allowing manually
304 constructed packets to be sent
306 void req_send_reply(struct smbsrv_request *req)
308 req_sign_packet(req);
310 req_send_reply_nosign(req);
316 construct and send an error packet with a forced DOS error code
317 this is needed to match win2000 behaviour for some parts of the protocol
319 void req_reply_dos_error(struct smbsrv_request *req, uint8_t eclass, uint16_t ecode)
321 /* if the basic packet hasn't been setup yet then do it now */
322 if (req->out.buffer == NULL) {
323 req_setup_reply(req, 0, 0);
326 SCVAL(req->out.hdr, HDR_RCLS, eclass);
327 SSVAL(req->out.hdr, HDR_ERR, ecode);
328 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
333 setup the header of a reply to include an NTSTATUS code
335 void req_setup_error(struct smbsrv_request *req, NTSTATUS status)
337 if (!lp_nt_status_support() || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
338 /* convert to DOS error codes */
341 ntstatus_to_dos(status, &eclass, &ecode);
342 SCVAL(req->out.hdr, HDR_RCLS, eclass);
343 SSVAL(req->out.hdr, HDR_ERR, ecode);
344 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
348 if (NT_STATUS_IS_DOS(status)) {
349 /* its a encoded DOS error, using the reserved range */
350 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
351 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
352 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
354 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
355 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
360 construct and send an error packet, then destroy the request
361 auto-converts to DOS error format when appropriate
363 void req_reply_error(struct smbsrv_request *req, NTSTATUS status)
365 req_setup_reply(req, 0, 0);
367 /* error returns never have any data */
368 req_grow_data(req, 0);
370 req_setup_error(req, status);
376 push a string into the data portion of the request packet, growing it if necessary
377 this gets quite tricky - please be very careful to cover all cases when modifying this
379 if dest is NULL, then put the string at the end of the data portion of the packet
381 if dest_len is -1 then no limit applies
383 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, uint_t flags)
388 const int max_bytes_per_char = 3;
390 if (!(flags & (STR_ASCII|STR_UNICODE))) {
391 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
395 dest = req->out.data + req->out.data_size;
398 if (dest_len != -1) {
401 len = (strlen(str)+2) * max_bytes_per_char;
404 grow_size = len + PTR_DIFF(dest, req->out.data);
405 buf0 = req->out.buffer;
407 req_grow_allocation(req, grow_size);
409 if (buf0 != req->out.buffer) {
410 dest = req->out.buffer + PTR_DIFF(dest, buf0);
413 len = push_string(dest, str, len, flags);
415 grow_size = len + PTR_DIFF(dest, req->out.data);
417 if (grow_size > req->out.data_size) {
418 req_grow_data(req, grow_size);
425 append raw bytes into the data portion of the request packet
426 return the number of bytes added
428 size_t req_append_bytes(struct smbsrv_request *req,
429 const uint8_t *bytes, size_t byte_len)
431 req_grow_allocation(req, byte_len + req->out.data_size);
432 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
433 req_grow_data(req, byte_len + req->out.data_size);
437 append variable block (type 5 buffer) into the data portion of the request packet
438 return the number of bytes added
440 size_t req_append_var_block(struct smbsrv_request *req,
441 const uint8_t *bytes, uint16_t byte_len)
443 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
444 SCVAL(req->out.data + req->out.data_size, 0, 5);
445 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
447 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
449 req_grow_data(req, byte_len + 3 + req->out.data_size);
453 pull a UCS2 string from a request packet, returning a talloced unix string
455 the string length is limited by the 3 things:
456 - the data size in the request (end of packet)
457 - the passed 'byte_len' if it is not -1
458 - the end of string (null termination)
460 Note that 'byte_len' is the number of bytes in the packet
462 on failure zero is returned and *dest is set to NULL, otherwise the number
463 of bytes consumed in the packet is returned
465 static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
467 int src_len, src_len2, alignment=0;
471 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
474 if (byte_len != -1) {
479 if (flags & STR_NO_RANGE_CHECK) {
482 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
488 if (byte_len != -1 && src_len > byte_len) {
493 src_len2 = utf16_len_n(src, src_len);
495 *dest = talloc_strdup(req, "");
496 return src_len2 + alignment;
499 ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
507 return src_len2 + alignment;
511 pull a ascii string from a request packet, returning a talloced string
513 the string length is limited by the 3 things:
514 - the data size in the request (end of packet)
515 - the passed 'byte_len' if it is not -1
516 - the end of string (null termination)
518 Note that 'byte_len' is the number of bytes in the packet
520 on failure zero is returned and *dest is set to NULL, otherwise the number
521 of bytes consumed in the packet is returned
523 static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
525 int src_len, src_len2;
529 if (flags & STR_NO_RANGE_CHECK) {
532 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
537 if (byte_len != -1 && src_len > byte_len) {
542 src_len2 = strnlen((const char *)src, src_len);
543 if (src_len2 <= src_len - 1) {
544 /* include the termination if we didn't reach the end of the packet */
548 ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
560 pull a string from a request packet, returning a talloced string
562 the string length is limited by the 3 things:
563 - the data size in the request (end of packet)
564 - the passed 'byte_len' if it is not -1
565 - the end of string (null termination)
567 Note that 'byte_len' is the number of bytes in the packet
569 on failure zero is returned and *dest is set to NULL, otherwise the number
570 of bytes consumed in the packet is returned
572 size_t req_pull_string(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
574 if (!(flags & STR_ASCII) &&
575 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
576 return req_pull_ucs2(req, dest, src, byte_len, flags);
579 return req_pull_ascii(req, dest, src, byte_len, flags);
584 pull a ASCII4 string buffer from a request packet, returning a talloced string
586 an ASCII4 buffer is a null terminated string that has a prefix
587 of the character 0x4. It tends to be used in older parts of the protocol.
589 on failure *dest is set to the zero length string. This seems to
590 match win2000 behaviour
592 size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const uint8_t *src, uint_t flags)
596 if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
597 /* win2000 treats this as the NULL string! */
598 (*dest) = talloc_strdup(req, "");
602 /* this consumes the 0x4 byte. We don't check whether the byte
603 is actually 0x4 or not. This matches win2000 server
607 ret = req_pull_string(req, dest, src, -1, flags);
609 (*dest) = talloc_strdup(req, "");
617 pull a DATA_BLOB from a request packet, returning a talloced blob
619 return False if any part is outside the data portion of the packet
621 BOOL req_pull_blob(struct smbsrv_request *req, const uint8_t *src, int len, DATA_BLOB *blob)
623 if (len != 0 && req_data_oob(req, src, len)) {
627 (*blob) = data_blob_talloc(req, src, len);
632 /* check that a lump of data in a request is within the bounds of the data section of
634 BOOL req_data_oob(struct smbsrv_request *req, const uint8_t *ptr, uint32_t count)
640 /* be careful with wraparound! */
641 if (ptr < req->in.data ||
642 ptr >= req->in.data + req->in.data_size ||
643 count > req->in.data_size ||
644 ptr + count > req->in.data + req->in.data_size) {
652 pull an open file handle from a packet, taking account of the chained_fnum
654 uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
656 if (req->chained_fnum != -1) {
657 return req->chained_fnum;
659 return SVAL(base, offset);