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