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