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 3 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, see <http://www.gnu.org/licenses/>.
21
this file implements functions for manipulating the 'struct smbsrv_request' structure in smbd
25
#include "smb_server/smb_server.h"
26
#include "smb_server/service_smb_proto.h"
27
#include "smbd/service_stream.h"
28
#include "lib/stream/packet.h"
29
#include "ntvfs/ntvfs.h"
32
/* we over allocate the data buffer to prevent too many realloc calls */
33
#define REQ_OVER_ALLOCATION 0
35
/* setup the bufinfo used for strings and range checking */
36
void smbsrv_setup_bufinfo(struct smbsrv_request *req)
38
req->in.bufinfo.mem_ctx = req;
39
req->in.bufinfo.flags = 0;
40
if (req->flags2 & FLAGS2_UNICODE_STRINGS) {
41
req->in.bufinfo.flags |= BUFINFO_FLAG_UNICODE;
43
req->in.bufinfo.align_base = req->in.buffer;
44
req->in.bufinfo.data = req->in.data;
45
req->in.bufinfo.data_size = req->in.data_size;
49
static int smbsrv_request_destructor(struct smbsrv_request *req)
51
DLIST_REMOVE(req->smb_conn->requests, req);
55
/****************************************************************************
56
construct a basic request packet, mostly used to construct async packets
57
such as change notify and oplock break requests
58
****************************************************************************/
59
struct smbsrv_request *smbsrv_init_request(struct smbsrv_connection *smb_conn)
61
struct smbsrv_request *req;
63
req = talloc_zero(smb_conn, struct smbsrv_request);
68
/* setup the request context */
69
req->smb_conn = smb_conn;
71
talloc_set_destructor(req, smbsrv_request_destructor);
78
setup a chained reply in req->out with the given word count and initial data buffer size.
80
static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
82
uint32_t chain_base_size = req->out.size;
84
/* we need room for the wct value, the words, the buffer length and the buffer */
85
req->out.size += 1 + VWV(wct) + 2 + buflen;
87
/* over allocate by a small amount */
88
req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
90
req->out.buffer = talloc_realloc(req, req->out.buffer,
91
uint8_t, req->out.allocated);
92
if (!req->out.buffer) {
93
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 smbsrv_setup_reply(struct smbsrv_request *req, uint_t wct, size_t buflen)
118
if (req->chain_count != 0) {
119
req_setup_chain_reply(req, wct, buflen);
123
req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + buflen;
125
/* over allocate by a small amount */
126
req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
128
req->out.buffer = talloc_size(req, req->out.allocated);
129
if (!req->out.buffer) {
130
smbsrv_terminate_connection(req->smb_conn, "allocation failed");
134
flags2 = FLAGS2_LONG_PATH_COMPONENTS |
135
FLAGS2_EXTENDED_ATTRIBUTES |
137
#define _SMB_FLAGS2_ECHOED_FLAGS ( \
138
FLAGS2_UNICODE_STRINGS | \
139
FLAGS2_EXTENDED_SECURITY | \
140
FLAGS2_SMB_SECURITY_SIGNATURES \
142
flags2 |= (req->flags2 & _SMB_FLAGS2_ECHOED_FLAGS);
143
if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
144
flags2 |= FLAGS2_32_BIT_ERROR_CODES;
147
req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
148
req->out.vwv = req->out.hdr + HDR_VWV;
150
req->out.data = req->out.vwv + VWV(wct) + 2;
151
req->out.data_size = buflen;
152
req->out.ptr = req->out.data;
154
SIVAL(req->out.hdr, HDR_RCLS, 0);
156
SCVAL(req->out.hdr, HDR_WCT, wct);
157
SSVAL(req->out.vwv, VWV(wct), buflen);
159
memcpy(req->out.hdr, "\377SMB", 4);
160
SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
161
SSVAL(req->out.hdr,HDR_FLG2, flags2);
162
SSVAL(req->out.hdr,HDR_PIDHIGH,0);
163
memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
166
/* copy the cmd, tid, pid, uid and mid from the request */
167
SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
168
SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
169
SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
170
SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
171
SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
173
SCVAL(req->out.hdr,HDR_COM,0);
174
SSVAL(req->out.hdr,HDR_TID,0);
175
SSVAL(req->out.hdr,HDR_PID,0);
176
SSVAL(req->out.hdr,HDR_UID,0);
177
SSVAL(req->out.hdr,HDR_MID,0);
183
setup a copy of a request, used when the server needs to send
184
more than one reply for a single request packet
186
struct smbsrv_request *smbsrv_setup_secondary_request(struct smbsrv_request *old_req)
188
struct smbsrv_request *req;
191
req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
196
req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
197
if (req->out.buffer == NULL) {
202
diff = req->out.buffer - old_req->out.buffer;
204
req->out.hdr += diff;
205
req->out.vwv += diff;
206
req->out.data += diff;
207
req->out.ptr += diff;
213
work out the maximum data size we will allow for this reply, given
214
the negotiated max_xmit. The basic reply packet must be setup before
217
note that this is deliberately a signed integer reply
219
int req_max_data(struct smbsrv_request *req)
222
ret = req->smb_conn->negotiate.max_send;
223
ret -= PTR_DIFF(req->out.data, req->out.hdr);
224
if (ret < 0) ret = 0;
230
grow the allocation of the data buffer portion of a reply
231
packet. Note that as this can reallocate the packet buffer this
232
invalidates any local pointers into the packet.
234
To cope with this req->out.ptr is supplied. This will be updated to
235
point at the same offset into the packet as before this call
237
static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
242
delta = new_size - req->out.data_size;
243
if (delta + req->out.size <= req->out.allocated) {
244
/* it fits in the preallocation */
248
/* we need to realloc */
249
req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
250
buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
252
smb_panic("out of memory in req_grow_allocation");
255
if (buf2 == req->out.buffer) {
256
/* the malloc library gave us the same pointer */
260
/* update the pointers into the packet */
261
req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
262
req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
263
req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
264
req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
266
req->out.buffer = buf2;
271
grow the data buffer portion of a reply packet. Note that as this
272
can reallocate the packet buffer this invalidates any local pointers
275
To cope with this req->out.ptr is supplied. This will be updated to
276
point at the same offset into the packet as before this call
278
void req_grow_data(struct smbsrv_request *req, size_t new_size)
282
if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
283
smb_panic("reply buffer too large!");
286
req_grow_allocation(req, new_size);
288
delta = new_size - req->out.data_size;
290
req->out.size += delta;
291
req->out.data_size += delta;
293
/* set the BCC to the new data size */
294
SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
298
send a reply and destroy the request buffer
300
note that this only looks at req->out.buffer and req->out.size, allowing manually
301
constructed packets to be sent
303
void smbsrv_send_reply_nosign(struct smbsrv_request *req)
308
if (req->smb_conn->connection->event.fde == NULL) {
309
/* we are in the process of shutting down this connection */
314
if (req->out.size > NBT_HDR_SIZE) {
315
_smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
318
blob = data_blob_const(req->out.buffer, req->out.size);
319
status = packet_send(req->smb_conn->packet, blob);
320
if (!NT_STATUS_IS_OK(status)) {
321
smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
327
possibly sign a message then send a reply and destroy the request buffer
329
note that this only looks at req->out.buffer and req->out.size, allowing manually
330
constructed packets to be sent
332
void smbsrv_send_reply(struct smbsrv_request *req)
334
if (req->smb_conn->connection->event.fde == NULL) {
335
/* we are in the process of shutting down this connection */
339
smbsrv_sign_packet(req);
341
smbsrv_send_reply_nosign(req);
345
setup the header of a reply to include an NTSTATUS code
347
void smbsrv_setup_error(struct smbsrv_request *req, NTSTATUS status)
349
if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
350
/* convert to DOS error codes */
353
ntstatus_to_dos(status, &eclass, &ecode);
354
SCVAL(req->out.hdr, HDR_RCLS, eclass);
355
SSVAL(req->out.hdr, HDR_ERR, ecode);
356
SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
360
if (NT_STATUS_IS_DOS(status)) {
361
/* its a encoded DOS error, using the reserved range */
362
SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
363
SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
364
SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
366
SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
367
SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
372
construct and send an error packet, then destroy the request
373
auto-converts to DOS error format when appropriate
375
void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status)
377
if (req->smb_conn->connection->event.fde == NULL) {
378
/* the socket has been destroyed - no point trying to send an error! */
382
smbsrv_setup_reply(req, 0, 0);
384
/* error returns never have any data */
385
req_grow_data(req, 0);
387
smbsrv_setup_error(req, status);
388
smbsrv_send_reply(req);
393
push a string into the data portion of the request packet, growing it if necessary
394
this gets quite tricky - please be very careful to cover all cases when modifying this
396
if dest is NULL, then put the string at the end of the data portion of the packet
398
if dest_len is -1 then no limit applies
400
size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, size_t flags)
405
const int max_bytes_per_char = 3;
407
if (!(flags & (STR_ASCII|STR_UNICODE))) {
408
flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
412
dest = req->out.data + req->out.data_size;
415
if (dest_len != -1) {
418
len = (strlen(str)+2) * max_bytes_per_char;
421
grow_size = len + PTR_DIFF(dest, req->out.data);
422
buf0 = req->out.buffer;
424
req_grow_allocation(req, grow_size);
426
if (buf0 != req->out.buffer) {
427
dest = req->out.buffer + PTR_DIFF(dest, buf0);
430
len = push_string(dest, str, len, flags);
432
grow_size = len + PTR_DIFF(dest, req->out.data);
434
if (grow_size > req->out.data_size) {
435
req_grow_data(req, grow_size);
442
append raw bytes into the data portion of the request packet
443
return the number of bytes added
445
size_t req_append_bytes(struct smbsrv_request *req,
446
const uint8_t *bytes, size_t byte_len)
448
req_grow_allocation(req, byte_len + req->out.data_size);
449
memcpy(req->out.data + req->out.data_size, bytes, byte_len);
450
req_grow_data(req, byte_len + req->out.data_size);
454
append variable block (type 5 buffer) into the data portion of the request packet
455
return the number of bytes added
457
size_t req_append_var_block(struct smbsrv_request *req,
458
const uint8_t *bytes, uint16_t byte_len)
460
req_grow_allocation(req, byte_len + 3 + req->out.data_size);
461
SCVAL(req->out.data + req->out.data_size, 0, 5);
462
SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
464
memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
466
req_grow_data(req, byte_len + 3 + req->out.data_size);
470
pull a UCS2 string from a request packet, returning a talloced unix 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_ucs2(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
484
int src_len, src_len2, alignment=0;
488
if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
491
if (byte_len != -1) {
496
if (flags & STR_NO_RANGE_CHECK) {
499
src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
500
if (byte_len != -1 && src_len > byte_len) {
510
src_len2 = utf16_len_n(src, src_len);
512
*dest = talloc_strdup(bufinfo->mem_ctx, "");
513
return src_len2 + alignment;
516
ret = convert_string_talloc(bufinfo->mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, NULL, false);
524
return src_len2 + alignment;
528
pull a ascii string from a request packet, returning a talloced string
530
the string length is limited by the 3 things:
531
- the data size in the request (end of packet)
532
- the passed 'byte_len' if it is not -1
533
- the end of string (null termination)
535
Note that 'byte_len' is the number of bytes in the packet
537
on failure zero is returned and *dest is set to NULL, otherwise the number
538
of bytes consumed in the packet is returned
540
static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
542
int src_len, src_len2;
546
if (flags & STR_NO_RANGE_CHECK) {
549
src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
554
if (byte_len != -1 && src_len > byte_len) {
559
src_len2 = strnlen((const char *)src, src_len);
560
if (src_len2 <= src_len - 1) {
561
/* include the termination if we didn't reach the end of the packet */
565
ret = convert_string_talloc(bufinfo->mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2, NULL, false);
577
pull a string from a request packet, returning a talloced string
579
the string length is limited by the 3 things:
580
- the data size in the request (end of packet)
581
- the passed 'byte_len' if it is not -1
582
- the end of string (null termination)
584
Note that 'byte_len' is the number of bytes in the packet
586
on failure zero is returned and *dest is set to NULL, otherwise the number
587
of bytes consumed in the packet is returned
589
size_t req_pull_string(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
591
if (!(flags & STR_ASCII) &&
592
(((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) {
593
return req_pull_ucs2(bufinfo, dest, src, byte_len, flags);
596
return req_pull_ascii(bufinfo, dest, src, byte_len, flags);
601
pull a ASCII4 string buffer from a request packet, returning a talloced string
603
an ASCII4 buffer is a null terminated string that has a prefix
604
of the character 0x4. It tends to be used in older parts of the protocol.
606
on failure *dest is set to the zero length string. This seems to
607
match win2000 behaviour
609
size_t req_pull_ascii4(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, uint_t flags)
613
if (PTR_DIFF(src, bufinfo->data) + 1 > bufinfo->data_size) {
614
/* win2000 treats this as the empty string! */
615
(*dest) = talloc_strdup(bufinfo->mem_ctx, "");
619
/* this consumes the 0x4 byte. We don't check whether the byte
620
is actually 0x4 or not. This matches win2000 server
624
ret = req_pull_string(bufinfo, dest, src, -1, flags);
626
(*dest) = talloc_strdup(bufinfo->mem_ctx, "");
634
pull a DATA_BLOB from a request packet, returning a talloced blob
636
return false if any part is outside the data portion of the packet
638
bool req_pull_blob(struct request_bufinfo *bufinfo, const uint8_t *src, int len, DATA_BLOB *blob)
640
if (len != 0 && req_data_oob(bufinfo, src, len)) {
644
(*blob) = data_blob_talloc(bufinfo->mem_ctx, src, len);
649
/* check that a lump of data in a request is within the bounds of the data section of
651
bool req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count)
657
/* be careful with wraparound! */
658
if ((uintptr_t)ptr < (uintptr_t)bufinfo->data ||
659
(uintptr_t)ptr >= (uintptr_t)bufinfo->data + bufinfo->data_size ||
660
count > bufinfo->data_size ||
661
(uintptr_t)ptr + count > (uintptr_t)bufinfo->data + bufinfo->data_size) {
669
pull an open file handle from a packet, taking account of the chained_fnum
671
static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
673
if (req->chained_fnum != -1) {
674
return req->chained_fnum;
676
return SVAL(base, offset);
679
struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
681
struct smbsrv_handle *handle;
682
uint16_t fnum = req_fnum(req, base, offset);
684
handle = smbsrv_smb_handle_find(req->tcon, fnum, req->request_time);
690
* For SMB tcons and sessions can be mixed!
691
* But we need to make sure that file handles
692
* are only accessed by the opening session!
694
* So check if the handle is valid for the given session!
696
if (handle->session != req->session) {
700
return handle->ntvfs;
703
void smbsrv_push_fnum(uint8_t *base, uint_t offset, struct ntvfs_handle *ntvfs)
705
struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
706
struct smbsrv_handle);
707
SSVAL(base, offset, handle->hid);
710
NTSTATUS smbsrv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
712
struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
713
struct smbsrv_request);
714
struct smbsrv_handle *handle;
715
struct ntvfs_handle *h;
717
handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
718
if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
720
h = talloc_zero(handle, struct ntvfs_handle);
724
* note: we don't set handle->ntvfs yet,
725
* this will be done by smbsrv_handle_make_valid()
726
* this makes sure the handle is invalid for clients
727
* until the ntvfs subsystem has made it valid
730
h->session_info = ntvfs->session_info;
731
h->smbpid = ntvfs->smbpid;
733
h->frontend_data.private_data = handle;
739
return NT_STATUS_NO_MEMORY;
742
NTSTATUS smbsrv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
744
struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
745
struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
746
struct smbsrv_handle);
747
/* this tells the frontend that the handle is valid */
749
/* this moves the smbsrv_request to the smbsrv_tcon memory context */
750
talloc_steal(tcon, handle);
754
void smbsrv_handle_destroy(void *private_data, struct ntvfs_handle *h)
756
struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
757
struct smbsrv_handle);
761
struct ntvfs_handle *smbsrv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
763
struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
764
struct smbsrv_request);
766
if (key->length != 2) return NULL;
768
return smbsrv_pull_fnum(req, key->data, 0);
771
DATA_BLOB smbsrv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
775
smbsrv_push_fnum(key, 0, handle);
777
return data_blob_talloc(mem_ctx, key, sizeof(key));