root/source4/libnet/userman.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. continue_useradd_create
  2. libnet_rpc_useradd_send
  3. libnet_rpc_useradd_recv
  4. libnet_rpc_useradd
  5. continue_userdel_name_found
  6. continue_userdel_user_opened
  7. continue_userdel_deleted
  8. libnet_rpc_userdel_send
  9. libnet_rpc_userdel_recv
  10. libnet_rpc_userdel
  11. continue_usermod_name_found
  12. usermod_setfields
  13. usermod_change
  14. continue_usermod_user_opened
  15. continue_usermod_user_queried
  16. continue_usermod_user_changed
  17. libnet_rpc_usermod_send
  18. libnet_rpc_usermod_recv
  19. libnet_rpc_usermod

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

/* [<][>][^][v][top][bottom][index][help] */