LCOV - code coverage report
Current view: top level - source4/librpc/rpc - dcerpc_connect.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 289 468 61.8 %
Date: 2024-06-13 04:01:37 Functions: 26 36 72.2 %

          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        3630 : static void continue_pipe_open_smb(struct composite_context *ctx)
      70             : {
      71        3630 :         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        3630 :         c->status = dcerpc_pipe_open_smb_recv(ctx);
      76        3630 :         if (!composite_is_ok(c)) return;
      77             : 
      78        3472 :         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           0 : static void continue_smb_connect(struct composite_context *ctx)
      89             : {
      90           0 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
      91             :                                                       struct composite_context);
      92           0 :         struct pipe_np_smb_state *s = talloc_get_type(c->private_data,
      93             :                                                       struct pipe_np_smb_state);
      94             :         struct smbcli_tree *t;
      95             : 
      96             :         /* receive result of smb connect request */
      97           0 :         c->status = smb_composite_connect_recv(ctx, s->io.conn);
      98           0 :         if (!composite_is_ok(c)) return;
      99             : 
     100           0 :         t = s->conn.out.tree;
     101             : 
     102             :         /* prepare named pipe open parameters */
     103           0 :         s->io.smb.conn = t->session->transport->conn;
     104           0 :         s->io.smb.session = t->session->smbXcli;
     105           0 :         s->io.smb.tcon = t->smbXcli;
     106           0 :         smb1cli_tcon_set_id(s->io.smb.tcon, t->tid);
     107           0 :         s->io.smb.pipe_name = dcerpc_binding_get_string_option(s->io.binding,
     108             :                                                                "endpoint");
     109             : 
     110           0 :         continue_smb_open(c);
     111             : }
     112             : 
     113        3630 : static void continue_smb_open(struct composite_context *c)
     114             : {
     115        3630 :         struct pipe_np_smb_state *s = talloc_get_type(c->private_data,
     116             :                                                       struct pipe_np_smb_state);
     117             :         struct composite_context *open_ctx;
     118             : 
     119             :         /* send named pipe open request */
     120        3630 :         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        3630 :         if (composite_nomem(open_ctx, c)) return;
     127             : 
     128        3630 :         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        3650 : 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             :         struct composite_context *c;
     139             :         struct pipe_np_smb_state *s;
     140        3650 :         struct tevent_req *subreq = NULL;
     141             :         struct smb_composite_connect *conn;
     142             :         uint32_t flags;
     143        3650 :         const char *target_hostname = NULL;
     144        3650 :         const char *dest_address = NULL;
     145        3650 :         const char *calling_name = NULL;
     146             : 
     147             :         /* composite context allocation and setup */
     148        3650 :         c = composite_create(mem_ctx, io->conn->event_ctx);
     149        3650 :         if (c == NULL) return NULL;
     150             : 
     151        3650 :         s = talloc_zero(c, struct pipe_np_smb_state);
     152        3650 :         if (composite_nomem(s, c)) return c;
     153        3650 :         c->private_data = s;
     154             : 
     155        3650 :         s->io  = *io;
     156        3650 :         conn   = &s->conn;
     157             : 
     158        3650 :         if (smbXcli_conn_is_connected(s->io.smb.conn)) {
     159           0 :                 continue_smb_open(c);
     160           0 :                 return c;
     161             :         }
     162             : 
     163        3650 :         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        3650 :         target_hostname = dcerpc_binding_get_string_option(s->io.binding, "target_hostname");
     171        3650 :         conn->in.dest_host = dcerpc_binding_get_string_option(s->io.binding, "host");
     172        3650 :         conn->in.dest_ports = lpcfg_smb_ports(lp_ctx);
     173        3650 :         conn->in.called_name = target_hostname;
     174        3650 :         if (conn->in.called_name == NULL) {
     175           0 :                 conn->in.called_name = "*SMBSERVER";
     176             :         }
     177        3650 :         conn->in.socket_options         = lpcfg_socket_options(lp_ctx);
     178        3650 :         conn->in.service                = "IPC$";
     179        3650 :         conn->in.service_type           = NULL;
     180        3650 :         conn->in.workgroup           = lpcfg_workgroup(lp_ctx);
     181        3650 :         conn->in.gensec_settings = lpcfg_gensec_settings(conn, lp_ctx);
     182             : 
     183        3650 :         lpcfg_smbcli_options(lp_ctx, &conn->in.options);
     184        3650 :         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        3650 :         s->conn.in.credentials = s->io.creds;
     193        3650 :         flags = dcerpc_binding_get_flags(s->io.binding);
     194        3650 :         if (flags & (DCERPC_SCHANNEL|DCERPC_ANON_FALLBACK)) {
     195         364 :                 conn->in.fallback_to_anonymous  = true;
     196             :         } else {
     197        3286 :                 conn->in.fallback_to_anonymous  = false;
     198             :         }
     199             : 
     200        3650 :         conn->in.options.min_protocol = lpcfg_client_ipc_min_protocol(lp_ctx);
     201        3650 :         conn->in.options.max_protocol = lpcfg_client_ipc_max_protocol(lp_ctx);
     202        3650 :         if ((flags & DCERPC_SMB1) && (flags & DCERPC_SMB2)) {
     203             :                 /* auto */
     204        3650 :         } else if (flags & DCERPC_SMB2) {
     205          31 :                 if (conn->in.options.min_protocol < PROTOCOL_SMB2_02) {
     206          31 :                         conn->in.options.min_protocol = PROTOCOL_SMB2_02;
     207             :                 }
     208          31 :                 if (conn->in.options.max_protocol < PROTOCOL_SMB2_02) {
     209           0 :                         conn->in.options.max_protocol = PROTOCOL_LATEST;
     210             :                 }
     211        3619 :         } else if (flags & DCERPC_SMB1) {
     212           0 :                 conn->in.options.min_protocol = PROTOCOL_NT1;
     213           0 :                 conn->in.options.max_protocol = PROTOCOL_NT1;
     214             :         } else {
     215             :                 /* auto */
     216             :         }
     217             : 
     218        3650 :         conn->in.options.signing = lpcfg_client_ipc_signing(lp_ctx);
     219             : 
     220        3650 :         if (s->conn.in.credentials != NULL) {
     221        3650 :                 calling_name = cli_credentials_get_workstation(s->conn.in.credentials);
     222             :         }
     223        3650 :         if (calling_name == NULL) {
     224           9 :                 calling_name = "SMBCLIENT";
     225             :         }
     226             : 
     227        3650 :         if (target_hostname == NULL) {
     228           0 :                 target_hostname = conn->in.dest_host;
     229             :         }
     230             : 
     231        3650 :         if (conn->in.dest_host != NULL && is_ipaddress(conn->in.dest_host)) {
     232         110 :                 dest_address = conn->in.dest_host;
     233             :         }
     234             : 
     235        6376 :         subreq = smb_connect_nego_send(s,
     236             :                                        c->event_ctx,
     237             :                                        s->io.resolve_ctx,
     238        3650 :                                        &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        3650 :         if (composite_nomem(subreq, c)) return c;
     247        3650 :         tevent_req_set_callback(subreq,
     248             :                                 continue_smbXcli_connect,
     249             :                                 c);
     250             : 
     251        3650 :         return c;
     252             : }
     253             : 
     254        3650 : static void continue_smbXcli_connect(struct tevent_req *subreq)
     255             : {
     256        2726 :         struct composite_context *c =
     257        3650 :                 tevent_req_callback_data(subreq,
     258             :                 struct composite_context);
     259        2726 :         struct pipe_np_smb_state *s =
     260        3650 :                 talloc_get_type_abort(c->private_data,
     261             :                 struct pipe_np_smb_state);
     262        3650 :         struct smb_composite_connect *conn = &s->conn;
     263        3650 :         struct composite_context *creq = NULL;
     264             :         enum protocol_types protocol;
     265             : 
     266        3650 :         c->status = smb_connect_nego_recv(subreq, s,
     267             :                                           &conn->in.existing_conn);
     268        3650 :         TALLOC_FREE(subreq);
     269        3650 :         if (!composite_is_ok(c)) return;
     270             : 
     271        3649 :         protocol = smbXcli_conn_protocol(conn->in.existing_conn);
     272        3649 :         if (protocol >= PROTOCOL_SMB2_02) {
     273             :                 /*
     274             :                  * continue with smb2 session setup/tree connect
     275             :                  * on the established connection.
     276             :                  */
     277        9099 :                 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        3649 :                                 conn->in.fallback_to_anonymous,
     284             :                                 &conn->in.existing_conn,
     285             :                                 0, /* previous_session_id */
     286        3649 :                                 &conn->in.options,
     287             :                                 conn->in.socket_options,
     288             :                                 conn->in.gensec_settings);
     289        3649 :                 if (composite_nomem(subreq, c)) return;
     290        3649 :                 tevent_req_set_callback(subreq, continue_smb2_connect, c);
     291        3649 :                 return;
     292             :         }
     293             : 
     294             :         /*
     295             :          * continue with smb1 session setup/tree connect
     296             :          * on the established connection.
     297             :          */
     298           0 :         creq = smb_composite_connect_send(conn, s->io.conn,
     299             :                                           s->io.resolve_ctx,
     300             :                                           c->event_ctx);
     301           0 :         if (composite_nomem(creq, c)) return;
     302             : 
     303           0 :         composite_continue(c, creq, continue_smb_connect, c);
     304           0 :         return;
     305             : }
     306             : 
     307             : 
     308             : /*
     309             :   Receive result of a rpc connection to a rpc pipe on SMB
     310             : */
     311        3650 : static NTSTATUS dcerpc_pipe_connect_ncacn_np_smb_recv(struct composite_context *c)
     312             : {
     313        3650 :         NTSTATUS status = composite_wait(c);
     314             : 
     315        3650 :         talloc_free(c);
     316        3650 :         return status;
     317             : }
     318             : 
     319             : /*
     320             :   Stage 2 of ncacn_np_smb2: Open a named pipe after successful smb2 connection
     321             : */
     322        3649 : static void continue_smb2_connect(struct tevent_req *subreq)
     323             : {
     324        2725 :         struct composite_context *c =
     325        3649 :                 tevent_req_callback_data(subreq,
     326             :                 struct composite_context);
     327        3649 :         struct pipe_np_smb_state *s = talloc_get_type(c->private_data,
     328             :                                                       struct pipe_np_smb_state);
     329             :         struct smb2_tree *t;
     330             : 
     331             :         /* receive result of smb2 connect request */
     332        3649 :         c->status = smb2_connect_recv(subreq, s->io.conn, &t);
     333        3649 :         TALLOC_FREE(subreq);
     334        3649 :         if (!composite_is_ok(c)) return;
     335             : 
     336        3630 :         s->io.smb.conn = t->session->transport->conn;
     337        3630 :         s->io.smb.session = t->session->smbXcli;
     338        3630 :         s->io.smb.tcon = t->smbXcli;
     339        3630 :         s->io.smb.pipe_name = dcerpc_binding_get_string_option(s->io.binding,
     340             :                                                                "endpoint");
     341             : 
     342        3630 :         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       13844 : static void continue_pipe_open_ncacn_ip_tcp(struct composite_context *ctx)
     359             : {
     360       13844 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
     361             :                                                       struct composite_context);
     362       13844 :         struct pipe_ip_tcp_state *s = talloc_get_type(c->private_data,
     363             :                                                       struct pipe_ip_tcp_state);
     364       13844 :         char *localaddr = NULL;
     365       13844 :         char *remoteaddr = NULL;
     366             : 
     367             :         /* receive result of named pipe open request on tcp/ip */
     368       13844 :         c->status = dcerpc_pipe_open_tcp_recv(ctx, s, &localaddr, &remoteaddr);
     369       18412 :         if (!composite_is_ok(c)) return;
     370             : 
     371        9040 :         c->status = dcerpc_binding_set_string_option(s->io.binding,
     372             :                                                      "localaddress",
     373             :                                                      localaddr);
     374        9040 :         if (!composite_is_ok(c)) return;
     375             : 
     376        9040 :         c->status = dcerpc_binding_set_string_option(s->io.binding,
     377             :                                                      "host",
     378             :                                                      remoteaddr);
     379        9040 :         if (!composite_is_ok(c)) return;
     380             : 
     381        9040 :         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       13846 : static struct composite_context* dcerpc_pipe_connect_ncacn_ip_tcp_send(TALLOC_CTX *mem_ctx,
     390             :                                                                        struct dcerpc_pipe_connect *io)
     391             : {
     392             :         struct composite_context *c;
     393             :         struct pipe_ip_tcp_state *s;
     394             :         struct composite_context *pipe_req;
     395             :         const char *endpoint;
     396             : 
     397             :         /* composite context allocation and setup */
     398       13846 :         c = composite_create(mem_ctx, io->conn->event_ctx);
     399       13846 :         if (c == NULL) return NULL;
     400             : 
     401       13846 :         s = talloc_zero(c, struct pipe_ip_tcp_state);
     402       13846 :         if (composite_nomem(s, c)) return c;
     403       13846 :         c->private_data = s;
     404             : 
     405             :         /* store input parameters in state structure */
     406       13846 :         s->io = *io;
     407       13846 :         s->localaddr = dcerpc_binding_get_string_option(io->binding,
     408             :                                                         "localaddress");
     409       13846 :         s->host = dcerpc_binding_get_string_option(io->binding, "host");
     410       13846 :         s->target_hostname = dcerpc_binding_get_string_option(io->binding,
     411             :                                                               "target_hostname");
     412       13846 :         endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
     413             :         /* port number is a binding endpoint here */
     414       13846 :         if (endpoint != NULL) {
     415       13846 :                 s->port = atoi(endpoint);
     416             :         }
     417             : 
     418       13846 :         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       13846 :         pipe_req = dcerpc_pipe_open_tcp_send(s->io.conn, s->localaddr, s->host, s->target_hostname,
     425             :                                              s->port, io->resolve_ctx);
     426       13846 :         composite_continue(c, pipe_req, continue_pipe_open_ncacn_ip_tcp, c);
     427       13846 :         return c;
     428             : }
     429             : 
     430             : 
     431             : /*
     432             :   Receive result of a rpc connection to a rpc pipe on TCP/IP
     433             : */
     434       13844 : static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp_recv(struct composite_context *c)
     435             : {
     436       13844 :         NTSTATUS status = composite_wait(c);
     437             :         
     438       13844 :         talloc_free(c);
     439       13844 :         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             :         struct composite_context *c;
     497             :         struct pipe_http_state *s;
     498             :         struct tevent_req *subreq;
     499             :         const char *endpoint;
     500             :         const char *use_proxy;
     501             :         char *proxy;
     502             :         char *port;
     503             :         const char *opt;
     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             :         struct composite_context *c;
     651             :         struct pipe_unix_state *s;
     652             :         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        1280 : static void continue_pipe_open_ncalrpc(struct composite_context *ctx)
     701             : {
     702        1280 :         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        1280 :         c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
     707        1280 :         if (!composite_is_ok(c)) return;
     708             : 
     709        1280 :         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        1280 : static struct composite_context* dcerpc_pipe_connect_ncalrpc_send(TALLOC_CTX *mem_ctx,
     718             :                                                                   struct dcerpc_pipe_connect *io)
     719             : {
     720             :         struct composite_context *c;
     721             :         struct pipe_ncalrpc_state *s;
     722             :         struct composite_context *pipe_req;
     723             :         const char *endpoint;
     724             : 
     725             :         /* composite context allocation and setup */
     726        1280 :         c = composite_create(mem_ctx, io->conn->event_ctx);
     727        1280 :         if (c == NULL) return NULL;
     728             : 
     729        1280 :         s = talloc_zero(c, struct pipe_ncalrpc_state);
     730        1280 :         if (composite_nomem(s, c)) return c;
     731        1280 :         c->private_data = s;
     732             :         
     733             :         /* store input parameters in state structure */
     734        1280 :         s->io  = *io;
     735             : 
     736        1280 :         endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
     737        1280 :         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        1280 :         pipe_req = dcerpc_pipe_open_pipe_send(s->io.conn,
     744             :                                               s->io.ncalrpc.dir,
     745             :                                               endpoint);
     746        1280 :         composite_continue(c, pipe_req, continue_pipe_open_ncalrpc, c);
     747        1280 :         return c;
     748             : }
     749             : 
     750             : 
     751             : /*
     752             :   Receive result of a rpc connection to a rpc pipe on NCALRPC
     753             : */
     754        2560 : static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c)
     755             : {
     756        2560 :         NTSTATUS status = composite_wait(c);
     757             :         
     758        2560 :         talloc_free(c);
     759        2560 :         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       22776 : static void continue_map_binding(struct composite_context *ctx)
     787             : {
     788       22776 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
     789             :                                                       struct composite_context);
     790       22776 :         struct pipe_connect_state *s = talloc_get_type(c->private_data,
     791             :                                                        struct pipe_connect_state);
     792             :         const char *endpoint;
     793             : 
     794       22776 :         c->status = dcerpc_epm_map_binding_recv(ctx);
     795       22776 :         if (!composite_is_ok(c)) return;
     796             : 
     797       17972 :         endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
     798       17972 :         DEBUG(4,("Mapped to DCERPC endpoint %s\n", endpoint));
     799             : 
     800       17972 :         continue_connect(c, s);
     801             : }
     802             : 
     803             : 
     804             : /*
     805             :   Stage 2 of pipe_connect_b: Continue connection after endpoint is known
     806             : */
     807       18776 : static void continue_connect(struct composite_context *c, struct pipe_connect_state *s)
     808             : {
     809             :         struct dcerpc_pipe_connect pc;
     810             : 
     811             :         /* potential exits to another stage by sending an async request */
     812             :         struct composite_context *ncacn_np_smb_req;
     813             :         struct composite_context *ncacn_ip_tcp_req;
     814             :         struct composite_context *ncacn_http_req;
     815             :         struct composite_context *ncacn_unix_req;
     816             :         struct composite_context *ncalrpc_req;
     817             :         enum dcerpc_transport_t transport;
     818             : 
     819             :         /* dcerpc pipe connect input parameters */
     820       18776 :         ZERO_STRUCT(pc);
     821       18776 :         pc.conn         = s->pipe->conn;
     822       18776 :         pc.binding      = s->binding;
     823       18776 :         pc.interface    = s->table;
     824       18776 :         pc.creds        = s->credentials;
     825       18776 :         pc.resolve_ctx  = lpcfg_resolve_context(s->lp_ctx);
     826             : 
     827       18776 :         transport = dcerpc_binding_get_transport(s->binding);
     828             : 
     829             :         /* connect dcerpc pipe depending on required transport */
     830       18776 :         switch (transport) {
     831        3650 :         case NCACN_NP:
     832             :                 /*
     833             :                  * SMB1/2/3...
     834             :                  */
     835        3650 :                 ncacn_np_smb_req = dcerpc_pipe_connect_ncacn_np_smb_send(c, &pc, s->lp_ctx);
     836        3650 :                 composite_continue(c, ncacn_np_smb_req, continue_pipe_connect_ncacn_np_smb, c);
     837        4818 :                 return;
     838             : 
     839       13846 :         case NCACN_IP_TCP:
     840       13846 :                 ncacn_ip_tcp_req = dcerpc_pipe_connect_ncacn_ip_tcp_send(c, &pc);
     841       13846 :                 composite_continue(c, ncacn_ip_tcp_req, continue_pipe_connect_ncacn_ip_tcp, c);
     842       13846 :                 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        1280 :         case NCALRPC:
     855        1280 :                 pc.ncalrpc.dir = lpcfg_ncalrpc_dir(s->lp_ctx);
     856        1280 :                 c->status = dcerpc_binding_set_string_option(s->binding, "ncalrpc_dir",
     857             :                                                              pc.ncalrpc.dir);
     858        1280 :                 if (!composite_is_ok(c)) return;
     859        1280 :                 ncalrpc_req = dcerpc_pipe_connect_ncalrpc_send(c, &pc);
     860        1280 :                 composite_continue(c, ncalrpc_req, continue_pipe_connect_ncalrpc, c);
     861        1280 :                 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        3650 : static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx)
     875             : {
     876        3650 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
     877             :                                                       struct composite_context);
     878        3650 :         struct pipe_connect_state *s = talloc_get_type(c->private_data,
     879             :                                                        struct pipe_connect_state);
     880             : 
     881        3650 :         c->status = dcerpc_pipe_connect_ncacn_np_smb_recv(ctx);
     882        3650 :         if (!composite_is_ok(c)) return;
     883             :         
     884        3472 :         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       13844 : static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx)
     892             : {
     893       13844 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
     894             :                                                       struct composite_context);
     895       13844 :         struct pipe_connect_state *s = talloc_get_type(c->private_data,
     896             :                                                        struct pipe_connect_state);
     897             : 
     898       13844 :         c->status = dcerpc_pipe_connect_ncacn_ip_tcp_recv(ctx);
     899       13844 :         if (!composite_is_ok(c)) return;
     900             : 
     901        9040 :         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        1280 : static void continue_pipe_connect_ncalrpc(struct composite_context *ctx)
     943             : {
     944        1280 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
     945             :                                                       struct composite_context);
     946        1280 :         struct pipe_connect_state *s = talloc_get_type(c->private_data,
     947             :                                                        struct pipe_connect_state);
     948             :         
     949        1280 :         c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
     950        1280 :         if (!composite_is_ok(c)) return;
     951             : 
     952        1280 :         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       13792 : static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s)
     961             : {
     962             :         struct composite_context *auth_bind_req;
     963             : 
     964       13792 :         s->pipe->binding = dcerpc_binding_dup(s->pipe, s->binding);
     965       13792 :         if (composite_nomem(s->pipe->binding, c)) {
     966           0 :                 return;
     967             :         }
     968             : 
     969       13792 :         auth_bind_req = dcerpc_pipe_auth_send(s->pipe, s->binding, s->table,
     970             :                                               s->credentials, s->lp_ctx);
     971       13792 :         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       13792 : static void continue_pipe_auth(struct composite_context *ctx)
     980             : {
     981       13792 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
     982             :                                                       struct composite_context);
     983       13792 :         struct pipe_connect_state *s = talloc_get_type(c->private_data, struct pipe_connect_state);
     984             : 
     985       13792 :         c->status = dcerpc_pipe_auth_recv(ctx, s, &s->pipe);
     986       13792 :         if (!composite_is_ok(c)) return;
     987             : 
     988       13767 :         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       23581 : _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             :         struct composite_context *c;
    1020             :         struct pipe_connect_state *s;
    1021             :         enum dcerpc_transport_t transport;
    1022       23581 :         const char *endpoint = NULL;
    1023       23581 :         struct cli_credentials *epm_creds = NULL;
    1024             : 
    1025             :         /* composite context allocation and setup */
    1026       23581 :         c = composite_create(parent_ctx, ev);
    1027       23581 :         if (c == NULL) {
    1028           0 :                 return NULL;
    1029             :         }
    1030             : 
    1031       23581 :         s = talloc_zero(c, struct pipe_connect_state);
    1032       23581 :         if (composite_nomem(s, c)) return c;
    1033       23581 :         c->private_data = s;
    1034             : 
    1035             :         /* initialise dcerpc pipe structure */
    1036       23581 :         s->pipe = dcerpc_pipe_init(c, ev);
    1037       23581 :         if (composite_nomem(s->pipe, c)) return c;
    1038             : 
    1039       23581 :         if (DEBUGLEVEL >= 10)
    1040           0 :                 s->pipe->conn->packet_log_dir = lpcfg_lock_directory(lp_ctx);
    1041             : 
    1042             :         /* store parameters in state structure */
    1043       23581 :         s->binding      = dcerpc_binding_dup(s, binding);
    1044       23581 :         if (composite_nomem(s->binding, c)) return c;
    1045       23581 :         s->table        = table;
    1046       23581 :         s->credentials  = credentials;
    1047       23581 :         s->lp_ctx    = lp_ctx;
    1048             : 
    1049       23581 :         s->pipe->timed_out = false;
    1050       23581 :         s->pipe->inhibit_timeout_processing = false;
    1051             : 
    1052       23581 :         tevent_add_timer(c->event_ctx, c,
    1053             :                          timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
    1054             :                          dcerpc_connect_timeout_handler, c);
    1055             : 
    1056       23581 :         transport = dcerpc_binding_get_transport(s->binding);
    1057             : 
    1058       23581 :         switch (transport) {
    1059       23182 :         case NCACN_NP:
    1060             :         case NCACN_IP_TCP:
    1061             :         case NCALRPC:
    1062       23182 :                 endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
    1063             : 
    1064             :                 /* anonymous credentials for rpc connection used to get endpoint mapping */
    1065       23182 :                 epm_creds = cli_credentials_init_anon(s);
    1066       23182 :                 if (composite_nomem(epm_creds, c)) return c;
    1067             : 
    1068       23182 :                 break;
    1069           0 :         case NCACN_HTTP:
    1070           0 :                 endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
    1071           0 :                 epm_creds = credentials;
    1072           0 :                 break;
    1073         399 :         default:
    1074         399 :                 DBG_INFO("Unknown transport; continuing with anon, no endpoint.\n");
    1075         399 :                 epm_creds = cli_credentials_init_anon(s);
    1076         399 :                 if (composite_nomem(epm_creds, c)){
    1077           0 :                         return c;
    1078             :                 }
    1079         399 :                 break;
    1080             :         }
    1081             : 
    1082       23581 :         if (endpoint == NULL) {
    1083             :                 struct composite_context *binding_req;
    1084             : 
    1085       43230 :                 binding_req = dcerpc_epm_map_binding_send(c, s->binding, s->table,
    1086             :                                                           epm_creds,
    1087       22777 :                                                           s->pipe->conn->event_ctx,
    1088             :                                                           s->lp_ctx);
    1089       22777 :                 composite_continue(c, binding_req, continue_map_binding, c);
    1090       22777 :                 return c;
    1091             :         }
    1092             : 
    1093         804 :         continue_connect(c, s);
    1094         804 :         return c;
    1095             : }
    1096             : 
    1097             : 
    1098             : /*
    1099             :   receive result of a request to open a rpc connection to a rpc pipe
    1100             : */
    1101       23578 : _PUBLIC_ NTSTATUS dcerpc_pipe_connect_b_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
    1102             :                                     struct dcerpc_pipe **p)
    1103             : {
    1104             :         NTSTATUS status;
    1105             :         struct pipe_connect_state *s;
    1106             :         
    1107       23578 :         status = composite_wait(c);
    1108             :         
    1109       23578 :         if (NT_STATUS_IS_OK(status)) {
    1110       13767 :                 s = talloc_get_type(c->private_data, struct pipe_connect_state);
    1111       13767 :                 talloc_steal(mem_ctx, s->pipe);
    1112       13767 :                 *p = s->pipe;
    1113             :         }
    1114       23578 :         talloc_free(c);
    1115       23578 :         return status;
    1116             : }
    1117             : 
    1118             : 
    1119             : /*
    1120             :   open a rpc connection to a rpc pipe, using the specified 
    1121             :   binding structure to determine the endpoint and options - sync version
    1122             : */
    1123        3990 : _PUBLIC_ NTSTATUS dcerpc_pipe_connect_b(TALLOC_CTX *parent_ctx,
    1124             :                                struct dcerpc_pipe **pp,
    1125             :                                const struct dcerpc_binding *binding,
    1126             :                                const struct ndr_interface_table *table,
    1127             :                                struct cli_credentials *credentials,
    1128             :                                struct tevent_context *ev,
    1129             :                                struct loadparm_context *lp_ctx)
    1130             : {
    1131             :         struct composite_context *c;
    1132             :         
    1133        3990 :         c = dcerpc_pipe_connect_b_send(parent_ctx, binding, table,
    1134             :                                        credentials, ev, lp_ctx);
    1135        3990 :         return dcerpc_pipe_connect_b_recv(c, parent_ctx, pp);
    1136             : }
    1137             : 
    1138             : 
    1139             : struct pipe_conn_state {
    1140             :         struct dcerpc_pipe *pipe;
    1141             : };
    1142             : 
    1143             : 
    1144             : static void continue_pipe_connect_b(struct composite_context *ctx);
    1145             : 
    1146             : 
    1147             : /*
    1148             :   Initiate rpc connection to a rpc pipe, using the specified string
    1149             :   binding to determine the endpoint and options.
    1150             :   The string is to be parsed to a binding structure first.
    1151             : */
    1152        4284 : _PUBLIC_ struct composite_context* dcerpc_pipe_connect_send(TALLOC_CTX *parent_ctx,
    1153             :                                                    const char *binding,
    1154             :                                                    const struct ndr_interface_table *table,
    1155             :                                                    struct cli_credentials *credentials,
    1156             :                                                    struct tevent_context *ev, struct loadparm_context *lp_ctx)
    1157             : {
    1158             :         struct composite_context *c;
    1159             :         struct pipe_conn_state *s;
    1160             :         struct dcerpc_binding *b;
    1161             :         struct composite_context *pipe_conn_req;
    1162             : 
    1163             :         /* composite context allocation and setup */
    1164        4284 :         c = composite_create(parent_ctx, ev);
    1165        4284 :         if (c == NULL) {
    1166           0 :                 return NULL;
    1167             :         }
    1168             : 
    1169        4284 :         s = talloc_zero(c, struct pipe_conn_state);
    1170        4284 :         if (composite_nomem(s, c)) return c;
    1171        4284 :         c->private_data = s;
    1172             : 
    1173             :         /* parse binding string to the structure */
    1174        4284 :         c->status = dcerpc_parse_binding(c, binding, &b);
    1175        4284 :         if (!NT_STATUS_IS_OK(c->status)) {
    1176           0 :                 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", binding));
    1177           0 :                 composite_error(c, c->status);
    1178           0 :                 return c;
    1179             :         }
    1180             : 
    1181        4284 :         DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(c, b)));
    1182             : 
    1183             :         /* 
    1184             :            start connecting to a rpc pipe after binding structure
    1185             :            is established
    1186             :          */
    1187        4284 :         pipe_conn_req = dcerpc_pipe_connect_b_send(c, b, table,
    1188             :                                                    credentials, ev, lp_ctx);
    1189        4284 :         composite_continue(c, pipe_conn_req, continue_pipe_connect_b, c);
    1190        4284 :         return c;
    1191             : }
    1192             : 
    1193             : 
    1194             : /*
    1195             :   Stage 2 of pipe_connect: Receive result of actual pipe connect request
    1196             :   and say if we're done ok
    1197             : */
    1198        4283 : static void continue_pipe_connect_b(struct composite_context *ctx)
    1199             : {
    1200        4283 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
    1201             :                                                       struct composite_context);
    1202        4283 :         struct pipe_conn_state *s = talloc_get_type(c->private_data,
    1203             :                                                     struct pipe_conn_state);
    1204             : 
    1205        4283 :         c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe);
    1206        4283 :         talloc_steal(s, s->pipe);
    1207        4283 :         if (!composite_is_ok(c)) return;
    1208             : 
    1209        4272 :         composite_done(c);
    1210             : }
    1211             : 
    1212             : 
    1213             : /*
    1214             :   Receive result of pipe connect (using binding string) request
    1215             :   and return connected pipe structure.
    1216             : */
    1217        4284 : NTSTATUS dcerpc_pipe_connect_recv(struct composite_context *c,
    1218             :                                   TALLOC_CTX *mem_ctx,
    1219             :                                   struct dcerpc_pipe **pp)
    1220             : {
    1221             :         NTSTATUS status;
    1222             :         struct pipe_conn_state *s;
    1223             : 
    1224        4284 :         status = composite_wait(c);
    1225        4283 :         if (NT_STATUS_IS_OK(status)) {
    1226        4272 :                 s = talloc_get_type(c->private_data, struct pipe_conn_state);
    1227        4272 :                 *pp = talloc_steal(mem_ctx, s->pipe);
    1228             :         }
    1229        4283 :         talloc_free(c);
    1230        4283 :         return status;
    1231             : }
    1232             : 
    1233             : 
    1234             : /*
    1235             :   Open a rpc connection to a rpc pipe, using the specified string
    1236             :   binding to determine the endpoint and options - sync version
    1237             : */
    1238        4284 : _PUBLIC_ NTSTATUS dcerpc_pipe_connect(TALLOC_CTX *parent_ctx, 
    1239             :                              struct dcerpc_pipe **pp, 
    1240             :                              const char *binding,
    1241             :                              const struct ndr_interface_table *table,
    1242             :                              struct cli_credentials *credentials,
    1243             :                              struct tevent_context *ev,
    1244             :                              struct loadparm_context *lp_ctx)
    1245             : {
    1246             :         struct composite_context *c;
    1247        4284 :         c = dcerpc_pipe_connect_send(parent_ctx, binding, 
    1248             :                                      table, credentials, ev, lp_ctx);
    1249        4284 :         return dcerpc_pipe_connect_recv(c, parent_ctx, pp);
    1250             : }
    1251             : 

Generated by: LCOV version 1.13