LCOV - code coverage report
Current view: top level - source4/librpc/rpc - dcerpc_connect.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 346 519 66.7 %
Date: 2024-01-11 09:59:51 Functions: 27 36 75.0 %

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

Generated by: LCOV version 1.14