s4-rpc_server: Do not use LM hash in password changes
[Samba.git] / source4 / librpc / rpc / dcerpc_connect.c
blob9a7b9aeb8d1eea41259a351756306c945e7139cc
1 /*
2 Unix SMB/CIFS implementation.
4 dcerpc connect functions
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
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.
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.
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/>.
26 #include "includes.h"
27 #include "libcli/composite/composite.h"
28 #include "libcli/smb_composite/smb_composite.h"
29 #include "lib/events/events.h"
30 #include "libcli/smb2/smb2.h"
31 #include "libcli/smb2/smb2_calls.h"
32 #include "libcli/smb/smbXcli_base.h"
33 #include "librpc/rpc/dcerpc.h"
34 #include "librpc/rpc/dcerpc_proto.h"
35 #include "auth/credentials/credentials.h"
36 #include "param/param.h"
37 #include "libcli/resolve/resolve.h"
38 #include "libcli/http/http.h"
39 #include "lib/util/util_net.h"
41 #undef strcasecmp
43 struct dcerpc_pipe_connect {
44 struct dcecli_connection *conn;
45 struct dcerpc_binding *binding;
46 const struct ndr_interface_table *interface;
47 struct cli_credentials *creds;
48 struct resolve_context *resolve_ctx;
49 struct {
50 const char *dir;
51 } ncalrpc;
52 struct {
53 struct smbXcli_conn *conn;
54 struct smbXcli_session *session;
55 struct smbXcli_tcon *tcon;
56 const char *pipe_name;
57 } smb;
60 struct pipe_np_smb_state {
61 struct smb_composite_connect conn;
62 struct dcerpc_pipe_connect io;
67 Stage 3 of ncacn_np_smb: Named pipe opened (or not)
69 static void continue_pipe_open_smb(struct composite_context *ctx)
71 struct composite_context *c = talloc_get_type(ctx->async.private_data,
72 struct composite_context);
74 /* receive result of named pipe open request on smb */
75 c->status = dcerpc_pipe_open_smb_recv(ctx);
76 if (!composite_is_ok(c)) return;
78 composite_done(c);
81 static void continue_smb_open(struct composite_context *c);
82 static void continue_smb2_connect(struct tevent_req *subreq);
83 static void continue_smbXcli_connect(struct tevent_req *subreq);
86 Stage 2 of ncacn_np_smb: Open a named pipe after successful smb connection
88 static void continue_smb_connect(struct composite_context *ctx)
90 struct composite_context *c = talloc_get_type(ctx->async.private_data,
91 struct composite_context);
92 struct pipe_np_smb_state *s = talloc_get_type(c->private_data,
93 struct pipe_np_smb_state);
94 struct smbcli_tree *t;
96 /* receive result of smb connect request */
97 c->status = smb_composite_connect_recv(ctx, s->io.conn);
98 if (!composite_is_ok(c)) return;
100 t = s->conn.out.tree;
102 /* prepare named pipe open parameters */
103 s->io.smb.conn = t->session->transport->conn;
104 s->io.smb.session = t->session->smbXcli;
105 s->io.smb.tcon = t->smbXcli;
106 smb1cli_tcon_set_id(s->io.smb.tcon, t->tid);
107 s->io.smb.pipe_name = dcerpc_binding_get_string_option(s->io.binding,
108 "endpoint");
110 continue_smb_open(c);
113 static void continue_smb_open(struct composite_context *c)
115 struct pipe_np_smb_state *s = talloc_get_type(c->private_data,
116 struct pipe_np_smb_state);
117 struct composite_context *open_ctx;
119 /* send named pipe open request */
120 open_ctx = dcerpc_pipe_open_smb_send(s->io.conn,
121 s->io.smb.conn,
122 s->io.smb.session,
123 s->io.smb.tcon,
124 DCERPC_REQUEST_TIMEOUT * 1000,
125 s->io.smb.pipe_name);
126 if (composite_nomem(open_ctx, c)) return;
128 composite_continue(c, open_ctx, continue_pipe_open_smb, c);
133 Initiate async open of a rpc connection to a rpc pipe on SMB using
134 the binding structure to determine the endpoint and options
136 static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CTX *mem_ctx, struct dcerpc_pipe_connect *io, struct loadparm_context *lp_ctx)
138 struct composite_context *c;
139 struct pipe_np_smb_state *s;
140 struct tevent_req *subreq = NULL;
141 struct smb_composite_connect *conn;
142 uint32_t flags;
143 const char *target_hostname = NULL;
144 const char *dest_address = NULL;
145 const char *calling_name = NULL;
147 /* composite context allocation and setup */
148 c = composite_create(mem_ctx, io->conn->event_ctx);
149 if (c == NULL) return NULL;
151 s = talloc_zero(c, struct pipe_np_smb_state);
152 if (composite_nomem(s, c)) return c;
153 c->private_data = s;
155 s->io = *io;
156 conn = &s->conn;
158 if (smbXcli_conn_is_connected(s->io.smb.conn)) {
159 continue_smb_open(c);
160 return c;
163 if (s->io.creds == NULL) {
164 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
165 return c;
168 /* prepare smb connection parameters: we're connecting to IPC$ share on
169 remote rpc server */
170 target_hostname = dcerpc_binding_get_string_option(s->io.binding, "target_hostname");
171 conn->in.dest_host = dcerpc_binding_get_string_option(s->io.binding, "host");
172 conn->in.dest_ports = lpcfg_smb_ports(lp_ctx);
173 conn->in.called_name = target_hostname;
174 if (conn->in.called_name == NULL) {
175 conn->in.called_name = "*SMBSERVER";
177 conn->in.socket_options = lpcfg_socket_options(lp_ctx);
178 conn->in.service = "IPC$";
179 conn->in.service_type = NULL;
180 conn->in.workgroup = lpcfg_workgroup(lp_ctx);
181 conn->in.gensec_settings = lpcfg_gensec_settings(conn, lp_ctx);
183 lpcfg_smbcli_options(lp_ctx, &conn->in.options);
184 lpcfg_smbcli_session_options(lp_ctx, &conn->in.session_options);
187 * provide proper credentials - user supplied, but allow a
188 * fallback to anonymous if this is an schannel connection
189 * (might be NT4 not allowing machine logins at session
190 * setup) or if asked to do so by the caller (perhaps a SAMR password change?)
192 s->conn.in.credentials = s->io.creds;
193 flags = dcerpc_binding_get_flags(s->io.binding);
194 if (flags & (DCERPC_SCHANNEL|DCERPC_ANON_FALLBACK)) {
195 conn->in.fallback_to_anonymous = true;
196 } else {
197 conn->in.fallback_to_anonymous = false;
200 conn->in.options.min_protocol = lpcfg_client_ipc_min_protocol(lp_ctx);
201 conn->in.options.max_protocol = lpcfg_client_ipc_max_protocol(lp_ctx);
202 if ((flags & DCERPC_SMB1) && (flags & DCERPC_SMB2)) {
203 /* auto */
204 } else if (flags & DCERPC_SMB2) {
205 if (conn->in.options.min_protocol < PROTOCOL_SMB2_02) {
206 conn->in.options.min_protocol = PROTOCOL_SMB2_02;
208 if (conn->in.options.max_protocol < PROTOCOL_SMB2_02) {
209 conn->in.options.max_protocol = PROTOCOL_LATEST;
211 } else if (flags & DCERPC_SMB1) {
212 conn->in.options.min_protocol = PROTOCOL_NT1;
213 conn->in.options.max_protocol = PROTOCOL_NT1;
214 } else {
215 /* auto */
218 conn->in.options.signing = lpcfg_client_ipc_signing(lp_ctx);
220 if (s->conn.in.credentials != NULL) {
221 calling_name = cli_credentials_get_workstation(s->conn.in.credentials);
223 if (calling_name == NULL) {
224 calling_name = "SMBCLIENT";
227 if (target_hostname == NULL) {
228 target_hostname = conn->in.dest_host;
231 if (conn->in.dest_host != NULL && is_ipaddress(conn->in.dest_host)) {
232 dest_address = conn->in.dest_host;
235 subreq = smb_connect_nego_send(s,
236 c->event_ctx,
237 s->io.resolve_ctx,
238 &conn->in.options,
239 conn->in.socket_options,
240 conn->in.dest_host,
241 dest_address,
242 conn->in.dest_ports,
243 target_hostname,
244 conn->in.called_name,
245 calling_name);
246 if (composite_nomem(subreq, c)) return c;
247 tevent_req_set_callback(subreq,
248 continue_smbXcli_connect,
251 return c;
254 static void continue_smbXcli_connect(struct tevent_req *subreq)
256 struct composite_context *c =
257 tevent_req_callback_data(subreq,
258 struct composite_context);
259 struct pipe_np_smb_state *s =
260 talloc_get_type_abort(c->private_data,
261 struct pipe_np_smb_state);
262 struct smb_composite_connect *conn = &s->conn;
263 struct composite_context *creq = NULL;
264 enum protocol_types protocol;
266 c->status = smb_connect_nego_recv(subreq, s,
267 &conn->in.existing_conn);
268 TALLOC_FREE(subreq);
269 if (!composite_is_ok(c)) return;
271 protocol = smbXcli_conn_protocol(conn->in.existing_conn);
272 if (protocol >= PROTOCOL_SMB2_02) {
274 * continue with smb2 session setup/tree connect
275 * on the established connection.
277 subreq = smb2_connect_send(s, c->event_ctx,
278 conn->in.dest_host,
279 conn->in.dest_ports,
280 conn->in.service,
281 s->io.resolve_ctx,
282 conn->in.credentials,
283 conn->in.fallback_to_anonymous,
284 &conn->in.existing_conn,
285 0, /* previous_session_id */
286 &conn->in.options,
287 conn->in.socket_options,
288 conn->in.gensec_settings);
289 if (composite_nomem(subreq, c)) return;
290 tevent_req_set_callback(subreq, continue_smb2_connect, c);
291 return;
295 * continue with smb1 session setup/tree connect
296 * on the established connection.
298 creq = smb_composite_connect_send(conn, s->io.conn,
299 s->io.resolve_ctx,
300 c->event_ctx);
301 if (composite_nomem(creq, c)) return;
303 composite_continue(c, creq, continue_smb_connect, c);
304 return;
309 Receive result of a rpc connection to a rpc pipe on SMB
311 static NTSTATUS dcerpc_pipe_connect_ncacn_np_smb_recv(struct composite_context *c)
313 NTSTATUS status = composite_wait(c);
315 talloc_free(c);
316 return status;
320 Stage 2 of ncacn_np_smb2: Open a named pipe after successful smb2 connection
322 static void continue_smb2_connect(struct tevent_req *subreq)
324 struct composite_context *c =
325 tevent_req_callback_data(subreq,
326 struct composite_context);
327 struct pipe_np_smb_state *s = talloc_get_type(c->private_data,
328 struct pipe_np_smb_state);
329 struct smb2_tree *t;
331 /* receive result of smb2 connect request */
332 c->status = smb2_connect_recv(subreq, s->io.conn, &t);
333 TALLOC_FREE(subreq);
334 if (!composite_is_ok(c)) return;
336 s->io.smb.conn = t->session->transport->conn;
337 s->io.smb.session = t->session->smbXcli;
338 s->io.smb.tcon = t->smbXcli;
339 s->io.smb.pipe_name = dcerpc_binding_get_string_option(s->io.binding,
340 "endpoint");
342 continue_smb_open(c);
346 struct pipe_ip_tcp_state {
347 struct dcerpc_pipe_connect io;
348 const char *localaddr;
349 const char *host;
350 const char *target_hostname;
351 uint32_t port;
356 Stage 2 of ncacn_ip_tcp: rpc pipe opened (or not)
358 static void continue_pipe_open_ncacn_ip_tcp(struct composite_context *ctx)
360 struct composite_context *c = talloc_get_type(ctx->async.private_data,
361 struct composite_context);
362 struct pipe_ip_tcp_state *s = talloc_get_type(c->private_data,
363 struct pipe_ip_tcp_state);
364 char *localaddr = NULL;
365 char *remoteaddr = NULL;
367 /* receive result of named pipe open request on tcp/ip */
368 c->status = dcerpc_pipe_open_tcp_recv(ctx, s, &localaddr, &remoteaddr);
369 if (!composite_is_ok(c)) return;
371 c->status = dcerpc_binding_set_string_option(s->io.binding,
372 "localaddress",
373 localaddr);
374 if (!composite_is_ok(c)) return;
376 c->status = dcerpc_binding_set_string_option(s->io.binding,
377 "host",
378 remoteaddr);
379 if (!composite_is_ok(c)) return;
381 composite_done(c);
386 Initiate async open of a rpc connection to a rpc pipe on TCP/IP using
387 the binding structure to determine the endpoint and options
389 static struct composite_context* dcerpc_pipe_connect_ncacn_ip_tcp_send(TALLOC_CTX *mem_ctx,
390 struct dcerpc_pipe_connect *io)
392 struct composite_context *c;
393 struct pipe_ip_tcp_state *s;
394 struct composite_context *pipe_req;
395 const char *endpoint;
397 /* composite context allocation and setup */
398 c = composite_create(mem_ctx, io->conn->event_ctx);
399 if (c == NULL) return NULL;
401 s = talloc_zero(c, struct pipe_ip_tcp_state);
402 if (composite_nomem(s, c)) return c;
403 c->private_data = s;
405 /* store input parameters in state structure */
406 s->io = *io;
407 s->localaddr = dcerpc_binding_get_string_option(io->binding,
408 "localaddress");
409 s->host = dcerpc_binding_get_string_option(io->binding, "host");
410 s->target_hostname = dcerpc_binding_get_string_option(io->binding,
411 "target_hostname");
412 endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
413 /* port number is a binding endpoint here */
414 if (endpoint != NULL) {
415 s->port = atoi(endpoint);
418 if (s->port == 0) {
419 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
420 return c;
423 /* send pipe open request on tcp/ip */
424 pipe_req = dcerpc_pipe_open_tcp_send(s->io.conn, s->localaddr, s->host, s->target_hostname,
425 s->port, io->resolve_ctx);
426 composite_continue(c, pipe_req, continue_pipe_open_ncacn_ip_tcp, c);
427 return c;
432 Receive result of a rpc connection to a rpc pipe on TCP/IP
434 static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp_recv(struct composite_context *c)
436 NTSTATUS status = composite_wait(c);
438 talloc_free(c);
439 return status;
443 struct pipe_http_state {
444 struct dcerpc_pipe_connect io;
445 const char *localaddr;
446 const char *target_hostname;
447 const char *rpc_server;
448 uint32_t rpc_server_port;
449 char *rpc_proxy;
450 uint32_t rpc_proxy_port;
451 char *http_proxy;
452 uint32_t http_proxy_port;
453 bool use_tls;
454 bool use_proxy;
455 enum http_auth_method http_auth;
456 struct loadparm_context *lp_ctx;
460 Stage 2 of ncacn_http: rpc pipe opened (or not)
462 static void continue_pipe_open_ncacn_http(struct tevent_req *subreq)
464 struct composite_context *c = NULL;
465 struct pipe_http_state *s = NULL;
466 struct tstream_context *stream = NULL;
467 struct tevent_queue *queue = NULL;
469 c = tevent_req_callback_data(subreq, struct composite_context);
470 s = talloc_get_type(c->private_data, struct pipe_http_state);
472 /* receive result of RoH connect request */
473 c->status = dcerpc_pipe_open_roh_recv(subreq, s->io.conn,
474 &stream, &queue);
475 TALLOC_FREE(subreq);
476 if (!composite_is_ok(c)) return;
478 s->io.conn->transport.transport = NCACN_HTTP;
479 s->io.conn->transport.stream = stream;
480 s->io.conn->transport.write_queue = queue;
481 s->io.conn->transport.pending_reads = 0;
482 s->io.conn->server_name = strupper_talloc(s->io.conn,
483 s->target_hostname);
485 composite_done(c);
489 Initiate async open of a rpc connection to a rpc pipe using HTTP transport,
490 and using the binding structure to determine the endpoint and options
492 static struct composite_context* dcerpc_pipe_connect_ncacn_http_send(
493 TALLOC_CTX *mem_ctx, struct dcerpc_pipe_connect *io,
494 struct loadparm_context *lp_ctx)
496 struct composite_context *c;
497 struct pipe_http_state *s;
498 struct tevent_req *subreq;
499 const char *endpoint;
500 const char *use_proxy;
501 char *proxy;
502 char *port;
503 const char *opt;
505 /* composite context allocation and setup */
506 c = composite_create(mem_ctx, io->conn->event_ctx);
507 if (c == NULL) return NULL;
509 s = talloc_zero(c, struct pipe_http_state);
510 if (composite_nomem(s, c)) return c;
511 c->private_data = s;
513 /* store input parameters in state structure */
514 s->lp_ctx = lp_ctx;
515 s->io = *io;
516 s->localaddr = dcerpc_binding_get_string_option(io->binding,
517 "localaddress");
518 /* RPC server and port (the endpoint) */
519 s->rpc_server = dcerpc_binding_get_string_option(io->binding, "host");
520 s->target_hostname = dcerpc_binding_get_string_option(io->binding,
521 "target_hostname");
522 endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
523 if (endpoint == NULL) {
524 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
525 return c;
527 s->rpc_server_port = atoi(endpoint);
528 if (s->rpc_server_port == 0) {
529 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
530 return c;
533 /* Use TLS */
534 opt = dcerpc_binding_get_string_option(io->binding, "HttpUseTls");
535 if (opt) {
536 if (strcasecmp(opt, "true") == 0) {
537 s->use_tls = true;
538 } else if (strcasecmp(opt, "false") == 0) {
539 s->use_tls = false;
540 } else {
541 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
542 return c;
544 } else {
545 s->use_tls = true;
548 /* RPC Proxy */
549 proxy = port = talloc_strdup(s, dcerpc_binding_get_string_option(
550 io->binding, "RpcProxy"));
551 s->rpc_proxy = strsep(&port, ":");
552 if (proxy && port) {
553 s->rpc_proxy_port = atoi(port);
554 } else {
555 s->rpc_proxy_port = s->use_tls ? 443 : 80;
557 if (s->rpc_proxy == NULL) {
558 s->rpc_proxy = talloc_strdup(s, s->rpc_server);
559 if (composite_nomem(s->rpc_proxy, c)) return c;
562 /* HTTP Proxy */
563 proxy = port = talloc_strdup(s, dcerpc_binding_get_string_option(
564 io->binding, "HttpProxy"));
565 s->http_proxy = strsep(&port, ":");
566 if (proxy && port) {
567 s->http_proxy_port = atoi(port);
568 } else {
569 s->http_proxy_port = s->use_tls ? 443 : 80;
572 /* Use local proxy */
573 use_proxy = dcerpc_binding_get_string_option(io->binding,
574 "HttpConnectOption");
575 if (use_proxy && strcasecmp(use_proxy, "UseHttpProxy")) {
576 s->use_proxy = true;
579 /* If use local proxy set, the http proxy should be provided */
580 if (s->use_proxy && !s->http_proxy) {
581 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
582 return c;
585 /* Check which HTTP authentication method to use */
586 opt = dcerpc_binding_get_string_option(io->binding, "HttpAuthOption");
587 if (opt) {
588 if (strcasecmp(opt, "basic") == 0) {
589 s->http_auth = HTTP_AUTH_BASIC;
590 } else if (strcasecmp(opt, "ntlm") == 0) {
591 s->http_auth = HTTP_AUTH_NTLM;
592 } else if (strcasecmp(opt, "negotiate") == 0) {
593 s->http_auth = HTTP_AUTH_NEGOTIATE;
594 } else {
595 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
596 return c;
598 } else {
599 s->http_auth = HTTP_AUTH_NTLM;
602 subreq = dcerpc_pipe_open_roh_send(s->io.conn, s->localaddr,
603 s->rpc_server, s->rpc_server_port,
604 s->rpc_proxy, s->rpc_proxy_port,
605 s->http_proxy, s->http_proxy_port,
606 s->use_tls, s->use_proxy,
607 s->io.creds, io->resolve_ctx,
608 s->lp_ctx, s->http_auth);
609 if (composite_nomem(subreq, c)) return c;
611 tevent_req_set_callback(subreq, continue_pipe_open_ncacn_http, c);
612 return c;
615 static NTSTATUS dcerpc_pipe_connect_ncacn_http_recv(struct composite_context *c)
617 return composite_wait_free(c);
621 struct pipe_unix_state {
622 struct dcerpc_pipe_connect io;
623 const char *path;
628 Stage 2 of ncacn_unix: rpc pipe opened (or not)
630 static void continue_pipe_open_ncacn_unix_stream(struct composite_context *ctx)
632 struct composite_context *c = talloc_get_type(ctx->async.private_data,
633 struct composite_context);
635 /* receive result of pipe open request on unix socket */
636 c->status = dcerpc_pipe_open_unix_stream_recv(ctx);
637 if (!composite_is_ok(c)) return;
639 composite_done(c);
644 Initiate async open of a rpc connection to a rpc pipe on unix socket using
645 the binding structure to determine the endpoint and options
647 static struct composite_context* dcerpc_pipe_connect_ncacn_unix_stream_send(TALLOC_CTX *mem_ctx,
648 struct dcerpc_pipe_connect *io)
650 struct composite_context *c;
651 struct pipe_unix_state *s;
652 struct composite_context *pipe_req;
654 /* composite context allocation and setup */
655 c = composite_create(mem_ctx, io->conn->event_ctx);
656 if (c == NULL) return NULL;
658 s = talloc_zero(c, struct pipe_unix_state);
659 if (composite_nomem(s, c)) return c;
660 c->private_data = s;
662 /* prepare pipe open parameters and store them in state structure
663 also, verify whether biding endpoint is not null */
664 s->io = *io;
666 s->path = dcerpc_binding_get_string_option(io->binding, "endpoint");
667 if (s->path == NULL) {
668 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
669 return c;
672 /* send pipe open request on unix socket */
673 pipe_req = dcerpc_pipe_open_unix_stream_send(s->io.conn, s->path);
674 composite_continue(c, pipe_req, continue_pipe_open_ncacn_unix_stream, c);
675 return c;
680 Receive result of a rpc connection to a pipe on unix socket
682 static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream_recv(struct composite_context *c)
684 NTSTATUS status = composite_wait(c);
686 talloc_free(c);
687 return status;
691 struct pipe_ncalrpc_state {
692 struct dcerpc_pipe_connect io;
695 static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c);
698 Stage 2 of ncalrpc: rpc pipe opened (or not)
700 static void continue_pipe_open_ncalrpc(struct composite_context *ctx)
702 struct composite_context *c = talloc_get_type(ctx->async.private_data,
703 struct composite_context);
705 /* receive result of pipe open request on ncalrpc */
706 c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
707 if (!composite_is_ok(c)) return;
709 composite_done(c);
714 Initiate async open of a rpc connection request on NCALRPC using
715 the binding structure to determine the endpoint and options
717 static struct composite_context* dcerpc_pipe_connect_ncalrpc_send(TALLOC_CTX *mem_ctx,
718 struct dcerpc_pipe_connect *io)
720 struct composite_context *c;
721 struct pipe_ncalrpc_state *s;
722 struct composite_context *pipe_req;
723 const char *endpoint;
725 /* composite context allocation and setup */
726 c = composite_create(mem_ctx, io->conn->event_ctx);
727 if (c == NULL) return NULL;
729 s = talloc_zero(c, struct pipe_ncalrpc_state);
730 if (composite_nomem(s, c)) return c;
731 c->private_data = s;
733 /* store input parameters in state structure */
734 s->io = *io;
736 endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
737 if (endpoint == NULL) {
738 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
739 return c;
742 /* send pipe open request */
743 pipe_req = dcerpc_pipe_open_pipe_send(s->io.conn,
744 s->io.ncalrpc.dir,
745 endpoint);
746 composite_continue(c, pipe_req, continue_pipe_open_ncalrpc, c);
747 return c;
752 Receive result of a rpc connection to a rpc pipe on NCALRPC
754 static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c)
756 NTSTATUS status = composite_wait(c);
758 talloc_free(c);
759 return status;
763 struct pipe_connect_state {
764 struct dcerpc_pipe *pipe;
765 struct dcerpc_binding *binding;
766 const struct ndr_interface_table *table;
767 struct cli_credentials *credentials;
768 struct loadparm_context *lp_ctx;
772 static void continue_map_binding(struct composite_context *ctx);
773 static void continue_connect(struct composite_context *c, struct pipe_connect_state *s);
774 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx);
775 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx);
776 static void continue_pipe_connect_ncacn_http(struct composite_context *ctx);
777 static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx);
778 static void continue_pipe_connect_ncalrpc(struct composite_context *ctx);
779 static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s);
780 static void continue_pipe_auth(struct composite_context *ctx);
784 Stage 2 of pipe_connect_b: Receive result of endpoint mapping
786 static void continue_map_binding(struct composite_context *ctx)
788 struct composite_context *c = talloc_get_type(ctx->async.private_data,
789 struct composite_context);
790 struct pipe_connect_state *s = talloc_get_type(c->private_data,
791 struct pipe_connect_state);
792 const char *endpoint;
794 c->status = dcerpc_epm_map_binding_recv(ctx);
795 if (!composite_is_ok(c)) return;
797 endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
798 DEBUG(4,("Mapped to DCERPC endpoint %s\n", endpoint));
800 continue_connect(c, s);
805 Stage 2 of pipe_connect_b: Continue connection after endpoint is known
807 static void continue_connect(struct composite_context *c, struct pipe_connect_state *s)
809 struct dcerpc_pipe_connect pc;
811 /* potential exits to another stage by sending an async request */
812 struct composite_context *ncacn_np_smb_req;
813 struct composite_context *ncacn_ip_tcp_req;
814 struct composite_context *ncacn_http_req;
815 struct composite_context *ncacn_unix_req;
816 struct composite_context *ncalrpc_req;
817 enum dcerpc_transport_t transport;
819 /* dcerpc pipe connect input parameters */
820 ZERO_STRUCT(pc);
821 pc.conn = s->pipe->conn;
822 pc.binding = s->binding;
823 pc.interface = s->table;
824 pc.creds = s->credentials;
825 pc.resolve_ctx = lpcfg_resolve_context(s->lp_ctx);
827 transport = dcerpc_binding_get_transport(s->binding);
829 /* connect dcerpc pipe depending on required transport */
830 switch (transport) {
831 case NCACN_NP:
833 * SMB1/2/3...
835 ncacn_np_smb_req = dcerpc_pipe_connect_ncacn_np_smb_send(c, &pc, s->lp_ctx);
836 composite_continue(c, ncacn_np_smb_req, continue_pipe_connect_ncacn_np_smb, c);
837 return;
839 case NCACN_IP_TCP:
840 ncacn_ip_tcp_req = dcerpc_pipe_connect_ncacn_ip_tcp_send(c, &pc);
841 composite_continue(c, ncacn_ip_tcp_req, continue_pipe_connect_ncacn_ip_tcp, c);
842 return;
844 case NCACN_HTTP:
845 ncacn_http_req = dcerpc_pipe_connect_ncacn_http_send(c, &pc, s->lp_ctx);
846 composite_continue(c, ncacn_http_req, continue_pipe_connect_ncacn_http, c);
847 return;
849 case NCACN_UNIX_STREAM:
850 ncacn_unix_req = dcerpc_pipe_connect_ncacn_unix_stream_send(c, &pc);
851 composite_continue(c, ncacn_unix_req, continue_pipe_connect_ncacn_unix, c);
852 return;
854 case NCALRPC:
855 pc.ncalrpc.dir = lpcfg_ncalrpc_dir(s->lp_ctx);
856 c->status = dcerpc_binding_set_string_option(s->binding, "ncalrpc_dir",
857 pc.ncalrpc.dir);
858 if (!composite_is_ok(c)) return;
859 ncalrpc_req = dcerpc_pipe_connect_ncalrpc_send(c, &pc);
860 composite_continue(c, ncalrpc_req, continue_pipe_connect_ncalrpc, c);
861 return;
863 default:
864 /* looks like a transport we don't support now */
865 composite_error(c, NT_STATUS_NOT_SUPPORTED);
871 Stage 3 of pipe_connect_b: Receive result of pipe connect request on
872 named pipe on smb
874 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx)
876 struct composite_context *c = talloc_get_type(ctx->async.private_data,
877 struct composite_context);
878 struct pipe_connect_state *s = talloc_get_type(c->private_data,
879 struct pipe_connect_state);
881 c->status = dcerpc_pipe_connect_ncacn_np_smb_recv(ctx);
882 if (!composite_is_ok(c)) return;
884 continue_pipe_connect(c, s);
889 Stage 3 of pipe_connect_b: Receive result of pipe connect request on tcp/ip
891 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx)
893 struct composite_context *c = talloc_get_type(ctx->async.private_data,
894 struct composite_context);
895 struct pipe_connect_state *s = talloc_get_type(c->private_data,
896 struct pipe_connect_state);
898 c->status = dcerpc_pipe_connect_ncacn_ip_tcp_recv(ctx);
899 if (!composite_is_ok(c)) return;
901 continue_pipe_connect(c, s);
906 Stage 3 of pipe_connect_b: Receive result of pipe connect request on http
908 static void continue_pipe_connect_ncacn_http(struct composite_context *ctx)
910 struct composite_context *c = talloc_get_type(ctx->async.private_data,
911 struct composite_context);
912 struct pipe_connect_state *s = talloc_get_type(c->private_data,
913 struct pipe_connect_state);
915 c->status = dcerpc_pipe_connect_ncacn_http_recv(ctx);
916 if (!composite_is_ok(c)) return;
918 continue_pipe_connect(c, s);
923 Stage 3 of pipe_connect_b: Receive result of pipe connect request on unix socket
925 static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx)
927 struct composite_context *c = talloc_get_type(ctx->async.private_data,
928 struct composite_context);
929 struct pipe_connect_state *s = talloc_get_type(c->private_data,
930 struct pipe_connect_state);
932 c->status = dcerpc_pipe_connect_ncacn_unix_stream_recv(ctx);
933 if (!composite_is_ok(c)) return;
935 continue_pipe_connect(c, s);
940 Stage 3 of pipe_connect_b: Receive result of pipe connect request on local rpc
942 static void continue_pipe_connect_ncalrpc(struct composite_context *ctx)
944 struct composite_context *c = talloc_get_type(ctx->async.private_data,
945 struct composite_context);
946 struct pipe_connect_state *s = talloc_get_type(c->private_data,
947 struct pipe_connect_state);
949 c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
950 if (!composite_is_ok(c)) return;
952 continue_pipe_connect(c, s);
957 Stage 4 of pipe_connect_b: Start an authentication on connected dcerpc pipe
958 depending on credentials and binding flags passed.
960 static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s)
962 struct composite_context *auth_bind_req;
964 s->pipe->binding = dcerpc_binding_dup(s->pipe, s->binding);
965 if (composite_nomem(s->pipe->binding, c)) {
966 return;
969 auth_bind_req = dcerpc_pipe_auth_send(s->pipe, s->binding, s->table,
970 s->credentials, s->lp_ctx);
971 composite_continue(c, auth_bind_req, continue_pipe_auth, c);
976 Stage 5 of pipe_connect_b: Receive result of pipe authentication request
977 and say if all went ok
979 static void continue_pipe_auth(struct composite_context *ctx)
981 struct composite_context *c = talloc_get_type(ctx->async.private_data,
982 struct composite_context);
983 struct pipe_connect_state *s = talloc_get_type(c->private_data, struct pipe_connect_state);
985 c->status = dcerpc_pipe_auth_recv(ctx, s, &s->pipe);
986 if (!composite_is_ok(c)) return;
988 composite_done(c);
993 handle timeouts of a dcerpc connect
995 static void dcerpc_connect_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
996 struct timeval t, void *private_data)
998 struct composite_context *c = talloc_get_type_abort(private_data,
999 struct composite_context);
1000 struct pipe_connect_state *s = talloc_get_type_abort(c->private_data, struct pipe_connect_state);
1001 if (!s->pipe->inhibit_timeout_processing) {
1002 composite_error(c, NT_STATUS_IO_TIMEOUT);
1003 } else {
1004 s->pipe->timed_out = true;
1009 start a request to open a rpc connection to a rpc pipe, using
1010 specified binding structure to determine the endpoint and options
1012 _PUBLIC_ struct composite_context* dcerpc_pipe_connect_b_send(TALLOC_CTX *parent_ctx,
1013 const struct dcerpc_binding *binding,
1014 const struct ndr_interface_table *table,
1015 struct cli_credentials *credentials,
1016 struct tevent_context *ev,
1017 struct loadparm_context *lp_ctx)
1019 struct composite_context *c;
1020 struct pipe_connect_state *s;
1021 enum dcerpc_transport_t transport;
1022 const char *endpoint = NULL;
1023 struct cli_credentials *epm_creds = NULL;
1025 /* composite context allocation and setup */
1026 c = composite_create(parent_ctx, ev);
1027 if (c == NULL) {
1028 return NULL;
1031 s = talloc_zero(c, struct pipe_connect_state);
1032 if (composite_nomem(s, c)) return c;
1033 c->private_data = s;
1035 /* initialise dcerpc pipe structure */
1036 s->pipe = dcerpc_pipe_init(c, ev);
1037 if (composite_nomem(s->pipe, c)) return c;
1039 if (DEBUGLEVEL >= 10)
1040 s->pipe->conn->packet_log_dir = lpcfg_lock_directory(lp_ctx);
1042 /* store parameters in state structure */
1043 s->binding = dcerpc_binding_dup(s, binding);
1044 if (composite_nomem(s->binding, c)) return c;
1045 s->table = table;
1046 s->credentials = credentials;
1047 s->lp_ctx = lp_ctx;
1049 s->pipe->timed_out = false;
1050 s->pipe->inhibit_timeout_processing = false;
1052 tevent_add_timer(c->event_ctx, c,
1053 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1054 dcerpc_connect_timeout_handler, c);
1056 transport = dcerpc_binding_get_transport(s->binding);
1058 switch (transport) {
1059 case NCACN_NP:
1060 case NCACN_IP_TCP:
1061 case NCALRPC:
1062 endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
1064 /* anonymous credentials for rpc connection used to get endpoint mapping */
1065 epm_creds = cli_credentials_init_anon(s);
1066 if (composite_nomem(epm_creds, c)) return c;
1068 break;
1069 case NCACN_HTTP:
1070 endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
1071 epm_creds = credentials;
1072 break;
1073 default:
1074 DBG_INFO("Unknown transport; continuing with anon, no endpoint.\n");
1075 epm_creds = cli_credentials_init_anon(s);
1076 if (composite_nomem(epm_creds, c)){
1077 return c;
1079 break;
1082 if (endpoint == NULL) {
1083 struct composite_context *binding_req;
1085 binding_req = dcerpc_epm_map_binding_send(c, s->binding, s->table,
1086 epm_creds,
1087 s->pipe->conn->event_ctx,
1088 s->lp_ctx);
1089 composite_continue(c, binding_req, continue_map_binding, c);
1090 return c;
1093 continue_connect(c, s);
1094 return c;
1099 receive result of a request to open a rpc connection to a rpc pipe
1101 _PUBLIC_ NTSTATUS dcerpc_pipe_connect_b_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
1102 struct dcerpc_pipe **p)
1104 NTSTATUS status;
1105 struct pipe_connect_state *s;
1107 status = composite_wait(c);
1109 if (NT_STATUS_IS_OK(status)) {
1110 s = talloc_get_type(c->private_data, struct pipe_connect_state);
1111 talloc_steal(mem_ctx, s->pipe);
1112 *p = s->pipe;
1114 talloc_free(c);
1115 return status;
1120 open a rpc connection to a rpc pipe, using the specified
1121 binding structure to determine the endpoint and options - sync version
1123 _PUBLIC_ NTSTATUS dcerpc_pipe_connect_b(TALLOC_CTX *parent_ctx,
1124 struct dcerpc_pipe **pp,
1125 const struct dcerpc_binding *binding,
1126 const struct ndr_interface_table *table,
1127 struct cli_credentials *credentials,
1128 struct tevent_context *ev,
1129 struct loadparm_context *lp_ctx)
1131 struct composite_context *c;
1133 c = dcerpc_pipe_connect_b_send(parent_ctx, binding, table,
1134 credentials, ev, lp_ctx);
1135 return dcerpc_pipe_connect_b_recv(c, parent_ctx, pp);
1139 struct pipe_conn_state {
1140 struct dcerpc_pipe *pipe;
1144 static void continue_pipe_connect_b(struct composite_context *ctx);
1148 Initiate rpc connection to a rpc pipe, using the specified string
1149 binding to determine the endpoint and options.
1150 The string is to be parsed to a binding structure first.
1152 _PUBLIC_ struct composite_context* dcerpc_pipe_connect_send(TALLOC_CTX *parent_ctx,
1153 const char *binding,
1154 const struct ndr_interface_table *table,
1155 struct cli_credentials *credentials,
1156 struct tevent_context *ev, struct loadparm_context *lp_ctx)
1158 struct composite_context *c;
1159 struct pipe_conn_state *s;
1160 struct dcerpc_binding *b;
1161 struct composite_context *pipe_conn_req;
1163 /* composite context allocation and setup */
1164 c = composite_create(parent_ctx, ev);
1165 if (c == NULL) {
1166 return NULL;
1169 s = talloc_zero(c, struct pipe_conn_state);
1170 if (composite_nomem(s, c)) return c;
1171 c->private_data = s;
1173 /* parse binding string to the structure */
1174 c->status = dcerpc_parse_binding(c, binding, &b);
1175 if (!NT_STATUS_IS_OK(c->status)) {
1176 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", binding));
1177 composite_error(c, c->status);
1178 return c;
1181 DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(c, b)));
1184 start connecting to a rpc pipe after binding structure
1185 is established
1187 pipe_conn_req = dcerpc_pipe_connect_b_send(c, b, table,
1188 credentials, ev, lp_ctx);
1189 composite_continue(c, pipe_conn_req, continue_pipe_connect_b, c);
1190 return c;
1195 Stage 2 of pipe_connect: Receive result of actual pipe connect request
1196 and say if we're done ok
1198 static void continue_pipe_connect_b(struct composite_context *ctx)
1200 struct composite_context *c = talloc_get_type(ctx->async.private_data,
1201 struct composite_context);
1202 struct pipe_conn_state *s = talloc_get_type(c->private_data,
1203 struct pipe_conn_state);
1205 c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe);
1206 talloc_steal(s, s->pipe);
1207 if (!composite_is_ok(c)) return;
1209 composite_done(c);
1214 Receive result of pipe connect (using binding string) request
1215 and return connected pipe structure.
1217 NTSTATUS dcerpc_pipe_connect_recv(struct composite_context *c,
1218 TALLOC_CTX *mem_ctx,
1219 struct dcerpc_pipe **pp)
1221 NTSTATUS status;
1222 struct pipe_conn_state *s;
1224 status = composite_wait(c);
1225 if (NT_STATUS_IS_OK(status)) {
1226 s = talloc_get_type(c->private_data, struct pipe_conn_state);
1227 *pp = talloc_steal(mem_ctx, s->pipe);
1229 talloc_free(c);
1230 return status;
1235 Open a rpc connection to a rpc pipe, using the specified string
1236 binding to determine the endpoint and options - sync version
1238 _PUBLIC_ NTSTATUS dcerpc_pipe_connect(TALLOC_CTX *parent_ctx,
1239 struct dcerpc_pipe **pp,
1240 const char *binding,
1241 const struct ndr_interface_table *table,
1242 struct cli_credentials *credentials,
1243 struct tevent_context *ev,
1244 struct loadparm_context *lp_ctx)
1246 struct composite_context *c;
1247 c = dcerpc_pipe_connect_send(parent_ctx, binding,
1248 table, credentials, ev, lp_ctx);
1249 return dcerpc_pipe_connect_recv(c, parent_ctx, pp);