s4:lib/tevent: rename structs
[ira/wip.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-2007
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 "librpc/rpc/dcerpc_proto.h"
34 #include "auth/credentials/credentials.h"
35 #include "param/param.h"
36 #include "libcli/resolve/resolve.h"
37
38
39 struct pipe_np_smb_state {
40         struct smb_composite_connect conn;
41         struct smbcli_tree *tree;
42         struct dcerpc_pipe_connect io;
43 };
44
45
46 /*
47   Stage 3 of ncacn_np_smb: Named pipe opened (or not)
48 */
49 static void continue_pipe_open_smb(struct composite_context *ctx)
50 {
51         struct composite_context *c = talloc_get_type(ctx->async.private_data,
52                                                       struct composite_context);
53
54         /* receive result of named pipe open request on smb */
55         c->status = dcerpc_pipe_open_smb_recv(ctx);
56         if (!composite_is_ok(c)) return;
57
58         composite_done(c);
59 }
60
61
62 /*
63   Stage 2 of ncacn_np_smb: Open a named pipe after successful smb connection
64 */
65 static void continue_smb_connect(struct composite_context *ctx)
66 {
67         struct composite_context *open_ctx;
68         struct composite_context *c = talloc_get_type(ctx->async.private_data,
69                                                       struct composite_context);
70         struct pipe_np_smb_state *s = talloc_get_type(c->private_data,
71                                                       struct pipe_np_smb_state);
72         
73         /* receive result of smb connect request */
74         c->status = smb_composite_connect_recv(ctx, c);
75         if (!composite_is_ok(c)) return;
76
77         /* prepare named pipe open parameters */
78         s->tree         = s->conn.out.tree;
79         s->io.pipe_name = s->io.binding->endpoint;
80
81         /* send named pipe open request */
82         open_ctx = dcerpc_pipe_open_smb_send(s->io.pipe, s->tree, s->io.pipe_name);
83         if (composite_nomem(open_ctx, c)) return;
84
85         composite_continue(c, open_ctx, continue_pipe_open_smb, c);
86 }
87
88
89 /*
90   Initiate async open of a rpc connection to a rpc pipe on SMB using
91   the binding structure to determine the endpoint and options
92 */
93 static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CTX *mem_ctx, struct dcerpc_pipe_connect *io, struct loadparm_context *lp_ctx)
94 {
95         struct composite_context *c;
96         struct pipe_np_smb_state *s;
97         struct composite_context *conn_req;
98         struct smb_composite_connect *conn;
99
100         /* composite context allocation and setup */
101         c = composite_create(mem_ctx, io->pipe->conn->event_ctx);
102         if (c == NULL) return NULL;
103
104         s = talloc_zero(c, struct pipe_np_smb_state);
105         if (composite_nomem(s, c)) return c;
106         c->private_data = s;
107
108         s->io  = *io;
109         conn   = &s->conn;
110
111         /* prepare smb connection parameters: we're connecting to IPC$ share on
112            remote rpc server */
113         conn->in.dest_host              = s->io.binding->host;
114         conn->in.dest_ports                  = lp_smb_ports(lp_ctx);
115         if (s->io.binding->target_hostname == NULL)
116                 conn->in.called_name = "*SMBSERVER"; /* FIXME: This is invalid */
117         else
118                 conn->in.called_name            = s->io.binding->target_hostname;
119         conn->in.socket_options         = lp_socket_options(lp_ctx);
120         conn->in.service                = "IPC$";
121         conn->in.service_type           = NULL;
122         conn->in.workgroup              = lp_workgroup(lp_ctx);
123         conn->in.gensec_settings = lp_gensec_settings(conn, lp_ctx);
124         conn->in.iconv_convenience = lp_iconv_convenience(lp_ctx);
125
126         lp_smbcli_options(lp_ctx, &conn->in.options);
127         lp_smbcli_session_options(lp_ctx, &conn->in.session_options);
128
129         /*
130          * provide proper credentials - user supplied, but allow a
131          * fallback to anonymous if this is an schannel connection
132          * (might be NT4 not allowing machine logins at session
133          * setup).
134          */
135         s->conn.in.credentials = s->io.creds;
136         if (s->io.binding->flags & DCERPC_SCHANNEL) {
137                 conn->in.fallback_to_anonymous  = true;
138         } else {
139                 conn->in.fallback_to_anonymous  = false;
140         }
141
142         /* send smb connect request */
143         conn_req = smb_composite_connect_send(conn, s->io.pipe->conn, 
144                                               s->io.resolve_ctx,
145                                               s->io.pipe->conn->event_ctx);
146         if (composite_nomem(conn_req, c)) return c;
147
148         composite_continue(c, conn_req, continue_smb_connect, c);
149         return c;
150 }
151
152
153 /*
154   Receive result of a rpc connection to a rpc pipe on SMB
155 */
156 static NTSTATUS dcerpc_pipe_connect_ncacn_np_smb_recv(struct composite_context *c)
157 {
158         NTSTATUS status = composite_wait(c);
159
160         talloc_free(c);
161         return status;
162 }
163
164
165 struct pipe_np_smb2_state {
166         struct smb2_tree *tree;
167         struct dcerpc_pipe_connect io;
168 };
169
170
171 /*
172   Stage 3 of ncacn_np_smb: Named pipe opened (or not)
173 */
174 static void continue_pipe_open_smb2(struct composite_context *ctx)
175 {
176         struct composite_context *c = talloc_get_type(ctx->async.private_data,
177                                                       struct composite_context);
178
179         /* receive result of named pipe open request on smb2 */
180         c->status = dcerpc_pipe_open_smb2_recv(ctx);
181         if (!composite_is_ok(c)) return;
182
183         composite_done(c);
184 }
185
186
187 /*
188   Stage 2 of ncacn_np_smb2: Open a named pipe after successful smb2 connection
189 */
190 static void continue_smb2_connect(struct composite_context *ctx)
191 {
192         struct composite_context *open_req;
193         struct composite_context *c = talloc_get_type(ctx->async.private_data,
194                                                       struct composite_context);
195         struct pipe_np_smb2_state *s = talloc_get_type(c->private_data,
196                                                        struct pipe_np_smb2_state);
197
198         /* receive result of smb2 connect request */
199         c->status = smb2_connect_recv(ctx, c, &s->tree);
200         if (!composite_is_ok(c)) return;
201
202         /* prepare named pipe open parameters */
203         s->io.pipe_name = s->io.binding->endpoint;
204
205         /* send named pipe open request */
206         open_req = dcerpc_pipe_open_smb2_send(s->io.pipe, s->tree, s->io.pipe_name);
207         if (composite_nomem(open_req, c)) return;
208
209         composite_continue(c, open_req, continue_pipe_open_smb2, c);
210 }
211
212
213 /* 
214    Initiate async open of a rpc connection request on SMB2 using
215    the binding structure to determine the endpoint and options
216 */
217 static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb2_send(
218                                         TALLOC_CTX *mem_ctx,
219                                         struct dcerpc_pipe_connect *io,
220                                         struct loadparm_context *lp_ctx)
221 {
222         struct composite_context *c;
223         struct pipe_np_smb2_state *s;
224         struct composite_context *conn_req;
225         struct smbcli_options options;
226
227         /* composite context allocation and setup */
228         c = composite_create(mem_ctx, io->pipe->conn->event_ctx);
229         if (c == NULL) return NULL;
230
231         s = talloc_zero(c, struct pipe_np_smb2_state);
232         if (composite_nomem(s, c)) return c;
233         c->private_data = s;
234
235         s->io = *io;
236
237         /*
238          * provide proper credentials - user supplied or anonymous in case this is
239          * schannel connection
240          */
241         if (s->io.binding->flags & DCERPC_SCHANNEL) {
242                 s->io.creds = cli_credentials_init(mem_ctx);
243                 if (composite_nomem(s->io.creds, c)) return c;
244
245                 cli_credentials_guess(s->io.creds, lp_ctx);
246         }
247
248         lp_smbcli_options(lp_ctx, &options);
249
250         /* send smb2 connect request */
251         conn_req = smb2_connect_send(mem_ctx, s->io.binding->host, 
252                         lp_parm_string_list(mem_ctx, lp_ctx, NULL, "smb2", "ports", NULL),
253                                         "IPC$", 
254                                      s->io.resolve_ctx,
255                                      s->io.creds,
256                                      c->event_ctx,
257                                      &options,
258                                          lp_socket_options(lp_ctx),
259                                          lp_gensec_settings(mem_ctx, lp_ctx)
260                                          );
261         composite_continue(c, conn_req, continue_smb2_connect, c);
262         return c;
263 }
264
265
266 /*
267   Receive result of a rpc connection to a rpc pipe on SMB2
268 */
269 static NTSTATUS dcerpc_pipe_connect_ncacn_np_smb2_recv(struct composite_context *c)
270 {
271         NTSTATUS status = composite_wait(c);
272         
273         talloc_free(c);
274         return status;
275 }
276
277
278 struct pipe_ip_tcp_state {
279         struct dcerpc_pipe_connect io;
280         const char *host;
281         const char *target_hostname;
282         uint32_t port;
283 };
284
285
286 /*
287   Stage 2 of ncacn_ip_tcp: rpc pipe opened (or not)
288 */
289 static void continue_pipe_open_ncacn_ip_tcp(struct composite_context *ctx)
290 {
291         struct composite_context *c = talloc_get_type(ctx->async.private_data,
292                                                       struct composite_context);
293
294         /* receive result of named pipe open request on tcp/ip */
295         c->status = dcerpc_pipe_open_tcp_recv(ctx);
296         if (!composite_is_ok(c)) return;
297
298         composite_done(c);
299 }
300
301
302 /*
303   Initiate async open of a rpc connection to a rpc pipe on TCP/IP using
304   the binding structure to determine the endpoint and options
305 */
306 static struct composite_context* dcerpc_pipe_connect_ncacn_ip_tcp_send(TALLOC_CTX *mem_ctx,
307                                                                        struct dcerpc_pipe_connect *io)
308 {
309         struct composite_context *c;
310         struct pipe_ip_tcp_state *s;
311         struct composite_context *pipe_req;
312
313         /* composite context allocation and setup */
314         c = composite_create(mem_ctx, io->pipe->conn->event_ctx);
315         if (c == NULL) return NULL;
316
317         s = talloc_zero(c, struct pipe_ip_tcp_state);
318         if (composite_nomem(s, c)) return c;
319         c->private_data = s;
320
321         /* store input parameters in state structure */
322         s->io               = *io;
323         s->host             = talloc_reference(c, io->binding->host);
324         s->target_hostname  = talloc_reference(c, io->binding->target_hostname);
325                              /* port number is a binding endpoint here */
326         s->port             = atoi(io->binding->endpoint);   
327
328         /* send pipe open request on tcp/ip */
329         pipe_req = dcerpc_pipe_open_tcp_send(s->io.pipe->conn, s->host, s->target_hostname, 
330                                              s->port, io->resolve_ctx);
331         composite_continue(c, pipe_req, continue_pipe_open_ncacn_ip_tcp, c);
332         return c;
333 }
334
335
336 /*
337   Receive result of a rpc connection to a rpc pipe on TCP/IP
338 */
339 static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp_recv(struct composite_context *c)
340 {
341         NTSTATUS status = composite_wait(c);
342         
343         talloc_free(c);
344         return status;
345 }
346
347
348 struct pipe_unix_state {
349         struct dcerpc_pipe_connect io;
350         const char *path;
351 };
352
353
354 /*
355   Stage 2 of ncacn_unix: rpc pipe opened (or not)
356 */
357 static void continue_pipe_open_ncacn_unix_stream(struct composite_context *ctx)
358 {
359         struct composite_context *c = talloc_get_type(ctx->async.private_data,
360                                                       struct composite_context);
361
362         /* receive result of pipe open request on unix socket */
363         c->status = dcerpc_pipe_open_unix_stream_recv(ctx);
364         if (!composite_is_ok(c)) return;
365
366         composite_done(c);
367 }
368
369
370 /*
371   Initiate async open of a rpc connection to a rpc pipe on unix socket using
372   the binding structure to determine the endpoint and options
373 */
374 static struct composite_context* dcerpc_pipe_connect_ncacn_unix_stream_send(TALLOC_CTX *mem_ctx,
375                                                                             struct dcerpc_pipe_connect *io)
376 {
377         struct composite_context *c;
378         struct pipe_unix_state *s;
379         struct composite_context *pipe_req;
380
381         /* composite context allocation and setup */
382         c = composite_create(mem_ctx, io->pipe->conn->event_ctx);
383         if (c == NULL) return NULL;
384
385         s = talloc_zero(c, struct pipe_unix_state);
386         if (composite_nomem(s, c)) return c;
387         c->private_data = s;
388
389         /* prepare pipe open parameters and store them in state structure
390            also, verify whether biding endpoint is not null */
391         s->io = *io;
392         
393         if (!io->binding->endpoint) {
394                 DEBUG(0, ("Path to unix socket not specified\n"));
395                 composite_error(c, NT_STATUS_INVALID_PARAMETER);
396                 return c;
397         }
398
399         s->path  = talloc_strdup(c, io->binding->endpoint);  /* path is a binding endpoint here */
400         if (composite_nomem(s->path, c)) return c;
401
402         /* send pipe open request on unix socket */
403         pipe_req = dcerpc_pipe_open_unix_stream_send(s->io.pipe->conn, s->path);
404         composite_continue(c, pipe_req, continue_pipe_open_ncacn_unix_stream, c);
405         return c;
406 }
407
408
409 /*
410   Receive result of a rpc connection to a pipe on unix socket
411 */
412 static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream_recv(struct composite_context *c)
413 {
414         NTSTATUS status = composite_wait(c);
415
416         talloc_free(c);
417         return status;
418 }
419
420
421 struct pipe_ncalrpc_state {
422         struct dcerpc_pipe_connect io;
423 };
424
425 static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c);
426
427 /*
428   Stage 2 of ncalrpc: rpc pipe opened (or not)
429 */
430 static void continue_pipe_open_ncalrpc(struct composite_context *ctx)
431 {
432         struct composite_context *c = talloc_get_type(ctx->async.private_data,
433                                                       struct composite_context);
434
435         /* receive result of pipe open request on ncalrpc */
436         c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
437         if (!composite_is_ok(c)) return;
438
439         composite_done(c);
440 }
441
442
443 /* 
444    Initiate async open of a rpc connection request on NCALRPC using
445    the binding structure to determine the endpoint and options
446 */
447 static struct composite_context* dcerpc_pipe_connect_ncalrpc_send(TALLOC_CTX *mem_ctx,
448                                                                   struct dcerpc_pipe_connect *io, struct loadparm_context *lp_ctx)
449 {
450         struct composite_context *c;
451         struct pipe_ncalrpc_state *s;
452         struct composite_context *pipe_req;
453
454         /* composite context allocation and setup */
455         c = composite_create(mem_ctx, io->pipe->conn->event_ctx);
456         if (c == NULL) return NULL;
457
458         s = talloc_zero(c, struct pipe_ncalrpc_state);
459         if (composite_nomem(s, c)) return c;
460         c->private_data = s;
461         
462         /* store input parameters in state structure */
463         s->io  = *io;
464
465         /* send pipe open request */
466         pipe_req = dcerpc_pipe_open_pipe_send(s->io.pipe->conn, lp_ncalrpc_dir(lp_ctx), 
467                                               s->io.binding->endpoint);
468         composite_continue(c, pipe_req, continue_pipe_open_ncalrpc, c);
469         return c;
470 }
471
472
473 /*
474   Receive result of a rpc connection to a rpc pipe on NCALRPC
475 */
476 static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c)
477 {
478         NTSTATUS status = composite_wait(c);
479         
480         talloc_free(c);
481         return status;
482 }
483
484
485 struct pipe_connect_state {
486         struct dcerpc_pipe *pipe;
487         struct dcerpc_binding *binding;
488         const struct ndr_interface_table *table;
489         struct cli_credentials *credentials;
490         struct loadparm_context *lp_ctx;
491 };
492
493
494 static void continue_map_binding(struct composite_context *ctx);
495 static void continue_connect(struct composite_context *c, struct pipe_connect_state *s);
496 static void continue_pipe_connect_ncacn_np_smb2(struct composite_context *ctx);
497 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx);
498 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx);
499 static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx);
500 static void continue_pipe_connect_ncalrpc(struct composite_context *ctx);
501 static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s);
502 static void continue_pipe_auth(struct composite_context *ctx);
503
504
505 /*
506   Stage 2 of pipe_connect_b: Receive result of endpoint mapping
507 */
508 static void continue_map_binding(struct composite_context *ctx)
509 {
510         struct composite_context *c = talloc_get_type(ctx->async.private_data,
511                                                       struct composite_context);
512         struct pipe_connect_state *s = talloc_get_type(c->private_data,
513                                                        struct pipe_connect_state);
514         
515         c->status = dcerpc_epm_map_binding_recv(ctx);
516         if (!composite_is_ok(c)) return;
517
518         DEBUG(2,("Mapped to DCERPC endpoint %s\n", s->binding->endpoint));
519         
520         continue_connect(c, s);
521 }
522
523
524 /*
525   Stage 2 of pipe_connect_b: Continue connection after endpoint is known
526 */
527 static void continue_connect(struct composite_context *c, struct pipe_connect_state *s)
528 {
529         struct dcerpc_pipe_connect pc;
530
531         /* potential exits to another stage by sending an async request */
532         struct composite_context *ncacn_np_smb2_req;
533         struct composite_context *ncacn_np_smb_req;
534         struct composite_context *ncacn_ip_tcp_req;
535         struct composite_context *ncacn_unix_req;
536         struct composite_context *ncalrpc_req;
537
538         /* dcerpc pipe connect input parameters */
539         pc.pipe         = s->pipe;
540         pc.binding      = s->binding;
541         pc.interface    = s->table;
542         pc.creds        = s->credentials;
543         pc.resolve_ctx  = lp_resolve_context(s->lp_ctx);
544
545         /* connect dcerpc pipe depending on required transport */
546         switch (s->binding->transport) {
547         case NCACN_NP:
548                 if (pc.binding->flags & DCERPC_SMB2) {
549                         /* new varient of SMB a.k.a. SMB2 */
550                         ncacn_np_smb2_req = dcerpc_pipe_connect_ncacn_np_smb2_send(c, &pc, s->lp_ctx);
551                         composite_continue(c, ncacn_np_smb2_req, continue_pipe_connect_ncacn_np_smb2, c);
552                         return;
553
554                 } else {
555                         /* good old ordinary SMB */
556                         ncacn_np_smb_req = dcerpc_pipe_connect_ncacn_np_smb_send(c, &pc, s->lp_ctx);
557                         composite_continue(c, ncacn_np_smb_req, continue_pipe_connect_ncacn_np_smb, c);
558                         return;
559                 }
560                 break;
561
562         case NCACN_IP_TCP:
563                 ncacn_ip_tcp_req = dcerpc_pipe_connect_ncacn_ip_tcp_send(c, &pc);
564                 composite_continue(c, ncacn_ip_tcp_req, continue_pipe_connect_ncacn_ip_tcp, c);
565                 return;
566
567         case NCACN_UNIX_STREAM:
568                 ncacn_unix_req = dcerpc_pipe_connect_ncacn_unix_stream_send(c, &pc);
569                 composite_continue(c, ncacn_unix_req, continue_pipe_connect_ncacn_unix, c);
570                 return;
571
572         case NCALRPC:
573                 ncalrpc_req = dcerpc_pipe_connect_ncalrpc_send(c, &pc, s->lp_ctx);
574                 composite_continue(c, ncalrpc_req, continue_pipe_connect_ncalrpc, c);
575                 return;
576
577         default:
578                 /* looks like a transport we don't support now */
579                 composite_error(c, NT_STATUS_NOT_SUPPORTED);
580         }
581 }
582
583
584 /*
585   Stage 3 of pipe_connect_b: Receive result of pipe connect request on
586   named pipe on smb2
587 */
588 static void continue_pipe_connect_ncacn_np_smb2(struct composite_context *ctx)
589 {
590         struct composite_context *c = talloc_get_type(ctx->async.private_data,
591                                                       struct composite_context);
592         struct pipe_connect_state *s = talloc_get_type(c->private_data,
593                                                        struct pipe_connect_state);
594
595         c->status = dcerpc_pipe_connect_ncacn_np_smb2_recv(ctx);
596         if (!composite_is_ok(c)) return;
597
598         continue_pipe_connect(c, s);
599 }
600
601
602 /*
603   Stage 3 of pipe_connect_b: Receive result of pipe connect request on
604   named pipe on smb
605 */
606 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx)
607 {
608         struct composite_context *c = talloc_get_type(ctx->async.private_data,
609                                                       struct composite_context);
610         struct pipe_connect_state *s = talloc_get_type(c->private_data,
611                                                        struct pipe_connect_state);
612
613         c->status = dcerpc_pipe_connect_ncacn_np_smb_recv(ctx);
614         if (!composite_is_ok(c)) return;
615         
616         continue_pipe_connect(c, s);
617 }
618
619
620 /*
621   Stage 3 of pipe_connect_b: Receive result of pipe connect request on tcp/ip
622 */
623 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx)
624 {
625         struct composite_context *c = talloc_get_type(ctx->async.private_data,
626                                                       struct composite_context);
627         struct pipe_connect_state *s = talloc_get_type(c->private_data,
628                                                        struct pipe_connect_state);
629
630         c->status = dcerpc_pipe_connect_ncacn_ip_tcp_recv(ctx);
631         if (!composite_is_ok(c)) return;
632
633         continue_pipe_connect(c, s);
634 }
635
636
637 /*
638   Stage 3 of pipe_connect_b: Receive result of pipe connect request on unix socket
639 */
640 static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx)
641 {
642         struct composite_context *c = talloc_get_type(ctx->async.private_data,
643                                                       struct composite_context);
644         struct pipe_connect_state *s = talloc_get_type(c->private_data,
645                                                        struct pipe_connect_state);
646         
647         c->status = dcerpc_pipe_connect_ncacn_unix_stream_recv(ctx);
648         if (!composite_is_ok(c)) return;
649         
650         continue_pipe_connect(c, s);
651 }
652
653
654 /*
655   Stage 3 of pipe_connect_b: Receive result of pipe connect request on local rpc
656 */
657 static void continue_pipe_connect_ncalrpc(struct composite_context *ctx)
658 {
659         struct composite_context *c = talloc_get_type(ctx->async.private_data,
660                                                       struct composite_context);
661         struct pipe_connect_state *s = talloc_get_type(c->private_data,
662                                                        struct pipe_connect_state);
663         
664         c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
665         if (!composite_is_ok(c)) return;
666
667         continue_pipe_connect(c, s);
668 }
669
670
671 /*
672   Stage 4 of pipe_connect_b: Start an authentication on connected dcerpc pipe
673   depending on credentials and binding flags passed.
674 */
675 static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s)
676 {
677         struct composite_context *auth_bind_req;
678
679         s->pipe->binding = s->binding;
680         if (!talloc_reference(s->pipe, s->binding)) {
681                 composite_error(c, NT_STATUS_NO_MEMORY);
682                 return;
683         }
684
685         auth_bind_req = dcerpc_pipe_auth_send(s->pipe, s->binding, s->table,
686                                               s->credentials, s->lp_ctx);
687         composite_continue(c, auth_bind_req, continue_pipe_auth, c);
688 }
689
690
691 /*
692   Stage 5 of pipe_connect_b: Receive result of pipe authentication request
693   and say if all went ok
694 */
695 static void continue_pipe_auth(struct composite_context *ctx)
696 {
697         struct composite_context *c = talloc_get_type(ctx->async.private_data,
698                                                       struct composite_context);
699         struct pipe_connect_state *s = talloc_get_type(c->private_data, struct pipe_connect_state);
700
701         c->status = dcerpc_pipe_auth_recv(ctx, s, &s->pipe);
702         if (!composite_is_ok(c)) return;
703
704         composite_done(c);
705 }
706
707
708 /*
709   handle timeouts of a dcerpc connect
710 */
711 static void dcerpc_connect_timeout_handler(struct tevent_context *ev, struct tevent_timer *te, 
712                                            struct timeval t, void *private)
713 {
714         struct composite_context *c = talloc_get_type(private, struct composite_context);
715         composite_error(c, NT_STATUS_IO_TIMEOUT);
716 }
717
718 /*
719   start a request to open a rpc connection to a rpc pipe, using
720   specified binding structure to determine the endpoint and options
721 */
722 _PUBLIC_ struct composite_context* dcerpc_pipe_connect_b_send(TALLOC_CTX *parent_ctx,
723                                                      struct dcerpc_binding *binding,
724                                                      const struct ndr_interface_table *table,
725                                                      struct cli_credentials *credentials,
726                                                      struct tevent_context *ev,
727                                                      struct loadparm_context *lp_ctx)
728 {
729         struct composite_context *c;
730         struct pipe_connect_state *s;
731         struct tevent_context *new_ev = NULL;
732
733         /* composite context allocation and setup */
734         c = composite_create(parent_ctx, ev);
735         if (c == NULL) {
736                 talloc_free(new_ev);
737                 return NULL;
738         }
739         talloc_steal(c, new_ev);
740
741         s = talloc_zero(c, struct pipe_connect_state);
742         if (composite_nomem(s, c)) return c;
743         c->private_data = s;
744
745         /* initialise dcerpc pipe structure */
746         s->pipe = dcerpc_pipe_init(c, ev, lp_iconv_convenience(lp_ctx));
747         if (composite_nomem(s->pipe, c)) return c;
748
749         if (DEBUGLEVEL >= 10)
750                 s->pipe->conn->packet_log_dir = lp_lockdir(lp_ctx);
751
752         /* store parameters in state structure */
753         s->binding      = binding;
754         s->table        = table;
755         s->credentials  = credentials;
756         s->lp_ctx       = lp_ctx;
757
758         event_add_timed(c->event_ctx, c,
759                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
760                         dcerpc_connect_timeout_handler, c);
761         
762         switch (s->binding->transport) {
763         case NCA_UNKNOWN: {
764                 struct composite_context *binding_req;
765                 binding_req = dcerpc_epm_map_binding_send(c, s->binding, s->table,
766                                                           s->pipe->conn->event_ctx,
767                                                           s->lp_ctx);
768                 composite_continue(c, binding_req, continue_map_binding, c);
769                 return c;
770                 }
771
772         case NCACN_NP:
773         case NCACN_IP_TCP:
774         case NCALRPC:
775                 if (!s->binding->endpoint) {
776                         struct composite_context *binding_req;
777                         binding_req = dcerpc_epm_map_binding_send(c, s->binding, s->table,
778                                                                   s->pipe->conn->event_ctx,
779                                                                   s->lp_ctx);
780                         composite_continue(c, binding_req, continue_map_binding, c);
781                         return c;
782                 }
783
784         default:
785                 break;
786         }
787
788         continue_connect(c, s);
789         return c;
790 }
791
792
793 /*
794   receive result of a request to open a rpc connection to a rpc pipe
795 */
796 _PUBLIC_ NTSTATUS dcerpc_pipe_connect_b_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
797                                     struct dcerpc_pipe **p)
798 {
799         NTSTATUS status;
800         struct pipe_connect_state *s;
801         
802         status = composite_wait(c);
803         
804         if (NT_STATUS_IS_OK(status)) {
805                 s = talloc_get_type(c->private_data, struct pipe_connect_state);
806                 talloc_steal(mem_ctx, s->pipe);
807                 *p = s->pipe;
808         }
809         talloc_free(c);
810         return status;
811 }
812
813
814 /*
815   open a rpc connection to a rpc pipe, using the specified 
816   binding structure to determine the endpoint and options - sync version
817 */
818 _PUBLIC_ NTSTATUS dcerpc_pipe_connect_b(TALLOC_CTX *parent_ctx,
819                                struct dcerpc_pipe **pp,
820                                struct dcerpc_binding *binding,
821                                const struct ndr_interface_table *table,
822                                struct cli_credentials *credentials,
823                                struct tevent_context *ev,
824                                struct loadparm_context *lp_ctx)
825 {
826         struct composite_context *c;
827         
828         c = dcerpc_pipe_connect_b_send(parent_ctx, binding, table,
829                                        credentials, ev, lp_ctx);
830         return dcerpc_pipe_connect_b_recv(c, parent_ctx, pp);
831 }
832
833
834 struct pipe_conn_state {
835         struct dcerpc_pipe *pipe;
836 };
837
838
839 static void continue_pipe_connect_b(struct composite_context *ctx);
840
841
842 /*
843   Initiate rpc connection to a rpc pipe, using the specified string
844   binding to determine the endpoint and options.
845   The string is to be parsed to a binding structure first.
846 */
847 _PUBLIC_ struct composite_context* dcerpc_pipe_connect_send(TALLOC_CTX *parent_ctx,
848                                                    const char *binding,
849                                                    const struct ndr_interface_table *table,
850                                                    struct cli_credentials *credentials,
851                                                    struct tevent_context *ev, struct loadparm_context *lp_ctx)
852 {
853         struct composite_context *c;
854         struct pipe_conn_state *s;
855         struct dcerpc_binding *b;
856         struct composite_context *pipe_conn_req;
857
858         /* composite context allocation and setup */
859         c = composite_create(parent_ctx, ev);
860         if (c == NULL) {
861                 return NULL;
862         }
863
864         s = talloc_zero(c, struct pipe_conn_state);
865         if (composite_nomem(s, c)) return c;
866         c->private_data = s;
867
868         /* parse binding string to the structure */
869         c->status = dcerpc_parse_binding(c, binding, &b);
870         if (!NT_STATUS_IS_OK(c->status)) {
871                 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", binding));
872                 composite_error(c, c->status);
873                 return c;
874         }
875
876         DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(c, b)));
877
878         /* 
879            start connecting to a rpc pipe after binding structure
880            is established
881          */
882         pipe_conn_req = dcerpc_pipe_connect_b_send(c, b, table,
883                                                    credentials, ev, lp_ctx);
884         composite_continue(c, pipe_conn_req, continue_pipe_connect_b, c);
885         return c;
886 }
887
888
889 /*
890   Stage 2 of pipe_connect: Receive result of actual pipe connect request
891   and say if we're done ok
892 */
893 static void continue_pipe_connect_b(struct composite_context *ctx)
894 {
895         struct composite_context *c = talloc_get_type(ctx->async.private_data,
896                                                       struct composite_context);
897         struct pipe_conn_state *s = talloc_get_type(c->private_data,
898                                                     struct pipe_conn_state);
899
900         c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe);
901         talloc_steal(s, s->pipe);
902         if (!composite_is_ok(c)) return;
903
904         composite_done(c);
905 }
906
907
908 /*
909   Receive result of pipe connect (using binding string) request
910   and return connected pipe structure.
911 */
912 NTSTATUS dcerpc_pipe_connect_recv(struct composite_context *c,
913                                   TALLOC_CTX *mem_ctx,
914                                   struct dcerpc_pipe **pp)
915 {
916         NTSTATUS status;
917         struct pipe_conn_state *s;
918
919         status = composite_wait(c);
920         if (NT_STATUS_IS_OK(status)) {
921                 s = talloc_get_type(c->private_data, struct pipe_conn_state);
922                 *pp = talloc_steal(mem_ctx, s->pipe);
923         }
924         talloc_free(c);
925         return status;
926 }
927
928
929 /*
930   Open a rpc connection to a rpc pipe, using the specified string
931   binding to determine the endpoint and options - sync version
932 */
933 _PUBLIC_ NTSTATUS dcerpc_pipe_connect(TALLOC_CTX *parent_ctx, 
934                              struct dcerpc_pipe **pp, 
935                              const char *binding,
936                              const struct ndr_interface_table *table,
937                              struct cli_credentials *credentials,
938                              struct tevent_context *ev,
939                              struct loadparm_context *lp_ctx)
940 {
941         struct composite_context *c;
942         c = dcerpc_pipe_connect_send(parent_ctx, binding, 
943                                      table, credentials, ev, lp_ctx);
944         return dcerpc_pipe_connect_recv(c, parent_ctx, pp);
945 }
946