~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/smb_server/smb/request.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
   
 
4
   Copyright (C) Andrew Tridgell              2003
 
5
   
 
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.
 
10
   
 
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.
 
15
   
 
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/>.
 
18
*/
 
19
 
 
20
/*
 
21
  this file implements functions for manipulating the 'struct smbsrv_request' structure in smbd
 
22
*/
 
23
 
 
24
#include "includes.h"
 
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"
 
30
 
 
31
 
 
32
/* we over allocate the data buffer to prevent too many realloc calls */
 
33
#define REQ_OVER_ALLOCATION 0
 
34
 
 
35
/* setup the bufinfo used for strings and range checking */
 
36
void smbsrv_setup_bufinfo(struct smbsrv_request *req)
 
37
{
 
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;
 
42
        }
 
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;
 
46
}
 
47
 
 
48
 
 
49
static int smbsrv_request_destructor(struct smbsrv_request *req)
 
50
{
 
51
        DLIST_REMOVE(req->smb_conn->requests, req);
 
52
        return 0;
 
53
}
 
54
 
 
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)
 
60
{
 
61
        struct smbsrv_request *req;
 
62
 
 
63
        req = talloc_zero(smb_conn, struct smbsrv_request);
 
64
        if (!req) {
 
65
                return NULL;
 
66
        }
 
67
 
 
68
        /* setup the request context */
 
69
        req->smb_conn = smb_conn;
 
70
 
 
71
        talloc_set_destructor(req, smbsrv_request_destructor);
 
72
 
 
73
        return req;
 
74
}
 
75
 
 
76
 
 
77
/*
 
78
  setup a chained reply in req->out with the given word count and initial data buffer size. 
 
79
*/
 
80
static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
 
81
{
 
82
        uint32_t chain_base_size = req->out.size;
 
83
 
 
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;
 
86
 
 
87
        /* over allocate by a small amount */
 
88
        req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 
 
89
 
 
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");
 
94
                return;
 
95
        }
 
96
 
 
97
        req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
 
98
        req->out.vwv = req->out.buffer + chain_base_size + 1;
 
99
        req->out.wct = wct;
 
100
        req->out.data = req->out.vwv + VWV(wct) + 2;
 
101
        req->out.data_size = buflen;
 
102
        req->out.ptr = req->out.data;
 
103
 
 
104
        SCVAL(req->out.buffer, chain_base_size, wct);
 
105
        SSVAL(req->out.vwv, VWV(wct), buflen);
 
106
}
 
107
 
 
108
 
 
109
/*
 
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
 
113
*/
 
114
void smbsrv_setup_reply(struct smbsrv_request *req, uint_t wct, size_t buflen)
 
115
{
 
116
        uint16_t flags2;
 
117
 
 
118
        if (req->chain_count != 0) {
 
119
                req_setup_chain_reply(req, wct, buflen);
 
120
                return;
 
121
        }
 
122
 
 
123
        req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + buflen;
 
124
 
 
125
        /* over allocate by a small amount */
 
126
        req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 
 
127
 
 
128
        req->out.buffer = talloc_size(req, req->out.allocated);
 
129
        if (!req->out.buffer) {
 
130
                smbsrv_terminate_connection(req->smb_conn, "allocation failed");
 
131
                return;
 
132
        }
 
133
 
 
134
        flags2 = FLAGS2_LONG_PATH_COMPONENTS | 
 
135
                FLAGS2_EXTENDED_ATTRIBUTES | 
 
136
                FLAGS2_IS_LONG_NAME;
 
137
#define _SMB_FLAGS2_ECHOED_FLAGS ( \
 
138
        FLAGS2_UNICODE_STRINGS | \
 
139
        FLAGS2_EXTENDED_SECURITY | \
 
140
        FLAGS2_SMB_SECURITY_SIGNATURES \
 
141
)
 
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;
 
145
        }
 
146
 
 
147
        req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
 
148
        req->out.vwv = req->out.hdr + HDR_VWV;
 
149
        req->out.wct = wct;
 
150
        req->out.data = req->out.vwv + VWV(wct) + 2;
 
151
        req->out.data_size = buflen;
 
152
        req->out.ptr = req->out.data;
 
153
 
 
154
        SIVAL(req->out.hdr, HDR_RCLS, 0);
 
155
 
 
156
        SCVAL(req->out.hdr, HDR_WCT, wct);
 
157
        SSVAL(req->out.vwv, VWV(wct), buflen);
 
158
 
 
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);
 
164
 
 
165
        if (req->in.hdr) {
 
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));
 
172
        } else {
 
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);
 
178
        }
 
179
}
 
180
 
 
181
 
 
182
/*
 
183
  setup a copy of a request, used when the server needs to send
 
184
  more than one reply for a single request packet
 
185
*/
 
186
struct smbsrv_request *smbsrv_setup_secondary_request(struct smbsrv_request *old_req)
 
187
{
 
188
        struct smbsrv_request *req;
 
189
        ptrdiff_t diff;
 
190
 
 
191
        req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
 
192
        if (req == NULL) {
 
193
                return NULL;
 
194
        }
 
195
 
 
196
        req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
 
197
        if (req->out.buffer == NULL) {
 
198
                talloc_free(req);
 
199
                return NULL;
 
200
        }
 
201
 
 
202
        diff = req->out.buffer - old_req->out.buffer;
 
203
 
 
204
        req->out.hdr  += diff;
 
205
        req->out.vwv  += diff;
 
206
        req->out.data += diff;
 
207
        req->out.ptr  += diff;
 
208
 
 
209
        return req;
 
210
}
 
211
 
 
212
/*
 
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
 
215
  this call
 
216
 
 
217
  note that this is deliberately a signed integer reply
 
218
*/
 
219
int req_max_data(struct smbsrv_request *req)
 
220
{
 
221
        int ret;
 
222
        ret = req->smb_conn->negotiate.max_send;
 
223
        ret -= PTR_DIFF(req->out.data, req->out.hdr);
 
224
        if (ret < 0) ret = 0;
 
225
        return ret;
 
226
}
 
227
 
 
228
 
 
229
/*
 
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.
 
233
 
 
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
 
236
*/
 
237
static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
 
238
{
 
239
        int delta;
 
240
        uint8_t *buf2;
 
241
 
 
242
        delta = new_size - req->out.data_size;
 
243
        if (delta + req->out.size <= req->out.allocated) {
 
244
                /* it fits in the preallocation */
 
245
                return;
 
246
        }
 
247
 
 
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);
 
251
        if (buf2 == NULL) {
 
252
                smb_panic("out of memory in req_grow_allocation");
 
253
        }
 
254
 
 
255
        if (buf2 == req->out.buffer) {
 
256
                /* the malloc library gave us the same pointer */
 
257
                return;
 
258
        }
 
259
        
 
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);
 
265
 
 
266
        req->out.buffer = buf2;
 
267
}
 
268
 
 
269
 
 
270
/*
 
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
 
273
  into the packet. 
 
274
 
 
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
 
277
*/
 
278
void req_grow_data(struct smbsrv_request *req, size_t new_size)
 
279
{
 
280
        int delta;
 
281
 
 
282
        if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
 
283
                smb_panic("reply buffer too large!");
 
284
        }
 
285
 
 
286
        req_grow_allocation(req, new_size);
 
287
 
 
288
        delta = new_size - req->out.data_size;
 
289
 
 
290
        req->out.size += delta;
 
291
        req->out.data_size += delta;
 
292
 
 
293
        /* set the BCC to the new data size */
 
294
        SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
 
295
}
 
296
 
 
297
/*
 
298
  send a reply and destroy the request buffer
 
299
 
 
300
  note that this only looks at req->out.buffer and req->out.size, allowing manually 
 
301
  constructed packets to be sent
 
302
*/
 
303
void smbsrv_send_reply_nosign(struct smbsrv_request *req)
 
304
{
 
305
        DATA_BLOB blob;
 
306
        NTSTATUS status;
 
307
 
 
308
        if (req->smb_conn->connection->event.fde == NULL) {
 
309
                /* we are in the process of shutting down this connection */
 
310
                talloc_free(req);
 
311
                return;
 
312
        }
 
313
 
 
314
        if (req->out.size > NBT_HDR_SIZE) {
 
315
                _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
 
316
        }
 
317
 
 
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));
 
322
        }
 
323
        talloc_free(req);
 
324
}
 
325
 
 
326
/*
 
327
  possibly sign a message then send a reply and destroy the request buffer
 
328
 
 
329
  note that this only looks at req->out.buffer and req->out.size, allowing manually 
 
330
  constructed packets to be sent
 
331
*/
 
332
void smbsrv_send_reply(struct smbsrv_request *req)
 
333
{
 
334
        if (req->smb_conn->connection->event.fde == NULL) {
 
335
                /* we are in the process of shutting down this connection */
 
336
                talloc_free(req);
 
337
                return;
 
338
        }
 
339
        smbsrv_sign_packet(req);
 
340
 
 
341
        smbsrv_send_reply_nosign(req);
 
342
}
 
343
 
 
344
/* 
 
345
   setup the header of a reply to include an NTSTATUS code
 
346
*/
 
347
void smbsrv_setup_error(struct smbsrv_request *req, NTSTATUS status)
 
348
{
 
349
        if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
 
350
                /* convert to DOS error codes */
 
351
                uint8_t eclass;
 
352
                uint32_t ecode;
 
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);
 
357
                return;
 
358
        }
 
359
 
 
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);
 
365
        } else {
 
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);
 
368
        }
 
369
}
 
370
 
 
371
/* 
 
372
   construct and send an error packet, then destroy the request 
 
373
   auto-converts to DOS error format when appropriate
 
374
*/
 
375
void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status)
 
376
{
 
377
        if (req->smb_conn->connection->event.fde == NULL) {
 
378
                /* the socket has been destroyed - no point trying to send an error! */
 
379
                talloc_free(req);
 
380
                return;
 
381
        }
 
382
        smbsrv_setup_reply(req, 0, 0);
 
383
 
 
384
        /* error returns never have any data */
 
385
        req_grow_data(req, 0);
 
386
 
 
387
        smbsrv_setup_error(req, status);
 
388
        smbsrv_send_reply(req);
 
389
}
 
390
 
 
391
 
 
392
/*
 
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
 
395
 
 
396
  if dest is NULL, then put the string at the end of the data portion of the packet
 
397
 
 
398
  if dest_len is -1 then no limit applies
 
399
*/
 
400
size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, size_t flags)
 
401
{
 
402
        size_t len;
 
403
        uint_t grow_size;
 
404
        uint8_t *buf0;
 
405
        const int max_bytes_per_char = 3;
 
406
 
 
407
        if (!(flags & (STR_ASCII|STR_UNICODE))) {
 
408
                flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
 
409
        }
 
410
 
 
411
        if (dest == NULL) {
 
412
                dest = req->out.data + req->out.data_size;
 
413
        }
 
414
 
 
415
        if (dest_len != -1) {
 
416
                len = dest_len;
 
417
        } else {
 
418
                len = (strlen(str)+2) * max_bytes_per_char;
 
419
        }
 
420
 
 
421
        grow_size = len + PTR_DIFF(dest, req->out.data);
 
422
        buf0 = req->out.buffer;
 
423
 
 
424
        req_grow_allocation(req, grow_size);
 
425
 
 
426
        if (buf0 != req->out.buffer) {
 
427
                dest = req->out.buffer + PTR_DIFF(dest, buf0);
 
428
        }
 
429
 
 
430
        len = push_string(dest, str, len, flags);
 
431
 
 
432
        grow_size = len + PTR_DIFF(dest, req->out.data);
 
433
 
 
434
        if (grow_size > req->out.data_size) {
 
435
                req_grow_data(req, grow_size);
 
436
        }
 
437
 
 
438
        return len;
 
439
}
 
440
 
 
441
/*
 
442
  append raw bytes into the data portion of the request packet
 
443
  return the number of bytes added
 
444
*/
 
445
size_t req_append_bytes(struct smbsrv_request *req, 
 
446
                        const uint8_t *bytes, size_t byte_len)
 
447
{
 
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);
 
451
        return byte_len;
 
452
}
 
453
/*
 
454
  append variable block (type 5 buffer) into the data portion of the request packet
 
455
  return the number of bytes added
 
456
*/
 
457
size_t req_append_var_block(struct smbsrv_request *req, 
 
458
                const uint8_t *bytes, uint16_t byte_len)
 
459
{
 
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 */
 
463
        if (byte_len > 0) {
 
464
                memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
 
465
        }
 
466
        req_grow_data(req, byte_len + 3 + req->out.data_size);
 
467
        return byte_len + 3;
 
468
}
 
469
/**
 
470
  pull a UCS2 string from a request packet, returning a talloced unix string
 
471
 
 
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)
 
476
 
 
477
  Note that 'byte_len' is the number of bytes in the packet
 
478
 
 
479
  on failure zero is returned and *dest is set to NULL, otherwise the number
 
480
  of bytes consumed in the packet is returned
 
481
*/
 
482
static size_t req_pull_ucs2(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
 
483
{
 
484
        int src_len, src_len2, alignment=0;
 
485
        bool ret;
 
486
        char *dest2;
 
487
 
 
488
        if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
 
489
                src++;
 
490
                alignment=1;
 
491
                if (byte_len != -1) {
 
492
                        byte_len--;
 
493
                }
 
494
        }
 
495
 
 
496
        if (flags & STR_NO_RANGE_CHECK) {
 
497
                src_len = byte_len;
 
498
        } else {
 
499
                src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
 
500
                if (byte_len != -1 && src_len > byte_len) {
 
501
                        src_len = byte_len;
 
502
                }
 
503
        }
 
504
 
 
505
        if (src_len < 0) {
 
506
                *dest = NULL;
 
507
                return 0;
 
508
        }
 
509
        
 
510
        src_len2 = utf16_len_n(src, src_len);
 
511
        if (src_len2 == 0) {
 
512
                *dest = talloc_strdup(bufinfo->mem_ctx, "");
 
513
                return src_len2 + alignment;
 
514
        }
 
515
 
 
516
        ret = convert_string_talloc(bufinfo->mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, NULL, false);
 
517
 
 
518
        if (!ret) {
 
519
                *dest = NULL;
 
520
                return 0;
 
521
        }
 
522
        *dest = dest2;
 
523
 
 
524
        return src_len2 + alignment;
 
525
}
 
526
 
 
527
/**
 
528
  pull a ascii string from a request packet, returning a talloced string
 
529
 
 
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)
 
534
 
 
535
  Note that 'byte_len' is the number of bytes in the packet
 
536
 
 
537
  on failure zero is returned and *dest is set to NULL, otherwise the number
 
538
  of bytes consumed in the packet is returned
 
539
*/
 
540
static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
 
541
{
 
542
        int src_len, src_len2;
 
543
        bool ret;
 
544
        char *dest2;
 
545
 
 
546
        if (flags & STR_NO_RANGE_CHECK) {
 
547
                src_len = byte_len;
 
548
        } else {
 
549
                src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
 
550
                if (src_len < 0) {
 
551
                        *dest = NULL;
 
552
                        return 0;
 
553
                }
 
554
                if (byte_len != -1 && src_len > byte_len) {
 
555
                        src_len = byte_len;
 
556
                }
 
557
        }
 
558
 
 
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 */
 
562
                src_len2++;
 
563
        }
 
564
 
 
565
        ret = convert_string_talloc(bufinfo->mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2, NULL, false);
 
566
 
 
567
        if (!ret) {
 
568
                *dest = NULL;
 
569
                return 0;
 
570
        }
 
571
        *dest = dest2;
 
572
 
 
573
        return src_len2;
 
574
}
 
575
 
 
576
/**
 
577
  pull a string from a request packet, returning a talloced string
 
578
 
 
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)
 
583
 
 
584
  Note that 'byte_len' is the number of bytes in the packet
 
585
 
 
586
  on failure zero is returned and *dest is set to NULL, otherwise the number
 
587
  of bytes consumed in the packet is returned
 
588
*/
 
589
size_t req_pull_string(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
 
590
{
 
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);
 
594
        }
 
595
 
 
596
        return req_pull_ascii(bufinfo, dest, src, byte_len, flags);
 
597
}
 
598
 
 
599
 
 
600
/**
 
601
  pull a ASCII4 string buffer from a request packet, returning a talloced string
 
602
  
 
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.
 
605
 
 
606
  on failure *dest is set to the zero length string. This seems to
 
607
  match win2000 behaviour
 
608
*/
 
609
size_t req_pull_ascii4(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, uint_t flags)
 
610
{
 
611
        ssize_t ret;
 
612
 
 
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, "");
 
616
                return 0;
 
617
        }
 
618
 
 
619
        /* this consumes the 0x4 byte. We don't check whether the byte
 
620
           is actually 0x4 or not. This matches win2000 server
 
621
           behaviour */
 
622
        src++;
 
623
 
 
624
        ret = req_pull_string(bufinfo, dest, src, -1, flags);
 
625
        if (ret == -1) {
 
626
                (*dest) = talloc_strdup(bufinfo->mem_ctx, "");
 
627
                return 1;
 
628
        }
 
629
        
 
630
        return ret + 1;
 
631
}
 
632
 
 
633
/**
 
634
  pull a DATA_BLOB from a request packet, returning a talloced blob
 
635
 
 
636
  return false if any part is outside the data portion of the packet
 
637
*/
 
638
bool req_pull_blob(struct request_bufinfo *bufinfo, const uint8_t *src, int len, DATA_BLOB *blob)
 
639
{
 
640
        if (len != 0 && req_data_oob(bufinfo, src, len)) {
 
641
                return false;
 
642
        }
 
643
 
 
644
        (*blob) = data_blob_talloc(bufinfo->mem_ctx, src, len);
 
645
 
 
646
        return true;
 
647
}
 
648
 
 
649
/* check that a lump of data in a request is within the bounds of the data section of
 
650
   the packet */
 
651
bool req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count)
 
652
{
 
653
        if (count == 0) {
 
654
                return false;
 
655
        }
 
656
        
 
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) {
 
662
                return true;
 
663
        }
 
664
        return false;
 
665
}
 
666
 
 
667
 
 
668
/* 
 
669
   pull an open file handle from a packet, taking account of the chained_fnum
 
670
*/
 
671
static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
 
672
{
 
673
        if (req->chained_fnum != -1) {
 
674
                return req->chained_fnum;
 
675
        }
 
676
        return SVAL(base, offset);
 
677
}
 
678
 
 
679
struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
 
680
{
 
681
        struct smbsrv_handle *handle;
 
682
        uint16_t fnum = req_fnum(req, base, offset);
 
683
 
 
684
        handle = smbsrv_smb_handle_find(req->tcon, fnum, req->request_time);
 
685
        if (!handle) {
 
686
                return NULL;
 
687
        }
 
688
 
 
689
        /*
 
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!
 
693
         *
 
694
         * So check if the handle is valid for the given session!
 
695
         */
 
696
        if (handle->session != req->session) {
 
697
                return NULL;
 
698
        }
 
699
 
 
700
        return handle->ntvfs;
 
701
}
 
702
 
 
703
void smbsrv_push_fnum(uint8_t *base, uint_t offset, struct ntvfs_handle *ntvfs)
 
704
{
 
705
        struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
 
706
                                       struct smbsrv_handle);
 
707
        SSVAL(base, offset, handle->hid);
 
708
}
 
709
 
 
710
NTSTATUS smbsrv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
 
711
{
 
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;
 
716
 
 
717
        handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
 
718
        if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
 
719
 
 
720
        h = talloc_zero(handle, struct ntvfs_handle);
 
721
        if (!h) goto nomem;
 
722
 
 
723
        /* 
 
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
 
728
         */
 
729
        h->ctx          = ntvfs->ctx;
 
730
        h->session_info = ntvfs->session_info;
 
731
        h->smbpid       = ntvfs->smbpid;
 
732
 
 
733
        h->frontend_data.private_data = handle;
 
734
 
 
735
        *_h = h;
 
736
        return NT_STATUS_OK;
 
737
nomem:
 
738
        talloc_free(handle);
 
739
        return NT_STATUS_NO_MEMORY;
 
740
}
 
741
 
 
742
NTSTATUS smbsrv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
 
743
{
 
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 */
 
748
        handle->ntvfs = h;
 
749
        /* this moves the smbsrv_request to the smbsrv_tcon memory context */
 
750
        talloc_steal(tcon, handle);
 
751
        return NT_STATUS_OK;
 
752
}
 
753
 
 
754
void smbsrv_handle_destroy(void *private_data, struct ntvfs_handle *h)
 
755
{
 
756
        struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
 
757
                                                       struct smbsrv_handle);
 
758
        talloc_free(handle);
 
759
}
 
760
 
 
761
struct ntvfs_handle *smbsrv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
 
762
{
 
763
        struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
 
764
                                     struct smbsrv_request);
 
765
 
 
766
        if (key->length != 2) return NULL;
 
767
 
 
768
        return smbsrv_pull_fnum(req, key->data, 0);
 
769
}
 
770
 
 
771
DATA_BLOB smbsrv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
 
772
{
 
773
        uint8_t key[2];
 
774
 
 
775
        smbsrv_push_fnum(key, 0, handle);
 
776
 
 
777
        return data_blob_talloc(mem_ctx, key, sizeof(key));
 
778
}