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