LCOV - code coverage report
Current view: top level - source4/libnet - libnet_domain.c (source / functions) Hit Total Coverage
Test: coverage report for master 469b22b8 Lines: 379 553 68.5 %
Date: 2024-06-10 12:05:21 Functions: 30 31 96.8 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Copyright (C) Rafal Szczesniak 2005
       5             :    
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             :    
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             :    
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : /*
      21             :   a composite function for domain handling on samr and lsa pipes
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include "libcli/composite/composite.h"
      26             : #include "libnet/libnet.h"
      27             : #include "librpc/gen_ndr/ndr_samr_c.h"
      28             : #include "librpc/gen_ndr/ndr_lsa_c.h"
      29             : 
      30             : 
      31             : struct domain_open_samr_state {
      32             :         struct libnet_context     *ctx;
      33             :         struct dcerpc_pipe        *pipe;
      34             :         struct libnet_RpcConnect  rpcconn;
      35             :         struct samr_Connect       connect;
      36             :         struct samr_LookupDomain  lookup;
      37             :         struct samr_OpenDomain    open;
      38             :         struct samr_Close         close;
      39             :         struct lsa_String         domain_name;
      40             :         uint32_t                  access_mask;
      41             :         struct policy_handle      connect_handle;
      42             :         struct policy_handle      domain_handle;
      43             :         struct dom_sid2           *domain_sid;
      44             : 
      45             :         /* information about the progress */
      46             :         void (*monitor_fn)(struct monitor_msg*);
      47             : };
      48             : 
      49             : 
      50             : static void continue_domain_open_close(struct tevent_req *subreq);
      51             : static void continue_domain_open_connect(struct tevent_req *subreq);
      52             : static void continue_domain_open_lookup(struct tevent_req *subreq);
      53             : static void continue_domain_open_open(struct tevent_req *subreq);
      54             : 
      55             : 
      56             : /**
      57             :  * Stage 0.5 (optional): Connect to samr rpc pipe
      58             :  */
      59           4 : static void continue_domain_open_rpc_connect(struct composite_context *ctx)
      60             : {
      61           0 :         struct composite_context *c;
      62           0 :         struct domain_open_samr_state *s;
      63           0 :         struct tevent_req *subreq;
      64             : 
      65           4 :         c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
      66           4 :         s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
      67             : 
      68           4 :         c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
      69           4 :         if (!composite_is_ok(c)) return;
      70             : 
      71           4 :         s->pipe = s->rpcconn.out.dcerpc_pipe;
      72             : 
      73             :         /* preparing parameters for samr_Connect rpc call */
      74           4 :         s->connect.in.system_name      = 0;
      75           4 :         s->connect.in.access_mask      = s->access_mask;
      76           4 :         s->connect.out.connect_handle  = &s->connect_handle;
      77             : 
      78             :         /* send request */
      79           4 :         subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
      80           4 :                                             s->pipe->binding_handle,
      81             :                                             &s->connect);
      82           4 :         if (composite_nomem(subreq, c)) return;
      83             : 
      84             :         /* callback handler */
      85           4 :         tevent_req_set_callback(subreq, continue_domain_open_connect, c);
      86             : }
      87             : 
      88             : 
      89             : /**
      90             :  * Stage 0.5 (optional): Close existing (in libnet context) domain
      91             :  * handle
      92             :  */
      93           0 : static void continue_domain_open_close(struct tevent_req *subreq)
      94             : {
      95           0 :         struct composite_context *c;
      96           0 :         struct domain_open_samr_state *s;
      97             : 
      98           0 :         c = tevent_req_callback_data(subreq, struct composite_context);
      99           0 :         s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
     100             : 
     101             :         /* receive samr_Close reply */
     102           0 :         c->status = dcerpc_samr_Close_r_recv(subreq, s);
     103           0 :         TALLOC_FREE(subreq);
     104           0 :         if (!composite_is_ok(c)) return;
     105             : 
     106           0 :         if (s->monitor_fn) {
     107           0 :                 struct monitor_msg msg;
     108             :                 
     109           0 :                 msg.type = mon_SamrClose;
     110           0 :                 msg.data = NULL;
     111           0 :                 msg.data_size = 0;
     112           0 :                 s->monitor_fn(&msg);
     113             :         }
     114             : 
     115             :         /* reset domain handle and associated data in libnet_context */
     116           0 :         s->ctx->samr.name        = NULL;
     117           0 :         s->ctx->samr.access_mask = 0;
     118           0 :         ZERO_STRUCT(s->ctx->samr.handle);
     119             : 
     120             :         /* preparing parameters for samr_Connect rpc call */
     121           0 :         s->connect.in.system_name      = 0;
     122           0 :         s->connect.in.access_mask      = s->access_mask;
     123           0 :         s->connect.out.connect_handle  = &s->connect_handle;
     124             :         
     125             :         /* send request */
     126           0 :         subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
     127           0 :                                             s->pipe->binding_handle,
     128             :                                             &s->connect);
     129           0 :         if (composite_nomem(subreq, c)) return;
     130             : 
     131             :         /* callback handler */
     132           0 :         tevent_req_set_callback(subreq, continue_domain_open_connect, c);
     133             : }
     134             : 
     135             : 
     136             : /**
     137             :  * Stage 1: Connect to SAM server.
     138             :  */
     139          10 : static void continue_domain_open_connect(struct tevent_req *subreq)
     140             : {
     141           0 :         struct composite_context *c;
     142           0 :         struct domain_open_samr_state *s;
     143           0 :         struct samr_LookupDomain *r;
     144             :         
     145          10 :         c = tevent_req_callback_data(subreq, struct composite_context);
     146          10 :         s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
     147             : 
     148             :         /* receive samr_Connect reply */
     149          10 :         c->status = dcerpc_samr_Connect_r_recv(subreq, s);
     150          10 :         TALLOC_FREE(subreq);
     151          10 :         if (!composite_is_ok(c)) return;
     152             : 
     153          10 :         if (s->monitor_fn) {
     154           0 :                 struct monitor_msg msg;
     155             : 
     156           0 :                 msg.type = mon_SamrConnect;
     157           0 :                 msg.data = NULL;
     158           0 :                 msg.data_size = 0;
     159           0 :                 s->monitor_fn(&msg);
     160             :         }
     161             : 
     162          10 :         r = &s->lookup;
     163             : 
     164             :         /* prepare for samr_LookupDomain call */
     165          10 :         r->in.connect_handle = &s->connect_handle;
     166          10 :         r->in.domain_name    = &s->domain_name;
     167          10 :         r->out.sid           = talloc(s, struct dom_sid2 *);
     168          10 :         if (composite_nomem(r->out.sid, c)) return;
     169             : 
     170          10 :         subreq = dcerpc_samr_LookupDomain_r_send(s, c->event_ctx,
     171          10 :                                                  s->pipe->binding_handle,
     172             :                                                  r);
     173          10 :         if (composite_nomem(subreq, c)) return;
     174             : 
     175          10 :         tevent_req_set_callback(subreq, continue_domain_open_lookup, c);
     176             : }
     177             : 
     178             : 
     179             : /**
     180             :  * Stage 2: Lookup domain by name.
     181             :  */
     182          10 : static void continue_domain_open_lookup(struct tevent_req *subreq)
     183             : {
     184           0 :         struct composite_context *c;
     185           0 :         struct domain_open_samr_state *s;
     186           0 :         struct samr_OpenDomain *r;
     187             : 
     188          10 :         c = tevent_req_callback_data(subreq, struct composite_context);
     189          10 :         s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
     190             :         
     191             :         /* receive samr_LookupDomain reply */
     192          10 :         c->status = dcerpc_samr_LookupDomain_r_recv(subreq, s);
     193          10 :         TALLOC_FREE(subreq);
     194             : 
     195          10 :         if (s->monitor_fn) {
     196           0 :                 struct monitor_msg msg;
     197           0 :                 struct msg_rpc_lookup_domain data;
     198             : 
     199           0 :                 data.domain_name = s->domain_name.string;
     200             : 
     201           0 :                 msg.type = mon_SamrLookupDomain;
     202           0 :                 msg.data = (void*)&data;
     203           0 :                 msg.data_size = sizeof(data);
     204           0 :                 s->monitor_fn(&msg);
     205             :         }
     206             : 
     207          10 :         r = &s->open;
     208             : 
     209             :         /* check the rpc layer status */
     210          10 :         if (!composite_is_ok(c)) return;
     211             : 
     212             :         /* check the rpc call itself status */
     213          10 :         if (!NT_STATUS_IS_OK(s->lookup.out.result)) {
     214           0 :                 composite_error(c, s->lookup.out.result);
     215           0 :                 return;
     216             :         }
     217             : 
     218             :         /* prepare for samr_OpenDomain call */
     219          10 :         r->in.connect_handle = &s->connect_handle;
     220          10 :         r->in.access_mask    = SEC_FLAG_MAXIMUM_ALLOWED;
     221          10 :         r->in.sid            = *s->lookup.out.sid;
     222          10 :         r->out.domain_handle = &s->domain_handle;
     223             : 
     224          10 :         subreq = dcerpc_samr_OpenDomain_r_send(s, c->event_ctx,
     225          10 :                                                s->pipe->binding_handle,
     226             :                                                r);
     227          10 :         if (composite_nomem(subreq, c)) return;
     228             : 
     229          10 :         tevent_req_set_callback(subreq, continue_domain_open_open, c);
     230             : }
     231             : 
     232             : 
     233             : /*
     234             :  * Stage 3: Open domain.
     235             :  */
     236          10 : static void continue_domain_open_open(struct tevent_req *subreq)
     237             : {
     238           0 :         struct composite_context *c;
     239           0 :         struct domain_open_samr_state *s;
     240             : 
     241          10 :         c = tevent_req_callback_data(subreq, struct composite_context);
     242          10 :         s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
     243             : 
     244             :         /* receive samr_OpenDomain reply */
     245          10 :         c->status = dcerpc_samr_OpenDomain_r_recv(subreq, s);
     246          10 :         TALLOC_FREE(subreq);
     247          10 :         if (!composite_is_ok(c)) return;
     248             : 
     249          10 :         if (s->monitor_fn) {
     250           0 :                 struct monitor_msg msg;
     251             :                 
     252           0 :                 msg.type = mon_SamrOpenDomain;
     253           0 :                 msg.data = NULL;
     254           0 :                 msg.data_size = 0;
     255           0 :                 s->monitor_fn(&msg);
     256             :         }
     257             : 
     258          10 :         composite_done(c);
     259             : }
     260             : 
     261             : 
     262             : /**
     263             :  * Sends asynchronous DomainOpenSamr request
     264             :  *
     265             :  * @param ctx initialised libnet context
     266             :  * @param io arguments and results of the call
     267             :  * @param monitor pointer to monitor function that is passed monitor message
     268             :  */
     269             : 
     270          10 : struct composite_context *libnet_DomainOpenSamr_send(struct libnet_context *ctx,
     271             :                                                      TALLOC_CTX *mem_ctx,
     272             :                                                      struct libnet_DomainOpen *io,
     273             :                                                      void (*monitor)(struct monitor_msg*))
     274             : {
     275           0 :         struct composite_context *c;
     276           0 :         struct domain_open_samr_state *s;
     277           0 :         struct composite_context *rpcconn_req;
     278           0 :         struct tevent_req *subreq;
     279             : 
     280          10 :         c = composite_create(mem_ctx, ctx->event_ctx);
     281          10 :         if (c == NULL) return NULL;
     282             : 
     283          10 :         s = talloc_zero(c, struct domain_open_samr_state);
     284          10 :         if (composite_nomem(s, c)) return c;
     285             : 
     286          10 :         c->private_data = s;
     287          10 :         s->monitor_fn   = monitor;
     288             : 
     289          10 :         s->ctx                 = ctx;
     290          10 :         s->pipe                = ctx->samr.pipe;
     291          10 :         s->access_mask         = io->in.access_mask;
     292          10 :         s->domain_name.string  = talloc_strdup(c, io->in.domain_name);
     293             : 
     294             :         /* check, if there's samr pipe opened already, before opening a domain */
     295          10 :         if (ctx->samr.pipe == NULL) {
     296             : 
     297             :                 /* attempting to connect a domain controller */
     298           4 :                 s->rpcconn.level           = LIBNET_RPC_CONNECT_DC;
     299           4 :                 s->rpcconn.in.name         = io->in.domain_name;
     300           4 :                 s->rpcconn.in.dcerpc_iface = &ndr_table_samr;
     301             :                 
     302             :                 /* send rpc pipe connect request */
     303           4 :                 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
     304           4 :                 if (composite_nomem(rpcconn_req, c)) return c;
     305             : 
     306           4 :                 composite_continue(c, rpcconn_req, continue_domain_open_rpc_connect, c);
     307           4 :                 return c;
     308             :         }
     309             : 
     310             :         /* libnet context's domain handle is not empty, so check out what
     311             :            was opened first, before doing anything */
     312           6 :         if (!ndr_policy_handle_empty(&ctx->samr.handle)) {
     313           0 :                 if (strequal(ctx->samr.name, io->in.domain_name) &&
     314           0 :                     ctx->samr.access_mask == io->in.access_mask) {
     315             : 
     316             :                         /* this domain is already opened */
     317           0 :                         composite_done(c);
     318           0 :                         return c;
     319             : 
     320             :                 } else {
     321             :                         /* another domain or access rights have been
     322             :                            requested - close the existing handle first */
     323           0 :                         s->close.in.handle = &ctx->samr.handle;
     324             : 
     325             :                         /* send request to close domain handle */
     326           0 :                         subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
     327           0 :                                                           s->pipe->binding_handle,
     328             :                                                           &s->close);
     329           0 :                         if (composite_nomem(subreq, c)) return c;
     330             : 
     331             :                         /* callback handler */
     332           0 :                         tevent_req_set_callback(subreq, continue_domain_open_close, c);
     333           0 :                         return c;
     334             :                 }
     335             :         }
     336             : 
     337             :         /* preparing parameters for samr_Connect rpc call */
     338           6 :         s->connect.in.system_name      = 0;
     339           6 :         s->connect.in.access_mask      = s->access_mask;
     340           6 :         s->connect.out.connect_handle  = &s->connect_handle;
     341             :         
     342             :         /* send request */
     343           6 :         subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
     344           6 :                                             s->pipe->binding_handle,
     345             :                                             &s->connect);
     346           6 :         if (composite_nomem(subreq, c)) return c;
     347             : 
     348             :         /* callback handler */
     349           6 :         tevent_req_set_callback(subreq, continue_domain_open_connect, c);
     350           6 :         return c;
     351             : }
     352             : 
     353             : 
     354             : /**
     355             :  * Waits for and receives result of asynchronous DomainOpenSamr call
     356             :  * 
     357             :  * @param c composite context returned by asynchronous DomainOpen call
     358             :  * @param ctx initialised libnet context
     359             :  * @param mem_ctx memory context of the call
     360             :  * @param io pointer to results (and arguments) of the call
     361             :  * @return nt status code of execution
     362             :  */
     363             : 
     364          10 : NTSTATUS libnet_DomainOpenSamr_recv(struct composite_context *c, struct libnet_context *ctx,
     365             :                                     TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
     366             : {
     367           0 :         NTSTATUS status;
     368           0 :         struct domain_open_samr_state *s;
     369             : 
     370             :         /* wait for results of sending request */
     371          10 :         status = composite_wait(c);
     372             :         
     373          10 :         if (NT_STATUS_IS_OK(status) && io) {
     374          10 :                 s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
     375          10 :                 io->out.domain_handle = s->domain_handle;
     376             : 
     377             :                 /* store the resulting handle and related data for use by other
     378             :                    libnet functions */
     379          10 :                 ctx->samr.connect_handle = s->connect_handle;
     380          10 :                 ctx->samr.handle      = s->domain_handle;
     381          10 :                 ctx->samr.sid         = talloc_steal(ctx, *s->lookup.out.sid);
     382          10 :                 ctx->samr.name        = talloc_steal(ctx, s->domain_name.string);
     383          10 :                 ctx->samr.access_mask = s->access_mask;
     384             :         }
     385             : 
     386          10 :         talloc_free(c);
     387          10 :         return status;
     388             : }
     389             : 
     390             : 
     391             : struct domain_open_lsa_state {
     392             :         const char *name;
     393             :         uint32_t access_mask;
     394             :         struct libnet_context *ctx;
     395             :         struct libnet_RpcConnect rpcconn;
     396             :         struct lsa_OpenPolicy2   openpol;
     397             :         struct policy_handle handle;
     398             :         struct dcerpc_pipe *pipe;
     399             : 
     400             :         /* information about the progress */
     401             :         void (*monitor_fn)(struct monitor_msg*);
     402             : };
     403             : 
     404             : 
     405             : static void continue_rpc_connect_lsa(struct composite_context *ctx);
     406             : static void continue_lsa_policy_open(struct tevent_req *subreq);
     407             : 
     408             : 
     409             : /**
     410             :  * Sends asynchronous DomainOpenLsa request
     411             :  *
     412             :  * @param ctx initialised libnet context
     413             :  * @param io arguments and results of the call
     414             :  * @param monitor pointer to monitor function that is passed monitor message
     415             :  */
     416             : 
     417           7 : struct composite_context* libnet_DomainOpenLsa_send(struct libnet_context *ctx,
     418             :                                                     TALLOC_CTX *mem_ctx,
     419             :                                                     struct libnet_DomainOpen *io,
     420             :                                                     void (*monitor)(struct monitor_msg*))
     421             : {
     422           0 :         struct composite_context *c;
     423           0 :         struct domain_open_lsa_state *s;
     424           0 :         struct composite_context *rpcconn_req;
     425           0 :         struct tevent_req *subreq;
     426           0 :         struct lsa_QosInfo *qos;
     427             : 
     428             :         /* create composite context and state */
     429           7 :         c = composite_create(mem_ctx, ctx->event_ctx);
     430           7 :         if (c == NULL) return c;
     431             : 
     432           7 :         s = talloc_zero(c, struct domain_open_lsa_state);
     433           7 :         if (composite_nomem(s, c)) return c;
     434             : 
     435           7 :         c->private_data = s;
     436             : 
     437             :         /* store arguments in the state structure */
     438           7 :         s->name         = talloc_strdup(c, io->in.domain_name);
     439           7 :         s->access_mask  = io->in.access_mask;
     440           7 :         s->ctx          = ctx;
     441             : 
     442             :         /* check, if there's lsa pipe opened already, before opening a handle */
     443           7 :         if (ctx->lsa.pipe == NULL) {
     444             : 
     445           4 :                 ZERO_STRUCT(s->rpcconn);
     446             : 
     447             :                 /* attempting to connect a domain controller */
     448           4 :                 s->rpcconn.level           = LIBNET_RPC_CONNECT_DC;
     449           4 :                 s->rpcconn.in.name         = talloc_strdup(c, io->in.domain_name);
     450           4 :                 s->rpcconn.in.dcerpc_iface = &ndr_table_lsarpc;
     451             :                 
     452             :                 /* send rpc pipe connect request */
     453           4 :                 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
     454           4 :                 if (composite_nomem(rpcconn_req, c)) return c;
     455             : 
     456           4 :                 composite_continue(c, rpcconn_req, continue_rpc_connect_lsa, c);
     457           4 :                 return c;
     458             :         }
     459             : 
     460           3 :         s->pipe = ctx->lsa.pipe;
     461             : 
     462             :         /* preparing parameters for lsa_OpenPolicy2 rpc call */
     463           3 :         s->openpol.in.system_name = s->name;
     464           3 :         s->openpol.in.access_mask = s->access_mask;
     465           3 :         s->openpol.in.attr        = talloc_zero(c, struct lsa_ObjectAttribute);
     466             : 
     467           3 :         qos = talloc_zero(c, struct lsa_QosInfo);
     468           3 :         qos->len                 = 0;
     469           3 :         qos->impersonation_level = 2;
     470           3 :         qos->context_mode        = 1;
     471           3 :         qos->effective_only      = 0;
     472             : 
     473           3 :         s->openpol.in.attr->sec_qos = qos;
     474           3 :         s->openpol.out.handle       = &s->handle;
     475             :         
     476             :         /* send rpc request */
     477           3 :         subreq = dcerpc_lsa_OpenPolicy2_r_send(s, c->event_ctx,
     478           3 :                                                s->pipe->binding_handle,
     479             :                                                &s->openpol);
     480           3 :         if (composite_nomem(subreq, c)) return c;
     481             : 
     482           3 :         tevent_req_set_callback(subreq, continue_lsa_policy_open, c);
     483           3 :         return c;
     484             : }
     485             : 
     486             : 
     487             : /*
     488             :   Stage 0.5 (optional): Rpc pipe connected, send lsa open policy request
     489             :  */
     490           4 : static void continue_rpc_connect_lsa(struct composite_context *ctx)
     491             : {
     492           0 :         struct composite_context *c;
     493           0 :         struct domain_open_lsa_state *s;
     494           0 :         struct lsa_QosInfo *qos;
     495           0 :         struct tevent_req *subreq;
     496             : 
     497           4 :         c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
     498           4 :         s = talloc_get_type_abort(c->private_data, struct domain_open_lsa_state);
     499             : 
     500             :         /* receive rpc connection */
     501           4 :         c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
     502           4 :         if (!composite_is_ok(c)) return;
     503             : 
     504             :         /* RpcConnect function leaves the pipe in libnet context,
     505             :            so get it from there */
     506           4 :         s->pipe = s->ctx->lsa.pipe;
     507             : 
     508             :         /* prepare lsa_OpenPolicy2 call */
     509           4 :         s->openpol.in.system_name = s->name;
     510           4 :         s->openpol.in.access_mask = s->access_mask;
     511           4 :         s->openpol.in.attr        = talloc_zero(c, struct lsa_ObjectAttribute);
     512             : 
     513           4 :         qos = talloc_zero(c, struct lsa_QosInfo);
     514           4 :         qos->len                 = 0;
     515           4 :         qos->impersonation_level = 2;
     516           4 :         qos->context_mode        = 1;
     517           4 :         qos->effective_only      = 0;
     518             : 
     519           4 :         s->openpol.in.attr->sec_qos = qos;
     520           4 :         s->openpol.out.handle       = &s->handle;
     521             : 
     522             :         /* send rpc request */
     523           4 :         subreq = dcerpc_lsa_OpenPolicy2_r_send(s, c->event_ctx,
     524           4 :                                                s->pipe->binding_handle,
     525             :                                                &s->openpol);
     526           4 :         if (composite_nomem(subreq, c)) return;
     527             : 
     528           4 :         tevent_req_set_callback(subreq, continue_lsa_policy_open, c);
     529             : }
     530             : 
     531             : 
     532             : /*
     533             :   Stage 1: Lsa policy opened - we're done, if successfully
     534             :  */
     535           7 : static void continue_lsa_policy_open(struct tevent_req *subreq)
     536             : {
     537           0 :         struct composite_context *c;
     538           0 :         struct domain_open_lsa_state *s;
     539             : 
     540           7 :         c = tevent_req_callback_data(subreq, struct composite_context);
     541           7 :         s = talloc_get_type_abort(c->private_data, struct domain_open_lsa_state);
     542             : 
     543           7 :         c->status = dcerpc_lsa_OpenPolicy2_r_recv(subreq, s);
     544           7 :         TALLOC_FREE(subreq);
     545           7 :         if (!composite_is_ok(c)) return;
     546             : 
     547           7 :         if (s->monitor_fn) {
     548           0 :                 struct monitor_msg msg;
     549             :                 
     550           0 :                 msg.type      = mon_LsaOpenPolicy;
     551           0 :                 msg.data      = NULL;
     552           0 :                 msg.data_size = 0;
     553           0 :                 s->monitor_fn(&msg);
     554             :         }
     555             : 
     556           7 :         composite_done(c);
     557             : }
     558             : 
     559             : 
     560             : /**
     561             :  * Receives result of asynchronous DomainOpenLsa call
     562             :  *
     563             :  * @param c composite context returned by asynchronous DomainOpenLsa call
     564             :  * @param ctx initialised libnet context
     565             :  * @param mem_ctx memory context of the call
     566             :  * @param io pointer to results (and arguments) of the call
     567             :  * @return nt status code of execution
     568             :  */
     569             : 
     570           7 : NTSTATUS libnet_DomainOpenLsa_recv(struct composite_context *c, struct libnet_context *ctx,
     571             :                                    TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
     572             : {
     573           0 :         NTSTATUS status;
     574           0 :         struct domain_open_lsa_state *s;
     575             : 
     576           7 :         status = composite_wait(c);
     577             : 
     578           7 :         if (NT_STATUS_IS_OK(status) && io) {
     579             :                 /* everything went fine - get the results and
     580             :                    return the error string */
     581           7 :                 s = talloc_get_type_abort(c->private_data, struct domain_open_lsa_state);
     582           7 :                 io->out.domain_handle = s->handle;
     583             : 
     584           7 :                 ctx->lsa.handle      = s->handle;
     585           7 :                 ctx->lsa.name        = talloc_steal(ctx, s->name);
     586           7 :                 ctx->lsa.access_mask = s->access_mask;
     587             :                 
     588           7 :                 io->out.error_string = talloc_strdup(mem_ctx, "Success");
     589             : 
     590           0 :         } else if (!NT_STATUS_IS_OK(status)) {
     591             :                 /* there was an error, so provide nt status code description */
     592           0 :                 io->out.error_string = talloc_asprintf(mem_ctx,
     593             :                                                        "Failed to open domain: %s",
     594             :                                                        nt_errstr(status));
     595             :         }
     596             : 
     597           7 :         talloc_free(c);
     598           7 :         return status;
     599             : }
     600             : 
     601             : 
     602             : /**
     603             :  * Sends a request to open a domain in desired service
     604             :  *
     605             :  * @param ctx initialised libnet context
     606             :  * @param io arguments and results of the call
     607             :  * @param monitor pointer to monitor function that is passed monitor message
     608             :  */
     609             : 
     610          17 : struct composite_context* libnet_DomainOpen_send(struct libnet_context *ctx,
     611             :                                                  TALLOC_CTX *mem_ctx,
     612             :                                                  struct libnet_DomainOpen *io,
     613             :                                                  void (*monitor)(struct monitor_msg*))
     614             : {
     615           0 :         struct composite_context *c;
     616             : 
     617          17 :         switch (io->in.type) {
     618           7 :         case DOMAIN_LSA:
     619             :                 /* request to open a policy handle on \pipe\lsarpc */
     620           7 :                 c = libnet_DomainOpenLsa_send(ctx, mem_ctx, io, monitor);
     621           7 :                 break;
     622             : 
     623          10 :         case DOMAIN_SAMR:
     624             :         default:
     625             :                 /* request to open a domain policy handle on \pipe\samr */
     626          10 :                 c = libnet_DomainOpenSamr_send(ctx, mem_ctx, io, monitor);
     627          10 :                 break;
     628             :         }
     629             : 
     630          17 :         return c;
     631             : }
     632             : 
     633             : 
     634             : /**
     635             :  * Receive result of domain open request
     636             :  *
     637             :  * @param c composite context returned by DomainOpen_send function
     638             :  * @param ctx initialised libnet context
     639             :  * @param mem_ctx memory context of the call
     640             :  * @param io results and arguments of the call
     641             :  */
     642             : 
     643          17 : NTSTATUS libnet_DomainOpen_recv(struct composite_context *c, struct libnet_context *ctx,
     644             :                                 TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
     645             : {
     646           0 :         NTSTATUS status;
     647             : 
     648          17 :         switch (io->in.type) {
     649           7 :         case DOMAIN_LSA:
     650           7 :                 status = libnet_DomainOpenLsa_recv(c, ctx, mem_ctx, io);
     651           7 :                 break;
     652             : 
     653          10 :         case DOMAIN_SAMR:
     654             :         default:
     655          10 :                 status = libnet_DomainOpenSamr_recv(c, ctx, mem_ctx, io);
     656          10 :                 break;
     657             :         }
     658             :         
     659          17 :         return status;
     660             : }
     661             : 
     662             : 
     663             : /**
     664             :  * Synchronous version of DomainOpen call
     665             :  *
     666             :  * @param ctx initialised libnet context
     667             :  * @param mem_ctx memory context for the call
     668             :  * @param io arguments and results of the call
     669             :  * @return nt status code of execution
     670             :  */
     671             : 
     672           3 : NTSTATUS libnet_DomainOpen(struct libnet_context *ctx,
     673             :                            TALLOC_CTX *mem_ctx,
     674             :                            struct libnet_DomainOpen *io)
     675             : {
     676           3 :         struct composite_context *c = libnet_DomainOpen_send(ctx, mem_ctx, io, NULL);
     677           3 :         return libnet_DomainOpen_recv(c, ctx, mem_ctx, io);
     678             : }
     679             : 
     680             : 
     681             : struct domain_close_lsa_state {
     682             :         struct dcerpc_pipe *pipe;
     683             :         struct lsa_Close close;
     684             :         struct policy_handle handle;
     685             : 
     686             :         void (*monitor_fn)(struct monitor_msg*);
     687             : };
     688             : 
     689             : 
     690             : static void continue_lsa_close(struct tevent_req *subreq);
     691             : 
     692             : 
     693           1 : struct composite_context* libnet_DomainCloseLsa_send(struct libnet_context *ctx,
     694             :                                                      TALLOC_CTX *mem_ctx,
     695             :                                                      struct libnet_DomainClose *io,
     696             :                                                      void (*monitor)(struct monitor_msg*))
     697             : {
     698           0 :         struct composite_context *c;
     699           0 :         struct domain_close_lsa_state *s;
     700           0 :         struct tevent_req *subreq;
     701             : 
     702             :         /* composite context and state structure allocation */
     703           1 :         c = composite_create(mem_ctx, ctx->event_ctx);
     704           1 :         if (c == NULL) return c;
     705             : 
     706           1 :         s = talloc_zero(c, struct domain_close_lsa_state);
     707           1 :         if (composite_nomem(s, c)) return c;
     708             : 
     709           1 :         c->private_data = s;
     710           1 :         s->monitor_fn   = monitor;
     711             : 
     712             :         /* TODO: check if lsa pipe pointer is non-null */
     713             : 
     714           1 :         if (!strequal(ctx->lsa.name, io->in.domain_name)) {
     715           0 :                 composite_error(c, NT_STATUS_INVALID_PARAMETER);
     716           0 :                 return c;
     717             :         }
     718             : 
     719             :         /* get opened lsarpc pipe pointer */
     720           1 :         s->pipe = ctx->lsa.pipe;
     721             :         
     722             :         /* prepare close handle call arguments */
     723           1 :         s->close.in.handle  = &ctx->lsa.handle;
     724           1 :         s->close.out.handle = &s->handle;
     725             : 
     726             :         /* send the request */
     727           1 :         subreq = dcerpc_lsa_Close_r_send(s, c->event_ctx,
     728           1 :                                          s->pipe->binding_handle,
     729             :                                          &s->close);
     730           1 :         if (composite_nomem(subreq, c)) return c;
     731             : 
     732           1 :         tevent_req_set_callback(subreq, continue_lsa_close, c);
     733           1 :         return c;
     734             : }
     735             : 
     736             : 
     737             : /*
     738             :   Stage 1: Receive result of lsa close call
     739             : */
     740           1 : static void continue_lsa_close(struct tevent_req *subreq)
     741             : {
     742           0 :         struct composite_context *c;
     743           0 :         struct domain_close_lsa_state *s;
     744             :         
     745           1 :         c = tevent_req_callback_data(subreq, struct composite_context);
     746           1 :         s = talloc_get_type_abort(c->private_data, struct domain_close_lsa_state);
     747             : 
     748           1 :         c->status = dcerpc_lsa_Close_r_recv(subreq, s);
     749           1 :         TALLOC_FREE(subreq);
     750           1 :         if (!composite_is_ok(c)) return;
     751             : 
     752           1 :         if (s->monitor_fn) {
     753           0 :                 struct monitor_msg msg;
     754             : 
     755           0 :                 msg.type      = mon_LsaClose;
     756           0 :                 msg.data      = NULL;
     757           0 :                 msg.data_size = 0;
     758           0 :                 s->monitor_fn(&msg);
     759             :         }
     760             : 
     761           1 :         composite_done(c);
     762             : }
     763             : 
     764             : 
     765           1 : NTSTATUS libnet_DomainCloseLsa_recv(struct composite_context *c, struct libnet_context *ctx,
     766             :                                     TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
     767             : {
     768           0 :         NTSTATUS status;
     769             : 
     770           1 :         status = composite_wait(c);
     771             : 
     772           1 :         if (NT_STATUS_IS_OK(status) && io) {
     773             :                 /* policy handle closed successfully */
     774             : 
     775           1 :                 ctx->lsa.name = NULL;
     776           1 :                 ZERO_STRUCT(ctx->lsa.handle);
     777             : 
     778           1 :                 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
     779             : 
     780           0 :         } else if (!NT_STATUS_IS_OK(status)) {
     781             :                 /* there was an error, so return description of the status code */
     782           0 :                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
     783             :         }
     784             : 
     785           1 :         talloc_free(c);
     786           1 :         return status;
     787             : }
     788             : 
     789             : 
     790             : struct domain_close_samr_state {
     791             :         struct samr_Close close;
     792             :         struct policy_handle handle;
     793             :         
     794             :         void (*monitor_fn)(struct monitor_msg*);
     795             : };
     796             : 
     797             : 
     798             : static void continue_samr_close(struct tevent_req *subreq);
     799             : 
     800             : 
     801           1 : struct composite_context* libnet_DomainCloseSamr_send(struct libnet_context *ctx,
     802             :                                                       TALLOC_CTX *mem_ctx,
     803             :                                                       struct libnet_DomainClose *io,
     804             :                                                       void (*monitor)(struct monitor_msg*))
     805             : {
     806           0 :         struct composite_context *c;
     807           0 :         struct domain_close_samr_state *s;
     808           0 :         struct tevent_req *subreq;
     809             : 
     810             :         /* composite context and state structure allocation */
     811           1 :         c = composite_create(mem_ctx, ctx->event_ctx);
     812           1 :         if (c == NULL) return c;
     813             : 
     814           1 :         s = talloc_zero(c, struct domain_close_samr_state);
     815           1 :         if (composite_nomem(s, c)) return c;
     816             : 
     817           1 :         c->private_data = s;
     818           1 :         s->monitor_fn   = monitor;
     819             : 
     820             :         /* TODO: check if samr pipe pointer is non-null */
     821             : 
     822           1 :         if (!strequal(ctx->samr.name, io->in.domain_name)) {
     823           0 :                 composite_error(c, NT_STATUS_INVALID_PARAMETER);
     824           0 :                 return c;
     825             :         }
     826             : 
     827             :         /* prepare close domain handle call arguments */
     828           1 :         ZERO_STRUCT(s->close);
     829           1 :         s->close.in.handle  = &ctx->samr.handle;
     830           1 :         s->close.out.handle = &s->handle;
     831             : 
     832             :         /* send the request */
     833           1 :         subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
     834           1 :                                           ctx->samr.pipe->binding_handle,
     835             :                                           &s->close);
     836           1 :         if (composite_nomem(subreq, c)) return c;
     837             : 
     838           1 :         tevent_req_set_callback(subreq, continue_samr_close, c);
     839           1 :         return c;
     840             : }
     841             : 
     842             : 
     843             : /*
     844             :   Stage 1: Receive result of samr close call
     845             : */
     846           1 : static void continue_samr_close(struct tevent_req *subreq)
     847             : {
     848           0 :         struct composite_context *c;
     849           0 :         struct domain_close_samr_state *s;
     850             : 
     851           1 :         c = tevent_req_callback_data(subreq, struct composite_context);
     852           1 :         s = talloc_get_type_abort(c->private_data, struct domain_close_samr_state);
     853             :         
     854           1 :         c->status = dcerpc_samr_Close_r_recv(subreq, s);
     855           1 :         TALLOC_FREE(subreq);
     856           1 :         if (!composite_is_ok(c)) return;
     857             : 
     858           1 :         if (s->monitor_fn) {
     859           0 :                 struct monitor_msg msg;
     860             :                 
     861           0 :                 msg.type      = mon_SamrClose;
     862           0 :                 msg.data      = NULL;
     863           0 :                 msg.data_size = 0;
     864           0 :                 s->monitor_fn(&msg);
     865             :         }
     866             :         
     867           1 :         composite_done(c);
     868             : }
     869             : 
     870             : 
     871           1 : NTSTATUS libnet_DomainCloseSamr_recv(struct composite_context *c, struct libnet_context *ctx,
     872             :                                      TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
     873             : {
     874           0 :         NTSTATUS status;
     875             : 
     876           1 :         status = composite_wait(c);
     877             : 
     878           1 :         if (NT_STATUS_IS_OK(status) && io) {
     879             :                 /* domain policy handle closed successfully */
     880             : 
     881           1 :                 ZERO_STRUCT(ctx->samr.handle);
     882           1 :                 talloc_free(discard_const_p(char, ctx->samr.name));
     883           1 :                 talloc_free(ctx->samr.sid);
     884           1 :                 ctx->samr.name = NULL;
     885           1 :                 ctx->samr.sid = NULL;
     886             : 
     887           1 :                 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
     888             : 
     889           0 :         } else if (!NT_STATUS_IS_OK(status)) {
     890             :                 /* there was an error, so return description of the status code */
     891           0 :                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
     892             :         }
     893             : 
     894           1 :         talloc_free(c);
     895           1 :         return status;
     896             : }
     897             : 
     898             : 
     899           2 : struct composite_context* libnet_DomainClose_send(struct libnet_context *ctx,
     900             :                                                   TALLOC_CTX *mem_ctx,
     901             :                                                   struct libnet_DomainClose *io,
     902             :                                                   void (*monitor)(struct monitor_msg*))
     903             : {
     904           0 :         struct composite_context *c;
     905             : 
     906           2 :         switch (io->in.type) {
     907           1 :         case DOMAIN_LSA:
     908             :                 /* request to close policy handle on \pipe\lsarpc */
     909           1 :                 c = libnet_DomainCloseLsa_send(ctx, mem_ctx, io, monitor);
     910           1 :                 break;
     911             : 
     912           1 :         case DOMAIN_SAMR:
     913             :         default:
     914             :                 /* request to close domain policy handle on \pipe\samr */
     915           1 :                 c = libnet_DomainCloseSamr_send(ctx, mem_ctx, io, monitor);
     916           1 :                 break;
     917             :         }
     918             :         
     919           2 :         return c;
     920             : }
     921             : 
     922             : 
     923           2 : NTSTATUS libnet_DomainClose_recv(struct composite_context *c, struct libnet_context *ctx,
     924             :                                  TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
     925             : {
     926           0 :         NTSTATUS status;
     927             : 
     928           2 :         switch (io->in.type) {
     929           1 :         case DOMAIN_LSA:
     930             :                 /* receive result of closing lsa policy handle */
     931           1 :                 status = libnet_DomainCloseLsa_recv(c, ctx, mem_ctx, io);
     932           1 :                 break;
     933             : 
     934           1 :         case DOMAIN_SAMR:
     935             :         default:
     936             :                 /* receive result of closing samr domain policy handle */
     937           1 :                 status = libnet_DomainCloseSamr_recv(c, ctx, mem_ctx, io);
     938           1 :                 break;
     939             :         }
     940             :         
     941           2 :         return status;
     942             : }
     943             : 
     944             : 
     945           2 : NTSTATUS libnet_DomainClose(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
     946             :                             struct libnet_DomainClose *io)
     947             : {
     948           0 :         struct composite_context *c;
     949             :         
     950           2 :         c = libnet_DomainClose_send(ctx, mem_ctx, io, NULL);
     951           2 :         return libnet_DomainClose_recv(c, ctx, mem_ctx, io);
     952             : }
     953             : 
     954             : 
     955             : struct domain_list_state {      
     956             :         struct libnet_context *ctx;
     957             :         struct libnet_RpcConnect rpcconn;
     958             :         struct samr_Connect samrconn;
     959             :         struct samr_EnumDomains enumdom;
     960             :         struct samr_Close samrclose;
     961             :         const char *hostname;
     962             :         struct policy_handle connect_handle;
     963             :         int buf_size;
     964             :         struct domainlist *domains;
     965             :         uint32_t resume_handle;
     966             :         uint32_t count;
     967             : 
     968             :         void (*monitor_fn)(struct monitor_msg*);
     969             : };
     970             : 
     971             : 
     972             : static void continue_rpc_connect(struct composite_context *c);
     973             : static void continue_samr_connect(struct tevent_req *subreq);
     974             : static void continue_samr_enum_domains(struct tevent_req *subreq);
     975             : static void continue_samr_close_handle(struct tevent_req *subreq);
     976             : 
     977             : static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s);
     978             : 
     979             : 
     980             : /*
     981             :   Stage 1: Receive connected rpc pipe and send connection
     982             :   request to SAMR service
     983             : */
     984           1 : static void continue_rpc_connect(struct composite_context *ctx)
     985             : {
     986           0 :         struct composite_context *c;
     987           0 :         struct domain_list_state *s;
     988           0 :         struct tevent_req *subreq;
     989             : 
     990           1 :         c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
     991           1 :         s = talloc_get_type_abort(c->private_data, struct domain_list_state);
     992             :         
     993           1 :         c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
     994           1 :         if (!composite_is_ok(c)) return;
     995             : 
     996           1 :         s->samrconn.in.system_name     = 0;
     997           1 :         s->samrconn.in.access_mask     = SEC_GENERIC_READ;     /* should be enough */
     998           1 :         s->samrconn.out.connect_handle = &s->connect_handle;
     999             : 
    1000           1 :         subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
    1001           1 :                                             s->ctx->samr.pipe->binding_handle,
    1002             :                                             &s->samrconn);
    1003           1 :         if (composite_nomem(subreq, c)) return;
    1004             : 
    1005           1 :         tevent_req_set_callback(subreq, continue_samr_connect, c);
    1006             : }
    1007             : 
    1008             : 
    1009             : /*
    1010             :   Stage 2: Receive policy handle to the connected SAMR service and issue
    1011             :   a request to enumerate domain databases available
    1012             : */
    1013           2 : static void continue_samr_connect(struct tevent_req *subreq)
    1014             : {
    1015           0 :         struct composite_context *c;
    1016           0 :         struct domain_list_state *s;
    1017             : 
    1018           2 :         c = tevent_req_callback_data(subreq, struct composite_context);
    1019           2 :         s = talloc_get_type_abort(c->private_data, struct domain_list_state);
    1020             :         
    1021           2 :         c->status = dcerpc_samr_Connect_r_recv(subreq, s);
    1022           2 :         TALLOC_FREE(subreq);
    1023           2 :         if (!composite_is_ok(c)) return;
    1024             : 
    1025           2 :         if (s->monitor_fn) {
    1026           0 :                 struct monitor_msg msg;
    1027             :                 
    1028           0 :                 msg.type      = mon_SamrConnect;
    1029           0 :                 msg.data      = NULL;
    1030           0 :                 msg.data_size = 0;
    1031           0 :                 s->monitor_fn(&msg);
    1032             :         }
    1033             : 
    1034           2 :         s->enumdom.in.connect_handle = &s->connect_handle;
    1035           2 :         s->enumdom.in.resume_handle  = &s->resume_handle;
    1036           2 :         s->enumdom.in.buf_size       = s->buf_size;
    1037           2 :         s->enumdom.out.resume_handle = &s->resume_handle;
    1038           2 :         s->enumdom.out.num_entries   = talloc(s, uint32_t);
    1039           2 :         if (composite_nomem(s->enumdom.out.num_entries, c)) return;
    1040           2 :         s->enumdom.out.sam           = talloc(s, struct samr_SamArray *);
    1041           2 :         if (composite_nomem(s->enumdom.out.sam, c)) return;
    1042             : 
    1043           2 :         subreq = dcerpc_samr_EnumDomains_r_send(s, c->event_ctx,
    1044           2 :                                                 s->ctx->samr.pipe->binding_handle,
    1045             :                                                 &s->enumdom);
    1046           2 :         if (composite_nomem(subreq, c)) return;
    1047             : 
    1048           2 :         tevent_req_set_callback(subreq, continue_samr_enum_domains, c);
    1049             : }
    1050             : 
    1051             : 
    1052             : /*
    1053             :   Stage 3: Receive domain names available and repeat the request
    1054             :   enumeration is not complete yet. Close samr connection handle
    1055             :   upon completion.
    1056             : */
    1057           2 : static void continue_samr_enum_domains(struct tevent_req *subreq)
    1058             : {
    1059           0 :         struct composite_context *c;
    1060           0 :         struct domain_list_state *s;
    1061             : 
    1062           2 :         c = tevent_req_callback_data(subreq, struct composite_context);
    1063           2 :         s = talloc_get_type_abort(c->private_data, struct domain_list_state);
    1064             :         
    1065           2 :         c->status = dcerpc_samr_EnumDomains_r_recv(subreq, s);
    1066           2 :         TALLOC_FREE(subreq);
    1067           2 :         if (!composite_is_ok(c)) return;
    1068             : 
    1069           2 :         if (s->monitor_fn) {
    1070           0 :                 struct monitor_msg msg;
    1071             :                 
    1072           0 :                 msg.type      = mon_SamrEnumDomains;
    1073           0 :                 msg.data      = NULL;
    1074           0 :                 msg.data_size = 0;
    1075           0 :                 s->monitor_fn(&msg);
    1076             :         }
    1077             : 
    1078           2 :         if (NT_STATUS_IS_OK(s->enumdom.out.result)) {
    1079             : 
    1080           2 :                 s->domains = get_domain_list(c, s);
    1081             : 
    1082           0 :         } else if (NT_STATUS_EQUAL(s->enumdom.out.result, STATUS_MORE_ENTRIES)) {
    1083             :                 
    1084           0 :                 s->domains = get_domain_list(c, s);
    1085             :                 
    1086             :                 /* prepare next round of enumeration */
    1087           0 :                 s->enumdom.in.connect_handle = &s->connect_handle;
    1088           0 :                 s->enumdom.in.resume_handle  = &s->resume_handle;
    1089           0 :                 s->enumdom.in.buf_size       = s->ctx->samr.buf_size;
    1090           0 :                 s->enumdom.out.resume_handle = &s->resume_handle;
    1091             : 
    1092             :                 /* send the request */
    1093           0 :                 subreq = dcerpc_samr_EnumDomains_r_send(s, c->event_ctx,
    1094           0 :                                                         s->ctx->samr.pipe->binding_handle,
    1095             :                                                         &s->enumdom);
    1096           0 :                 if (composite_nomem(subreq, c)) return;
    1097             : 
    1098           0 :                 tevent_req_set_callback(subreq, continue_samr_enum_domains, c);
    1099             : 
    1100             :         } else {
    1101           0 :                 composite_error(c, s->enumdom.out.result);
    1102           0 :                 return;
    1103             :         }
    1104             : 
    1105             :         /* close samr connection handle */
    1106           2 :         s->samrclose.in.handle  = &s->connect_handle;
    1107           2 :         s->samrclose.out.handle = &s->connect_handle;
    1108             :         
    1109             :         /* send the request */
    1110           2 :         subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
    1111           2 :                                           s->ctx->samr.pipe->binding_handle,
    1112             :                                           &s->samrclose);
    1113           2 :         if (composite_nomem(subreq, c)) return;
    1114             : 
    1115           2 :         tevent_req_set_callback(subreq, continue_samr_close_handle, c);
    1116             : }
    1117             : 
    1118             : 
    1119             : /*
    1120             :   Stage 4: Receive result of closing samr connection handle.
    1121             : */
    1122           2 : static void continue_samr_close_handle(struct tevent_req *subreq)
    1123             : {
    1124           0 :         struct composite_context *c;
    1125           0 :         struct domain_list_state *s;
    1126             : 
    1127           2 :         c = tevent_req_callback_data(subreq, struct composite_context);
    1128           2 :         s = talloc_get_type_abort(c->private_data, struct domain_list_state);
    1129             : 
    1130           2 :         c->status = dcerpc_samr_Close_r_recv(subreq, s);
    1131           2 :         TALLOC_FREE(subreq);
    1132           2 :         if (!composite_is_ok(c)) return;
    1133             : 
    1134           2 :         if (s->monitor_fn) {
    1135           0 :                 struct monitor_msg msg;
    1136             :                 
    1137           0 :                 msg.type      = mon_SamrClose;
    1138           0 :                 msg.data      = NULL;
    1139           0 :                 msg.data_size = 0;
    1140           0 :                 s->monitor_fn(&msg);
    1141             :         }
    1142             : 
    1143             :         /* did everything go fine ? */
    1144           2 :         if (!NT_STATUS_IS_OK(s->samrclose.out.result)) {
    1145           0 :                 composite_error(c, s->samrclose.out.result);
    1146           0 :                 return;
    1147             :         }
    1148             : 
    1149           2 :         composite_done(c);
    1150             : }
    1151             : 
    1152             : 
    1153             : /*
    1154             :   Utility function to copy domain names from result of samr_EnumDomains call
    1155             : */
    1156           2 : static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s)
    1157             : {
    1158           0 :         uint32_t i;
    1159           2 :         if (mem_ctx == NULL || s == NULL) return NULL;
    1160             : 
    1161             :         /* prepare domains array */
    1162           2 :         if (s->domains == NULL) {
    1163           2 :                 s->domains = talloc_array(mem_ctx, struct domainlist,
    1164             :                                           *s->enumdom.out.num_entries);
    1165             :         } else {
    1166           0 :                 s->domains = talloc_realloc(mem_ctx, s->domains, struct domainlist,
    1167             :                                             s->count + *s->enumdom.out.num_entries);
    1168             :         }
    1169             : 
    1170             :         /* copy domain names returned from samr_EnumDomains call */
    1171           6 :         for (i = s->count; i < s->count + *s->enumdom.out.num_entries; i++)
    1172             :         {
    1173           4 :                 struct lsa_String *domain_name = &(*s->enumdom.out.sam)->entries[i - s->count].name;
    1174             : 
    1175             :                 /* strdup name as a child of allocated array to make it follow the array
    1176             :                    in case of talloc_steal or talloc_free */
    1177           4 :                 s->domains[i].name = talloc_strdup(s->domains, domain_name->string);
    1178           4 :                 s->domains[i].sid  = NULL;  /* this is to be filled out later */
    1179             :         }
    1180             : 
    1181             :         /* number of entries returned (domains enumerated) */
    1182           2 :         s->count += *s->enumdom.out.num_entries;
    1183             :         
    1184           2 :         return s->domains;
    1185             : }
    1186             : 
    1187             : 
    1188             : /**
    1189             :  * Sends a request to list domains on given host
    1190             :  *
    1191             :  * @param ctx initialised libnet context
    1192             :  * @param mem_ctx memory context
    1193             :  * @param io arguments and results of the call
    1194             :  * @param monitor pointer to monitor function that is passed monitor messages
    1195             :  */
    1196             : 
    1197           2 : struct composite_context* libnet_DomainList_send(struct libnet_context *ctx,
    1198             :                                                  TALLOC_CTX *mem_ctx,
    1199             :                                                  struct libnet_DomainList *io,
    1200             :                                                  void (*monitor)(struct monitor_msg*))
    1201             : {
    1202           0 :         struct composite_context *c;
    1203           0 :         struct domain_list_state *s;
    1204           0 :         struct composite_context *rpcconn_req;
    1205           0 :         struct tevent_req *subreq;
    1206             : 
    1207             :         /* composite context and state structure allocation */
    1208           2 :         c = composite_create(ctx, ctx->event_ctx);
    1209           2 :         if (c == NULL) return c;
    1210             : 
    1211           2 :         s = talloc_zero(c, struct domain_list_state);
    1212           2 :         if (composite_nomem(s, c)) return c;
    1213             : 
    1214           2 :         c->private_data = s;
    1215           2 :         s->monitor_fn   = monitor;
    1216             : 
    1217           2 :         s->ctx      = ctx;
    1218           2 :         s->hostname = talloc_strdup(c, io->in.hostname);
    1219           2 :         if (composite_nomem(s->hostname, c)) return c;
    1220             : 
    1221             :         /* check whether samr pipe has already been opened */
    1222           2 :         if (ctx->samr.pipe == NULL) {
    1223           1 :                 ZERO_STRUCT(s->rpcconn);
    1224             : 
    1225             :                 /* prepare rpc connect call */
    1226           1 :                 s->rpcconn.level           = LIBNET_RPC_CONNECT_SERVER;
    1227           1 :                 s->rpcconn.in.name         = s->hostname;
    1228           1 :                 s->rpcconn.in.dcerpc_iface = &ndr_table_samr;
    1229             : 
    1230           1 :                 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
    1231           1 :                 if (composite_nomem(rpcconn_req, c)) return c;
    1232             :                 
    1233           1 :                 composite_continue(c, rpcconn_req, continue_rpc_connect, c);
    1234             : 
    1235             :         } else {
    1236             :                 /* prepare samr_Connect call */
    1237           1 :                 s->samrconn.in.system_name     = 0;
    1238           1 :                 s->samrconn.in.access_mask     = SEC_GENERIC_READ;
    1239           1 :                 s->samrconn.out.connect_handle = &s->connect_handle;
    1240             :                 
    1241           1 :                 subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
    1242           1 :                                                     s->ctx->samr.pipe->binding_handle,
    1243             :                                                     &s->samrconn);
    1244           1 :                 if (composite_nomem(subreq, c)) return c;
    1245             : 
    1246           1 :                 tevent_req_set_callback(subreq, continue_samr_connect, c);
    1247             :         }
    1248             : 
    1249           2 :         return c;
    1250             : }
    1251             : 
    1252             : 
    1253             : /**
    1254             :  * Receive result of domain list request
    1255             :  *
    1256             :  * @param c composite context returned by DomainList_send function
    1257             :  * @param ctx initialised libnet context
    1258             :  * @param mem_ctx memory context of the call
    1259             :  * @param io results and arguments of the call
    1260             :  */
    1261             : 
    1262           2 : NTSTATUS libnet_DomainList_recv(struct composite_context *c, struct libnet_context *ctx,
    1263             :                                 TALLOC_CTX *mem_ctx, struct libnet_DomainList *io)
    1264             : {
    1265           0 :         NTSTATUS status;
    1266           0 :         struct domain_list_state *s;
    1267             : 
    1268           2 :         status = composite_wait(c);
    1269             : 
    1270           2 :         s = talloc_get_type_abort(c->private_data, struct domain_list_state);
    1271             : 
    1272           2 :         if (NT_STATUS_IS_OK(status) && ctx && mem_ctx && io) {
    1273             :                 /* fetch the results to be returned by io structure */
    1274           2 :                 io->out.count        = s->count;
    1275           2 :                 io->out.domains      = talloc_steal(mem_ctx, s->domains);
    1276           2 :                 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
    1277             : 
    1278           0 :         } else if (!NT_STATUS_IS_OK(status)) {
    1279             :                 /* there was an error, so return description of the status code */
    1280           0 :                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
    1281             :         }
    1282             : 
    1283           2 :         talloc_free(c);
    1284           2 :         return status;
    1285             : }
    1286             : 
    1287             : 
    1288             : /**
    1289             :  * Synchronous version of DomainList call
    1290             :  *
    1291             :  * @param ctx initialised libnet context
    1292             :  * @param mem_ctx memory context for the call
    1293             :  * @param io arguments and results of the call
    1294             :  * @return nt status code of execution
    1295             :  */
    1296             : 
    1297           2 : NTSTATUS libnet_DomainList(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
    1298             :                            struct libnet_DomainList *io)
    1299             : {
    1300           0 :         struct composite_context *c;
    1301             : 
    1302           2 :         c = libnet_DomainList_send(ctx, mem_ctx, io, NULL);
    1303           2 :         return libnet_DomainList_recv(c, ctx, mem_ctx, io);
    1304             : }

Generated by: LCOV version 1.14