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#include "includes.h" 22#include "libnet/libnet.h" 23#include "libcli/composite/composite.h" 24#include "auth/credentials/credentials.h" 25#include "librpc/ndr/libndr.h" 26#include "librpc/gen_ndr/samr.h" 27#include "librpc/gen_ndr/ndr_samr_c.h" 28#include "librpc/gen_ndr/lsa.h" 29#include "librpc/gen_ndr/ndr_lsa_c.h" 30#include "libcli/security/security.h" 31 32 33struct create_user_state { 34 struct libnet_CreateUser r; 35 struct libnet_DomainOpen domain_open; 36 struct libnet_rpc_useradd user_add; 37 struct libnet_context *ctx; 38 39 /* information about the progress */ 40 void (*monitor_fn)(struct monitor_msg *); 41}; 42 43 44static void continue_rpc_useradd(struct composite_context *ctx); 45static void continue_domain_open_create(struct composite_context *ctx); 46 47 48/** 49 * Sends request to create user account 50 * 51 * @param ctx initialised libnet context 52 * @param mem_ctx memory context of this call 53 * @param r pointer to a structure containing arguments and results of this call 54 * @param monitor function pointer for receiving monitor messages 55 * @return compostite context of this request 56 */ 57struct composite_context* libnet_CreateUser_send(struct libnet_context *ctx, 58 TALLOC_CTX *mem_ctx, 59 struct libnet_CreateUser *r, 60 void (*monitor)(struct monitor_msg*)) 61{ 62 struct composite_context *c; 63 struct create_user_state *s; 64 struct composite_context *create_req; 65 bool prereq_met = false; 66 67 /* composite context allocation and setup */ 68 c = composite_create(mem_ctx, ctx->event_ctx); 69 if (c == NULL) return NULL; 70 71 s = talloc_zero(c, struct create_user_state); 72 if (composite_nomem(s, c)) return c; 73 74 c->private_data = s; 75 76 /* store arguments in the state structure */ 77 s->ctx = ctx; 78 s->r = *r; 79 ZERO_STRUCT(s->r.out); 80 81 /* prerequisite: make sure the domain is opened */ 82 prereq_met = samr_domain_opened(ctx, s->r.in.domain_name, &c, &s->domain_open, 83 continue_domain_open_create, monitor); 84 if (!prereq_met) return c; 85 86 /* prepare arguments for useradd call */ 87 s->user_add.in.username = r->in.user_name; 88 s->user_add.in.domain_handle = ctx->samr.handle; 89 90 /* send the request */ 91 create_req = libnet_rpc_useradd_send(ctx->samr.pipe, &s->user_add, monitor); 92 if (composite_nomem(create_req, c)) return c; 93 94 /* set the next stage */ 95 composite_continue(c, create_req, continue_rpc_useradd, c); 96 return c; 97} 98 99 100/* 101 * Stage 0.5 (optional): receive result of domain open request 102 * and send useradd request 103 */ 104static void continue_domain_open_create(struct composite_context *ctx) 105{ 106 struct composite_context *c; 107 struct create_user_state *s; 108 struct composite_context *create_req; 109 struct monitor_msg msg; 110 111 c = talloc_get_type(ctx->async.private_data, struct composite_context); 112 s = talloc_get_type(c->private_data, struct create_user_state); 113 114 /* receive result of DomainOpen call */ 115 c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open); 116 if (!composite_is_ok(c)) return; 117 118 /* send monitor message */ 119 if (s->monitor_fn) s->monitor_fn(&msg); 120 121 /* prepare arguments for useradd call */ 122 s->user_add.in.username = s->r.in.user_name; 123 s->user_add.in.domain_handle = s->ctx->samr.handle; 124 125 /* send the request */ 126 create_req = libnet_rpc_useradd_send(s->ctx->samr.pipe, &s->user_add, s->monitor_fn); 127 if (composite_nomem(create_req, c)) return; 128 129 /* set the next stage */ 130 composite_continue(c, create_req, continue_rpc_useradd, c); 131} 132 133 134/* 135 * Stage 1: receive result of useradd call 136 */ 137static void continue_rpc_useradd(struct composite_context *ctx) 138{ 139 struct composite_context *c; 140 struct create_user_state *s; 141 struct monitor_msg msg; 142 143 c = talloc_get_type(ctx->async.private_data, struct composite_context); 144 s = talloc_get_type(c->private_data, struct create_user_state); 145 146 /* receive result of the call */ 147 c->status = libnet_rpc_useradd_recv(ctx, c, &s->user_add); 148 if (!composite_is_ok(c)) return; 149 150 /* send monitor message */ 151 if (s->monitor_fn) s->monitor_fn(&msg); 152 153 /* we're done */ 154 composite_done(c); 155} 156 157 158/** 159 * Receive result of CreateUser call 160 * 161 * @param c composite context returned by send request routine 162 * @param mem_ctx memory context of this call 163 * @param r pointer to a structure containing arguments and result of this call 164 * @return nt status 165 */ 166NTSTATUS libnet_CreateUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 167 struct libnet_CreateUser *r) 168{ 169 NTSTATUS status; 170 struct create_user_state *s; 171 172 r->out.error_string = NULL; 173 174 /* wait for result of async request and check status code */ 175 status = composite_wait(c); 176 if (!NT_STATUS_IS_OK(status)) { 177 s = talloc_get_type(c->private_data, struct create_user_state); 178 r->out.error_string = talloc_strdup(mem_ctx, nt_errstr(status)); 179 } 180 181 return status; 182} 183 184 185/** 186 * Synchronous version of CreateUser call 187 * 188 * @param ctx initialised libnet context 189 * @param mem_ctx memory context of this call 190 * @param r pointer to a structure containing arguments and result of this call 191 * @return nt status 192 */ 193NTSTATUS libnet_CreateUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, 194 struct libnet_CreateUser *r) 195{ 196 struct composite_context *c; 197 198 c = libnet_CreateUser_send(ctx, mem_ctx, r, NULL); 199 return libnet_CreateUser_recv(c, mem_ctx, r); 200} 201 202 203struct delete_user_state { 204 struct libnet_DeleteUser r; 205 struct libnet_context *ctx; 206 struct libnet_DomainOpen domain_open; 207 struct libnet_rpc_userdel user_del; 208 209 /* information about the progress */ 210 void (*monitor_fn)(struct monitor_msg *); 211}; 212 213 214static void continue_rpc_userdel(struct composite_context *ctx); 215static void continue_domain_open_delete(struct composite_context *ctx); 216 217 218/** 219 * Sends request to delete user account 220 * 221 * @param ctx initialised libnet context 222 * @param mem_ctx memory context of this call 223 * @param r pointer to structure containing arguments and result of this call 224 * @param monitor function pointer for receiving monitor messages 225 */ 226struct composite_context *libnet_DeleteUser_send(struct libnet_context *ctx, 227 TALLOC_CTX *mem_ctx, 228 struct libnet_DeleteUser *r, 229 void (*monitor)(struct monitor_msg*)) 230{ 231 struct composite_context *c; 232 struct delete_user_state *s; 233 struct composite_context *delete_req; 234 bool prereq_met = false; 235 236 /* composite context allocation and setup */ 237 c = composite_create(mem_ctx, ctx->event_ctx); 238 if (c == NULL) return NULL; 239 240 s = talloc_zero(c, struct delete_user_state); 241 if (composite_nomem(s, c)) return c; 242 243 c->private_data = s; 244 245 /* store arguments in state structure */ 246 s->ctx = ctx; 247 s->r = *r; 248 ZERO_STRUCT(s->r.out); 249 250 /* prerequisite: make sure the domain is opened before proceeding */ 251 prereq_met = samr_domain_opened(ctx, s->r.in.domain_name, &c, &s->domain_open, 252 continue_domain_open_delete, monitor); 253 if (!prereq_met) return c; 254 255 /* prepare arguments for userdel call */ 256 s->user_del.in.username = r->in.user_name; 257 s->user_del.in.domain_handle = ctx->samr.handle; 258 259 /* send request */ 260 delete_req = libnet_rpc_userdel_send(ctx->samr.pipe, &s->user_del, monitor); 261 if (composite_nomem(delete_req, c)) return c; 262 263 /* set the next stage */ 264 composite_continue(c, delete_req, continue_rpc_userdel, c); 265 return c; 266} 267 268 269/* 270 * Stage 0.5 (optional): receive result of domain open request 271 * and send useradd request 272 */ 273static void continue_domain_open_delete(struct composite_context *ctx) 274{ 275 struct composite_context *c; 276 struct delete_user_state *s; 277 struct composite_context *delete_req; 278 struct monitor_msg msg; 279 280 c = talloc_get_type(ctx->async.private_data, struct composite_context); 281 s = talloc_get_type(c->private_data, struct delete_user_state); 282 283 /* receive result of DomainOpen call */ 284 c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open); 285 if (!composite_is_ok(c)) return; 286 287 /* send monitor message */ 288 if (s->monitor_fn) s->monitor_fn(&msg); 289 290 /* prepare arguments for userdel call */ 291 s->user_del.in.username = s->r.in.user_name; 292 s->user_del.in.domain_handle = s->ctx->samr.handle; 293 294 /* send request */ 295 delete_req = libnet_rpc_userdel_send(s->ctx->samr.pipe, &s->user_del, s->monitor_fn); 296 if (composite_nomem(delete_req, c)) return; 297 298 /* set the next stage */ 299 composite_continue(c, delete_req, continue_rpc_userdel, c); 300} 301 302 303/* 304 * Stage 1: receive result of userdel call and finish the composite function 305 */ 306static void continue_rpc_userdel(struct composite_context *ctx) 307{ 308 struct composite_context *c; 309 struct delete_user_state *s; 310 struct monitor_msg msg; 311 312 c = talloc_get_type(ctx->async.private_data, struct composite_context); 313 s = talloc_get_type(c->private_data, struct delete_user_state); 314 315 /* receive result of userdel call */ 316 c->status = libnet_rpc_userdel_recv(ctx, c, &s->user_del); 317 if (!composite_is_ok(c)) return; 318 319 /* send monitor message */ 320 if (s->monitor_fn) s->monitor_fn(&msg); 321 322 /* we're done */ 323 composite_done(c); 324} 325 326 327/** 328 * Receives result of asynchronous DeleteUser call 329 * 330 * @param c composite context returned by async DeleteUser call 331 * @param mem_ctx memory context of this call 332 * @param r pointer to structure containing arguments and result 333 */ 334NTSTATUS libnet_DeleteUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 335 struct libnet_DeleteUser *r) 336{ 337 NTSTATUS status; 338 struct delete_user_state *s; 339 340 r->out.error_string = NULL; 341 342 /* wait for result of async request and check status code */ 343 status = composite_wait(c); 344 if (!NT_STATUS_IS_OK(status)) { 345 s = talloc_get_type(c->private_data, struct delete_user_state); 346 r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string); 347 } 348 349 return status; 350} 351 352 353/** 354 * Synchronous version of DeleteUser call 355 * 356 * @param ctx initialised libnet context 357 * @param mem_ctx memory context of this call 358 * @param r pointer to structure containing arguments and result 359 */ 360NTSTATUS libnet_DeleteUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, 361 struct libnet_DeleteUser *r) 362{ 363 struct composite_context *c; 364 365 c = libnet_DeleteUser_send(ctx, mem_ctx, r, NULL); 366 return libnet_DeleteUser_recv(c, mem_ctx, r); 367} 368 369 370struct modify_user_state { 371 struct libnet_ModifyUser r; 372 struct libnet_context *ctx; 373 struct libnet_DomainOpen domain_open; 374 struct libnet_rpc_userinfo user_info; 375 struct libnet_rpc_usermod user_mod; 376 377 void (*monitor_fn)(struct monitor_msg *); 378}; 379 380 381static void continue_rpc_usermod(struct composite_context *ctx); 382static void continue_domain_open_modify(struct composite_context *ctx); 383static NTSTATUS set_user_changes(TALLOC_CTX *mem_ctx, struct usermod_change *mod, 384 struct libnet_rpc_userinfo *info, struct libnet_ModifyUser *r); 385static void continue_rpc_userinfo(struct composite_context *ctx); 386 387 388/** 389 * Sends request to modify user account 390 * 391 * @param ctx initialised libnet context 392 * @param mem_ctx memory context of this call 393 * @param r pointer to structure containing arguments and result of this call 394 * @param monitor function pointer for receiving monitor messages 395 */ 396struct composite_context *libnet_ModifyUser_send(struct libnet_context *ctx, 397 TALLOC_CTX *mem_ctx, 398 struct libnet_ModifyUser *r, 399 void (*monitor)(struct monitor_msg*)) 400{ 401 const uint16_t level = 21; 402 struct composite_context *c; 403 struct modify_user_state *s; 404 struct composite_context *userinfo_req; 405 bool prereq_met = false; 406 407 c = composite_create(mem_ctx, ctx->event_ctx); 408 if (c == NULL) return NULL; 409 410 s = talloc_zero(c, struct modify_user_state); 411 if (composite_nomem(s, c)) return c; 412 413 c->private_data = s; 414 415 s->ctx = ctx; 416 s->r = *r; 417 418 prereq_met = samr_domain_opened(ctx, s->r.in.domain_name, &c, &s->domain_open, 419 continue_domain_open_modify, monitor); 420 if (!prereq_met) return c; 421 422 s->user_info.in.username = r->in.user_name; 423 s->user_info.in.domain_handle = ctx->samr.handle; 424 s->user_info.in.level = level; 425 426 userinfo_req = libnet_rpc_userinfo_send(ctx->samr.pipe, &s->user_info, monitor); 427 if (composite_nomem(userinfo_req, c)) return c; 428 429 composite_continue(c, userinfo_req, continue_rpc_userinfo, c); 430 return c; 431} 432 433 434/* 435 * Stage 0.5 (optional): receive result of domain open request 436 * and send userinfo request 437 */ 438static void continue_domain_open_modify(struct composite_context *ctx) 439{ 440 const uint16_t level = 21; 441 struct composite_context *c; 442 struct modify_user_state *s; 443 struct composite_context *userinfo_req; 444 struct monitor_msg msg; 445 446 c = talloc_get_type(ctx->async.private_data, struct composite_context); 447 s = talloc_get_type(c->private_data, struct modify_user_state); 448 449 c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open); 450 if (!composite_is_ok(c)) return; 451 452 if (s->monitor_fn) s->monitor_fn(&msg); 453 454 s->user_info.in.domain_handle = s->ctx->samr.handle; 455 s->user_info.in.username = s->r.in.user_name; 456 s->user_info.in.level = level; 457 458 userinfo_req = libnet_rpc_userinfo_send(s->ctx->samr.pipe, &s->user_info, s->monitor_fn); 459 if (composite_nomem(userinfo_req, c)) return; 460 461 composite_continue(c, userinfo_req, continue_rpc_userinfo, c); 462} 463 464 465/* 466 * Stage 1: receive result of userinfo call, prepare user changes 467 * (set the fields a caller required to change) and send usermod request 468 */ 469static void continue_rpc_userinfo(struct composite_context *ctx) 470{ 471 struct composite_context *c; 472 struct modify_user_state *s; 473 struct composite_context *usermod_req; 474 475 c = talloc_get_type(ctx->async.private_data, struct composite_context); 476 s = talloc_get_type(c->private_data, struct modify_user_state); 477 478 c->status = libnet_rpc_userinfo_recv(ctx, c, &s->user_info); 479 if (!composite_is_ok(c)) return; 480 481 s->user_mod.in.domain_handle = s->ctx->samr.handle; 482 s->user_mod.in.username = s->r.in.user_name; 483 484 c->status = set_user_changes(c, &s->user_mod.in.change, &s->user_info, &s->r); 485 486 usermod_req = libnet_rpc_usermod_send(s->ctx->samr.pipe, &s->user_mod, s->monitor_fn); 487 if (composite_nomem(usermod_req, c)) return; 488 489 composite_continue(c, usermod_req, continue_rpc_usermod, c); 490} 491 492 493/* 494 * Prepare user changes: compare userinfo result to requested changes and 495 * set the field values and flags accordingly for user modify call 496 */ 497static NTSTATUS set_user_changes(TALLOC_CTX *mem_ctx, struct usermod_change *mod, 498 struct libnet_rpc_userinfo *info, struct libnet_ModifyUser *r) 499{ 500 struct samr_UserInfo21 *user; 501 502 if (mod == NULL || info == NULL || r == NULL || info->in.level != 21) { 503 return NT_STATUS_INVALID_PARAMETER; 504 } 505 506 user = &info->out.info.info21; 507 mod->fields = 0; /* reset flag field before setting individual flags */ 508 509 /* account name change */ 510 SET_FIELD_LSA_STRING(r->in, user, mod, account_name, USERMOD_FIELD_ACCOUNT_NAME); 511 512 /* full name change */ 513 SET_FIELD_LSA_STRING(r->in, user, mod, full_name, USERMOD_FIELD_FULL_NAME); 514 515 /* description change */ 516 SET_FIELD_LSA_STRING(r->in, user, mod, description, USERMOD_FIELD_DESCRIPTION); 517 518 /* comment change */ 519 SET_FIELD_LSA_STRING(r->in, user, mod, comment, USERMOD_FIELD_COMMENT); 520 521 /* home directory change */ 522 SET_FIELD_LSA_STRING(r->in, user, mod, home_directory, USERMOD_FIELD_HOME_DIRECTORY); 523 524 /* home drive change */ 525 SET_FIELD_LSA_STRING(r->in, user, mod, home_drive, USERMOD_FIELD_HOME_DRIVE); 526 527 /* logon script change */ 528 SET_FIELD_LSA_STRING(r->in, user, mod, logon_script, USERMOD_FIELD_LOGON_SCRIPT); 529 530 /* profile path change */ 531 SET_FIELD_LSA_STRING(r->in, user, mod, profile_path, USERMOD_FIELD_PROFILE_PATH); 532 533 /* account expiry change */ 534 SET_FIELD_NTTIME(r->in, user, mod, acct_expiry, USERMOD_FIELD_ACCT_EXPIRY); 535 536 /* account flags change */ 537 SET_FIELD_ACCT_FLAGS(r->in, user, mod, acct_flags, USERMOD_FIELD_ACCT_FLAGS); 538 539 return NT_STATUS_OK; 540} 541 542 543/* 544 * Stage 2: receive result of usermod request and finish the composite function 545 */ 546static void continue_rpc_usermod(struct composite_context *ctx) 547{ 548 struct composite_context *c; 549 struct modify_user_state *s; 550 struct monitor_msg msg; 551 552 c = talloc_get_type(ctx->async.private_data, struct composite_context); 553 s = talloc_get_type(c->private_data, struct modify_user_state); 554 555 c->status = libnet_rpc_usermod_recv(ctx, c, &s->user_mod); 556 if (!composite_is_ok(c)) return; 557 558 if (s->monitor_fn) s->monitor_fn(&msg); 559 composite_done(c); 560} 561 562 563/** 564 * Receive result of ModifyUser call 565 * 566 * @param c composite context returned by send request routine 567 * @param mem_ctx memory context of this call 568 * @param r pointer to a structure containing arguments and result of this call 569 * @return nt status 570 */ 571NTSTATUS libnet_ModifyUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 572 struct libnet_ModifyUser *r) 573{ 574 NTSTATUS status = composite_wait(c); 575 return status; 576} 577 578 579/** 580 * Synchronous version of ModifyUser call 581 * 582 * @param ctx initialised libnet context 583 * @param mem_ctx memory context of this call 584 * @param r pointer to a structure containing arguments and result of this call 585 * @return nt status 586 */ 587NTSTATUS libnet_ModifyUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, 588 struct libnet_ModifyUser *r) 589{ 590 struct composite_context *c; 591 592 c = libnet_ModifyUser_send(ctx, mem_ctx, r, NULL); 593 return libnet_ModifyUser_recv(c, mem_ctx, r); 594} 595 596 597struct user_info_state { 598 struct libnet_context *ctx; 599 const char *domain_name; 600 enum libnet_UserInfo_level level; 601 const char *user_name; 602 const char *sid_string; 603 struct libnet_LookupName lookup; 604 struct libnet_DomainOpen domopen; 605 struct libnet_rpc_userinfo userinfo; 606 607 /* information about the progress */ 608 void (*monitor_fn)(struct monitor_msg *); 609}; 610 611 612static void continue_name_found(struct composite_context *ctx); 613static void continue_domain_open_info(struct composite_context *ctx); 614static void continue_info_received(struct composite_context *ctx); 615 616 617/** 618 * Sends request to get user account information 619 * 620 * @param ctx initialised libnet context 621 * @param mem_ctx memory context of this call 622 * @param r pointer to a structure containing arguments and results of this call 623 * @param monitor function pointer for receiving monitor messages 624 * @return compostite context of this request 625 */ 626struct composite_context* libnet_UserInfo_send(struct libnet_context *ctx, 627 TALLOC_CTX *mem_ctx, 628 struct libnet_UserInfo *r, 629 void (*monitor)(struct monitor_msg*)) 630{ 631 struct composite_context *c; 632 struct user_info_state *s; 633 struct composite_context *lookup_req, *info_req; 634 bool prereq_met = false; 635 636 /* composite context allocation and setup */ 637 c = composite_create(mem_ctx, ctx->event_ctx); 638 if (c == NULL) return NULL; 639 640 s = talloc_zero(c, struct user_info_state); 641 if (composite_nomem(s, c)) return c; 642 643 c->private_data = s; 644 645 /* store arguments in the state structure */ 646 s->monitor_fn = monitor; 647 s->ctx = ctx; 648 s->domain_name = talloc_strdup(c, r->in.domain_name); 649 s->level = r->in.level; 650 switch (s->level) { 651 case USER_INFO_BY_NAME: 652 s->user_name = talloc_strdup(c, r->in.data.user_name); 653 s->sid_string = NULL; 654 break; 655 case USER_INFO_BY_SID: 656 s->user_name = NULL; 657 s->sid_string = dom_sid_string(c, r->in.data.user_sid); 658 break; 659 } 660 661 /* prerequisite: make sure the domain is opened */ 662 prereq_met = samr_domain_opened(ctx, s->domain_name, &c, &s->domopen, 663 continue_domain_open_info, monitor); 664 if (!prereq_met) return c; 665 666 switch (s->level) { 667 case USER_INFO_BY_NAME: 668 /* prepare arguments for LookupName call */ 669 s->lookup.in.domain_name = s->domain_name; 670 s->lookup.in.name = s->user_name; 671 672 /* send the request */ 673 lookup_req = libnet_LookupName_send(ctx, c, &s->lookup, 674 s->monitor_fn); 675 if (composite_nomem(lookup_req, c)) return c; 676 677 /* set the next stage */ 678 composite_continue(c, lookup_req, continue_name_found, c); 679 break; 680 case USER_INFO_BY_SID: 681 /* prepare arguments for UserInfo call */ 682 s->userinfo.in.domain_handle = s->ctx->samr.handle; 683 s->userinfo.in.sid = s->sid_string; 684 s->userinfo.in.level = 21; 685 686 /* send the request */ 687 info_req = libnet_rpc_userinfo_send(s->ctx->samr.pipe, 688 &s->userinfo, 689 s->monitor_fn); 690 if (composite_nomem(info_req, c)) return c; 691 692 /* set the next stage */ 693 composite_continue(c, info_req, continue_info_received, c); 694 break; 695 } 696 697 return c; 698} 699 700 701/* 702 * Stage 0.5 (optional): receive result of domain open request 703 * and send LookupName request 704 */ 705static void continue_domain_open_info(struct composite_context *ctx) 706{ 707 struct composite_context *c; 708 struct user_info_state *s; 709 struct composite_context *lookup_req, *info_req; 710 struct monitor_msg msg; 711 712 c = talloc_get_type(ctx->async.private_data, struct composite_context); 713 s = talloc_get_type(c->private_data, struct user_info_state); 714 715 /* receive result of DomainOpen call */ 716 c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domopen); 717 if (!composite_is_ok(c)) return; 718 719 /* send monitor message */ 720 if (s->monitor_fn) s->monitor_fn(&msg); 721 722 switch (s->level) { 723 case USER_INFO_BY_NAME: 724 /* prepare arguments for LookupName call */ 725 s->lookup.in.domain_name = s->domain_name; 726 s->lookup.in.name = s->user_name; 727 728 /* send the request */ 729 lookup_req = libnet_LookupName_send(s->ctx, c, &s->lookup, s->monitor_fn); 730 if (composite_nomem(lookup_req, c)) return; 731 732 /* set the next stage */ 733 composite_continue(c, lookup_req, continue_name_found, c); 734 break; 735 736 case USER_INFO_BY_SID: 737 /* prepare arguments for UserInfo call */ 738 s->userinfo.in.domain_handle = s->ctx->samr.handle; 739 s->userinfo.in.sid = s->sid_string; 740 s->userinfo.in.level = 21; 741 742 /* send the request */ 743 info_req = libnet_rpc_userinfo_send(s->ctx->samr.pipe, 744 &s->userinfo, 745 s->monitor_fn); 746 if (composite_nomem(info_req, c)) return; 747 748 /* set the next stage */ 749 composite_continue(c, info_req, continue_info_received, c); 750 break; 751 } 752} 753 754 755/* 756 * Stage 1: receive the name (if found) and send userinfo request 757 */ 758static void continue_name_found(struct composite_context *ctx) 759{ 760 struct composite_context *c; 761 struct user_info_state *s; 762 struct composite_context *info_req; 763 764 c = talloc_get_type(ctx->async.private_data, struct composite_context); 765 s = talloc_get_type(c->private_data, struct user_info_state); 766 767 /* receive result of LookupName call */ 768 c->status = libnet_LookupName_recv(ctx, c, &s->lookup); 769 if (!composite_is_ok(c)) return; 770 771 /* we're only interested in user accounts this time */ 772 if (s->lookup.out.sid_type != SID_NAME_USER) { 773 composite_error(c, NT_STATUS_NO_SUCH_USER); 774 return; 775 } 776 777 /* prepare arguments for UserInfo call */ 778 s->userinfo.in.domain_handle = s->ctx->samr.handle; 779 s->userinfo.in.sid = s->lookup.out.sidstr; 780 s->userinfo.in.level = 21; 781 782 /* send the request */ 783 info_req = libnet_rpc_userinfo_send(s->ctx->samr.pipe, &s->userinfo, s->monitor_fn); 784 if (composite_nomem(info_req, c)) return; 785 786 /* set the next stage */ 787 composite_continue(c, info_req, continue_info_received, c); 788} 789 790 791/* 792 * Stage 2: receive user account information and finish the composite function 793 */ 794static void continue_info_received(struct composite_context *ctx) 795{ 796 struct composite_context *c; 797 struct user_info_state *s; 798 799 c = talloc_get_type(ctx->async.private_data, struct composite_context); 800 s = talloc_get_type(c->private_data, struct user_info_state); 801 802 /* receive result of userinfo call */ 803 c->status = libnet_rpc_userinfo_recv(ctx, c, &s->userinfo); 804 if (!composite_is_ok(c)) return; 805 806 composite_done(c); 807} 808 809 810/** 811 * Receive result of UserInfo call 812 * 813 * @param c composite context returned by send request routine 814 * @param mem_ctx memory context of this call 815 * @param r pointer to a structure containing arguments and result of this call 816 * @return nt status 817 */ 818NTSTATUS libnet_UserInfo_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 819 struct libnet_UserInfo *r) 820{ 821 NTSTATUS status; 822 struct user_info_state *s; 823 824 status = composite_wait(c); 825 826 if (NT_STATUS_IS_OK(status) && r != NULL) { 827 struct samr_UserInfo21 *info; 828 829 s = talloc_get_type(c->private_data, struct user_info_state); 830 info = &s->userinfo.out.info.info21; 831 832 r->out.user_sid = dom_sid_add_rid(mem_ctx, s->ctx->samr.sid, info->rid); 833 r->out.primary_group_sid = dom_sid_add_rid(mem_ctx, s->ctx->samr.sid, info->primary_gid); 834 835 /* string fields */ 836 r->out.account_name = talloc_steal(mem_ctx, info->account_name.string); 837 r->out.full_name = talloc_steal(mem_ctx, info->full_name.string); 838 r->out.description = talloc_steal(mem_ctx, info->description.string); 839 r->out.home_directory = talloc_steal(mem_ctx, info->home_directory.string); 840 r->out.home_drive = talloc_steal(mem_ctx, info->home_drive.string); 841 r->out.comment = talloc_steal(mem_ctx, info->comment.string); 842 r->out.logon_script = talloc_steal(mem_ctx, info->logon_script.string); 843 r->out.profile_path = talloc_steal(mem_ctx, info->profile_path.string); 844 845 /* time fields (allocation) */ 846 r->out.acct_expiry = talloc(mem_ctx, struct timeval); 847 r->out.allow_password_change = talloc(mem_ctx, struct timeval); 848 r->out.force_password_change = talloc(mem_ctx, struct timeval); 849 r->out.last_logon = talloc(mem_ctx, struct timeval); 850 r->out.last_logoff = talloc(mem_ctx, struct timeval); 851 r->out.last_password_change = talloc(mem_ctx, struct timeval); 852 853 /* time fields (converting) */ 854 nttime_to_timeval(r->out.acct_expiry, info->acct_expiry); 855 nttime_to_timeval(r->out.allow_password_change, info->allow_password_change); 856 nttime_to_timeval(r->out.force_password_change, info->force_password_change); 857 nttime_to_timeval(r->out.last_logon, info->last_logon); 858 nttime_to_timeval(r->out.last_logoff, info->last_logoff); 859 nttime_to_timeval(r->out.last_password_change, info->last_password_change); 860 861 /* flag and number fields */ 862 r->out.acct_flags = info->acct_flags; 863 864 r->out.error_string = talloc_strdup(mem_ctx, "Success"); 865 866 } else { 867 r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status)); 868 } 869 870 talloc_free(c); 871 872 return status; 873} 874 875 876/** 877 * Synchronous version of UserInfo call 878 * 879 * @param ctx initialised libnet context 880 * @param mem_ctx memory context of this call 881 * @param r pointer to a structure containing arguments and result of this call 882 * @return nt status 883 */ 884NTSTATUS libnet_UserInfo(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, 885 struct libnet_UserInfo *r) 886{ 887 struct composite_context *c; 888 889 c = libnet_UserInfo_send(ctx, mem_ctx, r, NULL); 890 return libnet_UserInfo_recv(c, mem_ctx, r); 891} 892 893 894struct userlist_state { 895 struct libnet_context *ctx; 896 const char *domain_name; 897 struct lsa_DomainInfo dominfo; 898 int page_size; 899 uint32_t resume_index; 900 struct userlist *users; 901 uint32_t count; 902 903 struct libnet_DomainOpen domain_open; 904 struct lsa_QueryInfoPolicy query_domain; 905 struct samr_EnumDomainUsers user_list; 906 907 void (*monitor_fn)(struct monitor_msg*); 908}; 909 910 911static void continue_lsa_domain_opened(struct composite_context *ctx); 912static void continue_domain_queried(struct rpc_request *req); 913static void continue_samr_domain_opened(struct composite_context *ctx); 914static void continue_users_enumerated(struct rpc_request *req); 915 916 917/** 918 * Sends request to list (enumerate) user accounts 919 * 920 * @param ctx initialised libnet context 921 * @param mem_ctx memory context of this call 922 * @param r pointer to structure containing arguments and results of this call 923 * @param monitor function pointer for receiving monitor messages 924 * @return compostite context of this request 925 */ 926struct composite_context* libnet_UserList_send(struct libnet_context *ctx, 927 TALLOC_CTX *mem_ctx, 928 struct libnet_UserList *r, 929 void (*monitor)(struct monitor_msg*)) 930{ 931 struct composite_context *c; 932 struct userlist_state *s; 933 struct rpc_request *query_req; 934 bool prereq_met = false; 935 936 /* composite context allocation and setup */ 937 c = composite_create(mem_ctx, ctx->event_ctx); 938 if (c == NULL) return NULL; 939 940 s = talloc_zero(c, struct userlist_state); 941 if (composite_nomem(s, c)) return c; 942 943 c->private_data = s; 944 945 /* store the arguments in the state structure */ 946 s->ctx = ctx; 947 s->page_size = r->in.page_size; 948 s->resume_index = r->in.resume_index; 949 s->domain_name = talloc_strdup(c, r->in.domain_name); 950 s->monitor_fn = monitor; 951 952 /* make sure we have lsa domain handle before doing anything */ 953 prereq_met = lsa_domain_opened(ctx, s->domain_name, &c, &s->domain_open, 954 continue_lsa_domain_opened, monitor); 955 if (!prereq_met) return c; 956 957 /* prepare arguments of QueryDomainInfo call */ 958 s->query_domain.in.handle = &ctx->lsa.handle; 959 s->query_domain.in.level = LSA_POLICY_INFO_DOMAIN; 960 s->query_domain.out.info = talloc_zero(c, union lsa_PolicyInformation *); 961 if (composite_nomem(s->query_domain.out.info, c)) return c; 962 963 /* send the request */ 964 query_req = dcerpc_lsa_QueryInfoPolicy_send(ctx->lsa.pipe, c, &s->query_domain); 965 if (composite_nomem(query_req, c)) return c; 966 967 composite_continue_rpc(c, query_req, continue_domain_queried, c); 968 return c; 969} 970 971 972/* 973 * Stage 0.5 (optional): receive lsa domain handle and send 974 * request to query domain info 975 */ 976static void continue_lsa_domain_opened(struct composite_context *ctx) 977{ 978 struct composite_context *c; 979 struct userlist_state *s; 980 struct rpc_request *query_req; 981 982 c = talloc_get_type(ctx->async.private_data, struct composite_context); 983 s = talloc_get_type(c->private_data, struct userlist_state); 984 985 /* receive lsa domain handle */ 986 c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open); 987 if (!composite_is_ok(c)) return; 988 989 /* prepare arguments of QueryDomainInfo call */ 990 s->query_domain.in.handle = &s->ctx->lsa.handle; 991 s->query_domain.in.level = LSA_POLICY_INFO_DOMAIN; 992 s->query_domain.out.info = talloc_zero(c, union lsa_PolicyInformation *); 993 if (composite_nomem(s->query_domain.out.info, c)) return; 994 995 /* send the request */ 996 query_req = dcerpc_lsa_QueryInfoPolicy_send(s->ctx->lsa.pipe, c, &s->query_domain); 997 if (composite_nomem(query_req, c)) return; 998 999 composite_continue_rpc(c, query_req, continue_domain_queried, c); 1000} 1001 1002 1003/* 1004 * Stage 1: receive domain info and request to enum users, 1005 * provided a valid samr handle is opened 1006 */ 1007static void continue_domain_queried(struct rpc_request *req) 1008{ 1009 struct composite_context *c; 1010 struct userlist_state *s; 1011 struct rpc_request *enum_req; 1012 bool prereq_met = false; 1013 1014 c = talloc_get_type(req->async.private_data, struct composite_context); 1015 s = talloc_get_type(c->private_data, struct userlist_state); 1016 1017 /* receive result of rpc request */ 1018 c->status = dcerpc_ndr_request_recv(req); 1019 if (!composite_is_ok(c)) return; 1020 1021 /* get the returned domain info */ 1022 s->dominfo = (*s->query_domain.out.info)->domain; 1023 1024 /* make sure we have samr domain handle before continuing */ 1025 prereq_met = samr_domain_opened(s->ctx, s->domain_name, &c, &s->domain_open, 1026 continue_samr_domain_opened, s->monitor_fn); 1027 if (!prereq_met) return; 1028 1029 /* prepare arguments of EnumDomainUsers call */ 1030 s->user_list.in.domain_handle = &s->ctx->samr.handle; 1031 s->user_list.in.max_size = s->page_size; 1032 s->user_list.in.resume_handle = &s->resume_index; 1033 s->user_list.in.acct_flags = ACB_NORMAL; 1034 s->user_list.out.resume_handle = &s->resume_index; 1035 s->user_list.out.num_entries = talloc(s, uint32_t); 1036 if (composite_nomem(s->user_list.out.num_entries, c)) return; 1037 s->user_list.out.sam = talloc(s, struct samr_SamArray *); 1038 if (composite_nomem(s->user_list.out.sam, c)) return; 1039 1040 /* send the request */ 1041 enum_req = dcerpc_samr_EnumDomainUsers_send(s->ctx->samr.pipe, c, &s->user_list); 1042 if (composite_nomem(enum_req, c)) return; 1043 1044 composite_continue_rpc(c, enum_req, continue_users_enumerated, c); 1045} 1046 1047 1048/* 1049 * Stage 1.5 (optional): receive samr domain handle 1050 * and request to enumerate accounts 1051 */ 1052static void continue_samr_domain_opened(struct composite_context *ctx) 1053{ 1054 struct composite_context *c; 1055 struct userlist_state *s; 1056 struct rpc_request *enum_req; 1057 1058 c = talloc_get_type(ctx->async.private_data, struct composite_context); 1059 s = talloc_get_type(c->private_data, struct userlist_state); 1060 1061 /* receive samr domain handle */ 1062 c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open); 1063 if (!composite_is_ok(c)) return; 1064 1065 /* prepare arguments of EnumDomainUsers call */ 1066 s->user_list.in.domain_handle = &s->ctx->samr.handle; 1067 s->user_list.in.max_size = s->page_size; 1068 s->user_list.in.resume_handle = &s->resume_index; 1069 s->user_list.in.acct_flags = ACB_NORMAL; 1070 s->user_list.out.resume_handle = &s->resume_index; 1071 s->user_list.out.sam = talloc(s, struct samr_SamArray *); 1072 if (composite_nomem(s->user_list.out.sam, c)) return; 1073 s->user_list.out.num_entries = talloc(s, uint32_t); 1074 if (composite_nomem(s->user_list.out.num_entries, c)) return; 1075 1076 /* send the request */ 1077 enum_req = dcerpc_samr_EnumDomainUsers_send(s->ctx->samr.pipe, c, &s->user_list); 1078 if (composite_nomem(enum_req, c)) return; 1079 1080 composite_continue_rpc(c, enum_req, continue_users_enumerated, c); 1081} 1082 1083 1084/* 1085 * Stage 2: receive enumerated users and their rids 1086 */ 1087static void continue_users_enumerated(struct rpc_request *req) 1088{ 1089 struct composite_context *c; 1090 struct userlist_state *s; 1091 int i; 1092 1093 c = talloc_get_type(req->async.private_data, struct composite_context); 1094 s = talloc_get_type(c->private_data, struct userlist_state); 1095 1096 /* receive result of rpc request */ 1097 c->status = dcerpc_ndr_request_recv(req); 1098 if (!composite_is_ok(c)) return; 1099 1100 /* get the actual status of the rpc call result 1101 (instead of rpc layer status) */ 1102 c->status = s->user_list.out.result; 1103 1104 /* we're interested in status "ok" as well as two 1105 enum-specific status codes */ 1106 if (NT_STATUS_IS_OK(c->status) || 1107 NT_STATUS_EQUAL(c->status, STATUS_MORE_ENTRIES) || 1108 NT_STATUS_EQUAL(c->status, NT_STATUS_NO_MORE_ENTRIES)) { 1109 1110 /* get enumerated accounts counter and resume handle (the latter allows 1111 making subsequent call to continue enumeration) */ 1112 s->resume_index = *s->user_list.out.resume_handle; 1113 s->count = *s->user_list.out.num_entries; 1114 1115 /* prepare returned user accounts array */ 1116 s->users = talloc_array(c, struct userlist, (*s->user_list.out.sam)->count); 1117 if (composite_nomem(s->users, c)) return; 1118 1119 for (i = 0; i < (*s->user_list.out.sam)->count; i++) { 1120 struct dom_sid *user_sid; 1121 struct samr_SamEntry *entry = &(*s->user_list.out.sam)->entries[i]; 1122 struct dom_sid *domain_sid = (*s->query_domain.out.info)->domain.sid; 1123 1124 /* construct user sid from returned rid and queried domain sid */ 1125 user_sid = dom_sid_add_rid(c, domain_sid, entry->idx); 1126 if (composite_nomem(user_sid, c)) return; 1127 1128 /* username */ 1129 s->users[i].username = talloc_strdup(c, entry->name.string); 1130 if (composite_nomem(s->users[i].username, c)) return; 1131 1132 /* sid string */ 1133 s->users[i].sid = dom_sid_string(c, user_sid); 1134 if (composite_nomem(s->users[i].sid, c)) return; 1135 } 1136 1137 /* that's it */ 1138 composite_done(c); 1139 1140 } else { 1141 /* something went wrong */ 1142 composite_error(c, c->status); 1143 } 1144} 1145 1146 1147/** 1148 * Receive result of UserList call 1149 * 1150 * @param c composite context returned by send request routine 1151 * @param mem_ctx memory context of this call 1152 * @param r pointer to structure containing arguments and result of this call 1153 * @return nt status 1154 */ 1155NTSTATUS libnet_UserList_recv(struct composite_context* c, TALLOC_CTX *mem_ctx, 1156 struct libnet_UserList *r) 1157{ 1158 NTSTATUS status; 1159 struct userlist_state *s; 1160 1161 if (c == NULL || mem_ctx == NULL || r == NULL) { 1162 return NT_STATUS_INVALID_PARAMETER; 1163 } 1164 1165 status = composite_wait(c); 1166 if (NT_STATUS_IS_OK(status) || 1167 NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) || 1168 NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) { 1169 1170 s = talloc_get_type(c->private_data, struct userlist_state); 1171 1172 /* get results from composite context */ 1173 r->out.count = s->count; 1174 r->out.resume_index = s->resume_index; 1175 r->out.users = talloc_steal(mem_ctx, s->users); 1176 1177 if (NT_STATUS_IS_OK(status)) { 1178 r->out.error_string = talloc_strdup(mem_ctx, "Success"); 1179 } else { 1180 /* success, but we're not done yet */ 1181 r->out.error_string = talloc_asprintf(mem_ctx, "Success (status: %s)", 1182 nt_errstr(status)); 1183 } 1184 1185 } else { 1186 r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status)); 1187 } 1188 1189 return status; 1190} 1191 1192 1193/** 1194 * Synchronous version of UserList call 1195 * 1196 * @param ctx initialised libnet context 1197 * @param mem_ctx memory context of this call 1198 * @param r pointer to structure containing arguments and result of this call 1199 * @return nt status 1200 */ 1201NTSTATUS libnet_UserList(struct libnet_context *ctx, 1202 TALLOC_CTX *mem_ctx, 1203 struct libnet_UserList *r) 1204{ 1205 struct composite_context *c; 1206 1207 c = libnet_UserList_send(ctx, mem_ctx, r, NULL); 1208 return libnet_UserList_recv(c, mem_ctx, r); 1209} 1210