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/>.
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"
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;
53 struct smbXcli_conn *conn;
54 struct smbXcli_session *session;
55 struct smbXcli_tcon *tcon;
56 const char *pipe_name;
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;
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,
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,
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;
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;
158 if (smbXcli_conn_is_connected(s->io.smb.conn)) {
159 continue_smb_open(c);
163 if (s->io.creds == NULL) {
164 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
168 /* prepare smb connection parameters: we're connecting to IPC$ share on
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;
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)) {
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;
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,
239 conn->in.socket_options,
244 conn->in.called_name,
246 if (composite_nomem(subreq, c)) return c;
247 tevent_req_set_callback(subreq,
248 continue_smbXcli_connect,
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);
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,
282 conn->in.credentials,
283 conn->in.fallback_to_anonymous,
284 &conn->in.existing_conn,
285 0, /* previous_session_id */
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);
295 * continue with smb1 session setup/tree connect
296 * on the established connection.
298 creq = smb_composite_connect_send(conn, s->io.conn,
301 if (composite_nomem(creq, c)) return;
303 composite_continue(c, creq, continue_smb_connect, c);
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);
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);
331 /* receive result of smb2 connect request */
332 c->status = smb2_connect_recv(subreq, s->io.conn, &t);
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,
342 continue_smb_open(c);
346 struct pipe_ip_tcp_state {
347 struct dcerpc_pipe_connect io;
348 const char *localaddr;
350 const char *target_hostname;
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,
374 if (!composite_is_ok(c)) return;
376 c->status = dcerpc_binding_set_string_option(s->io.binding,
379 if (!composite_is_ok(c)) return;
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;
405 /* store input parameters in state structure */
407 s->localaddr = dcerpc_binding_get_string_option(io->binding,
409 s->host = dcerpc_binding_get_string_option(io->binding, "host");
410 s->target_hostname = dcerpc_binding_get_string_option(io->binding,
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);
419 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
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);
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);
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;
450 uint32_t rpc_proxy_port;
452 uint32_t http_proxy_port;
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,
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,
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;
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;
513 /* store input parameters in state structure */
516 s->localaddr = dcerpc_binding_get_string_option(io->binding,
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,
522 endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
523 if (endpoint == NULL) {
524 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
527 s->rpc_server_port = atoi(endpoint);
528 if (s->rpc_server_port == 0) {
529 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
534 opt = dcerpc_binding_get_string_option(io->binding, "HttpUseTls");
536 if (strcasecmp(opt, "true") == 0) {
538 } else if (strcasecmp(opt, "false") == 0) {
541 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
549 proxy = port = talloc_strdup(s, dcerpc_binding_get_string_option(
550 io->binding, "RpcProxy"));
551 s->rpc_proxy = strsep(&port, ":");
553 s->rpc_proxy_port = atoi(port);
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;
563 proxy = port = talloc_strdup(s, dcerpc_binding_get_string_option(
564 io->binding, "HttpProxy"));
565 s->http_proxy = strsep(&port, ":");
567 s->http_proxy_port = atoi(port);
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")) {
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);
585 /* Check which HTTP authentication method to use */
586 opt = dcerpc_binding_get_string_option(io->binding, "HttpAuthOption");
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;
595 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
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);
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;
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;
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;
662 /* prepare pipe open parameters and store them in state structure
663 also, verify whether biding endpoint is not null */
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);
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);
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);
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;
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;
733 /* store input parameters in state structure */
736 endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
737 if (endpoint == NULL) {
738 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
742 /* send pipe open request */
743 pipe_req = dcerpc_pipe_open_pipe_send(s->io.conn,
746 composite_continue(c, pipe_req, continue_pipe_open_ncalrpc, 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);
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 */
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 */
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);
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);
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);
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);
855 pc.ncalrpc.dir = lpcfg_ncalrpc_dir(s->lp_ctx);
856 c->status = dcerpc_binding_set_string_option(s->binding, "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);
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
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)) {
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;
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);
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);
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;
1046 s->credentials = credentials;
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) {
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;
1070 endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
1071 epm_creds = credentials;
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)){
1082 if (endpoint == NULL) {
1083 struct composite_context *binding_req;
1085 binding_req = dcerpc_epm_map_binding_send(c, s->binding, s->table,
1087 s->pipe->conn->event_ctx,
1089 composite_continue(c, binding_req, continue_map_binding, c);
1093 continue_connect(c, s);
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)
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);
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);
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);
1181 DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(c, b)));
1184 start connecting to a rpc pipe after binding structure
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);
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;
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)
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);
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);