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 /* ahh, its so nice to destroy a complex structure in such a
38 /****************************************************************************
39 construct a basic request packet, mostly used to construct async packets
40 such as change notify and oplock break requests
41 ****************************************************************************/
42 struct smbsrv_request *init_smb_request(struct smbsrv_connection *smb_conn)
44 struct smbsrv_request *req;
46 smb_conn->pkt_count++;
48 req = talloc_p(smb_conn, struct smbsrv_request);
55 /* setup the request context */
56 req->smb_conn = smb_conn;
63 setup a chained reply in req->out with the given word count and initial data buffer size.
65 static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
67 uint32_t chain_base_size = req->out.size;
69 /* we need room for the wct value, the words, the buffer length and the buffer */
70 req->out.size += 1 + VWV(wct) + 2 + buflen;
72 /* over allocate by a small amount */
73 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
75 req->out.buffer = talloc_realloc(req, req->out.buffer, req->out.allocated);
76 if (!req->out.buffer) {
77 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
80 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
81 req->out.vwv = req->out.buffer + chain_base_size + 1;
83 req->out.data = req->out.vwv + VWV(wct) + 2;
84 req->out.data_size = buflen;
85 req->out.ptr = req->out.data;
87 SCVAL(req->out.buffer, chain_base_size, wct);
88 SSVAL(req->out.vwv, VWV(wct), buflen);
93 setup a reply in req->out with the given word count and initial data buffer size.
94 the caller will then fill in the command words and data before calling req_send_reply() to
95 send the reply on its way
97 void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
99 if (req->chain_count != 0) {
100 req_setup_chain_reply(req, wct, buflen);
104 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen;
106 /* over allocate by a small amount */
107 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
109 req->out.buffer = talloc(req, req->out.allocated);
110 if (!req->out.buffer) {
111 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
114 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
115 req->out.vwv = req->out.hdr + HDR_VWV;
117 req->out.data = req->out.vwv + VWV(wct) + 2;
118 req->out.data_size = buflen;
119 req->out.ptr = req->out.data;
121 SIVAL(req->out.hdr, HDR_RCLS, 0);
123 SCVAL(req->out.hdr, HDR_WCT, wct);
124 SSVAL(req->out.vwv, VWV(wct), buflen);
127 memcpy(req->out.hdr, "\377SMB", 4);
128 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
129 SSVAL(req->out.hdr,HDR_FLG2,
130 (req->flags2 & FLAGS2_UNICODE_STRINGS) |
131 FLAGS2_LONG_PATH_COMPONENTS | FLAGS2_32_BIT_ERROR_CODES | FLAGS2_EXTENDED_SECURITY);
133 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
134 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
137 /* copy the cmd, tid, pid, uid and mid from the request */
138 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
139 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
140 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
141 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
142 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
144 SSVAL(req->out.hdr,HDR_TID,0);
145 SSVAL(req->out.hdr,HDR_PID,0);
146 SSVAL(req->out.hdr,HDR_UID,0);
147 SSVAL(req->out.hdr,HDR_MID,0);
152 work out the maximum data size we will allow for this reply, given
153 the negotiated max_xmit. The basic reply packet must be setup before
156 note that this is deliberately a signed integer reply
158 int req_max_data(struct smbsrv_request *req)
161 ret = req->smb_conn->negotiate.max_send;
162 ret -= PTR_DIFF(req->out.data, req->out.hdr);
163 if (ret < 0) ret = 0;
169 grow the allocation of the data buffer portion of a reply
170 packet. Note that as this can reallocate the packet buffer this
171 invalidates any local pointers into the packet.
173 To cope with this req->out.ptr is supplied. This will be updated to
174 point at the same offset into the packet as before this call
176 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
181 delta = new_size - req->out.data_size;
182 if (delta + req->out.size <= req->out.allocated) {
183 /* it fits in the preallocation */
187 /* we need to realloc */
188 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
189 buf2 = talloc_realloc(req, req->out.buffer, req->out.allocated);
191 smb_panic("out of memory in req_grow_allocation");
194 if (buf2 == req->out.buffer) {
195 /* the malloc library gave us the same pointer */
199 /* update the pointers into the packet */
200 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
201 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
202 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
203 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
205 req->out.buffer = buf2;
210 grow the data buffer portion of a reply packet. Note that as this
211 can reallocate the packet buffer this invalidates any local pointers
214 To cope with this req->out.ptr is supplied. This will be updated to
215 point at the same offset into the packet as before this call
217 void req_grow_data(struct smbsrv_request *req, uint_t new_size)
221 if (!(req->control_flags & REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
222 smb_panic("reply buffer too large!");
225 req_grow_allocation(req, new_size);
227 delta = new_size - req->out.data_size;
229 req->out.size += delta;
230 req->out.data_size += delta;
232 /* set the BCC to the new data size */
233 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
237 send a reply and destroy the request buffer
239 note that this only looks at req->out.buffer and req->out.size, allowing manually
240 constructed packets to be sent
242 void req_send_reply_nosign(struct smbsrv_request *req)
248 if (req->out.size > NBT_HDR_SIZE) {
249 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
252 tmp_blob.data = req->out.buffer;
253 tmp_blob.length = req->out.size;
255 status = socket_send(req->smb_conn->connection->socket, &tmp_blob, &sendlen, SOCKET_FLAG_BLOCK);
256 if (!NT_STATUS_IS_OK(status) || (req->out.size != sendlen)) {
257 smbsrv_terminate_connection(req->smb_conn, "failed to send reply\n");
265 possibly sign a message then send a reply and destroy the request buffer
267 note that this only looks at req->out.buffer and req->out.size, allowing manually
268 constructed packets to be sent
270 void req_send_reply(struct smbsrv_request *req)
272 req_sign_packet(req);
274 req_send_reply_nosign(req);
280 construct and send an error packet with a forced DOS error code
281 this is needed to match win2000 behaviour for some parts of the protocol
283 void req_reply_dos_error(struct smbsrv_request *req, uint8_t eclass, uint16_t ecode)
285 /* if the basic packet hasn't been setup yet then do it now */
286 if (req->out.buffer == NULL) {
287 req_setup_reply(req, 0, 0);
290 SCVAL(req->out.hdr, HDR_RCLS, eclass);
291 SSVAL(req->out.hdr, HDR_ERR, ecode);
292 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
297 setup the header of a reply to include an NTSTATUS code
299 void req_setup_error(struct smbsrv_request *req, NTSTATUS status)
301 if (!lp_nt_status_support() || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
302 /* convert to DOS error codes */
305 ntstatus_to_dos(status, &eclass, &ecode);
306 SCVAL(req->out.hdr, HDR_RCLS, eclass);
307 SSVAL(req->out.hdr, HDR_ERR, ecode);
308 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
312 if (NT_STATUS_IS_DOS(status)) {
313 /* its a encoded DOS error, using the reserved range */
314 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
315 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
316 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
318 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
319 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
324 construct and send an error packet, then destroy the request
325 auto-converts to DOS error format when appropriate
327 void req_reply_error(struct smbsrv_request *req, NTSTATUS status)
329 req_setup_reply(req, 0, 0);
331 /* error returns never have any data */
332 req_grow_data(req, 0);
334 req_setup_error(req, status);
340 push a string into the data portion of the request packet, growing it if necessary
341 this gets quite tricky - please be very careful to cover all cases when modifying this
343 if dest is NULL, then put the string at the end of the data portion of the packet
345 if dest_len is -1 then no limit applies
347 size_t req_push_str(struct smbsrv_request *req, char *dest, const char *str, int dest_len, uint_t flags)
352 const int max_bytes_per_char = 3;
354 if (!(flags & (STR_ASCII|STR_UNICODE))) {
355 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
359 dest = req->out.data + req->out.data_size;
362 if (dest_len != -1) {
365 len = (strlen(str)+2) * max_bytes_per_char;
368 grow_size = len + PTR_DIFF(dest, req->out.data);
369 buf0 = req->out.buffer;
371 req_grow_allocation(req, grow_size);
373 if (buf0 != req->out.buffer) {
374 dest = req->out.buffer + PTR_DIFF(dest, buf0);
377 len = push_string(dest, str, len, flags);
379 grow_size = len + PTR_DIFF(dest, req->out.data);
381 if (grow_size > req->out.data_size) {
382 req_grow_data(req, grow_size);
389 append raw bytes into the data portion of the request packet
390 return the number of bytes added
392 size_t req_append_bytes(struct smbsrv_request *req,
393 const uint8_t *bytes, size_t byte_len)
395 req_grow_allocation(req, byte_len + req->out.data_size);
396 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
397 req_grow_data(req, byte_len + req->out.data_size);
401 append variable block (type 5 buffer) into the data portion of the request packet
402 return the number of bytes added
404 size_t req_append_var_block(struct smbsrv_request *req,
405 const uint8_t *bytes, uint16_t byte_len)
407 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
408 SCVAL(req->out.data + req->out.data_size, 0, 5);
409 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
411 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
413 req_grow_data(req, byte_len + 3 + req->out.data_size);
417 pull a UCS2 string from a request packet, returning a talloced unix string
419 the string length is limited by the 3 things:
420 - the data size in the request (end of packet)
421 - the passed 'byte_len' if it is not -1
422 - the end of string (null termination)
424 Note that 'byte_len' is the number of bytes in the packet
426 on failure zero is returned and *dest is set to NULL, otherwise the number
427 of bytes consumed in the packet is returned
429 static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const char *src, int byte_len, uint_t flags)
431 int src_len, src_len2, alignment=0;
435 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
438 if (byte_len != -1) {
443 if (flags & STR_NO_RANGE_CHECK) {
446 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
452 if (byte_len != -1 && src_len > byte_len) {
457 src_len2 = utf16_len_n(src, src_len);
458 ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
466 return src_len2 + alignment;
470 pull a ascii string from a request packet, returning a talloced string
472 the string length is limited by the 3 things:
473 - the data size in the request (end of packet)
474 - the passed 'byte_len' if it is not -1
475 - the end of string (null termination)
477 Note that 'byte_len' is the number of bytes in the packet
479 on failure zero is returned and *dest is set to NULL, otherwise the number
480 of bytes consumed in the packet is returned
482 static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const char *src, int byte_len, uint_t flags)
484 int src_len, src_len2;
488 if (flags & STR_NO_RANGE_CHECK) {
491 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
496 if (byte_len != -1 && src_len > byte_len) {
501 src_len2 = strnlen(src, src_len);
502 if (src_len2 <= src_len - 1) {
503 /* include the termination if we didn't reach the end of the packet */
507 ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
519 pull a string from a request packet, returning a talloced string
521 the string length is limited by the 3 things:
522 - the data size in the request (end of packet)
523 - the passed 'byte_len' if it is not -1
524 - the end of string (null termination)
526 Note that 'byte_len' is the number of bytes in the packet
528 on failure zero is returned and *dest is set to NULL, otherwise the number
529 of bytes consumed in the packet is returned
531 size_t req_pull_string(struct smbsrv_request *req, const char **dest, const char *src, int byte_len, uint_t flags)
533 if (!(flags & STR_ASCII) &&
534 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
535 return req_pull_ucs2(req, dest, src, byte_len, flags);
538 return req_pull_ascii(req, dest, src, byte_len, flags);
543 pull a ASCII4 string buffer from a request packet, returning a talloced string
545 an ASCII4 buffer is a null terminated string that has a prefix
546 of the character 0x4. It tends to be used in older parts of the protocol.
548 on failure *dest is set to the zero length string. This seems to
549 match win2000 behaviour
551 size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const char *src, uint_t flags)
555 if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
556 /* win2000 treats this as the NULL string! */
557 (*dest) = talloc_strdup(req, "");
561 /* this consumes the 0x4 byte. We don't check whether the byte
562 is actually 0x4 or not. This matches win2000 server
566 ret = req_pull_string(req, dest, src, -1, flags);
568 (*dest) = talloc_strdup(req, "");
576 pull a DATA_BLOB from a request packet, returning a talloced blob
578 return False if any part is outside the data portion of the packet
580 BOOL req_pull_blob(struct smbsrv_request *req, const char *src, int len, DATA_BLOB *blob)
582 if (len != 0 && req_data_oob(req, src, len)) {
586 (*blob) = data_blob_talloc(req, src, len);
591 /* check that a lump of data in a request is within the bounds of the data section of
593 BOOL req_data_oob(struct smbsrv_request *req, const char *ptr, uint32_t count)
599 /* be careful with wraparound! */
600 if (ptr < req->in.data ||
601 ptr >= req->in.data + req->in.data_size ||
602 count > req->in.data_size ||
603 ptr + count > req->in.data + req->in.data_size) {
611 pull an open file handle from a packet, taking account of the chained_fnum
613 uint16_t req_fnum(struct smbsrv_request *req, const char *base, uint_t offset)
615 if (req->chained_fnum != -1) {
616 return req->chained_fnum;
618 return SVAL(base, offset);