smbd: change flag name from UCF_CREATING_FILE to UCF_PREP_CREATEFILE
[Samba/wip.git] / source4 / libnet / userman.c
bloba7301eab6c616506ff648e3d28c3c31ffde31b7e
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Rafal Szczesniak 2005
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.
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.
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/>.
21 a composite functions for user management operations (add/del/chg)
24 #include "includes.h"
25 #include "libcli/composite/composite.h"
26 #include "libnet/libnet.h"
27 #include "librpc/gen_ndr/ndr_samr_c.h"
30 * Composite USER ADD functionality
33 struct useradd_state {
34 struct dcerpc_pipe *pipe;
35 struct policy_handle domain_handle;
36 struct samr_CreateUser createuser;
37 struct policy_handle user_handle;
38 uint32_t user_rid;
40 /* information about the progress */
41 void (*monitor_fn)(struct monitor_msg *);
45 static void continue_useradd_create(struct tevent_req *subreq);
48 /**
49 * Stage 1 (and the only one for now): Create user account.
51 static void continue_useradd_create(struct tevent_req *subreq)
53 struct composite_context *c;
54 struct useradd_state *s;
56 c = tevent_req_callback_data(subreq, struct composite_context);
57 s = talloc_get_type(c->private_data, struct useradd_state);
59 /* check rpc layer status code */
60 c->status = dcerpc_samr_CreateUser_r_recv(subreq, s);
61 TALLOC_FREE(subreq);
62 if (!composite_is_ok(c)) return;
64 /* check create user call status code */
65 c->status = s->createuser.out.result;
67 /* get created user account data */
68 s->user_handle = *s->createuser.out.user_handle;
69 s->user_rid = *s->createuser.out.rid;
71 /* issue a monitor message */
72 if (s->monitor_fn) {
73 struct monitor_msg msg;
74 struct msg_rpc_create_user rpc_create;
76 rpc_create.rid = *s->createuser.out.rid;
78 msg.type = mon_SamrCreateUser;
79 msg.data = (void*)&rpc_create;
80 msg.data_size = sizeof(rpc_create);
82 s->monitor_fn(&msg);
85 composite_done(c);
89 /**
90 * Sends asynchronous useradd request
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
97 struct composite_context *libnet_rpc_useradd_send(struct dcerpc_pipe *p,
98 TALLOC_CTX *mem_ctx,
99 struct libnet_rpc_useradd *io,
100 void (*monitor)(struct monitor_msg*))
102 struct composite_context *c;
103 struct useradd_state *s;
104 struct tevent_req *subreq;
106 if (!p || !io) return NULL;
108 /* composite allocation and setup */
109 c = composite_create(mem_ctx, dcerpc_event_context(p));
110 if (c == NULL) return NULL;
112 s = talloc_zero(c, struct useradd_state);
113 if (composite_nomem(s, c)) return c;
115 c->private_data = s;
117 /* put passed arguments to the state structure */
118 s->domain_handle = io->in.domain_handle;
119 s->pipe = p;
120 s->monitor_fn = monitor;
122 /* preparing parameters to send rpc request */
123 s->createuser.in.domain_handle = &io->in.domain_handle;
125 s->createuser.in.account_name = talloc_zero(c, struct lsa_String);
126 if (composite_nomem(s->createuser.in.account_name, c)) return c;
128 s->createuser.in.account_name->string = talloc_strdup(c, io->in.username);
129 if (composite_nomem(s->createuser.in.account_name->string, c)) return c;
131 s->createuser.out.user_handle = &s->user_handle;
132 s->createuser.out.rid = &s->user_rid;
134 /* send the request */
135 subreq = dcerpc_samr_CreateUser_r_send(s, c->event_ctx,
136 p->binding_handle,
137 &s->createuser);
138 if (composite_nomem(subreq, c)) return c;
140 tevent_req_set_callback(subreq, continue_useradd_create, c);
141 return c;
146 * Waits for and receives result of asynchronous useradd call
148 * @param c composite context returned by asynchronous useradd call
149 * @param mem_ctx memory context of the call
150 * @param io pointer to results (and arguments) of the call
151 * @return nt status code of execution
154 NTSTATUS libnet_rpc_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
155 struct libnet_rpc_useradd *io)
157 NTSTATUS status;
158 struct useradd_state *s;
160 status = composite_wait(c);
162 if (NT_STATUS_IS_OK(status) && io) {
163 /* get and return result of the call */
164 s = talloc_get_type(c->private_data, struct useradd_state);
165 io->out.user_handle = s->user_handle;
168 talloc_free(c);
169 return status;
174 * Synchronous version of useradd call
176 * @param pipe dce/rpc call pipe
177 * @param mem_ctx memory context for the call
178 * @param io arguments and results of the call
179 * @return nt status code of execution
182 NTSTATUS libnet_rpc_useradd(struct dcerpc_pipe *p,
183 TALLOC_CTX *mem_ctx,
184 struct libnet_rpc_useradd *io)
186 struct composite_context *c = libnet_rpc_useradd_send(p, mem_ctx, io, NULL);
187 return libnet_rpc_useradd_recv(c, mem_ctx, io);
193 * Composite USER DELETE functionality
197 struct userdel_state {
198 struct dcerpc_pipe *pipe;
199 struct policy_handle domain_handle;
200 struct policy_handle user_handle;
201 struct samr_LookupNames lookupname;
202 struct samr_OpenUser openuser;
203 struct samr_DeleteUser deleteuser;
205 /* information about the progress */
206 void (*monitor_fn)(struct monitor_msg *);
210 static void continue_userdel_name_found(struct tevent_req *subreq);
211 static void continue_userdel_user_opened(struct tevent_req *subreq);
212 static void continue_userdel_deleted(struct tevent_req *subreq);
216 * Stage 1: Lookup the user name and resolve it to rid
218 static void continue_userdel_name_found(struct tevent_req *subreq)
220 struct composite_context *c;
221 struct userdel_state *s;
222 struct monitor_msg msg;
224 c = tevent_req_callback_data(subreq, struct composite_context);
225 s = talloc_get_type(c->private_data, struct userdel_state);
227 /* receive samr_LookupNames result */
228 c->status = dcerpc_samr_LookupNames_r_recv(subreq, s);
229 TALLOC_FREE(subreq);
230 if (!composite_is_ok(c)) return;
232 c->status = s->lookupname.out.result;
233 if (!NT_STATUS_IS_OK(c->status)) {
234 composite_error(c, c->status);
235 return;
238 /* what to do when there's no user account to delete
239 and what if there's more than one rid resolved */
240 if (s->lookupname.out.rids->count != s->lookupname.in.num_names) {
241 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
242 return;
244 if (s->lookupname.out.types->count != s->lookupname.in.num_names) {
245 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
246 return;
249 /* issue a monitor message */
250 if (s->monitor_fn) {
251 struct msg_rpc_lookup_name msg_lookup;
253 msg_lookup.rid = s->lookupname.out.rids->ids;
254 msg_lookup.count = s->lookupname.out.rids->count;
256 msg.type = mon_SamrLookupName;
257 msg.data = (void*)&msg_lookup;
258 msg.data_size = sizeof(msg_lookup);
259 s->monitor_fn(&msg);
262 /* prepare the arguments for rpc call */
263 s->openuser.in.domain_handle = &s->domain_handle;
264 s->openuser.in.rid = s->lookupname.out.rids->ids[0];
265 s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
266 s->openuser.out.user_handle = &s->user_handle;
268 /* send rpc request */
269 subreq = dcerpc_samr_OpenUser_r_send(s, c->event_ctx,
270 s->pipe->binding_handle,
271 &s->openuser);
272 if (composite_nomem(subreq, c)) return;
274 tevent_req_set_callback(subreq, continue_userdel_user_opened, c);
279 * Stage 2: Open user account.
281 static void continue_userdel_user_opened(struct tevent_req *subreq)
283 struct composite_context *c;
284 struct userdel_state *s;
285 struct monitor_msg msg;
287 c = tevent_req_callback_data(subreq, struct composite_context);
288 s = talloc_get_type(c->private_data, struct userdel_state);
290 /* receive samr_OpenUser result */
291 c->status = dcerpc_samr_OpenUser_r_recv(subreq, s);
292 TALLOC_FREE(subreq);
293 if (!composite_is_ok(c)) return;
295 c->status = s->openuser.out.result;
296 if (!NT_STATUS_IS_OK(c->status)) {
297 composite_error(c, c->status);
298 return;
301 /* issue a monitor message */
302 if (s->monitor_fn) {
303 struct msg_rpc_open_user msg_open;
305 msg_open.rid = s->openuser.in.rid;
306 msg_open.access_mask = s->openuser.in.access_mask;
308 msg.type = mon_SamrOpenUser;
309 msg.data = (void*)&msg_open;
310 msg.data_size = sizeof(msg_open);
311 s->monitor_fn(&msg);
314 /* prepare the final rpc call arguments */
315 s->deleteuser.in.user_handle = &s->user_handle;
316 s->deleteuser.out.user_handle = &s->user_handle;
318 /* send rpc request */
319 subreq = dcerpc_samr_DeleteUser_r_send(s, c->event_ctx,
320 s->pipe->binding_handle,
321 &s->deleteuser);
322 if (composite_nomem(subreq, c)) return;
324 /* callback handler setup */
325 tevent_req_set_callback(subreq, continue_userdel_deleted, c);
330 * Stage 3: Delete user account
332 static void continue_userdel_deleted(struct tevent_req *subreq)
334 struct composite_context *c;
335 struct userdel_state *s;
336 struct monitor_msg msg;
338 c = tevent_req_callback_data(subreq, struct composite_context);
339 s = talloc_get_type(c->private_data, struct userdel_state);
341 /* receive samr_DeleteUser result */
342 c->status = dcerpc_samr_DeleteUser_r_recv(subreq, s);
343 TALLOC_FREE(subreq);
344 if (!composite_is_ok(c)) return;
346 /* return the actual function call status */
347 c->status = s->deleteuser.out.result;
348 if (!NT_STATUS_IS_OK(c->status)) {
349 composite_error(c, c->status);
350 return;
353 /* issue a monitor message */
354 if (s->monitor_fn) {
355 msg.type = mon_SamrDeleteUser;
356 msg.data = NULL;
357 msg.data_size = 0;
358 s->monitor_fn(&msg);
361 composite_done(c);
366 * Sends asynchronous userdel request
368 * @param p dce/rpc call pipe
369 * @param io arguments and results of the call
370 * @param monitor monitor function for providing information about the progress
373 struct composite_context *libnet_rpc_userdel_send(struct dcerpc_pipe *p,
374 TALLOC_CTX *mem_ctx,
375 struct libnet_rpc_userdel *io,
376 void (*monitor)(struct monitor_msg*))
378 struct composite_context *c;
379 struct userdel_state *s;
380 struct tevent_req *subreq;
382 /* composite context allocation and setup */
383 c = composite_create(mem_ctx, dcerpc_event_context(p));
384 if (c == NULL) return NULL;
386 s = talloc_zero(c, struct userdel_state);
387 if (composite_nomem(s, c)) return c;
389 c->private_data = s;
391 /* store function parameters in the state structure */
392 s->pipe = p;
393 s->domain_handle = io->in.domain_handle;
394 s->monitor_fn = monitor;
396 /* preparing parameters to send rpc request */
397 s->lookupname.in.domain_handle = &io->in.domain_handle;
398 s->lookupname.in.num_names = 1;
399 s->lookupname.in.names = talloc_zero(s, struct lsa_String);
400 s->lookupname.in.names->string = io->in.username;
401 s->lookupname.out.rids = talloc_zero(s, struct samr_Ids);
402 s->lookupname.out.types = talloc_zero(s, struct samr_Ids);
403 if (composite_nomem(s->lookupname.out.rids, c)) return c;
404 if (composite_nomem(s->lookupname.out.types, c)) return c;
406 /* send the request */
407 subreq = dcerpc_samr_LookupNames_r_send(s, c->event_ctx,
408 p->binding_handle,
409 &s->lookupname);
410 if (composite_nomem(subreq, c)) return c;
412 /* set the next stage */
413 tevent_req_set_callback(subreq, continue_userdel_name_found, c);
414 return c;
419 * Waits for and receives results of asynchronous userdel call
421 * @param c composite context returned by asynchronous userdel call
422 * @param mem_ctx memory context of the call
423 * @param io pointer to results (and arguments) of the call
424 * @return nt status code of execution
427 NTSTATUS libnet_rpc_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
428 struct libnet_rpc_userdel *io)
430 NTSTATUS status;
431 struct userdel_state *s;
433 status = composite_wait(c);
435 if (NT_STATUS_IS_OK(status) && io) {
436 s = talloc_get_type(c->private_data, struct userdel_state);
437 io->out.user_handle = s->user_handle;
440 talloc_free(c);
441 return status;
446 * Synchronous version of userdel call
448 * @param pipe dce/rpc call pipe
449 * @param mem_ctx memory context for the call
450 * @param io arguments and results of the call
451 * @return nt status code of execution
454 NTSTATUS libnet_rpc_userdel(struct dcerpc_pipe *p,
455 TALLOC_CTX *mem_ctx,
456 struct libnet_rpc_userdel *io)
458 struct composite_context *c = libnet_rpc_userdel_send(p, mem_ctx, io, NULL);
459 return libnet_rpc_userdel_recv(c, mem_ctx, io);
464 * USER MODIFY functionality
467 static void continue_usermod_name_found(struct tevent_req *subreq);
468 static void continue_usermod_user_opened(struct tevent_req *subreq);
469 static void continue_usermod_user_queried(struct tevent_req *subreq);
470 static void continue_usermod_user_changed(struct tevent_req *subreq);
473 struct usermod_state {
474 struct dcerpc_pipe *pipe;
475 struct policy_handle domain_handle;
476 struct policy_handle user_handle;
477 struct usermod_change change;
478 union samr_UserInfo info;
479 struct samr_LookupNames lookupname;
480 struct samr_OpenUser openuser;
481 struct samr_SetUserInfo setuser;
482 struct samr_QueryUserInfo queryuser;
484 /* information about the progress */
485 void (*monitor_fn)(struct monitor_msg *);
490 * Step 1: Lookup user name
492 static void continue_usermod_name_found(struct tevent_req *subreq)
494 struct composite_context *c;
495 struct usermod_state *s;
496 struct monitor_msg msg;
498 c = tevent_req_callback_data(subreq, struct composite_context);
499 s = talloc_get_type(c->private_data, struct usermod_state);
501 /* receive samr_LookupNames result */
502 c->status = dcerpc_samr_LookupNames_r_recv(subreq, s);
503 TALLOC_FREE(subreq);
504 if (!composite_is_ok(c)) return;
506 c->status = s->lookupname.out.result;
507 if (!NT_STATUS_IS_OK(c->status)) {
508 composite_error(c, c->status);
509 return;
512 /* what to do when there's no user account to delete
513 and what if there's more than one rid resolved */
514 if (s->lookupname.out.rids->count != s->lookupname.in.num_names) {
515 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
516 return;
518 if (s->lookupname.out.types->count != s->lookupname.in.num_names) {
519 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
520 return;
523 /* issue a monitor message */
524 if (s->monitor_fn) {
525 struct msg_rpc_lookup_name msg_lookup;
527 msg_lookup.rid = s->lookupname.out.rids->ids;
528 msg_lookup.count = s->lookupname.out.rids->count;
530 msg.type = mon_SamrLookupName;
531 msg.data = (void*)&msg_lookup;
532 msg.data_size = sizeof(msg_lookup);
533 s->monitor_fn(&msg);
536 /* prepare the next rpc call */
537 s->openuser.in.domain_handle = &s->domain_handle;
538 s->openuser.in.rid = s->lookupname.out.rids->ids[0];
539 s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
540 s->openuser.out.user_handle = &s->user_handle;
542 /* send the rpc request */
543 subreq = dcerpc_samr_OpenUser_r_send(s, c->event_ctx,
544 s->pipe->binding_handle,
545 &s->openuser);
546 if (composite_nomem(subreq, c)) return;
548 tevent_req_set_callback(subreq, continue_usermod_user_opened, c);
553 * Choose a proper level of samr_UserInfo structure depending on required
554 * change specified by means of flags field. Subsequent calls of this
555 * function are made until there's no flags set meaning that all of the
556 * changes have been made.
558 static bool usermod_setfields(struct usermod_state *s, uint16_t *level,
559 union samr_UserInfo *i, bool queried)
561 if (s->change.fields == 0) return s->change.fields;
563 *level = 0;
565 if ((s->change.fields & USERMOD_FIELD_ACCOUNT_NAME) &&
566 (*level == 0 || *level == 7)) {
567 *level = 7;
568 i->info7.account_name.string = s->change.account_name;
570 s->change.fields ^= USERMOD_FIELD_ACCOUNT_NAME;
573 if ((s->change.fields & USERMOD_FIELD_FULL_NAME) &&
574 (*level == 0 || *level == 8)) {
575 *level = 8;
576 i->info8.full_name.string = s->change.full_name;
578 s->change.fields ^= USERMOD_FIELD_FULL_NAME;
581 if ((s->change.fields & USERMOD_FIELD_DESCRIPTION) &&
582 (*level == 0 || *level == 13)) {
583 *level = 13;
584 i->info13.description.string = s->change.description;
586 s->change.fields ^= USERMOD_FIELD_DESCRIPTION;
589 if ((s->change.fields & USERMOD_FIELD_COMMENT) &&
590 (*level == 0 || *level == 2)) {
591 *level = 2;
593 if (queried) {
594 /* the user info is obtained, so now set the required field */
595 i->info2.comment.string = s->change.comment;
596 s->change.fields ^= USERMOD_FIELD_COMMENT;
598 } else {
599 /* we need to query the user info before setting one field in it */
600 return false;
604 if ((s->change.fields & USERMOD_FIELD_LOGON_SCRIPT) &&
605 (*level == 0 || *level == 11)) {
606 *level = 11;
607 i->info11.logon_script.string = s->change.logon_script;
609 s->change.fields ^= USERMOD_FIELD_LOGON_SCRIPT;
612 if ((s->change.fields & USERMOD_FIELD_PROFILE_PATH) &&
613 (*level == 0 || *level == 12)) {
614 *level = 12;
615 i->info12.profile_path.string = s->change.profile_path;
617 s->change.fields ^= USERMOD_FIELD_PROFILE_PATH;
620 if ((s->change.fields & USERMOD_FIELD_HOME_DIRECTORY) &&
621 (*level == 0 || *level == 10)) {
622 *level = 10;
624 if (queried) {
625 i->info10.home_directory.string = s->change.home_directory;
626 s->change.fields ^= USERMOD_FIELD_HOME_DIRECTORY;
627 } else {
628 return false;
632 if ((s->change.fields & USERMOD_FIELD_HOME_DRIVE) &&
633 (*level == 0 || *level == 10)) {
634 *level = 10;
636 if (queried) {
637 i->info10.home_drive.string = s->change.home_drive;
638 s->change.fields ^= USERMOD_FIELD_HOME_DRIVE;
639 } else {
640 return false;
644 if ((s->change.fields & USERMOD_FIELD_ACCT_EXPIRY) &&
645 (*level == 0 || *level == 17)) {
646 *level = 17;
647 i->info17.acct_expiry = timeval_to_nttime(s->change.acct_expiry);
649 s->change.fields ^= USERMOD_FIELD_ACCT_EXPIRY;
652 if ((s->change.fields & USERMOD_FIELD_ACCT_FLAGS) &&
653 (*level == 0 || *level == 16)) {
654 *level = 16;
655 i->info16.acct_flags = s->change.acct_flags;
657 s->change.fields ^= USERMOD_FIELD_ACCT_FLAGS;
660 /* We're going to be here back again soon unless all fields have been set */
661 return true;
665 static NTSTATUS usermod_change(struct composite_context *c,
666 struct usermod_state *s)
668 bool do_set;
669 union samr_UserInfo *i = &s->info;
670 struct tevent_req *subreq;
672 /* set the level to invalid value, so that unless setfields routine
673 gives it a valid value we report the error correctly */
674 uint16_t level = 27;
676 /* prepare UserInfo level and data based on bitmask field */
677 do_set = usermod_setfields(s, &level, i, false);
679 if (level < 1 || level > 26) {
680 /* apparently there's a field that the setfields routine
681 does not know how to set */
682 return NT_STATUS_INVALID_PARAMETER;
685 /* If some specific level is used to set user account data and the change
686 itself does not cover all fields then we need to query the user info
687 first, right before changing the data. Otherwise we could set required
688 fields and accidentally reset the others.
690 if (!do_set) {
691 s->queryuser.in.user_handle = &s->user_handle;
692 s->queryuser.in.level = level;
693 s->queryuser.out.info = talloc(s, union samr_UserInfo *);
694 if (composite_nomem(s->queryuser.out.info, c)) return NT_STATUS_NO_MEMORY;
697 /* send query user info request to retrieve complete data of
698 a particular info level */
699 subreq = dcerpc_samr_QueryUserInfo_r_send(s, c->event_ctx,
700 s->pipe->binding_handle,
701 &s->queryuser);
702 if (composite_nomem(subreq, c)) return NT_STATUS_NO_MEMORY;
703 tevent_req_set_callback(subreq, continue_usermod_user_queried, c);
705 } else {
706 s->setuser.in.user_handle = &s->user_handle;
707 s->setuser.in.level = level;
708 s->setuser.in.info = i;
710 /* send set user info request after making required change */
711 subreq = dcerpc_samr_SetUserInfo_r_send(s, c->event_ctx,
712 s->pipe->binding_handle,
713 &s->setuser);
714 if (composite_nomem(subreq, c)) return NT_STATUS_NO_MEMORY;
715 tevent_req_set_callback(subreq, continue_usermod_user_changed, c);
718 return NT_STATUS_OK;
723 * Stage 2: Open user account
725 static void continue_usermod_user_opened(struct tevent_req *subreq)
727 struct composite_context *c;
728 struct usermod_state *s;
730 c = tevent_req_callback_data(subreq, struct composite_context);
731 s = talloc_get_type(c->private_data, struct usermod_state);
733 c->status = dcerpc_samr_OpenUser_r_recv(subreq, s);
734 TALLOC_FREE(subreq);
735 if (!composite_is_ok(c)) return;
737 c->status = s->openuser.out.result;
738 if (!NT_STATUS_IS_OK(c->status)) {
739 composite_error(c, c->status);
740 return;
743 c->status = usermod_change(c, s);
748 * Stage 2a (optional): Query the user information
750 static void continue_usermod_user_queried(struct tevent_req *subreq)
752 struct composite_context *c;
753 struct usermod_state *s;
754 union samr_UserInfo *i;
755 uint16_t level;
757 c = tevent_req_callback_data(subreq, struct composite_context);
758 s = talloc_get_type(c->private_data, struct usermod_state);
760 i = &s->info;
762 /* receive samr_QueryUserInfo result */
763 c->status = dcerpc_samr_QueryUserInfo_r_recv(subreq, s);
764 TALLOC_FREE(subreq);
765 if (!composite_is_ok(c)) return;
767 c->status = s->queryuser.out.result;
768 if (!NT_STATUS_IS_OK(c->status)) {
769 composite_error(c, c->status);
770 return;
773 /* get returned user data and make a change (potentially one
774 of many) */
775 s->info = *(*s->queryuser.out.info);
777 usermod_setfields(s, &level, i, true);
779 /* prepare rpc call arguments */
780 s->setuser.in.user_handle = &s->user_handle;
781 s->setuser.in.level = level;
782 s->setuser.in.info = i;
784 /* send the rpc request */
785 subreq = dcerpc_samr_SetUserInfo_r_send(s, c->event_ctx,
786 s->pipe->binding_handle,
787 &s->setuser);
788 if (composite_nomem(subreq, c)) return;
789 tevent_req_set_callback(subreq, continue_usermod_user_changed, c);
794 * Stage 3: Set new user account data
796 static void continue_usermod_user_changed(struct tevent_req *subreq)
798 struct composite_context *c;
799 struct usermod_state *s;
801 c = tevent_req_callback_data(subreq, struct composite_context);
802 s = talloc_get_type(c->private_data, struct usermod_state);
804 /* receive samr_SetUserInfo result */
805 c->status = dcerpc_samr_SetUserInfo_r_recv(subreq, s);
806 TALLOC_FREE(subreq);
807 if (!composite_is_ok(c)) return;
809 /* return the actual function call status */
810 c->status = s->setuser.out.result;
811 if (!NT_STATUS_IS_OK(c->status)) {
812 composite_error(c, c->status);
813 return;
816 if (s->change.fields == 0) {
817 /* all fields have been set - we're done */
818 composite_done(c);
820 } else {
821 /* something's still not changed - repeat the procedure */
822 c->status = usermod_change(c, s);
828 * Sends asynchronous usermod request
830 * @param p dce/rpc call pipe
831 * @param io arguments and results of the call
832 * @param monitor monitor function for providing information about the progress
835 struct composite_context *libnet_rpc_usermod_send(struct dcerpc_pipe *p,
836 TALLOC_CTX *mem_ctx,
837 struct libnet_rpc_usermod *io,
838 void (*monitor)(struct monitor_msg*))
840 struct composite_context *c;
841 struct usermod_state *s;
842 struct tevent_req *subreq;
844 /* composite context allocation and setup */
845 c = composite_create(mem_ctx, dcerpc_event_context(p));
846 if (c == NULL) return NULL;
847 s = talloc_zero(c, struct usermod_state);
848 if (composite_nomem(s, c)) return c;
850 c->private_data = s;
852 /* store parameters in the call structure */
853 s->pipe = p;
854 s->domain_handle = io->in.domain_handle;
855 s->change = io->in.change;
856 s->monitor_fn = monitor;
858 /* prepare rpc call arguments */
859 s->lookupname.in.domain_handle = &io->in.domain_handle;
860 s->lookupname.in.num_names = 1;
861 s->lookupname.in.names = talloc_zero(s, struct lsa_String);
862 s->lookupname.in.names->string = io->in.username;
863 s->lookupname.out.rids = talloc_zero(s, struct samr_Ids);
864 s->lookupname.out.types = talloc_zero(s, struct samr_Ids);
865 if (composite_nomem(s->lookupname.out.rids, c)) return c;
866 if (composite_nomem(s->lookupname.out.types, c)) return c;
868 /* send the rpc request */
869 subreq = dcerpc_samr_LookupNames_r_send(s, c->event_ctx,
870 p->binding_handle,
871 &s->lookupname);
872 if (composite_nomem(subreq, c)) return c;
874 /* callback handler setup */
875 tevent_req_set_callback(subreq, continue_usermod_name_found, c);
876 return c;
881 * Waits for and receives results of asynchronous usermod call
883 * @param c composite context returned by asynchronous usermod call
884 * @param mem_ctx memory context of the call
885 * @param io pointer to results (and arguments) of the call
886 * @return nt status code of execution
889 NTSTATUS libnet_rpc_usermod_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
890 struct libnet_rpc_usermod *io)
892 NTSTATUS status;
894 status = composite_wait(c);
896 talloc_free(c);
897 return status;
902 * Synchronous version of usermod call
904 * @param pipe dce/rpc call pipe
905 * @param mem_ctx memory context for the call
906 * @param io arguments and results of the call
907 * @return nt status code of execution
910 NTSTATUS libnet_rpc_usermod(struct dcerpc_pipe *p,
911 TALLOC_CTX *mem_ctx,
912 struct libnet_rpc_usermod *io)
914 struct composite_context *c = libnet_rpc_usermod_send(p, mem_ctx, io, NULL);
915 return libnet_rpc_usermod_recv(c, mem_ctx, io);