Deal with c_req send errors asynchronously
[Samba/vfs_proxy.git] / source4 / libnet / userman.c
blobc638d8af32115aaf2c7baeb6e07b409e4c88c03e
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/composite.h"
27 #include "libnet/userman.h"
28 #include "libnet/userinfo.h"
29 #include "librpc/gen_ndr/ndr_samr_c.h"
30 #include "libnet/libnet_proto.h"
33 * Composite USER ADD functionality
36 struct useradd_state {
37 struct dcerpc_pipe *pipe;
38 struct rpc_request *req;
39 struct policy_handle domain_handle;
40 struct samr_CreateUser createuser;
41 struct policy_handle user_handle;
42 uint32_t user_rid;
44 /* information about the progress */
45 void (*monitor_fn)(struct monitor_msg *);
49 static void continue_useradd_create(struct rpc_request *req);
52 /**
53 * Stage 1 (and the only one for now): Create user account.
55 static void continue_useradd_create(struct rpc_request *req)
57 struct composite_context *c;
58 struct useradd_state *s;
60 c = talloc_get_type(req->async.private_data, struct composite_context);
61 s = talloc_get_type(c->private_data, struct useradd_state);
63 /* check rpc layer status code */
64 c->status = dcerpc_ndr_request_recv(s->req);
65 if (!composite_is_ok(c)) return;
67 /* check create user call status code */
68 c->status = s->createuser.out.result;
70 /* get created user account data */
71 s->user_handle = *s->createuser.out.user_handle;
72 s->user_rid = *s->createuser.out.rid;
74 /* issue a monitor message */
75 if (s->monitor_fn) {
76 struct monitor_msg msg;
77 struct msg_rpc_create_user rpc_create;
79 rpc_create.rid = *s->createuser.out.rid;
81 msg.type = mon_SamrCreateUser;
82 msg.data = (void*)&rpc_create;
83 msg.data_size = sizeof(rpc_create);
85 s->monitor_fn(&msg);
88 composite_done(c);
92 /**
93 * Sends asynchronous useradd request
95 * @param p dce/rpc call pipe
96 * @param io arguments and results of the call
97 * @param monitor monitor function for providing information about the progress
100 struct composite_context *libnet_rpc_useradd_send(struct dcerpc_pipe *p,
101 struct libnet_rpc_useradd *io,
102 void (*monitor)(struct monitor_msg*))
104 struct composite_context *c;
105 struct useradd_state *s;
107 if (!p || !io) return NULL;
109 /* composite allocation and setup */
110 c = composite_create(p, dcerpc_event_context(p));
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->pipe = p;
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 s->req = dcerpc_samr_CreateUser_send(p, c, &s->createuser);
137 if (composite_nomem(s->req, c)) return c;
139 composite_continue_rpc(c, s->req, continue_useradd_create, c);
140 return c;
145 * Waits for and receives result of asynchronous useradd call
147 * @param c composite context returned by asynchronous useradd call
148 * @param mem_ctx memory context of the call
149 * @param io pointer to results (and arguments) of the call
150 * @return nt status code of execution
153 NTSTATUS libnet_rpc_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
154 struct libnet_rpc_useradd *io)
156 NTSTATUS status;
157 struct useradd_state *s;
159 status = composite_wait(c);
161 if (NT_STATUS_IS_OK(status) && io) {
162 /* get and return result of the call */
163 s = talloc_get_type(c->private_data, struct useradd_state);
164 io->out.user_handle = s->user_handle;
167 talloc_free(c);
168 return status;
173 * Synchronous version of useradd call
175 * @param pipe dce/rpc call pipe
176 * @param mem_ctx memory context for the call
177 * @param io arguments and results of the call
178 * @return nt status code of execution
181 NTSTATUS libnet_rpc_useradd(struct dcerpc_pipe *p,
182 TALLOC_CTX *mem_ctx,
183 struct libnet_rpc_useradd *io)
185 struct composite_context *c = libnet_rpc_useradd_send(p, io, NULL);
186 return libnet_rpc_useradd_recv(c, mem_ctx, io);
192 * Composite USER DELETE functionality
196 struct userdel_state {
197 struct dcerpc_pipe *pipe;
198 struct policy_handle domain_handle;
199 struct policy_handle user_handle;
200 struct samr_LookupNames lookupname;
201 struct samr_OpenUser openuser;
202 struct samr_DeleteUser deleteuser;
204 /* information about the progress */
205 void (*monitor_fn)(struct monitor_msg *);
209 static void continue_userdel_name_found(struct rpc_request *req);
210 static void continue_userdel_user_opened(struct rpc_request* req);
211 static void continue_userdel_deleted(struct rpc_request *req);
215 * Stage 1: Lookup the user name and resolve it to rid
217 static void continue_userdel_name_found(struct rpc_request *req)
219 struct composite_context *c;
220 struct userdel_state *s;
221 struct rpc_request *openuser_req;
222 struct monitor_msg msg;
224 c = talloc_get_type(req->async.private_data, struct composite_context);
225 s = talloc_get_type(c->private_data, struct userdel_state);
227 /* receive samr_LookupNames result */
228 c->status = dcerpc_ndr_request_recv(req);
229 if (!composite_is_ok(c)) return;
231 c->status = s->lookupname.out.result;
232 if (!NT_STATUS_IS_OK(c->status)) {
233 composite_error(c, c->status);
234 return;
237 /* what to do when there's no user account to delete
238 and what if there's more than one rid resolved */
239 if (!s->lookupname.out.rids->count) {
240 c->status = NT_STATUS_NO_SUCH_USER;
241 composite_error(c, c->status);
242 return;
244 } else if (!s->lookupname.out.rids->count > 1) {
245 c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
246 composite_error(c, c->status);
247 return;
250 /* issue a monitor message */
251 if (s->monitor_fn) {
252 struct msg_rpc_lookup_name msg_lookup;
254 msg_lookup.rid = s->lookupname.out.rids->ids;
255 msg_lookup.count = s->lookupname.out.rids->count;
257 msg.type = mon_SamrLookupName;
258 msg.data = (void*)&msg_lookup;
259 msg.data_size = sizeof(msg_lookup);
260 s->monitor_fn(&msg);
263 /* prepare the arguments for rpc call */
264 s->openuser.in.domain_handle = &s->domain_handle;
265 s->openuser.in.rid = s->lookupname.out.rids->ids[0];
266 s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
267 s->openuser.out.user_handle = &s->user_handle;
269 /* send rpc request */
270 openuser_req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
271 if (composite_nomem(openuser_req, c)) return;
273 composite_continue_rpc(c, openuser_req, continue_userdel_user_opened, c);
278 * Stage 2: Open user account.
280 static void continue_userdel_user_opened(struct rpc_request* req)
282 struct composite_context *c;
283 struct userdel_state *s;
284 struct rpc_request *deluser_req;
285 struct monitor_msg msg;
287 c = talloc_get_type(req->async.private_data, struct composite_context);
288 s = talloc_get_type(c->private_data, struct userdel_state);
290 /* receive samr_OpenUser result */
291 c->status = dcerpc_ndr_request_recv(req);
292 if (!composite_is_ok(c)) return;
294 c->status = s->openuser.out.result;
295 if (!NT_STATUS_IS_OK(c->status)) {
296 composite_error(c, c->status);
297 return;
300 /* issue a monitor message */
301 if (s->monitor_fn) {
302 struct msg_rpc_open_user msg_open;
304 msg_open.rid = s->openuser.in.rid;
305 msg_open.access_mask = s->openuser.in.access_mask;
307 msg.type = mon_SamrOpenUser;
308 msg.data = (void*)&msg_open;
309 msg.data_size = sizeof(msg_open);
310 s->monitor_fn(&msg);
313 /* prepare the final rpc call arguments */
314 s->deleteuser.in.user_handle = &s->user_handle;
315 s->deleteuser.out.user_handle = &s->user_handle;
317 /* send rpc request */
318 deluser_req = dcerpc_samr_DeleteUser_send(s->pipe, c, &s->deleteuser);
319 if (composite_nomem(deluser_req, c)) return;
321 /* callback handler setup */
322 composite_continue_rpc(c, deluser_req, continue_userdel_deleted, c);
327 * Stage 3: Delete user account
329 static void continue_userdel_deleted(struct rpc_request *req)
331 struct composite_context *c;
332 struct userdel_state *s;
333 struct monitor_msg msg;
335 c = talloc_get_type(req->async.private_data, struct composite_context);
336 s = talloc_get_type(c->private_data, struct userdel_state);
338 /* receive samr_DeleteUser result */
339 c->status = dcerpc_ndr_request_recv(req);
340 if (!composite_is_ok(c)) return;
342 /* return the actual function call status */
343 c->status = s->deleteuser.out.result;
344 if (!NT_STATUS_IS_OK(c->status)) {
345 composite_error(c, c->status);
346 return;
349 /* issue a monitor message */
350 if (s->monitor_fn) {
351 msg.type = mon_SamrDeleteUser;
352 msg.data = NULL;
353 msg.data_size = 0;
354 s->monitor_fn(&msg);
357 composite_done(c);
362 * Sends asynchronous userdel request
364 * @param p dce/rpc call pipe
365 * @param io arguments and results of the call
366 * @param monitor monitor function for providing information about the progress
369 struct composite_context *libnet_rpc_userdel_send(struct dcerpc_pipe *p,
370 struct libnet_rpc_userdel *io,
371 void (*monitor)(struct monitor_msg*))
373 struct composite_context *c;
374 struct userdel_state *s;
375 struct rpc_request *lookup_req;
377 /* composite context allocation and setup */
378 c = composite_create(p, dcerpc_event_context(p));
379 if (c == NULL) return NULL;
381 s = talloc_zero(c, struct userdel_state);
382 if (composite_nomem(s, c)) return c;
384 c->private_data = s;
386 /* store function parameters in the state structure */
387 s->pipe = p;
388 s->domain_handle = io->in.domain_handle;
389 s->monitor_fn = monitor;
391 /* preparing parameters to send rpc request */
392 s->lookupname.in.domain_handle = &io->in.domain_handle;
393 s->lookupname.in.num_names = 1;
394 s->lookupname.in.names = talloc_zero(s, struct lsa_String);
395 s->lookupname.in.names->string = io->in.username;
396 s->lookupname.out.rids = talloc_zero(s, struct samr_Ids);
397 s->lookupname.out.types = talloc_zero(s, struct samr_Ids);
398 if (composite_nomem(s->lookupname.out.rids, c)) return c;
399 if (composite_nomem(s->lookupname.out.types, c)) return c;
401 /* send the request */
402 lookup_req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
403 if (composite_nomem(lookup_req, c)) return c;
405 /* set the next stage */
406 composite_continue_rpc(c, lookup_req, continue_userdel_name_found, c);
407 return c;
412 * Waits for and receives results of asynchronous userdel call
414 * @param c composite context returned by asynchronous userdel call
415 * @param mem_ctx memory context of the call
416 * @param io pointer to results (and arguments) of the call
417 * @return nt status code of execution
420 NTSTATUS libnet_rpc_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
421 struct libnet_rpc_userdel *io)
423 NTSTATUS status;
424 struct userdel_state *s;
426 status = composite_wait(c);
428 if (NT_STATUS_IS_OK(status) && io) {
429 s = talloc_get_type(c->private_data, struct userdel_state);
430 io->out.user_handle = s->user_handle;
433 talloc_free(c);
434 return status;
439 * Synchronous version of userdel call
441 * @param pipe dce/rpc call pipe
442 * @param mem_ctx memory context for the call
443 * @param io arguments and results of the call
444 * @return nt status code of execution
447 NTSTATUS libnet_rpc_userdel(struct dcerpc_pipe *p,
448 TALLOC_CTX *mem_ctx,
449 struct libnet_rpc_userdel *io)
451 struct composite_context *c = libnet_rpc_userdel_send(p, io, NULL);
452 return libnet_rpc_userdel_recv(c, mem_ctx, io);
457 * USER MODIFY functionality
460 static void continue_usermod_name_found(struct rpc_request *req);
461 static void continue_usermod_user_opened(struct rpc_request *req);
462 static void continue_usermod_user_queried(struct rpc_request *req);
463 static void continue_usermod_user_changed(struct rpc_request *req);
466 struct usermod_state {
467 struct dcerpc_pipe *pipe;
468 struct policy_handle domain_handle;
469 struct policy_handle user_handle;
470 struct usermod_change change;
471 union samr_UserInfo info;
472 struct samr_LookupNames lookupname;
473 struct samr_OpenUser openuser;
474 struct samr_SetUserInfo setuser;
475 struct samr_QueryUserInfo queryuser;
477 /* information about the progress */
478 void (*monitor_fn)(struct monitor_msg *);
483 * Step 1: Lookup user name
485 static void continue_usermod_name_found(struct rpc_request *req)
487 struct composite_context *c;
488 struct usermod_state *s;
489 struct rpc_request *openuser_req;
490 struct monitor_msg msg;
492 c = talloc_get_type(req->async.private_data, struct composite_context);
493 s = talloc_get_type(c->private_data, struct usermod_state);
495 /* receive samr_LookupNames result */
496 c->status = dcerpc_ndr_request_recv(req);
497 if (!composite_is_ok(c)) return;
499 c->status = s->lookupname.out.result;
500 if (!NT_STATUS_IS_OK(c->status)) {
501 composite_error(c, c->status);
502 return;
505 /* what to do when there's no user account to delete
506 and what if there's more than one rid resolved */
507 if (!s->lookupname.out.rids->count) {
508 c->status = NT_STATUS_NO_SUCH_USER;
509 composite_error(c, c->status);
510 return;
512 } else if (!s->lookupname.out.rids->count > 1) {
513 c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
514 composite_error(c, c->status);
515 return;
518 /* issue a monitor message */
519 if (s->monitor_fn) {
520 struct msg_rpc_lookup_name msg_lookup;
522 msg_lookup.rid = s->lookupname.out.rids->ids;
523 msg_lookup.count = s->lookupname.out.rids->count;
525 msg.type = mon_SamrLookupName;
526 msg.data = (void*)&msg_lookup;
527 msg.data_size = sizeof(msg_lookup);
528 s->monitor_fn(&msg);
531 /* prepare the next rpc call */
532 s->openuser.in.domain_handle = &s->domain_handle;
533 s->openuser.in.rid = s->lookupname.out.rids->ids[0];
534 s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
535 s->openuser.out.user_handle = &s->user_handle;
537 /* send the rpc request */
538 openuser_req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
539 if (composite_nomem(openuser_req, c)) return;
541 composite_continue_rpc(c, openuser_req, continue_usermod_user_opened, c);
546 * Choose a proper level of samr_UserInfo structure depending on required
547 * change specified by means of flags field. Subsequent calls of this
548 * function are made until there's no flags set meaning that all of the
549 * changes have been made.
551 static bool usermod_setfields(struct usermod_state *s, uint16_t *level,
552 union samr_UserInfo *i, bool queried)
554 if (s->change.fields == 0) return s->change.fields;
556 *level = 0;
558 if ((s->change.fields & USERMOD_FIELD_ACCOUNT_NAME) &&
559 (*level == 0 || *level == 7)) {
560 *level = 7;
561 i->info7.account_name.string = s->change.account_name;
563 s->change.fields ^= USERMOD_FIELD_ACCOUNT_NAME;
566 if ((s->change.fields & USERMOD_FIELD_FULL_NAME) &&
567 (*level == 0 || *level == 8)) {
568 *level = 8;
569 i->info8.full_name.string = s->change.full_name;
571 s->change.fields ^= USERMOD_FIELD_FULL_NAME;
574 if ((s->change.fields & USERMOD_FIELD_DESCRIPTION) &&
575 (*level == 0 || *level == 13)) {
576 *level = 13;
577 i->info13.description.string = s->change.description;
579 s->change.fields ^= USERMOD_FIELD_DESCRIPTION;
582 if ((s->change.fields & USERMOD_FIELD_COMMENT) &&
583 (*level == 0 || *level == 2)) {
584 *level = 2;
586 if (queried) {
587 /* the user info is obtained, so now set the required field */
588 i->info2.comment.string = s->change.comment;
589 s->change.fields ^= USERMOD_FIELD_COMMENT;
591 } else {
592 /* we need to query the user info before setting one field in it */
593 return false;
597 if ((s->change.fields & USERMOD_FIELD_LOGON_SCRIPT) &&
598 (*level == 0 || *level == 11)) {
599 *level = 11;
600 i->info11.logon_script.string = s->change.logon_script;
602 s->change.fields ^= USERMOD_FIELD_LOGON_SCRIPT;
605 if ((s->change.fields & USERMOD_FIELD_PROFILE_PATH) &&
606 (*level == 0 || *level == 12)) {
607 *level = 12;
608 i->info12.profile_path.string = s->change.profile_path;
610 s->change.fields ^= USERMOD_FIELD_PROFILE_PATH;
613 if ((s->change.fields & USERMOD_FIELD_HOME_DIRECTORY) &&
614 (*level == 0 || *level == 10)) {
615 *level = 10;
617 if (queried) {
618 i->info10.home_directory.string = s->change.home_directory;
619 s->change.fields ^= USERMOD_FIELD_HOME_DIRECTORY;
620 } else {
621 return false;
625 if ((s->change.fields & USERMOD_FIELD_HOME_DRIVE) &&
626 (*level == 0 || *level == 10)) {
627 *level = 10;
629 if (queried) {
630 i->info10.home_drive.string = s->change.home_drive;
631 s->change.fields ^= USERMOD_FIELD_HOME_DRIVE;
632 } else {
633 return false;
637 if ((s->change.fields & USERMOD_FIELD_ACCT_EXPIRY) &&
638 (*level == 0 || *level == 17)) {
639 *level = 17;
640 i->info17.acct_expiry = timeval_to_nttime(s->change.acct_expiry);
642 s->change.fields ^= USERMOD_FIELD_ACCT_EXPIRY;
645 if ((s->change.fields & USERMOD_FIELD_ACCT_FLAGS) &&
646 (*level == 0 || *level == 16)) {
647 *level = 16;
648 i->info16.acct_flags = s->change.acct_flags;
650 s->change.fields ^= USERMOD_FIELD_ACCT_FLAGS;
653 /* We're going to be here back again soon unless all fields have been set */
654 return true;
658 static NTSTATUS usermod_change(struct composite_context *c,
659 struct usermod_state *s)
661 struct rpc_request *query_req, *setuser_req;
662 bool do_set;
663 union samr_UserInfo *i = &s->info;
665 /* set the level to invalid value, so that unless setfields routine
666 gives it a valid value we report the error correctly */
667 uint16_t level = 27;
669 /* prepare UserInfo level and data based on bitmask field */
670 do_set = usermod_setfields(s, &level, i, false);
672 if (level < 1 || level > 26) {
673 /* apparently there's a field that the setfields routine
674 does not know how to set */
675 return NT_STATUS_INVALID_PARAMETER;
678 /* If some specific level is used to set user account data and the change
679 itself does not cover all fields then we need to query the user info
680 first, right before changing the data. Otherwise we could set required
681 fields and accidentally reset the others.
683 if (!do_set) {
684 s->queryuser.in.user_handle = &s->user_handle;
685 s->queryuser.in.level = level;
686 s->queryuser.out.info = talloc(s, union samr_UserInfo *);
687 if (composite_nomem(s->queryuser.out.info, c)) return;
690 /* send query user info request to retrieve complete data of
691 a particular info level */
692 query_req = dcerpc_samr_QueryUserInfo_send(s->pipe, c, &s->queryuser);
693 composite_continue_rpc(c, query_req, continue_usermod_user_queried, c);
695 } else {
696 s->setuser.in.user_handle = &s->user_handle;
697 s->setuser.in.level = level;
698 s->setuser.in.info = i;
700 /* send set user info request after making required change */
701 setuser_req = dcerpc_samr_SetUserInfo_send(s->pipe, c, &s->setuser);
702 composite_continue_rpc(c, setuser_req, continue_usermod_user_changed, c);
705 return NT_STATUS_OK;
710 * Stage 2: Open user account
712 static void continue_usermod_user_opened(struct rpc_request *req)
714 struct composite_context *c;
715 struct usermod_state *s;
717 c = talloc_get_type(req->async.private_data, struct composite_context);
718 s = talloc_get_type(c->private_data, struct usermod_state);
720 c->status = dcerpc_ndr_request_recv(req);
721 if (!composite_is_ok(c)) return;
723 c->status = s->openuser.out.result;
724 if (!NT_STATUS_IS_OK(c->status)) {
725 composite_error(c, c->status);
726 return;
729 c->status = usermod_change(c, s);
734 * Stage 2a (optional): Query the user information
736 static void continue_usermod_user_queried(struct rpc_request *req)
738 struct composite_context *c;
739 struct usermod_state *s;
740 union samr_UserInfo *i;
741 uint16_t level;
742 struct rpc_request *setuser_req;
744 c = talloc_get_type(req->async.private_data, struct composite_context);
745 s = talloc_get_type(c->private_data, struct usermod_state);
747 i = &s->info;
749 /* receive samr_QueryUserInfo result */
750 c->status = dcerpc_ndr_request_recv(req);
751 if (!composite_is_ok(c)) return;
753 c->status = s->queryuser.out.result;
754 if (!NT_STATUS_IS_OK(c->status)) {
755 composite_error(c, c->status);
756 return;
759 /* get returned user data and make a change (potentially one
760 of many) */
761 s->info = *(*s->queryuser.out.info);
763 usermod_setfields(s, &level, i, true);
765 /* prepare rpc call arguments */
766 s->setuser.in.user_handle = &s->user_handle;
767 s->setuser.in.level = level;
768 s->setuser.in.info = i;
770 /* send the rpc request */
771 setuser_req = dcerpc_samr_SetUserInfo_send(s->pipe, c, &s->setuser);
772 composite_continue_rpc(c, setuser_req, continue_usermod_user_changed, c);
777 * Stage 3: Set new user account data
779 static void continue_usermod_user_changed(struct rpc_request *req)
781 struct composite_context *c;
782 struct usermod_state *s;
784 c = talloc_get_type(req->async.private_data, struct composite_context);
785 s = talloc_get_type(c->private_data, struct usermod_state);
787 /* receive samr_SetUserInfo result */
788 c->status = dcerpc_ndr_request_recv(req);
789 if (!composite_is_ok(c)) return;
791 /* return the actual function call status */
792 c->status = s->setuser.out.result;
793 if (!NT_STATUS_IS_OK(c->status)) {
794 composite_error(c, c->status);
795 return;
798 if (s->change.fields == 0) {
799 /* all fields have been set - we're done */
800 composite_done(c);
802 } else {
803 /* something's still not changed - repeat the procedure */
804 c->status = usermod_change(c, s);
810 * Sends asynchronous usermod request
812 * @param p dce/rpc call pipe
813 * @param io arguments and results of the call
814 * @param monitor monitor function for providing information about the progress
817 struct composite_context *libnet_rpc_usermod_send(struct dcerpc_pipe *p,
818 struct libnet_rpc_usermod *io,
819 void (*monitor)(struct monitor_msg*))
821 struct composite_context *c;
822 struct usermod_state *s;
823 struct rpc_request *lookup_req;
825 /* composite context allocation and setup */
826 c = composite_create(p, dcerpc_event_context(p));
827 if (c == NULL) return NULL;
828 s = talloc_zero(c, struct usermod_state);
829 if (composite_nomem(s, c)) return c;
831 c->private_data = s;
833 /* store parameters in the call structure */
834 s->pipe = p;
835 s->domain_handle = io->in.domain_handle;
836 s->change = io->in.change;
837 s->monitor_fn = monitor;
839 /* prepare rpc call arguments */
840 s->lookupname.in.domain_handle = &io->in.domain_handle;
841 s->lookupname.in.num_names = 1;
842 s->lookupname.in.names = talloc_zero(s, struct lsa_String);
843 s->lookupname.in.names->string = io->in.username;
844 s->lookupname.out.rids = talloc_zero(s, struct samr_Ids);
845 s->lookupname.out.types = talloc_zero(s, struct samr_Ids);
846 if (composite_nomem(s->lookupname.out.rids, c)) return c;
847 if (composite_nomem(s->lookupname.out.types, c)) return c;
849 /* send the rpc request */
850 lookup_req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
851 if (composite_nomem(lookup_req, c)) return c;
853 /* callback handler setup */
854 composite_continue_rpc(c, lookup_req, continue_usermod_name_found, c);
855 return c;
860 * Waits for and receives results of asynchronous usermod call
862 * @param c composite context returned by asynchronous usermod call
863 * @param mem_ctx memory context of the call
864 * @param io pointer to results (and arguments) of the call
865 * @return nt status code of execution
868 NTSTATUS libnet_rpc_usermod_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
869 struct libnet_rpc_usermod *io)
871 NTSTATUS status;
873 status = composite_wait(c);
875 talloc_free(c);
876 return status;
881 * Synchronous version of usermod call
883 * @param pipe dce/rpc call pipe
884 * @param mem_ctx memory context for the call
885 * @param io arguments and results of the call
886 * @return nt status code of execution
889 NTSTATUS libnet_rpc_usermod(struct dcerpc_pipe *p,
890 TALLOC_CTX *mem_ctx,
891 struct libnet_rpc_usermod *io)
893 struct composite_context *c = libnet_rpc_usermod_send(p, io, NULL);
894 return libnet_rpc_usermod_recv(c, mem_ctx, io);