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/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
;
40 /* information about the progress */
41 void (*monitor_fn
)(struct monitor_msg
*);
45 static void continue_useradd_create(struct tevent_req
*subreq
);
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
);
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 */
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
);
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
,
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
;
117 /* put passed arguments to the state structure */
118 s
->domain_handle
= io
->in
.domain_handle
;
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
,
138 if (composite_nomem(subreq
, c
)) return c
;
140 tevent_req_set_callback(subreq
, continue_useradd_create
, 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
)
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
;
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
,
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
);
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
);
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
) {
241 c
->status
= NT_STATUS_NO_SUCH_USER
;
242 composite_error(c
, c
->status
);
245 } else if (!s
->lookupname
.out
.rids
->count
> 1) {
246 c
->status
= NT_STATUS_INVALID_ACCOUNT_NAME
;
247 composite_error(c
, c
->status
);
251 /* issue a monitor message */
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
);
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
->pipe
->binding_handle
,
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
);
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
);
303 /* issue a monitor message */
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
);
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
->pipe
->binding_handle
,
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
);
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
);
355 /* issue a monitor message */
357 msg
.type
= mon_SamrDeleteUser
;
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(struct dcerpc_pipe
*p
,
377 struct libnet_rpc_userdel
*io
,
378 void (*monitor
)(struct monitor_msg
*))
380 struct composite_context
*c
;
381 struct userdel_state
*s
;
382 struct tevent_req
*subreq
;
384 /* composite context allocation and setup */
385 c
= composite_create(mem_ctx
, dcerpc_event_context(p
));
386 if (c
== NULL
) return NULL
;
388 s
= talloc_zero(c
, struct userdel_state
);
389 if (composite_nomem(s
, c
)) return c
;
393 /* store function parameters in the state structure */
395 s
->domain_handle
= io
->in
.domain_handle
;
396 s
->monitor_fn
= monitor
;
398 /* preparing parameters to send rpc request */
399 s
->lookupname
.in
.domain_handle
= &io
->in
.domain_handle
;
400 s
->lookupname
.in
.num_names
= 1;
401 s
->lookupname
.in
.names
= talloc_zero(s
, struct lsa_String
);
402 s
->lookupname
.in
.names
->string
= io
->in
.username
;
403 s
->lookupname
.out
.rids
= talloc_zero(s
, struct samr_Ids
);
404 s
->lookupname
.out
.types
= talloc_zero(s
, struct samr_Ids
);
405 if (composite_nomem(s
->lookupname
.out
.rids
, c
)) return c
;
406 if (composite_nomem(s
->lookupname
.out
.types
, c
)) return c
;
408 /* send the request */
409 subreq
= dcerpc_samr_LookupNames_r_send(s
, c
->event_ctx
,
412 if (composite_nomem(subreq
, c
)) return c
;
414 /* set the next stage */
415 tevent_req_set_callback(subreq
, continue_userdel_name_found
, c
);
421 * Waits for and receives results of asynchronous userdel call
423 * @param c composite context returned by asynchronous userdel call
424 * @param mem_ctx memory context of the call
425 * @param io pointer to results (and arguments) of the call
426 * @return nt status code of execution
429 NTSTATUS
libnet_rpc_userdel_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
430 struct libnet_rpc_userdel
*io
)
433 struct userdel_state
*s
;
435 status
= composite_wait(c
);
437 if (NT_STATUS_IS_OK(status
) && io
) {
438 s
= talloc_get_type(c
->private_data
, struct userdel_state
);
439 io
->out
.user_handle
= s
->user_handle
;
448 * Synchronous version of userdel call
450 * @param pipe dce/rpc call pipe
451 * @param mem_ctx memory context for the call
452 * @param io arguments and results of the call
453 * @return nt status code of execution
456 NTSTATUS
libnet_rpc_userdel(struct dcerpc_pipe
*p
,
458 struct libnet_rpc_userdel
*io
)
460 struct composite_context
*c
= libnet_rpc_userdel_send(p
, mem_ctx
, io
, NULL
);
461 return libnet_rpc_userdel_recv(c
, mem_ctx
, io
);
466 * USER MODIFY functionality
469 static void continue_usermod_name_found(struct tevent_req
*subreq
);
470 static void continue_usermod_user_opened(struct tevent_req
*subreq
);
471 static void continue_usermod_user_queried(struct tevent_req
*subreq
);
472 static void continue_usermod_user_changed(struct tevent_req
*subreq
);
475 struct usermod_state
{
476 struct dcerpc_pipe
*pipe
;
477 struct policy_handle domain_handle
;
478 struct policy_handle user_handle
;
479 struct usermod_change change
;
480 union samr_UserInfo info
;
481 struct samr_LookupNames lookupname
;
482 struct samr_OpenUser openuser
;
483 struct samr_SetUserInfo setuser
;
484 struct samr_QueryUserInfo queryuser
;
486 /* information about the progress */
487 void (*monitor_fn
)(struct monitor_msg
*);
492 * Step 1: Lookup user name
494 static void continue_usermod_name_found(struct tevent_req
*subreq
)
496 struct composite_context
*c
;
497 struct usermod_state
*s
;
498 struct monitor_msg msg
;
500 c
= tevent_req_callback_data(subreq
, struct composite_context
);
501 s
= talloc_get_type(c
->private_data
, struct usermod_state
);
503 /* receive samr_LookupNames result */
504 c
->status
= dcerpc_samr_LookupNames_r_recv(subreq
, s
);
506 if (!composite_is_ok(c
)) return;
508 c
->status
= s
->lookupname
.out
.result
;
509 if (!NT_STATUS_IS_OK(c
->status
)) {
510 composite_error(c
, c
->status
);
514 /* what to do when there's no user account to delete
515 and what if there's more than one rid resolved */
516 if (!s
->lookupname
.out
.rids
->count
) {
517 c
->status
= NT_STATUS_NO_SUCH_USER
;
518 composite_error(c
, c
->status
);
521 } else if (!s
->lookupname
.out
.rids
->count
> 1) {
522 c
->status
= NT_STATUS_INVALID_ACCOUNT_NAME
;
523 composite_error(c
, c
->status
);
527 /* issue a monitor message */
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
);
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
->pipe
->binding_handle
,
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
;
569 if ((s
->change
.fields
& USERMOD_FIELD_ACCOUNT_NAME
) &&
570 (*level
== 0 || *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)) {
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)) {
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)) {
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
;
603 /* we need to query the user info before setting one field in it */
608 if ((s
->change
.fields
& USERMOD_FIELD_LOGON_SCRIPT
) &&
609 (*level
== 0 || *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)) {
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)) {
629 i
->info10
.home_directory
.string
= s
->change
.home_directory
;
630 s
->change
.fields
^= USERMOD_FIELD_HOME_DIRECTORY
;
636 if ((s
->change
.fields
& USERMOD_FIELD_HOME_DRIVE
) &&
637 (*level
== 0 || *level
== 10)) {
641 i
->info10
.home_drive
.string
= s
->change
.home_drive
;
642 s
->change
.fields
^= USERMOD_FIELD_HOME_DRIVE
;
648 if ((s
->change
.fields
& USERMOD_FIELD_ACCT_EXPIRY
) &&
649 (*level
== 0 || *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)) {
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 */
669 static NTSTATUS
usermod_change(struct composite_context
*c
,
670 struct usermod_state
*s
)
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 */
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.
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
->pipe
->binding_handle
,
706 if (composite_nomem(subreq
, c
)) return NT_STATUS_NO_MEMORY
;
707 tevent_req_set_callback(subreq
, continue_usermod_user_queried
, c
);
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
->pipe
->binding_handle
,
718 if (composite_nomem(subreq
, c
)) return NT_STATUS_NO_MEMORY
;
719 tevent_req_set_callback(subreq
, continue_usermod_user_changed
, c
);
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
);
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
);
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
;
761 c
= tevent_req_callback_data(subreq
, struct composite_context
);
762 s
= talloc_get_type(c
->private_data
, struct usermod_state
);
766 /* receive samr_QueryUserInfo result */
767 c
->status
= dcerpc_samr_QueryUserInfo_r_recv(subreq
, s
);
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
);
777 /* get returned user data and make a change (potentially one
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
->pipe
->binding_handle
,
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
);
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
);
820 if (s
->change
.fields
== 0) {
821 /* all fields have been set - we're done */
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(struct dcerpc_pipe
*p
,
841 struct libnet_rpc_usermod
*io
,
842 void (*monitor
)(struct monitor_msg
*))
844 struct composite_context
*c
;
845 struct usermod_state
*s
;
846 struct tevent_req
*subreq
;
848 /* composite context allocation and setup */
849 c
= composite_create(mem_ctx
, dcerpc_event_context(p
));
850 if (c
== NULL
) return NULL
;
851 s
= talloc_zero(c
, struct usermod_state
);
852 if (composite_nomem(s
, c
)) return c
;
856 /* store parameters in the call structure */
858 s
->domain_handle
= io
->in
.domain_handle
;
859 s
->change
= io
->in
.change
;
860 s
->monitor_fn
= monitor
;
862 /* prepare rpc call arguments */
863 s
->lookupname
.in
.domain_handle
= &io
->in
.domain_handle
;
864 s
->lookupname
.in
.num_names
= 1;
865 s
->lookupname
.in
.names
= talloc_zero(s
, struct lsa_String
);
866 s
->lookupname
.in
.names
->string
= io
->in
.username
;
867 s
->lookupname
.out
.rids
= talloc_zero(s
, struct samr_Ids
);
868 s
->lookupname
.out
.types
= talloc_zero(s
, struct samr_Ids
);
869 if (composite_nomem(s
->lookupname
.out
.rids
, c
)) return c
;
870 if (composite_nomem(s
->lookupname
.out
.types
, c
)) return c
;
872 /* send the rpc request */
873 subreq
= dcerpc_samr_LookupNames_r_send(s
, c
->event_ctx
,
876 if (composite_nomem(subreq
, c
)) return c
;
878 /* callback handler setup */
879 tevent_req_set_callback(subreq
, continue_usermod_name_found
, c
);
885 * Waits for and receives results of asynchronous usermod call
887 * @param c composite context returned by asynchronous usermod call
888 * @param mem_ctx memory context of the call
889 * @param io pointer to results (and arguments) of the call
890 * @return nt status code of execution
893 NTSTATUS
libnet_rpc_usermod_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
894 struct libnet_rpc_usermod
*io
)
898 status
= composite_wait(c
);
906 * Synchronous version of usermod call
908 * @param pipe dce/rpc call pipe
909 * @param mem_ctx memory context for the call
910 * @param io arguments and results of the call
911 * @return nt status code of execution
914 NTSTATUS
libnet_rpc_usermod(struct dcerpc_pipe
*p
,
916 struct libnet_rpc_usermod
*io
)
918 struct composite_context
*c
= libnet_rpc_usermod_send(p
, mem_ctx
, io
, NULL
);
919 return libnet_rpc_usermod_recv(c
, mem_ctx
, io
);