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

          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 functions for user management operations (add/del/chg)
      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             : 
      29             : /*
      30             :  * Composite USER ADD functionality
      31             :  */
      32             : 
      33             : struct useradd_state {
      34             :         struct dcerpc_binding_handle *binding_handle;
      35             :         struct policy_handle     domain_handle;
      36             :         struct samr_CreateUser   createuser;
      37             :         struct policy_handle     user_handle;
      38             :         uint32_t                 user_rid;
      39             : 
      40             :         /* information about the progress */
      41             :         void (*monitor_fn)(struct monitor_msg *);
      42             : };
      43             : 
      44             : 
      45             : static void continue_useradd_create(struct tevent_req *subreq);
      46             : 
      47             : 
      48             : /**
      49             :  * Stage 1 (and the only one for now): Create user account.
      50             :  */
      51           3 : static void continue_useradd_create(struct tevent_req *subreq)
      52             : {
      53           0 :         struct composite_context *c;
      54           0 :         struct useradd_state *s;
      55             : 
      56           3 :         c = tevent_req_callback_data(subreq, struct composite_context);
      57           3 :         s = talloc_get_type(c->private_data, struct useradd_state);
      58             : 
      59             :         /* check rpc layer status code */
      60           3 :         c->status = dcerpc_samr_CreateUser_r_recv(subreq, s);
      61           3 :         TALLOC_FREE(subreq);
      62           3 :         if (!composite_is_ok(c)) return;
      63             : 
      64             :         /* check create user call status code */
      65           3 :         c->status = s->createuser.out.result;
      66             : 
      67             :         /* get created user account data */
      68           3 :         s->user_handle = *s->createuser.out.user_handle;
      69           3 :         s->user_rid    = *s->createuser.out.rid;
      70             : 
      71             :         /* issue a monitor message */
      72           3 :         if (s->monitor_fn) {
      73           0 :                 struct monitor_msg msg;
      74           0 :                 struct msg_rpc_create_user rpc_create;
      75             : 
      76           1 :                 rpc_create.rid = *s->createuser.out.rid;
      77             : 
      78           1 :                 msg.type      = mon_SamrCreateUser;
      79           1 :                 msg.data      = (void*)&rpc_create;
      80           1 :                 msg.data_size = sizeof(rpc_create);
      81             :                 
      82           1 :                 s->monitor_fn(&msg);
      83             :         }
      84             :         
      85           3 :         composite_done(c);
      86             : }
      87             : 
      88             : 
      89             : /**
      90             :  * Sends asynchronous useradd request
      91             :  *
      92             :  * @param p dce/rpc call pipe 
      93             :  * @param io arguments and results of the call
      94             :  * @param monitor monitor function for providing information about the progress
      95             :  */
      96             : 
      97           3 : struct composite_context *libnet_rpc_useradd_send(TALLOC_CTX *mem_ctx,
      98             :                                                   struct tevent_context *ev,
      99             :                                                   struct dcerpc_binding_handle *b,
     100             :                                                   struct libnet_rpc_useradd *io,
     101             :                                                   void (*monitor)(struct monitor_msg*))
     102             : {
     103           0 :         struct composite_context *c;
     104           0 :         struct useradd_state *s;
     105           0 :         struct tevent_req *subreq;
     106             : 
     107           3 :         if (!b || !io) return NULL;
     108             : 
     109             :         /* composite allocation and setup */
     110           3 :         c = composite_create(mem_ctx, ev);
     111           3 :         if (c == NULL) return NULL;
     112             :         
     113           3 :         s = talloc_zero(c, struct useradd_state);
     114           3 :         if (composite_nomem(s, c)) return c;
     115             :         
     116           3 :         c->private_data = s;
     117             : 
     118             :         /* put passed arguments to the state structure */
     119           3 :         s->domain_handle = io->in.domain_handle;
     120           3 :         s->binding_handle= b;
     121           3 :         s->monitor_fn    = monitor;
     122             :         
     123             :         /* preparing parameters to send rpc request */
     124           3 :         s->createuser.in.domain_handle         = &io->in.domain_handle;
     125             : 
     126           3 :         s->createuser.in.account_name          = talloc_zero(c, struct lsa_String);
     127           3 :         if (composite_nomem(s->createuser.in.account_name, c)) return c;
     128             : 
     129           3 :         s->createuser.in.account_name->string  = talloc_strdup(c, io->in.username);
     130           3 :         if (composite_nomem(s->createuser.in.account_name->string, c)) return c;
     131             : 
     132           3 :         s->createuser.out.user_handle          = &s->user_handle;
     133           3 :         s->createuser.out.rid                  = &s->user_rid;
     134             : 
     135             :         /* send the request */
     136           3 :         subreq = dcerpc_samr_CreateUser_r_send(s, c->event_ctx,
     137             :                                                s->binding_handle,
     138             :                                                &s->createuser);
     139           3 :         if (composite_nomem(subreq, c)) return c;
     140             : 
     141           3 :         tevent_req_set_callback(subreq, continue_useradd_create, c);
     142           3 :         return c;
     143             : }
     144             : 
     145             : 
     146             : /**
     147             :  * Waits for and receives result of asynchronous useradd call
     148             :  * 
     149             :  * @param c composite context returned by asynchronous useradd call
     150             :  * @param mem_ctx memory context of the call
     151             :  * @param io pointer to results (and arguments) of the call
     152             :  * @return nt status code of execution
     153             :  */
     154             : 
     155           3 : NTSTATUS libnet_rpc_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
     156             :                                  struct libnet_rpc_useradd *io)
     157             : {
     158           0 :         NTSTATUS status;
     159           0 :         struct useradd_state *s;
     160             :         
     161           3 :         status = composite_wait(c);
     162             :         
     163           3 :         if (NT_STATUS_IS_OK(status) && io) {
     164             :                 /* get and return result of the call */
     165           3 :                 s = talloc_get_type(c->private_data, struct useradd_state);
     166           3 :                 io->out.user_handle = s->user_handle;
     167             :         }
     168             : 
     169           3 :         talloc_free(c);
     170           3 :         return status;
     171             : }
     172             : 
     173             : 
     174             : /**
     175             :  * Synchronous version of useradd call
     176             :  *
     177             :  * @param pipe dce/rpc call pipe
     178             :  * @param mem_ctx memory context for the call
     179             :  * @param io arguments and results of the call
     180             :  * @return nt status code of execution
     181             :  */
     182             : 
     183           1 : NTSTATUS libnet_rpc_useradd(struct tevent_context *ev,
     184             :                             struct dcerpc_binding_handle *b,
     185             :                             TALLOC_CTX *mem_ctx,
     186             :                             struct libnet_rpc_useradd *io)
     187             : {
     188           1 :         struct composite_context *c = libnet_rpc_useradd_send(mem_ctx, ev, b, io, NULL);
     189           1 :         return libnet_rpc_useradd_recv(c, mem_ctx, io);
     190             : }
     191             : 
     192             : 
     193             : 
     194             : /*
     195             :  * Composite USER DELETE functionality
     196             :  */
     197             : 
     198             : 
     199             : struct userdel_state {
     200             :         struct dcerpc_binding_handle *binding_handle;
     201             :         struct policy_handle      domain_handle;
     202             :         struct policy_handle      user_handle;
     203             :         struct samr_LookupNames   lookupname;
     204             :         struct samr_OpenUser      openuser;
     205             :         struct samr_DeleteUser    deleteuser;
     206             : 
     207             :         /* information about the progress */
     208             :         void (*monitor_fn)(struct monitor_msg *);
     209             : };
     210             : 
     211             : 
     212             : static void continue_userdel_name_found(struct tevent_req *subreq);
     213             : static void continue_userdel_user_opened(struct tevent_req *subreq);
     214             : static void continue_userdel_deleted(struct tevent_req *subreq);
     215             : 
     216             : 
     217             : /**
     218             :  * Stage 1: Lookup the user name and resolve it to rid
     219             :  */
     220           2 : static void continue_userdel_name_found(struct tevent_req *subreq)
     221             : {
     222           0 :         struct composite_context *c;
     223           0 :         struct userdel_state *s;
     224           0 :         struct monitor_msg msg;
     225             : 
     226           2 :         c = tevent_req_callback_data(subreq, struct composite_context);
     227           2 :         s = talloc_get_type(c->private_data, struct userdel_state);
     228             : 
     229             :         /* receive samr_LookupNames result */
     230           2 :         c->status = dcerpc_samr_LookupNames_r_recv(subreq, s);
     231           2 :         TALLOC_FREE(subreq);
     232           2 :         if (!composite_is_ok(c)) return;
     233             : 
     234           2 :         c->status = s->lookupname.out.result;
     235           2 :         if (!NT_STATUS_IS_OK(c->status)) {
     236           0 :                 composite_error(c, c->status);
     237           0 :                 return;
     238             :         }
     239             : 
     240             :         /* what to do when there's no user account to delete
     241             :            and what if there's more than one rid resolved */
     242           2 :         if (s->lookupname.out.rids->count != s->lookupname.in.num_names) {
     243           0 :                 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
     244           0 :                 return;
     245             :         }
     246           2 :         if (s->lookupname.out.types->count != s->lookupname.in.num_names) {
     247           0 :                 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
     248           0 :                 return;
     249             :         }
     250             : 
     251             :         /* issue a monitor message */
     252           2 :         if (s->monitor_fn) {
     253           0 :                 struct msg_rpc_lookup_name msg_lookup;
     254             : 
     255           0 :                 msg_lookup.rid   = s->lookupname.out.rids->ids;
     256           0 :                 msg_lookup.count = s->lookupname.out.rids->count;
     257             : 
     258           0 :                 msg.type      = mon_SamrLookupName;
     259           0 :                 msg.data      = (void*)&msg_lookup;
     260           0 :                 msg.data_size = sizeof(msg_lookup);
     261           0 :                 s->monitor_fn(&msg);
     262             :         }
     263             : 
     264             :         /* prepare the arguments for rpc call */
     265           2 :         s->openuser.in.domain_handle = &s->domain_handle;
     266           2 :         s->openuser.in.rid           = s->lookupname.out.rids->ids[0];
     267           2 :         s->openuser.in.access_mask   = SEC_FLAG_MAXIMUM_ALLOWED;
     268           2 :         s->openuser.out.user_handle  = &s->user_handle;
     269             : 
     270             :         /* send rpc request */
     271           2 :         subreq = dcerpc_samr_OpenUser_r_send(s, c->event_ctx,
     272             :                                              s->binding_handle,
     273             :                                              &s->openuser);
     274           2 :         if (composite_nomem(subreq, c)) return;
     275             : 
     276           2 :         tevent_req_set_callback(subreq, continue_userdel_user_opened, c);
     277             : }
     278             : 
     279             : 
     280             : /**
     281             :  * Stage 2: Open user account.
     282             :  */
     283           2 : static void continue_userdel_user_opened(struct tevent_req *subreq)
     284             : {
     285           0 :         struct composite_context *c;
     286           0 :         struct userdel_state *s;
     287           0 :         struct monitor_msg msg;
     288             : 
     289           2 :         c = tevent_req_callback_data(subreq, struct composite_context);
     290           2 :         s = talloc_get_type(c->private_data, struct userdel_state);
     291             : 
     292             :         /* receive samr_OpenUser result */
     293           2 :         c->status = dcerpc_samr_OpenUser_r_recv(subreq, s);
     294           2 :         TALLOC_FREE(subreq);
     295           2 :         if (!composite_is_ok(c)) return;
     296             : 
     297           2 :         c->status = s->openuser.out.result;
     298           2 :         if (!NT_STATUS_IS_OK(c->status)) {
     299           0 :                 composite_error(c, c->status);
     300           0 :                 return;
     301             :         }
     302             :         
     303             :         /* issue a monitor message */
     304           2 :         if (s->monitor_fn) {
     305           0 :                 struct msg_rpc_open_user msg_open;
     306             : 
     307           0 :                 msg_open.rid         = s->openuser.in.rid;
     308           0 :                 msg_open.access_mask = s->openuser.in.access_mask;
     309             : 
     310           0 :                 msg.type      = mon_SamrOpenUser;
     311           0 :                 msg.data      = (void*)&msg_open;
     312           0 :                 msg.data_size = sizeof(msg_open);
     313           0 :                 s->monitor_fn(&msg);
     314             :         }
     315             : 
     316             :         /* prepare the final rpc call arguments */
     317           2 :         s->deleteuser.in.user_handle   = &s->user_handle;
     318           2 :         s->deleteuser.out.user_handle  = &s->user_handle;
     319             :         
     320             :         /* send rpc request */
     321           2 :         subreq = dcerpc_samr_DeleteUser_r_send(s, c->event_ctx,
     322             :                                                s->binding_handle,
     323             :                                                &s->deleteuser);
     324           2 :         if (composite_nomem(subreq, c)) return;
     325             : 
     326             :         /* callback handler setup */
     327           2 :         tevent_req_set_callback(subreq, continue_userdel_deleted, c);
     328             : }
     329             : 
     330             : 
     331             : /**
     332             :  * Stage 3: Delete user account
     333             :  */
     334           2 : static void continue_userdel_deleted(struct tevent_req *subreq)
     335             : {
     336           0 :         struct composite_context *c;
     337           0 :         struct userdel_state *s;
     338           0 :         struct monitor_msg msg;
     339             : 
     340           2 :         c = tevent_req_callback_data(subreq, struct composite_context);
     341           2 :         s = talloc_get_type(c->private_data, struct userdel_state);
     342             : 
     343             :         /* receive samr_DeleteUser result */
     344           2 :         c->status = dcerpc_samr_DeleteUser_r_recv(subreq, s);
     345           2 :         TALLOC_FREE(subreq);
     346           2 :         if (!composite_is_ok(c)) return;
     347             : 
     348             :         /* return the actual function call status */
     349           2 :         c->status = s->deleteuser.out.result;
     350           2 :         if (!NT_STATUS_IS_OK(c->status)) {
     351           0 :                 composite_error(c, c->status);
     352           0 :                 return;
     353             :         }
     354             :         
     355             :         /* issue a monitor message */
     356           2 :         if (s->monitor_fn) {
     357           0 :                 msg.type      = mon_SamrDeleteUser;
     358           0 :                 msg.data      = NULL;
     359           0 :                 msg.data_size = 0;
     360           0 :                 s->monitor_fn(&msg);
     361             :         }
     362             : 
     363           2 :         composite_done(c);
     364             : }
     365             : 
     366             : 
     367             : /**
     368             :  * Sends asynchronous userdel request
     369             :  *
     370             :  * @param p dce/rpc call pipe
     371             :  * @param io arguments and results of the call
     372             :  * @param monitor monitor function for providing information about the progress
     373             :  */
     374             : 
     375           2 : struct composite_context *libnet_rpc_userdel_send(TALLOC_CTX *mem_ctx,
     376             :                                                   struct tevent_context *ev,
     377             :                                                   struct dcerpc_binding_handle *b,
     378             :                                                   struct libnet_rpc_userdel *io,
     379             :                                                   void (*monitor)(struct monitor_msg*))
     380             : {
     381           0 :         struct composite_context *c;
     382           0 :         struct userdel_state *s;
     383           0 :         struct tevent_req *subreq;
     384             : 
     385             :         /* composite context allocation and setup */
     386           2 :         c = composite_create(mem_ctx, ev);
     387           2 :         if (c == NULL) return NULL;
     388             : 
     389           2 :         s = talloc_zero(c, struct userdel_state);
     390           2 :         if (composite_nomem(s, c)) return c;
     391             : 
     392           2 :         c->private_data  = s;
     393             : 
     394             :         /* store function parameters in the state structure */
     395           2 :         s->binding_handle= b;
     396           2 :         s->domain_handle = io->in.domain_handle;
     397           2 :         s->monitor_fn    = monitor;
     398             :         
     399             :         /* preparing parameters to send rpc request */
     400           2 :         s->lookupname.in.domain_handle = &io->in.domain_handle;
     401           2 :         s->lookupname.in.num_names     = 1;
     402           2 :         s->lookupname.in.names         = talloc_zero(s, struct lsa_String);
     403           2 :         s->lookupname.in.names->string = io->in.username;
     404           2 :         s->lookupname.out.rids         = talloc_zero(s, struct samr_Ids);
     405           2 :         s->lookupname.out.types        = talloc_zero(s, struct samr_Ids);
     406           2 :         if (composite_nomem(s->lookupname.out.rids, c)) return c;
     407           2 :         if (composite_nomem(s->lookupname.out.types, c)) return c;
     408             : 
     409             :         /* send the request */
     410           2 :         subreq = dcerpc_samr_LookupNames_r_send(s, c->event_ctx,
     411             :                                                 s->binding_handle,
     412             :                                                 &s->lookupname);
     413           2 :         if (composite_nomem(subreq, c)) return c;
     414             : 
     415             :         /* set the next stage */
     416           2 :         tevent_req_set_callback(subreq, continue_userdel_name_found, c);
     417           2 :         return c;
     418             : }
     419             : 
     420             : 
     421             : /**
     422             :  * Waits for and receives results of asynchronous userdel call
     423             :  *
     424             :  * @param c composite context returned by asynchronous userdel call
     425             :  * @param mem_ctx memory context of the call
     426             :  * @param io pointer to results (and arguments) of the call
     427             :  * @return nt status code of execution
     428             :  */
     429             : 
     430           2 : NTSTATUS libnet_rpc_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
     431             :                                  struct libnet_rpc_userdel *io)
     432             : {
     433           0 :         NTSTATUS status;
     434           0 :         struct userdel_state *s;
     435             :         
     436           2 :         status = composite_wait(c);
     437             : 
     438           2 :         if (NT_STATUS_IS_OK(status) && io) {
     439           2 :                 s  = talloc_get_type(c->private_data, struct userdel_state);
     440           2 :                 io->out.user_handle = s->user_handle;
     441             :         }
     442             : 
     443           2 :         talloc_free(c);
     444           2 :         return status;
     445             : }
     446             : 
     447             : 
     448             : /**
     449             :  * Synchronous version of userdel call
     450             :  *
     451             :  * @param pipe dce/rpc call pipe
     452             :  * @param mem_ctx memory context for the call
     453             :  * @param io arguments and results of the call
     454             :  * @return nt status code of execution
     455             :  */
     456             : 
     457           1 : NTSTATUS libnet_rpc_userdel(struct tevent_context *ev,
     458             :                             struct dcerpc_binding_handle *b,
     459             :                             TALLOC_CTX *mem_ctx,
     460             :                             struct libnet_rpc_userdel *io)
     461             : {
     462           1 :         struct composite_context *c = libnet_rpc_userdel_send(mem_ctx, ev, b, io, NULL);
     463           1 :         return libnet_rpc_userdel_recv(c, mem_ctx, io);
     464             : }
     465             : 
     466             : 
     467             : /*
     468             :  * USER MODIFY functionality
     469             :  */
     470             : 
     471             : static void continue_usermod_name_found(struct tevent_req *subreq);
     472             : static void continue_usermod_user_opened(struct tevent_req *subreq);
     473             : static void continue_usermod_user_queried(struct tevent_req *subreq);
     474             : static void continue_usermod_user_changed(struct tevent_req *subreq);
     475             : 
     476             : 
     477             : struct usermod_state {
     478             :         struct dcerpc_binding_handle *binding_handle;
     479             :         struct policy_handle       domain_handle;
     480             :         struct policy_handle       user_handle;
     481             :         struct usermod_change      change;
     482             :         union  samr_UserInfo       info;
     483             :         struct samr_LookupNames    lookupname;
     484             :         struct samr_OpenUser       openuser;
     485             :         struct samr_SetUserInfo    setuser;
     486             :         struct samr_QueryUserInfo  queryuser;
     487             : 
     488             :         /* information about the progress */
     489             :         void (*monitor_fn)(struct monitor_msg *);
     490             : };
     491             : 
     492             : 
     493             : /**
     494             :  * Step 1: Lookup user name
     495             :  */
     496          20 : static void continue_usermod_name_found(struct tevent_req *subreq)
     497             : {
     498           0 :         struct composite_context *c;
     499           0 :         struct usermod_state *s;
     500           0 :         struct monitor_msg msg;
     501             : 
     502          20 :         c = tevent_req_callback_data(subreq, struct composite_context);
     503          20 :         s = talloc_get_type(c->private_data, struct usermod_state);
     504             : 
     505             :         /* receive samr_LookupNames result */
     506          20 :         c->status = dcerpc_samr_LookupNames_r_recv(subreq, s);
     507          20 :         TALLOC_FREE(subreq);
     508          20 :         if (!composite_is_ok(c)) return;
     509             : 
     510          20 :         c->status = s->lookupname.out.result;
     511          20 :         if (!NT_STATUS_IS_OK(c->status)) {
     512           0 :                 composite_error(c, c->status);
     513           0 :                 return;
     514             :         }
     515             : 
     516             :         /* what to do when there's no user account to delete
     517             :            and what if there's more than one rid resolved */
     518          20 :         if (s->lookupname.out.rids->count != s->lookupname.in.num_names) {
     519           0 :                 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
     520           0 :                 return;
     521             :         }
     522          20 :         if (s->lookupname.out.types->count != s->lookupname.in.num_names) {
     523           0 :                 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
     524           0 :                 return;
     525             :         }
     526             : 
     527             :         /* issue a monitor message */
     528          20 :         if (s->monitor_fn) {
     529           0 :                 struct msg_rpc_lookup_name msg_lookup;
     530             : 
     531           0 :                 msg_lookup.rid   = s->lookupname.out.rids->ids;
     532           0 :                 msg_lookup.count = s->lookupname.out.rids->count;
     533             : 
     534           0 :                 msg.type      = mon_SamrLookupName;
     535           0 :                 msg.data      = (void*)&msg_lookup;
     536           0 :                 msg.data_size = sizeof(msg_lookup);
     537           0 :                 s->monitor_fn(&msg);
     538             :         }
     539             : 
     540             :         /* prepare the next rpc call */
     541          20 :         s->openuser.in.domain_handle = &s->domain_handle;
     542          20 :         s->openuser.in.rid           = s->lookupname.out.rids->ids[0];
     543          20 :         s->openuser.in.access_mask   = SEC_FLAG_MAXIMUM_ALLOWED;
     544          20 :         s->openuser.out.user_handle  = &s->user_handle;
     545             : 
     546             :         /* send the rpc request */
     547          20 :         subreq = dcerpc_samr_OpenUser_r_send(s, c->event_ctx,
     548             :                                              s->binding_handle,
     549             :                                              &s->openuser);
     550          20 :         if (composite_nomem(subreq, c)) return;
     551             : 
     552          20 :         tevent_req_set_callback(subreq, continue_usermod_user_opened, c);
     553             : }
     554             : 
     555             : 
     556             : /**
     557             :  * Choose a proper level of samr_UserInfo structure depending on required
     558             :  * change specified by means of flags field. Subsequent calls of this
     559             :  * function are made until there's no flags set meaning that all of the
     560             :  * changes have been made.
     561             :  */
     562          71 : static bool usermod_setfields(struct usermod_state *s, uint16_t *level,
     563             :                               union samr_UserInfo *i, bool queried)
     564             : {
     565          71 :         if (s->change.fields == 0) return s->change.fields;
     566             : 
     567          71 :         *level = 0;
     568             : 
     569          71 :         if ((s->change.fields & USERMOD_FIELD_ACCOUNT_NAME) &&
     570             :             (*level == 0 || *level == 7)) {
     571           4 :                 *level = 7;
     572           4 :                 i->info7.account_name.string = s->change.account_name;
     573             :                 
     574           4 :                 s->change.fields ^= USERMOD_FIELD_ACCOUNT_NAME;
     575             :         }
     576             : 
     577          80 :         if ((s->change.fields & USERMOD_FIELD_FULL_NAME) &&
     578           9 :             (*level == 0 || *level == 8)) {
     579           6 :                 *level = 8;
     580           6 :                 i->info8.full_name.string = s->change.full_name;
     581             :                 
     582           6 :                 s->change.fields ^= USERMOD_FIELD_FULL_NAME;
     583             :         }
     584             :         
     585          83 :         if ((s->change.fields & USERMOD_FIELD_DESCRIPTION) &&
     586          12 :             (*level == 0 || *level == 13)) {
     587           5 :                 *level = 13;
     588           5 :                 i->info13.description.string = s->change.description;
     589             :                 
     590           5 :                 s->change.fields ^= USERMOD_FIELD_DESCRIPTION;               
     591             :         }
     592             : 
     593          83 :         if ((s->change.fields & USERMOD_FIELD_COMMENT) &&
     594          12 :             (*level == 0 || *level == 2)) {
     595           6 :                 *level = 2;
     596             :                 
     597           6 :                 if (queried) {
     598             :                         /* the user info is obtained, so now set the required field */
     599           3 :                         i->info2.comment.string = s->change.comment;
     600           3 :                         s->change.fields ^= USERMOD_FIELD_COMMENT;
     601             :                         
     602             :                 } else {
     603             :                         /* we need to query the user info before setting one field in it */
     604             :                         return false;
     605             :                 }
     606             :         }
     607             : 
     608          74 :         if ((s->change.fields & USERMOD_FIELD_LOGON_SCRIPT) &&
     609           6 :             (*level == 0 || *level == 11)) {
     610           2 :                 *level = 11;
     611           2 :                 i->info11.logon_script.string = s->change.logon_script;
     612             :                 
     613           2 :                 s->change.fields ^= USERMOD_FIELD_LOGON_SCRIPT;
     614             :         }
     615             : 
     616          93 :         if ((s->change.fields & USERMOD_FIELD_PROFILE_PATH) &&
     617          25 :             (*level == 0 || *level == 12)) {
     618          10 :                 *level = 12;
     619          10 :                 i->info12.profile_path.string = s->change.profile_path;
     620             :                 
     621          10 :                 s->change.fields ^= USERMOD_FIELD_PROFILE_PATH;
     622             :         }
     623             : 
     624         106 :         if ((s->change.fields & USERMOD_FIELD_HOME_DIRECTORY) &&
     625          38 :             (*level == 0 || *level == 10)) {
     626          16 :                 *level = 10;
     627             :                 
     628          16 :                 if (queried) {
     629           8 :                         i->info10.home_directory.string = s->change.home_directory;
     630           8 :                         s->change.fields ^= USERMOD_FIELD_HOME_DIRECTORY;
     631             :                 } else {
     632             :                         return false;
     633             :                 }
     634             :         }
     635             : 
     636          94 :         if ((s->change.fields & USERMOD_FIELD_HOME_DRIVE) &&
     637          34 :             (*level == 0 || *level == 10)) {
     638          11 :                 *level = 10;
     639             :                 
     640          11 :                 if (queried) {
     641           9 :                         i->info10.home_drive.string = s->change.home_drive;
     642           9 :                         s->change.fields ^= USERMOD_FIELD_HOME_DRIVE;
     643             :                 } else {
     644             :                         return false;
     645             :                 }
     646             :         }
     647             :         
     648         101 :         if ((s->change.fields & USERMOD_FIELD_ACCT_EXPIRY) &&
     649          43 :             (*level == 0 || *level == 17)) {
     650          11 :                 *level = 17;
     651          11 :                 i->info17.acct_expiry = timeval_to_nttime(s->change.acct_expiry);
     652             :                 
     653          11 :                 s->change.fields ^= USERMOD_FIELD_ACCT_EXPIRY;
     654             :         }
     655             : 
     656          98 :         if ((s->change.fields & USERMOD_FIELD_ACCT_FLAGS) &&
     657          40 :             (*level == 0 || *level == 16)) {
     658           7 :                 *level = 16;
     659           7 :                 i->info16.acct_flags = s->change.acct_flags;
     660             :                 
     661           7 :                 s->change.fields ^= USERMOD_FIELD_ACCT_FLAGS;
     662             :         }
     663             : 
     664             :         /* We're going to be here back again soon unless all fields have been set */
     665             :         return true;
     666             : }
     667             : 
     668             : 
     669          58 : static NTSTATUS usermod_change(struct composite_context *c,
     670             :                                struct usermod_state *s)
     671             : {
     672           0 :         bool do_set;
     673          58 :         union samr_UserInfo *i = &s->info;
     674           0 :         struct tevent_req *subreq;
     675             : 
     676             :         /* set the level to invalid value, so that unless setfields routine 
     677             :            gives it a valid value we report the error correctly */
     678          58 :         uint16_t level = 27;
     679             : 
     680             :         /* prepare UserInfo level and data based on bitmask field */
     681          58 :         do_set = usermod_setfields(s, &level, i, false);
     682             : 
     683          58 :         if (level < 1 || level > 26) {
     684             :                 /* apparently there's a field that the setfields routine
     685             :                    does not know how to set */
     686           0 :                 return NT_STATUS_INVALID_PARAMETER;
     687             :         }
     688             : 
     689             :         /* If some specific level is used to set user account data and the change
     690             :            itself does not cover all fields then we need to query the user info
     691             :            first, right before changing the data. Otherwise we could set required
     692             :            fields and accidentally reset the others.
     693             :         */
     694          58 :         if (!do_set) {
     695          13 :                 s->queryuser.in.user_handle = &s->user_handle;
     696          13 :                 s->queryuser.in.level       = level;
     697          13 :                 s->queryuser.out.info       = talloc(s, union samr_UserInfo *);
     698          13 :                 if (composite_nomem(s->queryuser.out.info, c)) return NT_STATUS_NO_MEMORY;
     699             : 
     700             : 
     701             :                 /* send query user info request to retrieve complete data of
     702             :                    a particular info level */
     703          13 :                 subreq = dcerpc_samr_QueryUserInfo_r_send(s, c->event_ctx,
     704             :                                                           s->binding_handle,
     705             :                                                           &s->queryuser);
     706          13 :                 if (composite_nomem(subreq, c)) return NT_STATUS_NO_MEMORY;
     707          13 :                 tevent_req_set_callback(subreq, continue_usermod_user_queried, c);
     708             : 
     709             :         } else {
     710          45 :                 s->setuser.in.user_handle  = &s->user_handle;
     711          45 :                 s->setuser.in.level        = level;
     712          45 :                 s->setuser.in.info         = i;
     713             : 
     714             :                 /* send set user info request after making required change */
     715          45 :                 subreq = dcerpc_samr_SetUserInfo_r_send(s, c->event_ctx,
     716             :                                                         s->binding_handle,
     717             :                                                         &s->setuser);
     718          45 :                 if (composite_nomem(subreq, c)) return NT_STATUS_NO_MEMORY;
     719          45 :                 tevent_req_set_callback(subreq, continue_usermod_user_changed, c);
     720             :         }
     721             :         
     722          58 :         return NT_STATUS_OK;
     723             : }
     724             : 
     725             : 
     726             : /**
     727             :  * Stage 2: Open user account
     728             :  */
     729          20 : static void continue_usermod_user_opened(struct tevent_req *subreq)
     730             : {
     731           0 :         struct composite_context *c;
     732           0 :         struct usermod_state *s;
     733             : 
     734          20 :         c = tevent_req_callback_data(subreq, struct composite_context);
     735          20 :         s = talloc_get_type(c->private_data, struct usermod_state);
     736             : 
     737          20 :         c->status = dcerpc_samr_OpenUser_r_recv(subreq, s);
     738          20 :         TALLOC_FREE(subreq);
     739          20 :         if (!composite_is_ok(c)) return;
     740             : 
     741          20 :         c->status = s->openuser.out.result;
     742          20 :         if (!NT_STATUS_IS_OK(c->status)) {
     743           0 :                 composite_error(c, c->status);
     744           0 :                 return;
     745             :         }
     746             : 
     747          20 :         c->status = usermod_change(c, s);
     748             : }
     749             : 
     750             : 
     751             : /**
     752             :  * Stage 2a (optional): Query the user information
     753             :  */
     754          13 : static void continue_usermod_user_queried(struct tevent_req *subreq)
     755             : {
     756           0 :         struct composite_context *c;
     757           0 :         struct usermod_state *s;
     758           0 :         union samr_UserInfo *i;
     759          13 :         uint16_t level = 0;
     760             :         
     761          13 :         c = tevent_req_callback_data(subreq, struct composite_context);
     762          13 :         s = talloc_get_type(c->private_data, struct usermod_state);
     763             : 
     764          13 :         i = &s->info;
     765             : 
     766             :         /* receive samr_QueryUserInfo result */
     767          13 :         c->status = dcerpc_samr_QueryUserInfo_r_recv(subreq, s);
     768          13 :         TALLOC_FREE(subreq);
     769          13 :         if (!composite_is_ok(c)) return;
     770             : 
     771          13 :         c->status = s->queryuser.out.result;
     772          13 :         if (!NT_STATUS_IS_OK(c->status)) {
     773           0 :                 composite_error(c, c->status);
     774           0 :                 return;
     775             :         }
     776             : 
     777             :         /* get returned user data and make a change (potentially one
     778             :            of many) */
     779          13 :         s->info = *(*s->queryuser.out.info);
     780             : 
     781          13 :         usermod_setfields(s, &level, i, true);
     782             : 
     783             :         /* prepare rpc call arguments */
     784          13 :         s->setuser.in.user_handle  = &s->user_handle;
     785          13 :         s->setuser.in.level        = level;
     786          13 :         s->setuser.in.info         = i;
     787             : 
     788             :         /* send the rpc request */
     789          13 :         subreq = dcerpc_samr_SetUserInfo_r_send(s, c->event_ctx,
     790             :                                                 s->binding_handle,
     791             :                                                 &s->setuser);
     792          13 :         if (composite_nomem(subreq, c)) return;
     793          13 :         tevent_req_set_callback(subreq, continue_usermod_user_changed, c);
     794             : }
     795             : 
     796             : 
     797             : /**
     798             :  * Stage 3: Set new user account data
     799             :  */
     800          58 : static void continue_usermod_user_changed(struct tevent_req *subreq)
     801             : {
     802           0 :         struct composite_context *c;
     803           0 :         struct usermod_state *s;
     804             :         
     805          58 :         c = tevent_req_callback_data(subreq, struct composite_context);
     806          58 :         s = talloc_get_type(c->private_data, struct usermod_state);
     807             : 
     808             :         /* receive samr_SetUserInfo result */
     809          58 :         c->status = dcerpc_samr_SetUserInfo_r_recv(subreq, s);
     810          58 :         TALLOC_FREE(subreq);
     811          58 :         if (!composite_is_ok(c)) return;
     812             : 
     813             :         /* return the actual function call status */
     814          58 :         c->status = s->setuser.out.result;
     815          58 :         if (!NT_STATUS_IS_OK(c->status)) {
     816           0 :                 composite_error(c, c->status);
     817           0 :                 return;
     818             :         }
     819             : 
     820          58 :         if (s->change.fields == 0) {
     821             :                 /* all fields have been set - we're done */
     822          20 :                 composite_done(c);
     823             : 
     824             :         } else {
     825             :                 /* something's still not changed - repeat the procedure */
     826          38 :                 c->status = usermod_change(c, s);
     827             :         }
     828             : }
     829             : 
     830             : 
     831             : /**
     832             :  * Sends asynchronous usermod request
     833             :  *
     834             :  * @param p dce/rpc call pipe
     835             :  * @param io arguments and results of the call
     836             :  * @param monitor monitor function for providing information about the progress
     837             :  */
     838             : 
     839          20 : struct composite_context *libnet_rpc_usermod_send(TALLOC_CTX *mem_ctx,
     840             :                                                   struct tevent_context *ev,
     841             :                                                   struct dcerpc_binding_handle *b,
     842             :                                                   struct libnet_rpc_usermod *io,
     843             :                                                   void (*monitor)(struct monitor_msg*))
     844             : {
     845           0 :         struct composite_context *c;
     846           0 :         struct usermod_state *s;
     847           0 :         struct tevent_req *subreq;
     848             : 
     849             :         /* composite context allocation and setup */
     850          20 :         c = composite_create(mem_ctx, ev);
     851          20 :         if (c == NULL) return NULL;
     852          20 :         s = talloc_zero(c, struct usermod_state);
     853          20 :         if (composite_nomem(s, c)) return c;
     854             : 
     855          20 :         c->private_data = s;
     856             : 
     857             :         /* store parameters in the call structure */
     858          20 :         s->binding_handle= b;
     859          20 :         s->domain_handle = io->in.domain_handle;
     860          20 :         s->change        = io->in.change;
     861          20 :         s->monitor_fn    = monitor;
     862             :         
     863             :         /* prepare rpc call arguments */
     864          20 :         s->lookupname.in.domain_handle = &io->in.domain_handle;
     865          20 :         s->lookupname.in.num_names     = 1;
     866          20 :         s->lookupname.in.names         = talloc_zero(s, struct lsa_String);
     867          20 :         s->lookupname.in.names->string = io->in.username;
     868          20 :         s->lookupname.out.rids         = talloc_zero(s, struct samr_Ids);
     869          20 :         s->lookupname.out.types        = talloc_zero(s, struct samr_Ids);
     870          20 :         if (composite_nomem(s->lookupname.out.rids, c)) return c;
     871          20 :         if (composite_nomem(s->lookupname.out.types, c)) return c;
     872             : 
     873             :         /* send the rpc request */
     874          20 :         subreq = dcerpc_samr_LookupNames_r_send(s, c->event_ctx,
     875             :                                                 s->binding_handle,
     876             :                                                 &s->lookupname);
     877          20 :         if (composite_nomem(subreq, c)) return c;
     878             :         
     879             :         /* callback handler setup */
     880          20 :         tevent_req_set_callback(subreq, continue_usermod_name_found, c);
     881          20 :         return c;
     882             : }
     883             : 
     884             : 
     885             : /**
     886             :  * Waits for and receives results of asynchronous usermod call
     887             :  *
     888             :  * @param c composite context returned by asynchronous usermod call
     889             :  * @param mem_ctx memory context of the call
     890             :  * @param io pointer to results (and arguments) of the call
     891             :  * @return nt status code of execution
     892             :  */
     893             : 
     894          20 : NTSTATUS libnet_rpc_usermod_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
     895             :                                  struct libnet_rpc_usermod *io)
     896             : {
     897           0 :         NTSTATUS status;
     898             :         
     899          20 :         status = composite_wait(c);
     900             : 
     901          20 :         talloc_free(c);
     902          20 :         return status;
     903             : }
     904             : 
     905             : 
     906             : /**
     907             :  * Synchronous version of usermod call
     908             :  *
     909             :  * @param pipe dce/rpc call pipe
     910             :  * @param mem_ctx memory context for the call
     911             :  * @param io arguments and results of the call
     912             :  * @return nt status code of execution
     913             :  */
     914             : 
     915          10 : NTSTATUS libnet_rpc_usermod(struct tevent_context *ev,
     916             :                             struct dcerpc_binding_handle *b,
     917             :                             TALLOC_CTX *mem_ctx,
     918             :                             struct libnet_rpc_usermod *io)
     919             : {
     920          10 :         struct composite_context *c = libnet_rpc_usermod_send(mem_ctx, ev, b, io, NULL);
     921          10 :         return libnet_rpc_usermod_recv(c, mem_ctx, io);
     922             : }

Generated by: LCOV version 1.13