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