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 req = talloc(smb_conn, struct smbsrv_request);
57 /* setup the request context */
58 req->smb_conn = smb_conn;
60 req->async_states = talloc(req, struct ntvfs_async_state);
61 if (!req->async_states) {
65 req->async_states->state = 0;
72 setup a chained reply in req->out with the given word count and initial data buffer size.
74 static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
76 uint32_t chain_base_size = req->out.size;
78 /* we need room for the wct value, the words, the buffer length and the buffer */
79 req->out.size += 1 + VWV(wct) + 2 + buflen;
81 /* over allocate by a small amount */
82 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
84 req->out.buffer = talloc_realloc(req, req->out.buffer,
85 uint8_t, req->out.allocated);
86 if (!req->out.buffer) {
87 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
91 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
92 req->out.vwv = req->out.buffer + chain_base_size + 1;
94 req->out.data = req->out.vwv + VWV(wct) + 2;
95 req->out.data_size = buflen;
96 req->out.ptr = req->out.data;
98 SCVAL(req->out.buffer, chain_base_size, wct);
99 SSVAL(req->out.vwv, VWV(wct), buflen);
104 setup a reply in req->out with the given word count and initial data buffer size.
105 the caller will then fill in the command words and data before calling req_send_reply() to
106 send the reply on its way
108 void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
112 if (req->chain_count != 0) {
113 req_setup_chain_reply(req, wct, buflen);
117 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen;
119 /* over allocate by a small amount */
120 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
122 req->out.buffer = talloc_size(req, req->out.allocated);
123 if (!req->out.buffer) {
124 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
128 flags2 = FLAGS2_LONG_PATH_COMPONENTS |
129 FLAGS2_EXTENDED_ATTRIBUTES |
131 flags2 |= (req->flags2 & (FLAGS2_UNICODE_STRINGS|FLAGS2_EXTENDED_SECURITY));
132 if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
133 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
136 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
137 req->out.vwv = req->out.hdr + HDR_VWV;
139 req->out.data = req->out.vwv + VWV(wct) + 2;
140 req->out.data_size = buflen;
141 req->out.ptr = req->out.data;
143 SIVAL(req->out.hdr, HDR_RCLS, 0);
145 SCVAL(req->out.hdr, HDR_WCT, wct);
146 SSVAL(req->out.vwv, VWV(wct), buflen);
148 memcpy(req->out.hdr, "\377SMB", 4);
149 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
150 SSVAL(req->out.hdr,HDR_FLG2, flags2);
151 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
152 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
155 /* copy the cmd, tid, pid, uid and mid from the request */
156 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
157 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
158 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
159 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
160 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
162 SSVAL(req->out.hdr,HDR_TID,0);
163 SSVAL(req->out.hdr,HDR_PID,0);
164 SSVAL(req->out.hdr,HDR_UID,0);
165 SSVAL(req->out.hdr,HDR_MID,0);
171 setup a copy of a request, used when the server needs to send
172 more than one reply for a single request packet
174 struct smbsrv_request *req_setup_secondary(struct smbsrv_request *old_req)
176 struct smbsrv_request *req;
179 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
184 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
185 if (req->out.buffer == NULL) {
190 diff = req->out.buffer - old_req->out.buffer;
192 req->out.hdr += diff;
193 req->out.vwv += diff;
194 req->out.data += diff;
195 req->out.ptr += diff;
201 work out the maximum data size we will allow for this reply, given
202 the negotiated max_xmit. The basic reply packet must be setup before
205 note that this is deliberately a signed integer reply
207 int req_max_data(struct smbsrv_request *req)
210 ret = req->smb_conn->negotiate.max_send;
211 ret -= PTR_DIFF(req->out.data, req->out.hdr);
212 if (ret < 0) ret = 0;
218 grow the allocation of the data buffer portion of a reply
219 packet. Note that as this can reallocate the packet buffer this
220 invalidates any local pointers into the packet.
222 To cope with this req->out.ptr is supplied. This will be updated to
223 point at the same offset into the packet as before this call
225 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
230 delta = new_size - req->out.data_size;
231 if (delta + req->out.size <= req->out.allocated) {
232 /* it fits in the preallocation */
236 /* we need to realloc */
237 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
238 buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
240 smb_panic("out of memory in req_grow_allocation");
243 if (buf2 == req->out.buffer) {
244 /* the malloc library gave us the same pointer */
248 /* update the pointers into the packet */
249 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
250 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
251 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
252 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
254 req->out.buffer = buf2;
259 grow the data buffer portion of a reply packet. Note that as this
260 can reallocate the packet buffer this invalidates any local pointers
263 To cope with this req->out.ptr is supplied. This will be updated to
264 point at the same offset into the packet as before this call
266 void req_grow_data(struct smbsrv_request *req, uint_t new_size)
270 if (!(req->control_flags & REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
271 smb_panic("reply buffer too large!");
274 req_grow_allocation(req, new_size);
276 delta = new_size - req->out.data_size;
278 req->out.size += delta;
279 req->out.data_size += delta;
281 /* set the BCC to the new data size */
282 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
286 send a reply and destroy the request buffer
288 note that this only looks at req->out.buffer and req->out.size, allowing manually
289 constructed packets to be sent
291 void req_send_reply_nosign(struct smbsrv_request *req)
293 if (req->out.size > NBT_HDR_SIZE) {
294 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
297 /* add the request to the list of requests that need to be
298 sent to the client, then mark the socket event structure
299 ready for write events */
300 DLIST_ADD_END(req->smb_conn->pending_send, req, struct smbsrv_request *);
302 req->smb_conn->connection->event.fde->flags |= EVENT_FD_WRITE;
306 possibly sign a message then send a reply and destroy the request buffer
308 note that this only looks at req->out.buffer and req->out.size, allowing manually
309 constructed packets to be sent
311 void req_send_reply(struct smbsrv_request *req)
313 req_sign_packet(req);
315 req_send_reply_nosign(req);
321 construct and send an error packet with a forced DOS error code
322 this is needed to match win2000 behaviour for some parts of the protocol
324 void req_reply_dos_error(struct smbsrv_request *req, uint8_t eclass, uint16_t ecode)
326 /* if the basic packet hasn't been setup yet then do it now */
327 if (req->out.buffer == NULL) {
328 req_setup_reply(req, 0, 0);
331 SCVAL(req->out.hdr, HDR_RCLS, eclass);
332 SSVAL(req->out.hdr, HDR_ERR, ecode);
333 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
338 setup the header of a reply to include an NTSTATUS code
340 void req_setup_error(struct smbsrv_request *req, NTSTATUS status)
342 if (!lp_nt_status_support() || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
343 /* convert to DOS error codes */
346 ntstatus_to_dos(status, &eclass, &ecode);
347 SCVAL(req->out.hdr, HDR_RCLS, eclass);
348 SSVAL(req->out.hdr, HDR_ERR, ecode);
349 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
353 if (NT_STATUS_IS_DOS(status)) {
354 /* its a encoded DOS error, using the reserved range */
355 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
356 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
357 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
359 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
360 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
365 construct and send an error packet, then destroy the request
366 auto-converts to DOS error format when appropriate
368 void req_reply_error(struct smbsrv_request *req, NTSTATUS status)
370 req_setup_reply(req, 0, 0);
372 /* error returns never have any data */
373 req_grow_data(req, 0);
375 req_setup_error(req, status);
381 push a string into the data portion of the request packet, growing it if necessary
382 this gets quite tricky - please be very careful to cover all cases when modifying this
384 if dest is NULL, then put the string at the end of the data portion of the packet
386 if dest_len is -1 then no limit applies
388 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, uint_t flags)
393 const int max_bytes_per_char = 3;
395 if (!(flags & (STR_ASCII|STR_UNICODE))) {
396 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
400 dest = req->out.data + req->out.data_size;
403 if (dest_len != -1) {
406 len = (strlen(str)+2) * max_bytes_per_char;
409 grow_size = len + PTR_DIFF(dest, req->out.data);
410 buf0 = req->out.buffer;
412 req_grow_allocation(req, grow_size);
414 if (buf0 != req->out.buffer) {
415 dest = req->out.buffer + PTR_DIFF(dest, buf0);
418 len = push_string(dest, str, len, flags);
420 grow_size = len + PTR_DIFF(dest, req->out.data);
422 if (grow_size > req->out.data_size) {
423 req_grow_data(req, grow_size);
430 append raw bytes into the data portion of the request packet
431 return the number of bytes added
433 size_t req_append_bytes(struct smbsrv_request *req,
434 const uint8_t *bytes, size_t byte_len)
436 req_grow_allocation(req, byte_len + req->out.data_size);
437 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
438 req_grow_data(req, byte_len + req->out.data_size);
442 append variable block (type 5 buffer) into the data portion of the request packet
443 return the number of bytes added
445 size_t req_append_var_block(struct smbsrv_request *req,
446 const uint8_t *bytes, uint16_t byte_len)
448 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
449 SCVAL(req->out.data + req->out.data_size, 0, 5);
450 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
452 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
454 req_grow_data(req, byte_len + 3 + req->out.data_size);
458 pull a UCS2 string from a request packet, returning a talloced unix string
460 the string length is limited by the 3 things:
461 - the data size in the request (end of packet)
462 - the passed 'byte_len' if it is not -1
463 - the end of string (null termination)
465 Note that 'byte_len' is the number of bytes in the packet
467 on failure zero is returned and *dest is set to NULL, otherwise the number
468 of bytes consumed in the packet is returned
470 static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
472 int src_len, src_len2, alignment=0;
476 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
479 if (byte_len != -1) {
484 if (flags & STR_NO_RANGE_CHECK) {
487 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
493 if (byte_len != -1 && src_len > byte_len) {
498 src_len2 = utf16_len_n(src, src_len);
500 *dest = talloc_strdup(req, "");
501 return src_len2 + alignment;
504 ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
512 return src_len2 + alignment;
516 pull a ascii string from a request packet, returning a talloced string
518 the string length is limited by the 3 things:
519 - the data size in the request (end of packet)
520 - the passed 'byte_len' if it is not -1
521 - the end of string (null termination)
523 Note that 'byte_len' is the number of bytes in the packet
525 on failure zero is returned and *dest is set to NULL, otherwise the number
526 of bytes consumed in the packet is returned
528 static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
530 int src_len, src_len2;
534 if (flags & STR_NO_RANGE_CHECK) {
537 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
542 if (byte_len != -1 && src_len > byte_len) {
547 src_len2 = strnlen((const char *)src, src_len);
548 if (src_len2 <= src_len - 1) {
549 /* include the termination if we didn't reach the end of the packet */
553 ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
565 pull a string from a request packet, returning a talloced string
567 the string length is limited by the 3 things:
568 - the data size in the request (end of packet)
569 - the passed 'byte_len' if it is not -1
570 - the end of string (null termination)
572 Note that 'byte_len' is the number of bytes in the packet
574 on failure zero is returned and *dest is set to NULL, otherwise the number
575 of bytes consumed in the packet is returned
577 size_t req_pull_string(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
579 if (!(flags & STR_ASCII) &&
580 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
581 return req_pull_ucs2(req, dest, src, byte_len, flags);
584 return req_pull_ascii(req, dest, src, byte_len, flags);
589 pull a ASCII4 string buffer from a request packet, returning a talloced string
591 an ASCII4 buffer is a null terminated string that has a prefix
592 of the character 0x4. It tends to be used in older parts of the protocol.
594 on failure *dest is set to the zero length string. This seems to
595 match win2000 behaviour
597 size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const uint8_t *src, uint_t flags)
601 if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
602 /* win2000 treats this as the NULL string! */
603 (*dest) = talloc_strdup(req, "");
607 /* this consumes the 0x4 byte. We don't check whether the byte
608 is actually 0x4 or not. This matches win2000 server
612 ret = req_pull_string(req, dest, src, -1, flags);
614 (*dest) = talloc_strdup(req, "");
622 pull a DATA_BLOB from a request packet, returning a talloced blob
624 return False if any part is outside the data portion of the packet
626 BOOL req_pull_blob(struct smbsrv_request *req, const uint8_t *src, int len, DATA_BLOB *blob)
628 if (len != 0 && req_data_oob(req, src, len)) {
632 (*blob) = data_blob_talloc(req, src, len);
637 /* check that a lump of data in a request is within the bounds of the data section of
639 BOOL req_data_oob(struct smbsrv_request *req, const uint8_t *ptr, uint32_t count)
645 /* be careful with wraparound! */
646 if (ptr < req->in.data ||
647 ptr >= req->in.data + req->in.data_size ||
648 count > req->in.data_size ||
649 ptr + count > req->in.data + req->in.data_size) {
657 pull an open file handle from a packet, taking account of the chained_fnum
659 uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
661 if (req->chained_fnum != -1) {
662 return req->chained_fnum;
664 return SVAL(base, offset);