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 request_context' 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 request_context *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 request_context *init_smb_request(struct server_context *smb)
50 struct request_context *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->socket.pkt_count);
62 smb->socket.pkt_count++;
64 req = talloc(mem_ctx, sizeof(*req));
67 /* setup the request context */
69 req->mem_ctx = mem_ctx;
76 setup a chained reply in req->out with the given word count and initial data buffer size.
78 static void req_setup_chain_reply(struct request_context *req, unsigned wct, unsigned buflen)
80 uint32 chain_base_size = req->out.size;
82 /* we need room for the wct value, the words, the buffer length and the buffer */
83 req->out.size += 1 + VWV(wct) + 2 + buflen;
85 /* over allocate by a small amount */
86 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
88 req->out.buffer = talloc_realloc(req->mem_ctx, req->out.buffer, req->out.allocated);
89 if (!req->out.buffer) {
90 exit_server(req->smb, "allocation failed");
93 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
94 req->out.vwv = req->out.buffer + chain_base_size + 1;
96 req->out.data = req->out.vwv + VWV(wct) + 2;
97 req->out.data_size = buflen;
98 req->out.ptr = req->out.data;
100 SCVAL(req->out.buffer, chain_base_size, wct);
101 SSVAL(req->out.vwv, VWV(wct), buflen);
106 setup a reply in req->out with the given word count and initial data buffer size.
107 the caller will then fill in the command words and data before calling req_send_reply() to
108 send the reply on its way
110 void req_setup_reply(struct request_context *req, unsigned wct, unsigned 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(req->mem_ctx, req->out.allocated);
123 if (!req->out.buffer) {
124 exit_server(req->smb, "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);
165 work out the maximum data size we will allow for this reply, given
166 the negotiated max_xmit. The basic reply packet must be setup before
169 note that this is deliberately a signed integer reply
171 int req_max_data(struct request_context *req)
174 ret = req->smb->negotiate.max_send;
175 ret -= PTR_DIFF(req->out.data, req->out.hdr);
176 if (ret < 0) ret = 0;
182 grow the allocation of the data buffer portion of a reply
183 packet. Note that as this can reallocate the packet buffer this
184 invalidates any local pointers into the packet.
186 To cope with this req->out.ptr is supplied. This will be updated to
187 point at the same offset into the packet as before this call
189 static void req_grow_allocation(struct request_context *req, unsigned new_size)
194 delta = new_size - req->out.data_size;
195 if (delta + req->out.size <= req->out.allocated) {
196 /* it fits in the preallocation */
200 /* we need to realloc */
201 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
202 buf2 = talloc_realloc(req->mem_ctx, req->out.buffer, req->out.allocated);
204 smb_panic("out of memory in req_grow_allocation");
207 if (buf2 == req->out.buffer) {
208 /* the malloc library gave us the same pointer */
212 /* update the pointers into the packet */
213 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
214 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
215 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
216 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
218 req->out.buffer = buf2;
223 grow the data buffer portion of a reply packet. Note that as this
224 can reallocate the packet buffer this invalidates any local pointers
227 To cope with this req->out.ptr is supplied. This will be updated to
228 point at the same offset into the packet as before this call
230 void req_grow_data(struct request_context *req, unsigned new_size)
234 if (!(req->control_flags & REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
235 smb_panic("reply buffer too large!");
238 req_grow_allocation(req, new_size);
240 delta = new_size - req->out.data_size;
242 req->out.size += delta;
243 req->out.data_size += delta;
245 /* set the BCC to the new data size */
246 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
250 send a reply and destroy the request buffer
252 note that this only looks at req->out.buffer and req->out.size, allowing manually
253 constructed packets to be sent
255 void req_send_reply(struct request_context *req)
257 if (req->out.size > NBT_HDR_SIZE) {
258 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
261 if (write_data(req->smb->socket.fd, req->out.buffer, req->out.size) != req->out.size) {
262 smb_panic("failed to send reply\n");
271 construct and send an error packet with a forced DOS error code
272 this is needed to match win2000 behaviour for some parts of the protocol
274 void req_reply_dos_error(struct request_context *req, uint8 eclass, uint16 ecode)
276 /* if the basic packet hasn't been setup yet then do it now */
277 if (req->out.buffer == NULL) {
278 req_setup_reply(req, 0, 0);
281 SCVAL(req->out.hdr, HDR_RCLS, eclass);
282 SSVAL(req->out.hdr, HDR_ERR, ecode);
284 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
290 construct and send an error packet, then destroy the request
291 auto-converts to DOS error format when appropriate
293 void req_reply_error(struct request_context *req, NTSTATUS status)
295 req_setup_reply(req, 0, 0);
297 /* error returns never have any data */
298 req_grow_data(req, 0);
300 if (!lp_nt_status_support() || !(req->smb->negotiate.client_caps & CAP_STATUS32)) {
301 /* convert to DOS error codes */
304 ntstatus_to_dos(status, &eclass, &ecode);
305 req_reply_dos_error(req, eclass, ecode);
309 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
310 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
317 push a string into the data portion of the request packet, growing it if necessary
318 this gets quite tricky - please be very careful to cover all cases when modifying this
320 if dest is NULL, then put the string at the end of the data portion of the packet
322 if dest_len is -1 then no limit applies
324 size_t req_push_str(struct request_context *req, char *dest, const char *str, int dest_len, unsigned flags)
329 const int max_bytes_per_char = 3;
331 if (!(flags & (STR_ASCII|STR_UNICODE))) {
332 flags |= (req->smb->negotiate.client_caps & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
336 dest = req->out.data + req->out.data_size;
339 if (dest_len != -1) {
342 len = (strlen(str)+2) * max_bytes_per_char;
345 grow_size = len + PTR_DIFF(dest, req->out.data);
346 buf0 = req->out.buffer;
348 req_grow_allocation(req, grow_size);
350 if (buf0 != req->out.buffer) {
351 dest = req->out.buffer + PTR_DIFF(dest, buf0);
354 len = push_string(req->out.hdr, dest, str, len, flags);
356 grow_size = len + PTR_DIFF(dest, req->out.data);
358 if (grow_size > req->out.data_size) {
359 req_grow_data(req, grow_size);
367 pull a UCS2 string from a request packet, returning a talloced unix string
369 the string length is limited by the 3 things:
370 - the data size in the request (end of packet)
371 - the passed 'byte_len' if it is not -1
372 - the end of string (null termination)
374 Note that 'byte_len' is the number of bytes in the packet
376 on failure zero is returned and *dest is set to NULL, otherwise the number
377 of bytes consumed in the packet is returned
379 static size_t req_pull_ucs2(struct request_context *req, const char **dest, const char *src, int byte_len, unsigned flags)
381 int src_len, src_len2, alignment=0;
384 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
387 if (byte_len != -1) {
392 if (flags & STR_NO_RANGE_CHECK) {
395 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
401 if (byte_len != -1 && src_len > byte_len) {
406 src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
408 if (src_len2 <= src_len - 2) {
409 /* include the termination if we didn't reach the end of the packet */
413 ret = convert_string_talloc(req->mem_ctx, CH_UCS2, CH_UNIX, src, src_len2, (const void **)dest);
420 return src_len2 + alignment;
424 pull a ascii string from a request packet, returning a talloced string
426 the string length is limited by the 3 things:
427 - the data size in the request (end of packet)
428 - the passed 'byte_len' if it is not -1
429 - the end of string (null termination)
431 Note that 'byte_len' is the number of bytes in the packet
433 on failure zero is returned and *dest is set to NULL, otherwise the number
434 of bytes consumed in the packet is returned
436 static size_t req_pull_ascii(struct request_context *req, const char **dest, const char *src, int byte_len, unsigned flags)
438 int src_len, src_len2;
441 if (flags & STR_NO_RANGE_CHECK) {
444 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
449 if (byte_len != -1 && src_len > byte_len) {
454 src_len2 = strnlen(src, src_len);
455 if (src_len2 <= src_len - 1) {
456 /* include the termination if we didn't reach the end of the packet */
460 ret = convert_string_talloc(req->mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
471 pull a string from a request packet, returning a talloced string
473 the string length is limited by the 3 things:
474 - the data size in the request (end of packet)
475 - the passed 'byte_len' if it is not -1
476 - the end of string (null termination)
478 Note that 'byte_len' is the number of bytes in the packet
480 on failure zero is returned and *dest is set to NULL, otherwise the number
481 of bytes consumed in the packet is returned
483 size_t req_pull_string(struct request_context *req, const char **dest, const char *src, int byte_len, unsigned flags)
485 if (!(flags & STR_ASCII) &&
486 ((flags & STR_UNICODE || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
487 return req_pull_ucs2(req, dest, src, byte_len, flags);
490 return req_pull_ascii(req, dest, src, byte_len, flags);
495 pull a ASCII4 string buffer from a request packet, returning a talloced string
497 an ASCII4 buffer is a null terminated string that has a prefix
498 of the character 0x4. It tends to be used in older parts of the protocol.
500 on failure *dest is set to the zero length string. This seems to
501 match win2000 behaviour
503 size_t req_pull_ascii4(struct request_context *req, const char **dest, const char *src, unsigned flags)
507 if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
508 /* win2000 treats this as the NULL string! */
509 (*dest) = talloc_strdup(req->mem_ctx, "");
513 /* this consumes the 0x4 byte. We don't check whether the byte
514 is actually 0x4 or not. This matches win2000 server
518 ret = req_pull_string(req, dest, src, -1, flags);
520 (*dest) = talloc_strdup(req->mem_ctx, "");
528 pull a DATA_BLOB from a request packet, returning a talloced blob
530 return False if any part is outside the data portion of the packet
532 BOOL req_pull_blob(struct request_context *req, const char *src, int len, DATA_BLOB *blob)
534 if (len != 0 && req_data_oob(req, src, len)) {
538 (*blob) = data_blob_talloc(req->mem_ctx, src, len);
543 /* check that a lump of data in a request is within the bounds of the data section of
545 BOOL req_data_oob(struct request_context *req, const char *ptr, uint32 count)
551 /* be careful with wraparound! */
552 if (ptr < req->in.data ||
553 ptr >= req->in.data + req->in.data_size ||
554 count > req->in.data_size ||
555 ptr + count > req->in.data + req->in.data_size) {
563 pull an open file handle from a packet, taking account of the chained_fnum
565 uint16 req_fnum(struct request_context *req, const char *base, unsigned offset)
567 if (req->chained_fnum != -1) {
568 return req->chained_fnum;
570 return SVAL(base, offset);