r23792: convert Samba4 to GPLv3
[mdw/samba.git] / source4 / librpc / rpc / dcerpc_connect.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    dcerpc connect functions
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Jelmer Vernooij 2004
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
9    Copyright (C) Rafal Szczesniak  2005
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25
26 #include "includes.h"
27 #include "libcli/composite/composite.h"
28 #include "libcli/smb_composite/smb_composite.h"
29 #include "lib/events/events.h"
30 #include "libcli/smb2/smb2.h"
31 #include "libcli/smb2/smb2_calls.h"
32 #include "librpc/rpc/dcerpc.h"
33 #include "auth/credentials/credentials.h"
34
35
36 struct pipe_np_smb_state {
37         struct smb_composite_connect conn;
38         struct smbcli_tree *tree;
39         struct dcerpc_pipe_connect io;
40 };
41
42
43 /*
44   Stage 3 of ncacn_np_smb: Named pipe opened (or not)
45 */
46 static void continue_pipe_open_smb(struct composite_context *ctx)
47 {
48         struct composite_context *c = talloc_get_type(ctx->async.private_data,
49                                                       struct composite_context);
50
51         /* receive result of named pipe open request on smb */
52         c->status = dcerpc_pipe_open_smb_recv(ctx);
53         if (!composite_is_ok(c)) return;
54
55         composite_done(c);
56 }
57
58
59 /*
60   Stage 2 of ncacn_np_smb: Open a named pipe after successful smb connection
61 */
62 static void continue_smb_connect(struct composite_context *ctx)
63 {
64         struct composite_context *open_ctx;
65         struct composite_context *c = talloc_get_type(ctx->async.private_data,
66                                                       struct composite_context);
67         struct pipe_np_smb_state *s = talloc_get_type(c->private_data,
68                                                       struct pipe_np_smb_state);
69         
70         /* receive result of smb connect request */
71         c->status = smb_composite_connect_recv(ctx, c);
72         if (!composite_is_ok(c)) return;
73
74         /* prepare named pipe open parameters */
75         s->tree         = s->conn.out.tree;
76         s->io.pipe_name = s->io.binding->endpoint;
77
78         /* send named pipe open request */
79         open_ctx = dcerpc_pipe_open_smb_send(s->io.pipe, s->tree, s->io.pipe_name);
80         if (composite_nomem(open_ctx, c)) return;
81
82         composite_continue(c, open_ctx, continue_pipe_open_smb, c);
83 }
84
85
86 /*
87   Initiate async open of a rpc connection to a rpc pipe on SMB using
88   the binding structure to determine the endpoint and options
89 */
90 static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CTX *mem_ctx, 
91                                                                 struct dcerpc_pipe_connect *io)
92 {
93         struct composite_context *c;
94         struct pipe_np_smb_state *s;
95         struct composite_context *conn_req;
96         struct smb_composite_connect *conn;
97
98         /* composite context allocation and setup */
99         c = composite_create(mem_ctx, io->pipe->conn->event_ctx);
100         if (c == NULL) return NULL;
101
102         s = talloc_zero(c, struct pipe_np_smb_state);
103         if (composite_nomem(s, c)) return c;
104         c->private_data = s;
105
106         s->io  = *io;
107         conn   = &s->conn;
108
109         /* prepare smb connection parameters: we're connecting to IPC$ share on
110            remote rpc server */
111         conn->in.dest_host              = s->io.binding->host;
112         conn->in.port                   = 0;
113         conn->in.called_name            = s->io.binding->target_hostname;
114         conn->in.service                = "IPC$";
115         conn->in.service_type           = NULL;
116         conn->in.workgroup              = lp_workgroup();
117
118         /*
119          * provide proper credentials - user supplied, but allow a
120          * fallback to anonymous if this is an schannel connection
121          * (might be NT4 not allowing machine logins at session
122          * setup).
123          */
124         s->conn.in.credentials = s->io.creds;
125         if (s->io.binding->flags & DCERPC_SCHANNEL) {
126                 conn->in.fallback_to_anonymous  = True;
127         } else {
128                 conn->in.fallback_to_anonymous  = False;
129         }
130
131         /* send smb connect request */
132         conn_req = smb_composite_connect_send(conn, s->io.pipe->conn, s->io.pipe->conn->event_ctx);
133         if (composite_nomem(conn_req, c)) return c;
134
135         composite_continue(c, conn_req, continue_smb_connect, c);
136         return c;
137 }
138
139
140 /*
141   Receive result of a rpc connection to a rpc pipe on SMB
142 */
143 static NTSTATUS dcerpc_pipe_connect_ncacn_np_smb_recv(struct composite_context *c)
144 {
145         NTSTATUS status = composite_wait(c);
146
147         talloc_free(c);
148         return status;
149 }
150
151
152 struct pipe_np_smb2_state {
153         struct smb2_tree *tree;
154         struct dcerpc_pipe_connect io;
155 };
156
157
158 /*
159   Stage 3 of ncacn_np_smb: Named pipe opened (or not)
160 */
161 static void continue_pipe_open_smb2(struct composite_context *ctx)
162 {
163         struct composite_context *c = talloc_get_type(ctx->async.private_data,
164                                                       struct composite_context);
165
166         /* receive result of named pipe open request on smb2 */
167         c->status = dcerpc_pipe_open_smb2_recv(ctx);
168         if (!composite_is_ok(c)) return;
169
170         composite_done(c);
171 }
172
173
174 /*
175   Stage 2 of ncacn_np_smb2: Open a named pipe after successful smb2 connection
176 */
177 static void continue_smb2_connect(struct composite_context *ctx)
178 {
179         struct composite_context *open_req;
180         struct composite_context *c = talloc_get_type(ctx->async.private_data,
181                                                       struct composite_context);
182         struct pipe_np_smb2_state *s = talloc_get_type(c->private_data,
183                                                        struct pipe_np_smb2_state);
184
185         /* receive result of smb2 connect request */
186         c->status = smb2_connect_recv(ctx, c, &s->tree);
187         if (!composite_is_ok(c)) return;
188
189         /* prepare named pipe open parameters */
190         s->io.pipe_name = s->io.binding->endpoint;
191
192         /* send named pipe open request */
193         open_req = dcerpc_pipe_open_smb2_send(s->io.pipe, s->tree, s->io.pipe_name);
194         if (composite_nomem(open_req, c)) return;
195
196         composite_continue(c, open_req, continue_pipe_open_smb2, c);
197 }
198
199
200 /* 
201    Initiate async open of a rpc connection request on SMB2 using
202    the binding structure to determine the endpoint and options
203 */
204 static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb2_send(TALLOC_CTX *mem_ctx,
205                                                                         struct dcerpc_pipe_connect *io)
206 {
207         struct composite_context *c;
208         struct pipe_np_smb2_state *s;
209         struct composite_context *conn_req;
210
211         /* composite context allocation and setup */
212         c = composite_create(mem_ctx, io->pipe->conn->event_ctx);
213         if (c == NULL) return NULL;
214
215         s = talloc_zero(c, struct pipe_np_smb2_state);
216         if (composite_nomem(s, c)) return c;
217         c->private_data = s;
218
219         s->io = *io;
220
221         /*
222          * provide proper credentials - user supplied or anonymous in case this is
223          * schannel connection
224          */
225         if (s->io.binding->flags & DCERPC_SCHANNEL) {
226                 s->io.creds = cli_credentials_init(mem_ctx);
227                 if (composite_nomem(s->io.creds, c)) return c;
228
229                 cli_credentials_set_anonymous(s->io.creds);
230                 cli_credentials_guess(s->io.creds);
231         }
232
233         /* send smb2 connect request */
234         conn_req = smb2_connect_send(mem_ctx, s->io.binding->host, "IPC$", s->io.creds,
235                                      c->event_ctx);
236         composite_continue(c, conn_req, continue_smb2_connect, c);
237         return c;
238 }
239
240
241 /*
242   Receive result of a rpc connection to a rpc pipe on SMB2
243 */
244 static NTSTATUS dcerpc_pipe_connect_ncacn_np_smb2_recv(struct composite_context *c)
245 {
246         NTSTATUS status = composite_wait(c);
247         
248         talloc_free(c);
249         return status;
250 }
251
252
253 struct pipe_ip_tcp_state {
254         struct dcerpc_pipe_connect io;
255         const char *host;
256         const char *target_hostname;
257         uint32_t port;
258 };
259
260
261 /*
262   Stage 2 of ncacn_ip_tcp: rpc pipe opened (or not)
263 */
264 static void continue_pipe_open_ncacn_ip_tcp(struct composite_context *ctx)
265 {
266         struct composite_context *c = talloc_get_type(ctx->async.private_data,
267                                                       struct composite_context);
268
269         /* receive result of named pipe open request on tcp/ip */
270         c->status = dcerpc_pipe_open_tcp_recv(ctx);
271         if (!composite_is_ok(c)) return;
272
273         composite_done(c);
274 }
275
276
277 /*
278   Initiate async open of a rpc connection to a rpc pipe on TCP/IP using
279   the binding structure to determine the endpoint and options
280 */
281 static struct composite_context* dcerpc_pipe_connect_ncacn_ip_tcp_send(TALLOC_CTX *mem_ctx,
282                                                                        struct dcerpc_pipe_connect *io)
283 {
284         struct composite_context *c;
285         struct pipe_ip_tcp_state *s;
286         struct composite_context *pipe_req;
287
288         /* composite context allocation and setup */
289         c = composite_create(mem_ctx, io->pipe->conn->event_ctx);
290         if (c == NULL) return NULL;
291
292         s = talloc_zero(c, struct pipe_ip_tcp_state);
293         if (composite_nomem(s, c)) return c;
294         c->private_data = s;
295
296         /* store input parameters in state structure */
297         s->io               = *io;
298         s->host             = talloc_reference(c, io->binding->host);
299         s->target_hostname  = talloc_reference(c, io->binding->target_hostname);
300                              /* port number is a binding endpoint here */
301         s->port             = atoi(io->binding->endpoint);   
302
303         /* send pipe open request on tcp/ip */
304         pipe_req = dcerpc_pipe_open_tcp_send(s->io.pipe->conn, s->host, s->target_hostname, 
305                                              s->port);
306         composite_continue(c, pipe_req, continue_pipe_open_ncacn_ip_tcp, c);
307         return c;
308 }
309
310
311 /*
312   Receive result of a rpc connection to a rpc pipe on TCP/IP
313 */
314 static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp_recv(struct composite_context *c)
315 {
316         NTSTATUS status = composite_wait(c);
317         
318         talloc_free(c);
319         return status;
320 }
321
322
323 struct pipe_unix_state {
324         struct dcerpc_pipe_connect io;
325         const char *path;
326 };
327
328
329 /*
330   Stage 2 of ncacn_unix: rpc pipe opened (or not)
331 */
332 static void continue_pipe_open_ncacn_unix_stream(struct composite_context *ctx)
333 {
334         struct composite_context *c = talloc_get_type(ctx->async.private_data,
335                                                       struct composite_context);
336
337         /* receive result of pipe open request on unix socket */
338         c->status = dcerpc_pipe_open_unix_stream_recv(ctx);
339         if (!composite_is_ok(c)) return;
340
341         composite_done(c);
342 }
343
344
345 /*
346   Initiate async open of a rpc connection to a rpc pipe on unix socket using
347   the binding structure to determine the endpoint and options
348 */
349 static struct composite_context* dcerpc_pipe_connect_ncacn_unix_stream_send(TALLOC_CTX *mem_ctx,
350                                                                             struct dcerpc_pipe_connect *io)
351 {
352         struct composite_context *c;
353         struct pipe_unix_state *s;
354         struct composite_context *pipe_req;
355
356         /* composite context allocation and setup */
357         c = composite_create(mem_ctx, io->pipe->conn->event_ctx);
358         if (c == NULL) return NULL;
359
360         s = talloc_zero(c, struct pipe_unix_state);
361         if (composite_nomem(s, c)) return c;
362         c->private_data = s;
363
364         /* prepare pipe open parameters and store them in state structure
365            also, verify whether biding endpoint is not null */
366         s->io = *io;
367         
368         if (!io->binding->endpoint) {
369                 DEBUG(0, ("Path to unix socket not specified\n"));
370                 composite_error(c, NT_STATUS_INVALID_PARAMETER);
371                 return c;
372         }
373
374         s->path  = talloc_strdup(c, io->binding->endpoint);  /* path is a binding endpoint here */
375         if (composite_nomem(s->path, c)) return c;
376
377         /* send pipe open request on unix socket */
378         pipe_req = dcerpc_pipe_open_unix_stream_send(s->io.pipe->conn, s->path);
379         composite_continue(c, pipe_req, continue_pipe_open_ncacn_unix_stream, c);
380         return c;
381 }
382
383
384 /*
385   Receive result of a rpc connection to a pipe on unix socket
386 */
387 static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream_recv(struct composite_context *c)
388 {
389         NTSTATUS status = composite_wait(c);
390
391         talloc_free(c);
392         return status;
393 }
394
395
396 struct pipe_ncalrpc_state {
397         struct dcerpc_pipe_connect io;
398 };
399
400 static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c);
401
402 /*
403   Stage 2 of ncalrpc: rpc pipe opened (or not)
404 */
405 static void continue_pipe_open_ncalrpc(struct composite_context *ctx)
406 {
407         struct composite_context *c = talloc_get_type(ctx->async.private_data,
408                                                       struct composite_context);
409
410         /* receive result of pipe open request on ncalrpc */
411         c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
412         if (!composite_is_ok(c)) return;
413
414         composite_done(c);
415 }
416
417
418 /* 
419    Initiate async open of a rpc connection request on NCALRPC using
420    the binding structure to determine the endpoint and options
421 */
422 static struct composite_context* dcerpc_pipe_connect_ncalrpc_send(TALLOC_CTX *mem_ctx,
423                                                                   struct dcerpc_pipe_connect *io)
424 {
425         struct composite_context *c;
426         struct pipe_ncalrpc_state *s;
427         struct composite_context *pipe_req;
428
429         /* composite context allocation and setup */
430         c = composite_create(mem_ctx, io->pipe->conn->event_ctx);
431         if (c == NULL) return NULL;
432
433         s = talloc_zero(c, struct pipe_ncalrpc_state);
434         if (composite_nomem(s, c)) return c;
435         c->private_data = s;
436         
437         /* store input parameters in state structure */
438         s->io  = *io;
439
440         /* send pipe open request */
441         pipe_req = dcerpc_pipe_open_pipe_send(s->io.pipe->conn, s->io.binding->endpoint);
442         composite_continue(c, pipe_req, continue_pipe_open_ncalrpc, c);
443         return c;
444 }
445
446
447 /*
448   Receive result of a rpc connection to a rpc pipe on NCALRPC
449 */
450 static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c)
451 {
452         NTSTATUS status = composite_wait(c);
453         
454         talloc_free(c);
455         return status;
456 }
457
458
459 struct pipe_connect_state {
460         struct dcerpc_pipe *pipe;
461         struct dcerpc_binding *binding;
462         const struct dcerpc_interface_table *table;
463         struct cli_credentials *credentials;
464 };
465
466
467 static void continue_map_binding(struct composite_context *ctx);
468 static void continue_connect(struct composite_context *c, struct pipe_connect_state *s);
469 static void continue_pipe_connect_ncacn_np_smb2(struct composite_context *ctx);
470 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx);
471 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx);
472 static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx);
473 static void continue_pipe_connect_ncalrpc(struct composite_context *ctx);
474 static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s);
475 static void continue_pipe_auth(struct composite_context *ctx);
476
477
478 /*
479   Stage 2 of pipe_connect_b: Receive result of endpoint mapping
480 */
481 static void continue_map_binding(struct composite_context *ctx)
482 {
483         struct composite_context *c = talloc_get_type(ctx->async.private_data,
484                                                       struct composite_context);
485         struct pipe_connect_state *s = talloc_get_type(c->private_data,
486                                                        struct pipe_connect_state);
487         
488         c->status = dcerpc_epm_map_binding_recv(ctx);
489         if (!composite_is_ok(c)) return;
490
491         DEBUG(2,("Mapped to DCERPC endpoint %s\n", s->binding->endpoint));
492         
493         continue_connect(c, s);
494 }
495
496
497 /*
498   Stage 2 of pipe_connect_b: Continue connection after endpoint is known
499 */
500 static void continue_connect(struct composite_context *c, struct pipe_connect_state *s)
501 {
502         struct dcerpc_pipe_connect pc;
503
504         /* potential exits to another stage by sending an async request */
505         struct composite_context *ncacn_np_smb2_req;
506         struct composite_context *ncacn_np_smb_req;
507         struct composite_context *ncacn_ip_tcp_req;
508         struct composite_context *ncacn_unix_req;
509         struct composite_context *ncalrpc_req;
510
511         /* dcerpc pipe connect input parameters */
512         pc.pipe         = s->pipe;
513         pc.binding      = s->binding;
514         pc.interface    = s->table;
515         pc.creds        = s->credentials;
516
517         /* connect dcerpc pipe depending on required transport */
518         switch (s->binding->transport) {
519         case NCACN_NP:
520                 if (pc.binding->flags & DCERPC_SMB2) {
521                         /* new varient of SMB a.k.a. SMB2 */
522                         ncacn_np_smb2_req = dcerpc_pipe_connect_ncacn_np_smb2_send(c, &pc);
523                         composite_continue(c, ncacn_np_smb2_req, continue_pipe_connect_ncacn_np_smb2, c);
524                         return;
525
526                 } else {
527                         /* good old ordinary SMB */
528                         ncacn_np_smb_req = dcerpc_pipe_connect_ncacn_np_smb_send(c, &pc);
529                         composite_continue(c, ncacn_np_smb_req, continue_pipe_connect_ncacn_np_smb, c);
530                         return;
531                 }
532                 break;
533
534         case NCACN_IP_TCP:
535                 ncacn_ip_tcp_req = dcerpc_pipe_connect_ncacn_ip_tcp_send(c, &pc);
536                 composite_continue(c, ncacn_ip_tcp_req, continue_pipe_connect_ncacn_ip_tcp, c);
537                 return;
538
539         case NCACN_UNIX_STREAM:
540                 ncacn_unix_req = dcerpc_pipe_connect_ncacn_unix_stream_send(c, &pc);
541                 composite_continue(c, ncacn_unix_req, continue_pipe_connect_ncacn_unix, c);
542                 return;
543
544         case NCALRPC:
545                 ncalrpc_req = dcerpc_pipe_connect_ncalrpc_send(c, &pc);
546                 composite_continue(c, ncalrpc_req, continue_pipe_connect_ncalrpc, c);
547                 return;
548
549         default:
550                 /* looks like a transport we don't support now */
551                 composite_error(c, NT_STATUS_NOT_SUPPORTED);
552         }
553 }
554
555
556 /*
557   Stage 3 of pipe_connect_b: Receive result of pipe connect request on
558   named pipe on smb2
559 */
560 static void continue_pipe_connect_ncacn_np_smb2(struct composite_context *ctx)
561 {
562         struct composite_context *c = talloc_get_type(ctx->async.private_data,
563                                                       struct composite_context);
564         struct pipe_connect_state *s = talloc_get_type(c->private_data,
565                                                        struct pipe_connect_state);
566
567         c->status = dcerpc_pipe_connect_ncacn_np_smb2_recv(ctx);
568         if (!composite_is_ok(c)) return;
569
570         continue_pipe_connect(c, s);
571 }
572
573
574 /*
575   Stage 3 of pipe_connect_b: Receive result of pipe connect request on
576   named pipe on smb
577 */
578 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx)
579 {
580         struct composite_context *c = talloc_get_type(ctx->async.private_data,
581                                                       struct composite_context);
582         struct pipe_connect_state *s = talloc_get_type(c->private_data,
583                                                        struct pipe_connect_state);
584
585         c->status = dcerpc_pipe_connect_ncacn_np_smb_recv(ctx);
586         if (!composite_is_ok(c)) return;
587         
588         continue_pipe_connect(c, s);
589 }
590
591
592 /*
593   Stage 3 of pipe_connect_b: Receive result of pipe connect request on tcp/ip
594 */
595 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx)
596 {
597         struct composite_context *c = talloc_get_type(ctx->async.private_data,
598                                                       struct composite_context);
599         struct pipe_connect_state *s = talloc_get_type(c->private_data,
600                                                        struct pipe_connect_state);
601
602         c->status = dcerpc_pipe_connect_ncacn_ip_tcp_recv(ctx);
603         if (!composite_is_ok(c)) return;
604
605         continue_pipe_connect(c, s);
606 }
607
608
609 /*
610   Stage 3 of pipe_connect_b: Receive result of pipe connect request on unix socket
611 */
612 static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx)
613 {
614         struct composite_context *c = talloc_get_type(ctx->async.private_data,
615                                                       struct composite_context);
616         struct pipe_connect_state *s = talloc_get_type(c->private_data,
617                                                        struct pipe_connect_state);
618         
619         c->status = dcerpc_pipe_connect_ncacn_unix_stream_recv(ctx);
620         if (!composite_is_ok(c)) return;
621         
622         continue_pipe_connect(c, s);
623 }
624
625
626 /*
627   Stage 3 of pipe_connect_b: Receive result of pipe connect request on local rpc
628 */
629 static void continue_pipe_connect_ncalrpc(struct composite_context *ctx)
630 {
631         struct composite_context *c = talloc_get_type(ctx->async.private_data,
632                                                       struct composite_context);
633         struct pipe_connect_state *s = talloc_get_type(c->private_data,
634                                                        struct pipe_connect_state);
635         
636         c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
637         if (!composite_is_ok(c)) return;
638
639         continue_pipe_connect(c, s);
640 }
641
642
643 /*
644   Stage 4 of pipe_connect_b: Start an authentication on connected dcerpc pipe
645   depending on credentials and binding flags passed.
646 */
647 static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s)
648 {
649         struct composite_context *auth_bind_req;
650
651         s->pipe->binding = s->binding;
652         if (!talloc_reference(s->pipe, s->binding)) {
653                 composite_error(c, NT_STATUS_NO_MEMORY);
654                 return;
655         }
656
657         auth_bind_req = dcerpc_pipe_auth_send(s->pipe, s->binding, s->table,
658                                               s->credentials);
659         composite_continue(c, auth_bind_req, continue_pipe_auth, c);
660 }
661
662
663 /*
664   Stage 5 of pipe_connect_b: Receive result of pipe authentication request
665   and say if all went ok
666 */
667 static void continue_pipe_auth(struct composite_context *ctx)
668 {
669         struct composite_context *c = talloc_get_type(ctx->async.private_data,
670                                                       struct composite_context);
671         struct pipe_connect_state *s = talloc_get_type(c->private_data, struct pipe_connect_state);
672
673         c->status = dcerpc_pipe_auth_recv(ctx, s, &s->pipe);
674         if (!composite_is_ok(c)) return;
675
676         composite_done(c);
677 }
678
679
680 /*
681   handle timeouts of a dcerpc connect
682 */
683 static void dcerpc_connect_timeout_handler(struct event_context *ev, struct timed_event *te, 
684                                            struct timeval t, void *private)
685 {
686         struct composite_context *c = talloc_get_type(private, struct composite_context);
687         composite_error(c, NT_STATUS_IO_TIMEOUT);
688 }
689
690 /*
691   start a request to open a rpc connection to a rpc pipe, using
692   specified binding structure to determine the endpoint and options
693 */
694 struct composite_context* dcerpc_pipe_connect_b_send(TALLOC_CTX *parent_ctx,
695                                                      struct dcerpc_binding *binding,
696                                                      const struct dcerpc_interface_table *table,
697                                                      struct cli_credentials *credentials,
698                                                      struct event_context *ev)
699 {
700         struct composite_context *c;
701         struct pipe_connect_state *s;
702         struct event_context *new_ev = NULL;
703
704         if (ev == NULL) {
705                 new_ev = event_context_init(parent_ctx);
706                 if (new_ev == NULL) return NULL;
707                 ev = new_ev;
708         }
709
710         /* composite context allocation and setup */
711         c = composite_create(parent_ctx, ev);
712         if (c == NULL) {
713                 talloc_free(new_ev);
714                 return NULL;
715         }
716         talloc_steal(c, new_ev);
717
718         s = talloc_zero(c, struct pipe_connect_state);
719         if (composite_nomem(s, c)) return c;
720         c->private_data = s;
721
722         /* initialise dcerpc pipe structure */
723         s->pipe = dcerpc_pipe_init(c, ev);
724         if (composite_nomem(s->pipe, c)) return c;
725
726         /* store parameters in state structure */
727         s->binding      = binding;
728         s->table        = table;
729         s->credentials  = credentials;
730
731         event_add_timed(c->event_ctx, c,
732                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
733                         dcerpc_connect_timeout_handler, c);
734         
735         switch (s->binding->transport) {
736         case NCACN_NP:
737         case NCACN_IP_TCP:
738         case NCALRPC:
739                 if (!s->binding->endpoint) {
740                         struct composite_context *binding_req;
741                         binding_req = dcerpc_epm_map_binding_send(c, s->binding, s->table,
742                                                                   s->pipe->conn->event_ctx);
743                         composite_continue(c, binding_req, continue_map_binding, c);
744                         return c;
745                 }
746
747         default:
748                 break;
749         }
750
751         continue_connect(c, s);
752         return c;
753 }
754
755
756 /*
757   receive result of a request to open a rpc connection to a rpc pipe
758 */
759 NTSTATUS dcerpc_pipe_connect_b_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
760                                     struct dcerpc_pipe **p)
761 {
762         NTSTATUS status;
763         struct pipe_connect_state *s;
764         
765         status = composite_wait(c);
766         
767         if (NT_STATUS_IS_OK(status)) {
768                 s = talloc_get_type(c->private_data, struct pipe_connect_state);
769                 talloc_steal(mem_ctx, s->pipe);
770                 *p = s->pipe;
771         }
772         talloc_free(c);
773         return status;
774 }
775
776
777 /*
778   open a rpc connection to a rpc pipe, using the specified 
779   binding structure to determine the endpoint and options - sync version
780 */
781 NTSTATUS dcerpc_pipe_connect_b(TALLOC_CTX *parent_ctx,
782                                struct dcerpc_pipe **pp,
783                                struct dcerpc_binding *binding,
784                                const struct dcerpc_interface_table *table,
785                                struct cli_credentials *credentials,
786                                struct event_context *ev)
787 {
788         struct composite_context *c;
789         
790         c = dcerpc_pipe_connect_b_send(parent_ctx, binding, table,
791                                        credentials, ev);
792         return dcerpc_pipe_connect_b_recv(c, parent_ctx, pp);
793 }
794
795
796 struct pipe_conn_state {
797         struct dcerpc_pipe *pipe;
798 };
799
800
801 static void continue_pipe_connect_b(struct composite_context *ctx);
802
803
804 /*
805   Initiate rpc connection to a rpc pipe, using the specified string
806   binding to determine the endpoint and options.
807   The string is to be parsed to a binding structure first.
808 */
809 struct composite_context* dcerpc_pipe_connect_send(TALLOC_CTX *parent_ctx,
810                                                    const char *binding,
811                                                    const struct dcerpc_interface_table *table,
812                                                    struct cli_credentials *credentials,
813                                                    struct event_context *ev)
814 {
815         struct composite_context *c;
816         struct pipe_conn_state *s;
817         struct dcerpc_binding *b;
818         struct composite_context *pipe_conn_req;
819         struct event_context *new_ev = NULL;
820
821         if (ev == NULL) {
822                 new_ev = event_context_init(parent_ctx);
823                 if (new_ev == NULL) return NULL;
824                 ev = new_ev;
825         }
826
827         /* composite context allocation and setup */
828         c = composite_create(parent_ctx, ev);
829         if (c == NULL) {
830                 talloc_free(new_ev);
831                 return NULL;
832         }
833         talloc_steal(c, new_ev);
834
835         s = talloc_zero(c, struct pipe_conn_state);
836         if (composite_nomem(s, c)) return c;
837         c->private_data = s;
838
839         /* parse binding string to the structure */
840         c->status = dcerpc_parse_binding(c, binding, &b);
841         if (!NT_STATUS_IS_OK(c->status)) {
842                 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", binding));
843                 composite_error(c, c->status);
844                 return c;
845         }
846
847         DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(c, b)));
848
849         /* 
850            start connecting to a rpc pipe after binding structure
851            is established
852          */
853         pipe_conn_req = dcerpc_pipe_connect_b_send(c, b, table,
854                                                    credentials, ev);
855         composite_continue(c, pipe_conn_req, continue_pipe_connect_b, c);
856         return c;
857 }
858
859
860 /*
861   Stage 2 of pipe_connect: Receive result of actual pipe connect request
862   and say if we're done ok
863 */
864 static void continue_pipe_connect_b(struct composite_context *ctx)
865 {
866         struct composite_context *c = talloc_get_type(ctx->async.private_data,
867                                                       struct composite_context);
868         struct pipe_conn_state *s = talloc_get_type(c->private_data,
869                                                     struct pipe_conn_state);
870
871         c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe);
872         talloc_steal(s, s->pipe);
873         if (!composite_is_ok(c)) return;
874
875         composite_done(c);
876 }
877
878
879 /*
880   Receive result of pipe connect (using binding string) request
881   and return connected pipe structure.
882 */
883 NTSTATUS dcerpc_pipe_connect_recv(struct composite_context *c,
884                                   TALLOC_CTX *mem_ctx,
885                                   struct dcerpc_pipe **pp)
886 {
887         NTSTATUS status;
888         struct pipe_conn_state *s;
889
890         status = composite_wait(c);
891         if (NT_STATUS_IS_OK(status)) {
892                 s = talloc_get_type(c->private_data, struct pipe_conn_state);
893                 *pp = talloc_steal(mem_ctx, s->pipe);
894         }
895         talloc_free(c);
896         return status;
897 }
898
899
900 /*
901   Open a rpc connection to a rpc pipe, using the specified string
902   binding to determine the endpoint and options - sync version
903 */
904 NTSTATUS dcerpc_pipe_connect(TALLOC_CTX *parent_ctx, 
905                              struct dcerpc_pipe **pp, 
906                              const char *binding,
907                              const struct dcerpc_interface_table *table,
908                              struct cli_credentials *credentials,
909                              struct event_context *ev)
910 {
911         struct composite_context *c;
912         c = dcerpc_pipe_connect_send(parent_ctx, binding, 
913                                      table,
914                                      credentials, ev);
915         return dcerpc_pipe_connect_recv(c, parent_ctx, pp);
916 }
917
918
919 struct sec_conn_state {
920         struct dcerpc_pipe *pipe;
921         struct dcerpc_pipe *pipe2;
922         struct dcerpc_binding *binding;
923         struct smbcli_tree *tree;
924 };
925
926
927 static void continue_open_smb(struct composite_context *ctx);
928 static void continue_open_tcp(struct composite_context *ctx);
929 static void continue_open_pipe(struct composite_context *ctx);
930 static void continue_pipe_open(struct composite_context *c);
931
932
933 /*
934   Send request to create a secondary dcerpc connection from a primary
935   connection
936 */
937 struct composite_context* dcerpc_secondary_connection_send(struct dcerpc_pipe *p,
938                                                            struct dcerpc_binding *b)
939 {
940         struct composite_context *c;
941         struct sec_conn_state *s;
942         struct composite_context *pipe_smb_req;
943         struct composite_context *pipe_tcp_req;
944         struct composite_context *pipe_ncalrpc_req;
945         
946         /* composite context allocation and setup */
947         c = composite_create(p, p->conn->event_ctx);
948         if (c == NULL) return NULL;
949
950         s = talloc_zero(c, struct sec_conn_state);
951         if (composite_nomem(s, c)) return c;
952         c->private_data = s;
953
954         s->pipe     = p;
955         s->binding  = b;
956
957         /* initialise second dcerpc pipe based on primary pipe's event context */
958         s->pipe2 = dcerpc_pipe_init(c, s->pipe->conn->event_ctx);
959         if (composite_nomem(s->pipe2, c)) return c;
960
961         /* open second dcerpc pipe using the same transport as for primary pipe */
962         switch (s->pipe->conn->transport.transport) {
963         case NCACN_NP:
964                 /* get smb tree of primary dcerpc pipe opened on smb */
965                 s->tree = dcerpc_smb_tree(s->pipe->conn);
966                 if (!s->tree) {
967                         composite_error(c, NT_STATUS_INVALID_PARAMETER);
968                         return c;
969                 }
970
971                 pipe_smb_req = dcerpc_pipe_open_smb_send(s->pipe2, s->tree,
972                                                          s->binding->endpoint);
973                 composite_continue(c, pipe_smb_req, continue_open_smb, c);
974                 return c;
975
976         case NCACN_IP_TCP:
977                 pipe_tcp_req = dcerpc_pipe_open_tcp_send(s->pipe2->conn,
978                                                          s->binding->host,
979                                                          s->binding->target_hostname,
980                                                          atoi(s->binding->endpoint));
981                 composite_continue(c, pipe_tcp_req, continue_open_tcp, c);
982                 return c;
983
984         case NCALRPC:
985                 pipe_ncalrpc_req = dcerpc_pipe_open_pipe_send(s->pipe2->conn,
986                                                               s->binding->endpoint);
987                 composite_continue(c, pipe_ncalrpc_req, continue_open_pipe, c);
988                 return c;
989
990         default:
991                 /* looks like a transport we don't support */
992                 composite_error(c, NT_STATUS_NOT_SUPPORTED);
993         }
994
995         return c;
996 }
997
998
999 /*
1000   Stage 2 of secondary_connection: Receive result of pipe open request on smb
1001 */
1002 static void continue_open_smb(struct composite_context *ctx)
1003 {
1004         struct composite_context *c = talloc_get_type(ctx->async.private_data,
1005                                                       struct composite_context);
1006         
1007         c->status = dcerpc_pipe_open_smb_recv(ctx);
1008         if (!composite_is_ok(c)) return;
1009
1010         continue_pipe_open(c);
1011 }
1012
1013
1014 /*
1015   Stage 2 of secondary_connection: Receive result of pipe open request on tcp/ip
1016 */
1017 static void continue_open_tcp(struct composite_context *ctx)
1018 {
1019         struct composite_context *c = talloc_get_type(ctx->async.private_data,
1020                                                       struct composite_context);
1021         
1022         c->status = dcerpc_pipe_open_tcp_recv(ctx);
1023         if (!composite_is_ok(c)) return;
1024
1025         continue_pipe_open(c);
1026 }
1027
1028
1029 /*
1030   Stage 2 of secondary_connection: Receive result of pipe open request on ncalrpc
1031 */
1032 static void continue_open_pipe(struct composite_context *ctx)
1033 {
1034         struct composite_context *c = talloc_get_type(ctx->async.private_data,
1035                                                       struct composite_context);
1036
1037         c->status = dcerpc_pipe_open_pipe_recv(ctx);
1038         if (!composite_is_ok(c)) return;
1039
1040         continue_pipe_open(c);
1041 }
1042
1043
1044 /*
1045   Stage 3 of secondary_connection: Get binding data and flags from primary pipe
1046   and say if we're done ok.
1047 */
1048 static void continue_pipe_open(struct composite_context *c)
1049 {
1050         struct sec_conn_state *s;
1051
1052         s = talloc_get_type(c->private_data, struct sec_conn_state);
1053
1054         s->pipe2->conn->flags = s->pipe->conn->flags;
1055         s->pipe2->binding     = s->binding;
1056         if (!talloc_reference(s->pipe2, s->binding)) {
1057                 composite_error(c, NT_STATUS_NO_MEMORY);
1058                 return;
1059         }
1060
1061         composite_done(c);
1062 }
1063
1064
1065 /*
1066   Receive result of secondary rpc connection request and return
1067   second dcerpc pipe.
1068 */
1069 NTSTATUS dcerpc_secondary_connection_recv(struct composite_context *c,
1070                                           struct dcerpc_pipe **p2)
1071 {
1072         NTSTATUS status = composite_wait(c);
1073         struct sec_conn_state *s;
1074
1075         s = talloc_get_type(c->private_data, struct sec_conn_state);
1076
1077         if (NT_STATUS_IS_OK(status)) {
1078                 *p2 = talloc_steal(s->pipe, s->pipe2);
1079         }
1080
1081         talloc_free(c);
1082         return status;
1083 }
1084
1085 /*
1086   Create a secondary dcerpc connection from a primary connection
1087   - sync version
1088
1089   If the primary is a SMB connection then the secondary connection
1090   will be on the same SMB connection, but using a new fnum
1091 */
1092 NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p,
1093                                      struct dcerpc_pipe **p2,
1094                                      struct dcerpc_binding *b)
1095 {
1096         struct composite_context *c;
1097         
1098         c = dcerpc_secondary_connection_send(p, b);
1099         return dcerpc_secondary_connection_recv(c, p2);
1100 }