LCOV - code coverage report
Current view: top level - source4/librpc/rpc - dcerpc_secondary.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 137 164 83.5 %
Date: 2024-04-21 15:09:00 Functions: 11 12 91.7 %

          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 "lib/events/events.h"
      29             : #include "librpc/rpc/dcerpc.h"
      30             : #include "librpc/rpc/dcerpc_proto.h"
      31             : #include "auth/credentials/credentials.h"
      32             : #include "param/param.h"
      33             : #include "libcli/resolve/resolve.h"
      34             : #include "lib/util/util_net.h"
      35             : 
      36             : struct sec_conn_state {
      37             :         struct dcerpc_pipe *pipe;
      38             :         struct dcerpc_pipe *pipe2;
      39             :         struct dcerpc_binding *binding;
      40             : };
      41             : 
      42             : 
      43             : static void continue_open_smb(struct composite_context *ctx);
      44             : static void continue_open_tcp(struct composite_context *ctx);
      45             : static void continue_open_ncalrpc(struct composite_context *ctx);
      46             : static void continue_open_ncacn_unix(struct composite_context *ctx);
      47             : static void continue_pipe_open(struct composite_context *c);
      48             : 
      49             : 
      50             : /*
      51             :   Send request to create a secondary dcerpc connection from a primary
      52             :   connection
      53             : */
      54        1640 : _PUBLIC_ struct composite_context* dcerpc_secondary_connection_send(struct dcerpc_pipe *p,
      55             :                                                         const struct dcerpc_binding *b)
      56             : {
      57         230 :         struct composite_context *c;
      58         230 :         struct sec_conn_state *s;
      59         230 :         struct composite_context *pipe_smb_req;
      60         230 :         struct composite_context *pipe_tcp_req;
      61        1640 :         const char *localaddress = NULL;
      62         230 :         struct composite_context *pipe_ncalrpc_req;
      63        1640 :         const char *ncalrpc_dir = NULL;
      64         230 :         struct composite_context *pipe_unix_req;
      65         230 :         const char *host;
      66         230 :         const char *target_hostname;
      67         230 :         const char *endpoint;
      68             : 
      69             :         /* composite context allocation and setup */
      70        1640 :         c = composite_create(p, p->conn->event_ctx);
      71        1640 :         if (c == NULL) return NULL;
      72             : 
      73        1640 :         s = talloc_zero(c, struct sec_conn_state);
      74        1640 :         if (composite_nomem(s, c)) return c;
      75        1640 :         c->private_data = s;
      76             : 
      77        1640 :         s->pipe     = p;
      78        1640 :         s->binding  = dcerpc_binding_dup(s, b);
      79        1640 :         if (composite_nomem(s->binding, c)) return c;
      80             : 
      81             :         /* initialise second dcerpc pipe based on primary pipe's event context */
      82        1640 :         s->pipe2 = dcerpc_pipe_init(c, s->pipe->conn->event_ctx);
      83        1640 :         if (composite_nomem(s->pipe2, c)) return c;
      84             : 
      85        1640 :         if (DEBUGLEVEL >= 10)
      86           0 :                 s->pipe2->conn->packet_log_dir = s->pipe->conn->packet_log_dir;
      87             : 
      88        1640 :         host = dcerpc_binding_get_string_option(s->binding, "host");
      89        1640 :         if (host == NULL) {
      90             :                 /*
      91             :                  * We may fallback to the host of the given connection
      92             :                  */
      93           8 :                 host = dcerpc_binding_get_string_option(s->pipe->binding,
      94             :                                                         "host");
      95             :         }
      96        1640 :         target_hostname = dcerpc_binding_get_string_option(s->binding, "target_hostname");
      97        1640 :         if (target_hostname == NULL) {
      98             :                 /*
      99             :                  * We may fallback to the target_hostname of the given connection
     100             :                  */
     101           8 :                 target_hostname = dcerpc_binding_get_string_option(s->pipe->binding,
     102             :                                                                    "target_hostname");
     103             :         }
     104        1640 :         endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
     105        1640 :         if (endpoint == NULL) {
     106             :                 /*
     107             :                  * We may fallback to the endpoint of the given connection
     108             :                  */
     109           0 :                 endpoint = dcerpc_binding_get_string_option(s->pipe->binding, "endpoint");
     110             :         }
     111        1640 :         if (endpoint == NULL) {
     112           0 :                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
     113           0 :                 return c;
     114             :         }
     115             : 
     116             :         /* open second dcerpc pipe using the same transport as for primary pipe */
     117        1640 :         switch (s->pipe->conn->transport.transport) {
     118        1210 :         case NCACN_NP:
     119        1440 :                 pipe_smb_req = dcerpc_secondary_smb_send(s->pipe->conn,
     120        1210 :                                                          s->pipe2->conn,
     121             :                                                          endpoint);
     122        1210 :                 composite_continue(c, pipe_smb_req, continue_open_smb, c);
     123        1640 :                 return c;
     124             : 
     125         248 :         case NCACN_IP_TCP:
     126         248 :                 if (host == NULL) {
     127           0 :                         composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
     128           0 :                         return c;
     129             :                 }
     130             : 
     131         248 :                 if (!is_ipaddress(host)) {
     132             :                         /*
     133             :                          * We may fallback to the host of the given connection
     134             :                          */
     135          72 :                         host = dcerpc_binding_get_string_option(s->pipe->binding,
     136             :                                                                 "host");
     137          72 :                         if (host == NULL) {
     138           0 :                                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
     139           0 :                                 return c;
     140             :                         }
     141          72 :                         if (!is_ipaddress(host)) {
     142           0 :                                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
     143           0 :                                 return c;
     144             :                         }
     145             :                 }
     146             : 
     147         248 :                 localaddress = dcerpc_binding_get_string_option(s->binding,
     148             :                                                                 "localaddress");
     149         248 :                 if (localaddress == NULL) {
     150             :                         /*
     151             :                          * We may fallback to the localaddress of the given connection
     152             :                          */
     153          72 :                         localaddress = dcerpc_binding_get_string_option(s->pipe->binding,
     154             :                                                                         "localaddress");
     155             :                 }
     156             : 
     157         248 :                 pipe_tcp_req = dcerpc_pipe_open_tcp_send(s->pipe2->conn,
     158             :                                                          localaddress,
     159             :                                                          host,
     160             :                                                          target_hostname,
     161         248 :                                                          atoi(endpoint),
     162             :                                                          resolve_context_init(s));
     163         248 :                 composite_continue(c, pipe_tcp_req, continue_open_tcp, c);
     164         248 :                 return c;
     165             : 
     166         182 :         case NCALRPC:
     167         182 :                 ncalrpc_dir = dcerpc_binding_get_string_option(s->binding,
     168             :                                                                "ncalrpc_dir");
     169         182 :                 if (ncalrpc_dir == NULL) {
     170          72 :                         ncalrpc_dir = dcerpc_binding_get_string_option(s->pipe->binding,
     171             :                                                                 "ncalrpc_dir");
     172             :                 }
     173         182 :                 if (ncalrpc_dir == NULL) {
     174           0 :                         composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
     175           0 :                         return c;
     176             :                 }
     177             : 
     178         182 :                 pipe_ncalrpc_req = dcerpc_pipe_open_pipe_send(s->pipe2->conn,
     179             :                                                               ncalrpc_dir,
     180             :                                                               endpoint);
     181         182 :                 composite_continue(c, pipe_ncalrpc_req, continue_open_ncalrpc, c);
     182         182 :                 return c;
     183             : 
     184           0 :         case NCACN_UNIX_STREAM:
     185           0 :                 pipe_unix_req = dcerpc_pipe_open_unix_stream_send(s->pipe2->conn,
     186             :                                                                   endpoint);
     187           0 :                 composite_continue(c, pipe_unix_req, continue_open_ncacn_unix, c);
     188           0 :                 return c;
     189             : 
     190           0 :         default:
     191             :                 /* looks like a transport we don't support */
     192           0 :                 composite_error(c, NT_STATUS_NOT_SUPPORTED);
     193             :         }
     194             : 
     195           0 :         return c;
     196             : }
     197             : 
     198             : 
     199             : /*
     200             :   Stage 2 of secondary_connection: Receive result of pipe open request on smb
     201             : */
     202        1210 : static void continue_open_smb(struct composite_context *ctx)
     203             : {
     204        1210 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
     205             :                                                       struct composite_context);
     206             :         
     207        1210 :         c->status = dcerpc_secondary_smb_recv(ctx);
     208        1210 :         if (!composite_is_ok(c)) return;
     209             : 
     210        1210 :         continue_pipe_open(c);
     211             : }
     212             : 
     213             : 
     214             : /*
     215             :   Stage 2 of secondary_connection: Receive result of pipe open request on tcp/ip
     216             : */
     217         248 : static void continue_open_tcp(struct composite_context *ctx)
     218             : {
     219         248 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
     220             :                                                       struct composite_context);
     221         248 :         struct sec_conn_state *s = talloc_get_type_abort(c->private_data,
     222             :                                                          struct sec_conn_state);
     223         248 :         char *localaddr = NULL;
     224         248 :         char *remoteaddr = NULL;
     225             : 
     226         248 :         c->status = dcerpc_pipe_open_tcp_recv(ctx, s, &localaddr, &remoteaddr);
     227         248 :         if (!composite_is_ok(c)) return;
     228             : 
     229         248 :         c->status = dcerpc_binding_set_string_option(s->binding,
     230             :                                                      "localaddress",
     231             :                                                      localaddr);
     232         248 :         if (!composite_is_ok(c)) return;
     233             : 
     234         248 :         c->status = dcerpc_binding_set_string_option(s->binding,
     235             :                                                      "host",
     236             :                                                      remoteaddr);
     237         248 :         if (!composite_is_ok(c)) return;
     238             : 
     239         248 :         continue_pipe_open(c);
     240             : }
     241             : 
     242             : /*
     243             :   Stage 2 of secondary_connection: Receive result of pipe open request on ncalrpc
     244             : */
     245         182 : static void continue_open_ncalrpc(struct composite_context *ctx)
     246             : {
     247         182 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
     248             :                                                       struct composite_context);
     249             : 
     250         182 :         c->status = dcerpc_pipe_open_pipe_recv(ctx);
     251         182 :         if (!composite_is_ok(c)) return;
     252             : 
     253         182 :         continue_pipe_open(c);
     254             : }
     255             : 
     256             : /*
     257             :   Stage 2 of secondary_connection: Receive result of pipe open request on ncacn_unix
     258             : */
     259           0 : static void continue_open_ncacn_unix(struct composite_context *ctx)
     260             : {
     261           0 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
     262             :                                                       struct composite_context);
     263             : 
     264           0 :         c->status = dcerpc_pipe_open_unix_stream_recv(ctx);
     265           0 :         if (!composite_is_ok(c)) return;
     266             : 
     267           0 :         continue_pipe_open(c);
     268             : }
     269             : 
     270             : 
     271             : /*
     272             :   Stage 3 of secondary_connection: Get binding data and flags from primary pipe
     273             :   and say if we're done ok.
     274             : */
     275        1640 : static void continue_pipe_open(struct composite_context *c)
     276             : {
     277         230 :         struct sec_conn_state *s;
     278             : 
     279        1640 :         s = talloc_get_type(c->private_data, struct sec_conn_state);
     280             : 
     281        1640 :         s->pipe2->conn->flags = s->pipe->conn->flags;
     282        1640 :         s->pipe2->binding     = dcerpc_binding_dup(s->pipe2, s->binding);
     283        1640 :         if (composite_nomem(s->pipe2->binding, c)) {
     284           0 :                 return;
     285             :         }
     286             : 
     287        1640 :         composite_done(c);
     288             : }
     289             : 
     290             : 
     291             : /*
     292             :   Receive result of secondary rpc connection request and return
     293             :   second dcerpc pipe.
     294             : */
     295        1640 : _PUBLIC_ NTSTATUS dcerpc_secondary_connection_recv(struct composite_context *c,
     296             :                                           struct dcerpc_pipe **p2)
     297             : {
     298        1640 :         NTSTATUS status = composite_wait(c);
     299         230 :         struct sec_conn_state *s;
     300             : 
     301        1640 :         s = talloc_get_type(c->private_data, struct sec_conn_state);
     302             : 
     303        1640 :         if (NT_STATUS_IS_OK(status)) {
     304        1640 :                 *p2 = talloc_steal(s->pipe, s->pipe2);
     305             :         }
     306             : 
     307        1640 :         talloc_free(c);
     308        1640 :         return status;
     309             : }
     310             : 
     311             : /*
     312             :   Create a secondary DCERPC connection, then bind (and possibly
     313             :   authenticate) using the supplied credentials.
     314             : 
     315             :   This creates a second connection, to the same host (and on ncacn_np on the same connection) as the first
     316             : */
     317             : struct sec_auth_conn_state {
     318             :         struct dcerpc_pipe *pipe2;
     319             :         const struct dcerpc_binding *binding;
     320             :         const struct ndr_interface_table *table;
     321             :         struct cli_credentials *credentials;
     322             :         struct composite_context *ctx;
     323             :         struct loadparm_context *lp_ctx;
     324             : };
     325             : 
     326             : static void dcerpc_secondary_auth_connection_bind(struct composite_context *ctx);
     327             : static void dcerpc_secondary_auth_connection_continue(struct composite_context *ctx);
     328             : 
     329        1136 : _PUBLIC_ struct composite_context* dcerpc_secondary_auth_connection_send(struct dcerpc_pipe *p,
     330             :                                                                 const struct dcerpc_binding *binding,
     331             :                                                                 const struct ndr_interface_table *table,
     332             :                                                                 struct cli_credentials *credentials,
     333             :                                                                 struct loadparm_context *lp_ctx)
     334             : {
     335             : 
     336         174 :         struct composite_context *c, *secondary_conn_ctx;
     337         174 :         struct sec_auth_conn_state *s;
     338             :         
     339             :         /* composite context allocation and setup */
     340        1136 :         c = composite_create(p, p->conn->event_ctx);
     341        1136 :         if (c == NULL) return NULL;
     342             : 
     343        1136 :         s = talloc_zero(c, struct sec_auth_conn_state);
     344        1136 :         if (composite_nomem(s, c)) return c;
     345        1136 :         c->private_data = s;
     346        1136 :         s->ctx = c;
     347             : 
     348        1136 :         s->binding  = binding;
     349        1136 :         s->table    = table;
     350        1136 :         s->credentials = credentials;
     351        1136 :         s->lp_ctx = lp_ctx;
     352             :         
     353        1136 :         secondary_conn_ctx = dcerpc_secondary_connection_send(p, binding);
     354             :         
     355        1136 :         if (composite_nomem(secondary_conn_ctx, s->ctx)) {
     356           0 :                 talloc_free(c);
     357           0 :                 return NULL;
     358             :         }
     359             : 
     360        1136 :         composite_continue(s->ctx, secondary_conn_ctx, dcerpc_secondary_auth_connection_bind,
     361             :                            s);
     362        1136 :         return c;
     363             : }
     364             : 
     365             : /*
     366             :   Stage 2 of secondary_auth_connection: 
     367             :   Having made the secondary connection, we will need to do an (authenticated) bind
     368             : */
     369        1136 : static void dcerpc_secondary_auth_connection_bind(struct composite_context *ctx)
     370             : {
     371         174 :         struct composite_context *secondary_auth_ctx;
     372        1136 :         struct sec_auth_conn_state *s = talloc_get_type(ctx->async.private_data,
     373             :                                                         struct sec_auth_conn_state);
     374             :         
     375        1136 :         s->ctx->status = dcerpc_secondary_connection_recv(ctx, &s->pipe2);
     376        1136 :         if (!composite_is_ok(s->ctx)) return;
     377             :         
     378        1136 :         secondary_auth_ctx = dcerpc_pipe_auth_send(s->pipe2, s->binding, s->table, s->credentials,
     379             :                                                    s->lp_ctx);
     380        1136 :         composite_continue(s->ctx, secondary_auth_ctx, dcerpc_secondary_auth_connection_continue, s);
     381             :         
     382             : }
     383             : 
     384             : /*
     385             :   Stage 3 of secondary_auth_connection: Receive result of authenticated bind request
     386             : */
     387        1136 : static void dcerpc_secondary_auth_connection_continue(struct composite_context *ctx)
     388             : {
     389        1136 :         struct sec_auth_conn_state *s = talloc_get_type(ctx->async.private_data,
     390             :                                                         struct sec_auth_conn_state);
     391             : 
     392        1136 :         s->ctx->status = dcerpc_pipe_auth_recv(ctx, s, &s->pipe2);
     393        1136 :         if (!composite_is_ok(s->ctx)) return;
     394             :         
     395        1127 :         composite_done(s->ctx);
     396             : }
     397             : 
     398             : /*
     399             :   Receive an authenticated pipe, created as a secondary connection
     400             : */
     401        1136 : _PUBLIC_ NTSTATUS dcerpc_secondary_auth_connection_recv(struct composite_context *c, 
     402             :                                                TALLOC_CTX *mem_ctx,
     403             :                                                struct dcerpc_pipe **p)
     404             : {
     405        1136 :         NTSTATUS status = composite_wait(c);
     406         174 :         struct sec_auth_conn_state *s;
     407             : 
     408        1136 :         s = talloc_get_type(c->private_data, struct sec_auth_conn_state);
     409             : 
     410        1136 :         if (NT_STATUS_IS_OK(status)) {
     411        1127 :                 *p = talloc_steal(mem_ctx, s->pipe2);
     412             :         }
     413             : 
     414        1136 :         talloc_free(c);
     415        1136 :         return status;
     416             : }
     417             : 
     418         576 : _PUBLIC_ NTSTATUS dcerpc_secondary_auth_connection(struct dcerpc_pipe *p,
     419             :                                         const struct dcerpc_binding *binding,
     420             :                                         const struct ndr_interface_table *table,
     421             :                                         struct cli_credentials *credentials,
     422             :                                         struct loadparm_context *lp_ctx,
     423             :                                         TALLOC_CTX *mem_ctx,
     424             :                                         struct dcerpc_pipe **p2)
     425             : {
     426         102 :         struct composite_context *c;
     427             : 
     428         576 :         c = dcerpc_secondary_auth_connection_send(p, binding, table,
     429             :                                                   credentials, lp_ctx);
     430         576 :         return dcerpc_secondary_auth_connection_recv(c, mem_ctx, p2);
     431             : }

Generated by: LCOV version 1.14