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 "lib/http/http.h"
39 #include "lib/util/util_net.h"
41 struct dcerpc_pipe_connect {
42 struct dcecli_connection *conn;
43 struct dcerpc_binding *binding;
44 const struct ndr_interface_table *interface;
45 struct cli_credentials *creds;
46 struct resolve_context *resolve_ctx;
51 struct smbXcli_conn *conn;
52 struct smbXcli_session *session;
53 struct smbXcli_tcon *tcon;
54 const char *pipe_name;
58 struct dcerpc_binding_smbXcli_pointers_ref;
60 struct dcerpc_binding_smbXcli_pointers {
61 struct smbXcli_conn *conn;
62 struct dcerpc_binding_smbXcli_pointers_ref *conn_ref;
63 struct smbXcli_session *sess;
64 struct dcerpc_binding_smbXcli_pointers_ref *sess_ref;
65 struct smbXcli_tcon *tcon;
66 struct dcerpc_binding_smbXcli_pointers_ref *tcon_ref;
69 struct dcerpc_binding_smbXcli_pointers_ref {
70 struct dcerpc_binding_smbXcli_pointers *p;
73 static int dcerpc_binding_smbXcli_pointers_ref_destructor(
74 struct dcerpc_binding_smbXcli_pointers_ref *ref)
76 struct dcerpc_binding_smbXcli_pointers *p;
84 p->conn_ref->p = NULL;
85 p->sess_ref->p = NULL;
86 p->tcon_ref->p = NULL;
88 if (p->conn_ref != ref) {
89 talloc_free(p->conn_ref);
92 if (p->sess_ref != ref) {
93 talloc_free(p->sess_ref);
96 if (p->tcon_ref != ref) {
97 talloc_free(p->tcon_ref);
104 static int dcerpc_binding_smbXcli_pointers_destructor(
105 struct dcerpc_binding_smbXcli_pointers *p)
107 if (p->conn_ref != NULL) {
108 p->conn_ref->p = NULL;
111 if (p->sess_ref != NULL) {
112 p->sess_ref->p = NULL;
115 if (p->tcon_ref != NULL) {
116 p->tcon_ref->p = NULL;
119 talloc_free(p->conn_ref);
120 talloc_free(p->sess_ref);
121 talloc_free(p->tcon_ref);
127 NTSTATUS dcerpc_binding_set_smbXcli_pointers(struct dcerpc_binding *b,
128 struct smbXcli_conn *conn,
129 struct smbXcli_session *sess,
130 struct smbXcli_tcon *tcon)
132 struct dcerpc_binding_smbXcli_pointers *p;
133 struct dcerpc_binding_smbXcli_pointers_ref *r;
136 if (!smbXcli_conn_is_connected(conn)) {
137 return NT_STATUS_INVALID_PARAMETER_MIX;
141 return NT_STATUS_INVALID_PARAMETER_MIX;
145 return NT_STATUS_INVALID_PARAMETER_MIX;
148 p = talloc_zero(b, struct dcerpc_binding_smbXcli_pointers);
150 return NT_STATUS_NO_MEMORY;
152 talloc_set_destructor(p, dcerpc_binding_smbXcli_pointers_destructor);
154 r = talloc_zero(conn, struct dcerpc_binding_smbXcli_pointers_ref);
157 return NT_STATUS_NO_MEMORY;
159 talloc_set_destructor(r, dcerpc_binding_smbXcli_pointers_ref_destructor);
163 r = talloc_zero(sess, struct dcerpc_binding_smbXcli_pointers_ref);
166 return NT_STATUS_NO_MEMORY;
168 talloc_set_destructor(r, dcerpc_binding_smbXcli_pointers_ref_destructor);
172 r = talloc_zero(tcon, struct dcerpc_binding_smbXcli_pointers_ref);
175 return NT_STATUS_NO_MEMORY;
177 talloc_set_destructor(r, dcerpc_binding_smbXcli_pointers_ref_destructor);
185 status = dcerpc_binding_set_pointer_option(b, "connection",
186 struct dcerpc_binding_smbXcli_pointers, p);
187 if (!NT_STATUS_IS_OK(status)) {
195 NTSTATUS dcerpc_binding_get_smbXcli_pointers(const struct dcerpc_binding *b,
196 struct smbXcli_conn **conn,
197 struct smbXcli_session **sess,
198 struct smbXcli_tcon **tcon)
200 struct dcerpc_binding_smbXcli_pointers *p;
202 p = dcerpc_binding_get_pointer_option(b, "connection",
203 struct dcerpc_binding_smbXcli_pointers);
205 return NT_STATUS_CONNECTION_DISCONNECTED;
208 if (!smbXcli_conn_is_connected(p->conn)) {
209 return NT_STATUS_CONNECTION_DISCONNECTED;
212 if (p->sess == NULL) {
213 return NT_STATUS_CONNECTION_DISCONNECTED;
216 if (p->tcon == NULL) {
217 return NT_STATUS_CONNECTION_DISCONNECTED;
227 struct pipe_np_smb_state {
228 struct smb_composite_connect conn;
229 struct dcerpc_pipe_connect io;
234 Stage 3 of ncacn_np_smb: Named pipe opened (or not)
236 static void continue_pipe_open_smb(struct composite_context *ctx)
238 struct composite_context *c = talloc_get_type(ctx->async.private_data,
239 struct composite_context);
241 /* receive result of named pipe open request on smb */
242 c->status = dcerpc_pipe_open_smb_recv(ctx);
243 if (!composite_is_ok(c)) return;
248 static void continue_smb_open(struct composite_context *c);
249 static void continue_smb2_connect(struct tevent_req *subreq);
250 static void continue_smbXcli_connect(struct tevent_req *subreq);
253 Stage 2 of ncacn_np_smb: Open a named pipe after successful smb connection
255 static void continue_smb_connect(struct composite_context *ctx)
257 struct composite_context *c = talloc_get_type(ctx->async.private_data,
258 struct composite_context);
259 struct pipe_np_smb_state *s = talloc_get_type(c->private_data,
260 struct pipe_np_smb_state);
261 struct smbcli_tree *t;
263 /* receive result of smb connect request */
264 c->status = smb_composite_connect_recv(ctx, s->io.conn);
265 if (!composite_is_ok(c)) return;
267 t = s->conn.out.tree;
269 /* prepare named pipe open parameters */
270 s->io.smb.conn = t->session->transport->conn;
271 s->io.smb.session = t->session->smbXcli;
272 s->io.smb.tcon = t->smbXcli;
273 smb1cli_tcon_set_id(s->io.smb.tcon, t->tid);
274 s->io.smb.pipe_name = dcerpc_binding_get_string_option(s->io.binding,
277 c->status = dcerpc_binding_set_smbXcli_pointers(s->io.binding,
281 if (!composite_is_ok(c)) return;
283 continue_smb_open(c);
286 static void continue_smb_open(struct composite_context *c)
288 struct pipe_np_smb_state *s = talloc_get_type(c->private_data,
289 struct pipe_np_smb_state);
290 struct composite_context *open_ctx;
292 /* send named pipe open request */
293 open_ctx = dcerpc_pipe_open_smb_send(s->io.conn,
297 DCERPC_REQUEST_TIMEOUT * 1000,
298 s->io.smb.pipe_name);
299 if (composite_nomem(open_ctx, c)) return;
301 composite_continue(c, open_ctx, continue_pipe_open_smb, c);
306 Initiate async open of a rpc connection to a rpc pipe on SMB using
307 the binding structure to determine the endpoint and options
309 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)
311 struct composite_context *c;
312 struct pipe_np_smb_state *s;
313 struct tevent_req *subreq = NULL;
314 struct smb_composite_connect *conn;
316 const char *target_hostname = NULL;
317 const char *dest_address = NULL;
318 const char *calling_name = NULL;
320 /* composite context allocation and setup */
321 c = composite_create(mem_ctx, io->conn->event_ctx);
322 if (c == NULL) return NULL;
324 s = talloc_zero(c, struct pipe_np_smb_state);
325 if (composite_nomem(s, c)) return c;
331 if (smbXcli_conn_is_connected(s->io.smb.conn)) {
332 continue_smb_open(c);
336 if (s->io.creds == NULL) {
337 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
341 /* prepare smb connection parameters: we're connecting to IPC$ share on
343 target_hostname = dcerpc_binding_get_string_option(s->io.binding, "target_hostname");
344 conn->in.dest_host = dcerpc_binding_get_string_option(s->io.binding, "host");
345 conn->in.dest_ports = lpcfg_smb_ports(lp_ctx);
346 conn->in.called_name = target_hostname;
347 if (conn->in.called_name == NULL) {
348 conn->in.called_name = "*SMBSERVER";
350 conn->in.socket_options = lpcfg_socket_options(lp_ctx);
351 conn->in.service = "IPC$";
352 conn->in.service_type = NULL;
353 conn->in.workgroup = lpcfg_workgroup(lp_ctx);
354 conn->in.gensec_settings = lpcfg_gensec_settings(conn, lp_ctx);
356 lpcfg_smbcli_options(lp_ctx, &conn->in.options);
357 lpcfg_smbcli_session_options(lp_ctx, &conn->in.session_options);
360 * provide proper credentials - user supplied, but allow a
361 * fallback to anonymous if this is an schannel connection
362 * (might be NT4 not allowing machine logins at session
363 * setup) or if asked to do so by the caller (perhaps a SAMR password change?)
365 s->conn.in.credentials = s->io.creds;
366 flags = dcerpc_binding_get_flags(s->io.binding);
367 if (flags & (DCERPC_SCHANNEL|DCERPC_ANON_FALLBACK)) {
368 conn->in.fallback_to_anonymous = true;
370 conn->in.fallback_to_anonymous = false;
373 conn->in.options.min_protocol = lpcfg_client_ipc_min_protocol(lp_ctx);
374 conn->in.options.max_protocol = lpcfg_client_ipc_max_protocol(lp_ctx);
375 if ((flags & DCERPC_SMB1) && (flags & DCERPC_SMB2)) {
377 } else if (flags & DCERPC_SMB2) {
378 if (conn->in.options.min_protocol < PROTOCOL_SMB2_02) {
379 conn->in.options.min_protocol = PROTOCOL_SMB2_02;
381 if (conn->in.options.max_protocol < PROTOCOL_SMB2_02) {
382 conn->in.options.max_protocol = PROTOCOL_LATEST;
384 } else if (flags & DCERPC_SMB1) {
385 conn->in.options.min_protocol = PROTOCOL_NT1;
386 conn->in.options.max_protocol = PROTOCOL_NT1;
391 conn->in.options.signing = lpcfg_client_ipc_signing(lp_ctx);
393 if (s->conn.in.credentials != NULL) {
394 calling_name = cli_credentials_get_workstation(s->conn.in.credentials);
396 if (calling_name == NULL) {
397 calling_name = "SMBCLIENT";
400 if (target_hostname == NULL) {
401 target_hostname = conn->in.dest_host;
404 if (is_ipaddress(conn->in.dest_host)) {
405 dest_address = conn->in.dest_host;
408 subreq = smb_connect_nego_send(s,
412 conn->in.socket_options,
417 conn->in.called_name,
419 if (composite_nomem(subreq, c)) return c;
420 tevent_req_set_callback(subreq,
421 continue_smbXcli_connect,
427 static void continue_smbXcli_connect(struct tevent_req *subreq)
429 struct composite_context *c =
430 tevent_req_callback_data(subreq,
431 struct composite_context);
432 struct pipe_np_smb_state *s =
433 talloc_get_type_abort(c->private_data,
434 struct pipe_np_smb_state);
435 struct smb_composite_connect *conn = &s->conn;
436 struct composite_context *creq = NULL;
437 enum protocol_types protocol;
439 c->status = smb_connect_nego_recv(subreq, s,
440 &conn->in.existing_conn);
442 if (!composite_is_ok(c)) return;
444 protocol = smbXcli_conn_protocol(conn->in.existing_conn);
445 if (protocol >= PROTOCOL_SMB2_02) {
447 * continue with smb2 session setup/tree connect
448 * on the established connection.
450 subreq = smb2_connect_send(s, c->event_ctx,
455 conn->in.credentials,
456 conn->in.fallback_to_anonymous,
457 &conn->in.existing_conn,
458 0, /* previous_session_id */
460 conn->in.socket_options,
461 conn->in.gensec_settings);
462 if (composite_nomem(subreq, c)) return;
463 tevent_req_set_callback(subreq, continue_smb2_connect, c);
468 * continue with smb1 session setup/tree connect
469 * on the established connection.
471 creq = smb_composite_connect_send(conn, s->io.conn,
474 if (composite_nomem(creq, c)) return;
476 composite_continue(c, creq, continue_smb_connect, c);
482 Receive result of a rpc connection to a rpc pipe on SMB
484 static NTSTATUS dcerpc_pipe_connect_ncacn_np_smb_recv(struct composite_context *c)
486 NTSTATUS status = composite_wait(c);
493 Stage 2 of ncacn_np_smb2: Open a named pipe after successful smb2 connection
495 static void continue_smb2_connect(struct tevent_req *subreq)
497 struct composite_context *c =
498 tevent_req_callback_data(subreq,
499 struct composite_context);
500 struct pipe_np_smb_state *s = talloc_get_type(c->private_data,
501 struct pipe_np_smb_state);
504 /* receive result of smb2 connect request */
505 c->status = smb2_connect_recv(subreq, s->io.conn, &t);
507 if (!composite_is_ok(c)) return;
509 s->io.smb.conn = t->session->transport->conn;
510 s->io.smb.session = t->session->smbXcli;
511 s->io.smb.tcon = t->smbXcli;
512 s->io.smb.pipe_name = dcerpc_binding_get_string_option(s->io.binding,
515 c->status = dcerpc_binding_set_pointer_option(s->io.binding,
519 if (!composite_is_ok(c)) return;
521 c->status = dcerpc_binding_set_pointer_option(s->io.binding,
523 struct smbXcli_session,
525 if (!composite_is_ok(c)) return;
527 c->status = dcerpc_binding_set_pointer_option(s->io.binding,
531 if (!composite_is_ok(c)) return;
533 continue_smb_open(c);
537 struct pipe_ip_tcp_state {
538 struct dcerpc_pipe_connect io;
539 const char *localaddr;
541 const char *target_hostname;
547 Stage 2 of ncacn_ip_tcp: rpc pipe opened (or not)
549 static void continue_pipe_open_ncacn_ip_tcp(struct composite_context *ctx)
551 struct composite_context *c = talloc_get_type(ctx->async.private_data,
552 struct composite_context);
553 struct pipe_ip_tcp_state *s = talloc_get_type(c->private_data,
554 struct pipe_ip_tcp_state);
555 char *localaddr = NULL;
556 char *remoteaddr = NULL;
558 /* receive result of named pipe open request on tcp/ip */
559 c->status = dcerpc_pipe_open_tcp_recv(ctx, s, &localaddr, &remoteaddr);
560 if (!composite_is_ok(c)) return;
562 c->status = dcerpc_binding_set_string_option(s->io.binding,
565 if (!composite_is_ok(c)) return;
567 c->status = dcerpc_binding_set_string_option(s->io.binding,
570 if (!composite_is_ok(c)) return;
577 Initiate async open of a rpc connection to a rpc pipe on TCP/IP using
578 the binding structure to determine the endpoint and options
580 static struct composite_context* dcerpc_pipe_connect_ncacn_ip_tcp_send(TALLOC_CTX *mem_ctx,
581 struct dcerpc_pipe_connect *io)
583 struct composite_context *c;
584 struct pipe_ip_tcp_state *s;
585 struct composite_context *pipe_req;
586 const char *endpoint;
588 /* composite context allocation and setup */
589 c = composite_create(mem_ctx, io->conn->event_ctx);
590 if (c == NULL) return NULL;
592 s = talloc_zero(c, struct pipe_ip_tcp_state);
593 if (composite_nomem(s, c)) return c;
596 /* store input parameters in state structure */
598 s->localaddr = dcerpc_binding_get_string_option(io->binding,
600 s->host = dcerpc_binding_get_string_option(io->binding, "host");
601 s->target_hostname = dcerpc_binding_get_string_option(io->binding,
603 endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
604 /* port number is a binding endpoint here */
605 if (endpoint != NULL) {
606 s->port = atoi(endpoint);
610 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
614 /* send pipe open request on tcp/ip */
615 pipe_req = dcerpc_pipe_open_tcp_send(s->io.conn, s->localaddr, s->host, s->target_hostname,
616 s->port, io->resolve_ctx);
617 composite_continue(c, pipe_req, continue_pipe_open_ncacn_ip_tcp, c);
623 Receive result of a rpc connection to a rpc pipe on TCP/IP
625 static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp_recv(struct composite_context *c)
627 NTSTATUS status = composite_wait(c);
634 struct pipe_http_state {
635 struct dcerpc_pipe_connect io;
636 const char *localaddr;
637 const char *target_hostname;
638 const char *rpc_server;
639 uint32_t rpc_server_port;
641 uint32_t rpc_proxy_port;
643 uint32_t http_proxy_port;
646 enum http_auth_method http_auth;
647 struct loadparm_context *lp_ctx;
651 Stage 2 of ncacn_http: rpc pipe opened (or not)
653 static void continue_pipe_open_ncacn_http(struct tevent_req *subreq)
655 struct composite_context *c = NULL;
656 struct pipe_http_state *s = NULL;
657 struct tstream_context *stream = NULL;
658 struct tevent_queue *queue = NULL;
660 c = tevent_req_callback_data(subreq, struct composite_context);
661 s = talloc_get_type(c->private_data, struct pipe_http_state);
663 /* receive result of RoH connect request */
664 c->status = dcerpc_pipe_open_roh_recv(subreq, s->io.conn,
667 if (!composite_is_ok(c)) return;
669 s->io.conn->transport.transport = NCACN_HTTP;
670 s->io.conn->transport.stream = stream;
671 s->io.conn->transport.write_queue = queue;
672 s->io.conn->transport.pending_reads = 0;
673 s->io.conn->server_name = strupper_talloc(s->io.conn,
680 Initiate async open of a rpc connection to a rpc pipe using HTTP transport,
681 and using the binding structure to determine the endpoint and options
683 static struct composite_context* dcerpc_pipe_connect_ncacn_http_send(
684 TALLOC_CTX *mem_ctx, struct dcerpc_pipe_connect *io,
685 struct loadparm_context *lp_ctx)
687 struct composite_context *c;
688 struct pipe_http_state *s;
689 struct tevent_req *subreq;
690 const char *endpoint;
691 const char *use_proxy;
696 /* composite context allocation and setup */
697 c = composite_create(mem_ctx, io->conn->event_ctx);
698 if (c == NULL) return NULL;
700 s = talloc_zero(c, struct pipe_http_state);
701 if (composite_nomem(s, c)) return c;
704 /* store input parameters in state structure */
707 s->localaddr = dcerpc_binding_get_string_option(io->binding,
709 /* RPC server and port (the endpoint) */
710 s->rpc_server = dcerpc_binding_get_string_option(io->binding, "host");
711 s->target_hostname = dcerpc_binding_get_string_option(io->binding,
713 endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
714 if (endpoint == NULL) {
715 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
718 s->rpc_server_port = atoi(endpoint);
719 if (s->rpc_server_port == 0) {
720 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
725 opt = dcerpc_binding_get_string_option(io->binding, "HttpUseTls");
727 if (strcasecmp(opt, "true") == 0) {
729 } else if (strcasecmp(opt, "false") == 0) {
732 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
740 proxy = port = talloc_strdup(s, dcerpc_binding_get_string_option(
741 io->binding, "RpcProxy"));
742 s->rpc_proxy = strsep(&port, ":");
744 s->rpc_proxy_port = atoi(port);
746 s->rpc_proxy_port = s->use_tls ? 443 : 80;
748 if (s->rpc_proxy == NULL) {
749 s->rpc_proxy = talloc_strdup(s, s->rpc_server);
750 if (composite_nomem(s->rpc_proxy, c)) return c;
754 proxy = port = talloc_strdup(s, dcerpc_binding_get_string_option(
755 io->binding, "HttpProxy"));
756 s->http_proxy = strsep(&port, ":");
758 s->http_proxy_port = atoi(port);
760 s->http_proxy_port = s->use_tls ? 443 : 80;
763 /* Use local proxy */
764 use_proxy = dcerpc_binding_get_string_option(io->binding,
765 "HttpConnectOption");
766 if (use_proxy && strcasecmp(use_proxy, "UseHttpProxy")) {
770 /* If use local proxy set, the http proxy should be provided */
771 if (s->use_proxy && !s->http_proxy) {
772 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
776 /* Check which HTTP authentication method to use */
777 opt = dcerpc_binding_get_string_option(io->binding, "HttpAuthOption");
779 if (strcasecmp(opt, "basic") == 0) {
780 s->http_auth = HTTP_AUTH_BASIC;
781 } else if (strcasecmp(opt, "ntlm") == 0) {
782 s->http_auth = HTTP_AUTH_NTLM;
783 } else if (strcasecmp(opt, "negotiate") == 0) {
784 s->http_auth = HTTP_AUTH_NEGOTIATE;
786 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
790 s->http_auth = HTTP_AUTH_NTLM;
793 subreq = dcerpc_pipe_open_roh_send(s->io.conn, s->localaddr,
794 s->rpc_server, s->rpc_server_port,
795 s->rpc_proxy, s->rpc_proxy_port,
796 s->http_proxy, s->http_proxy_port,
797 s->use_tls, s->use_proxy,
798 s->io.creds, io->resolve_ctx,
799 s->lp_ctx, s->http_auth);
800 if (composite_nomem(subreq, c)) return c;
802 tevent_req_set_callback(subreq, continue_pipe_open_ncacn_http, c);
806 static NTSTATUS dcerpc_pipe_connect_ncacn_http_recv(struct composite_context *c)
808 return composite_wait_free(c);
812 struct pipe_unix_state {
813 struct dcerpc_pipe_connect io;
819 Stage 2 of ncacn_unix: rpc pipe opened (or not)
821 static void continue_pipe_open_ncacn_unix_stream(struct composite_context *ctx)
823 struct composite_context *c = talloc_get_type(ctx->async.private_data,
824 struct composite_context);
826 /* receive result of pipe open request on unix socket */
827 c->status = dcerpc_pipe_open_unix_stream_recv(ctx);
828 if (!composite_is_ok(c)) return;
835 Initiate async open of a rpc connection to a rpc pipe on unix socket using
836 the binding structure to determine the endpoint and options
838 static struct composite_context* dcerpc_pipe_connect_ncacn_unix_stream_send(TALLOC_CTX *mem_ctx,
839 struct dcerpc_pipe_connect *io)
841 struct composite_context *c;
842 struct pipe_unix_state *s;
843 struct composite_context *pipe_req;
845 /* composite context allocation and setup */
846 c = composite_create(mem_ctx, io->conn->event_ctx);
847 if (c == NULL) return NULL;
849 s = talloc_zero(c, struct pipe_unix_state);
850 if (composite_nomem(s, c)) return c;
853 /* prepare pipe open parameters and store them in state structure
854 also, verify whether biding endpoint is not null */
857 s->path = dcerpc_binding_get_string_option(io->binding, "endpoint");
858 if (s->path == NULL) {
859 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
863 /* send pipe open request on unix socket */
864 pipe_req = dcerpc_pipe_open_unix_stream_send(s->io.conn, s->path);
865 composite_continue(c, pipe_req, continue_pipe_open_ncacn_unix_stream, c);
871 Receive result of a rpc connection to a pipe on unix socket
873 static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream_recv(struct composite_context *c)
875 NTSTATUS status = composite_wait(c);
882 struct pipe_ncalrpc_state {
883 struct dcerpc_pipe_connect io;
886 static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c);
889 Stage 2 of ncalrpc: rpc pipe opened (or not)
891 static void continue_pipe_open_ncalrpc(struct composite_context *ctx)
893 struct composite_context *c = talloc_get_type(ctx->async.private_data,
894 struct composite_context);
896 /* receive result of pipe open request on ncalrpc */
897 c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
898 if (!composite_is_ok(c)) return;
905 Initiate async open of a rpc connection request on NCALRPC using
906 the binding structure to determine the endpoint and options
908 static struct composite_context* dcerpc_pipe_connect_ncalrpc_send(TALLOC_CTX *mem_ctx,
909 struct dcerpc_pipe_connect *io)
911 struct composite_context *c;
912 struct pipe_ncalrpc_state *s;
913 struct composite_context *pipe_req;
914 const char *endpoint;
916 /* composite context allocation and setup */
917 c = composite_create(mem_ctx, io->conn->event_ctx);
918 if (c == NULL) return NULL;
920 s = talloc_zero(c, struct pipe_ncalrpc_state);
921 if (composite_nomem(s, c)) return c;
924 /* store input parameters in state structure */
927 endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
928 if (endpoint == NULL) {
929 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
933 /* send pipe open request */
934 pipe_req = dcerpc_pipe_open_pipe_send(s->io.conn,
937 composite_continue(c, pipe_req, continue_pipe_open_ncalrpc, c);
943 Receive result of a rpc connection to a rpc pipe on NCALRPC
945 static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c)
947 NTSTATUS status = composite_wait(c);
954 struct pipe_connect_state {
955 struct dcerpc_pipe *pipe;
956 struct dcerpc_binding *binding;
957 const struct ndr_interface_table *table;
958 struct cli_credentials *credentials;
959 struct loadparm_context *lp_ctx;
963 static void continue_map_binding(struct composite_context *ctx);
964 static void continue_connect(struct composite_context *c, struct pipe_connect_state *s);
965 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx);
966 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx);
967 static void continue_pipe_connect_ncacn_http(struct composite_context *ctx);
968 static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx);
969 static void continue_pipe_connect_ncalrpc(struct composite_context *ctx);
970 static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s);
971 static void continue_pipe_auth(struct composite_context *ctx);
975 Stage 2 of pipe_connect_b: Receive result of endpoint mapping
977 static void continue_map_binding(struct composite_context *ctx)
979 struct composite_context *c = talloc_get_type(ctx->async.private_data,
980 struct composite_context);
981 struct pipe_connect_state *s = talloc_get_type(c->private_data,
982 struct pipe_connect_state);
983 const char *endpoint;
985 c->status = dcerpc_epm_map_binding_recv(ctx);
986 if (!composite_is_ok(c)) return;
988 endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
989 DEBUG(4,("Mapped to DCERPC endpoint %s\n", endpoint));
991 continue_connect(c, s);
996 Stage 2 of pipe_connect_b: Continue connection after endpoint is known
998 static void continue_connect(struct composite_context *c, struct pipe_connect_state *s)
1000 struct dcerpc_pipe_connect pc;
1002 /* potential exits to another stage by sending an async request */
1003 struct composite_context *ncacn_np_smb_req;
1004 struct composite_context *ncacn_ip_tcp_req;
1005 struct composite_context *ncacn_http_req;
1006 struct composite_context *ncacn_unix_req;
1007 struct composite_context *ncalrpc_req;
1008 enum dcerpc_transport_t transport;
1009 const char *endpoint = NULL;
1011 /* dcerpc pipe connect input parameters */
1013 pc.conn = s->pipe->conn;
1014 pc.binding = s->binding;
1015 pc.interface = s->table;
1016 pc.creds = s->credentials;
1017 pc.resolve_ctx = lpcfg_resolve_context(s->lp_ctx);
1019 transport = dcerpc_binding_get_transport(s->binding);
1021 /* connect dcerpc pipe depending on required transport */
1022 switch (transport) {
1028 endpoint = dcerpc_binding_get_string_option(pc.binding,
1030 if (endpoint != NULL) {
1033 pc.smb.pipe_name = endpoint;
1035 status = dcerpc_binding_get_smbXcli_pointers(pc.binding,
1039 if (!NT_STATUS_IS_OK(status)) {
1040 ZERO_STRUCT(pc.smb);
1044 ncacn_np_smb_req = dcerpc_pipe_connect_ncacn_np_smb_send(c, &pc, s->lp_ctx);
1045 composite_continue(c, ncacn_np_smb_req, continue_pipe_connect_ncacn_np_smb, c);
1049 ncacn_ip_tcp_req = dcerpc_pipe_connect_ncacn_ip_tcp_send(c, &pc);
1050 composite_continue(c, ncacn_ip_tcp_req, continue_pipe_connect_ncacn_ip_tcp, c);
1054 ncacn_http_req = dcerpc_pipe_connect_ncacn_http_send(c, &pc, s->lp_ctx);
1055 composite_continue(c, ncacn_http_req, continue_pipe_connect_ncacn_http, c);
1058 case NCACN_UNIX_STREAM:
1059 ncacn_unix_req = dcerpc_pipe_connect_ncacn_unix_stream_send(c, &pc);
1060 composite_continue(c, ncacn_unix_req, continue_pipe_connect_ncacn_unix, c);
1064 pc.ncalrpc.dir = lpcfg_ncalrpc_dir(s->lp_ctx);
1065 c->status = dcerpc_binding_set_string_option(s->binding, "ncalrpc_dir",
1067 if (!composite_is_ok(c)) return;
1068 ncalrpc_req = dcerpc_pipe_connect_ncalrpc_send(c, &pc);
1069 composite_continue(c, ncalrpc_req, continue_pipe_connect_ncalrpc, c);
1073 /* looks like a transport we don't support now */
1074 composite_error(c, NT_STATUS_NOT_SUPPORTED);
1080 Stage 3 of pipe_connect_b: Receive result of pipe connect request on
1083 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx)
1085 struct composite_context *c = talloc_get_type(ctx->async.private_data,
1086 struct composite_context);
1087 struct pipe_connect_state *s = talloc_get_type(c->private_data,
1088 struct pipe_connect_state);
1090 c->status = dcerpc_pipe_connect_ncacn_np_smb_recv(ctx);
1091 if (!composite_is_ok(c)) return;
1093 continue_pipe_connect(c, s);
1098 Stage 3 of pipe_connect_b: Receive result of pipe connect request on tcp/ip
1100 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx)
1102 struct composite_context *c = talloc_get_type(ctx->async.private_data,
1103 struct composite_context);
1104 struct pipe_connect_state *s = talloc_get_type(c->private_data,
1105 struct pipe_connect_state);
1107 c->status = dcerpc_pipe_connect_ncacn_ip_tcp_recv(ctx);
1108 if (!composite_is_ok(c)) return;
1110 continue_pipe_connect(c, s);
1115 Stage 3 of pipe_connect_b: Receive result of pipe connect request on http
1117 static void continue_pipe_connect_ncacn_http(struct composite_context *ctx)
1119 struct composite_context *c = talloc_get_type(ctx->async.private_data,
1120 struct composite_context);
1121 struct pipe_connect_state *s = talloc_get_type(c->private_data,
1122 struct pipe_connect_state);
1124 c->status = dcerpc_pipe_connect_ncacn_http_recv(ctx);
1125 if (!composite_is_ok(c)) return;
1127 continue_pipe_connect(c, s);
1132 Stage 3 of pipe_connect_b: Receive result of pipe connect request on unix socket
1134 static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx)
1136 struct composite_context *c = talloc_get_type(ctx->async.private_data,
1137 struct composite_context);
1138 struct pipe_connect_state *s = talloc_get_type(c->private_data,
1139 struct pipe_connect_state);
1141 c->status = dcerpc_pipe_connect_ncacn_unix_stream_recv(ctx);
1142 if (!composite_is_ok(c)) return;
1144 continue_pipe_connect(c, s);
1149 Stage 3 of pipe_connect_b: Receive result of pipe connect request on local rpc
1151 static void continue_pipe_connect_ncalrpc(struct composite_context *ctx)
1153 struct composite_context *c = talloc_get_type(ctx->async.private_data,
1154 struct composite_context);
1155 struct pipe_connect_state *s = talloc_get_type(c->private_data,
1156 struct pipe_connect_state);
1158 c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
1159 if (!composite_is_ok(c)) return;
1161 continue_pipe_connect(c, s);
1166 Stage 4 of pipe_connect_b: Start an authentication on connected dcerpc pipe
1167 depending on credentials and binding flags passed.
1169 static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s)
1171 struct composite_context *auth_bind_req;
1173 s->pipe->binding = talloc_move(s->pipe, &s->binding);
1175 auth_bind_req = dcerpc_pipe_auth_send(s->pipe, s->pipe->binding, s->table,
1176 s->credentials, s->lp_ctx);
1177 composite_continue(c, auth_bind_req, continue_pipe_auth, c);
1182 Stage 5 of pipe_connect_b: Receive result of pipe authentication request
1183 and say if all went ok
1185 static void continue_pipe_auth(struct composite_context *ctx)
1187 struct composite_context *c = talloc_get_type(ctx->async.private_data,
1188 struct composite_context);
1189 struct pipe_connect_state *s = talloc_get_type(c->private_data, struct pipe_connect_state);
1191 c->status = dcerpc_pipe_auth_recv(ctx, s, &s->pipe);
1192 if (!composite_is_ok(c)) return;
1199 handle timeouts of a dcerpc connect
1201 static void dcerpc_connect_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1202 struct timeval t, void *private_data)
1204 struct composite_context *c = talloc_get_type_abort(private_data,
1205 struct composite_context);
1206 struct pipe_connect_state *s = talloc_get_type_abort(c->private_data, struct pipe_connect_state);
1207 if (!s->pipe->inhibit_timeout_processing) {
1208 composite_error(c, NT_STATUS_IO_TIMEOUT);
1210 s->pipe->timed_out = true;
1215 start a request to open a rpc connection to a rpc pipe, using
1216 specified binding structure to determine the endpoint and options
1218 _PUBLIC_ struct composite_context* dcerpc_pipe_connect_b_send(TALLOC_CTX *parent_ctx,
1219 const struct dcerpc_binding *binding,
1220 const struct ndr_interface_table *table,
1221 struct cli_credentials *credentials,
1222 struct tevent_context *ev,
1223 struct loadparm_context *lp_ctx)
1225 struct composite_context *c;
1226 struct pipe_connect_state *s;
1227 enum dcerpc_transport_t transport;
1228 const char *endpoint = NULL;
1229 struct cli_credentials *epm_creds = NULL;
1231 /* composite context allocation and setup */
1232 c = composite_create(parent_ctx, ev);
1237 s = talloc_zero(c, struct pipe_connect_state);
1238 if (composite_nomem(s, c)) return c;
1239 c->private_data = s;
1241 /* initialise dcerpc pipe structure */
1242 s->pipe = dcerpc_pipe_init(c, ev);
1243 if (composite_nomem(s->pipe, c)) return c;
1245 if (DEBUGLEVEL >= 10)
1246 s->pipe->conn->packet_log_dir = lpcfg_lock_directory(lp_ctx);
1248 /* store parameters in state structure */
1249 s->binding = dcerpc_binding_dup(s, binding);
1250 if (composite_nomem(s->binding, c)) return c;
1252 s->credentials = credentials;
1255 s->pipe->timed_out = false;
1256 s->pipe->inhibit_timeout_processing = false;
1258 tevent_add_timer(c->event_ctx, c,
1259 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1260 dcerpc_connect_timeout_handler, c);
1262 transport = dcerpc_binding_get_transport(s->binding);
1264 switch (transport) {
1268 endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
1270 /* anonymous credentials for rpc connection used to get endpoint mapping */
1271 epm_creds = cli_credentials_init_anon(s);
1272 if (composite_nomem(epm_creds, c)) return c;
1276 endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
1277 epm_creds = credentials;
1283 if (endpoint == NULL) {
1284 struct composite_context *binding_req;
1286 binding_req = dcerpc_epm_map_binding_send(c, s->binding, s->table,
1288 s->pipe->conn->event_ctx,
1290 composite_continue(c, binding_req, continue_map_binding, c);
1294 continue_connect(c, s);
1300 receive result of a request to open a rpc connection to a rpc pipe
1302 _PUBLIC_ NTSTATUS dcerpc_pipe_connect_b_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
1303 struct dcerpc_pipe **p)
1306 struct pipe_connect_state *s;
1308 status = composite_wait(c);
1310 if (NT_STATUS_IS_OK(status)) {
1311 s = talloc_get_type(c->private_data, struct pipe_connect_state);
1312 talloc_steal(mem_ctx, s->pipe);
1321 open a rpc connection to a rpc pipe, using the specified
1322 binding structure to determine the endpoint and options - sync version
1324 _PUBLIC_ NTSTATUS dcerpc_pipe_connect_b(TALLOC_CTX *parent_ctx,
1325 struct dcerpc_pipe **pp,
1326 const struct dcerpc_binding *binding,
1327 const struct ndr_interface_table *table,
1328 struct cli_credentials *credentials,
1329 struct tevent_context *ev,
1330 struct loadparm_context *lp_ctx)
1332 struct composite_context *c;
1334 c = dcerpc_pipe_connect_b_send(parent_ctx, binding, table,
1335 credentials, ev, lp_ctx);
1336 return dcerpc_pipe_connect_b_recv(c, parent_ctx, pp);
1340 struct pipe_conn_state {
1341 struct dcerpc_pipe *pipe;
1345 static void continue_pipe_connect_b(struct composite_context *ctx);
1349 Initiate rpc connection to a rpc pipe, using the specified string
1350 binding to determine the endpoint and options.
1351 The string is to be parsed to a binding structure first.
1353 _PUBLIC_ struct composite_context* dcerpc_pipe_connect_send(TALLOC_CTX *parent_ctx,
1354 const char *binding,
1355 const struct ndr_interface_table *table,
1356 struct cli_credentials *credentials,
1357 struct tevent_context *ev, struct loadparm_context *lp_ctx)
1359 struct composite_context *c;
1360 struct pipe_conn_state *s;
1361 struct dcerpc_binding *b;
1362 struct composite_context *pipe_conn_req;
1364 /* composite context allocation and setup */
1365 c = composite_create(parent_ctx, ev);
1370 s = talloc_zero(c, struct pipe_conn_state);
1371 if (composite_nomem(s, c)) return c;
1372 c->private_data = s;
1374 /* parse binding string to the structure */
1375 c->status = dcerpc_parse_binding(c, binding, &b);
1376 if (!NT_STATUS_IS_OK(c->status)) {
1377 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", binding));
1378 composite_error(c, c->status);
1382 DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(c, b)));
1385 start connecting to a rpc pipe after binding structure
1388 pipe_conn_req = dcerpc_pipe_connect_b_send(c, b, table,
1389 credentials, ev, lp_ctx);
1390 composite_continue(c, pipe_conn_req, continue_pipe_connect_b, c);
1396 Stage 2 of pipe_connect: Receive result of actual pipe connect request
1397 and say if we're done ok
1399 static void continue_pipe_connect_b(struct composite_context *ctx)
1401 struct composite_context *c = talloc_get_type(ctx->async.private_data,
1402 struct composite_context);
1403 struct pipe_conn_state *s = talloc_get_type(c->private_data,
1404 struct pipe_conn_state);
1406 c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe);
1407 talloc_steal(s, s->pipe);
1408 if (!composite_is_ok(c)) return;
1415 Receive result of pipe connect (using binding string) request
1416 and return connected pipe structure.
1418 NTSTATUS dcerpc_pipe_connect_recv(struct composite_context *c,
1419 TALLOC_CTX *mem_ctx,
1420 struct dcerpc_pipe **pp)
1423 struct pipe_conn_state *s;
1425 status = composite_wait(c);
1426 if (NT_STATUS_IS_OK(status)) {
1427 s = talloc_get_type(c->private_data, struct pipe_conn_state);
1428 *pp = talloc_steal(mem_ctx, s->pipe);
1436 Open a rpc connection to a rpc pipe, using the specified string
1437 binding to determine the endpoint and options - sync version
1439 _PUBLIC_ NTSTATUS dcerpc_pipe_connect(TALLOC_CTX *parent_ctx,
1440 struct dcerpc_pipe **pp,
1441 const char *binding,
1442 const struct ndr_interface_table *table,
1443 struct cli_credentials *credentials,
1444 struct tevent_context *ev,
1445 struct loadparm_context *lp_ctx)
1447 struct composite_context *c;
1448 c = dcerpc_pipe_connect_send(parent_ctx, binding,
1449 table, credentials, ev, lp_ctx);
1450 return dcerpc_pipe_connect_recv(c, parent_ctx, pp);