s4:librpc/rpc: remember the target_hostname on ncacn_http connections
[npower/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
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 *target_hostname;
426         const char *rpc_server;
427         uint32_t rpc_server_port;
428         char *rpc_proxy;
429         uint32_t rpc_proxy_port;
430         char *http_proxy;
431         uint32_t http_proxy_port;
432         bool use_tls;
433         bool use_proxy;
434         bool use_ntlm;
435         struct loadparm_context *lp_ctx;
436 };
437
438 /*
439   Stage 2 of ncacn_http: rpc pipe opened (or not)
440  */
441 static void continue_pipe_open_ncacn_http(struct tevent_req *subreq)
442 {
443         struct composite_context *c = NULL;
444         struct pipe_http_state *s = NULL;
445         struct tstream_context *stream = NULL;
446         struct tevent_queue *queue = NULL;
447
448         c = tevent_req_callback_data(subreq, struct composite_context);
449         s = talloc_get_type(c->private_data, struct pipe_http_state);
450
451         /* receive result of RoH connect request */
452         c->status = dcerpc_pipe_open_roh_recv(subreq, s->io.conn,
453                                               &stream, &queue);
454         TALLOC_FREE(subreq);
455         if (!composite_is_ok(c)) return;
456
457         s->io.conn->transport.transport = NCACN_HTTP;
458         s->io.conn->transport.stream = stream;
459         s->io.conn->transport.write_queue = queue;
460         s->io.conn->transport.pending_reads = 0;
461         s->io.conn->server_name = strupper_talloc(s->io.conn,
462                                                   s->target_hostname);
463
464         composite_done(c);
465 }
466
467 /*
468   Initiate async open of a rpc connection to a rpc pipe using HTTP transport,
469   and using the binding structure to determine the endpoint and options
470 */
471 static struct composite_context* dcerpc_pipe_connect_ncacn_http_send(
472                 TALLOC_CTX *mem_ctx, struct dcerpc_pipe_connect *io,
473                 struct loadparm_context *lp_ctx)
474 {
475         struct composite_context *c;
476         struct pipe_http_state *s;
477         struct tevent_req *subreq;
478         const char *endpoint;
479         const char *use_proxy;
480         char *proxy;
481         char *port;
482         const char *opt;
483
484         /* composite context allocation and setup */
485         c = composite_create(mem_ctx, io->conn->event_ctx);
486         if (c == NULL) return NULL;
487
488         s = talloc_zero(c, struct pipe_http_state);
489         if (composite_nomem(s, c)) return c;
490         c->private_data = s;
491
492         /* store input parameters in state structure */
493         s->lp_ctx       = lp_ctx;
494         s->io           = *io;
495         s->localaddr    = dcerpc_binding_get_string_option(io->binding,
496                                                         "localaddress");
497         /* RPC server and port (the endpoint) */
498         s->rpc_server = dcerpc_binding_get_string_option(io->binding, "host");
499         s->target_hostname = dcerpc_binding_get_string_option(io->binding,
500                                                               "target_hostname");
501         endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
502         if (endpoint == NULL) {
503                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
504                 return c;
505         }
506         s->rpc_server_port = atoi(endpoint);
507         if (s->rpc_server_port == 0) {
508                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
509                 return c;
510         }
511
512         /* Use TLS */
513         opt = dcerpc_binding_get_string_option(io->binding, "HttpUseTls");
514         if (opt) {
515                 if (strcasecmp(opt, "true") == 0) {
516                         s->use_tls = true;
517                 } else if (strcasecmp(opt, "false") == 0) {
518                         s->use_tls = false;
519                 } else {
520                         composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
521                         return c;
522                 }
523         } else {
524                 s->use_tls = true;
525         }
526
527         /* RPC Proxy */
528         proxy = port = talloc_strdup(s, dcerpc_binding_get_string_option(
529                         io->binding, "RpcProxy"));
530         s->rpc_proxy  = strsep(&port, ":");
531         if (proxy && port) {
532                 s->rpc_proxy_port = atoi(port);
533         } else {
534                 s->rpc_proxy_port = s->use_tls ? 443 : 80;
535         }
536         if (s->rpc_proxy == NULL) {
537                 s->rpc_proxy = talloc_strdup(s, s->rpc_server);
538                 if (composite_nomem(s->rpc_proxy, c)) return c;
539         }
540
541         /* HTTP Proxy */
542         proxy = port = talloc_strdup(s, dcerpc_binding_get_string_option(
543                         io->binding, "HttpProxy"));
544         s->http_proxy = strsep(&port, ":");
545         if (proxy && port) {
546                 s->http_proxy_port = atoi(port);
547         } else {
548                 s->http_proxy_port = s->use_tls ? 443 : 80;
549         }
550
551         /* Use local proxy */
552         use_proxy = dcerpc_binding_get_string_option(io->binding,
553                                                  "HttpConnectOption");
554         if (use_proxy && strcasecmp(use_proxy, "UseHttpProxy")) {
555                 s->use_proxy = true;
556         }
557
558         /* If use local proxy set, the http proxy should be provided */
559         if (s->use_proxy && !s->http_proxy) {
560                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
561                 return c;
562         }
563
564         /* Check which HTTP authentication method to use */
565         opt = dcerpc_binding_get_string_option(io->binding, "HttpAuthOption");
566         if (opt) {
567                 if (strcasecmp(opt, "basic") == 0) {
568                         s->use_ntlm = false;
569                 } else if (strcasecmp(opt, "ntlm") == 0) {
570                         s->use_ntlm = true;
571                 } else {
572                         composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
573                         return c;
574                 }
575         } else {
576                 s->use_ntlm = true;
577         }
578
579         subreq = dcerpc_pipe_open_roh_send(s->io.conn, s->localaddr,
580                                            s->rpc_server, s->rpc_server_port,
581                                            s->rpc_proxy, s->rpc_proxy_port,
582                                            s->http_proxy, s->http_proxy_port,
583                                            s->use_tls, s->use_proxy,
584                                            s->io.creds, io->resolve_ctx,
585                                            s->lp_ctx, s->use_ntlm);
586         if (composite_nomem(subreq, c)) return c;
587
588         tevent_req_set_callback(subreq, continue_pipe_open_ncacn_http, c);
589         return c;
590 }
591
592 static NTSTATUS dcerpc_pipe_connect_ncacn_http_recv(struct composite_context *c)
593 {
594         return composite_wait_free(c);
595 }
596
597
598 struct pipe_unix_state {
599         struct dcerpc_pipe_connect io;
600         const char *path;
601 };
602
603
604 /*
605   Stage 2 of ncacn_unix: rpc pipe opened (or not)
606 */
607 static void continue_pipe_open_ncacn_unix_stream(struct composite_context *ctx)
608 {
609         struct composite_context *c = talloc_get_type(ctx->async.private_data,
610                                                       struct composite_context);
611
612         /* receive result of pipe open request on unix socket */
613         c->status = dcerpc_pipe_open_unix_stream_recv(ctx);
614         if (!composite_is_ok(c)) return;
615
616         composite_done(c);
617 }
618
619
620 /*
621   Initiate async open of a rpc connection to a rpc pipe on unix socket using
622   the binding structure to determine the endpoint and options
623 */
624 static struct composite_context* dcerpc_pipe_connect_ncacn_unix_stream_send(TALLOC_CTX *mem_ctx,
625                                                                             struct dcerpc_pipe_connect *io)
626 {
627         struct composite_context *c;
628         struct pipe_unix_state *s;
629         struct composite_context *pipe_req;
630
631         /* composite context allocation and setup */
632         c = composite_create(mem_ctx, io->conn->event_ctx);
633         if (c == NULL) return NULL;
634
635         s = talloc_zero(c, struct pipe_unix_state);
636         if (composite_nomem(s, c)) return c;
637         c->private_data = s;
638
639         /* prepare pipe open parameters and store them in state structure
640            also, verify whether biding endpoint is not null */
641         s->io = *io;
642
643         s->path = dcerpc_binding_get_string_option(io->binding, "endpoint");
644         if (s->path == NULL) {
645                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
646                 return c;
647         }
648
649         /* send pipe open request on unix socket */
650         pipe_req = dcerpc_pipe_open_unix_stream_send(s->io.conn, s->path);
651         composite_continue(c, pipe_req, continue_pipe_open_ncacn_unix_stream, c);
652         return c;
653 }
654
655
656 /*
657   Receive result of a rpc connection to a pipe on unix socket
658 */
659 static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream_recv(struct composite_context *c)
660 {
661         NTSTATUS status = composite_wait(c);
662
663         talloc_free(c);
664         return status;
665 }
666
667
668 struct pipe_ncalrpc_state {
669         struct dcerpc_pipe_connect io;
670 };
671
672 static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c);
673
674 /*
675   Stage 2 of ncalrpc: rpc pipe opened (or not)
676 */
677 static void continue_pipe_open_ncalrpc(struct composite_context *ctx)
678 {
679         struct composite_context *c = talloc_get_type(ctx->async.private_data,
680                                                       struct composite_context);
681
682         /* receive result of pipe open request on ncalrpc */
683         c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
684         if (!composite_is_ok(c)) return;
685
686         composite_done(c);
687 }
688
689
690 /* 
691    Initiate async open of a rpc connection request on NCALRPC using
692    the binding structure to determine the endpoint and options
693 */
694 static struct composite_context* dcerpc_pipe_connect_ncalrpc_send(TALLOC_CTX *mem_ctx,
695                                                                   struct dcerpc_pipe_connect *io)
696 {
697         struct composite_context *c;
698         struct pipe_ncalrpc_state *s;
699         struct composite_context *pipe_req;
700         const char *endpoint;
701
702         /* composite context allocation and setup */
703         c = composite_create(mem_ctx, io->conn->event_ctx);
704         if (c == NULL) return NULL;
705
706         s = talloc_zero(c, struct pipe_ncalrpc_state);
707         if (composite_nomem(s, c)) return c;
708         c->private_data = s;
709         
710         /* store input parameters in state structure */
711         s->io  = *io;
712
713         endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
714         if (endpoint == NULL) {
715                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
716                 return c;
717         }
718
719         /* send pipe open request */
720         pipe_req = dcerpc_pipe_open_pipe_send(s->io.conn,
721                                               s->io.ncalrpc.dir,
722                                               endpoint);
723         composite_continue(c, pipe_req, continue_pipe_open_ncalrpc, c);
724         return c;
725 }
726
727
728 /*
729   Receive result of a rpc connection to a rpc pipe on NCALRPC
730 */
731 static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c)
732 {
733         NTSTATUS status = composite_wait(c);
734         
735         talloc_free(c);
736         return status;
737 }
738
739
740 struct pipe_connect_state {
741         struct dcerpc_pipe *pipe;
742         struct dcerpc_binding *binding;
743         const struct ndr_interface_table *table;
744         struct cli_credentials *credentials;
745         struct loadparm_context *lp_ctx;
746 };
747
748
749 static void continue_map_binding(struct composite_context *ctx);
750 static void continue_connect(struct composite_context *c, struct pipe_connect_state *s);
751 static void continue_pipe_connect_ncacn_np_smb2(struct composite_context *ctx);
752 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx);
753 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx);
754 static void continue_pipe_connect_ncacn_http(struct composite_context *ctx);
755 static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx);
756 static void continue_pipe_connect_ncalrpc(struct composite_context *ctx);
757 static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s);
758 static void continue_pipe_auth(struct composite_context *ctx);
759
760
761 /*
762   Stage 2 of pipe_connect_b: Receive result of endpoint mapping
763 */
764 static void continue_map_binding(struct composite_context *ctx)
765 {
766         struct composite_context *c = talloc_get_type(ctx->async.private_data,
767                                                       struct composite_context);
768         struct pipe_connect_state *s = talloc_get_type(c->private_data,
769                                                        struct pipe_connect_state);
770         const char *endpoint;
771
772         c->status = dcerpc_epm_map_binding_recv(ctx);
773         if (!composite_is_ok(c)) return;
774
775         endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
776         DEBUG(4,("Mapped to DCERPC endpoint %s\n", endpoint));
777
778         continue_connect(c, s);
779 }
780
781
782 /*
783   Stage 2 of pipe_connect_b: Continue connection after endpoint is known
784 */
785 static void continue_connect(struct composite_context *c, struct pipe_connect_state *s)
786 {
787         struct dcerpc_pipe_connect pc;
788
789         /* potential exits to another stage by sending an async request */
790         struct composite_context *ncacn_np_smb2_req;
791         struct composite_context *ncacn_np_smb_req;
792         struct composite_context *ncacn_ip_tcp_req;
793         struct composite_context *ncacn_http_req;
794         struct composite_context *ncacn_unix_req;
795         struct composite_context *ncalrpc_req;
796         enum dcerpc_transport_t transport;
797         enum protocol_types min_ipc_protocol;
798         uint32_t flags;
799
800         /* dcerpc pipe connect input parameters */
801         ZERO_STRUCT(pc);
802         pc.conn         = s->pipe->conn;
803         pc.binding      = s->binding;
804         pc.interface    = s->table;
805         pc.creds        = s->credentials;
806         pc.resolve_ctx  = lpcfg_resolve_context(s->lp_ctx);
807
808         transport = dcerpc_binding_get_transport(s->binding);
809         flags = dcerpc_binding_get_flags(s->binding);
810
811         min_ipc_protocol = lpcfg_client_ipc_min_protocol(s->lp_ctx);
812         if (min_ipc_protocol >= PROTOCOL_SMB2_02) {
813                 flags |= DCERPC_SMB2;
814         }
815
816         /* connect dcerpc pipe depending on required transport */
817         switch (transport) {
818         case NCACN_NP:
819                 if (flags & DCERPC_SMB2) {
820                         /* new varient of SMB a.k.a. SMB2 */
821                         ncacn_np_smb2_req = dcerpc_pipe_connect_ncacn_np_smb2_send(c, &pc, s->lp_ctx);
822                         composite_continue(c, ncacn_np_smb2_req, continue_pipe_connect_ncacn_np_smb2, c);
823                         return;
824
825                 } else {
826                         /* good old ordinary SMB */
827                         ncacn_np_smb_req = dcerpc_pipe_connect_ncacn_np_smb_send(c, &pc, s->lp_ctx);
828                         composite_continue(c, ncacn_np_smb_req, continue_pipe_connect_ncacn_np_smb, c);
829                         return;
830                 }
831                 break;
832
833         case NCACN_IP_TCP:
834                 ncacn_ip_tcp_req = dcerpc_pipe_connect_ncacn_ip_tcp_send(c, &pc);
835                 composite_continue(c, ncacn_ip_tcp_req, continue_pipe_connect_ncacn_ip_tcp, c);
836                 return;
837
838         case NCACN_HTTP:
839                 ncacn_http_req = dcerpc_pipe_connect_ncacn_http_send(c, &pc, s->lp_ctx);
840                 composite_continue(c, ncacn_http_req, continue_pipe_connect_ncacn_http, c);
841                 return;
842
843         case NCACN_UNIX_STREAM:
844                 ncacn_unix_req = dcerpc_pipe_connect_ncacn_unix_stream_send(c, &pc);
845                 composite_continue(c, ncacn_unix_req, continue_pipe_connect_ncacn_unix, c);
846                 return;
847
848         case NCALRPC:
849                 pc.ncalrpc.dir = lpcfg_ncalrpc_dir(s->lp_ctx);
850                 c->status = dcerpc_binding_set_string_option(s->binding, "ncalrpc_dir",
851                                                              pc.ncalrpc.dir);
852                 if (!composite_is_ok(c)) return;
853                 ncalrpc_req = dcerpc_pipe_connect_ncalrpc_send(c, &pc);
854                 composite_continue(c, ncalrpc_req, continue_pipe_connect_ncalrpc, c);
855                 return;
856
857         default:
858                 /* looks like a transport we don't support now */
859                 composite_error(c, NT_STATUS_NOT_SUPPORTED);
860         }
861 }
862
863
864 /*
865   Stage 3 of pipe_connect_b: Receive result of pipe connect request on
866   named pipe on smb2
867 */
868 static void continue_pipe_connect_ncacn_np_smb2(struct composite_context *ctx)
869 {
870         struct composite_context *c = talloc_get_type(ctx->async.private_data,
871                                                       struct composite_context);
872         struct pipe_connect_state *s = talloc_get_type(c->private_data,
873                                                        struct pipe_connect_state);
874
875         c->status = dcerpc_pipe_connect_ncacn_np_smb2_recv(ctx);
876         if (!composite_is_ok(c)) return;
877
878         continue_pipe_connect(c, s);
879 }
880
881
882 /*
883   Stage 3 of pipe_connect_b: Receive result of pipe connect request on
884   named pipe on smb
885 */
886 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx)
887 {
888         struct composite_context *c = talloc_get_type(ctx->async.private_data,
889                                                       struct composite_context);
890         struct pipe_connect_state *s = talloc_get_type(c->private_data,
891                                                        struct pipe_connect_state);
892
893         c->status = dcerpc_pipe_connect_ncacn_np_smb_recv(ctx);
894         if (!composite_is_ok(c)) return;
895         
896         continue_pipe_connect(c, s);
897 }
898
899
900 /*
901   Stage 3 of pipe_connect_b: Receive result of pipe connect request on tcp/ip
902 */
903 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx)
904 {
905         struct composite_context *c = talloc_get_type(ctx->async.private_data,
906                                                       struct composite_context);
907         struct pipe_connect_state *s = talloc_get_type(c->private_data,
908                                                        struct pipe_connect_state);
909
910         c->status = dcerpc_pipe_connect_ncacn_ip_tcp_recv(ctx);
911         if (!composite_is_ok(c)) return;
912
913         continue_pipe_connect(c, s);
914 }
915
916
917 /*
918   Stage 3 of pipe_connect_b: Receive result of pipe connect request on http
919 */
920 static void continue_pipe_connect_ncacn_http(struct composite_context *ctx)
921 {
922         struct composite_context *c = talloc_get_type(ctx->async.private_data,
923                                                       struct composite_context);
924         struct pipe_connect_state *s = talloc_get_type(c->private_data,
925                                                        struct pipe_connect_state);
926
927         c->status = dcerpc_pipe_connect_ncacn_http_recv(ctx);
928         if (!composite_is_ok(c)) return;
929
930         continue_pipe_connect(c, s);
931 }
932
933
934 /*
935   Stage 3 of pipe_connect_b: Receive result of pipe connect request on unix socket
936 */
937 static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx)
938 {
939         struct composite_context *c = talloc_get_type(ctx->async.private_data,
940                                                       struct composite_context);
941         struct pipe_connect_state *s = talloc_get_type(c->private_data,
942                                                        struct pipe_connect_state);
943         
944         c->status = dcerpc_pipe_connect_ncacn_unix_stream_recv(ctx);
945         if (!composite_is_ok(c)) return;
946         
947         continue_pipe_connect(c, s);
948 }
949
950
951 /*
952   Stage 3 of pipe_connect_b: Receive result of pipe connect request on local rpc
953 */
954 static void continue_pipe_connect_ncalrpc(struct composite_context *ctx)
955 {
956         struct composite_context *c = talloc_get_type(ctx->async.private_data,
957                                                       struct composite_context);
958         struct pipe_connect_state *s = talloc_get_type(c->private_data,
959                                                        struct pipe_connect_state);
960         
961         c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
962         if (!composite_is_ok(c)) return;
963
964         continue_pipe_connect(c, s);
965 }
966
967
968 /*
969   Stage 4 of pipe_connect_b: Start an authentication on connected dcerpc pipe
970   depending on credentials and binding flags passed.
971 */
972 static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s)
973 {
974         struct composite_context *auth_bind_req;
975
976         s->pipe->binding = dcerpc_binding_dup(s->pipe, s->binding);
977         if (composite_nomem(s->pipe->binding, c)) {
978                 return;
979         }
980
981         auth_bind_req = dcerpc_pipe_auth_send(s->pipe, s->binding, s->table,
982                                               s->credentials, s->lp_ctx);
983         composite_continue(c, auth_bind_req, continue_pipe_auth, c);
984 }
985
986
987 /*
988   Stage 5 of pipe_connect_b: Receive result of pipe authentication request
989   and say if all went ok
990 */
991 static void continue_pipe_auth(struct composite_context *ctx)
992 {
993         struct composite_context *c = talloc_get_type(ctx->async.private_data,
994                                                       struct composite_context);
995         struct pipe_connect_state *s = talloc_get_type(c->private_data, struct pipe_connect_state);
996
997         c->status = dcerpc_pipe_auth_recv(ctx, s, &s->pipe);
998         if (!composite_is_ok(c)) return;
999
1000         composite_done(c);
1001 }
1002
1003
1004 /*
1005   handle timeouts of a dcerpc connect
1006 */
1007 static void dcerpc_connect_timeout_handler(struct tevent_context *ev, struct tevent_timer *te, 
1008                                            struct timeval t, void *private_data)
1009 {
1010         struct composite_context *c = talloc_get_type_abort(private_data,
1011                                                       struct composite_context);
1012         struct pipe_connect_state *s = talloc_get_type_abort(c->private_data, struct pipe_connect_state);
1013         if (!s->pipe->inhibit_timeout_processing) {
1014                 composite_error(c, NT_STATUS_IO_TIMEOUT);
1015         } else {
1016                 s->pipe->timed_out = true;
1017         }
1018 }
1019
1020 /*
1021   start a request to open a rpc connection to a rpc pipe, using
1022   specified binding structure to determine the endpoint and options
1023 */
1024 _PUBLIC_ struct composite_context* dcerpc_pipe_connect_b_send(TALLOC_CTX *parent_ctx,
1025                                                      const struct dcerpc_binding *binding,
1026                                                      const struct ndr_interface_table *table,
1027                                                      struct cli_credentials *credentials,
1028                                                      struct tevent_context *ev,
1029                                                      struct loadparm_context *lp_ctx)
1030 {
1031         struct composite_context *c;
1032         struct pipe_connect_state *s;
1033         enum dcerpc_transport_t transport;
1034         const char *endpoint = NULL;
1035         struct cli_credentials *epm_creds = NULL;
1036
1037         /* composite context allocation and setup */
1038         c = composite_create(parent_ctx, ev);
1039         if (c == NULL) {
1040                 return NULL;
1041         }
1042
1043         s = talloc_zero(c, struct pipe_connect_state);
1044         if (composite_nomem(s, c)) return c;
1045         c->private_data = s;
1046
1047         /* initialise dcerpc pipe structure */
1048         s->pipe = dcerpc_pipe_init(c, ev);
1049         if (composite_nomem(s->pipe, c)) return c;
1050
1051         if (DEBUGLEVEL >= 10)
1052                 s->pipe->conn->packet_log_dir = lpcfg_lock_directory(lp_ctx);
1053
1054         /* store parameters in state structure */
1055         s->binding      = dcerpc_binding_dup(s, binding);
1056         if (composite_nomem(s->binding, c)) return c;
1057         s->table        = table;
1058         s->credentials  = credentials;
1059         s->lp_ctx       = lp_ctx;
1060
1061         s->pipe->timed_out = false;
1062         s->pipe->inhibit_timeout_processing = false;
1063
1064         tevent_add_timer(c->event_ctx, c,
1065                          timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1066                          dcerpc_connect_timeout_handler, c);
1067
1068         transport = dcerpc_binding_get_transport(s->binding);
1069
1070         switch (transport) {
1071         case NCACN_NP:
1072         case NCACN_IP_TCP:
1073         case NCALRPC:
1074                 endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
1075
1076                 /* anonymous credentials for rpc connection used to get endpoint mapping */
1077                 epm_creds = cli_credentials_init_anon(s);
1078                 if (composite_nomem(epm_creds, c)) return c;
1079
1080                 break;
1081         case NCACN_HTTP:
1082                 endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
1083                 epm_creds = credentials;
1084                 break;
1085         default:
1086                 break;
1087         }
1088
1089         if (endpoint == NULL) {
1090                 struct composite_context *binding_req;
1091
1092                 binding_req = dcerpc_epm_map_binding_send(c, s->binding, s->table,
1093                                                           epm_creds,
1094                                                           s->pipe->conn->event_ctx,
1095                                                           s->lp_ctx);
1096                 composite_continue(c, binding_req, continue_map_binding, c);
1097                 return c;
1098         }
1099
1100         continue_connect(c, s);
1101         return c;
1102 }
1103
1104
1105 /*
1106   receive result of a request to open a rpc connection to a rpc pipe
1107 */
1108 _PUBLIC_ NTSTATUS dcerpc_pipe_connect_b_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
1109                                     struct dcerpc_pipe **p)
1110 {
1111         NTSTATUS status;
1112         struct pipe_connect_state *s;
1113         
1114         status = composite_wait(c);
1115         
1116         if (NT_STATUS_IS_OK(status)) {
1117                 s = talloc_get_type(c->private_data, struct pipe_connect_state);
1118                 talloc_steal(mem_ctx, s->pipe);
1119                 *p = s->pipe;
1120         }
1121         talloc_free(c);
1122         return status;
1123 }
1124
1125
1126 /*
1127   open a rpc connection to a rpc pipe, using the specified 
1128   binding structure to determine the endpoint and options - sync version
1129 */
1130 _PUBLIC_ NTSTATUS dcerpc_pipe_connect_b(TALLOC_CTX *parent_ctx,
1131                                struct dcerpc_pipe **pp,
1132                                const struct dcerpc_binding *binding,
1133                                const struct ndr_interface_table *table,
1134                                struct cli_credentials *credentials,
1135                                struct tevent_context *ev,
1136                                struct loadparm_context *lp_ctx)
1137 {
1138         struct composite_context *c;
1139         
1140         c = dcerpc_pipe_connect_b_send(parent_ctx, binding, table,
1141                                        credentials, ev, lp_ctx);
1142         return dcerpc_pipe_connect_b_recv(c, parent_ctx, pp);
1143 }
1144
1145
1146 struct pipe_conn_state {
1147         struct dcerpc_pipe *pipe;
1148 };
1149
1150
1151 static void continue_pipe_connect_b(struct composite_context *ctx);
1152
1153
1154 /*
1155   Initiate rpc connection to a rpc pipe, using the specified string
1156   binding to determine the endpoint and options.
1157   The string is to be parsed to a binding structure first.
1158 */
1159 _PUBLIC_ struct composite_context* dcerpc_pipe_connect_send(TALLOC_CTX *parent_ctx,
1160                                                    const char *binding,
1161                                                    const struct ndr_interface_table *table,
1162                                                    struct cli_credentials *credentials,
1163                                                    struct tevent_context *ev, struct loadparm_context *lp_ctx)
1164 {
1165         struct composite_context *c;
1166         struct pipe_conn_state *s;
1167         struct dcerpc_binding *b;
1168         struct composite_context *pipe_conn_req;
1169
1170         /* composite context allocation and setup */
1171         c = composite_create(parent_ctx, ev);
1172         if (c == NULL) {
1173                 return NULL;
1174         }
1175
1176         s = talloc_zero(c, struct pipe_conn_state);
1177         if (composite_nomem(s, c)) return c;
1178         c->private_data = s;
1179
1180         /* parse binding string to the structure */
1181         c->status = dcerpc_parse_binding(c, binding, &b);
1182         if (!NT_STATUS_IS_OK(c->status)) {
1183                 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", binding));
1184                 composite_error(c, c->status);
1185                 return c;
1186         }
1187
1188         DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(c, b)));
1189
1190         /* 
1191            start connecting to a rpc pipe after binding structure
1192            is established
1193          */
1194         pipe_conn_req = dcerpc_pipe_connect_b_send(c, b, table,
1195                                                    credentials, ev, lp_ctx);
1196         composite_continue(c, pipe_conn_req, continue_pipe_connect_b, c);
1197         return c;
1198 }
1199
1200
1201 /*
1202   Stage 2 of pipe_connect: Receive result of actual pipe connect request
1203   and say if we're done ok
1204 */
1205 static void continue_pipe_connect_b(struct composite_context *ctx)
1206 {
1207         struct composite_context *c = talloc_get_type(ctx->async.private_data,
1208                                                       struct composite_context);
1209         struct pipe_conn_state *s = talloc_get_type(c->private_data,
1210                                                     struct pipe_conn_state);
1211
1212         c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe);
1213         talloc_steal(s, s->pipe);
1214         if (!composite_is_ok(c)) return;
1215
1216         composite_done(c);
1217 }
1218
1219
1220 /*
1221   Receive result of pipe connect (using binding string) request
1222   and return connected pipe structure.
1223 */
1224 NTSTATUS dcerpc_pipe_connect_recv(struct composite_context *c,
1225                                   TALLOC_CTX *mem_ctx,
1226                                   struct dcerpc_pipe **pp)
1227 {
1228         NTSTATUS status;
1229         struct pipe_conn_state *s;
1230
1231         status = composite_wait(c);
1232         if (NT_STATUS_IS_OK(status)) {
1233                 s = talloc_get_type(c->private_data, struct pipe_conn_state);
1234                 *pp = talloc_steal(mem_ctx, s->pipe);
1235         }
1236         talloc_free(c);
1237         return status;
1238 }
1239
1240
1241 /*
1242   Open a rpc connection to a rpc pipe, using the specified string
1243   binding to determine the endpoint and options - sync version
1244 */
1245 _PUBLIC_ NTSTATUS dcerpc_pipe_connect(TALLOC_CTX *parent_ctx, 
1246                              struct dcerpc_pipe **pp, 
1247                              const char *binding,
1248                              const struct ndr_interface_table *table,
1249                              struct cli_credentials *credentials,
1250                              struct tevent_context *ev,
1251                              struct loadparm_context *lp_ctx)
1252 {
1253         struct composite_context *c;
1254         c = dcerpc_pipe_connect_send(parent_ctx, binding, 
1255                                      table, credentials, ev, lp_ctx);
1256         return dcerpc_pipe_connect_recv(c, parent_ctx, pp);
1257 }
1258