LCOV - code coverage report
Current view: top level - source4/libnet - libnet_rpc.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 324 435 74.5 %
Date: 2021-09-23 10:06:22 Functions: 22 22 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    
       4             :    Copyright (C) Stefan Metzmacher  2004
       5             :    Copyright (C) Rafal Szczesniak   2005
       6             :    
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             :    
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             :    
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "includes.h"
      22             : #include "libnet/libnet.h"
      23             : #include "libcli/libcli.h"
      24             : #include "libcli/composite/composite.h"
      25             : #include "librpc/rpc/dcerpc_proto.h"
      26             : #include "librpc/gen_ndr/ndr_lsa_c.h"
      27             : #include "librpc/gen_ndr/ndr_samr.h"
      28             : #include "auth/credentials/credentials.h"
      29             : 
      30             : struct rpc_connect_srv_state {
      31             :         struct libnet_context *ctx;
      32             :         struct libnet_RpcConnect r;
      33             :         const char *binding;
      34             : 
      35             :         /* information about the progress */
      36             :         void (*monitor_fn)(struct monitor_msg*);
      37             : };
      38             : 
      39             : 
      40             : static void continue_pipe_connect(struct composite_context *ctx);
      41             : 
      42             : 
      43             : /**
      44             :  * Initiates connection to rpc pipe on remote server
      45             :  * 
      46             :  * @param ctx initialised libnet context
      47             :  * @param mem_ctx memory context of this call
      48             :  * @param r data structure containing necessary parameters and return values
      49             :  * @return composite context of this call
      50             :  **/
      51             : 
      52         673 : static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context *ctx,
      53             :                                                            TALLOC_CTX *mem_ctx,
      54             :                                                            struct libnet_RpcConnect *r,
      55             :                                                            void (*monitor)(struct monitor_msg*))
      56             : {
      57         113 :         struct composite_context *c;    
      58         113 :         struct rpc_connect_srv_state *s;
      59         113 :         struct dcerpc_binding *b;
      60         113 :         struct composite_context *pipe_connect_req;
      61             : 
      62             :         /* composite context allocation and setup */
      63         673 :         c = composite_create(ctx, ctx->event_ctx);
      64         673 :         if (c == NULL) return c;
      65             : 
      66         673 :         s = talloc_zero(c, struct rpc_connect_srv_state);
      67         673 :         if (composite_nomem(s, c)) return c;
      68             : 
      69         673 :         c->private_data = s;
      70         673 :         s->monitor_fn   = monitor;
      71             : 
      72         673 :         s->ctx = ctx;
      73         673 :         s->r = *r;
      74         673 :         ZERO_STRUCT(s->r.out);
      75             : 
      76             :         /* prepare binding string */
      77         673 :         switch (r->level) {
      78          26 :         case LIBNET_RPC_CONNECT_SERVER:
      79          26 :                 s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.name);
      80         113 :                 break;
      81          81 :         case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
      82          81 :                 s->binding = talloc_asprintf(s, "ncacn_np:%s[target_hostname=%s]",
      83             :                                              r->in.address, r->in.name);
      84           8 :                 break;
      85             : 
      86         566 :         case LIBNET_RPC_CONNECT_BINDING:
      87         566 :                 s->binding = talloc_strdup(s, r->in.binding);
      88         100 :                 break;
      89             : 
      90           0 :         case LIBNET_RPC_CONNECT_DC:
      91             :         case LIBNET_RPC_CONNECT_PDC:
      92             :                 /* this should never happen - DC and PDC level has a separate
      93             :                    composite function */
      94             :         case LIBNET_RPC_CONNECT_DC_INFO:
      95             :                 /* this should never happen - DC_INFO level has a separate
      96             :                    composite function */
      97           0 :                 composite_error(c, NT_STATUS_INVALID_LEVEL);
      98           0 :                 return c;
      99             :         }
     100             : 
     101             :         /* parse binding string to the structure */
     102         673 :         c->status = dcerpc_parse_binding(c, s->binding, &b);
     103         673 :         if (!NT_STATUS_IS_OK(c->status)) {
     104           0 :                 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", s->binding));
     105           0 :                 composite_error(c, c->status);
     106           0 :                 return c;
     107             :         }
     108             : 
     109         673 :         switch (r->level) {
     110         107 :         case LIBNET_RPC_CONNECT_SERVER:
     111             :         case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
     112         107 :                 c->status = dcerpc_binding_set_flags(b, r->in.dcerpc_flags, 0);
     113         107 :                 if (!composite_is_ok(c)) return c;
     114             :                 break;
     115             :         default:
     116             :                 /* other types have already been checked before */
     117             :                 break;
     118             :         }
     119             : 
     120         673 :         if (DEBUGLEVEL >= 10) {
     121           0 :                 c->status = dcerpc_binding_set_flags(b, DCERPC_DEBUG_PRINT_BOTH, 0);
     122           0 :                 if (!composite_is_ok(c)) return c;
     123             :         }
     124             : 
     125             :         /* connect to remote dcerpc pipe */
     126         673 :         pipe_connect_req = dcerpc_pipe_connect_b_send(c, b, r->in.dcerpc_iface,
     127             :                                                       ctx->cred, c->event_ctx,
     128             :                                                       ctx->lp_ctx);
     129         673 :         if (composite_nomem(pipe_connect_req, c)) return c;
     130             : 
     131         673 :         composite_continue(c, pipe_connect_req, continue_pipe_connect, c);
     132             :         return c;
     133             : }
     134             : 
     135             : 
     136             : /*
     137             :   Step 2 of RpcConnectSrv - get rpc connection
     138             : */
     139         673 : static void continue_pipe_connect(struct composite_context *ctx)
     140             : {
     141         113 :         struct composite_context *c;
     142         113 :         struct rpc_connect_srv_state *s;
     143             : 
     144         673 :         c = talloc_get_type(ctx->async.private_data, struct composite_context);
     145         673 :         s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
     146             : 
     147             :         /* receive result of rpc pipe connection */
     148         673 :         c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->r.out.dcerpc_pipe);
     149             :         
     150             :         /* post monitor message */
     151         673 :         if (s->monitor_fn) {
     152           0 :                 struct monitor_msg msg;
     153           0 :                 struct msg_net_rpc_connect data;
     154           0 :                 const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
     155             : 
     156             :                 /* prepare monitor message and post it */
     157           0 :                 data.host        = dcerpc_binding_get_string_option(b, "host");
     158           0 :                 data.endpoint    = dcerpc_binding_get_string_option(b, "endpoint");
     159           0 :                 data.transport   = dcerpc_binding_get_transport(b);
     160           0 :                 data.domain_name = dcerpc_binding_get_string_option(b, "target_hostname");
     161             : 
     162           0 :                 msg.type      = mon_NetRpcConnect;
     163           0 :                 msg.data      = (void*)&data;
     164           0 :                 msg.data_size = sizeof(data);
     165           0 :                 s->monitor_fn(&msg);
     166             :         }
     167             : 
     168         673 :         composite_done(c);      
     169         673 : }
     170             : 
     171             : 
     172             : /**
     173             :  * Receives result of connection to rpc pipe on remote server
     174             :  *
     175             :  * @param c composite context
     176             :  * @param ctx initialised libnet context
     177             :  * @param mem_ctx memory context of this call
     178             :  * @param r data structure containing necessary parameters and return values
     179             :  * @return nt status of rpc connection
     180             :  **/
     181             : 
     182         673 : static NTSTATUS libnet_RpcConnectSrv_recv(struct composite_context *c,
     183             :                                           struct libnet_context *ctx,
     184             :                                           TALLOC_CTX *mem_ctx,
     185             :                                           struct libnet_RpcConnect *r)
     186             : {
     187         113 :         NTSTATUS status;
     188             : 
     189         673 :         status = composite_wait(c);
     190         673 :         if (NT_STATUS_IS_OK(status)) {
     191         112 :                 struct rpc_connect_srv_state *s;
     192             : 
     193             :                 /* move the returned rpc pipe between memory contexts */
     194         660 :                 s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
     195         660 :                 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
     196             : 
     197             :                 /* reference created pipe structure to long-term libnet_context
     198             :                    so that it can be used by other api functions even after short-term
     199             :                    mem_ctx is freed */
     200         660 :                 if (r->in.dcerpc_iface == &ndr_table_samr) {
     201          54 :                         ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
     202          54 :                         ctx->samr.samr_handle = ctx->samr.pipe->binding_handle;
     203             : 
     204         606 :                 } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
     205         583 :                         ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
     206         583 :                         ctx->lsa.lsa_handle = ctx->lsa.pipe->binding_handle;
     207             :                 }
     208             : 
     209         660 :                 r->out.error_string = talloc_strdup(mem_ctx, "Success");
     210             : 
     211             :         } else {
     212          13 :                 r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
     213             :         }
     214             : 
     215         673 :         talloc_free(c);
     216         673 :         return status;
     217             : }
     218             : 
     219             : 
     220             : struct rpc_connect_dc_state {
     221             :         struct libnet_context *ctx;
     222             :         struct libnet_RpcConnect r;
     223             :         struct libnet_RpcConnect r2;
     224             :         struct libnet_LookupDCs f;
     225             :         const char *connect_name;
     226             : 
     227             :         /* information about the progress */
     228             :         void (*monitor_fn)(struct monitor_msg *);
     229             : };
     230             : 
     231             : 
     232             : static void continue_lookup_dc(struct tevent_req *req);
     233             : static void continue_rpc_connect(struct composite_context *ctx);
     234             : 
     235             : 
     236             : /**
     237             :  * Initiates connection to rpc pipe on domain pdc
     238             :  * 
     239             :  * @param ctx initialised libnet context
     240             :  * @param mem_ctx memory context of this call
     241             :  * @param r data structure containing necessary parameters and return values
     242             :  * @return composite context of this call
     243             :  **/
     244             : 
     245          81 : static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context *ctx,
     246             :                                                           TALLOC_CTX *mem_ctx,
     247             :                                                           struct libnet_RpcConnect *r,
     248             :                                                           void (*monitor)(struct monitor_msg *msg))
     249             : {
     250           8 :         struct composite_context *c;
     251           8 :         struct rpc_connect_dc_state *s;
     252           8 :         struct tevent_req *lookup_dc_req;
     253             : 
     254             :         /* composite context allocation and setup */
     255          81 :         c = composite_create(ctx, ctx->event_ctx);
     256          81 :         if (c == NULL) return c;
     257             : 
     258          81 :         s = talloc_zero(c, struct rpc_connect_dc_state);
     259          81 :         if (composite_nomem(s, c)) return c;
     260             : 
     261          81 :         c->private_data = s;
     262          81 :         s->monitor_fn   = monitor;
     263             : 
     264          81 :         s->ctx = ctx;
     265          81 :         s->r   = *r;
     266          81 :         ZERO_STRUCT(s->r.out);
     267             : 
     268          81 :         switch (r->level) {
     269          50 :         case LIBNET_RPC_CONNECT_PDC:
     270          50 :                 s->f.in.name_type = NBT_NAME_PDC;
     271           2 :                 break;
     272             : 
     273          31 :         case LIBNET_RPC_CONNECT_DC:
     274          31 :                 s->f.in.name_type = NBT_NAME_LOGON;
     275           6 :                 break;
     276             : 
     277             :         default:
     278             :                 break;
     279             :         }
     280             : 
     281          81 :         s->f.in.domain_name = r->in.name;
     282          81 :         s->f.out.num_dcs    = 0;
     283          81 :         s->f.out.dcs        = NULL;
     284             : 
     285             :         /* find the domain pdc first */
     286          81 :         lookup_dc_req = libnet_LookupDCs_send(ctx, c, &s->f);
     287          81 :         if (composite_nomem(lookup_dc_req, c)) return c;
     288             : 
     289          81 :         tevent_req_set_callback(lookup_dc_req, continue_lookup_dc, c);
     290           8 :         return c;
     291             : }
     292             : 
     293             : 
     294             : /*
     295             :   Step 2 of RpcConnectDC: get domain controller name and
     296             :   initiate RpcConnect to it
     297             : */
     298          81 : static void continue_lookup_dc(struct tevent_req *req)
     299             : {
     300           8 :         struct composite_context *c;
     301           8 :         struct rpc_connect_dc_state *s;
     302           8 :         struct composite_context *rpc_connect_req;
     303           8 :         struct monitor_msg msg;
     304           8 :         struct msg_net_lookup_dc data;
     305             : 
     306          81 :         c = tevent_req_callback_data(req, struct composite_context);
     307          81 :         s = talloc_get_type_abort(c->private_data, struct rpc_connect_dc_state);
     308             :         
     309             :         /* receive result of domain controller lookup */
     310          81 :         c->status = libnet_LookupDCs_recv(req, c, &s->f);
     311          81 :         if (!composite_is_ok(c)) return;
     312             : 
     313             :         /* decide on preferred address type depending on DC type */
     314          81 :         s->connect_name = s->f.out.dcs[0].name;
     315             : 
     316             :         /* post monitor message */
     317          81 :         if (s->monitor_fn) {
     318             :                 /* prepare a monitor message and post it */
     319           0 :                 data.domain_name = s->f.in.domain_name;
     320           0 :                 data.hostname    = s->f.out.dcs[0].name;
     321           0 :                 data.address     = s->f.out.dcs[0].address;
     322             :                 
     323           0 :                 msg.type         = mon_NetLookupDc;
     324           0 :                 msg.data         = &data;
     325           0 :                 msg.data_size    = sizeof(data);
     326           0 :                 s->monitor_fn(&msg);
     327             :         }
     328             : 
     329             :         /* ok, pdc has been found so do attempt to rpc connect */
     330          81 :         s->r2.level         = LIBNET_RPC_CONNECT_SERVER_ADDRESS;
     331             : 
     332             :         /* this will cause yet another name resolution, but at least
     333             :          * we pass the right name down the stack now */
     334          81 :         s->r2.in.name          = talloc_strdup(s, s->connect_name);
     335          81 :         s->r2.in.address       = talloc_steal(s, s->f.out.dcs[0].address);
     336          81 :         s->r2.in.dcerpc_iface  = s->r.in.dcerpc_iface;    
     337          81 :         s->r2.in.dcerpc_flags  = s->r.in.dcerpc_flags;
     338             : 
     339             :         /* send rpc connect request to the server */
     340          81 :         rpc_connect_req = libnet_RpcConnectSrv_send(s->ctx, c, &s->r2, s->monitor_fn);
     341          81 :         if (composite_nomem(rpc_connect_req, c)) return;
     342             : 
     343          81 :         composite_continue(c, rpc_connect_req, continue_rpc_connect, c);
     344             : }
     345             : 
     346             : 
     347             : /*
     348             :   Step 3 of RpcConnectDC: get rpc connection to the server
     349             : */
     350          81 : static void continue_rpc_connect(struct composite_context *ctx)
     351             : {
     352           8 :         struct composite_context *c;
     353           8 :         struct rpc_connect_dc_state *s;
     354             : 
     355          81 :         c = talloc_get_type(ctx->async.private_data, struct composite_context);
     356          81 :         s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
     357             : 
     358          81 :         c->status = libnet_RpcConnectSrv_recv(ctx, s->ctx, c, &s->r2);
     359             : 
     360             :         /* error string is to be passed anyway */
     361          81 :         s->r.out.error_string  = s->r2.out.error_string;
     362          81 :         if (!composite_is_ok(c)) return;
     363             : 
     364          73 :         s->r.out.dcerpc_pipe = s->r2.out.dcerpc_pipe;
     365             :         
     366             :         /* post monitor message */
     367          73 :         if (s->monitor_fn) {
     368           0 :                 struct monitor_msg msg;
     369           0 :                 struct msg_net_rpc_connect data;
     370           0 :                 const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
     371             : 
     372           0 :                 data.host        = dcerpc_binding_get_string_option(b, "host");
     373           0 :                 data.endpoint    = dcerpc_binding_get_string_option(b, "endpoint");
     374           0 :                 data.transport   = dcerpc_binding_get_transport(b);
     375           0 :                 data.domain_name = dcerpc_binding_get_string_option(b, "target_hostname");
     376             : 
     377           0 :                 msg.type      = mon_NetRpcConnect;
     378           0 :                 msg.data      = (void*)&data;
     379           0 :                 msg.data_size = sizeof(data);
     380           0 :                 s->monitor_fn(&msg);
     381             :         }
     382             : 
     383          73 :         composite_done(c);
     384             : }
     385             : 
     386             : 
     387             : /**
     388             :  * Receives result of connection to rpc pipe on domain pdc
     389             :  *
     390             :  * @param c composite context
     391             :  * @param ctx initialised libnet context
     392             :  * @param mem_ctx memory context of this call
     393             :  * @param r data structure containing necessary parameters and return values
     394             :  * @return nt status of rpc connection
     395             :  **/
     396             : 
     397          81 : static NTSTATUS libnet_RpcConnectDC_recv(struct composite_context *c,
     398             :                                          struct libnet_context *ctx,
     399             :                                          TALLOC_CTX *mem_ctx,
     400             :                                          struct libnet_RpcConnect *r)
     401             : {
     402           8 :         NTSTATUS status;
     403          81 :         struct rpc_connect_dc_state *s = talloc_get_type(c->private_data,
     404             :                                          struct rpc_connect_dc_state);
     405             : 
     406          81 :         status = composite_wait(c);
     407          81 :         if (NT_STATUS_IS_OK(status)) {
     408             :                 /* move connected rpc pipe between memory contexts 
     409             :                    
     410             :                    The use of talloc_reparent(talloc_parent(), ...) is
     411             :                    bizarre, but it is needed because of the absolutely
     412             :                    atrocious use of talloc in this code. We need to
     413             :                    force the original parent to change, but finding
     414             :                    the original parent is well nigh impossible at this
     415             :                    point in the code (yes, I tried).
     416             :                  */
     417          73 :                 r->out.dcerpc_pipe = talloc_reparent(talloc_parent(s->r.out.dcerpc_pipe), 
     418          73 :                                                      mem_ctx, s->r.out.dcerpc_pipe);
     419             : 
     420             :                 /* reference created pipe structure to long-term libnet_context
     421             :                    so that it can be used by other api functions even after short-term
     422             :                    mem_ctx is freed */
     423          73 :                 if (r->in.dcerpc_iface == &ndr_table_samr) {
     424          51 :                         ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
     425          51 :                         ctx->samr.samr_handle = ctx->samr.pipe->binding_handle;
     426          22 :                 } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
     427          20 :                         ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
     428          20 :                         ctx->lsa.lsa_handle = ctx->lsa.pipe->binding_handle;
     429             :                 }
     430             : 
     431             :         } else {
     432           8 :                 r->out.error_string = talloc_asprintf(mem_ctx,
     433             :                                                       "Failed to rpc connect: %s",
     434             :                                                       nt_errstr(status));
     435             :         }
     436             : 
     437          81 :         talloc_free(c);
     438          81 :         return status;
     439             : }
     440             : 
     441             : 
     442             : 
     443             : struct rpc_connect_dci_state {
     444             :         struct libnet_context *ctx;
     445             :         struct libnet_RpcConnect r;
     446             :         struct libnet_RpcConnect rpc_conn;
     447             :         struct policy_handle lsa_handle;
     448             :         struct lsa_QosInfo qos;
     449             :         struct lsa_ObjectAttribute attr;
     450             :         struct lsa_OpenPolicy2 lsa_open_policy;
     451             :         struct dcerpc_pipe *lsa_pipe;
     452             :         struct lsa_QueryInfoPolicy2 lsa_query_info2;
     453             :         struct lsa_QueryInfoPolicy lsa_query_info;
     454             :         struct dcerpc_binding *final_binding;
     455             :         struct dcerpc_pipe *final_pipe;
     456             : 
     457             :         /* information about the progress */
     458             :         void (*monitor_fn)(struct monitor_msg*);
     459             : };
     460             : 
     461             : 
     462             : static void continue_dci_rpc_connect(struct composite_context *ctx);
     463             : static void continue_lsa_policy(struct tevent_req *subreq);
     464             : static void continue_lsa_query_info(struct tevent_req *subreq);
     465             : static void continue_lsa_query_info2(struct tevent_req *subreq);
     466             : static void continue_epm_map_binding(struct composite_context *ctx);
     467             : static void continue_secondary_conn(struct composite_context *ctx);
     468             : static void continue_epm_map_binding_send(struct composite_context *c);
     469             : 
     470             : 
     471             : /**
     472             :  * Initiates connection to rpc pipe on remote server or pdc. Received result
     473             :  * contains info on the domain name, domain sid and realm.
     474             :  * 
     475             :  * @param ctx initialised libnet context
     476             :  * @param mem_ctx memory context of this call
     477             :  * @param r data structure containing necessary parameters and return values. Must be a talloc context
     478             :  * @return composite context of this call
     479             :  **/
     480             : 
     481         579 : static struct composite_context* libnet_RpcConnectDCInfo_send(struct libnet_context *ctx,
     482             :                                                               TALLOC_CTX *mem_ctx,
     483             :                                                               struct libnet_RpcConnect *r,
     484             :                                                               void (*monitor)(struct monitor_msg*))
     485             : {
     486         106 :         struct composite_context *c, *conn_req;
     487         106 :         struct rpc_connect_dci_state *s;
     488             : 
     489             :         /* composite context allocation and setup */
     490         579 :         c = composite_create(ctx, ctx->event_ctx);
     491         579 :         if (c == NULL) return c;
     492             : 
     493         579 :         s = talloc_zero(c, struct rpc_connect_dci_state);
     494         579 :         if (composite_nomem(s, c)) return c;
     495             : 
     496         579 :         c->private_data = s;
     497         579 :         s->monitor_fn   = monitor;
     498             : 
     499         579 :         s->ctx = ctx;
     500         579 :         s->r   = *r;
     501         579 :         ZERO_STRUCT(s->r.out);
     502             : 
     503             : 
     504             :         /* proceed to pure rpc connection if the binding string is provided,
     505             :            otherwise try to connect domain controller */
     506         579 :         if (r->in.binding == NULL) {
     507             :                 /* Pass on any binding flags (such as anonymous fallback) that have been set */
     508          18 :                 s->rpc_conn.in.dcerpc_flags = r->in.dcerpc_flags;
     509             : 
     510          18 :                 s->rpc_conn.in.name         = r->in.name;
     511          18 :                 s->rpc_conn.level           = LIBNET_RPC_CONNECT_DC;
     512             :         } else {
     513         561 :                 s->rpc_conn.in.binding      = r->in.binding;
     514         561 :                 s->rpc_conn.level           = LIBNET_RPC_CONNECT_BINDING;
     515             :         }
     516             : 
     517             :         /* we need to query information on lsarpc interface first */
     518         579 :         s->rpc_conn.in.dcerpc_iface    = &ndr_table_lsarpc;
     519             :         
     520             :         /* request connection to the lsa pipe on the pdc */
     521         579 :         conn_req = libnet_RpcConnect_send(ctx, c, &s->rpc_conn, s->monitor_fn);
     522         579 :         if (composite_nomem(c, conn_req)) return c;
     523             : 
     524         579 :         composite_continue(c, conn_req, continue_dci_rpc_connect, c);
     525         106 :         return c;
     526             : }
     527             : 
     528             : 
     529             : /*
     530             :   Step 2 of RpcConnectDCInfo: receive opened rpc pipe and open
     531             :   lsa policy handle
     532             : */
     533         579 : static void continue_dci_rpc_connect(struct composite_context *ctx)
     534             : {
     535         106 :         struct composite_context *c;
     536         106 :         struct rpc_connect_dci_state *s;
     537         106 :         struct tevent_req *subreq;
     538         106 :         enum dcerpc_transport_t transport;
     539             : 
     540         579 :         c = talloc_get_type(ctx->async.private_data, struct composite_context);
     541         579 :         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
     542             : 
     543         579 :         c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpc_conn);
     544         579 :         if (!NT_STATUS_IS_OK(c->status)) {
     545           4 :                 composite_error(c, c->status);
     546           4 :                 return;
     547             :         }
     548             : 
     549             :         /* post monitor message */
     550         575 :         if (s->monitor_fn) {
     551           0 :                 struct monitor_msg msg;
     552           0 :                 struct msg_net_rpc_connect data;
     553           0 :                 const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
     554             : 
     555           0 :                 data.host        = dcerpc_binding_get_string_option(b, "host");
     556           0 :                 data.endpoint    = dcerpc_binding_get_string_option(b, "endpoint");
     557           0 :                 data.transport   = dcerpc_binding_get_transport(b);
     558           0 :                 data.domain_name = dcerpc_binding_get_string_option(b, "target_hostname");
     559             : 
     560           0 :                 msg.type      = mon_NetRpcConnect;
     561           0 :                 msg.data      = (void*)&data;
     562           0 :                 msg.data_size = sizeof(data);
     563           0 :                 s->monitor_fn(&msg);
     564             :         }
     565             : 
     566             :         /* prepare to open a policy handle on lsa pipe */
     567         575 :         s->lsa_pipe = s->ctx->lsa.pipe;
     568             :         
     569         575 :         s->qos.len                 = 0;
     570         575 :         s->qos.impersonation_level = 2;
     571         575 :         s->qos.context_mode        = 1;
     572         575 :         s->qos.effective_only      = 0;
     573             : 
     574         575 :         s->attr.sec_qos = &s->qos;
     575             : 
     576         575 :         transport = dcerpc_binding_get_transport(s->lsa_pipe->binding);
     577         575 :         if (transport == NCACN_IP_TCP) {
     578             :                 /*
     579             :                  * Skip to creating the actual connection. We can't open a
     580             :                  * policy handle over tcpip.
     581             :                  */
     582           0 :                 continue_epm_map_binding_send(c);
     583           0 :                 return;
     584             :         }
     585             : 
     586         575 :         s->lsa_open_policy.in.attr        = &s->attr;
     587         575 :         s->lsa_open_policy.in.system_name = talloc_asprintf(c, "\\");
     588         575 :         if (composite_nomem(s->lsa_open_policy.in.system_name, c)) return;
     589             : 
     590         575 :         s->lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
     591         575 :         s->lsa_open_policy.out.handle     = &s->lsa_handle;
     592             : 
     593        1150 :         subreq = dcerpc_lsa_OpenPolicy2_r_send(s, c->event_ctx,
     594         575 :                                                s->lsa_pipe->binding_handle,
     595             :                                                &s->lsa_open_policy);
     596         575 :         if (composite_nomem(subreq, c)) return;
     597             : 
     598         575 :         tevent_req_set_callback(subreq, continue_lsa_policy, c);
     599             : }
     600             : 
     601             : 
     602             : /*
     603             :   Step 3 of RpcConnectDCInfo: Get policy handle and query lsa info
     604             :   for kerberos realm (dns name) and guid. The query may fail.
     605             : */
     606         575 : static void continue_lsa_policy(struct tevent_req *subreq)
     607             : {
     608         105 :         struct composite_context *c;
     609         105 :         struct rpc_connect_dci_state *s;
     610             : 
     611         575 :         c = tevent_req_callback_data(subreq, struct composite_context);
     612         575 :         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
     613             : 
     614         575 :         c->status = dcerpc_lsa_OpenPolicy2_r_recv(subreq, s);
     615         575 :         TALLOC_FREE(subreq);
     616         575 :         if (!NT_STATUS_IS_OK(c->status)) {
     617           0 :                 composite_error(c, c->status);
     618           0 :                 return;
     619             :         }
     620             : 
     621         575 :         if (NT_STATUS_EQUAL(s->lsa_open_policy.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
     622           0 :                 s->r.out.realm = NULL;
     623           0 :                 s->r.out.guid  = NULL;
     624           0 :                 s->r.out.domain_name = NULL;
     625           0 :                 s->r.out.domain_sid  = NULL;
     626             : 
     627             :                 /* Skip to the creating the actual connection, no info available on this transport */
     628           0 :                 continue_epm_map_binding_send(c);
     629           0 :                 return;
     630             : 
     631         575 :         } else if (!NT_STATUS_IS_OK(s->lsa_open_policy.out.result)) {
     632           0 :                 composite_error(c, s->lsa_open_policy.out.result);
     633           0 :                 return;
     634             :         }
     635             : 
     636             :         /* post monitor message */
     637         575 :         if (s->monitor_fn) {
     638           0 :                 struct monitor_msg msg;
     639             : 
     640           0 :                 msg.type      = mon_LsaOpenPolicy;
     641           0 :                 msg.data      = NULL;
     642           0 :                 msg.data_size = 0;
     643           0 :                 s->monitor_fn(&msg);
     644             :         }
     645             : 
     646             :         /* query lsa info for dns domain name and guid */
     647         575 :         s->lsa_query_info2.in.handle = &s->lsa_handle;
     648         575 :         s->lsa_query_info2.in.level  = LSA_POLICY_INFO_DNS;
     649         575 :         s->lsa_query_info2.out.info  = talloc_zero(c, union lsa_PolicyInformation *);
     650         575 :         if (composite_nomem(s->lsa_query_info2.out.info, c)) return;
     651             : 
     652        1150 :         subreq = dcerpc_lsa_QueryInfoPolicy2_r_send(s, c->event_ctx,
     653         575 :                                                     s->lsa_pipe->binding_handle,
     654             :                                                     &s->lsa_query_info2);
     655         575 :         if (composite_nomem(subreq, c)) return;
     656             : 
     657         575 :         tevent_req_set_callback(subreq, continue_lsa_query_info2, c);
     658             : }
     659             : 
     660             : 
     661             : /*
     662             :   Step 4 of RpcConnectDCInfo: Get realm and guid if provided (rpc call
     663             :   may result in failure) and query lsa info for domain name and sid.
     664             : */
     665         575 : static void continue_lsa_query_info2(struct tevent_req *subreq)
     666             : {       
     667         105 :         struct composite_context *c;
     668         105 :         struct rpc_connect_dci_state *s;
     669             : 
     670         575 :         c = tevent_req_callback_data(subreq, struct composite_context);
     671         575 :         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
     672             : 
     673         575 :         c->status = dcerpc_lsa_QueryInfoPolicy2_r_recv(subreq, s);
     674         575 :         TALLOC_FREE(subreq);
     675             :         
     676             :         /* In case of error just null the realm and guid and proceed
     677             :            to the next step. After all, it doesn't have to be AD domain
     678             :            controller we talking to - NT-style PDC also counts */
     679             : 
     680         575 :         if (NT_STATUS_EQUAL(c->status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
     681          50 :                 s->r.out.realm = NULL;
     682          50 :                 s->r.out.guid  = NULL;
     683             : 
     684             :         } else {
     685         525 :                 if (!NT_STATUS_IS_OK(c->status)) {
     686           0 :                         s->r.out.error_string = talloc_asprintf(c,
     687             :                                                                 "lsa_QueryInfoPolicy2 failed: %s",
     688             :                                                                 nt_errstr(c->status));
     689           0 :                         composite_error(c, c->status);
     690           0 :                         return;
     691             :                 }
     692             : 
     693         525 :                 if (!NT_STATUS_IS_OK(s->lsa_query_info2.out.result)) {
     694           0 :                         s->r.out.error_string = talloc_asprintf(c,
     695             :                                                                 "lsa_QueryInfoPolicy2 failed: %s",
     696             :                                                                 nt_errstr(s->lsa_query_info2.out.result));
     697           0 :                         composite_error(c, s->lsa_query_info2.out.result);
     698           0 :                         return;
     699             :                 }
     700             : 
     701             :                 /* Copy the dns domain name and guid from the query result */
     702             : 
     703             :                 /* this should actually be a conversion from lsa_StringLarge */
     704         525 :                 s->r.out.realm = (*s->lsa_query_info2.out.info)->dns.dns_domain.string;
     705         525 :                 s->r.out.guid  = talloc(c, struct GUID);
     706         525 :                 if (composite_nomem(s->r.out.guid, c)) {
     707           0 :                         s->r.out.error_string = NULL;
     708           0 :                         return;
     709             :                 }
     710         525 :                 *s->r.out.guid = (*s->lsa_query_info2.out.info)->dns.domain_guid;
     711             :         }
     712             : 
     713             :         /* post monitor message */
     714         575 :         if (s->monitor_fn) {
     715           0 :                 struct monitor_msg msg;
     716             :                 
     717           0 :                 msg.type      = mon_LsaQueryPolicy;
     718           0 :                 msg.data      = NULL;
     719           0 :                 msg.data_size = 0;
     720           0 :                 s->monitor_fn(&msg);
     721             :         }
     722             : 
     723             :         /* query lsa info for domain name and sid */
     724         575 :         s->lsa_query_info.in.handle = &s->lsa_handle;
     725         575 :         s->lsa_query_info.in.level  = LSA_POLICY_INFO_DOMAIN;
     726         575 :         s->lsa_query_info.out.info  = talloc_zero(c, union lsa_PolicyInformation *);
     727         575 :         if (composite_nomem(s->lsa_query_info.out.info, c)) return;
     728             : 
     729        1150 :         subreq = dcerpc_lsa_QueryInfoPolicy_r_send(s, c->event_ctx,
     730         575 :                                                    s->lsa_pipe->binding_handle,
     731             :                                                    &s->lsa_query_info);
     732         575 :         if (composite_nomem(subreq, c)) return;
     733             : 
     734         575 :         tevent_req_set_callback(subreq, continue_lsa_query_info, c);
     735             : }
     736             : 
     737             : 
     738             : /*
     739             :   Step 5 of RpcConnectDCInfo: Get domain name and sid
     740             : */
     741         575 : static void continue_lsa_query_info(struct tevent_req *subreq)
     742             : {
     743         105 :         struct composite_context *c;
     744         105 :         struct rpc_connect_dci_state *s;
     745             : 
     746         575 :         c = tevent_req_callback_data(subreq, struct composite_context);
     747         575 :         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
     748             : 
     749         575 :         c->status = dcerpc_lsa_QueryInfoPolicy_r_recv(subreq, s);
     750         575 :         TALLOC_FREE(subreq);
     751         575 :         if (!NT_STATUS_IS_OK(c->status)) {
     752           0 :                 s->r.out.error_string = talloc_asprintf(c,
     753             :                                                         "lsa_QueryInfoPolicy failed: %s",
     754             :                                                         nt_errstr(c->status));
     755           0 :                 composite_error(c, c->status);
     756           0 :                 return;
     757             :         }
     758             : 
     759             :         /* post monitor message */
     760         575 :         if (s->monitor_fn) {
     761           0 :                 struct monitor_msg msg;
     762             :                 
     763           0 :                 msg.type      = mon_LsaQueryPolicy;
     764           0 :                 msg.data      = NULL;
     765           0 :                 msg.data_size = 0;
     766           0 :                 s->monitor_fn(&msg);
     767             :         }
     768             : 
     769             :         /* Copy the domain name and sid from the query result */
     770         575 :         s->r.out.domain_sid  = (*s->lsa_query_info.out.info)->domain.sid;
     771         575 :         s->r.out.domain_name = (*s->lsa_query_info.out.info)->domain.name.string;
     772             : 
     773         575 :         continue_epm_map_binding_send(c);
     774             : }
     775             : 
     776             : /* 
     777             :    Step 5 (continued) of RpcConnectDCInfo: request endpoint
     778             :    map binding.
     779             : 
     780             :    We may short-cut to this step if we don't support LSA OpenPolicy on this transport
     781             : */
     782         575 : static void continue_epm_map_binding_send(struct composite_context *c)
     783             : {
     784         105 :         struct rpc_connect_dci_state *s;
     785         105 :         struct composite_context *epm_map_req;
     786         575 :         struct cli_credentials *epm_creds = NULL;
     787             : 
     788         575 :         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
     789             : 
     790             :         /* prepare to get endpoint mapping for the requested interface */
     791         575 :         s->final_binding = dcerpc_binding_dup(s, s->lsa_pipe->binding);
     792         575 :         if (composite_nomem(s->final_binding, c)) return;
     793             : 
     794             :         /*
     795             :          * We don't want to inherit the assoc_group_id from the
     796             :          * lsa_pipe here!
     797             :          */
     798         575 :         dcerpc_binding_set_assoc_group_id(s->final_binding, 0);
     799             : 
     800         575 :         epm_creds = cli_credentials_init_anon(s);
     801         575 :         if (composite_nomem(epm_creds, c)) return;
     802             : 
     803         680 :         epm_map_req = dcerpc_epm_map_binding_send(c, s->final_binding, s->r.in.dcerpc_iface,
     804             :                                                   epm_creds,
     805         575 :                                                   s->ctx->event_ctx, s->ctx->lp_ctx);
     806         575 :         if (composite_nomem(epm_map_req, c)) return;
     807             : 
     808         575 :         composite_continue(c, epm_map_req, continue_epm_map_binding, c);
     809             : }
     810             : 
     811             : /*
     812             :   Step 6 of RpcConnectDCInfo: Receive endpoint mapping and create secondary
     813             :   rpc connection derived from already used pipe but connected to the requested
     814             :   one (as specified in libnet_RpcConnect structure)
     815             : */
     816         575 : static void continue_epm_map_binding(struct composite_context *ctx)
     817             : {
     818         105 :         struct composite_context *c, *sec_conn_req;
     819         105 :         struct rpc_connect_dci_state *s;
     820             : 
     821         575 :         c = talloc_get_type(ctx->async.private_data, struct composite_context);
     822         575 :         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
     823             : 
     824         575 :         c->status = dcerpc_epm_map_binding_recv(ctx);
     825         575 :         if (!NT_STATUS_IS_OK(c->status)) {
     826           0 :                 s->r.out.error_string = talloc_asprintf(c,
     827             :                                                         "failed to map pipe with endpoint mapper - %s",
     828             :                                                         nt_errstr(c->status));
     829           0 :                 composite_error(c, c->status);
     830           0 :                 return;
     831             :         }
     832             : 
     833             :         /* create secondary connection derived from lsa pipe */
     834        1150 :         sec_conn_req = dcerpc_secondary_auth_connection_send(s->lsa_pipe,
     835         575 :                                                              s->final_binding,
     836             :                                                              s->r.in.dcerpc_iface,
     837             :                                                              s->ctx->cred,
     838         575 :                                                              s->ctx->lp_ctx);
     839         575 :         if (composite_nomem(sec_conn_req, c)) return;
     840             : 
     841         575 :         composite_continue(c, sec_conn_req, continue_secondary_conn, c);
     842             : }
     843             : 
     844             : 
     845             : /*
     846             :   Step 7 of RpcConnectDCInfo: Get actual pipe to be returned
     847             :   and complete this composite call
     848             : */
     849         575 : static void continue_secondary_conn(struct composite_context *ctx)
     850             : {
     851         105 :         struct composite_context *c;
     852         105 :         struct rpc_connect_dci_state *s;
     853             : 
     854         575 :         c = talloc_get_type(ctx->async.private_data, struct composite_context);
     855         575 :         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
     856             : 
     857         575 :         c->status = dcerpc_secondary_auth_connection_recv(ctx, s->lsa_pipe,
     858             :                                                           &s->final_pipe);
     859         575 :         if (!NT_STATUS_IS_OK(c->status)) {
     860           0 :                 s->r.out.error_string = talloc_asprintf(c,
     861             :                                                         "secondary connection failed: %s",
     862             :                                                         nt_errstr(c->status));
     863             :                 
     864           0 :                 composite_error(c, c->status);
     865           0 :                 return;
     866             :         }
     867             : 
     868         575 :         s->r.out.dcerpc_pipe = s->final_pipe;
     869             : 
     870             :         /* post monitor message */
     871         575 :         if (s->monitor_fn) {
     872           0 :                 struct monitor_msg msg;
     873           0 :                 struct msg_net_rpc_connect data;
     874           0 :                 const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
     875             : 
     876             :                 /* prepare monitor message and post it */
     877           0 :                 data.host        = dcerpc_binding_get_string_option(b, "host");
     878           0 :                 data.endpoint    = dcerpc_binding_get_string_option(b, "endpoint");
     879           0 :                 data.transport   = dcerpc_binding_get_transport(b);
     880           0 :                 data.domain_name = dcerpc_binding_get_string_option(b, "target_hostname");
     881             : 
     882           0 :                 msg.type      = mon_NetRpcConnect;
     883           0 :                 msg.data      = (void*)&data;
     884           0 :                 msg.data_size = sizeof(data);
     885           0 :                 s->monitor_fn(&msg);
     886             :         }
     887             : 
     888         575 :         composite_done(c);
     889             : }
     890             : 
     891             : 
     892             : /**
     893             :  * Receives result of connection to rpc pipe and gets basic
     894             :  * domain info (name, sid, realm, guid)
     895             :  *
     896             :  * @param c composite context
     897             :  * @param ctx initialised libnet context
     898             :  * @param mem_ctx memory context of this call
     899             :  * @param r data structure containing return values
     900             :  * @return nt status of rpc connection
     901             :  **/
     902             : 
     903         579 : static NTSTATUS libnet_RpcConnectDCInfo_recv(struct composite_context *c, struct libnet_context *ctx,
     904             :                                              TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
     905             : {
     906         106 :         NTSTATUS status;
     907         579 :         struct rpc_connect_dci_state *s = talloc_get_type(c->private_data,
     908             :                                           struct rpc_connect_dci_state);
     909             : 
     910         579 :         status = composite_wait(c);
     911         579 :         if (NT_STATUS_IS_OK(status)) {
     912         575 :                 r->out.realm        = talloc_steal(mem_ctx, s->r.out.realm);
     913         575 :                 r->out.guid         = talloc_steal(mem_ctx, s->r.out.guid);
     914         575 :                 r->out.domain_name  = talloc_steal(mem_ctx, s->r.out.domain_name);
     915         575 :                 r->out.domain_sid   = talloc_steal(mem_ctx, s->r.out.domain_sid);
     916             : 
     917         575 :                 r->out.dcerpc_pipe  = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
     918             : 
     919             :                 /* reference created pipe structure to long-term libnet_context
     920             :                    so that it can be used by other api functions even after short-term
     921             :                    mem_ctx is freed */
     922         575 :                 if (r->in.dcerpc_iface == &ndr_table_samr) {
     923         573 :                         ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
     924         573 :                         ctx->samr.samr_handle = ctx->samr.pipe->binding_handle;
     925             : 
     926           2 :                 } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
     927           1 :                         ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
     928           1 :                         ctx->lsa.lsa_handle = ctx->lsa.pipe->binding_handle;
     929             :                 }
     930             : 
     931             :         } else {
     932           4 :                 if (s->r.out.error_string) {
     933           0 :                         r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
     934           4 :                 } else if (r->in.binding == NULL) {
     935           4 :                         r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC failed: %s", nt_errstr(status));
     936             :                 } else {
     937           0 :                         r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC %s failed: %s", 
     938             :                                                               r->in.binding, nt_errstr(status));
     939             :                 }
     940             :         }
     941             : 
     942         579 :         talloc_free(c);
     943         579 :         return status;
     944             : }
     945             : 
     946             : 
     947             : /**
     948             :  * Initiates connection to rpc pipe on remote server or pdc, optionally
     949             :  * providing domain info
     950             :  * 
     951             :  * @param ctx initialised libnet context
     952             :  * @param mem_ctx memory context of this call
     953             :  * @param r data structure containing necessary parameters and return values
     954             :  * @return composite context of this call
     955             :  **/
     956             : 
     957        1252 : struct composite_context* libnet_RpcConnect_send(struct libnet_context *ctx,
     958             :                                                  TALLOC_CTX *mem_ctx,
     959             :                                                  struct libnet_RpcConnect *r,
     960             :                                                  void (*monitor)(struct monitor_msg*))
     961             : {
     962         219 :         struct composite_context *c;
     963             : 
     964        1252 :         switch (r->level) {
     965         592 :         case LIBNET_RPC_CONNECT_SERVER:
     966             :         case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
     967             :         case LIBNET_RPC_CONNECT_BINDING:
     968         592 :                 c = libnet_RpcConnectSrv_send(ctx, mem_ctx, r, monitor);
     969         706 :                 break;
     970             : 
     971          81 :         case LIBNET_RPC_CONNECT_PDC:
     972             :         case LIBNET_RPC_CONNECT_DC:
     973          81 :                 c = libnet_RpcConnectDC_send(ctx, mem_ctx, r, monitor);
     974          73 :                 break;
     975             : 
     976         579 :         case LIBNET_RPC_CONNECT_DC_INFO:
     977         579 :                 c = libnet_RpcConnectDCInfo_send(ctx, mem_ctx, r, monitor);
     978         473 :                 break;
     979             : 
     980           0 :         default:
     981           0 :                 c = talloc_zero(mem_ctx, struct composite_context);
     982           0 :                 composite_error(c, NT_STATUS_INVALID_LEVEL);
     983             :         }
     984             : 
     985        1252 :         return c;
     986             : }
     987             : 
     988             : 
     989             : /**
     990             :  * Receives result of connection to rpc pipe on remote server or pdc
     991             :  *
     992             :  * @param c composite context
     993             :  * @param ctx initialised libnet context
     994             :  * @param mem_ctx memory context of this call
     995             :  * @param r data structure containing necessary parameters and return values
     996             :  * @return nt status of rpc connection
     997             :  **/
     998             : 
     999        1252 : NTSTATUS libnet_RpcConnect_recv(struct composite_context *c, struct libnet_context *ctx,
    1000             :                                 TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
    1001             : {
    1002        1252 :         switch (r->level) {
    1003         592 :         case LIBNET_RPC_CONNECT_SERVER:
    1004             :         case LIBNET_RPC_CONNECT_BINDING:
    1005         592 :                 return libnet_RpcConnectSrv_recv(c, ctx, mem_ctx, r);
    1006             : 
    1007          81 :         case LIBNET_RPC_CONNECT_PDC:
    1008             :         case LIBNET_RPC_CONNECT_DC:
    1009          81 :                 return libnet_RpcConnectDC_recv(c, ctx, mem_ctx, r);
    1010             : 
    1011         579 :         case LIBNET_RPC_CONNECT_DC_INFO:
    1012         579 :                 return libnet_RpcConnectDCInfo_recv(c, ctx, mem_ctx, r);
    1013             : 
    1014           0 :         default:
    1015           0 :                 ZERO_STRUCT(r->out);
    1016           0 :                 return NT_STATUS_INVALID_LEVEL;
    1017             :         }
    1018             : }
    1019             : 
    1020             : 
    1021             : /**
    1022             :  * Connect to a rpc pipe on a remote server - sync version
    1023             :  *
    1024             :  * @param ctx initialised libnet context
    1025             :  * @param mem_ctx memory context of this call
    1026             :  * @param r data structure containing necessary parameters and return values
    1027             :  * @return nt status of rpc connection
    1028             :  **/
    1029             : 
    1030         664 : NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
    1031             :                            struct libnet_RpcConnect *r)
    1032             : {
    1033         113 :         struct composite_context *c;
    1034             :         
    1035         664 :         c = libnet_RpcConnect_send(ctx, mem_ctx, r, NULL);
    1036         664 :         return libnet_RpcConnect_recv(c, ctx, mem_ctx, r);
    1037             : }

Generated by: LCOV version 1.13