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 "dlinklist.h"
28 /* we over allocate the data buffer to prevent too many realloc calls */
29 #define REQ_OVER_ALLOCATION 256
31 /* destroy a request structure */
32 void req_destroy(struct smbsrv_request *req)
34 /* ahh, its so nice to destroy a complex structure in such a
39 /****************************************************************************
40 construct a basic request packet, mostly used to construct async packets
41 such as change notify and oplock break requests
42 ****************************************************************************/
43 struct smbsrv_request *init_smb_request(struct smbsrv_connection *smb_conn)
45 struct smbsrv_request *req;
47 smb_conn->pkt_count++;
49 req = talloc_p(smb_conn, struct smbsrv_request);
56 /* setup the request context */
57 req->smb_conn = smb_conn;
59 req->async_states = talloc_p(req, struct ntvfs_async_state);
60 if (!req->async_states) {
64 req->async_states->state = 0;
71 setup a chained reply in req->out with the given word count and initial data buffer size.
73 static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
75 uint32_t chain_base_size = req->out.size;
77 /* we need room for the wct value, the words, the buffer length and the buffer */
78 req->out.size += 1 + VWV(wct) + 2 + buflen;
80 /* over allocate by a small amount */
81 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
83 req->out.buffer = talloc_realloc(req, req->out.buffer, req->out.allocated);
84 if (!req->out.buffer) {
85 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
88 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
89 req->out.vwv = req->out.buffer + chain_base_size + 1;
91 req->out.data = req->out.vwv + VWV(wct) + 2;
92 req->out.data_size = buflen;
93 req->out.ptr = req->out.data;
95 SCVAL(req->out.buffer, chain_base_size, wct);
96 SSVAL(req->out.vwv, VWV(wct), buflen);
101 setup a reply in req->out with the given word count and initial data buffer size.
102 the caller will then fill in the command words and data before calling req_send_reply() to
103 send the reply on its way
105 void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
107 if (req->chain_count != 0) {
108 req_setup_chain_reply(req, wct, buflen);
112 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen;
114 /* over allocate by a small amount */
115 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
117 req->out.buffer = talloc(req, req->out.allocated);
118 if (!req->out.buffer) {
119 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
122 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
123 req->out.vwv = req->out.hdr + HDR_VWV;
125 req->out.data = req->out.vwv + VWV(wct) + 2;
126 req->out.data_size = buflen;
127 req->out.ptr = req->out.data;
129 SIVAL(req->out.hdr, HDR_RCLS, 0);
131 SCVAL(req->out.hdr, HDR_WCT, wct);
132 SSVAL(req->out.vwv, VWV(wct), buflen);
135 memcpy(req->out.hdr, "\377SMB", 4);
136 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
137 SSVAL(req->out.hdr,HDR_FLG2,
138 (req->flags2 & FLAGS2_UNICODE_STRINGS) |
139 FLAGS2_LONG_PATH_COMPONENTS | FLAGS2_32_BIT_ERROR_CODES | FLAGS2_EXTENDED_SECURITY);
141 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
142 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
145 /* copy the cmd, tid, pid, uid and mid from the request */
146 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
147 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
148 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
149 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
150 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
152 SSVAL(req->out.hdr,HDR_TID,0);
153 SSVAL(req->out.hdr,HDR_PID,0);
154 SSVAL(req->out.hdr,HDR_UID,0);
155 SSVAL(req->out.hdr,HDR_MID,0);
161 setup a copy of a request, used when the server needs to send
162 more than one reply for a single request packet
164 struct smbsrv_request *req_setup_secondary(struct smbsrv_request *old_req)
166 struct smbsrv_request *req;
169 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
174 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
175 if (req->out.buffer == NULL) {
180 diff = req->out.buffer - old_req->out.buffer;
182 req->out.hdr += diff;
183 req->out.vwv += diff;
184 req->out.data += diff;
185 req->out.ptr += diff;
191 work out the maximum data size we will allow for this reply, given
192 the negotiated max_xmit. The basic reply packet must be setup before
195 note that this is deliberately a signed integer reply
197 int req_max_data(struct smbsrv_request *req)
200 ret = req->smb_conn->negotiate.max_send;
201 ret -= PTR_DIFF(req->out.data, req->out.hdr);
202 if (ret < 0) ret = 0;
208 grow the allocation of the data buffer portion of a reply
209 packet. Note that as this can reallocate the packet buffer this
210 invalidates any local pointers into the packet.
212 To cope with this req->out.ptr is supplied. This will be updated to
213 point at the same offset into the packet as before this call
215 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
220 delta = new_size - req->out.data_size;
221 if (delta + req->out.size <= req->out.allocated) {
222 /* it fits in the preallocation */
226 /* we need to realloc */
227 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
228 buf2 = talloc_realloc(req, req->out.buffer, req->out.allocated);
230 smb_panic("out of memory in req_grow_allocation");
233 if (buf2 == req->out.buffer) {
234 /* the malloc library gave us the same pointer */
238 /* update the pointers into the packet */
239 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
240 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
241 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
242 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
244 req->out.buffer = buf2;
249 grow the data buffer portion of a reply packet. Note that as this
250 can reallocate the packet buffer this invalidates any local pointers
253 To cope with this req->out.ptr is supplied. This will be updated to
254 point at the same offset into the packet as before this call
256 void req_grow_data(struct smbsrv_request *req, uint_t new_size)
260 if (!(req->control_flags & REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
261 smb_panic("reply buffer too large!");
264 req_grow_allocation(req, new_size);
266 delta = new_size - req->out.data_size;
268 req->out.size += delta;
269 req->out.data_size += delta;
271 /* set the BCC to the new data size */
272 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
276 send a reply and destroy the request buffer
278 note that this only looks at req->out.buffer and req->out.size, allowing manually
279 constructed packets to be sent
281 void req_send_reply_nosign(struct smbsrv_request *req)
283 if (req->out.size > NBT_HDR_SIZE) {
284 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
287 /* add the request to the list of requests that need to be
288 sent to the client, then mark the socket event structure
289 ready for write events */
290 DLIST_ADD_END(req->smb_conn->pending_send, req, struct smbsrv_request *);
292 req->smb_conn->connection->event.fde->flags |= EVENT_FD_WRITE;
296 possibly sign a message then send a reply and destroy the request buffer
298 note that this only looks at req->out.buffer and req->out.size, allowing manually
299 constructed packets to be sent
301 void req_send_reply(struct smbsrv_request *req)
303 req_sign_packet(req);
305 req_send_reply_nosign(req);
311 construct and send an error packet with a forced DOS error code
312 this is needed to match win2000 behaviour for some parts of the protocol
314 void req_reply_dos_error(struct smbsrv_request *req, uint8_t eclass, uint16_t ecode)
316 /* if the basic packet hasn't been setup yet then do it now */
317 if (req->out.buffer == NULL) {
318 req_setup_reply(req, 0, 0);
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);
328 setup the header of a reply to include an NTSTATUS code
330 void req_setup_error(struct smbsrv_request *req, NTSTATUS status)
332 if (!lp_nt_status_support() || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
333 /* convert to DOS error codes */
336 ntstatus_to_dos(status, &eclass, &ecode);
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);
343 if (NT_STATUS_IS_DOS(status)) {
344 /* its a encoded DOS error, using the reserved range */
345 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
346 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
347 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
349 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
350 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
355 construct and send an error packet, then destroy the request
356 auto-converts to DOS error format when appropriate
358 void req_reply_error(struct smbsrv_request *req, NTSTATUS status)
360 req_setup_reply(req, 0, 0);
362 /* error returns never have any data */
363 req_grow_data(req, 0);
365 req_setup_error(req, status);
371 push a string into the data portion of the request packet, growing it if necessary
372 this gets quite tricky - please be very careful to cover all cases when modifying this
374 if dest is NULL, then put the string at the end of the data portion of the packet
376 if dest_len is -1 then no limit applies
378 size_t req_push_str(struct smbsrv_request *req, char *dest, const char *str, int dest_len, uint_t flags)
383 const int max_bytes_per_char = 3;
385 if (!(flags & (STR_ASCII|STR_UNICODE))) {
386 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
390 dest = req->out.data + req->out.data_size;
393 if (dest_len != -1) {
396 len = (strlen(str)+2) * max_bytes_per_char;
399 grow_size = len + PTR_DIFF(dest, req->out.data);
400 buf0 = req->out.buffer;
402 req_grow_allocation(req, grow_size);
404 if (buf0 != req->out.buffer) {
405 dest = req->out.buffer + PTR_DIFF(dest, buf0);
408 len = push_string(dest, str, len, flags);
410 grow_size = len + PTR_DIFF(dest, req->out.data);
412 if (grow_size > req->out.data_size) {
413 req_grow_data(req, grow_size);
420 append raw bytes into the data portion of the request packet
421 return the number of bytes added
423 size_t req_append_bytes(struct smbsrv_request *req,
424 const uint8_t *bytes, size_t byte_len)
426 req_grow_allocation(req, byte_len + req->out.data_size);
427 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
428 req_grow_data(req, byte_len + req->out.data_size);
432 append variable block (type 5 buffer) into the data portion of the request packet
433 return the number of bytes added
435 size_t req_append_var_block(struct smbsrv_request *req,
436 const uint8_t *bytes, uint16_t byte_len)
438 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
439 SCVAL(req->out.data + req->out.data_size, 0, 5);
440 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
442 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
444 req_grow_data(req, byte_len + 3 + req->out.data_size);
448 pull a UCS2 string from a request packet, returning a talloced unix string
450 the string length is limited by the 3 things:
451 - the data size in the request (end of packet)
452 - the passed 'byte_len' if it is not -1
453 - the end of string (null termination)
455 Note that 'byte_len' is the number of bytes in the packet
457 on failure zero is returned and *dest is set to NULL, otherwise the number
458 of bytes consumed in the packet is returned
460 static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const char *src, int byte_len, uint_t flags)
462 int src_len, src_len2, alignment=0;
466 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
469 if (byte_len != -1) {
474 if (flags & STR_NO_RANGE_CHECK) {
477 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
483 if (byte_len != -1 && src_len > byte_len) {
488 src_len2 = utf16_len_n(src, src_len);
489 ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
497 return src_len2 + alignment;
501 pull a ascii string from a request packet, returning a talloced string
503 the string length is limited by the 3 things:
504 - the data size in the request (end of packet)
505 - the passed 'byte_len' if it is not -1
506 - the end of string (null termination)
508 Note that 'byte_len' is the number of bytes in the packet
510 on failure zero is returned and *dest is set to NULL, otherwise the number
511 of bytes consumed in the packet is returned
513 static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const char *src, int byte_len, uint_t flags)
515 int src_len, src_len2;
519 if (flags & STR_NO_RANGE_CHECK) {
522 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
527 if (byte_len != -1 && src_len > byte_len) {
532 src_len2 = strnlen(src, src_len);
533 if (src_len2 <= src_len - 1) {
534 /* include the termination if we didn't reach the end of the packet */
538 ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
550 pull a string from a request packet, returning a talloced string
552 the string length is limited by the 3 things:
553 - the data size in the request (end of packet)
554 - the passed 'byte_len' if it is not -1
555 - the end of string (null termination)
557 Note that 'byte_len' is the number of bytes in the packet
559 on failure zero is returned and *dest is set to NULL, otherwise the number
560 of bytes consumed in the packet is returned
562 size_t req_pull_string(struct smbsrv_request *req, const char **dest, const char *src, int byte_len, uint_t flags)
564 if (!(flags & STR_ASCII) &&
565 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
566 return req_pull_ucs2(req, dest, src, byte_len, flags);
569 return req_pull_ascii(req, dest, src, byte_len, flags);
574 pull a ASCII4 string buffer from a request packet, returning a talloced string
576 an ASCII4 buffer is a null terminated string that has a prefix
577 of the character 0x4. It tends to be used in older parts of the protocol.
579 on failure *dest is set to the zero length string. This seems to
580 match win2000 behaviour
582 size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const char *src, uint_t flags)
586 if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
587 /* win2000 treats this as the NULL string! */
588 (*dest) = talloc_strdup(req, "");
592 /* this consumes the 0x4 byte. We don't check whether the byte
593 is actually 0x4 or not. This matches win2000 server
597 ret = req_pull_string(req, dest, src, -1, flags);
599 (*dest) = talloc_strdup(req, "");
607 pull a DATA_BLOB from a request packet, returning a talloced blob
609 return False if any part is outside the data portion of the packet
611 BOOL req_pull_blob(struct smbsrv_request *req, const char *src, int len, DATA_BLOB *blob)
613 if (len != 0 && req_data_oob(req, src, len)) {
617 (*blob) = data_blob_talloc(req, src, len);
622 /* check that a lump of data in a request is within the bounds of the data section of
624 BOOL req_data_oob(struct smbsrv_request *req, const char *ptr, uint32_t count)
630 /* be careful with wraparound! */
631 if (ptr < req->in.data ||
632 ptr >= req->in.data + req->in.data_size ||
633 count > req->in.data_size ||
634 ptr + count > req->in.data + req->in.data_size) {
642 pull an open file handle from a packet, taking account of the chained_fnum
644 uint16_t req_fnum(struct smbsrv_request *req, const char *base, uint_t offset)
646 if (req->chained_fnum != -1) {
647 return req->chained_fnum;
649 return SVAL(base, offset);