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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 a composite functions for user management operations (add/del/chg)
26 #include "libcli/composite/composite.h"
27 #include "libnet/composite.h"
28 #include "libnet/userman.h"
29 #include "libnet/userinfo.h"
30 #include "librpc/gen_ndr/ndr_samr_c.h"
33 * Composite USER ADD functionality
36 static void useradd_handler(struct rpc_request
*);
38 enum useradd_stage
{ USERADD_CREATE
};
40 struct useradd_state
{
41 enum useradd_stage stage
;
42 struct dcerpc_pipe
*pipe
;
43 struct rpc_request
*req
;
44 struct policy_handle domain_handle
;
45 struct samr_CreateUser createuser
;
46 struct policy_handle user_handle
;
49 /* information about the progress */
50 void (*monitor_fn
)(struct monitor_msg
*);
55 * Stage 1 (and the only one for now): Create user account.
57 static NTSTATUS
useradd_create(struct composite_context
*c
,
58 struct useradd_state
*s
)
60 c
->status
= dcerpc_ndr_request_recv(s
->req
);
61 NT_STATUS_NOT_OK_RETURN(c
->status
);
63 c
->state
= COMPOSITE_STATE_DONE
;
69 * Event handler for asynchronous request. Handles transition through
70 * intermediate stages of the call.
72 * @param req rpc call context
74 static void useradd_handler(struct rpc_request
*req
)
76 struct composite_context
*c
= req
->async
.private;
77 struct useradd_state
*s
= talloc_get_type(c
->private_data
, struct useradd_state
);
78 struct monitor_msg msg
;
79 struct msg_rpc_create_user
*rpc_create
;
83 c
->status
= useradd_create(c
, s
);
85 /* prepare a message to pass to monitor function */
86 msg
.type
= rpc_create_user
;
87 rpc_create
= talloc(s
, struct msg_rpc_create_user
);
88 rpc_create
->rid
= *s
->createuser
.out
.rid
;
89 msg
.data
= (void*)rpc_create
;
90 msg
.data_size
= sizeof(*rpc_create
);
94 /* are we ok so far ? */
95 if (!NT_STATUS_IS_OK(c
->status
)) {
96 c
->state
= COMPOSITE_STATE_ERROR
;
99 /* call monitor function provided the pointer has been passed */
104 /* are we done yet ? */
105 if (c
->state
>= COMPOSITE_STATE_DONE
&&
113 * Sends asynchronous useradd request
115 * @param p dce/rpc call pipe
116 * @param io arguments and results of the call
117 * @param monitor monitor function for providing information about the progress
120 struct composite_context
*libnet_rpc_useradd_send(struct dcerpc_pipe
*p
,
121 struct libnet_rpc_useradd
*io
,
122 void (*monitor
)(struct monitor_msg
*))
124 struct composite_context
*c
;
125 struct useradd_state
*s
;
127 /* composite allocation and setup */
128 c
= talloc_zero(p
, struct composite_context
);
129 if (c
== NULL
) return NULL
;
131 s
= talloc_zero(c
, struct useradd_state
);
132 if (composite_nomem(s
, c
)) return c
;
134 c
->state
= COMPOSITE_STATE_IN_PROGRESS
;
136 c
->event_ctx
= dcerpc_event_context(p
);
138 /* put passed arguments to the state structure */
139 s
->domain_handle
= io
->in
.domain_handle
;
141 s
->monitor_fn
= monitor
;
143 /* preparing parameters to send rpc request */
144 s
->createuser
.in
.domain_handle
= &io
->in
.domain_handle
;
145 s
->createuser
.in
.account_name
= talloc_zero(c
, struct lsa_String
);
146 s
->createuser
.in
.account_name
->string
= talloc_strdup(c
, io
->in
.username
);
147 s
->createuser
.out
.user_handle
= &s
->user_handle
;
148 s
->createuser
.out
.rid
= &s
->user_rid
;
150 /* send the request */
151 s
->req
= dcerpc_samr_CreateUser_send(p
, c
, &s
->createuser
);
152 if (composite_nomem(s
->req
, c
)) return c
;
154 /* callback handler for continuation */
155 s
->req
->async
.callback
= useradd_handler
;
156 s
->req
->async
.private = c
;
157 s
->stage
= USERADD_CREATE
;
164 * Waits for and receives result of asynchronous useradd call
166 * @param c composite context returned by asynchronous useradd call
167 * @param mem_ctx memory context of the call
168 * @param io pointer to results (and arguments) of the call
169 * @return nt status code of execution
172 NTSTATUS
libnet_rpc_useradd_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
173 struct libnet_rpc_useradd
*io
)
176 struct useradd_state
*s
;
178 status
= composite_wait(c
);
180 if (NT_STATUS_IS_OK(status
) && io
) {
181 /* get and return result of the call */
182 s
= talloc_get_type(c
->private_data
, struct useradd_state
);
183 io
->out
.user_handle
= s
->user_handle
;
192 * Synchronous version of useradd call
194 * @param pipe dce/rpc call pipe
195 * @param mem_ctx memory context for the call
196 * @param io arguments and results of the call
197 * @return nt status code of execution
200 NTSTATUS
libnet_rpc_useradd(struct dcerpc_pipe
*p
,
202 struct libnet_rpc_useradd
*io
)
204 struct composite_context
*c
= libnet_rpc_useradd_send(p
, io
, NULL
);
205 return libnet_rpc_useradd_recv(c
, mem_ctx
, io
);
211 * Composite USER DELETE functionality
214 static void userdel_handler(struct rpc_request
*);
216 enum userdel_stage
{ USERDEL_LOOKUP
, USERDEL_OPEN
, USERDEL_DELETE
};
218 struct userdel_state
{
219 enum userdel_stage stage
;
220 struct dcerpc_pipe
*pipe
;
221 struct rpc_request
*req
;
222 struct policy_handle domain_handle
;
223 struct policy_handle user_handle
;
224 struct samr_LookupNames lookupname
;
225 struct samr_OpenUser openuser
;
226 struct samr_DeleteUser deleteuser
;
228 /* information about the progress */
229 void (*monitor_fn
)(struct monitor_msg
*);
234 * Stage 1: Lookup the user name and resolve it to rid
236 static NTSTATUS
userdel_lookup(struct composite_context
*c
,
237 struct userdel_state
*s
)
239 /* receive samr_LookupNames result */
240 c
->status
= dcerpc_ndr_request_recv(s
->req
);
241 NT_STATUS_NOT_OK_RETURN(c
->status
);
243 /* what to do when there's no user account to delete
244 and what if there's more than one rid resolved */
245 if (!s
->lookupname
.out
.rids
.count
) {
246 c
->status
= NT_STATUS_NO_SUCH_USER
;
247 composite_error(c
, c
->status
);
249 } else if (!s
->lookupname
.out
.rids
.count
> 1) {
250 c
->status
= NT_STATUS_INVALID_ACCOUNT_NAME
;
251 composite_error(c
, c
->status
);
254 /* prepare the next rpc call arguments */
255 s
->openuser
.in
.domain_handle
= &s
->domain_handle
;
256 s
->openuser
.in
.rid
= s
->lookupname
.out
.rids
.ids
[0];
257 s
->openuser
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
258 s
->openuser
.out
.user_handle
= &s
->user_handle
;
260 /* send rpc request */
261 s
->req
= dcerpc_samr_OpenUser_send(s
->pipe
, c
, &s
->openuser
);
262 if (s
->req
== NULL
) return NT_STATUS_NO_MEMORY
;
264 /* callback handler setup */
265 s
->req
->async
.callback
= userdel_handler
;
266 s
->req
->async
.private = c
;
267 s
->stage
= USERDEL_OPEN
;
274 * Stage 2: Open user account.
276 static NTSTATUS
userdel_open(struct composite_context
*c
,
277 struct userdel_state
*s
)
279 /* receive samr_OpenUser result */
280 c
->status
= dcerpc_ndr_request_recv(s
->req
);
281 NT_STATUS_NOT_OK_RETURN(c
->status
);
283 /* prepare the final rpc call arguments */
284 s
->deleteuser
.in
.user_handle
= &s
->user_handle
;
285 s
->deleteuser
.out
.user_handle
= &s
->user_handle
;
287 /* send rpc request */
288 s
->req
= dcerpc_samr_DeleteUser_send(s
->pipe
, c
, &s
->deleteuser
);
289 if (s
->req
== NULL
) return NT_STATUS_NO_MEMORY
;
291 /* callback handler setup */
292 s
->req
->async
.callback
= userdel_handler
;
293 s
->req
->async
.private = c
;
294 s
->stage
= USERDEL_DELETE
;
301 * Stage 3: Delete user account
303 static NTSTATUS
userdel_delete(struct composite_context
*c
,
304 struct userdel_state
*s
)
306 /* receive samr_DeleteUser result */
307 c
->status
= dcerpc_ndr_request_recv(s
->req
);
308 NT_STATUS_NOT_OK_RETURN(c
->status
);
310 c
->state
= COMPOSITE_STATE_DONE
;
317 * Event handler for asynchronous request. Handles transition through
318 * intermediate stages of the call.
320 * @param req rpc call context
322 static void userdel_handler(struct rpc_request
*req
)
324 struct composite_context
*c
;
325 struct userdel_state
*s
;
326 struct monitor_msg msg
;
327 struct msg_rpc_lookup_name
*msg_lookup
;
328 struct msg_rpc_open_user
*msg_open
;
330 c
= talloc_get_type(req
->async
.private, struct composite_context
);
331 s
= talloc_get_type(c
->private_data
, struct userdel_state
);
335 c
->status
= userdel_lookup(c
, s
);
337 /* monitor message */
338 msg
.type
= rpc_lookup_name
;
339 msg_lookup
= talloc(s
, struct msg_rpc_lookup_name
);
341 msg_lookup
->rid
= s
->lookupname
.out
.rids
.ids
;
342 msg_lookup
->count
= s
->lookupname
.out
.rids
.count
;
343 msg
.data
= (void*)msg_lookup
;
344 msg
.data_size
= sizeof(*msg_lookup
);
348 c
->status
= userdel_open(c
, s
);
350 /* monitor message */
351 msg
.type
= rpc_open_user
;
352 msg_open
= talloc(s
, struct msg_rpc_open_user
);
354 msg_open
->rid
= s
->openuser
.in
.rid
;
355 msg_open
->access_mask
= s
->openuser
.in
.rid
;
356 msg
.data
= (void*)msg_open
;
357 msg
.data_size
= sizeof(*msg_open
);
361 c
->status
= userdel_delete(c
, s
);
363 /* monitor message */
364 msg
.type
= rpc_delete_user
;
370 /* are we ok, so far ? */
371 if (!NT_STATUS_IS_OK(c
->status
)) {
372 c
->state
= COMPOSITE_STATE_ERROR
;
375 /* call monitor function provided the pointer has been passed */
380 /* are we done yet */
381 if (c
->state
>= COMPOSITE_STATE_DONE
&&
389 * Sends asynchronous userdel request
391 * @param p dce/rpc call pipe
392 * @param io arguments and results of the call
393 * @param monitor monitor function for providing information about the progress
396 struct composite_context
*libnet_rpc_userdel_send(struct dcerpc_pipe
*p
,
397 struct libnet_rpc_userdel
*io
,
398 void (*monitor
)(struct monitor_msg
*))
400 struct composite_context
*c
;
401 struct userdel_state
*s
;
403 /* composite context allocation and setup */
404 c
= talloc_zero(p
, struct composite_context
);
405 if (c
== NULL
) return NULL
;
407 s
= talloc_zero(c
, struct userdel_state
);
408 if (composite_nomem(s
, c
)) return c
;
410 c
->state
= COMPOSITE_STATE_IN_PROGRESS
;
412 c
->event_ctx
= dcerpc_event_context(p
);
414 /* store function parameters in the state structure */
416 s
->domain_handle
= io
->in
.domain_handle
;
417 s
->monitor_fn
= monitor
;
419 /* preparing parameters to send rpc request */
420 s
->lookupname
.in
.domain_handle
= &io
->in
.domain_handle
;
421 s
->lookupname
.in
.num_names
= 1;
422 s
->lookupname
.in
.names
= talloc_zero(s
, struct lsa_String
);
423 s
->lookupname
.in
.names
->string
= io
->in
.username
;
425 /* send the request */
426 s
->req
= dcerpc_samr_LookupNames_send(p
, c
, &s
->lookupname
);
428 /* callback handler setup */
429 s
->req
->async
.callback
= userdel_handler
;
430 s
->req
->async
.private = c
;
431 s
->stage
= USERDEL_LOOKUP
;
438 * Waits for and receives results of asynchronous userdel call
440 * @param c composite context returned by asynchronous userdel call
441 * @param mem_ctx memory context of the call
442 * @param io pointer to results (and arguments) of the call
443 * @return nt status code of execution
446 NTSTATUS
libnet_rpc_userdel_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
447 struct libnet_rpc_userdel
*io
)
450 struct userdel_state
*s
;
452 status
= composite_wait(c
);
454 if (NT_STATUS_IS_OK(status
) && io
) {
455 s
= talloc_get_type(c
->private_data
, struct userdel_state
);
456 io
->out
.user_handle
= s
->user_handle
;
465 * Synchronous version of userdel call
467 * @param pipe dce/rpc call pipe
468 * @param mem_ctx memory context for the call
469 * @param io arguments and results of the call
470 * @return nt status code of execution
473 NTSTATUS
libnet_rpc_userdel(struct dcerpc_pipe
*p
,
475 struct libnet_rpc_userdel
*io
)
477 struct composite_context
*c
= libnet_rpc_userdel_send(p
, io
, NULL
);
478 return libnet_rpc_userdel_recv(c
, mem_ctx
, io
);
483 * USER MODIFY functionality
486 static void usermod_handler(struct rpc_request
*);
488 enum usermod_stage
{ USERMOD_LOOKUP
, USERMOD_OPEN
, USERMOD_QUERY
, USERMOD_MODIFY
};
490 struct usermod_state
{
491 enum usermod_stage stage
;
492 struct dcerpc_pipe
*pipe
;
493 struct rpc_request
*req
;
494 struct policy_handle domain_handle
;
495 struct policy_handle user_handle
;
496 struct usermod_change change
;
497 union samr_UserInfo info
;
498 struct samr_LookupNames lookupname
;
499 struct samr_OpenUser openuser
;
500 struct samr_SetUserInfo setuser
;
501 struct samr_QueryUserInfo queryuser
;
503 /* information about the progress */
504 void (*monitor_fn
)(struct monitor_msg
*);
509 * Step 1: Lookup user name
511 static NTSTATUS
usermod_lookup(struct composite_context
*c
,
512 struct usermod_state
*s
)
514 /* receive samr_LookupNames result */
515 c
->status
= dcerpc_ndr_request_recv(s
->req
);
516 NT_STATUS_NOT_OK_RETURN(c
->status
);
518 /* what to do when there's no user account to delete
519 and what if there's more than one rid resolved */
520 if (!s
->lookupname
.out
.rids
.count
) {
521 c
->status
= NT_STATUS_NO_SUCH_USER
;
522 c
->state
= COMPOSITE_STATE_ERROR
;
525 } else if (!s
->lookupname
.out
.rids
.count
> 1) {
526 c
->status
= NT_STATUS_INVALID_ACCOUNT_NAME
;
527 c
->state
= COMPOSITE_STATE_ERROR
;
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 s
->req
= dcerpc_samr_OpenUser_send(s
->pipe
, c
, &s
->openuser
);
540 /* callback handler setup */
541 s
->req
->async
.callback
= usermod_handler
;
542 s
->req
->async
.private = c
;
543 s
->stage
= USERMOD_OPEN
;
550 * Choose a proper level of samr_UserInfo structure depending on required
551 * change specified by means of flags field. Subsequent calls of this
552 * function are made until there's no flags set meaning that all of the
553 * changes have been made.
555 static uint32_t usermod_setfields(struct usermod_state
*s
, uint16_t *level
,
556 union samr_UserInfo
*i
)
558 if (s
->change
.fields
== 0) return s
->change
.fields
;
562 if ((s
->change
.fields
& USERMOD_FIELD_ACCOUNT_NAME
) &&
563 (*level
== 0 || *level
== 7)) {
565 i
->info7
.account_name
.string
= s
->change
.account_name
;
567 s
->change
.fields
^= USERMOD_FIELD_ACCOUNT_NAME
;
571 if ((s
->change
.fields
& USERMOD_FIELD_FULL_NAME
) &&
572 (*level
== 0 || *level
== 8)) {
574 i
->info8
.full_name
.string
= s
->change
.full_name
;
576 s
->change
.fields
^= USERMOD_FIELD_FULL_NAME
;
579 if ((s
->change
.fields
& USERMOD_FIELD_DESCRIPTION
) &&
580 (*level
== 0 || *level
== 13)) {
582 i
->info13
.description
.string
= s
->change
.description
;
584 s
->change
.fields
^= USERMOD_FIELD_DESCRIPTION
;
588 if ((s
->change
.fields
& USERMOD_FIELD_COMMENT
) &&
589 (*level
== 0 || *level
== 2)) {
592 if (s
->stage
== USERMOD_QUERY
) {
593 /* the user info is obtained, so now set the required field */
594 i
->info2
.comment
.string
= s
->change
.comment
;
595 s
->change
.fields
^= USERMOD_FIELD_COMMENT
;
598 /* we need to query the user info before setting one field in it */
599 s
->stage
= USERMOD_QUERY
;
600 return s
->change
.fields
;
605 if ((s
->change
.fields
& USERMOD_FIELD_ALLOW_PASS_CHG
) &&
606 (*level
== 0 || *level
== 3)) {
609 if (s
->stage
== USERMOD_QUERY
) {
610 i
->info3
.allow_password_change
= timeval_to_nttime(s
->change
.allow_password_change
);
611 s
->change
.fields
^= USERMOD_FIELD_ALLOW_PASS_CHG
;
614 s
->stage
= USERMOD_QUERY
;
615 return s
->change
.fields
;
620 if ((s
->change
.fields
& USERMOD_FIELD_FORCE_PASS_CHG
) &&
621 (*level
== 0 || *level
== 3)) {
624 if (s
->stage
== USERMOD_QUERY
) {
625 i
->info3
.force_password_change
= timeval_to_nttime(s
->change
.force_password_change
);
626 s
->change
.fields
^= USERMOD_FIELD_FORCE_PASS_CHG
;
629 s
->stage
= USERMOD_QUERY
;
630 return s
->change
.fields
;
635 if ((s
->change
.fields
& USERMOD_FIELD_LAST_LOGON
) &&
636 (*level
== 0 || *level
== 3)) {
639 if (s
->stage
== USERMOD_QUERY
) {
640 i
->info3
.last_logon
= timeval_to_nttime(s
->change
.last_logon
);
641 s
->change
.fields
^= USERMOD_FIELD_LAST_LOGON
;
643 s
->stage
= USERMOD_QUERY
;
644 return s
->change
.fields
;
649 if ((s
->change
.fields
& USERMOD_FIELD_LAST_LOGOFF
) &&
650 (*level
== 0 || *level
== 3)) {
653 if (s
->stage
== USERMOD_QUERY
) {
654 i
->info3
.last_logoff
= timeval_to_nttime(s
->change
.last_logoff
);
655 s
->change
.fields
^= USERMOD_FIELD_LAST_LOGOFF
;
657 s
->stage
= USERMOD_QUERY
;
658 return s
->change
.fields
;
663 if ((s
->change
.fields
& USERMOD_FIELD_LAST_PASS_CHG
) &&
664 (*level
== 0 || *level
== 3)) {
667 if (s
->stage
== USERMOD_QUERY
) {
668 i
->info3
.last_password_change
= timeval_to_nttime(s
->change
.last_password_change
);
669 s
->change
.fields
^= USERMOD_FIELD_LAST_PASS_CHG
;
671 s
->stage
= USERMOD_QUERY
;
672 return s
->change
.fields
;
677 if ((s
->change
.fields
& USERMOD_FIELD_LOGON_SCRIPT
) &&
678 (*level
== 0 || *level
== 11)) {
680 i
->info11
.logon_script
.string
= s
->change
.logon_script
;
682 s
->change
.fields
^= USERMOD_FIELD_LOGON_SCRIPT
;
686 if ((s
->change
.fields
& USERMOD_FIELD_PROFILE_PATH
) &&
687 (*level
== 0 || *level
== 12)) {
689 i
->info12
.profile_path
.string
= s
->change
.profile_path
;
691 s
->change
.fields
^= USERMOD_FIELD_PROFILE_PATH
;
695 if ((s
->change
.fields
& USERMOD_FIELD_HOME_DIRECTORY
) &&
696 (*level
== 0 || *level
== 3)) {
699 if (s
->stage
== USERMOD_QUERY
) {
700 i
->info3
.home_directory
.string
= s
->change
.home_directory
;
701 s
->change
.fields
^= USERMOD_FIELD_HOME_DIRECTORY
;
703 s
->stage
= USERMOD_QUERY
;
704 return s
->change
.fields
;
709 if ((s
->change
.fields
& USERMOD_FIELD_HOME_DRIVE
) &&
710 (*level
== 0 || *level
== 3)) {
713 if (s
->stage
== USERMOD_QUERY
) {
714 i
->info3
.home_drive
.string
= s
->change
.home_drive
;
715 s
->change
.fields
^= USERMOD_FIELD_HOME_DRIVE
;
717 s
->stage
= USERMOD_QUERY
;
718 return s
->change
.fields
;
723 if ((s
->change
.fields
& USERMOD_FIELD_ACCT_EXPIRY
) &&
724 (*level
== 0 || *level
== 17)) {
726 i
->info17
.acct_expiry
= timeval_to_nttime(s
->change
.acct_expiry
);
728 s
->change
.fields
^= USERMOD_FIELD_ACCT_EXPIRY
;
732 if ((s
->change
.fields
& USERMOD_FIELD_ACCT_FLAGS
) &&
733 (*level
== 0 || *level
== 16)) {
735 i
->info16
.acct_flags
= s
->change
.acct_flags
;
737 s
->change
.fields
^= USERMOD_FIELD_ACCT_FLAGS
;
740 /* We're going to be here back again soon unless all fields have been set */
741 if (s
->change
.fields
) {
742 s
->stage
= USERMOD_OPEN
;
744 s
->stage
= USERMOD_MODIFY
;
747 return s
->change
.fields
;
751 static NTSTATUS
usermod_change(struct composite_context
*c
,
752 struct usermod_state
*s
)
754 union samr_UserInfo
*i
= &s
->info
;
756 /* set the level to invalid value, so that unless setfields routine
757 gives it a valid value we report the error correctly */
760 /* prepare UserInfo level and data based on bitmask field */
761 s
->change
.fields
= usermod_setfields(s
, &level
, i
);
763 if (level
< 1 || level
> 26) {
764 /* apparently there's a field that the setfields routine
765 does not know how to set */
766 c
->state
= COMPOSITE_STATE_ERROR
;
767 return NT_STATUS_INVALID_PARAMETER
;
770 /* If some specific level is used to set user account data and the change
771 itself does not cover all fields then we need to query the user info
772 first, right before changing the data. Otherwise we could set required
773 fields and accidentally reset the others.
775 if (s
->stage
== USERMOD_QUERY
) {
776 s
->queryuser
.in
.user_handle
= &s
->user_handle
;
777 s
->queryuser
.in
.level
= level
;
779 /* send query user info request to retrieve complete data of
780 a particular info level */
781 s
->req
= dcerpc_samr_QueryUserInfo_send(s
->pipe
, c
, &s
->queryuser
);
784 s
->setuser
.in
.user_handle
= &s
->user_handle
;
785 s
->setuser
.in
.level
= level
;
786 s
->setuser
.in
.info
= i
;
788 /* send set user info request after making required change */
789 s
->req
= dcerpc_samr_SetUserInfo_send(s
->pipe
, c
, &s
->setuser
);
792 /* callback handler setup */
793 s
->req
->async
.callback
= usermod_handler
;
794 s
->req
->async
.private = c
;
801 * Stage 2: Open user account
803 static NTSTATUS
usermod_open(struct composite_context
*c
,
804 struct usermod_state
*s
)
806 c
->status
= dcerpc_ndr_request_recv(s
->req
);
807 NT_STATUS_NOT_OK_RETURN(c
->status
);
809 return usermod_change(c
, s
);
814 * Stage 2a (optional): Query the user information
816 static NTSTATUS
usermod_query(struct composite_context
*c
,
817 struct usermod_state
*s
)
819 union samr_UserInfo
*i
= &s
->info
;
822 /* receive samr_QueryUserInfo result */
823 c
->status
= dcerpc_ndr_request_recv(s
->req
);
824 NT_STATUS_NOT_OK_RETURN(c
->status
);
826 /* get returned user data and make a change (potentially one
828 s
->info
= *s
->queryuser
.out
.info
;
830 s
->change
.fields
= usermod_setfields(s
, &level
, i
);
832 /* prepare rpc call arguments */
833 s
->setuser
.in
.user_handle
= &s
->user_handle
;
834 s
->setuser
.in
.level
= level
;
835 s
->setuser
.in
.info
= i
;
837 /* send the rpc request */
838 s
->req
= dcerpc_samr_SetUserInfo_send(s
->pipe
, c
, &s
->setuser
);
840 /* callback handler setup */
841 s
->req
->async
.callback
= usermod_handler
;
842 s
->req
->async
.private = c
;
849 * Stage 3: Set new user account data
851 static NTSTATUS
usermod_modify(struct composite_context
*c
,
852 struct usermod_state
*s
)
854 /* receive samr_SetUserInfo result */
855 c
->status
= dcerpc_ndr_request_recv(s
->req
);
856 NT_STATUS_NOT_OK_RETURN(c
->status
);
858 if (s
->change
.fields
== 0) {
859 /* all fields have been set - we're done */
860 c
->state
= COMPOSITE_STATE_DONE
;
862 /* something's still not changed - repeat the procedure */
863 return usermod_change(c
, s
);
871 * Event handler for asynchronous request. Handles transition through
872 * intermediate stages of the call.
874 * @param req rpc call context
877 static void usermod_handler(struct rpc_request
*req
)
879 struct composite_context
*c
;
880 struct usermod_state
*s
;
881 struct monitor_msg msg
;
882 struct msg_rpc_lookup_name
*msg_lookup
;
883 struct msg_rpc_open_user
*msg_open
;
885 c
= talloc_get_type(req
->async
.private, struct composite_context
);
886 s
= talloc_get_type(c
->private_data
, struct usermod_state
);
890 c
->status
= usermod_lookup(c
, s
);
892 if (NT_STATUS_IS_OK(c
->status
)) {
893 /* monitor message */
894 msg
.type
= rpc_lookup_name
;
895 msg_lookup
= talloc(s
, struct msg_rpc_lookup_name
);
897 msg_lookup
->rid
= s
->lookupname
.out
.rids
.ids
;
898 msg_lookup
->count
= s
->lookupname
.out
.rids
.count
;
899 msg
.data
= (void*)msg_lookup
;
900 msg
.data_size
= sizeof(*msg_lookup
);
905 c
->status
= usermod_open(c
, s
);
907 if (NT_STATUS_IS_OK(c
->status
)) {
908 /* monitor message */
909 msg
.type
= rpc_open_user
;
910 msg_open
= talloc(s
, struct msg_rpc_open_user
);
912 msg_open
->rid
= s
->openuser
.in
.rid
;
913 msg_open
->access_mask
= s
->openuser
.in
.rid
;
914 msg
.data
= (void*)msg_open
;
915 msg
.data_size
= sizeof(*msg_open
);
920 c
->status
= usermod_query(c
, s
);
922 if (NT_STATUS_IS_OK(c
->status
)) {
923 /* monitor message */
924 msg
.type
= rpc_query_user
;
931 c
->status
= usermod_modify(c
, s
);
933 if (NT_STATUS_IS_OK(c
->status
)) {
934 /* monitor message */
935 msg
.type
= rpc_set_user
;
942 /* are we ok, so far ? */
943 if (!NT_STATUS_IS_OK(c
->status
)) {
944 c
->state
= COMPOSITE_STATE_ERROR
;
947 /* call monitor function provided the pointer has been passed */
952 /* are we done yet ? */
953 if (c
->state
>= COMPOSITE_STATE_DONE
&&
961 * Sends asynchronous usermod request
963 * @param p dce/rpc call pipe
964 * @param io arguments and results of the call
965 * @param monitor monitor function for providing information about the progress
968 struct composite_context
*libnet_rpc_usermod_send(struct dcerpc_pipe
*p
,
969 struct libnet_rpc_usermod
*io
,
970 void (*monitor
)(struct monitor_msg
*))
972 struct composite_context
*c
;
973 struct usermod_state
*s
;
975 /* composite context allocation and setup */
976 c
= talloc_zero(p
, struct composite_context
);
977 if (c
== NULL
) return NULL
;
979 s
= talloc_zero(c
, struct usermod_state
);
980 if (composite_nomem(s
, c
)) return c
;
982 c
->state
= COMPOSITE_STATE_IN_PROGRESS
;
984 c
->event_ctx
= dcerpc_event_context(p
);
986 /* store parameters in the call structure */
988 s
->domain_handle
= io
->in
.domain_handle
;
989 s
->change
= io
->in
.change
;
990 s
->monitor_fn
= monitor
;
992 /* prepare rpc call arguments */
993 s
->lookupname
.in
.domain_handle
= &io
->in
.domain_handle
;
994 s
->lookupname
.in
.num_names
= 1;
995 s
->lookupname
.in
.names
= talloc_zero(s
, struct lsa_String
);
996 s
->lookupname
.in
.names
->string
= io
->in
.username
;
998 /* send the rpc request */
999 s
->req
= dcerpc_samr_LookupNames_send(p
, c
, &s
->lookupname
);
1001 /* callback handler setup */
1002 s
->req
->async
.callback
= usermod_handler
;
1003 s
->req
->async
.private = c
;
1004 s
->stage
= USERMOD_LOOKUP
;
1011 * Waits for and receives results of asynchronous usermod call
1013 * @param c composite context returned by asynchronous usermod call
1014 * @param mem_ctx memory context of the call
1015 * @param io pointer to results (and arguments) of the call
1016 * @return nt status code of execution
1019 NTSTATUS
libnet_rpc_usermod_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
1020 struct libnet_rpc_usermod
*io
)
1024 status
= composite_wait(c
);
1032 * Synchronous version of usermod call
1034 * @param pipe dce/rpc call pipe
1035 * @param mem_ctx memory context for the call
1036 * @param io arguments and results of the call
1037 * @return nt status code of execution
1040 NTSTATUS
libnet_rpc_usermod(struct dcerpc_pipe
*p
,
1041 TALLOC_CTX
*mem_ctx
,
1042 struct libnet_rpc_usermod
*io
)
1044 struct composite_context
*c
= libnet_rpc_usermod_send(p
, io
, NULL
);
1045 return libnet_rpc_usermod_recv(c
, mem_ctx
, io
);