~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/librpc/rpc/dcerpc_smb2.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
   dcerpc over SMB2 transport
 
5
 
 
6
   Copyright (C) Andrew Tridgell 2005
 
7
   
 
8
   This program is free software; you can redistribute it and/or modify
 
9
   it under the terms of the GNU General Public License as published by
 
10
   the Free Software Foundation; either version 3 of the License, or
 
11
   (at your option) any later version.
 
12
   
 
13
   This program is distributed in the hope that it will be useful,
 
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
   GNU General Public License for more details.
 
17
   
 
18
   You should have received a copy of the GNU General Public License
 
19
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
*/
 
21
 
 
22
#include "includes.h"
 
23
#include "libcli/raw/libcliraw.h"
 
24
#include "libcli/composite/composite.h"
 
25
#include "libcli/smb2/smb2.h"
 
26
#include "libcli/smb2/smb2_calls.h"
 
27
#include "libcli/raw/ioctl.h"
 
28
#include "librpc/rpc/dcerpc.h"
 
29
#include "librpc/rpc/dcerpc_proto.h"
 
30
 
 
31
/* transport private information used by SMB2 pipe transport */
 
32
struct smb2_private {
 
33
        struct smb2_handle handle;
 
34
        struct smb2_tree *tree;
 
35
        const char *server_name;
 
36
        bool dead;
 
37
};
 
38
 
 
39
 
 
40
/*
 
41
  tell the dcerpc layer that the transport is dead
 
42
*/
 
43
static void pipe_dead(struct dcerpc_connection *c, NTSTATUS status)
 
44
{
 
45
        struct smb2_private *smb = (struct smb2_private *)c->transport.private_data;
 
46
 
 
47
        if (smb->dead) {
 
48
                return;
 
49
        }
 
50
 
 
51
        smb->dead = true;
 
52
 
 
53
        if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
 
54
                status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
 
55
        }
 
56
 
 
57
        if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
 
58
                status = NT_STATUS_END_OF_FILE;
 
59
        }
 
60
 
 
61
        if (c->transport.recv_data) {
 
62
                c->transport.recv_data(c, NULL, status);
 
63
        }
 
64
}
 
65
 
 
66
 
 
67
/* 
 
68
   this holds the state of an in-flight call
 
69
*/
 
70
struct smb2_read_state {
 
71
        struct dcerpc_connection *c;
 
72
        DATA_BLOB data;
 
73
};
 
74
 
 
75
/*
 
76
  called when a read request has completed
 
77
*/
 
78
static void smb2_read_callback(struct smb2_request *req)
 
79
{
 
80
        struct smb2_private *smb;
 
81
        struct smb2_read_state *state;
 
82
        struct smb2_read io;
 
83
        uint16_t frag_length;
 
84
        NTSTATUS status;
 
85
 
 
86
        state = talloc_get_type(req->async.private_data, struct smb2_read_state);
 
87
        smb = talloc_get_type(state->c->transport.private_data, struct smb2_private);
 
88
 
 
89
        status = smb2_read_recv(req, state, &io);
 
90
        if (NT_STATUS_IS_ERR(status)) {
 
91
                pipe_dead(state->c, status);
 
92
                talloc_free(state);
 
93
                return;
 
94
        }
 
95
 
 
96
        if (!data_blob_append(state, &state->data, 
 
97
                                  io.out.data.data, io.out.data.length)) {
 
98
                pipe_dead(state->c, NT_STATUS_NO_MEMORY);
 
99
                talloc_free(state);
 
100
                return;
 
101
        }
 
102
 
 
103
        if (state->data.length < 16) {
 
104
                DEBUG(0,("dcerpc_smb2: short packet (length %d) in read callback!\n",
 
105
                         (int)state->data.length));
 
106
                pipe_dead(state->c, NT_STATUS_INFO_LENGTH_MISMATCH);
 
107
                talloc_free(state);
 
108
                return;
 
109
        }
 
110
 
 
111
        frag_length = dcerpc_get_frag_length(&state->data);
 
112
 
 
113
        if (frag_length <= state->data.length) {
 
114
                DATA_BLOB data = state->data;
 
115
                struct dcerpc_connection *c = state->c;
 
116
                talloc_steal(c, data.data);
 
117
                talloc_free(state);
 
118
                c->transport.recv_data(c, &data, NT_STATUS_OK);
 
119
                return;
 
120
        }
 
121
 
 
122
        /* initiate another read request, as we only got part of a fragment */
 
123
        ZERO_STRUCT(io);
 
124
        io.in.file.handle = smb->handle;
 
125
        io.in.length = MIN(state->c->srv_max_xmit_frag, 
 
126
                           frag_length - state->data.length);
 
127
        if (io.in.length < 16) {
 
128
                io.in.length = 16;
 
129
        }
 
130
        
 
131
        req = smb2_read_send(smb->tree, &io);
 
132
        if (req == NULL) {
 
133
                pipe_dead(state->c, NT_STATUS_NO_MEMORY);
 
134
                talloc_free(state);
 
135
                return;
 
136
        }
 
137
 
 
138
        req->async.fn = smb2_read_callback;
 
139
        req->async.private_data = state;
 
140
}
 
141
 
 
142
 
 
143
/*
 
144
  trigger a read request from the server, possibly with some initial
 
145
  data in the read buffer
 
146
*/
 
147
static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLOB *blob)
 
148
{
 
149
        struct smb2_private *smb = (struct smb2_private *)c->transport.private_data;
 
150
        struct smb2_read io;
 
151
        struct smb2_read_state *state;
 
152
        struct smb2_request *req;
 
153
 
 
154
        state = talloc(smb, struct smb2_read_state);
 
155
        if (state == NULL) {
 
156
                return NT_STATUS_NO_MEMORY;
 
157
        }
 
158
 
 
159
        state->c = c;
 
160
        if (blob == NULL) {
 
161
                state->data = data_blob(NULL, 0);
 
162
        } else {
 
163
                state->data = *blob;
 
164
                talloc_steal(state, state->data.data);
 
165
        }
 
166
 
 
167
        ZERO_STRUCT(io);
 
168
        io.in.file.handle = smb->handle;
 
169
 
 
170
        if (state->data.length >= 16) {
 
171
                uint16_t frag_length = dcerpc_get_frag_length(&state->data);
 
172
                io.in.length = frag_length - state->data.length;
 
173
        } else {
 
174
                io.in.length = 0x2000;
 
175
        }
 
176
 
 
177
        req = smb2_read_send(smb->tree, &io);
 
178
        if (req == NULL) {
 
179
                return NT_STATUS_NO_MEMORY;
 
180
        }
 
181
 
 
182
        req->async.fn = smb2_read_callback;
 
183
        req->async.private_data = state;
 
184
 
 
185
        return NT_STATUS_OK;
 
186
}
 
187
 
 
188
 
 
189
/*
 
190
  trigger a read request from the server
 
191
*/
 
192
static NTSTATUS send_read_request(struct dcerpc_connection *c)
 
193
{
 
194
        struct smb2_private *smb = (struct smb2_private *)c->transport.private_data;
 
195
 
 
196
        if (smb->dead) {
 
197
                return NT_STATUS_CONNECTION_DISCONNECTED;
 
198
        }
 
199
 
 
200
        return send_read_request_continue(c, NULL);
 
201
}
 
202
 
 
203
/* 
 
204
   this holds the state of an in-flight trans call
 
205
*/
 
206
struct smb2_trans_state {
 
207
        struct dcerpc_connection *c;
 
208
};
 
209
 
 
210
/*
 
211
  called when a trans request has completed
 
212
*/
 
213
static void smb2_trans_callback(struct smb2_request *req)
 
214
{
 
215
        struct smb2_trans_state *state = talloc_get_type(req->async.private_data,
 
216
                                                        struct smb2_trans_state);
 
217
        struct dcerpc_connection *c = state->c;
 
218
        NTSTATUS status;
 
219
        struct smb2_ioctl io;
 
220
 
 
221
        status = smb2_ioctl_recv(req, state, &io);
 
222
        if (NT_STATUS_IS_ERR(status)) {
 
223
                pipe_dead(c, status);
 
224
                return;
 
225
        }
 
226
 
 
227
        if (!NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
 
228
                DATA_BLOB data = io.out.out;
 
229
                talloc_steal(c, data.data);
 
230
                talloc_free(state);
 
231
                c->transport.recv_data(c, &data, NT_STATUS_OK);
 
232
                return;
 
233
        }
 
234
 
 
235
        /* there is more to receive - setup a read */
 
236
        send_read_request_continue(c, &io.out.out);
 
237
        talloc_free(state);
 
238
}
 
239
 
 
240
/*
 
241
  send a SMBtrans style request, using a named pipe read_write fsctl
 
242
*/
 
243
static NTSTATUS smb2_send_trans_request(struct dcerpc_connection *c, DATA_BLOB *blob)
 
244
{
 
245
        struct smb2_private *smb = talloc_get_type(c->transport.private_data,
 
246
                                                   struct smb2_private);
 
247
        struct smb2_ioctl io;
 
248
        struct smb2_trans_state *state;
 
249
        struct smb2_request *req;
 
250
 
 
251
        state = talloc(smb, struct smb2_trans_state);
 
252
        if (state == NULL) {
 
253
                return NT_STATUS_NO_MEMORY;
 
254
        }
 
255
 
 
256
        state->c = c;
 
257
        
 
258
        ZERO_STRUCT(io);
 
259
        io.in.file.handle       = smb->handle;
 
260
        io.in.function          = FSCTL_NAMED_PIPE_READ_WRITE;
 
261
        io.in.max_response_size = 0x1000;
 
262
        io.in.flags             = 1;
 
263
        io.in.out               = *blob;
 
264
 
 
265
        req = smb2_ioctl_send(smb->tree, &io);
 
266
        if (req == NULL) {
 
267
                talloc_free(state);
 
268
                return NT_STATUS_NO_MEMORY;
 
269
        }
 
270
 
 
271
        req->async.fn = smb2_trans_callback;
 
272
        req->async.private_data = state;
 
273
 
 
274
        talloc_steal(state, req);
 
275
 
 
276
        return NT_STATUS_OK;
 
277
}
 
278
 
 
279
/*
 
280
  called when a write request has completed
 
281
*/
 
282
static void smb2_write_callback(struct smb2_request *req)
 
283
{
 
284
        struct dcerpc_connection *c = (struct dcerpc_connection *)req->async.private_data;
 
285
 
 
286
        if (!NT_STATUS_IS_OK(req->status)) {
 
287
                DEBUG(0,("dcerpc_smb2: write callback error\n"));
 
288
                pipe_dead(c, req->status);
 
289
        }
 
290
 
 
291
        smb2_request_destroy(req);
 
292
}
 
293
 
 
294
/* 
 
295
   send a packet to the server
 
296
*/
 
297
static NTSTATUS smb2_send_request(struct dcerpc_connection *c, DATA_BLOB *blob, 
 
298
                                  bool trigger_read)
 
299
{
 
300
        struct smb2_private *smb = (struct smb2_private *)c->transport.private_data;
 
301
        struct smb2_write io;
 
302
        struct smb2_request *req;
 
303
 
 
304
        if (smb->dead) {
 
305
                return NT_STATUS_CONNECTION_DISCONNECTED;
 
306
        }
 
307
 
 
308
        if (trigger_read) {
 
309
                return smb2_send_trans_request(c, blob);
 
310
        }
 
311
 
 
312
        ZERO_STRUCT(io);
 
313
        io.in.file.handle       = smb->handle;
 
314
        io.in.data              = *blob;
 
315
 
 
316
        req = smb2_write_send(smb->tree, &io);
 
317
        if (req == NULL) {
 
318
                return NT_STATUS_NO_MEMORY;
 
319
        }
 
320
 
 
321
        req->async.fn = smb2_write_callback;
 
322
        req->async.private_data = c;
 
323
 
 
324
        return NT_STATUS_OK;
 
325
}
 
326
 
 
327
/* 
 
328
   shutdown SMB pipe connection
 
329
*/
 
330
static NTSTATUS smb2_shutdown_pipe(struct dcerpc_connection *c, NTSTATUS status)
 
331
{
 
332
        struct smb2_private *smb = (struct smb2_private *)c->transport.private_data;
 
333
        struct smb2_close io;
 
334
        struct smb2_request *req;
 
335
 
 
336
        /* maybe we're still starting up */
 
337
        if (!smb) return status;
 
338
 
 
339
        ZERO_STRUCT(io);
 
340
        io.in.file.handle = smb->handle;
 
341
        req = smb2_close_send(smb->tree, &io);
 
342
        if (req != NULL) {
 
343
                /* we don't care if this fails, so just free it if it succeeds */
 
344
                req->async.fn = (void (*)(struct smb2_request *))talloc_free;
 
345
        }
 
346
 
 
347
        talloc_free(smb);
 
348
 
 
349
        return status;
 
350
}
 
351
 
 
352
/*
 
353
  return SMB server name
 
354
*/
 
355
static const char *smb2_peer_name(struct dcerpc_connection *c)
 
356
{
 
357
        struct smb2_private *smb = talloc_get_type(c->transport.private_data,
 
358
                                                   struct smb2_private);
 
359
        return smb->server_name;
 
360
}
 
361
 
 
362
/*
 
363
  return remote name we make the actual connection (good for kerberos) 
 
364
*/
 
365
static const char *smb2_target_hostname(struct dcerpc_connection *c)
 
366
{
 
367
        struct smb2_private *smb = talloc_get_type(c->transport.private_data, 
 
368
                                                   struct smb2_private);
 
369
        return smb->tree->session->transport->socket->hostname;
 
370
}
 
371
 
 
372
/*
 
373
  fetch the user session key 
 
374
*/
 
375
static NTSTATUS smb2_session_key(struct dcerpc_connection *c, DATA_BLOB *session_key)
 
376
{
 
377
        struct smb2_private *smb = talloc_get_type(c->transport.private_data,
 
378
                                                   struct smb2_private);
 
379
        *session_key = smb->tree->session->session_key;
 
380
        if (session_key->data == NULL) {
 
381
                return NT_STATUS_NO_USER_SESSION_KEY;
 
382
        }
 
383
        return NT_STATUS_OK;
 
384
}
 
385
 
 
386
struct pipe_open_smb2_state {
 
387
        struct dcerpc_connection *c;
 
388
        struct composite_context *ctx;
 
389
};
 
390
 
 
391
static void pipe_open_recv(struct smb2_request *req);
 
392
 
 
393
struct composite_context *dcerpc_pipe_open_smb2_send(struct dcerpc_pipe *p, 
 
394
                                                     struct smb2_tree *tree,
 
395
                                                     const char *pipe_name)
 
396
{
 
397
        struct composite_context *ctx;
 
398
        struct pipe_open_smb2_state *state;
 
399
        struct smb2_create io;
 
400
        struct smb2_request *req;
 
401
        struct dcerpc_connection *c = p->conn;
 
402
 
 
403
        ctx = composite_create(c, c->event_ctx);
 
404
        if (ctx == NULL) return NULL;
 
405
 
 
406
        state = talloc(ctx, struct pipe_open_smb2_state);
 
407
        if (composite_nomem(state, ctx)) return ctx;
 
408
        ctx->private_data = state;
 
409
 
 
410
        state->c = c;
 
411
        state->ctx = ctx;
 
412
 
 
413
        ZERO_STRUCT(io);
 
414
        io.in.desired_access = 
 
415
                SEC_STD_READ_CONTROL |
 
416
                SEC_FILE_READ_ATTRIBUTE |
 
417
                SEC_FILE_WRITE_ATTRIBUTE |
 
418
                SEC_STD_SYNCHRONIZE |
 
419
                SEC_FILE_READ_EA |
 
420
                SEC_FILE_WRITE_EA |
 
421
                SEC_FILE_READ_DATA |
 
422
                SEC_FILE_WRITE_DATA |
 
423
                SEC_FILE_APPEND_DATA;
 
424
        io.in.share_access = 
 
425
                NTCREATEX_SHARE_ACCESS_READ |
 
426
                NTCREATEX_SHARE_ACCESS_WRITE;
 
427
        io.in.create_disposition = NTCREATEX_DISP_OPEN;
 
428
        io.in.create_options   = 
 
429
                NTCREATEX_OPTIONS_NON_DIRECTORY_FILE | 
 
430
                NTCREATEX_OPTIONS_NO_RECALL;
 
431
        io.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
 
432
 
 
433
        if ((strncasecmp(pipe_name, "/pipe/", 6) == 0) || 
 
434
            (strncasecmp(pipe_name, "\\pipe\\", 6) == 0)) {
 
435
                pipe_name += 6;
 
436
        }
 
437
        io.in.fname = pipe_name;
 
438
 
 
439
        req = smb2_create_send(tree, &io);
 
440
        composite_continue_smb2(ctx, req, pipe_open_recv, state);
 
441
        return ctx;
 
442
}
 
443
 
 
444
static void pipe_open_recv(struct smb2_request *req)
 
445
{
 
446
        struct pipe_open_smb2_state *state =
 
447
                talloc_get_type(req->async.private_data,
 
448
                                struct pipe_open_smb2_state);
 
449
        struct composite_context *ctx = state->ctx;
 
450
        struct dcerpc_connection *c = state->c;
 
451
        struct smb2_tree *tree = req->tree;
 
452
        struct smb2_private *smb;
 
453
        struct smb2_create io;
 
454
 
 
455
        ctx->status = smb2_create_recv(req, state, &io);
 
456
        if (!composite_is_ok(ctx)) return;
 
457
 
 
458
        /*
 
459
          fill in the transport methods
 
460
        */
 
461
        c->transport.transport = NCACN_NP;
 
462
        c->transport.private_data = NULL;
 
463
        c->transport.shutdown_pipe = smb2_shutdown_pipe;
 
464
        c->transport.peer_name = smb2_peer_name;
 
465
        c->transport.target_hostname = smb2_target_hostname;
 
466
 
 
467
        c->transport.send_request = smb2_send_request;
 
468
        c->transport.send_read = send_read_request;
 
469
        c->transport.recv_data = NULL;
 
470
        
 
471
        /* Over-ride the default session key with the SMB session key */
 
472
        c->security_state.session_key = smb2_session_key;
 
473
 
 
474
        smb = talloc(c, struct smb2_private);
 
475
        if (composite_nomem(smb, ctx)) return;
 
476
 
 
477
        smb->handle     = io.out.file.handle;
 
478
        smb->tree       = talloc_reference(smb, tree);
 
479
        smb->server_name= strupper_talloc(smb, 
 
480
                                          tree->session->transport->socket->hostname);
 
481
        if (composite_nomem(smb->server_name, ctx)) return;
 
482
        smb->dead       = false;
 
483
 
 
484
        c->transport.private_data = smb;
 
485
 
 
486
        composite_done(ctx);
 
487
}
 
488
 
 
489
NTSTATUS dcerpc_pipe_open_smb2_recv(struct composite_context *c)
 
490
{
 
491
        NTSTATUS status = composite_wait(c);
 
492
        talloc_free(c);
 
493
        return status;
 
494
}
 
495
 
 
496
NTSTATUS dcerpc_pipe_open_smb2(struct dcerpc_pipe *p,
 
497
                               struct smb2_tree *tree,
 
498
                               const char *pipe_name)
 
499
{
 
500
        struct composite_context *ctx = dcerpc_pipe_open_smb2_send(p, tree, pipe_name);
 
501
        return dcerpc_pipe_open_smb2_recv(ctx);
 
502
}
 
503
 
 
504
/*
 
505
  return the SMB2 tree used for a dcerpc over SMB2 pipe
 
506
*/
 
507
struct smb2_tree *dcerpc_smb2_tree(struct dcerpc_connection *c)
 
508
{
 
509
        struct smb2_private *smb = talloc_get_type(c->transport.private_data,
 
510
                                                   struct smb2_private);
 
511
        return smb->tree;
 
512
}