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
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;
52 smb_conn->socket.pkt_count++;
54 req = talloc_p(smb_conn, struct smbsrv_request);
61 /* setup the request context */
62 req->smb_conn = smb_conn;
69 setup a chained reply in req->out with the given word count and initial data buffer size.
71 static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
73 uint32_t chain_base_size = req->out.size;
75 /* we need room for the wct value, the words, the buffer length and the buffer */
76 req->out.size += 1 + VWV(wct) + 2 + buflen;
78 /* over allocate by a small amount */
79 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
81 req->out.buffer = talloc_realloc(req->out.buffer, req->out.allocated);
82 if (!req->out.buffer) {
83 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
86 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
87 req->out.vwv = req->out.buffer + chain_base_size + 1;
89 req->out.data = req->out.vwv + VWV(wct) + 2;
90 req->out.data_size = buflen;
91 req->out.ptr = req->out.data;
93 SCVAL(req->out.buffer, chain_base_size, wct);
94 SSVAL(req->out.vwv, VWV(wct), buflen);
99 setup a reply in req->out with the given word count and initial data buffer size.
100 the caller will then fill in the command words and data before calling req_send_reply() to
101 send the reply on its way
103 void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
105 if (req->chain_count != 0) {
106 req_setup_chain_reply(req, wct, buflen);
110 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen;
112 /* over allocate by a small amount */
113 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
115 req->out.buffer = talloc(req, req->out.allocated);
116 if (!req->out.buffer) {
117 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
120 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
121 req->out.vwv = req->out.hdr + HDR_VWV;
123 req->out.data = req->out.vwv + VWV(wct) + 2;
124 req->out.data_size = buflen;
125 req->out.ptr = req->out.data;
127 SIVAL(req->out.hdr, HDR_RCLS, 0);
129 SCVAL(req->out.hdr, HDR_WCT, wct);
130 SSVAL(req->out.vwv, VWV(wct), buflen);
133 memcpy(req->out.hdr, "\377SMB", 4);
134 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
135 SSVAL(req->out.hdr,HDR_FLG2,
136 (req->flags2 & FLAGS2_UNICODE_STRINGS) |
137 FLAGS2_LONG_PATH_COMPONENTS | FLAGS2_32_BIT_ERROR_CODES | FLAGS2_EXTENDED_SECURITY);
139 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
140 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
143 /* copy the cmd, tid, pid, uid and mid from the request */
144 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
145 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
146 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
147 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
148 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
150 SSVAL(req->out.hdr,HDR_TID,0);
151 SSVAL(req->out.hdr,HDR_PID,0);
152 SSVAL(req->out.hdr,HDR_UID,0);
153 SSVAL(req->out.hdr,HDR_MID,0);
158 work out the maximum data size we will allow for this reply, given
159 the negotiated max_xmit. The basic reply packet must be setup before
162 note that this is deliberately a signed integer reply
164 int req_max_data(struct smbsrv_request *req)
167 ret = req->smb_conn->negotiate.max_send;
168 ret -= PTR_DIFF(req->out.data, req->out.hdr);
169 if (ret < 0) ret = 0;
175 grow the allocation of the data buffer portion of a reply
176 packet. Note that as this can reallocate the packet buffer this
177 invalidates any local pointers into the packet.
179 To cope with this req->out.ptr is supplied. This will be updated to
180 point at the same offset into the packet as before this call
182 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
187 delta = new_size - req->out.data_size;
188 if (delta + req->out.size <= req->out.allocated) {
189 /* it fits in the preallocation */
193 /* we need to realloc */
194 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
195 buf2 = talloc_realloc(req->out.buffer, req->out.allocated);
197 smb_panic("out of memory in req_grow_allocation");
200 if (buf2 == req->out.buffer) {
201 /* the malloc library gave us the same pointer */
205 /* update the pointers into the packet */
206 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
207 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
208 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
209 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
211 req->out.buffer = buf2;
216 grow the data buffer portion of a reply packet. Note that as this
217 can reallocate the packet buffer this invalidates any local pointers
220 To cope with this req->out.ptr is supplied. This will be updated to
221 point at the same offset into the packet as before this call
223 void req_grow_data(struct smbsrv_request *req, uint_t new_size)
227 if (!(req->control_flags & REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
228 smb_panic("reply buffer too large!");
231 req_grow_allocation(req, new_size);
233 delta = new_size - req->out.data_size;
235 req->out.size += delta;
236 req->out.data_size += delta;
238 /* set the BCC to the new data size */
239 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
243 send a reply and destroy the request buffer
245 note that this only looks at req->out.buffer and req->out.size, allowing manually
246 constructed packets to be sent
248 void req_send_reply_nosign(struct smbsrv_request *req)
254 if (req->out.size > NBT_HDR_SIZE) {
255 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
258 tmp_blob.data = req->out.buffer;
259 tmp_blob.length = req->out.size;
261 status = socket_send(req->smb_conn->connection->socket, req, &tmp_blob, &sendlen, SOCKET_FLAG_BLOCK);
262 if (!NT_STATUS_IS_OK(status) || (req->out.size != sendlen)) {
263 smbsrv_terminate_connection(req->smb_conn, "failed to send reply\n");
270 possibly sign a message then send a reply and destroy the request buffer
272 note that this only looks at req->out.buffer and req->out.size, allowing manually
273 constructed packets to be sent
275 void req_send_reply(struct smbsrv_request *req)
277 req_sign_packet(req);
279 req_send_reply_nosign(req);
285 construct and send an error packet with a forced DOS error code
286 this is needed to match win2000 behaviour for some parts of the protocol
288 void req_reply_dos_error(struct smbsrv_request *req, uint8_t eclass, uint16_t ecode)
290 /* if the basic packet hasn't been setup yet then do it now */
291 if (req->out.buffer == NULL) {
292 req_setup_reply(req, 0, 0);
295 SCVAL(req->out.hdr, HDR_RCLS, eclass);
296 SSVAL(req->out.hdr, HDR_ERR, ecode);
297 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
302 setup the header of a reply to include an NTSTATUS code
304 void req_setup_error(struct smbsrv_request *req, NTSTATUS status)
306 if (!lp_nt_status_support() || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
307 /* convert to DOS error codes */
310 ntstatus_to_dos(status, &eclass, &ecode);
311 SCVAL(req->out.hdr, HDR_RCLS, eclass);
312 SSVAL(req->out.hdr, HDR_ERR, ecode);
313 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
317 if (NT_STATUS_IS_DOS(status)) {
318 /* its a encoded DOS error, using the reserved range */
319 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
320 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
321 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
323 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
324 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
329 construct and send an error packet, then destroy the request
330 auto-converts to DOS error format when appropriate
332 void req_reply_error(struct smbsrv_request *req, NTSTATUS status)
334 req_setup_reply(req, 0, 0);
336 /* error returns never have any data */
337 req_grow_data(req, 0);
339 req_setup_error(req, status);
345 push a string into the data portion of the request packet, growing it if necessary
346 this gets quite tricky - please be very careful to cover all cases when modifying this
348 if dest is NULL, then put the string at the end of the data portion of the packet
350 if dest_len is -1 then no limit applies
352 size_t req_push_str(struct smbsrv_request *req, char *dest, const char *str, int dest_len, uint_t flags)
357 const int max_bytes_per_char = 3;
359 if (!(flags & (STR_ASCII|STR_UNICODE))) {
360 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
364 dest = req->out.data + req->out.data_size;
367 if (dest_len != -1) {
370 len = (strlen(str)+2) * max_bytes_per_char;
373 grow_size = len + PTR_DIFF(dest, req->out.data);
374 buf0 = req->out.buffer;
376 req_grow_allocation(req, grow_size);
378 if (buf0 != req->out.buffer) {
379 dest = req->out.buffer + PTR_DIFF(dest, buf0);
382 len = push_string(req->out.hdr, dest, str, len, flags);
384 grow_size = len + PTR_DIFF(dest, req->out.data);
386 if (grow_size > req->out.data_size) {
387 req_grow_data(req, grow_size);
394 append raw bytes into the data portion of the request packet
395 return the number of bytes added
397 size_t req_append_bytes(struct smbsrv_request *req,
398 const uint8_t *bytes, size_t byte_len)
400 req_grow_allocation(req, byte_len + req->out.data_size);
401 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
402 req_grow_data(req, byte_len + req->out.data_size);
406 append variable block (type 5 buffer) into the data portion of the request packet
407 return the number of bytes added
409 size_t req_append_var_block(struct smbsrv_request *req,
410 const uint8_t *bytes, uint16_t byte_len)
412 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
413 SCVAL(req->out.data + req->out.data_size, 0, 5);
414 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
416 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
418 req_grow_data(req, byte_len + 3 + req->out.data_size);
422 pull a UCS2 string from a request packet, returning a talloced unix string
424 the string length is limited by the 3 things:
425 - the data size in the request (end of packet)
426 - the passed 'byte_len' if it is not -1
427 - the end of string (null termination)
429 Note that 'byte_len' is the number of bytes in the packet
431 on failure zero is returned and *dest is set to NULL, otherwise the number
432 of bytes consumed in the packet is returned
434 static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const char *src, int byte_len, uint_t flags)
436 int src_len, src_len2, alignment=0;
439 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
442 if (byte_len != -1) {
447 if (flags & STR_NO_RANGE_CHECK) {
450 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
456 if (byte_len != -1 && src_len > byte_len) {
461 src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
463 if (src_len2 <= src_len - 2) {
464 /* include the termination if we didn't reach the end of the packet */
468 ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (const void **)dest);
475 return src_len2 + alignment;
479 pull a ascii string from a request packet, returning a talloced string
481 the string length is limited by the 3 things:
482 - the data size in the request (end of packet)
483 - the passed 'byte_len' if it is not -1
484 - the end of string (null termination)
486 Note that 'byte_len' is the number of bytes in the packet
488 on failure zero is returned and *dest is set to NULL, otherwise the number
489 of bytes consumed in the packet is returned
491 static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const char *src, int byte_len, uint_t flags)
493 int src_len, src_len2;
496 if (flags & STR_NO_RANGE_CHECK) {
499 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
504 if (byte_len != -1 && src_len > byte_len) {
509 src_len2 = strnlen(src, src_len);
510 if (src_len2 <= src_len - 1) {
511 /* include the termination if we didn't reach the end of the packet */
515 ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
526 pull a string from a request packet, returning a talloced string
528 the string length is limited by the 3 things:
529 - the data size in the request (end of packet)
530 - the passed 'byte_len' if it is not -1
531 - the end of string (null termination)
533 Note that 'byte_len' is the number of bytes in the packet
535 on failure zero is returned and *dest is set to NULL, otherwise the number
536 of bytes consumed in the packet is returned
538 size_t req_pull_string(struct smbsrv_request *req, const char **dest, const char *src, int byte_len, uint_t flags)
540 if (!(flags & STR_ASCII) &&
541 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
542 return req_pull_ucs2(req, dest, src, byte_len, flags);
545 return req_pull_ascii(req, dest, src, byte_len, flags);
550 pull a ASCII4 string buffer from a request packet, returning a talloced string
552 an ASCII4 buffer is a null terminated string that has a prefix
553 of the character 0x4. It tends to be used in older parts of the protocol.
555 on failure *dest is set to the zero length string. This seems to
556 match win2000 behaviour
558 size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const char *src, uint_t flags)
562 if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
563 /* win2000 treats this as the NULL string! */
564 (*dest) = talloc_strdup(req, "");
568 /* this consumes the 0x4 byte. We don't check whether the byte
569 is actually 0x4 or not. This matches win2000 server
573 ret = req_pull_string(req, dest, src, -1, flags);
575 (*dest) = talloc_strdup(req, "");
583 pull a DATA_BLOB from a request packet, returning a talloced blob
585 return False if any part is outside the data portion of the packet
587 BOOL req_pull_blob(struct smbsrv_request *req, const char *src, int len, DATA_BLOB *blob)
589 if (len != 0 && req_data_oob(req, src, len)) {
593 (*blob) = data_blob_talloc(req, src, len);
598 /* check that a lump of data in a request is within the bounds of the data section of
600 BOOL req_data_oob(struct smbsrv_request *req, const char *ptr, uint32_t count)
606 /* be careful with wraparound! */
607 if (ptr < req->in.data ||
608 ptr >= req->in.data + req->in.data_size ||
609 count > req->in.data_size ||
610 ptr + count > req->in.data + req->in.data_size) {
618 pull an open file handle from a packet, taking account of the chained_fnum
620 uint16_t req_fnum(struct smbsrv_request *req, const char *base, uint_t offset)
622 if (req->chained_fnum != -1) {
623 return req->chained_fnum;
625 return SVAL(base, offset);