cff29bc06b2a9b70db446af3b3a8f823f153fd55
[metze/samba/wip.git] / source4 / librpc / rpc / dcerpc_connect.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    dcerpc connect functions
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Jelmer Vernooij 2004
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2007
9    Copyright (C) Rafal Szczesniak  2005
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25
26 #include "includes.h"
27 #include "libcli/composite/composite.h"
28 #include "libcli/smb_composite/smb_composite.h"
29 #include "lib/events/events.h"
30 #include "libcli/smb2/smb2.h"
31 #include "libcli/smb2/smb2_calls.h"
32 #include "libcli/smb/smbXcli_base.h"
33 #include "librpc/rpc/dcerpc.h"
34 #include "librpc/rpc/dcerpc_proto.h"
35 #include "auth/credentials/credentials.h"
36 #include "param/param.h"
37 #include "libcli/resolve/resolve.h"
38 #include "lib/http/http.h"
39 #include "lib/util/util_net.h"
40
41 struct dcerpc_pipe_connect {
42         struct dcecli_connection *conn;
43         struct dcerpc_binding *binding;
44         const struct ndr_interface_table *interface;
45         struct cli_credentials *creds;
46         struct resolve_context *resolve_ctx;
47         struct {
48                 const char *dir;
49         } ncalrpc;
50         struct {
51                 struct smbXcli_conn *conn;
52                 struct smbXcli_session *session;
53                 struct smbXcli_tcon *tcon;
54                 const char *pipe_name;
55         } smb;
56 };
57
58 struct dcerpc_binding_smbXcli_pointers_ref;
59
60 struct dcerpc_binding_smbXcli_pointers {
61         struct smbXcli_conn *conn;
62         struct dcerpc_binding_smbXcli_pointers_ref *conn_ref;
63         struct smbXcli_session *sess;
64         struct dcerpc_binding_smbXcli_pointers_ref *sess_ref;
65         struct smbXcli_tcon *tcon;
66         struct dcerpc_binding_smbXcli_pointers_ref *tcon_ref;
67 };
68
69 struct dcerpc_binding_smbXcli_pointers_ref {
70         struct dcerpc_binding_smbXcli_pointers *p;
71 };
72
73 static int dcerpc_binding_smbXcli_pointers_ref_destructor(
74         struct dcerpc_binding_smbXcli_pointers_ref *ref)
75 {
76         struct dcerpc_binding_smbXcli_pointers *p;
77
78         if (ref->p == NULL) {
79                 return 0;
80         }
81
82         p = ref->p;
83
84         p->conn_ref->p = NULL;
85         p->sess_ref->p = NULL;
86         p->tcon_ref->p = NULL;
87
88         if (p->conn_ref != ref) {
89                 talloc_free(p->conn_ref);
90         }
91
92         if (p->sess_ref != ref) {
93                 talloc_free(p->sess_ref);
94         }
95
96         if (p->tcon_ref != ref) {
97                 talloc_free(p->tcon_ref);
98         }
99
100         ZERO_STRUCTP(p);
101         return 0;
102 }
103
104 static int dcerpc_binding_smbXcli_pointers_destructor(
105         struct dcerpc_binding_smbXcli_pointers *p)
106 {
107         if (p->conn_ref != NULL) {
108                 p->conn_ref->p = NULL;
109         }
110
111         if (p->sess_ref != NULL) {
112                 p->sess_ref->p = NULL;
113         }
114
115         if (p->tcon_ref != NULL) {
116                 p->tcon_ref->p = NULL;
117         }
118
119         talloc_free(p->conn_ref);
120         talloc_free(p->sess_ref);
121         talloc_free(p->tcon_ref);
122
123         ZERO_STRUCTP(p);
124         return 0;
125 }
126
127 NTSTATUS dcerpc_binding_set_smbXcli_pointers(struct dcerpc_binding *b,
128                                              struct smbXcli_conn *conn,
129                                              struct smbXcli_session *sess,
130                                              struct smbXcli_tcon *tcon)
131 {
132         struct dcerpc_binding_smbXcli_pointers *p;
133         struct dcerpc_binding_smbXcli_pointers_ref *r;
134         NTSTATUS status;
135
136         if (!smbXcli_conn_is_connected(conn)) {
137                 return NT_STATUS_INVALID_PARAMETER_MIX;
138         }
139
140         if (sess == NULL) {
141                 return NT_STATUS_INVALID_PARAMETER_MIX;
142         }
143
144         if (tcon == NULL) {
145                 return NT_STATUS_INVALID_PARAMETER_MIX;
146         }
147
148         p = talloc_zero(b, struct dcerpc_binding_smbXcli_pointers);
149         if (p == NULL) {
150                 return NT_STATUS_NO_MEMORY;
151         }
152         talloc_set_destructor(p, dcerpc_binding_smbXcli_pointers_destructor);
153
154         r = talloc_zero(conn, struct dcerpc_binding_smbXcli_pointers_ref);
155         if (r == NULL) {
156                 TALLOC_FREE(p);
157                 return NT_STATUS_NO_MEMORY;
158         }
159         talloc_set_destructor(r, dcerpc_binding_smbXcli_pointers_ref_destructor);
160         r->p = p;
161         p->conn_ref = r;
162
163         r = talloc_zero(sess, struct dcerpc_binding_smbXcli_pointers_ref);
164         if (r == NULL) {
165                 TALLOC_FREE(p);
166                 return NT_STATUS_NO_MEMORY;
167         }
168         talloc_set_destructor(r, dcerpc_binding_smbXcli_pointers_ref_destructor);
169         r->p = p;
170         p->sess_ref = r;
171
172         r = talloc_zero(tcon, struct dcerpc_binding_smbXcli_pointers_ref);
173         if (r == NULL) {
174                 TALLOC_FREE(p);
175                 return NT_STATUS_NO_MEMORY;
176         }
177         talloc_set_destructor(r, dcerpc_binding_smbXcli_pointers_ref_destructor);
178         r->p = p;
179         p->tcon_ref = r;
180
181         p->conn = conn;
182         p->sess = sess;
183         p->tcon = tcon;
184
185         status = dcerpc_binding_set_pointer_option(b, "connection",
186                                 struct dcerpc_binding_smbXcli_pointers, p);
187         if (!NT_STATUS_IS_OK(status)) {
188                 TALLOC_FREE(p);
189                 return status;
190         }
191
192         return NT_STATUS_OK;
193 }
194
195 NTSTATUS dcerpc_binding_get_smbXcli_pointers(const struct dcerpc_binding *b,
196                                              struct smbXcli_conn **conn,
197                                              struct smbXcli_session **sess,
198                                              struct smbXcli_tcon **tcon)
199 {
200         struct dcerpc_binding_smbXcli_pointers *p;
201
202         p = dcerpc_binding_get_pointer_option(b, "connection",
203                                 struct dcerpc_binding_smbXcli_pointers);
204         if (p == NULL) {
205                 return NT_STATUS_CONNECTION_DISCONNECTED;
206         }
207
208         if (!smbXcli_conn_is_connected(p->conn)) {
209                 return NT_STATUS_CONNECTION_DISCONNECTED;
210         }
211
212         if (p->sess == NULL) {
213                 return NT_STATUS_CONNECTION_DISCONNECTED;
214         }
215
216         if (p->tcon == NULL) {
217                 return NT_STATUS_CONNECTION_DISCONNECTED;
218         }
219
220         *conn = p->conn;
221         *sess = p->sess;
222         *tcon = p->tcon;
223
224         return NT_STATUS_OK;
225 }
226
227 struct pipe_np_smb_state {
228         struct smb_composite_connect conn;
229         struct dcerpc_pipe_connect io;
230 };
231
232
233 /*
234   Stage 3 of ncacn_np_smb: Named pipe opened (or not)
235 */
236 static void continue_pipe_open_smb(struct composite_context *ctx)
237 {
238         struct composite_context *c = talloc_get_type(ctx->async.private_data,
239                                                       struct composite_context);
240
241         /* receive result of named pipe open request on smb */
242         c->status = dcerpc_pipe_open_smb_recv(ctx);
243         if (!composite_is_ok(c)) return;
244
245         composite_done(c);
246 }
247
248 static void continue_smb_open(struct composite_context *c);
249 static void continue_smb2_connect(struct tevent_req *subreq);
250 static void continue_smbXcli_connect(struct tevent_req *subreq);
251
252 /*
253   Stage 2 of ncacn_np_smb: Open a named pipe after successful smb connection
254 */
255 static void continue_smb_connect(struct composite_context *ctx)
256 {
257         struct composite_context *c = talloc_get_type(ctx->async.private_data,
258                                                       struct composite_context);
259         struct pipe_np_smb_state *s = talloc_get_type(c->private_data,
260                                                       struct pipe_np_smb_state);
261         struct smbcli_tree *t;
262
263         /* receive result of smb connect request */
264         c->status = smb_composite_connect_recv(ctx, s->io.conn);
265         if (!composite_is_ok(c)) return;
266
267         t = s->conn.out.tree;
268
269         /* prepare named pipe open parameters */
270         s->io.smb.conn = t->session->transport->conn;
271         s->io.smb.session = t->session->smbXcli;
272         s->io.smb.tcon = t->smbXcli;
273         smb1cli_tcon_set_id(s->io.smb.tcon, t->tid);
274         s->io.smb.pipe_name = dcerpc_binding_get_string_option(s->io.binding,
275                                                                "endpoint");
276
277         c->status = dcerpc_binding_set_smbXcli_pointers(s->io.binding,
278                                                         s->io.smb.conn,
279                                                         s->io.smb.session,
280                                                         s->io.smb.tcon);
281         if (!composite_is_ok(c)) return;
282
283         continue_smb_open(c);
284 }
285
286 static void continue_smb_open(struct composite_context *c)
287 {
288         struct pipe_np_smb_state *s = talloc_get_type(c->private_data,
289                                                       struct pipe_np_smb_state);
290         struct composite_context *open_ctx;
291
292         /* send named pipe open request */
293         open_ctx = dcerpc_pipe_open_smb_send(s->io.conn,
294                                              s->io.smb.conn,
295                                              s->io.smb.session,
296                                              s->io.smb.tcon,
297                                              DCERPC_REQUEST_TIMEOUT * 1000,
298                                              s->io.smb.pipe_name);
299         if (composite_nomem(open_ctx, c)) return;
300
301         composite_continue(c, open_ctx, continue_pipe_open_smb, c);
302 }
303
304
305 /*
306   Initiate async open of a rpc connection to a rpc pipe on SMB using
307   the binding structure to determine the endpoint and options
308 */
309 static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CTX *mem_ctx, struct dcerpc_pipe_connect *io, struct loadparm_context *lp_ctx)
310 {
311         struct composite_context *c;
312         struct pipe_np_smb_state *s;
313         struct tevent_req *subreq = NULL;
314         struct smb_composite_connect *conn;
315         uint32_t flags;
316         const char *target_hostname = NULL;
317         const char *dest_address = NULL;
318         const char *calling_name = NULL;
319
320         /* composite context allocation and setup */
321         c = composite_create(mem_ctx, io->conn->event_ctx);
322         if (c == NULL) return NULL;
323
324         s = talloc_zero(c, struct pipe_np_smb_state);
325         if (composite_nomem(s, c)) return c;
326         c->private_data = s;
327
328         s->io  = *io;
329         conn   = &s->conn;
330
331         if (smbXcli_conn_is_connected(s->io.smb.conn)) {
332                 continue_smb_open(c);
333                 return c;
334         }
335
336         if (s->io.creds == NULL) {
337                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
338                 return c;
339         }
340
341         /* prepare smb connection parameters: we're connecting to IPC$ share on
342            remote rpc server */
343         target_hostname = dcerpc_binding_get_string_option(s->io.binding, "target_hostname");
344         conn->in.dest_host = dcerpc_binding_get_string_option(s->io.binding, "host");
345         conn->in.dest_ports = lpcfg_smb_ports(lp_ctx);
346         conn->in.called_name = target_hostname;
347         if (conn->in.called_name == NULL) {
348                 conn->in.called_name = "*SMBSERVER";
349         }
350         conn->in.socket_options         = lpcfg_socket_options(lp_ctx);
351         conn->in.service                = "IPC$";
352         conn->in.service_type           = NULL;
353         conn->in.workgroup              = lpcfg_workgroup(lp_ctx);
354         conn->in.gensec_settings = lpcfg_gensec_settings(conn, lp_ctx);
355
356         lpcfg_smbcli_options(lp_ctx, &conn->in.options);
357         lpcfg_smbcli_session_options(lp_ctx, &conn->in.session_options);
358
359         /*
360          * provide proper credentials - user supplied, but allow a
361          * fallback to anonymous if this is an schannel connection
362          * (might be NT4 not allowing machine logins at session
363          * setup) or if asked to do so by the caller (perhaps a SAMR password change?)
364          */
365         s->conn.in.credentials = s->io.creds;
366         flags = dcerpc_binding_get_flags(s->io.binding);
367         if (flags & (DCERPC_SCHANNEL|DCERPC_ANON_FALLBACK)) {
368                 conn->in.fallback_to_anonymous  = true;
369         } else {
370                 conn->in.fallback_to_anonymous  = false;
371         }
372
373         conn->in.options.min_protocol = lpcfg_client_ipc_min_protocol(lp_ctx);
374         conn->in.options.max_protocol = lpcfg_client_ipc_max_protocol(lp_ctx);
375         if ((flags & DCERPC_SMB1) && (flags & DCERPC_SMB2)) {
376                 /* auto */
377         } else if (flags & DCERPC_SMB2) {
378                 if (conn->in.options.min_protocol < PROTOCOL_SMB2_02) {
379                         conn->in.options.min_protocol = PROTOCOL_SMB2_02;
380                 }
381                 if (conn->in.options.max_protocol < PROTOCOL_SMB2_02) {
382                         conn->in.options.max_protocol = PROTOCOL_LATEST;
383                 }
384         } else if (flags & DCERPC_SMB1) {
385                 conn->in.options.min_protocol = PROTOCOL_NT1;
386                 conn->in.options.max_protocol = PROTOCOL_NT1;
387         } else {
388                 /* auto */
389         }
390
391         conn->in.options.signing = lpcfg_client_ipc_signing(lp_ctx);
392
393         if (s->conn.in.credentials != NULL) {
394                 calling_name = cli_credentials_get_workstation(s->conn.in.credentials);
395         }
396         if (calling_name == NULL) {
397                 calling_name = "SMBCLIENT";
398         }
399
400         if (target_hostname == NULL) {
401                 target_hostname = conn->in.dest_host;
402         }
403
404         if (is_ipaddress(conn->in.dest_host)) {
405                 dest_address = conn->in.dest_host;
406         }
407
408         subreq = smb_connect_nego_send(s,
409                                        c->event_ctx,
410                                        s->io.resolve_ctx,
411                                        &conn->in.options,
412                                        conn->in.socket_options,
413                                        conn->in.dest_host,
414                                        dest_address,
415                                        conn->in.dest_ports,
416                                        target_hostname,
417                                        conn->in.called_name,
418                                        calling_name);
419         if (composite_nomem(subreq, c)) return c;
420         tevent_req_set_callback(subreq,
421                                 continue_smbXcli_connect,
422                                 c);
423
424         return c;
425 }
426
427 static void continue_smbXcli_connect(struct tevent_req *subreq)
428 {
429         struct composite_context *c =
430                 tevent_req_callback_data(subreq,
431                 struct composite_context);
432         struct pipe_np_smb_state *s =
433                 talloc_get_type_abort(c->private_data,
434                 struct pipe_np_smb_state);
435         struct smb_composite_connect *conn = &s->conn;
436         struct composite_context *creq = NULL;
437         enum protocol_types protocol;
438
439         c->status = smb_connect_nego_recv(subreq, s,
440                                           &conn->in.existing_conn);
441         TALLOC_FREE(subreq);
442         if (!composite_is_ok(c)) return;
443
444         protocol = smbXcli_conn_protocol(conn->in.existing_conn);
445         if (protocol >= PROTOCOL_SMB2_02) {
446                 /*
447                  * continue with smb2 session setup/tree connect
448                  * on the established connection.
449                  */
450                 subreq = smb2_connect_send(s, c->event_ctx,
451                                 conn->in.dest_host,
452                                 conn->in.dest_ports,
453                                 conn->in.service,
454                                 s->io.resolve_ctx,
455                                 conn->in.credentials,
456                                 conn->in.fallback_to_anonymous,
457                                 &conn->in.existing_conn,
458                                 0, /* previous_session_id */
459                                 &conn->in.options,
460                                 conn->in.socket_options,
461                                 conn->in.gensec_settings);
462                 if (composite_nomem(subreq, c)) return;
463                 tevent_req_set_callback(subreq, continue_smb2_connect, c);
464                 return;
465         }
466
467         /*
468          * continue with smb1 session setup/tree connect
469          * on the established connection.
470          */
471         creq = smb_composite_connect_send(conn, s->io.conn,
472                                           s->io.resolve_ctx,
473                                           c->event_ctx);
474         if (composite_nomem(creq, c)) return;
475
476         composite_continue(c, creq, continue_smb_connect, c);
477         return;
478 }
479
480
481 /*
482   Receive result of a rpc connection to a rpc pipe on SMB
483 */
484 static NTSTATUS dcerpc_pipe_connect_ncacn_np_smb_recv(struct composite_context *c)
485 {
486         NTSTATUS status = composite_wait(c);
487
488         talloc_free(c);
489         return status;
490 }
491
492 /*
493   Stage 2 of ncacn_np_smb2: Open a named pipe after successful smb2 connection
494 */
495 static void continue_smb2_connect(struct tevent_req *subreq)
496 {
497         struct composite_context *c =
498                 tevent_req_callback_data(subreq,
499                 struct composite_context);
500         struct pipe_np_smb_state *s = talloc_get_type(c->private_data,
501                                                       struct pipe_np_smb_state);
502         struct smb2_tree *t;
503
504         /* receive result of smb2 connect request */
505         c->status = smb2_connect_recv(subreq, s->io.conn, &t);
506         TALLOC_FREE(subreq);
507         if (!composite_is_ok(c)) return;
508
509         s->io.smb.conn = t->session->transport->conn;
510         s->io.smb.session = t->session->smbXcli;
511         s->io.smb.tcon = t->smbXcli;
512         s->io.smb.pipe_name = dcerpc_binding_get_string_option(s->io.binding,
513                                                                "endpoint");
514
515         c->status = dcerpc_binding_set_pointer_option(s->io.binding,
516                                                       "connection",
517                                                       struct smbXcli_conn,
518                                                       s->io.smb.conn);
519         if (!composite_is_ok(c)) return;
520
521         c->status = dcerpc_binding_set_pointer_option(s->io.binding,
522                                                       "connection",
523                                                       struct smbXcli_session,
524                                                       s->io.smb.session);
525         if (!composite_is_ok(c)) return;
526
527         c->status = dcerpc_binding_set_pointer_option(s->io.binding,
528                                                       "connection",
529                                                       struct smbXcli_tcon,
530                                                       s->io.smb.tcon);
531         if (!composite_is_ok(c)) return;
532
533         continue_smb_open(c);
534 }
535
536
537 struct pipe_ip_tcp_state {
538         struct dcerpc_pipe_connect io;
539         const char *localaddr;
540         const char *host;
541         const char *target_hostname;
542         uint32_t port;
543 };
544
545
546 /*
547   Stage 2 of ncacn_ip_tcp: rpc pipe opened (or not)
548 */
549 static void continue_pipe_open_ncacn_ip_tcp(struct composite_context *ctx)
550 {
551         struct composite_context *c = talloc_get_type(ctx->async.private_data,
552                                                       struct composite_context);
553         struct pipe_ip_tcp_state *s = talloc_get_type(c->private_data,
554                                                       struct pipe_ip_tcp_state);
555         char *localaddr = NULL;
556         char *remoteaddr = NULL;
557
558         /* receive result of named pipe open request on tcp/ip */
559         c->status = dcerpc_pipe_open_tcp_recv(ctx, s, &localaddr, &remoteaddr);
560         if (!composite_is_ok(c)) return;
561
562         c->status = dcerpc_binding_set_string_option(s->io.binding,
563                                                      "localaddress",
564                                                      localaddr);
565         if (!composite_is_ok(c)) return;
566
567         c->status = dcerpc_binding_set_string_option(s->io.binding,
568                                                      "host",
569                                                      remoteaddr);
570         if (!composite_is_ok(c)) return;
571
572         composite_done(c);
573 }
574
575
576 /*
577   Initiate async open of a rpc connection to a rpc pipe on TCP/IP using
578   the binding structure to determine the endpoint and options
579 */
580 static struct composite_context* dcerpc_pipe_connect_ncacn_ip_tcp_send(TALLOC_CTX *mem_ctx,
581                                                                        struct dcerpc_pipe_connect *io)
582 {
583         struct composite_context *c;
584         struct pipe_ip_tcp_state *s;
585         struct composite_context *pipe_req;
586         const char *endpoint;
587
588         /* composite context allocation and setup */
589         c = composite_create(mem_ctx, io->conn->event_ctx);
590         if (c == NULL) return NULL;
591
592         s = talloc_zero(c, struct pipe_ip_tcp_state);
593         if (composite_nomem(s, c)) return c;
594         c->private_data = s;
595
596         /* store input parameters in state structure */
597         s->io = *io;
598         s->localaddr = dcerpc_binding_get_string_option(io->binding,
599                                                         "localaddress");
600         s->host = dcerpc_binding_get_string_option(io->binding, "host");
601         s->target_hostname = dcerpc_binding_get_string_option(io->binding,
602                                                               "target_hostname");
603         endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
604         /* port number is a binding endpoint here */
605         if (endpoint != NULL) {
606                 s->port = atoi(endpoint);
607         }
608
609         if (s->port == 0) {
610                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
611                 return c;
612         }
613
614         /* send pipe open request on tcp/ip */
615         pipe_req = dcerpc_pipe_open_tcp_send(s->io.conn, s->localaddr, s->host, s->target_hostname,
616                                              s->port, io->resolve_ctx);
617         composite_continue(c, pipe_req, continue_pipe_open_ncacn_ip_tcp, c);
618         return c;
619 }
620
621
622 /*
623   Receive result of a rpc connection to a rpc pipe on TCP/IP
624 */
625 static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp_recv(struct composite_context *c)
626 {
627         NTSTATUS status = composite_wait(c);
628         
629         talloc_free(c);
630         return status;
631 }
632
633
634 struct pipe_http_state {
635         struct dcerpc_pipe_connect io;
636         const char *localaddr;
637         const char *target_hostname;
638         const char *rpc_server;
639         uint32_t rpc_server_port;
640         char *rpc_proxy;
641         uint32_t rpc_proxy_port;
642         char *http_proxy;
643         uint32_t http_proxy_port;
644         bool use_tls;
645         bool use_proxy;
646         enum http_auth_method http_auth;
647         struct loadparm_context *lp_ctx;
648 };
649
650 /*
651   Stage 2 of ncacn_http: rpc pipe opened (or not)
652  */
653 static void continue_pipe_open_ncacn_http(struct tevent_req *subreq)
654 {
655         struct composite_context *c = NULL;
656         struct pipe_http_state *s = NULL;
657         struct tstream_context *stream = NULL;
658         struct tevent_queue *queue = NULL;
659
660         c = tevent_req_callback_data(subreq, struct composite_context);
661         s = talloc_get_type(c->private_data, struct pipe_http_state);
662
663         /* receive result of RoH connect request */
664         c->status = dcerpc_pipe_open_roh_recv(subreq, s->io.conn,
665                                               &stream, &queue);
666         TALLOC_FREE(subreq);
667         if (!composite_is_ok(c)) return;
668
669         s->io.conn->transport.transport = NCACN_HTTP;
670         s->io.conn->transport.stream = stream;
671         s->io.conn->transport.write_queue = queue;
672         s->io.conn->transport.pending_reads = 0;
673         s->io.conn->server_name = strupper_talloc(s->io.conn,
674                                                   s->target_hostname);
675
676         composite_done(c);
677 }
678
679 /*
680   Initiate async open of a rpc connection to a rpc pipe using HTTP transport,
681   and using the binding structure to determine the endpoint and options
682 */
683 static struct composite_context* dcerpc_pipe_connect_ncacn_http_send(
684                 TALLOC_CTX *mem_ctx, struct dcerpc_pipe_connect *io,
685                 struct loadparm_context *lp_ctx)
686 {
687         struct composite_context *c;
688         struct pipe_http_state *s;
689         struct tevent_req *subreq;
690         const char *endpoint;
691         const char *use_proxy;
692         char *proxy;
693         char *port;
694         const char *opt;
695
696         /* composite context allocation and setup */
697         c = composite_create(mem_ctx, io->conn->event_ctx);
698         if (c == NULL) return NULL;
699
700         s = talloc_zero(c, struct pipe_http_state);
701         if (composite_nomem(s, c)) return c;
702         c->private_data = s;
703
704         /* store input parameters in state structure */
705         s->lp_ctx       = lp_ctx;
706         s->io           = *io;
707         s->localaddr    = dcerpc_binding_get_string_option(io->binding,
708                                                         "localaddress");
709         /* RPC server and port (the endpoint) */
710         s->rpc_server = dcerpc_binding_get_string_option(io->binding, "host");
711         s->target_hostname = dcerpc_binding_get_string_option(io->binding,
712                                                               "target_hostname");
713         endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
714         if (endpoint == NULL) {
715                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
716                 return c;
717         }
718         s->rpc_server_port = atoi(endpoint);
719         if (s->rpc_server_port == 0) {
720                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
721                 return c;
722         }
723
724         /* Use TLS */
725         opt = dcerpc_binding_get_string_option(io->binding, "HttpUseTls");
726         if (opt) {
727                 if (strcasecmp(opt, "true") == 0) {
728                         s->use_tls = true;
729                 } else if (strcasecmp(opt, "false") == 0) {
730                         s->use_tls = false;
731                 } else {
732                         composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
733                         return c;
734                 }
735         } else {
736                 s->use_tls = true;
737         }
738
739         /* RPC Proxy */
740         proxy = port = talloc_strdup(s, dcerpc_binding_get_string_option(
741                         io->binding, "RpcProxy"));
742         s->rpc_proxy  = strsep(&port, ":");
743         if (proxy && port) {
744                 s->rpc_proxy_port = atoi(port);
745         } else {
746                 s->rpc_proxy_port = s->use_tls ? 443 : 80;
747         }
748         if (s->rpc_proxy == NULL) {
749                 s->rpc_proxy = talloc_strdup(s, s->rpc_server);
750                 if (composite_nomem(s->rpc_proxy, c)) return c;
751         }
752
753         /* HTTP Proxy */
754         proxy = port = talloc_strdup(s, dcerpc_binding_get_string_option(
755                         io->binding, "HttpProxy"));
756         s->http_proxy = strsep(&port, ":");
757         if (proxy && port) {
758                 s->http_proxy_port = atoi(port);
759         } else {
760                 s->http_proxy_port = s->use_tls ? 443 : 80;
761         }
762
763         /* Use local proxy */
764         use_proxy = dcerpc_binding_get_string_option(io->binding,
765                                                  "HttpConnectOption");
766         if (use_proxy && strcasecmp(use_proxy, "UseHttpProxy")) {
767                 s->use_proxy = true;
768         }
769
770         /* If use local proxy set, the http proxy should be provided */
771         if (s->use_proxy && !s->http_proxy) {
772                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
773                 return c;
774         }
775
776         /* Check which HTTP authentication method to use */
777         opt = dcerpc_binding_get_string_option(io->binding, "HttpAuthOption");
778         if (opt) {
779                 if (strcasecmp(opt, "basic") == 0) {
780                         s->http_auth = HTTP_AUTH_BASIC;
781                 } else if (strcasecmp(opt, "ntlm") == 0) {
782                         s->http_auth = HTTP_AUTH_NTLM;
783                 } else if (strcasecmp(opt, "negotiate") == 0) {
784                         s->http_auth = HTTP_AUTH_NEGOTIATE;
785                 } else {
786                         composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
787                         return c;
788                 }
789         } else {
790                 s->http_auth = HTTP_AUTH_NTLM;
791         }
792
793         subreq = dcerpc_pipe_open_roh_send(s->io.conn, s->localaddr,
794                                            s->rpc_server, s->rpc_server_port,
795                                            s->rpc_proxy, s->rpc_proxy_port,
796                                            s->http_proxy, s->http_proxy_port,
797                                            s->use_tls, s->use_proxy,
798                                            s->io.creds, io->resolve_ctx,
799                                            s->lp_ctx, s->http_auth);
800         if (composite_nomem(subreq, c)) return c;
801
802         tevent_req_set_callback(subreq, continue_pipe_open_ncacn_http, c);
803         return c;
804 }
805
806 static NTSTATUS dcerpc_pipe_connect_ncacn_http_recv(struct composite_context *c)
807 {
808         return composite_wait_free(c);
809 }
810
811
812 struct pipe_unix_state {
813         struct dcerpc_pipe_connect io;
814         const char *path;
815 };
816
817
818 /*
819   Stage 2 of ncacn_unix: rpc pipe opened (or not)
820 */
821 static void continue_pipe_open_ncacn_unix_stream(struct composite_context *ctx)
822 {
823         struct composite_context *c = talloc_get_type(ctx->async.private_data,
824                                                       struct composite_context);
825
826         /* receive result of pipe open request on unix socket */
827         c->status = dcerpc_pipe_open_unix_stream_recv(ctx);
828         if (!composite_is_ok(c)) return;
829
830         composite_done(c);
831 }
832
833
834 /*
835   Initiate async open of a rpc connection to a rpc pipe on unix socket using
836   the binding structure to determine the endpoint and options
837 */
838 static struct composite_context* dcerpc_pipe_connect_ncacn_unix_stream_send(TALLOC_CTX *mem_ctx,
839                                                                             struct dcerpc_pipe_connect *io)
840 {
841         struct composite_context *c;
842         struct pipe_unix_state *s;
843         struct composite_context *pipe_req;
844
845         /* composite context allocation and setup */
846         c = composite_create(mem_ctx, io->conn->event_ctx);
847         if (c == NULL) return NULL;
848
849         s = talloc_zero(c, struct pipe_unix_state);
850         if (composite_nomem(s, c)) return c;
851         c->private_data = s;
852
853         /* prepare pipe open parameters and store them in state structure
854            also, verify whether biding endpoint is not null */
855         s->io = *io;
856
857         s->path = dcerpc_binding_get_string_option(io->binding, "endpoint");
858         if (s->path == NULL) {
859                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
860                 return c;
861         }
862
863         /* send pipe open request on unix socket */
864         pipe_req = dcerpc_pipe_open_unix_stream_send(s->io.conn, s->path);
865         composite_continue(c, pipe_req, continue_pipe_open_ncacn_unix_stream, c);
866         return c;
867 }
868
869
870 /*
871   Receive result of a rpc connection to a pipe on unix socket
872 */
873 static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream_recv(struct composite_context *c)
874 {
875         NTSTATUS status = composite_wait(c);
876
877         talloc_free(c);
878         return status;
879 }
880
881
882 struct pipe_ncalrpc_state {
883         struct dcerpc_pipe_connect io;
884 };
885
886 static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c);
887
888 /*
889   Stage 2 of ncalrpc: rpc pipe opened (or not)
890 */
891 static void continue_pipe_open_ncalrpc(struct composite_context *ctx)
892 {
893         struct composite_context *c = talloc_get_type(ctx->async.private_data,
894                                                       struct composite_context);
895
896         /* receive result of pipe open request on ncalrpc */
897         c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
898         if (!composite_is_ok(c)) return;
899
900         composite_done(c);
901 }
902
903
904 /* 
905    Initiate async open of a rpc connection request on NCALRPC using
906    the binding structure to determine the endpoint and options
907 */
908 static struct composite_context* dcerpc_pipe_connect_ncalrpc_send(TALLOC_CTX *mem_ctx,
909                                                                   struct dcerpc_pipe_connect *io)
910 {
911         struct composite_context *c;
912         struct pipe_ncalrpc_state *s;
913         struct composite_context *pipe_req;
914         const char *endpoint;
915
916         /* composite context allocation and setup */
917         c = composite_create(mem_ctx, io->conn->event_ctx);
918         if (c == NULL) return NULL;
919
920         s = talloc_zero(c, struct pipe_ncalrpc_state);
921         if (composite_nomem(s, c)) return c;
922         c->private_data = s;
923         
924         /* store input parameters in state structure */
925         s->io  = *io;
926
927         endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
928         if (endpoint == NULL) {
929                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
930                 return c;
931         }
932
933         /* send pipe open request */
934         pipe_req = dcerpc_pipe_open_pipe_send(s->io.conn,
935                                               s->io.ncalrpc.dir,
936                                               endpoint);
937         composite_continue(c, pipe_req, continue_pipe_open_ncalrpc, c);
938         return c;
939 }
940
941
942 /*
943   Receive result of a rpc connection to a rpc pipe on NCALRPC
944 */
945 static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c)
946 {
947         NTSTATUS status = composite_wait(c);
948         
949         talloc_free(c);
950         return status;
951 }
952
953
954 struct pipe_connect_state {
955         struct dcerpc_pipe *pipe;
956         struct dcerpc_binding *binding;
957         const struct ndr_interface_table *table;
958         struct cli_credentials *credentials;
959         struct loadparm_context *lp_ctx;
960 };
961
962
963 static void continue_map_binding(struct composite_context *ctx);
964 static void continue_connect(struct composite_context *c, struct pipe_connect_state *s);
965 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx);
966 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx);
967 static void continue_pipe_connect_ncacn_http(struct composite_context *ctx);
968 static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx);
969 static void continue_pipe_connect_ncalrpc(struct composite_context *ctx);
970 static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s);
971 static void continue_pipe_auth(struct composite_context *ctx);
972
973
974 /*
975   Stage 2 of pipe_connect_b: Receive result of endpoint mapping
976 */
977 static void continue_map_binding(struct composite_context *ctx)
978 {
979         struct composite_context *c = talloc_get_type(ctx->async.private_data,
980                                                       struct composite_context);
981         struct pipe_connect_state *s = talloc_get_type(c->private_data,
982                                                        struct pipe_connect_state);
983         const char *endpoint;
984
985         c->status = dcerpc_epm_map_binding_recv(ctx);
986         if (!composite_is_ok(c)) return;
987
988         endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
989         DEBUG(4,("Mapped to DCERPC endpoint %s\n", endpoint));
990
991         continue_connect(c, s);
992 }
993
994
995 /*
996   Stage 2 of pipe_connect_b: Continue connection after endpoint is known
997 */
998 static void continue_connect(struct composite_context *c, struct pipe_connect_state *s)
999 {
1000         struct dcerpc_pipe_connect pc;
1001
1002         /* potential exits to another stage by sending an async request */
1003         struct composite_context *ncacn_np_smb_req;
1004         struct composite_context *ncacn_ip_tcp_req;
1005         struct composite_context *ncacn_http_req;
1006         struct composite_context *ncacn_unix_req;
1007         struct composite_context *ncalrpc_req;
1008         enum dcerpc_transport_t transport;
1009         const char *endpoint = NULL;
1010
1011         /* dcerpc pipe connect input parameters */
1012         ZERO_STRUCT(pc);
1013         pc.conn         = s->pipe->conn;
1014         pc.binding      = s->binding;
1015         pc.interface    = s->table;
1016         pc.creds        = s->credentials;
1017         pc.resolve_ctx  = lpcfg_resolve_context(s->lp_ctx);
1018
1019         transport = dcerpc_binding_get_transport(s->binding);
1020
1021         /* connect dcerpc pipe depending on required transport */
1022         switch (transport) {
1023         case NCACN_NP:
1024                 /*
1025                  * SMB1/2/3...
1026                  */
1027
1028                 endpoint = dcerpc_binding_get_string_option(pc.binding,
1029                                                             "endpoint");
1030                 if (endpoint != NULL) {
1031                         NTSTATUS status;
1032
1033                         pc.smb.pipe_name = endpoint;
1034
1035                         status = dcerpc_binding_get_smbXcli_pointers(pc.binding,
1036                                                                 &pc.smb.conn,
1037                                                                 &pc.smb.session,
1038                                                                 &pc.smb.tcon);
1039                         if (!NT_STATUS_IS_OK(status)) {
1040                                 ZERO_STRUCT(pc.smb);
1041                         }
1042                 }
1043
1044                 ncacn_np_smb_req = dcerpc_pipe_connect_ncacn_np_smb_send(c, &pc, s->lp_ctx);
1045                 composite_continue(c, ncacn_np_smb_req, continue_pipe_connect_ncacn_np_smb, c);
1046                 return;
1047
1048         case NCACN_IP_TCP:
1049                 ncacn_ip_tcp_req = dcerpc_pipe_connect_ncacn_ip_tcp_send(c, &pc);
1050                 composite_continue(c, ncacn_ip_tcp_req, continue_pipe_connect_ncacn_ip_tcp, c);
1051                 return;
1052
1053         case NCACN_HTTP:
1054                 ncacn_http_req = dcerpc_pipe_connect_ncacn_http_send(c, &pc, s->lp_ctx);
1055                 composite_continue(c, ncacn_http_req, continue_pipe_connect_ncacn_http, c);
1056                 return;
1057
1058         case NCACN_UNIX_STREAM:
1059                 ncacn_unix_req = dcerpc_pipe_connect_ncacn_unix_stream_send(c, &pc);
1060                 composite_continue(c, ncacn_unix_req, continue_pipe_connect_ncacn_unix, c);
1061                 return;
1062
1063         case NCALRPC:
1064                 pc.ncalrpc.dir = lpcfg_ncalrpc_dir(s->lp_ctx);
1065                 c->status = dcerpc_binding_set_string_option(s->binding, "ncalrpc_dir",
1066                                                              pc.ncalrpc.dir);
1067                 if (!composite_is_ok(c)) return;
1068                 ncalrpc_req = dcerpc_pipe_connect_ncalrpc_send(c, &pc);
1069                 composite_continue(c, ncalrpc_req, continue_pipe_connect_ncalrpc, c);
1070                 return;
1071
1072         default:
1073                 /* looks like a transport we don't support now */
1074                 composite_error(c, NT_STATUS_NOT_SUPPORTED);
1075         }
1076 }
1077
1078
1079 /*
1080   Stage 3 of pipe_connect_b: Receive result of pipe connect request on
1081   named pipe on smb
1082 */
1083 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx)
1084 {
1085         struct composite_context *c = talloc_get_type(ctx->async.private_data,
1086                                                       struct composite_context);
1087         struct pipe_connect_state *s = talloc_get_type(c->private_data,
1088                                                        struct pipe_connect_state);
1089
1090         c->status = dcerpc_pipe_connect_ncacn_np_smb_recv(ctx);
1091         if (!composite_is_ok(c)) return;
1092         
1093         continue_pipe_connect(c, s);
1094 }
1095
1096
1097 /*
1098   Stage 3 of pipe_connect_b: Receive result of pipe connect request on tcp/ip
1099 */
1100 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx)
1101 {
1102         struct composite_context *c = talloc_get_type(ctx->async.private_data,
1103                                                       struct composite_context);
1104         struct pipe_connect_state *s = talloc_get_type(c->private_data,
1105                                                        struct pipe_connect_state);
1106
1107         c->status = dcerpc_pipe_connect_ncacn_ip_tcp_recv(ctx);
1108         if (!composite_is_ok(c)) return;
1109
1110         continue_pipe_connect(c, s);
1111 }
1112
1113
1114 /*
1115   Stage 3 of pipe_connect_b: Receive result of pipe connect request on http
1116 */
1117 static void continue_pipe_connect_ncacn_http(struct composite_context *ctx)
1118 {
1119         struct composite_context *c = talloc_get_type(ctx->async.private_data,
1120                                                       struct composite_context);
1121         struct pipe_connect_state *s = talloc_get_type(c->private_data,
1122                                                        struct pipe_connect_state);
1123
1124         c->status = dcerpc_pipe_connect_ncacn_http_recv(ctx);
1125         if (!composite_is_ok(c)) return;
1126
1127         continue_pipe_connect(c, s);
1128 }
1129
1130
1131 /*
1132   Stage 3 of pipe_connect_b: Receive result of pipe connect request on unix socket
1133 */
1134 static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx)
1135 {
1136         struct composite_context *c = talloc_get_type(ctx->async.private_data,
1137                                                       struct composite_context);
1138         struct pipe_connect_state *s = talloc_get_type(c->private_data,
1139                                                        struct pipe_connect_state);
1140         
1141         c->status = dcerpc_pipe_connect_ncacn_unix_stream_recv(ctx);
1142         if (!composite_is_ok(c)) return;
1143         
1144         continue_pipe_connect(c, s);
1145 }
1146
1147
1148 /*
1149   Stage 3 of pipe_connect_b: Receive result of pipe connect request on local rpc
1150 */
1151 static void continue_pipe_connect_ncalrpc(struct composite_context *ctx)
1152 {
1153         struct composite_context *c = talloc_get_type(ctx->async.private_data,
1154                                                       struct composite_context);
1155         struct pipe_connect_state *s = talloc_get_type(c->private_data,
1156                                                        struct pipe_connect_state);
1157         
1158         c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
1159         if (!composite_is_ok(c)) return;
1160
1161         continue_pipe_connect(c, s);
1162 }
1163
1164
1165 /*
1166   Stage 4 of pipe_connect_b: Start an authentication on connected dcerpc pipe
1167   depending on credentials and binding flags passed.
1168 */
1169 static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s)
1170 {
1171         struct composite_context *auth_bind_req;
1172
1173         s->pipe->binding = talloc_move(s->pipe, &s->binding);
1174
1175         auth_bind_req = dcerpc_pipe_auth_send(s->pipe, s->pipe->binding, s->table,
1176                                               s->credentials, s->lp_ctx);
1177         composite_continue(c, auth_bind_req, continue_pipe_auth, c);
1178 }
1179
1180
1181 /*
1182   Stage 5 of pipe_connect_b: Receive result of pipe authentication request
1183   and say if all went ok
1184 */
1185 static void continue_pipe_auth(struct composite_context *ctx)
1186 {
1187         struct composite_context *c = talloc_get_type(ctx->async.private_data,
1188                                                       struct composite_context);
1189         struct pipe_connect_state *s = talloc_get_type(c->private_data, struct pipe_connect_state);
1190
1191         c->status = dcerpc_pipe_auth_recv(ctx, s, &s->pipe);
1192         if (!composite_is_ok(c)) return;
1193
1194         composite_done(c);
1195 }
1196
1197
1198 /*
1199   handle timeouts of a dcerpc connect
1200 */
1201 static void dcerpc_connect_timeout_handler(struct tevent_context *ev, struct tevent_timer *te, 
1202                                            struct timeval t, void *private_data)
1203 {
1204         struct composite_context *c = talloc_get_type_abort(private_data,
1205                                                       struct composite_context);
1206         struct pipe_connect_state *s = talloc_get_type_abort(c->private_data, struct pipe_connect_state);
1207         if (!s->pipe->inhibit_timeout_processing) {
1208                 composite_error(c, NT_STATUS_IO_TIMEOUT);
1209         } else {
1210                 s->pipe->timed_out = true;
1211         }
1212 }
1213
1214 /*
1215   start a request to open a rpc connection to a rpc pipe, using
1216   specified binding structure to determine the endpoint and options
1217 */
1218 _PUBLIC_ struct composite_context* dcerpc_pipe_connect_b_send(TALLOC_CTX *parent_ctx,
1219                                                      const struct dcerpc_binding *binding,
1220                                                      const struct ndr_interface_table *table,
1221                                                      struct cli_credentials *credentials,
1222                                                      struct tevent_context *ev,
1223                                                      struct loadparm_context *lp_ctx)
1224 {
1225         struct composite_context *c;
1226         struct pipe_connect_state *s;
1227         enum dcerpc_transport_t transport;
1228         const char *endpoint = NULL;
1229         struct cli_credentials *epm_creds = NULL;
1230
1231         /* composite context allocation and setup */
1232         c = composite_create(parent_ctx, ev);
1233         if (c == NULL) {
1234                 return NULL;
1235         }
1236
1237         s = talloc_zero(c, struct pipe_connect_state);
1238         if (composite_nomem(s, c)) return c;
1239         c->private_data = s;
1240
1241         /* initialise dcerpc pipe structure */
1242         s->pipe = dcerpc_pipe_init(c, ev);
1243         if (composite_nomem(s->pipe, c)) return c;
1244
1245         if (DEBUGLEVEL >= 10)
1246                 s->pipe->conn->packet_log_dir = lpcfg_lock_directory(lp_ctx);
1247
1248         /* store parameters in state structure */
1249         s->binding      = dcerpc_binding_dup(s, binding);
1250         if (composite_nomem(s->binding, c)) return c;
1251         s->table        = table;
1252         s->credentials  = credentials;
1253         s->lp_ctx       = lp_ctx;
1254
1255         s->pipe->timed_out = false;
1256         s->pipe->inhibit_timeout_processing = false;
1257
1258         tevent_add_timer(c->event_ctx, c,
1259                          timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1260                          dcerpc_connect_timeout_handler, c);
1261
1262         transport = dcerpc_binding_get_transport(s->binding);
1263
1264         switch (transport) {
1265         case NCACN_NP:
1266         case NCACN_IP_TCP:
1267         case NCALRPC:
1268                 endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
1269
1270                 /* anonymous credentials for rpc connection used to get endpoint mapping */
1271                 epm_creds = cli_credentials_init_anon(s);
1272                 if (composite_nomem(epm_creds, c)) return c;
1273
1274                 break;
1275         case NCACN_HTTP:
1276                 endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
1277                 epm_creds = credentials;
1278                 break;
1279         default:
1280                 break;
1281         }
1282
1283         if (endpoint == NULL) {
1284                 struct composite_context *binding_req;
1285
1286                 binding_req = dcerpc_epm_map_binding_send(c, s->binding, s->table,
1287                                                           epm_creds,
1288                                                           s->pipe->conn->event_ctx,
1289                                                           s->lp_ctx);
1290                 composite_continue(c, binding_req, continue_map_binding, c);
1291                 return c;
1292         }
1293
1294         continue_connect(c, s);
1295         return c;
1296 }
1297
1298
1299 /*
1300   receive result of a request to open a rpc connection to a rpc pipe
1301 */
1302 _PUBLIC_ NTSTATUS dcerpc_pipe_connect_b_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
1303                                     struct dcerpc_pipe **p)
1304 {
1305         NTSTATUS status;
1306         struct pipe_connect_state *s;
1307         
1308         status = composite_wait(c);
1309         
1310         if (NT_STATUS_IS_OK(status)) {
1311                 s = talloc_get_type(c->private_data, struct pipe_connect_state);
1312                 talloc_steal(mem_ctx, s->pipe);
1313                 *p = s->pipe;
1314         }
1315         talloc_free(c);
1316         return status;
1317 }
1318
1319
1320 /*
1321   open a rpc connection to a rpc pipe, using the specified 
1322   binding structure to determine the endpoint and options - sync version
1323 */
1324 _PUBLIC_ NTSTATUS dcerpc_pipe_connect_b(TALLOC_CTX *parent_ctx,
1325                                struct dcerpc_pipe **pp,
1326                                const struct dcerpc_binding *binding,
1327                                const struct ndr_interface_table *table,
1328                                struct cli_credentials *credentials,
1329                                struct tevent_context *ev,
1330                                struct loadparm_context *lp_ctx)
1331 {
1332         struct composite_context *c;
1333         
1334         c = dcerpc_pipe_connect_b_send(parent_ctx, binding, table,
1335                                        credentials, ev, lp_ctx);
1336         return dcerpc_pipe_connect_b_recv(c, parent_ctx, pp);
1337 }
1338
1339
1340 struct pipe_conn_state {
1341         struct dcerpc_pipe *pipe;
1342 };
1343
1344
1345 static void continue_pipe_connect_b(struct composite_context *ctx);
1346
1347
1348 /*
1349   Initiate rpc connection to a rpc pipe, using the specified string
1350   binding to determine the endpoint and options.
1351   The string is to be parsed to a binding structure first.
1352 */
1353 _PUBLIC_ struct composite_context* dcerpc_pipe_connect_send(TALLOC_CTX *parent_ctx,
1354                                                    const char *binding,
1355                                                    const struct ndr_interface_table *table,
1356                                                    struct cli_credentials *credentials,
1357                                                    struct tevent_context *ev, struct loadparm_context *lp_ctx)
1358 {
1359         struct composite_context *c;
1360         struct pipe_conn_state *s;
1361         struct dcerpc_binding *b;
1362         struct composite_context *pipe_conn_req;
1363
1364         /* composite context allocation and setup */
1365         c = composite_create(parent_ctx, ev);
1366         if (c == NULL) {
1367                 return NULL;
1368         }
1369
1370         s = talloc_zero(c, struct pipe_conn_state);
1371         if (composite_nomem(s, c)) return c;
1372         c->private_data = s;
1373
1374         /* parse binding string to the structure */
1375         c->status = dcerpc_parse_binding(c, binding, &b);
1376         if (!NT_STATUS_IS_OK(c->status)) {
1377                 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", binding));
1378                 composite_error(c, c->status);
1379                 return c;
1380         }
1381
1382         DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(c, b)));
1383
1384         /* 
1385            start connecting to a rpc pipe after binding structure
1386            is established
1387          */
1388         pipe_conn_req = dcerpc_pipe_connect_b_send(c, b, table,
1389                                                    credentials, ev, lp_ctx);
1390         composite_continue(c, pipe_conn_req, continue_pipe_connect_b, c);
1391         return c;
1392 }
1393
1394
1395 /*
1396   Stage 2 of pipe_connect: Receive result of actual pipe connect request
1397   and say if we're done ok
1398 */
1399 static void continue_pipe_connect_b(struct composite_context *ctx)
1400 {
1401         struct composite_context *c = talloc_get_type(ctx->async.private_data,
1402                                                       struct composite_context);
1403         struct pipe_conn_state *s = talloc_get_type(c->private_data,
1404                                                     struct pipe_conn_state);
1405
1406         c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe);
1407         talloc_steal(s, s->pipe);
1408         if (!composite_is_ok(c)) return;
1409
1410         composite_done(c);
1411 }
1412
1413
1414 /*
1415   Receive result of pipe connect (using binding string) request
1416   and return connected pipe structure.
1417 */
1418 NTSTATUS dcerpc_pipe_connect_recv(struct composite_context *c,
1419                                   TALLOC_CTX *mem_ctx,
1420                                   struct dcerpc_pipe **pp)
1421 {
1422         NTSTATUS status;
1423         struct pipe_conn_state *s;
1424
1425         status = composite_wait(c);
1426         if (NT_STATUS_IS_OK(status)) {
1427                 s = talloc_get_type(c->private_data, struct pipe_conn_state);
1428                 *pp = talloc_steal(mem_ctx, s->pipe);
1429         }
1430         talloc_free(c);
1431         return status;
1432 }
1433
1434
1435 /*
1436   Open a rpc connection to a rpc pipe, using the specified string
1437   binding to determine the endpoint and options - sync version
1438 */
1439 _PUBLIC_ NTSTATUS dcerpc_pipe_connect(TALLOC_CTX *parent_ctx, 
1440                              struct dcerpc_pipe **pp, 
1441                              const char *binding,
1442                              const struct ndr_interface_table *table,
1443                              struct cli_credentials *credentials,
1444                              struct tevent_context *ev,
1445                              struct loadparm_context *lp_ctx)
1446 {
1447         struct composite_context *c;
1448         c = dcerpc_pipe_connect_send(parent_ctx, binding, 
1449                                      table, credentials, ev, lp_ctx);
1450         return dcerpc_pipe_connect_recv(c, parent_ctx, pp);
1451 }
1452