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