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