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 /* we over allocate the data buffer to prevent too many realloc calls */
28 #define REQ_OVER_ALLOCATION 256
30 /* destroy a request structure */
31 void req_destroy(struct smbsrv_request *req)
33 /* the request might be marked protected. This is done by the
34 * SMBecho code for example */
35 if (req->control_flags & REQ_CONTROL_PROTECTED) {
39 /* ahh, its so nice to destroy a complex structure in such a
41 talloc_destroy(req->mem_ctx);
44 /****************************************************************************
45 construct a basic request packet, mostly used to construct async packets
46 such as change notify and oplock break requests
47 ****************************************************************************/
48 struct smbsrv_request *init_smb_request(struct smbsrv_connection *smb_conn)
50 struct smbsrv_request *req;
53 /* each request gets its own talloc context. The request
54 structure itself is also allocated inside this context, so
55 we need to allocate it before we construct the request
57 mem_ctx = talloc_init("request_context[%d]", smb_conn->connection->socket->pkt_count);
62 smb_conn->connection->socket->pkt_count++;
64 req = talloc(mem_ctx, sizeof(*req));
71 /* setup the request context */
72 req->smb_conn = smb_conn;
73 req->mem_ctx = mem_ctx;
80 setup a chained reply in req->out with the given word count and initial data buffer size.
82 static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
84 uint32_t chain_base_size = req->out.size;
86 /* we need room for the wct value, the words, the buffer length and the buffer */
87 req->out.size += 1 + VWV(wct) + 2 + buflen;
89 /* over allocate by a small amount */
90 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
92 req->out.buffer = talloc_realloc(req->mem_ctx, req->out.buffer, req->out.allocated);
93 if (!req->out.buffer) {
94 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
97 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
98 req->out.vwv = req->out.buffer + chain_base_size + 1;
100 req->out.data = req->out.vwv + VWV(wct) + 2;
101 req->out.data_size = buflen;
102 req->out.ptr = req->out.data;
104 SCVAL(req->out.buffer, chain_base_size, wct);
105 SSVAL(req->out.vwv, VWV(wct), buflen);
110 setup a reply in req->out with the given word count and initial data buffer size.
111 the caller will then fill in the command words and data before calling req_send_reply() to
112 send the reply on its way
114 void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
116 if (req->chain_count != 0) {
117 req_setup_chain_reply(req, wct, buflen);
121 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen;
123 /* over allocate by a small amount */
124 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
126 req->out.buffer = talloc(req->mem_ctx, req->out.allocated);
127 if (!req->out.buffer) {
128 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
131 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
132 req->out.vwv = req->out.hdr + HDR_VWV;
134 req->out.data = req->out.vwv + VWV(wct) + 2;
135 req->out.data_size = buflen;
136 req->out.ptr = req->out.data;
138 SIVAL(req->out.hdr, HDR_RCLS, 0);
140 SCVAL(req->out.hdr, HDR_WCT, wct);
141 SSVAL(req->out.vwv, VWV(wct), buflen);
144 memcpy(req->out.hdr, "\377SMB", 4);
145 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
146 SSVAL(req->out.hdr,HDR_FLG2,
147 (req->flags2 & FLAGS2_UNICODE_STRINGS) |
148 FLAGS2_LONG_PATH_COMPONENTS | FLAGS2_32_BIT_ERROR_CODES | FLAGS2_EXTENDED_SECURITY);
150 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
151 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
154 /* copy the cmd, tid, pid, uid and mid from the request */
155 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
156 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
157 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
158 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
159 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
161 SSVAL(req->out.hdr,HDR_TID,0);
162 SSVAL(req->out.hdr,HDR_PID,0);
163 SSVAL(req->out.hdr,HDR_UID,0);
164 SSVAL(req->out.hdr,HDR_MID,0);
169 work out the maximum data size we will allow for this reply, given
170 the negotiated max_xmit. The basic reply packet must be setup before
173 note that this is deliberately a signed integer reply
175 int req_max_data(struct smbsrv_request *req)
178 ret = req->smb_conn->negotiate.max_send;
179 ret -= PTR_DIFF(req->out.data, req->out.hdr);
180 if (ret < 0) ret = 0;
186 grow the allocation of the data buffer portion of a reply
187 packet. Note that as this can reallocate the packet buffer this
188 invalidates any local pointers into the packet.
190 To cope with this req->out.ptr is supplied. This will be updated to
191 point at the same offset into the packet as before this call
193 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
198 delta = new_size - req->out.data_size;
199 if (delta + req->out.size <= req->out.allocated) {
200 /* it fits in the preallocation */
204 /* we need to realloc */
205 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
206 buf2 = talloc_realloc(req->mem_ctx, req->out.buffer, req->out.allocated);
208 smb_panic("out of memory in req_grow_allocation");
211 if (buf2 == req->out.buffer) {
212 /* the malloc library gave us the same pointer */
216 /* update the pointers into the packet */
217 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
218 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
219 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
220 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
222 req->out.buffer = buf2;
227 grow the data buffer portion of a reply packet. Note that as this
228 can reallocate the packet buffer this invalidates any local pointers
231 To cope with this req->out.ptr is supplied. This will be updated to
232 point at the same offset into the packet as before this call
234 void req_grow_data(struct smbsrv_request *req, uint_t new_size)
238 if (!(req->control_flags & REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
239 smb_panic("reply buffer too large!");
242 req_grow_allocation(req, new_size);
244 delta = new_size - req->out.data_size;
246 req->out.size += delta;
247 req->out.data_size += delta;
249 /* set the BCC to the new data size */
250 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
254 send a reply and destroy the request buffer
256 note that this only looks at req->out.buffer and req->out.size, allowing manually
257 constructed packets to be sent
259 void req_send_reply_nosign(struct smbsrv_request *req)
261 if (req->out.size > NBT_HDR_SIZE) {
262 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
265 if (write_data(req->smb_conn->connection->socket->fde->fd, req->out.buffer, req->out.size) != req->out.size) {
266 smb_panic("failed to send reply\n");
273 possibly sign a message then send a reply and destroy the request buffer
275 note that this only looks at req->out.buffer and req->out.size, allowing manually
276 constructed packets to be sent
278 void req_send_reply(struct smbsrv_request *req)
280 req_sign_packet(req);
282 req_send_reply_nosign(req);
288 construct and send an error packet with a forced DOS error code
289 this is needed to match win2000 behaviour for some parts of the protocol
291 void req_reply_dos_error(struct smbsrv_request *req, uint8_t eclass, uint16_t ecode)
293 /* if the basic packet hasn't been setup yet then do it now */
294 if (req->out.buffer == NULL) {
295 req_setup_reply(req, 0, 0);
298 SCVAL(req->out.hdr, HDR_RCLS, eclass);
299 SSVAL(req->out.hdr, HDR_ERR, ecode);
300 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
305 setup the header of a reply to include an NTSTATUS code
307 void req_setup_error(struct smbsrv_request *req, NTSTATUS status)
309 if (!lp_nt_status_support() || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
310 /* convert to DOS error codes */
313 ntstatus_to_dos(status, &eclass, &ecode);
314 SCVAL(req->out.hdr, HDR_RCLS, eclass);
315 SSVAL(req->out.hdr, HDR_ERR, ecode);
316 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
320 if (NT_STATUS_IS_DOS(status)) {
321 /* its a encoded DOS error, using the reserved range */
322 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
323 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
324 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
326 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
327 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
332 construct and send an error packet, then destroy the request
333 auto-converts to DOS error format when appropriate
335 void req_reply_error(struct smbsrv_request *req, NTSTATUS status)
337 req_setup_reply(req, 0, 0);
339 /* error returns never have any data */
340 req_grow_data(req, 0);
342 req_setup_error(req, status);
348 push a string into the data portion of the request packet, growing it if necessary
349 this gets quite tricky - please be very careful to cover all cases when modifying this
351 if dest is NULL, then put the string at the end of the data portion of the packet
353 if dest_len is -1 then no limit applies
355 size_t req_push_str(struct smbsrv_request *req, char *dest, const char *str, int dest_len, uint_t flags)
360 const int max_bytes_per_char = 3;
362 if (!(flags & (STR_ASCII|STR_UNICODE))) {
363 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
367 dest = req->out.data + req->out.data_size;
370 if (dest_len != -1) {
373 len = (strlen(str)+2) * max_bytes_per_char;
376 grow_size = len + PTR_DIFF(dest, req->out.data);
377 buf0 = req->out.buffer;
379 req_grow_allocation(req, grow_size);
381 if (buf0 != req->out.buffer) {
382 dest = req->out.buffer + PTR_DIFF(dest, buf0);
385 len = push_string(req->out.hdr, dest, str, len, flags);
387 grow_size = len + PTR_DIFF(dest, req->out.data);
389 if (grow_size > req->out.data_size) {
390 req_grow_data(req, grow_size);
397 append raw bytes into the data portion of the request packet
398 return the number of bytes added
400 size_t req_append_bytes(struct smbsrv_request *req,
401 const uint8_t *bytes, size_t byte_len)
403 req_grow_allocation(req, byte_len + req->out.data_size);
404 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
405 req_grow_data(req, byte_len + req->out.data_size);
409 append variable block (type 5 buffer) into the data portion of the request packet
410 return the number of bytes added
412 size_t req_append_var_block(struct smbsrv_request *req,
413 const uint8_t *bytes, uint16_t byte_len)
415 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
416 SCVAL(req->out.data + req->out.data_size, 0, 5);
417 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
419 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
421 req_grow_data(req, byte_len + 3 + req->out.data_size);
425 pull a UCS2 string from a request packet, returning a talloced unix string
427 the string length is limited by the 3 things:
428 - the data size in the request (end of packet)
429 - the passed 'byte_len' if it is not -1
430 - the end of string (null termination)
432 Note that 'byte_len' is the number of bytes in the packet
434 on failure zero is returned and *dest is set to NULL, otherwise the number
435 of bytes consumed in the packet is returned
437 static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const char *src, int byte_len, uint_t flags)
439 int src_len, src_len2, alignment=0;
442 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
445 if (byte_len != -1) {
450 if (flags & STR_NO_RANGE_CHECK) {
453 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
459 if (byte_len != -1 && src_len > byte_len) {
464 src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
466 if (src_len2 <= src_len - 2) {
467 /* include the termination if we didn't reach the end of the packet */
471 ret = convert_string_talloc(req->mem_ctx, CH_UCS2, CH_UNIX, src, src_len2, (const void **)dest);
478 return src_len2 + alignment;
482 pull a ascii string from a request packet, returning a talloced string
484 the string length is limited by the 3 things:
485 - the data size in the request (end of packet)
486 - the passed 'byte_len' if it is not -1
487 - the end of string (null termination)
489 Note that 'byte_len' is the number of bytes in the packet
491 on failure zero is returned and *dest is set to NULL, otherwise the number
492 of bytes consumed in the packet is returned
494 static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const char *src, int byte_len, uint_t flags)
496 int src_len, src_len2;
499 if (flags & STR_NO_RANGE_CHECK) {
502 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
507 if (byte_len != -1 && src_len > byte_len) {
512 src_len2 = strnlen(src, src_len);
513 if (src_len2 <= src_len - 1) {
514 /* include the termination if we didn't reach the end of the packet */
518 ret = convert_string_talloc(req->mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
529 pull a string from a request packet, returning a talloced string
531 the string length is limited by the 3 things:
532 - the data size in the request (end of packet)
533 - the passed 'byte_len' if it is not -1
534 - the end of string (null termination)
536 Note that 'byte_len' is the number of bytes in the packet
538 on failure zero is returned and *dest is set to NULL, otherwise the number
539 of bytes consumed in the packet is returned
541 size_t req_pull_string(struct smbsrv_request *req, const char **dest, const char *src, int byte_len, uint_t flags)
543 if (!(flags & STR_ASCII) &&
544 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
545 return req_pull_ucs2(req, dest, src, byte_len, flags);
548 return req_pull_ascii(req, dest, src, byte_len, flags);
553 pull a ASCII4 string buffer from a request packet, returning a talloced string
555 an ASCII4 buffer is a null terminated string that has a prefix
556 of the character 0x4. It tends to be used in older parts of the protocol.
558 on failure *dest is set to the zero length string. This seems to
559 match win2000 behaviour
561 size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const char *src, uint_t flags)
565 if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
566 /* win2000 treats this as the NULL string! */
567 (*dest) = talloc_strdup(req->mem_ctx, "");
571 /* this consumes the 0x4 byte. We don't check whether the byte
572 is actually 0x4 or not. This matches win2000 server
576 ret = req_pull_string(req, dest, src, -1, flags);
578 (*dest) = talloc_strdup(req->mem_ctx, "");
586 pull a DATA_BLOB from a request packet, returning a talloced blob
588 return False if any part is outside the data portion of the packet
590 BOOL req_pull_blob(struct smbsrv_request *req, const char *src, int len, DATA_BLOB *blob)
592 if (len != 0 && req_data_oob(req, src, len)) {
596 (*blob) = data_blob_talloc(req->mem_ctx, src, len);
601 /* check that a lump of data in a request is within the bounds of the data section of
603 BOOL req_data_oob(struct smbsrv_request *req, const char *ptr, uint32_t count)
609 /* be careful with wraparound! */
610 if (ptr < req->in.data ||
611 ptr >= req->in.data + req->in.data_size ||
612 count > req->in.data_size ||
613 ptr + count > req->in.data + req->in.data_size) {
621 pull an open file handle from a packet, taking account of the chained_fnum
623 uint16_t req_fnum(struct smbsrv_request *req, const char *base, uint_t offset)
625 if (req->chained_fnum != -1) {
626 return req->chained_fnum;
628 return SVAL(base, offset);