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