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 33struct 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 46static void continue_useradd_create(struct rpc_request *req); 47 48 49/** 50 * Stage 1 (and the only one for now): Create user account. 51 */ 52static void continue_useradd_create(struct rpc_request *req) 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 97struct composite_context *libnet_rpc_useradd_send(struct dcerpc_pipe *p, 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 150NTSTATUS libnet_rpc_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 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 178NTSTATUS libnet_rpc_useradd(struct dcerpc_pipe *p, 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 193struct 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 206static void continue_userdel_name_found(struct rpc_request *req); 207static void continue_userdel_user_opened(struct rpc_request* req); 208static void continue_userdel_deleted(struct rpc_request *req); 209 210 211/** 212 * Stage 1: Lookup the user name and resolve it to rid 213 */ 214static void continue_userdel_name_found(struct rpc_request *req) 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 */ 277static void continue_userdel_user_opened(struct rpc_request* req) 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 */ 326static void continue_userdel_deleted(struct rpc_request *req) 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 366struct composite_context *libnet_rpc_userdel_send(struct dcerpc_pipe *p, 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 417NTSTATUS libnet_rpc_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 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 444NTSTATUS libnet_rpc_userdel(struct dcerpc_pipe *p, 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 457static void continue_usermod_name_found(struct rpc_request *req); 458static void continue_usermod_user_opened(struct rpc_request *req); 459static void continue_usermod_user_queried(struct rpc_request *req); 460static void continue_usermod_user_changed(struct rpc_request *req); 461 462 463struct 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 */ 482static void continue_usermod_name_found(struct rpc_request *req) 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 */ 548static bool usermod_setfields(struct usermod_state *s, uint16_t *level, 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 655static NTSTATUS usermod_change(struct composite_context *c, 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 */ 709static void continue_usermod_user_opened(struct rpc_request *req) 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 */ 733static void continue_usermod_user_queried(struct rpc_request *req) 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 */ 776static void continue_usermod_user_changed(struct rpc_request *req) 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 814struct composite_context *libnet_rpc_usermod_send(struct dcerpc_pipe *p, 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 865NTSTATUS libnet_rpc_usermod_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 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 886NTSTATUS libnet_rpc_usermod(struct dcerpc_pipe *p, 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} 893