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)
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"
32 * Composite USER ADD functionality
35 static void useradd_handler(struct rpc_request*);
37 enum useradd_stage { USERADD_CREATE };
39 struct useradd_state {
40 enum useradd_stage stage;
41 struct dcerpc_pipe *pipe;
42 struct rpc_request *req;
43 struct policy_handle domain_handle;
44 struct samr_CreateUser createuser;
45 struct policy_handle user_handle;
48 /* information about the progress */
49 void (*monitor_fn)(struct monitor_msg *);
54 * Stage 1 (and the only one for now): Create user account.
56 static NTSTATUS useradd_create(struct composite_context *c,
57 struct useradd_state *s)
59 c->status = dcerpc_ndr_request_recv(s->req);
60 NT_STATUS_NOT_OK_RETURN(c->status);
62 /* return the actual function call status */
63 c->status = s->createuser.out.result;
65 c->state = COMPOSITE_STATE_DONE;
71 * Event handler for asynchronous request. Handles transition through
72 * intermediate stages of the call.
74 * @param req rpc call context
76 static void useradd_handler(struct rpc_request *req)
78 struct composite_context *c = req->async.private_data;
79 struct useradd_state *s = talloc_get_type(c->private_data, struct useradd_state);
80 struct monitor_msg msg;
81 struct msg_rpc_create_user *rpc_create;
85 c->status = useradd_create(c, s);
87 /* prepare a message to pass to monitor function */
88 msg.type = rpc_create_user;
89 rpc_create = talloc(s, struct msg_rpc_create_user);
90 rpc_create->rid = *s->createuser.out.rid;
91 msg.data = (void*)rpc_create;
92 msg.data_size = sizeof(*rpc_create);
96 /* are we ok so far ? */
97 if (!NT_STATUS_IS_OK(c->status)) {
98 c->state = COMPOSITE_STATE_ERROR;
101 /* call monitor function provided the pointer has been passed */
106 /* are we done yet ? */
107 if (c->state >= COMPOSITE_STATE_DONE &&
115 * Sends asynchronous useradd request
117 * @param p dce/rpc call pipe
118 * @param io arguments and results of the call
119 * @param monitor monitor function for providing information about the progress
122 struct composite_context *libnet_rpc_useradd_send(struct dcerpc_pipe *p,
123 struct libnet_rpc_useradd *io,
124 void (*monitor)(struct monitor_msg*))
126 struct composite_context *c;
127 struct useradd_state *s;
129 if (!p || !io) return NULL;
131 /* composite allocation and setup */
132 c = composite_create(p, dcerpc_event_context(p));
133 if (c == NULL) return NULL;
135 s = talloc_zero(c, struct useradd_state);
136 if (composite_nomem(s, c)) return c;
140 /* put passed arguments to the state structure */
141 s->domain_handle = io->in.domain_handle;
143 s->monitor_fn = monitor;
145 /* preparing parameters to send rpc request */
146 s->createuser.in.domain_handle = &io->in.domain_handle;
148 s->createuser.in.account_name = talloc_zero(c, struct lsa_String);
149 if (composite_nomem(s->createuser.in.account_name, c)) return c;
151 s->createuser.in.account_name->string = talloc_strdup(c, io->in.username);
152 if (composite_nomem(s->createuser.in.account_name->string, c)) return c;
154 s->createuser.out.user_handle = &s->user_handle;
155 s->createuser.out.rid = &s->user_rid;
157 /* send the request */
158 s->req = dcerpc_samr_CreateUser_send(p, c, &s->createuser);
159 if (composite_nomem(s->req, c)) return c;
161 /* callback handler for continuation */
162 s->req->async.callback = useradd_handler;
163 s->req->async.private_data = c;
164 s->stage = USERADD_CREATE;
171 * Waits for and receives result of asynchronous useradd call
173 * @param c composite context returned by asynchronous useradd call
174 * @param mem_ctx memory context of the call
175 * @param io pointer to results (and arguments) of the call
176 * @return nt status code of execution
179 NTSTATUS libnet_rpc_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
180 struct libnet_rpc_useradd *io)
183 struct useradd_state *s;
185 status = composite_wait(c);
187 if (NT_STATUS_IS_OK(status) && io) {
188 /* get and return result of the call */
189 s = talloc_get_type(c->private_data, struct useradd_state);
190 io->out.user_handle = s->user_handle;
199 * Synchronous version of useradd call
201 * @param pipe dce/rpc call pipe
202 * @param mem_ctx memory context for the call
203 * @param io arguments and results of the call
204 * @return nt status code of execution
207 NTSTATUS libnet_rpc_useradd(struct dcerpc_pipe *p,
209 struct libnet_rpc_useradd *io)
211 struct composite_context *c = libnet_rpc_useradd_send(p, io, NULL);
212 return libnet_rpc_useradd_recv(c, mem_ctx, io);
218 * Composite USER DELETE functionality
221 static void userdel_handler(struct rpc_request*);
223 enum userdel_stage { USERDEL_LOOKUP, USERDEL_OPEN, USERDEL_DELETE };
225 struct userdel_state {
226 enum userdel_stage stage;
227 struct dcerpc_pipe *pipe;
228 struct rpc_request *req;
229 struct policy_handle domain_handle;
230 struct policy_handle user_handle;
231 struct samr_LookupNames lookupname;
232 struct samr_OpenUser openuser;
233 struct samr_DeleteUser deleteuser;
235 /* information about the progress */
236 void (*monitor_fn)(struct monitor_msg *);
241 * Stage 1: Lookup the user name and resolve it to rid
243 static NTSTATUS userdel_lookup(struct composite_context *c,
244 struct userdel_state *s)
246 /* receive samr_LookupNames result */
247 c->status = dcerpc_ndr_request_recv(s->req);
249 /* check rpc layer status */
250 NT_STATUS_NOT_OK_RETURN(c->status);
252 /* check the call itself status */
253 NT_STATUS_NOT_OK_RETURN(s->lookupname.out.result);
255 /* what to do when there's no user account to delete
256 and what if there's more than one rid resolved */
257 if (!s->lookupname.out.rids.count) {
258 c->status = NT_STATUS_NO_SUCH_USER;
259 composite_error(c, c->status);
261 } else if (!s->lookupname.out.rids.count > 1) {
262 c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
263 composite_error(c, c->status);
266 /* prepare the next rpc call arguments */
267 s->openuser.in.domain_handle = &s->domain_handle;
268 s->openuser.in.rid = s->lookupname.out.rids.ids[0];
269 s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
270 s->openuser.out.user_handle = &s->user_handle;
272 /* send rpc request */
273 s->req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
274 if (s->req == NULL) return NT_STATUS_NO_MEMORY;
276 /* callback handler setup */
277 s->req->async.callback = userdel_handler;
278 s->req->async.private_data = c;
279 s->stage = USERDEL_OPEN;
286 * Stage 2: Open user account.
288 static NTSTATUS userdel_open(struct composite_context *c,
289 struct userdel_state *s)
291 /* receive samr_OpenUser result */
292 c->status = dcerpc_ndr_request_recv(s->req);
293 NT_STATUS_NOT_OK_RETURN(c->status);
295 /* prepare the final rpc call arguments */
296 s->deleteuser.in.user_handle = &s->user_handle;
297 s->deleteuser.out.user_handle = &s->user_handle;
299 /* send rpc request */
300 s->req = dcerpc_samr_DeleteUser_send(s->pipe, c, &s->deleteuser);
301 if (s->req == NULL) return NT_STATUS_NO_MEMORY;
303 /* callback handler setup */
304 s->req->async.callback = userdel_handler;
305 s->req->async.private_data = c;
306 s->stage = USERDEL_DELETE;
313 * Stage 3: Delete user account
315 static NTSTATUS userdel_delete(struct composite_context *c,
316 struct userdel_state *s)
318 /* receive samr_DeleteUser result */
319 c->status = dcerpc_ndr_request_recv(s->req);
320 NT_STATUS_NOT_OK_RETURN(c->status);
322 /* return the actual function call status */
323 c->status = s->deleteuser.out.result;
325 c->state = COMPOSITE_STATE_DONE;
332 * Event handler for asynchronous request. Handles transition through
333 * intermediate stages of the call.
335 * @param req rpc call context
337 static void userdel_handler(struct rpc_request *req)
339 struct composite_context *c;
340 struct userdel_state *s;
341 struct monitor_msg msg;
342 struct msg_rpc_lookup_name *msg_lookup;
343 struct msg_rpc_open_user *msg_open;
345 c = talloc_get_type(req->async.private_data, struct composite_context);
346 s = talloc_get_type(c->private_data, struct userdel_state);
350 c->status = userdel_lookup(c, s);
352 /* monitor message */
353 msg.type = rpc_lookup_name;
354 msg_lookup = talloc(s, struct msg_rpc_lookup_name);
356 msg_lookup->rid = s->lookupname.out.rids.ids;
357 msg_lookup->count = s->lookupname.out.rids.count;
358 msg.data = (void*)msg_lookup;
359 msg.data_size = sizeof(*msg_lookup);
363 c->status = userdel_open(c, s);
365 /* monitor message */
366 msg.type = rpc_open_user;
367 msg_open = talloc(s, struct msg_rpc_open_user);
369 msg_open->rid = s->openuser.in.rid;
370 msg_open->access_mask = s->openuser.in.rid;
371 msg.data = (void*)msg_open;
372 msg.data_size = sizeof(*msg_open);
376 c->status = userdel_delete(c, s);
378 /* monitor message */
379 msg.type = rpc_delete_user;
385 /* are we ok, so far ? */
386 if (!NT_STATUS_IS_OK(c->status)) {
387 c->state = COMPOSITE_STATE_ERROR;
390 /* call monitor function provided the pointer has been passed */
395 /* are we done yet */
396 if (c->state >= COMPOSITE_STATE_DONE &&
404 * Sends asynchronous userdel request
406 * @param p dce/rpc call pipe
407 * @param io arguments and results of the call
408 * @param monitor monitor function for providing information about the progress
411 struct composite_context *libnet_rpc_userdel_send(struct dcerpc_pipe *p,
412 struct libnet_rpc_userdel *io,
413 void (*monitor)(struct monitor_msg*))
415 struct composite_context *c;
416 struct userdel_state *s;
418 /* composite context allocation and setup */
419 c = talloc_zero(p, struct composite_context);
420 if (c == NULL) return NULL;
422 s = talloc_zero(c, struct userdel_state);
423 if (composite_nomem(s, c)) return c;
425 c->state = COMPOSITE_STATE_IN_PROGRESS;
427 c->event_ctx = dcerpc_event_context(p);
429 /* store function parameters in the state structure */
431 s->domain_handle = io->in.domain_handle;
432 s->monitor_fn = monitor;
434 /* preparing parameters to send rpc request */
435 s->lookupname.in.domain_handle = &io->in.domain_handle;
436 s->lookupname.in.num_names = 1;
437 s->lookupname.in.names = talloc_zero(s, struct lsa_String);
438 s->lookupname.in.names->string = io->in.username;
440 /* send the request */
441 s->req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
443 /* callback handler setup */
444 s->req->async.callback = userdel_handler;
445 s->req->async.private_data = c;
446 s->stage = USERDEL_LOOKUP;
453 * Waits for and receives results of asynchronous userdel call
455 * @param c composite context returned by asynchronous userdel call
456 * @param mem_ctx memory context of the call
457 * @param io pointer to results (and arguments) of the call
458 * @return nt status code of execution
461 NTSTATUS libnet_rpc_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
462 struct libnet_rpc_userdel *io)
465 struct userdel_state *s;
467 status = composite_wait(c);
469 if (NT_STATUS_IS_OK(status) && io) {
470 s = talloc_get_type(c->private_data, struct userdel_state);
471 io->out.user_handle = s->user_handle;
480 * Synchronous version of userdel call
482 * @param pipe dce/rpc call pipe
483 * @param mem_ctx memory context for the call
484 * @param io arguments and results of the call
485 * @return nt status code of execution
488 NTSTATUS libnet_rpc_userdel(struct dcerpc_pipe *p,
490 struct libnet_rpc_userdel *io)
492 struct composite_context *c = libnet_rpc_userdel_send(p, io, NULL);
493 return libnet_rpc_userdel_recv(c, mem_ctx, io);
498 * USER MODIFY functionality
501 static void usermod_handler(struct rpc_request*);
503 enum usermod_stage { USERMOD_LOOKUP, USERMOD_OPEN, USERMOD_QUERY, USERMOD_MODIFY };
505 struct usermod_state {
506 enum usermod_stage stage;
507 struct dcerpc_pipe *pipe;
508 struct rpc_request *req;
509 struct policy_handle domain_handle;
510 struct policy_handle user_handle;
511 struct usermod_change change;
512 union samr_UserInfo info;
513 struct samr_LookupNames lookupname;
514 struct samr_OpenUser openuser;
515 struct samr_SetUserInfo setuser;
516 struct samr_QueryUserInfo queryuser;
518 /* information about the progress */
519 void (*monitor_fn)(struct monitor_msg *);
524 * Step 1: Lookup user name
526 static NTSTATUS usermod_lookup(struct composite_context *c,
527 struct usermod_state *s)
529 /* receive samr_LookupNames result */
530 c->status = dcerpc_ndr_request_recv(s->req);
531 NT_STATUS_NOT_OK_RETURN(c->status);
533 /* what to do when there's no user account to delete
534 and what if there's more than one rid resolved */
535 if (!s->lookupname.out.rids.count) {
536 c->status = NT_STATUS_NO_SUCH_USER;
537 c->state = COMPOSITE_STATE_ERROR;
540 } else if (!s->lookupname.out.rids.count > 1) {
541 c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
542 c->state = COMPOSITE_STATE_ERROR;
546 /* prepare the next rpc call */
547 s->openuser.in.domain_handle = &s->domain_handle;
548 s->openuser.in.rid = s->lookupname.out.rids.ids[0];
549 s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
550 s->openuser.out.user_handle = &s->user_handle;
552 /* send the rpc request */
553 s->req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
555 /* callback handler setup */
556 s->req->async.callback = usermod_handler;
557 s->req->async.private_data = c;
558 s->stage = USERMOD_OPEN;
565 * Choose a proper level of samr_UserInfo structure depending on required
566 * change specified by means of flags field. Subsequent calls of this
567 * function are made until there's no flags set meaning that all of the
568 * changes have been made.
570 static uint32_t usermod_setfields(struct usermod_state *s, uint16_t *level,
571 union samr_UserInfo *i)
573 if (s->change.fields == 0) return s->change.fields;
577 if ((s->change.fields & USERMOD_FIELD_ACCOUNT_NAME) &&
578 (*level == 0 || *level == 7)) {
580 i->info7.account_name.string = s->change.account_name;
582 s->change.fields ^= USERMOD_FIELD_ACCOUNT_NAME;
585 if ((s->change.fields & USERMOD_FIELD_FULL_NAME) &&
586 (*level == 0 || *level == 8)) {
588 i->info8.full_name.string = s->change.full_name;
590 s->change.fields ^= USERMOD_FIELD_FULL_NAME;
593 if ((s->change.fields & USERMOD_FIELD_DESCRIPTION) &&
594 (*level == 0 || *level == 13)) {
596 i->info13.description.string = s->change.description;
598 s->change.fields ^= USERMOD_FIELD_DESCRIPTION;
601 if ((s->change.fields & USERMOD_FIELD_COMMENT) &&
602 (*level == 0 || *level == 2)) {
605 if (s->stage == USERMOD_QUERY) {
606 /* the user info is obtained, so now set the required field */
607 i->info2.comment.string = s->change.comment;
608 s->change.fields ^= USERMOD_FIELD_COMMENT;
611 /* we need to query the user info before setting one field in it */
612 s->stage = USERMOD_QUERY;
613 return s->change.fields;
617 if ((s->change.fields & USERMOD_FIELD_LOGON_SCRIPT) &&
618 (*level == 0 || *level == 11)) {
620 i->info11.logon_script.string = s->change.logon_script;
622 s->change.fields ^= USERMOD_FIELD_LOGON_SCRIPT;
625 if ((s->change.fields & USERMOD_FIELD_PROFILE_PATH) &&
626 (*level == 0 || *level == 12)) {
628 i->info12.profile_path.string = s->change.profile_path;
630 s->change.fields ^= USERMOD_FIELD_PROFILE_PATH;
633 if ((s->change.fields & USERMOD_FIELD_HOME_DIRECTORY) &&
634 (*level == 0 || *level == 10)) {
637 if (s->stage == USERMOD_QUERY) {
638 i->info10.home_directory.string = s->change.home_directory;
639 s->change.fields ^= USERMOD_FIELD_HOME_DIRECTORY;
641 s->stage = USERMOD_QUERY;
642 return s->change.fields;
646 if ((s->change.fields & USERMOD_FIELD_HOME_DRIVE) &&
647 (*level == 0 || *level == 10)) {
650 if (s->stage == USERMOD_QUERY) {
651 i->info10.home_drive.string = s->change.home_drive;
652 s->change.fields ^= USERMOD_FIELD_HOME_DRIVE;
654 s->stage = USERMOD_QUERY;
655 return s->change.fields;
659 if ((s->change.fields & USERMOD_FIELD_ACCT_EXPIRY) &&
660 (*level == 0 || *level == 17)) {
662 i->info17.acct_expiry = timeval_to_nttime(s->change.acct_expiry);
664 s->change.fields ^= USERMOD_FIELD_ACCT_EXPIRY;
667 if ((s->change.fields & USERMOD_FIELD_ACCT_FLAGS) &&
668 (*level == 0 || *level == 16)) {
670 i->info16.acct_flags = s->change.acct_flags;
672 s->change.fields ^= USERMOD_FIELD_ACCT_FLAGS;
675 /* We're going to be here back again soon unless all fields have been set */
676 if (s->change.fields) {
677 s->stage = USERMOD_OPEN;
679 s->stage = USERMOD_MODIFY;
682 return s->change.fields;
686 static NTSTATUS usermod_change(struct composite_context *c,
687 struct usermod_state *s)
689 union samr_UserInfo *i = &s->info;
691 /* set the level to invalid value, so that unless setfields routine
692 gives it a valid value we report the error correctly */
695 /* prepare UserInfo level and data based on bitmask field */
696 s->change.fields = usermod_setfields(s, &level, i);
698 if (level < 1 || level > 26) {
699 /* apparently there's a field that the setfields routine
700 does not know how to set */
701 c->state = COMPOSITE_STATE_ERROR;
702 return NT_STATUS_INVALID_PARAMETER;
705 /* If some specific level is used to set user account data and the change
706 itself does not cover all fields then we need to query the user info
707 first, right before changing the data. Otherwise we could set required
708 fields and accidentally reset the others.
710 if (s->stage == USERMOD_QUERY) {
711 s->queryuser.in.user_handle = &s->user_handle;
712 s->queryuser.in.level = level;
714 /* send query user info request to retrieve complete data of
715 a particular info level */
716 s->req = dcerpc_samr_QueryUserInfo_send(s->pipe, c, &s->queryuser);
719 s->setuser.in.user_handle = &s->user_handle;
720 s->setuser.in.level = level;
721 s->setuser.in.info = i;
723 /* send set user info request after making required change */
724 s->req = dcerpc_samr_SetUserInfo_send(s->pipe, c, &s->setuser);
727 /* callback handler setup */
728 s->req->async.callback = usermod_handler;
729 s->req->async.private_data = c;
736 * Stage 2: Open user account
738 static NTSTATUS usermod_open(struct composite_context *c,
739 struct usermod_state *s)
741 c->status = dcerpc_ndr_request_recv(s->req);
742 NT_STATUS_NOT_OK_RETURN(c->status);
744 return usermod_change(c, s);
749 * Stage 2a (optional): Query the user information
751 static NTSTATUS usermod_query(struct composite_context *c,
752 struct usermod_state *s)
754 union samr_UserInfo *i = &s->info;
757 /* receive samr_QueryUserInfo result */
758 c->status = dcerpc_ndr_request_recv(s->req);
759 NT_STATUS_NOT_OK_RETURN(c->status);
761 /* get returned user data and make a change (potentially one
763 s->info = *s->queryuser.out.info;
765 s->change.fields = usermod_setfields(s, &level, i);
767 /* prepare rpc call arguments */
768 s->setuser.in.user_handle = &s->user_handle;
769 s->setuser.in.level = level;
770 s->setuser.in.info = i;
772 /* send the rpc request */
773 s->req = dcerpc_samr_SetUserInfo_send(s->pipe, c, &s->setuser);
775 /* callback handler setup */
776 s->req->async.callback = usermod_handler;
777 s->req->async.private_data = c;
784 * Stage 3: Set new user account data
786 static NTSTATUS usermod_modify(struct composite_context *c,
787 struct usermod_state *s)
789 /* receive samr_SetUserInfo result */
790 c->status = dcerpc_ndr_request_recv(s->req);
791 NT_STATUS_NOT_OK_RETURN(c->status);
793 /* return the actual function call status */
794 c->status = s->setuser.out.result;
796 if (s->change.fields == 0) {
797 /* all fields have been set - we're done */
798 c->state = COMPOSITE_STATE_DONE;
800 /* something's still not changed - repeat the procedure */
801 return usermod_change(c, s);
809 * Event handler for asynchronous request. Handles transition through
810 * intermediate stages of the call.
812 * @param req rpc call context
815 static void usermod_handler(struct rpc_request *req)
817 struct composite_context *c;
818 struct usermod_state *s;
819 struct monitor_msg msg;
820 struct msg_rpc_lookup_name *msg_lookup;
821 struct msg_rpc_open_user *msg_open;
823 c = talloc_get_type(req->async.private_data, struct composite_context);
824 s = talloc_get_type(c->private_data, struct usermod_state);
828 c->status = usermod_lookup(c, s);
830 if (NT_STATUS_IS_OK(c->status)) {
831 /* monitor message */
832 msg.type = rpc_lookup_name;
833 msg_lookup = talloc(s, struct msg_rpc_lookup_name);
835 msg_lookup->rid = s->lookupname.out.rids.ids;
836 msg_lookup->count = s->lookupname.out.rids.count;
837 msg.data = (void*)msg_lookup;
838 msg.data_size = sizeof(*msg_lookup);
843 c->status = usermod_open(c, s);
845 if (NT_STATUS_IS_OK(c->status)) {
846 /* monitor message */
847 msg.type = rpc_open_user;
848 msg_open = talloc(s, struct msg_rpc_open_user);
850 msg_open->rid = s->openuser.in.rid;
851 msg_open->access_mask = s->openuser.in.rid;
852 msg.data = (void*)msg_open;
853 msg.data_size = sizeof(*msg_open);
858 c->status = usermod_query(c, s);
860 if (NT_STATUS_IS_OK(c->status)) {
861 /* monitor message */
862 msg.type = rpc_query_user;
869 c->status = usermod_modify(c, s);
871 if (NT_STATUS_IS_OK(c->status)) {
872 /* monitor message */
873 msg.type = rpc_set_user;
880 /* are we ok, so far ? */
881 if (!NT_STATUS_IS_OK(c->status)) {
882 c->state = COMPOSITE_STATE_ERROR;
885 /* call monitor function provided the pointer has been passed */
890 /* are we done yet ? */
891 if (c->state >= COMPOSITE_STATE_DONE &&
899 * Sends asynchronous usermod request
901 * @param p dce/rpc call pipe
902 * @param io arguments and results of the call
903 * @param monitor monitor function for providing information about the progress
906 struct composite_context *libnet_rpc_usermod_send(struct dcerpc_pipe *p,
907 struct libnet_rpc_usermod *io,
908 void (*monitor)(struct monitor_msg*))
910 struct composite_context *c;
911 struct usermod_state *s;
913 /* composite context allocation and setup */
914 c = talloc_zero(p, struct composite_context);
915 if (c == NULL) return NULL;
917 s = talloc_zero(c, struct usermod_state);
918 if (composite_nomem(s, c)) return c;
920 c->state = COMPOSITE_STATE_IN_PROGRESS;
922 c->event_ctx = dcerpc_event_context(p);
924 /* store parameters in the call structure */
926 s->domain_handle = io->in.domain_handle;
927 s->change = io->in.change;
928 s->monitor_fn = monitor;
930 /* prepare rpc call arguments */
931 s->lookupname.in.domain_handle = &io->in.domain_handle;
932 s->lookupname.in.num_names = 1;
933 s->lookupname.in.names = talloc_zero(s, struct lsa_String);
934 s->lookupname.in.names->string = io->in.username;
936 /* send the rpc request */
937 s->req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
939 /* callback handler setup */
940 s->req->async.callback = usermod_handler;
941 s->req->async.private_data = c;
942 s->stage = USERMOD_LOOKUP;
949 * Waits for and receives results of asynchronous usermod call
951 * @param c composite context returned by asynchronous usermod call
952 * @param mem_ctx memory context of the call
953 * @param io pointer to results (and arguments) of the call
954 * @return nt status code of execution
957 NTSTATUS libnet_rpc_usermod_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
958 struct libnet_rpc_usermod *io)
962 status = composite_wait(c);
970 * Synchronous version of usermod call
972 * @param pipe dce/rpc call pipe
973 * @param mem_ctx memory context for the call
974 * @param io arguments and results of the call
975 * @return nt status code of execution
978 NTSTATUS libnet_rpc_usermod(struct dcerpc_pipe *p,
980 struct libnet_rpc_usermod *io)
982 struct composite_context *c = libnet_rpc_usermod_send(p, io, NULL);
983 return libnet_rpc_usermod_recv(c, mem_ctx, io);