b9913106f0b8c4439505517afc439c108a91c1d1
[gd/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(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, lp_ncalrpc_dir(global_loadparm), 
448                                               s->io.binding->endpoint);
449         composite_continue(c, pipe_req, continue_pipe_open_ncalrpc, c);
450         return c;
451 }
452
453
454 /*
455   Receive result of a rpc connection to a rpc pipe on NCALRPC
456 */
457 static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c)
458 {
459         NTSTATUS status = composite_wait(c);
460         
461         talloc_free(c);
462         return status;
463 }
464
465
466 struct pipe_connect_state {
467         struct dcerpc_pipe *pipe;
468         struct dcerpc_binding *binding;
469         const struct ndr_interface_table *table;
470         struct cli_credentials *credentials;
471 };
472
473
474 static void continue_map_binding(struct composite_context *ctx);
475 static void continue_connect(struct composite_context *c, struct pipe_connect_state *s);
476 static void continue_pipe_connect_ncacn_np_smb2(struct composite_context *ctx);
477 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx);
478 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx);
479 static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx);
480 static void continue_pipe_connect_ncalrpc(struct composite_context *ctx);
481 static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s);
482 static void continue_pipe_auth(struct composite_context *ctx);
483
484
485 /*
486   Stage 2 of pipe_connect_b: Receive result of endpoint mapping
487 */
488 static void continue_map_binding(struct composite_context *ctx)
489 {
490         struct composite_context *c = talloc_get_type(ctx->async.private_data,
491                                                       struct composite_context);
492         struct pipe_connect_state *s = talloc_get_type(c->private_data,
493                                                        struct pipe_connect_state);
494         
495         c->status = dcerpc_epm_map_binding_recv(ctx);
496         if (!composite_is_ok(c)) return;
497
498         DEBUG(2,("Mapped to DCERPC endpoint %s\n", s->binding->endpoint));
499         
500         continue_connect(c, s);
501 }
502
503
504 /*
505   Stage 2 of pipe_connect_b: Continue connection after endpoint is known
506 */
507 static void continue_connect(struct composite_context *c, struct pipe_connect_state *s)
508 {
509         struct dcerpc_pipe_connect pc;
510
511         /* potential exits to another stage by sending an async request */
512         struct composite_context *ncacn_np_smb2_req;
513         struct composite_context *ncacn_np_smb_req;
514         struct composite_context *ncacn_ip_tcp_req;
515         struct composite_context *ncacn_unix_req;
516         struct composite_context *ncalrpc_req;
517
518         /* dcerpc pipe connect input parameters */
519         pc.pipe         = s->pipe;
520         pc.binding      = s->binding;
521         pc.interface    = s->table;
522         pc.creds        = s->credentials;
523         pc.name_resolve_order = lp_name_resolve_order(global_loadparm);
524
525         /* connect dcerpc pipe depending on required transport */
526         switch (s->binding->transport) {
527         case NCACN_NP:
528                 if (pc.binding->flags & DCERPC_SMB2) {
529                         /* new varient of SMB a.k.a. SMB2 */
530                         ncacn_np_smb2_req = dcerpc_pipe_connect_ncacn_np_smb2_send(c, &pc);
531                         composite_continue(c, ncacn_np_smb2_req, continue_pipe_connect_ncacn_np_smb2, c);
532                         return;
533
534                 } else {
535                         /* good old ordinary SMB */
536                         ncacn_np_smb_req = dcerpc_pipe_connect_ncacn_np_smb_send(c, &pc);
537                         composite_continue(c, ncacn_np_smb_req, continue_pipe_connect_ncacn_np_smb, c);
538                         return;
539                 }
540                 break;
541
542         case NCACN_IP_TCP:
543                 ncacn_ip_tcp_req = dcerpc_pipe_connect_ncacn_ip_tcp_send(c, &pc);
544                 composite_continue(c, ncacn_ip_tcp_req, continue_pipe_connect_ncacn_ip_tcp, c);
545                 return;
546
547         case NCACN_UNIX_STREAM:
548                 ncacn_unix_req = dcerpc_pipe_connect_ncacn_unix_stream_send(c, &pc);
549                 composite_continue(c, ncacn_unix_req, continue_pipe_connect_ncacn_unix, c);
550                 return;
551
552         case NCALRPC:
553                 ncalrpc_req = dcerpc_pipe_connect_ncalrpc_send(c, &pc);
554                 composite_continue(c, ncalrpc_req, continue_pipe_connect_ncalrpc, c);
555                 return;
556
557         default:
558                 /* looks like a transport we don't support now */
559                 composite_error(c, NT_STATUS_NOT_SUPPORTED);
560         }
561 }
562
563
564 /*
565   Stage 3 of pipe_connect_b: Receive result of pipe connect request on
566   named pipe on smb2
567 */
568 static void continue_pipe_connect_ncacn_np_smb2(struct composite_context *ctx)
569 {
570         struct composite_context *c = talloc_get_type(ctx->async.private_data,
571                                                       struct composite_context);
572         struct pipe_connect_state *s = talloc_get_type(c->private_data,
573                                                        struct pipe_connect_state);
574
575         c->status = dcerpc_pipe_connect_ncacn_np_smb2_recv(ctx);
576         if (!composite_is_ok(c)) return;
577
578         continue_pipe_connect(c, s);
579 }
580
581
582 /*
583   Stage 3 of pipe_connect_b: Receive result of pipe connect request on
584   named pipe on smb
585 */
586 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx)
587 {
588         struct composite_context *c = talloc_get_type(ctx->async.private_data,
589                                                       struct composite_context);
590         struct pipe_connect_state *s = talloc_get_type(c->private_data,
591                                                        struct pipe_connect_state);
592
593         c->status = dcerpc_pipe_connect_ncacn_np_smb_recv(ctx);
594         if (!composite_is_ok(c)) return;
595         
596         continue_pipe_connect(c, s);
597 }
598
599
600 /*
601   Stage 3 of pipe_connect_b: Receive result of pipe connect request on tcp/ip
602 */
603 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx)
604 {
605         struct composite_context *c = talloc_get_type(ctx->async.private_data,
606                                                       struct composite_context);
607         struct pipe_connect_state *s = talloc_get_type(c->private_data,
608                                                        struct pipe_connect_state);
609
610         c->status = dcerpc_pipe_connect_ncacn_ip_tcp_recv(ctx);
611         if (!composite_is_ok(c)) return;
612
613         continue_pipe_connect(c, s);
614 }
615
616
617 /*
618   Stage 3 of pipe_connect_b: Receive result of pipe connect request on unix socket
619 */
620 static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx)
621 {
622         struct composite_context *c = talloc_get_type(ctx->async.private_data,
623                                                       struct composite_context);
624         struct pipe_connect_state *s = talloc_get_type(c->private_data,
625                                                        struct pipe_connect_state);
626         
627         c->status = dcerpc_pipe_connect_ncacn_unix_stream_recv(ctx);
628         if (!composite_is_ok(c)) return;
629         
630         continue_pipe_connect(c, s);
631 }
632
633
634 /*
635   Stage 3 of pipe_connect_b: Receive result of pipe connect request on local rpc
636 */
637 static void continue_pipe_connect_ncalrpc(struct composite_context *ctx)
638 {
639         struct composite_context *c = talloc_get_type(ctx->async.private_data,
640                                                       struct composite_context);
641         struct pipe_connect_state *s = talloc_get_type(c->private_data,
642                                                        struct pipe_connect_state);
643         
644         c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
645         if (!composite_is_ok(c)) return;
646
647         continue_pipe_connect(c, s);
648 }
649
650
651 /*
652   Stage 4 of pipe_connect_b: Start an authentication on connected dcerpc pipe
653   depending on credentials and binding flags passed.
654 */
655 static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s)
656 {
657         struct composite_context *auth_bind_req;
658
659         s->pipe->binding = s->binding;
660         if (!talloc_reference(s->pipe, s->binding)) {
661                 composite_error(c, NT_STATUS_NO_MEMORY);
662                 return;
663         }
664
665         auth_bind_req = dcerpc_pipe_auth_send(s->pipe, s->binding, s->table,
666                                               s->credentials);
667         composite_continue(c, auth_bind_req, continue_pipe_auth, c);
668 }
669
670
671 /*
672   Stage 5 of pipe_connect_b: Receive result of pipe authentication request
673   and say if all went ok
674 */
675 static void continue_pipe_auth(struct composite_context *ctx)
676 {
677         struct composite_context *c = talloc_get_type(ctx->async.private_data,
678                                                       struct composite_context);
679         struct pipe_connect_state *s = talloc_get_type(c->private_data, struct pipe_connect_state);
680
681         c->status = dcerpc_pipe_auth_recv(ctx, s, &s->pipe);
682         if (!composite_is_ok(c)) return;
683
684         composite_done(c);
685 }
686
687
688 /*
689   handle timeouts of a dcerpc connect
690 */
691 static void dcerpc_connect_timeout_handler(struct event_context *ev, struct timed_event *te, 
692                                            struct timeval t, void *private)
693 {
694         struct composite_context *c = talloc_get_type(private, struct composite_context);
695         composite_error(c, NT_STATUS_IO_TIMEOUT);
696 }
697
698 /*
699   start a request to open a rpc connection to a rpc pipe, using
700   specified binding structure to determine the endpoint and options
701 */
702 struct composite_context* dcerpc_pipe_connect_b_send(TALLOC_CTX *parent_ctx,
703                                                      struct dcerpc_binding *binding,
704                                                      const struct ndr_interface_table *table,
705                                                      struct cli_credentials *credentials,
706                                                      struct event_context *ev)
707 {
708         struct composite_context *c;
709         struct pipe_connect_state *s;
710         struct event_context *new_ev = NULL;
711
712         if (ev == NULL) {
713                 new_ev = event_context_init(parent_ctx);
714                 if (new_ev == NULL) return NULL;
715                 ev = new_ev;
716         }
717
718         /* composite context allocation and setup */
719         c = composite_create(parent_ctx, ev);
720         if (c == NULL) {
721                 talloc_free(new_ev);
722                 return NULL;
723         }
724         talloc_steal(c, new_ev);
725
726         s = talloc_zero(c, struct pipe_connect_state);
727         if (composite_nomem(s, c)) return c;
728         c->private_data = s;
729
730         /* initialise dcerpc pipe structure */
731         s->pipe = dcerpc_pipe_init(c, ev);
732         if (composite_nomem(s->pipe, c)) return c;
733
734         /* store parameters in state structure */
735         s->binding      = binding;
736         s->table        = table;
737         s->credentials  = credentials;
738
739         event_add_timed(c->event_ctx, c,
740                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
741                         dcerpc_connect_timeout_handler, c);
742         
743         switch (s->binding->transport) {
744         case NCA_UNKNOWN: {
745                 struct composite_context *binding_req;
746                 binding_req = dcerpc_epm_map_binding_send(c, s->binding, s->table,
747                                                           s->pipe->conn->event_ctx);
748                 composite_continue(c, binding_req, continue_map_binding, c);
749                 return c;
750                 }
751
752         case NCACN_NP:
753         case NCACN_IP_TCP:
754         case NCALRPC:
755                 if (!s->binding->endpoint) {
756                         struct composite_context *binding_req;
757                         binding_req = dcerpc_epm_map_binding_send(c, s->binding, s->table,
758                                                                   s->pipe->conn->event_ctx);
759                         composite_continue(c, binding_req, continue_map_binding, c);
760                         return c;
761                 }
762
763         default:
764                 break;
765         }
766
767         continue_connect(c, s);
768         return c;
769 }
770
771
772 /*
773   receive result of a request to open a rpc connection to a rpc pipe
774 */
775 NTSTATUS dcerpc_pipe_connect_b_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
776                                     struct dcerpc_pipe **p)
777 {
778         NTSTATUS status;
779         struct pipe_connect_state *s;
780         
781         status = composite_wait(c);
782         
783         if (NT_STATUS_IS_OK(status)) {
784                 s = talloc_get_type(c->private_data, struct pipe_connect_state);
785                 talloc_steal(mem_ctx, s->pipe);
786                 *p = s->pipe;
787         }
788         talloc_free(c);
789         return status;
790 }
791
792
793 /*
794   open a rpc connection to a rpc pipe, using the specified 
795   binding structure to determine the endpoint and options - sync version
796 */
797 NTSTATUS dcerpc_pipe_connect_b(TALLOC_CTX *parent_ctx,
798                                struct dcerpc_pipe **pp,
799                                struct dcerpc_binding *binding,
800                                const struct ndr_interface_table *table,
801                                struct cli_credentials *credentials,
802                                struct event_context *ev)
803 {
804         struct composite_context *c;
805         
806         c = dcerpc_pipe_connect_b_send(parent_ctx, binding, table,
807                                        credentials, ev);
808         return dcerpc_pipe_connect_b_recv(c, parent_ctx, pp);
809 }
810
811
812 struct pipe_conn_state {
813         struct dcerpc_pipe *pipe;
814 };
815
816
817 static void continue_pipe_connect_b(struct composite_context *ctx);
818
819
820 /*
821   Initiate rpc connection to a rpc pipe, using the specified string
822   binding to determine the endpoint and options.
823   The string is to be parsed to a binding structure first.
824 */
825 struct composite_context* dcerpc_pipe_connect_send(TALLOC_CTX *parent_ctx,
826                                                    const char *binding,
827                                                    const struct ndr_interface_table *table,
828                                                    struct cli_credentials *credentials,
829                                                    struct event_context *ev)
830 {
831         struct composite_context *c;
832         struct pipe_conn_state *s;
833         struct dcerpc_binding *b;
834         struct composite_context *pipe_conn_req;
835         struct event_context *new_ev = NULL;
836
837         if (ev == NULL) {
838                 new_ev = event_context_init(parent_ctx);
839                 if (new_ev == NULL) return NULL;
840                 ev = new_ev;
841         }
842
843         /* composite context allocation and setup */
844         c = composite_create(parent_ctx, ev);
845         if (c == NULL) {
846                 talloc_free(new_ev);
847                 return NULL;
848         }
849         talloc_steal(c, new_ev);
850
851         s = talloc_zero(c, struct pipe_conn_state);
852         if (composite_nomem(s, c)) return c;
853         c->private_data = s;
854
855         /* parse binding string to the structure */
856         c->status = dcerpc_parse_binding(c, binding, &b);
857         if (!NT_STATUS_IS_OK(c->status)) {
858                 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", binding));
859                 composite_error(c, c->status);
860                 return c;
861         }
862
863         DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(c, b)));
864
865         /* 
866            start connecting to a rpc pipe after binding structure
867            is established
868          */
869         pipe_conn_req = dcerpc_pipe_connect_b_send(c, b, table,
870                                                    credentials, ev);
871         composite_continue(c, pipe_conn_req, continue_pipe_connect_b, c);
872         return c;
873 }
874
875
876 /*
877   Stage 2 of pipe_connect: Receive result of actual pipe connect request
878   and say if we're done ok
879 */
880 static void continue_pipe_connect_b(struct composite_context *ctx)
881 {
882         struct composite_context *c = talloc_get_type(ctx->async.private_data,
883                                                       struct composite_context);
884         struct pipe_conn_state *s = talloc_get_type(c->private_data,
885                                                     struct pipe_conn_state);
886
887         c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe);
888         talloc_steal(s, s->pipe);
889         if (!composite_is_ok(c)) return;
890
891         composite_done(c);
892 }
893
894
895 /*
896   Receive result of pipe connect (using binding string) request
897   and return connected pipe structure.
898 */
899 NTSTATUS dcerpc_pipe_connect_recv(struct composite_context *c,
900                                   TALLOC_CTX *mem_ctx,
901                                   struct dcerpc_pipe **pp)
902 {
903         NTSTATUS status;
904         struct pipe_conn_state *s;
905
906         status = composite_wait(c);
907         if (NT_STATUS_IS_OK(status)) {
908                 s = talloc_get_type(c->private_data, struct pipe_conn_state);
909                 *pp = talloc_steal(mem_ctx, s->pipe);
910         }
911         talloc_free(c);
912         return status;
913 }
914
915
916 /*
917   Open a rpc connection to a rpc pipe, using the specified string
918   binding to determine the endpoint and options - sync version
919 */
920 NTSTATUS dcerpc_pipe_connect(TALLOC_CTX *parent_ctx, 
921                              struct dcerpc_pipe **pp, 
922                              const char *binding,
923                              const struct ndr_interface_table *table,
924                              struct cli_credentials *credentials,
925                              struct event_context *ev)
926 {
927         struct composite_context *c;
928         c = dcerpc_pipe_connect_send(parent_ctx, binding, 
929                                      table,
930                                      credentials, ev);
931         return dcerpc_pipe_connect_recv(c, parent_ctx, pp);
932 }
933