s3: smbd: Use separate flag to track become_root()/unbecome_root() state.
[Samba.git] / source4 / libnet / userman.c
blob9e76364992c80114726237887eb6594e7439d69f
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_binding_handle *binding_handle;
35 struct policy_handle domain_handle;
36 struct samr_CreateUser createuser;
37 struct policy_handle user_handle;
38 uint32_t user_rid;
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(TALLOC_CTX *mem_ctx,
98 struct tevent_context *ev,
99 struct dcerpc_binding_handle *b,
100 struct libnet_rpc_useradd *io,
101 void (*monitor)(struct monitor_msg*))
103 struct composite_context *c;
104 struct useradd_state *s;
105 struct tevent_req *subreq;
107 if (!b || !io) return NULL;
109 /* composite allocation and setup */
110 c = composite_create(mem_ctx, ev);
111 if (c == NULL) return NULL;
113 s = talloc_zero(c, struct useradd_state);
114 if (composite_nomem(s, c)) return c;
116 c->private_data = s;
118 /* put passed arguments to the state structure */
119 s->domain_handle = io->in.domain_handle;
120 s->binding_handle= b;
121 s->monitor_fn = monitor;
123 /* preparing parameters to send rpc request */
124 s->createuser.in.domain_handle = &io->in.domain_handle;
126 s->createuser.in.account_name = talloc_zero(c, struct lsa_String);
127 if (composite_nomem(s->createuser.in.account_name, c)) return c;
129 s->createuser.in.account_name->string = talloc_strdup(c, io->in.username);
130 if (composite_nomem(s->createuser.in.account_name->string, c)) return c;
132 s->createuser.out.user_handle = &s->user_handle;
133 s->createuser.out.rid = &s->user_rid;
135 /* send the request */
136 subreq = dcerpc_samr_CreateUser_r_send(s, c->event_ctx,
137 s->binding_handle,
138 &s->createuser);
139 if (composite_nomem(subreq, c)) return c;
141 tevent_req_set_callback(subreq, continue_useradd_create, c);
142 return c;
147 * Waits for and receives result of asynchronous useradd call
149 * @param c composite context returned by asynchronous useradd call
150 * @param mem_ctx memory context of the call
151 * @param io pointer to results (and arguments) of the call
152 * @return nt status code of execution
155 NTSTATUS libnet_rpc_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
156 struct libnet_rpc_useradd *io)
158 NTSTATUS status;
159 struct useradd_state *s;
161 status = composite_wait(c);
163 if (NT_STATUS_IS_OK(status) && io) {
164 /* get and return result of the call */
165 s = talloc_get_type(c->private_data, struct useradd_state);
166 io->out.user_handle = s->user_handle;
169 talloc_free(c);
170 return status;
175 * Synchronous version of useradd call
177 * @param pipe dce/rpc call pipe
178 * @param mem_ctx memory context for the call
179 * @param io arguments and results of the call
180 * @return nt status code of execution
183 NTSTATUS libnet_rpc_useradd(struct tevent_context *ev,
184 struct dcerpc_binding_handle *b,
185 TALLOC_CTX *mem_ctx,
186 struct libnet_rpc_useradd *io)
188 struct composite_context *c = libnet_rpc_useradd_send(mem_ctx, ev, b, io, NULL);
189 return libnet_rpc_useradd_recv(c, mem_ctx, io);
195 * Composite USER DELETE functionality
199 struct userdel_state {
200 struct dcerpc_binding_handle *binding_handle;
201 struct policy_handle domain_handle;
202 struct policy_handle user_handle;
203 struct samr_LookupNames lookupname;
204 struct samr_OpenUser openuser;
205 struct samr_DeleteUser deleteuser;
207 /* information about the progress */
208 void (*monitor_fn)(struct monitor_msg *);
212 static void continue_userdel_name_found(struct tevent_req *subreq);
213 static void continue_userdel_user_opened(struct tevent_req *subreq);
214 static void continue_userdel_deleted(struct tevent_req *subreq);
218 * Stage 1: Lookup the user name and resolve it to rid
220 static void continue_userdel_name_found(struct tevent_req *subreq)
222 struct composite_context *c;
223 struct userdel_state *s;
224 struct monitor_msg msg;
226 c = tevent_req_callback_data(subreq, struct composite_context);
227 s = talloc_get_type(c->private_data, struct userdel_state);
229 /* receive samr_LookupNames result */
230 c->status = dcerpc_samr_LookupNames_r_recv(subreq, s);
231 TALLOC_FREE(subreq);
232 if (!composite_is_ok(c)) return;
234 c->status = s->lookupname.out.result;
235 if (!NT_STATUS_IS_OK(c->status)) {
236 composite_error(c, c->status);
237 return;
240 /* what to do when there's no user account to delete
241 and what if there's more than one rid resolved */
242 if (s->lookupname.out.rids->count != s->lookupname.in.num_names) {
243 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
244 return;
246 if (s->lookupname.out.types->count != s->lookupname.in.num_names) {
247 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
248 return;
251 /* issue a monitor message */
252 if (s->monitor_fn) {
253 struct msg_rpc_lookup_name msg_lookup;
255 msg_lookup.rid = s->lookupname.out.rids->ids;
256 msg_lookup.count = s->lookupname.out.rids->count;
258 msg.type = mon_SamrLookupName;
259 msg.data = (void*)&msg_lookup;
260 msg.data_size = sizeof(msg_lookup);
261 s->monitor_fn(&msg);
264 /* prepare the arguments for rpc call */
265 s->openuser.in.domain_handle = &s->domain_handle;
266 s->openuser.in.rid = s->lookupname.out.rids->ids[0];
267 s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
268 s->openuser.out.user_handle = &s->user_handle;
270 /* send rpc request */
271 subreq = dcerpc_samr_OpenUser_r_send(s, c->event_ctx,
272 s->binding_handle,
273 &s->openuser);
274 if (composite_nomem(subreq, c)) return;
276 tevent_req_set_callback(subreq, continue_userdel_user_opened, c);
281 * Stage 2: Open user account.
283 static void continue_userdel_user_opened(struct tevent_req *subreq)
285 struct composite_context *c;
286 struct userdel_state *s;
287 struct monitor_msg msg;
289 c = tevent_req_callback_data(subreq, struct composite_context);
290 s = talloc_get_type(c->private_data, struct userdel_state);
292 /* receive samr_OpenUser result */
293 c->status = dcerpc_samr_OpenUser_r_recv(subreq, s);
294 TALLOC_FREE(subreq);
295 if (!composite_is_ok(c)) return;
297 c->status = s->openuser.out.result;
298 if (!NT_STATUS_IS_OK(c->status)) {
299 composite_error(c, c->status);
300 return;
303 /* issue a monitor message */
304 if (s->monitor_fn) {
305 struct msg_rpc_open_user msg_open;
307 msg_open.rid = s->openuser.in.rid;
308 msg_open.access_mask = s->openuser.in.access_mask;
310 msg.type = mon_SamrOpenUser;
311 msg.data = (void*)&msg_open;
312 msg.data_size = sizeof(msg_open);
313 s->monitor_fn(&msg);
316 /* prepare the final rpc call arguments */
317 s->deleteuser.in.user_handle = &s->user_handle;
318 s->deleteuser.out.user_handle = &s->user_handle;
320 /* send rpc request */
321 subreq = dcerpc_samr_DeleteUser_r_send(s, c->event_ctx,
322 s->binding_handle,
323 &s->deleteuser);
324 if (composite_nomem(subreq, c)) return;
326 /* callback handler setup */
327 tevent_req_set_callback(subreq, continue_userdel_deleted, c);
332 * Stage 3: Delete user account
334 static void continue_userdel_deleted(struct tevent_req *subreq)
336 struct composite_context *c;
337 struct userdel_state *s;
338 struct monitor_msg msg;
340 c = tevent_req_callback_data(subreq, struct composite_context);
341 s = talloc_get_type(c->private_data, struct userdel_state);
343 /* receive samr_DeleteUser result */
344 c->status = dcerpc_samr_DeleteUser_r_recv(subreq, s);
345 TALLOC_FREE(subreq);
346 if (!composite_is_ok(c)) return;
348 /* return the actual function call status */
349 c->status = s->deleteuser.out.result;
350 if (!NT_STATUS_IS_OK(c->status)) {
351 composite_error(c, c->status);
352 return;
355 /* issue a monitor message */
356 if (s->monitor_fn) {
357 msg.type = mon_SamrDeleteUser;
358 msg.data = NULL;
359 msg.data_size = 0;
360 s->monitor_fn(&msg);
363 composite_done(c);
368 * Sends asynchronous userdel request
370 * @param p dce/rpc call pipe
371 * @param io arguments and results of the call
372 * @param monitor monitor function for providing information about the progress
375 struct composite_context *libnet_rpc_userdel_send(TALLOC_CTX *mem_ctx,
376 struct tevent_context *ev,
377 struct dcerpc_binding_handle *b,
378 struct libnet_rpc_userdel *io,
379 void (*monitor)(struct monitor_msg*))
381 struct composite_context *c;
382 struct userdel_state *s;
383 struct tevent_req *subreq;
385 /* composite context allocation and setup */
386 c = composite_create(mem_ctx, ev);
387 if (c == NULL) return NULL;
389 s = talloc_zero(c, struct userdel_state);
390 if (composite_nomem(s, c)) return c;
392 c->private_data = s;
394 /* store function parameters in the state structure */
395 s->binding_handle= b;
396 s->domain_handle = io->in.domain_handle;
397 s->monitor_fn = monitor;
399 /* preparing parameters to send rpc request */
400 s->lookupname.in.domain_handle = &io->in.domain_handle;
401 s->lookupname.in.num_names = 1;
402 s->lookupname.in.names = talloc_zero(s, struct lsa_String);
403 s->lookupname.in.names->string = io->in.username;
404 s->lookupname.out.rids = talloc_zero(s, struct samr_Ids);
405 s->lookupname.out.types = talloc_zero(s, struct samr_Ids);
406 if (composite_nomem(s->lookupname.out.rids, c)) return c;
407 if (composite_nomem(s->lookupname.out.types, c)) return c;
409 /* send the request */
410 subreq = dcerpc_samr_LookupNames_r_send(s, c->event_ctx,
411 s->binding_handle,
412 &s->lookupname);
413 if (composite_nomem(subreq, c)) return c;
415 /* set the next stage */
416 tevent_req_set_callback(subreq, continue_userdel_name_found, c);
417 return c;
422 * Waits for and receives results of asynchronous userdel call
424 * @param c composite context returned by asynchronous userdel call
425 * @param mem_ctx memory context of the call
426 * @param io pointer to results (and arguments) of the call
427 * @return nt status code of execution
430 NTSTATUS libnet_rpc_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
431 struct libnet_rpc_userdel *io)
433 NTSTATUS status;
434 struct userdel_state *s;
436 status = composite_wait(c);
438 if (NT_STATUS_IS_OK(status) && io) {
439 s = talloc_get_type(c->private_data, struct userdel_state);
440 io->out.user_handle = s->user_handle;
443 talloc_free(c);
444 return status;
449 * Synchronous version of userdel call
451 * @param pipe dce/rpc call pipe
452 * @param mem_ctx memory context for the call
453 * @param io arguments and results of the call
454 * @return nt status code of execution
457 NTSTATUS libnet_rpc_userdel(struct tevent_context *ev,
458 struct dcerpc_binding_handle *b,
459 TALLOC_CTX *mem_ctx,
460 struct libnet_rpc_userdel *io)
462 struct composite_context *c = libnet_rpc_userdel_send(mem_ctx, ev, b, io, NULL);
463 return libnet_rpc_userdel_recv(c, mem_ctx, io);
468 * USER MODIFY functionality
471 static void continue_usermod_name_found(struct tevent_req *subreq);
472 static void continue_usermod_user_opened(struct tevent_req *subreq);
473 static void continue_usermod_user_queried(struct tevent_req *subreq);
474 static void continue_usermod_user_changed(struct tevent_req *subreq);
477 struct usermod_state {
478 struct dcerpc_binding_handle *binding_handle;
479 struct policy_handle domain_handle;
480 struct policy_handle user_handle;
481 struct usermod_change change;
482 union samr_UserInfo info;
483 struct samr_LookupNames lookupname;
484 struct samr_OpenUser openuser;
485 struct samr_SetUserInfo setuser;
486 struct samr_QueryUserInfo queryuser;
488 /* information about the progress */
489 void (*monitor_fn)(struct monitor_msg *);
494 * Step 1: Lookup user name
496 static void continue_usermod_name_found(struct tevent_req *subreq)
498 struct composite_context *c;
499 struct usermod_state *s;
500 struct monitor_msg msg;
502 c = tevent_req_callback_data(subreq, struct composite_context);
503 s = talloc_get_type(c->private_data, struct usermod_state);
505 /* receive samr_LookupNames result */
506 c->status = dcerpc_samr_LookupNames_r_recv(subreq, s);
507 TALLOC_FREE(subreq);
508 if (!composite_is_ok(c)) return;
510 c->status = s->lookupname.out.result;
511 if (!NT_STATUS_IS_OK(c->status)) {
512 composite_error(c, c->status);
513 return;
516 /* what to do when there's no user account to delete
517 and what if there's more than one rid resolved */
518 if (s->lookupname.out.rids->count != s->lookupname.in.num_names) {
519 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
520 return;
522 if (s->lookupname.out.types->count != s->lookupname.in.num_names) {
523 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
524 return;
527 /* issue a monitor message */
528 if (s->monitor_fn) {
529 struct msg_rpc_lookup_name msg_lookup;
531 msg_lookup.rid = s->lookupname.out.rids->ids;
532 msg_lookup.count = s->lookupname.out.rids->count;
534 msg.type = mon_SamrLookupName;
535 msg.data = (void*)&msg_lookup;
536 msg.data_size = sizeof(msg_lookup);
537 s->monitor_fn(&msg);
540 /* prepare the next rpc call */
541 s->openuser.in.domain_handle = &s->domain_handle;
542 s->openuser.in.rid = s->lookupname.out.rids->ids[0];
543 s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
544 s->openuser.out.user_handle = &s->user_handle;
546 /* send the rpc request */
547 subreq = dcerpc_samr_OpenUser_r_send(s, c->event_ctx,
548 s->binding_handle,
549 &s->openuser);
550 if (composite_nomem(subreq, c)) return;
552 tevent_req_set_callback(subreq, continue_usermod_user_opened, c);
557 * Choose a proper level of samr_UserInfo structure depending on required
558 * change specified by means of flags field. Subsequent calls of this
559 * function are made until there's no flags set meaning that all of the
560 * changes have been made.
562 static bool usermod_setfields(struct usermod_state *s, uint16_t *level,
563 union samr_UserInfo *i, bool queried)
565 if (s->change.fields == 0) return s->change.fields;
567 *level = 0;
569 if ((s->change.fields & USERMOD_FIELD_ACCOUNT_NAME) &&
570 (*level == 0 || *level == 7)) {
571 *level = 7;
572 i->info7.account_name.string = s->change.account_name;
574 s->change.fields ^= USERMOD_FIELD_ACCOUNT_NAME;
577 if ((s->change.fields & USERMOD_FIELD_FULL_NAME) &&
578 (*level == 0 || *level == 8)) {
579 *level = 8;
580 i->info8.full_name.string = s->change.full_name;
582 s->change.fields ^= USERMOD_FIELD_FULL_NAME;
585 if ((s->change.fields & USERMOD_FIELD_DESCRIPTION) &&
586 (*level == 0 || *level == 13)) {
587 *level = 13;
588 i->info13.description.string = s->change.description;
590 s->change.fields ^= USERMOD_FIELD_DESCRIPTION;
593 if ((s->change.fields & USERMOD_FIELD_COMMENT) &&
594 (*level == 0 || *level == 2)) {
595 *level = 2;
597 if (queried) {
598 /* the user info is obtained, so now set the required field */
599 i->info2.comment.string = s->change.comment;
600 s->change.fields ^= USERMOD_FIELD_COMMENT;
602 } else {
603 /* we need to query the user info before setting one field in it */
604 return false;
608 if ((s->change.fields & USERMOD_FIELD_LOGON_SCRIPT) &&
609 (*level == 0 || *level == 11)) {
610 *level = 11;
611 i->info11.logon_script.string = s->change.logon_script;
613 s->change.fields ^= USERMOD_FIELD_LOGON_SCRIPT;
616 if ((s->change.fields & USERMOD_FIELD_PROFILE_PATH) &&
617 (*level == 0 || *level == 12)) {
618 *level = 12;
619 i->info12.profile_path.string = s->change.profile_path;
621 s->change.fields ^= USERMOD_FIELD_PROFILE_PATH;
624 if ((s->change.fields & USERMOD_FIELD_HOME_DIRECTORY) &&
625 (*level == 0 || *level == 10)) {
626 *level = 10;
628 if (queried) {
629 i->info10.home_directory.string = s->change.home_directory;
630 s->change.fields ^= USERMOD_FIELD_HOME_DIRECTORY;
631 } else {
632 return false;
636 if ((s->change.fields & USERMOD_FIELD_HOME_DRIVE) &&
637 (*level == 0 || *level == 10)) {
638 *level = 10;
640 if (queried) {
641 i->info10.home_drive.string = s->change.home_drive;
642 s->change.fields ^= USERMOD_FIELD_HOME_DRIVE;
643 } else {
644 return false;
648 if ((s->change.fields & USERMOD_FIELD_ACCT_EXPIRY) &&
649 (*level == 0 || *level == 17)) {
650 *level = 17;
651 i->info17.acct_expiry = timeval_to_nttime(s->change.acct_expiry);
653 s->change.fields ^= USERMOD_FIELD_ACCT_EXPIRY;
656 if ((s->change.fields & USERMOD_FIELD_ACCT_FLAGS) &&
657 (*level == 0 || *level == 16)) {
658 *level = 16;
659 i->info16.acct_flags = s->change.acct_flags;
661 s->change.fields ^= USERMOD_FIELD_ACCT_FLAGS;
664 /* We're going to be here back again soon unless all fields have been set */
665 return true;
669 static NTSTATUS usermod_change(struct composite_context *c,
670 struct usermod_state *s)
672 bool do_set;
673 union samr_UserInfo *i = &s->info;
674 struct tevent_req *subreq;
676 /* set the level to invalid value, so that unless setfields routine
677 gives it a valid value we report the error correctly */
678 uint16_t level = 27;
680 /* prepare UserInfo level and data based on bitmask field */
681 do_set = usermod_setfields(s, &level, i, false);
683 if (level < 1 || level > 26) {
684 /* apparently there's a field that the setfields routine
685 does not know how to set */
686 return NT_STATUS_INVALID_PARAMETER;
689 /* If some specific level is used to set user account data and the change
690 itself does not cover all fields then we need to query the user info
691 first, right before changing the data. Otherwise we could set required
692 fields and accidentally reset the others.
694 if (!do_set) {
695 s->queryuser.in.user_handle = &s->user_handle;
696 s->queryuser.in.level = level;
697 s->queryuser.out.info = talloc(s, union samr_UserInfo *);
698 if (composite_nomem(s->queryuser.out.info, c)) return NT_STATUS_NO_MEMORY;
701 /* send query user info request to retrieve complete data of
702 a particular info level */
703 subreq = dcerpc_samr_QueryUserInfo_r_send(s, c->event_ctx,
704 s->binding_handle,
705 &s->queryuser);
706 if (composite_nomem(subreq, c)) return NT_STATUS_NO_MEMORY;
707 tevent_req_set_callback(subreq, continue_usermod_user_queried, c);
709 } else {
710 s->setuser.in.user_handle = &s->user_handle;
711 s->setuser.in.level = level;
712 s->setuser.in.info = i;
714 /* send set user info request after making required change */
715 subreq = dcerpc_samr_SetUserInfo_r_send(s, c->event_ctx,
716 s->binding_handle,
717 &s->setuser);
718 if (composite_nomem(subreq, c)) return NT_STATUS_NO_MEMORY;
719 tevent_req_set_callback(subreq, continue_usermod_user_changed, c);
722 return NT_STATUS_OK;
727 * Stage 2: Open user account
729 static void continue_usermod_user_opened(struct tevent_req *subreq)
731 struct composite_context *c;
732 struct usermod_state *s;
734 c = tevent_req_callback_data(subreq, struct composite_context);
735 s = talloc_get_type(c->private_data, struct usermod_state);
737 c->status = dcerpc_samr_OpenUser_r_recv(subreq, s);
738 TALLOC_FREE(subreq);
739 if (!composite_is_ok(c)) return;
741 c->status = s->openuser.out.result;
742 if (!NT_STATUS_IS_OK(c->status)) {
743 composite_error(c, c->status);
744 return;
747 c->status = usermod_change(c, s);
752 * Stage 2a (optional): Query the user information
754 static void continue_usermod_user_queried(struct tevent_req *subreq)
756 struct composite_context *c;
757 struct usermod_state *s;
758 union samr_UserInfo *i;
759 uint16_t level = 0;
761 c = tevent_req_callback_data(subreq, struct composite_context);
762 s = talloc_get_type(c->private_data, struct usermod_state);
764 i = &s->info;
766 /* receive samr_QueryUserInfo result */
767 c->status = dcerpc_samr_QueryUserInfo_r_recv(subreq, s);
768 TALLOC_FREE(subreq);
769 if (!composite_is_ok(c)) return;
771 c->status = s->queryuser.out.result;
772 if (!NT_STATUS_IS_OK(c->status)) {
773 composite_error(c, c->status);
774 return;
777 /* get returned user data and make a change (potentially one
778 of many) */
779 s->info = *(*s->queryuser.out.info);
781 usermod_setfields(s, &level, i, true);
783 /* prepare rpc call arguments */
784 s->setuser.in.user_handle = &s->user_handle;
785 s->setuser.in.level = level;
786 s->setuser.in.info = i;
788 /* send the rpc request */
789 subreq = dcerpc_samr_SetUserInfo_r_send(s, c->event_ctx,
790 s->binding_handle,
791 &s->setuser);
792 if (composite_nomem(subreq, c)) return;
793 tevent_req_set_callback(subreq, continue_usermod_user_changed, c);
798 * Stage 3: Set new user account data
800 static void continue_usermod_user_changed(struct tevent_req *subreq)
802 struct composite_context *c;
803 struct usermod_state *s;
805 c = tevent_req_callback_data(subreq, struct composite_context);
806 s = talloc_get_type(c->private_data, struct usermod_state);
808 /* receive samr_SetUserInfo result */
809 c->status = dcerpc_samr_SetUserInfo_r_recv(subreq, s);
810 TALLOC_FREE(subreq);
811 if (!composite_is_ok(c)) return;
813 /* return the actual function call status */
814 c->status = s->setuser.out.result;
815 if (!NT_STATUS_IS_OK(c->status)) {
816 composite_error(c, c->status);
817 return;
820 if (s->change.fields == 0) {
821 /* all fields have been set - we're done */
822 composite_done(c);
824 } else {
825 /* something's still not changed - repeat the procedure */
826 c->status = usermod_change(c, s);
832 * Sends asynchronous usermod request
834 * @param p dce/rpc call pipe
835 * @param io arguments and results of the call
836 * @param monitor monitor function for providing information about the progress
839 struct composite_context *libnet_rpc_usermod_send(TALLOC_CTX *mem_ctx,
840 struct tevent_context *ev,
841 struct dcerpc_binding_handle *b,
842 struct libnet_rpc_usermod *io,
843 void (*monitor)(struct monitor_msg*))
845 struct composite_context *c;
846 struct usermod_state *s;
847 struct tevent_req *subreq;
849 /* composite context allocation and setup */
850 c = composite_create(mem_ctx, ev);
851 if (c == NULL) return NULL;
852 s = talloc_zero(c, struct usermod_state);
853 if (composite_nomem(s, c)) return c;
855 c->private_data = s;
857 /* store parameters in the call structure */
858 s->binding_handle= b;
859 s->domain_handle = io->in.domain_handle;
860 s->change = io->in.change;
861 s->monitor_fn = monitor;
863 /* prepare rpc call arguments */
864 s->lookupname.in.domain_handle = &io->in.domain_handle;
865 s->lookupname.in.num_names = 1;
866 s->lookupname.in.names = talloc_zero(s, struct lsa_String);
867 s->lookupname.in.names->string = io->in.username;
868 s->lookupname.out.rids = talloc_zero(s, struct samr_Ids);
869 s->lookupname.out.types = talloc_zero(s, struct samr_Ids);
870 if (composite_nomem(s->lookupname.out.rids, c)) return c;
871 if (composite_nomem(s->lookupname.out.types, c)) return c;
873 /* send the rpc request */
874 subreq = dcerpc_samr_LookupNames_r_send(s, c->event_ctx,
875 s->binding_handle,
876 &s->lookupname);
877 if (composite_nomem(subreq, c)) return c;
879 /* callback handler setup */
880 tevent_req_set_callback(subreq, continue_usermod_name_found, c);
881 return c;
886 * Waits for and receives results of asynchronous usermod call
888 * @param c composite context returned by asynchronous usermod call
889 * @param mem_ctx memory context of the call
890 * @param io pointer to results (and arguments) of the call
891 * @return nt status code of execution
894 NTSTATUS libnet_rpc_usermod_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
895 struct libnet_rpc_usermod *io)
897 NTSTATUS status;
899 status = composite_wait(c);
901 talloc_free(c);
902 return status;
907 * Synchronous version of usermod call
909 * @param pipe dce/rpc call pipe
910 * @param mem_ctx memory context for the call
911 * @param io arguments and results of the call
912 * @return nt status code of execution
915 NTSTATUS libnet_rpc_usermod(struct tevent_context *ev,
916 struct dcerpc_binding_handle *b,
917 TALLOC_CTX *mem_ctx,
918 struct libnet_rpc_usermod *io)
920 struct composite_context *c = libnet_rpc_usermod_send(mem_ctx, ev, b, io, NULL);
921 return libnet_rpc_usermod_recv(c, mem_ctx, io);