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 /* return the actual function call status */
64 c
->status
= s
->createuser
.out
.result
;
66 c
->state
= COMPOSITE_STATE_DONE
;
72 * Event handler for asynchronous request. Handles transition through
73 * intermediate stages of the call.
75 * @param req rpc call context
77 static void useradd_handler(struct rpc_request
*req
)
79 struct composite_context
*c
= req
->async
.private;
80 struct useradd_state
*s
= talloc_get_type(c
->private_data
, struct useradd_state
);
81 struct monitor_msg msg
;
82 struct msg_rpc_create_user
*rpc_create
;
86 c
->status
= useradd_create(c
, s
);
88 /* prepare a message to pass to monitor function */
89 msg
.type
= rpc_create_user
;
90 rpc_create
= talloc(s
, struct msg_rpc_create_user
);
91 rpc_create
->rid
= *s
->createuser
.out
.rid
;
92 msg
.data
= (void*)rpc_create
;
93 msg
.data_size
= sizeof(*rpc_create
);
97 /* are we ok so far ? */
98 if (!NT_STATUS_IS_OK(c
->status
)) {
99 c
->state
= COMPOSITE_STATE_ERROR
;
102 /* call monitor function provided the pointer has been passed */
107 /* are we done yet ? */
108 if (c
->state
>= COMPOSITE_STATE_DONE
&&
116 * Sends asynchronous useradd request
118 * @param p dce/rpc call pipe
119 * @param io arguments and results of the call
120 * @param monitor monitor function for providing information about the progress
123 struct composite_context
*libnet_rpc_useradd_send(struct dcerpc_pipe
*p
,
124 struct libnet_rpc_useradd
*io
,
125 void (*monitor
)(struct monitor_msg
*))
127 struct composite_context
*c
;
128 struct useradd_state
*s
;
130 /* composite allocation and setup */
131 c
= talloc_zero(p
, struct composite_context
);
132 if (c
== NULL
) return NULL
;
134 s
= talloc_zero(c
, struct useradd_state
);
135 if (composite_nomem(s
, c
)) return c
;
137 c
->state
= COMPOSITE_STATE_IN_PROGRESS
;
139 c
->event_ctx
= dcerpc_event_context(p
);
141 /* put passed arguments to the state structure */
142 s
->domain_handle
= io
->in
.domain_handle
;
144 s
->monitor_fn
= monitor
;
146 /* preparing parameters to send rpc request */
147 s
->createuser
.in
.domain_handle
= &io
->in
.domain_handle
;
148 s
->createuser
.in
.account_name
= talloc_zero(c
, struct lsa_String
);
149 s
->createuser
.in
.account_name
->string
= talloc_strdup(c
, io
->in
.username
);
150 s
->createuser
.out
.user_handle
= &s
->user_handle
;
151 s
->createuser
.out
.rid
= &s
->user_rid
;
153 /* send the request */
154 s
->req
= dcerpc_samr_CreateUser_send(p
, c
, &s
->createuser
);
155 if (composite_nomem(s
->req
, c
)) return c
;
157 /* callback handler for continuation */
158 s
->req
->async
.callback
= useradd_handler
;
159 s
->req
->async
.private = c
;
160 s
->stage
= USERADD_CREATE
;
167 * Waits for and receives result of asynchronous useradd call
169 * @param c composite context returned by asynchronous useradd call
170 * @param mem_ctx memory context of the call
171 * @param io pointer to results (and arguments) of the call
172 * @return nt status code of execution
175 NTSTATUS
libnet_rpc_useradd_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
176 struct libnet_rpc_useradd
*io
)
179 struct useradd_state
*s
;
181 status
= composite_wait(c
);
183 if (NT_STATUS_IS_OK(status
) && io
) {
184 /* get and return result of the call */
185 s
= talloc_get_type(c
->private_data
, struct useradd_state
);
186 io
->out
.user_handle
= s
->user_handle
;
195 * Synchronous version of useradd call
197 * @param pipe dce/rpc call pipe
198 * @param mem_ctx memory context for the call
199 * @param io arguments and results of the call
200 * @return nt status code of execution
203 NTSTATUS
libnet_rpc_useradd(struct dcerpc_pipe
*p
,
205 struct libnet_rpc_useradd
*io
)
207 struct composite_context
*c
= libnet_rpc_useradd_send(p
, io
, NULL
);
208 return libnet_rpc_useradd_recv(c
, mem_ctx
, io
);
214 * Composite USER DELETE functionality
217 static void userdel_handler(struct rpc_request
*);
219 enum userdel_stage
{ USERDEL_LOOKUP
, USERDEL_OPEN
, USERDEL_DELETE
};
221 struct userdel_state
{
222 enum userdel_stage stage
;
223 struct dcerpc_pipe
*pipe
;
224 struct rpc_request
*req
;
225 struct policy_handle domain_handle
;
226 struct policy_handle user_handle
;
227 struct samr_LookupNames lookupname
;
228 struct samr_OpenUser openuser
;
229 struct samr_DeleteUser deleteuser
;
231 /* information about the progress */
232 void (*monitor_fn
)(struct monitor_msg
*);
237 * Stage 1: Lookup the user name and resolve it to rid
239 static NTSTATUS
userdel_lookup(struct composite_context
*c
,
240 struct userdel_state
*s
)
242 /* receive samr_LookupNames result */
243 c
->status
= dcerpc_ndr_request_recv(s
->req
);
244 NT_STATUS_NOT_OK_RETURN(c
->status
);
246 /* what to do when there's no user account to delete
247 and what if there's more than one rid resolved */
248 if (!s
->lookupname
.out
.rids
.count
) {
249 c
->status
= NT_STATUS_NO_SUCH_USER
;
250 composite_error(c
, c
->status
);
252 } else if (!s
->lookupname
.out
.rids
.count
> 1) {
253 c
->status
= NT_STATUS_INVALID_ACCOUNT_NAME
;
254 composite_error(c
, c
->status
);
257 /* prepare the next rpc call arguments */
258 s
->openuser
.in
.domain_handle
= &s
->domain_handle
;
259 s
->openuser
.in
.rid
= s
->lookupname
.out
.rids
.ids
[0];
260 s
->openuser
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
261 s
->openuser
.out
.user_handle
= &s
->user_handle
;
263 /* send rpc request */
264 s
->req
= dcerpc_samr_OpenUser_send(s
->pipe
, c
, &s
->openuser
);
265 if (s
->req
== NULL
) return NT_STATUS_NO_MEMORY
;
267 /* callback handler setup */
268 s
->req
->async
.callback
= userdel_handler
;
269 s
->req
->async
.private = c
;
270 s
->stage
= USERDEL_OPEN
;
277 * Stage 2: Open user account.
279 static NTSTATUS
userdel_open(struct composite_context
*c
,
280 struct userdel_state
*s
)
282 /* receive samr_OpenUser result */
283 c
->status
= dcerpc_ndr_request_recv(s
->req
);
284 NT_STATUS_NOT_OK_RETURN(c
->status
);
286 /* prepare the final rpc call arguments */
287 s
->deleteuser
.in
.user_handle
= &s
->user_handle
;
288 s
->deleteuser
.out
.user_handle
= &s
->user_handle
;
290 /* send rpc request */
291 s
->req
= dcerpc_samr_DeleteUser_send(s
->pipe
, c
, &s
->deleteuser
);
292 if (s
->req
== NULL
) return NT_STATUS_NO_MEMORY
;
294 /* callback handler setup */
295 s
->req
->async
.callback
= userdel_handler
;
296 s
->req
->async
.private = c
;
297 s
->stage
= USERDEL_DELETE
;
304 * Stage 3: Delete user account
306 static NTSTATUS
userdel_delete(struct composite_context
*c
,
307 struct userdel_state
*s
)
309 /* receive samr_DeleteUser result */
310 c
->status
= dcerpc_ndr_request_recv(s
->req
);
311 NT_STATUS_NOT_OK_RETURN(c
->status
);
313 /* return the actual function call status */
314 c
->status
= s
->deleteuser
.out
.result
;
316 c
->state
= COMPOSITE_STATE_DONE
;
323 * Event handler for asynchronous request. Handles transition through
324 * intermediate stages of the call.
326 * @param req rpc call context
328 static void userdel_handler(struct rpc_request
*req
)
330 struct composite_context
*c
;
331 struct userdel_state
*s
;
332 struct monitor_msg msg
;
333 struct msg_rpc_lookup_name
*msg_lookup
;
334 struct msg_rpc_open_user
*msg_open
;
336 c
= talloc_get_type(req
->async
.private, struct composite_context
);
337 s
= talloc_get_type(c
->private_data
, struct userdel_state
);
341 c
->status
= userdel_lookup(c
, s
);
343 /* monitor message */
344 msg
.type
= rpc_lookup_name
;
345 msg_lookup
= talloc(s
, struct msg_rpc_lookup_name
);
347 msg_lookup
->rid
= s
->lookupname
.out
.rids
.ids
;
348 msg_lookup
->count
= s
->lookupname
.out
.rids
.count
;
349 msg
.data
= (void*)msg_lookup
;
350 msg
.data_size
= sizeof(*msg_lookup
);
354 c
->status
= userdel_open(c
, s
);
356 /* monitor message */
357 msg
.type
= rpc_open_user
;
358 msg_open
= talloc(s
, struct msg_rpc_open_user
);
360 msg_open
->rid
= s
->openuser
.in
.rid
;
361 msg_open
->access_mask
= s
->openuser
.in
.rid
;
362 msg
.data
= (void*)msg_open
;
363 msg
.data_size
= sizeof(*msg_open
);
367 c
->status
= userdel_delete(c
, s
);
369 /* monitor message */
370 msg
.type
= rpc_delete_user
;
376 /* are we ok, so far ? */
377 if (!NT_STATUS_IS_OK(c
->status
)) {
378 c
->state
= COMPOSITE_STATE_ERROR
;
381 /* call monitor function provided the pointer has been passed */
386 /* are we done yet */
387 if (c
->state
>= COMPOSITE_STATE_DONE
&&
395 * Sends asynchronous userdel request
397 * @param p dce/rpc call pipe
398 * @param io arguments and results of the call
399 * @param monitor monitor function for providing information about the progress
402 struct composite_context
*libnet_rpc_userdel_send(struct dcerpc_pipe
*p
,
403 struct libnet_rpc_userdel
*io
,
404 void (*monitor
)(struct monitor_msg
*))
406 struct composite_context
*c
;
407 struct userdel_state
*s
;
409 /* composite context allocation and setup */
410 c
= talloc_zero(p
, struct composite_context
);
411 if (c
== NULL
) return NULL
;
413 s
= talloc_zero(c
, struct userdel_state
);
414 if (composite_nomem(s
, c
)) return c
;
416 c
->state
= COMPOSITE_STATE_IN_PROGRESS
;
418 c
->event_ctx
= dcerpc_event_context(p
);
420 /* store function parameters in the state structure */
422 s
->domain_handle
= io
->in
.domain_handle
;
423 s
->monitor_fn
= monitor
;
425 /* preparing parameters to send rpc request */
426 s
->lookupname
.in
.domain_handle
= &io
->in
.domain_handle
;
427 s
->lookupname
.in
.num_names
= 1;
428 s
->lookupname
.in
.names
= talloc_zero(s
, struct lsa_String
);
429 s
->lookupname
.in
.names
->string
= io
->in
.username
;
431 /* send the request */
432 s
->req
= dcerpc_samr_LookupNames_send(p
, c
, &s
->lookupname
);
434 /* callback handler setup */
435 s
->req
->async
.callback
= userdel_handler
;
436 s
->req
->async
.private = c
;
437 s
->stage
= USERDEL_LOOKUP
;
444 * Waits for and receives results of asynchronous userdel call
446 * @param c composite context returned by asynchronous userdel call
447 * @param mem_ctx memory context of the call
448 * @param io pointer to results (and arguments) of the call
449 * @return nt status code of execution
452 NTSTATUS
libnet_rpc_userdel_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
453 struct libnet_rpc_userdel
*io
)
456 struct userdel_state
*s
;
458 status
= composite_wait(c
);
460 if (NT_STATUS_IS_OK(status
) && io
) {
461 s
= talloc_get_type(c
->private_data
, struct userdel_state
);
462 io
->out
.user_handle
= s
->user_handle
;
471 * Synchronous version of userdel call
473 * @param pipe dce/rpc call pipe
474 * @param mem_ctx memory context for the call
475 * @param io arguments and results of the call
476 * @return nt status code of execution
479 NTSTATUS
libnet_rpc_userdel(struct dcerpc_pipe
*p
,
481 struct libnet_rpc_userdel
*io
)
483 struct composite_context
*c
= libnet_rpc_userdel_send(p
, io
, NULL
);
484 return libnet_rpc_userdel_recv(c
, mem_ctx
, io
);
489 * USER MODIFY functionality
492 static void usermod_handler(struct rpc_request
*);
494 enum usermod_stage
{ USERMOD_LOOKUP
, USERMOD_OPEN
, USERMOD_QUERY
, USERMOD_MODIFY
};
496 struct usermod_state
{
497 enum usermod_stage stage
;
498 struct dcerpc_pipe
*pipe
;
499 struct rpc_request
*req
;
500 struct policy_handle domain_handle
;
501 struct policy_handle user_handle
;
502 struct usermod_change change
;
503 union samr_UserInfo info
;
504 struct samr_LookupNames lookupname
;
505 struct samr_OpenUser openuser
;
506 struct samr_SetUserInfo setuser
;
507 struct samr_QueryUserInfo queryuser
;
509 /* information about the progress */
510 void (*monitor_fn
)(struct monitor_msg
*);
515 * Step 1: Lookup user name
517 static NTSTATUS
usermod_lookup(struct composite_context
*c
,
518 struct usermod_state
*s
)
520 /* receive samr_LookupNames result */
521 c
->status
= dcerpc_ndr_request_recv(s
->req
);
522 NT_STATUS_NOT_OK_RETURN(c
->status
);
524 /* what to do when there's no user account to delete
525 and what if there's more than one rid resolved */
526 if (!s
->lookupname
.out
.rids
.count
) {
527 c
->status
= NT_STATUS_NO_SUCH_USER
;
528 c
->state
= COMPOSITE_STATE_ERROR
;
531 } else if (!s
->lookupname
.out
.rids
.count
> 1) {
532 c
->status
= NT_STATUS_INVALID_ACCOUNT_NAME
;
533 c
->state
= COMPOSITE_STATE_ERROR
;
537 /* prepare the next rpc call */
538 s
->openuser
.in
.domain_handle
= &s
->domain_handle
;
539 s
->openuser
.in
.rid
= s
->lookupname
.out
.rids
.ids
[0];
540 s
->openuser
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
541 s
->openuser
.out
.user_handle
= &s
->user_handle
;
543 /* send the rpc request */
544 s
->req
= dcerpc_samr_OpenUser_send(s
->pipe
, c
, &s
->openuser
);
546 /* callback handler setup */
547 s
->req
->async
.callback
= usermod_handler
;
548 s
->req
->async
.private = c
;
549 s
->stage
= USERMOD_OPEN
;
556 * Choose a proper level of samr_UserInfo structure depending on required
557 * change specified by means of flags field. Subsequent calls of this
558 * function are made until there's no flags set meaning that all of the
559 * changes have been made.
561 static uint32_t usermod_setfields(struct usermod_state
*s
, uint16_t *level
,
562 union samr_UserInfo
*i
)
564 if (s
->change
.fields
== 0) return s
->change
.fields
;
568 if ((s
->change
.fields
& USERMOD_FIELD_ACCOUNT_NAME
) &&
569 (*level
== 0 || *level
== 7)) {
571 i
->info7
.account_name
.string
= s
->change
.account_name
;
573 s
->change
.fields
^= USERMOD_FIELD_ACCOUNT_NAME
;
576 if ((s
->change
.fields
& USERMOD_FIELD_FULL_NAME
) &&
577 (*level
== 0 || *level
== 8)) {
579 i
->info8
.full_name
.string
= s
->change
.full_name
;
581 s
->change
.fields
^= USERMOD_FIELD_FULL_NAME
;
584 if ((s
->change
.fields
& USERMOD_FIELD_DESCRIPTION
) &&
585 (*level
== 0 || *level
== 13)) {
587 i
->info13
.description
.string
= s
->change
.description
;
589 s
->change
.fields
^= USERMOD_FIELD_DESCRIPTION
;
592 if ((s
->change
.fields
& USERMOD_FIELD_COMMENT
) &&
593 (*level
== 0 || *level
== 2)) {
596 if (s
->stage
== USERMOD_QUERY
) {
597 /* the user info is obtained, so now set the required field */
598 i
->info2
.comment
.string
= s
->change
.comment
;
599 s
->change
.fields
^= USERMOD_FIELD_COMMENT
;
602 /* we need to query the user info before setting one field in it */
603 s
->stage
= USERMOD_QUERY
;
604 return s
->change
.fields
;
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)) {
628 if (s
->stage
== USERMOD_QUERY
) {
629 i
->info10
.home_directory
.string
= s
->change
.home_directory
;
630 s
->change
.fields
^= USERMOD_FIELD_HOME_DIRECTORY
;
632 s
->stage
= USERMOD_QUERY
;
633 return s
->change
.fields
;
637 if ((s
->change
.fields
& USERMOD_FIELD_HOME_DRIVE
) &&
638 (*level
== 0 || *level
== 10)) {
641 if (s
->stage
== USERMOD_QUERY
) {
642 i
->info10
.home_drive
.string
= s
->change
.home_drive
;
643 s
->change
.fields
^= USERMOD_FIELD_HOME_DRIVE
;
645 s
->stage
= USERMOD_QUERY
;
646 return s
->change
.fields
;
650 if ((s
->change
.fields
& USERMOD_FIELD_ACCT_EXPIRY
) &&
651 (*level
== 0 || *level
== 17)) {
653 i
->info17
.acct_expiry
= timeval_to_nttime(s
->change
.acct_expiry
);
655 s
->change
.fields
^= USERMOD_FIELD_ACCT_EXPIRY
;
658 if ((s
->change
.fields
& USERMOD_FIELD_ACCT_FLAGS
) &&
659 (*level
== 0 || *level
== 16)) {
661 i
->info16
.acct_flags
= s
->change
.acct_flags
;
663 s
->change
.fields
^= USERMOD_FIELD_ACCT_FLAGS
;
666 /* We're going to be here back again soon unless all fields have been set */
667 if (s
->change
.fields
) {
668 s
->stage
= USERMOD_OPEN
;
670 s
->stage
= USERMOD_MODIFY
;
673 return s
->change
.fields
;
677 static NTSTATUS
usermod_change(struct composite_context
*c
,
678 struct usermod_state
*s
)
680 union samr_UserInfo
*i
= &s
->info
;
682 /* set the level to invalid value, so that unless setfields routine
683 gives it a valid value we report the error correctly */
686 /* prepare UserInfo level and data based on bitmask field */
687 s
->change
.fields
= usermod_setfields(s
, &level
, i
);
689 if (level
< 1 || level
> 26) {
690 /* apparently there's a field that the setfields routine
691 does not know how to set */
692 c
->state
= COMPOSITE_STATE_ERROR
;
693 return NT_STATUS_INVALID_PARAMETER
;
696 /* If some specific level is used to set user account data and the change
697 itself does not cover all fields then we need to query the user info
698 first, right before changing the data. Otherwise we could set required
699 fields and accidentally reset the others.
701 if (s
->stage
== USERMOD_QUERY
) {
702 s
->queryuser
.in
.user_handle
= &s
->user_handle
;
703 s
->queryuser
.in
.level
= level
;
705 /* send query user info request to retrieve complete data of
706 a particular info level */
707 s
->req
= dcerpc_samr_QueryUserInfo_send(s
->pipe
, c
, &s
->queryuser
);
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 s
->req
= dcerpc_samr_SetUserInfo_send(s
->pipe
, c
, &s
->setuser
);
718 /* callback handler setup */
719 s
->req
->async
.callback
= usermod_handler
;
720 s
->req
->async
.private = c
;
727 * Stage 2: Open user account
729 static NTSTATUS
usermod_open(struct composite_context
*c
,
730 struct usermod_state
*s
)
732 c
->status
= dcerpc_ndr_request_recv(s
->req
);
733 NT_STATUS_NOT_OK_RETURN(c
->status
);
735 return usermod_change(c
, s
);
740 * Stage 2a (optional): Query the user information
742 static NTSTATUS
usermod_query(struct composite_context
*c
,
743 struct usermod_state
*s
)
745 union samr_UserInfo
*i
= &s
->info
;
748 /* receive samr_QueryUserInfo result */
749 c
->status
= dcerpc_ndr_request_recv(s
->req
);
750 NT_STATUS_NOT_OK_RETURN(c
->status
);
752 /* get returned user data and make a change (potentially one
754 s
->info
= *s
->queryuser
.out
.info
;
756 s
->change
.fields
= usermod_setfields(s
, &level
, i
);
758 /* prepare rpc call arguments */
759 s
->setuser
.in
.user_handle
= &s
->user_handle
;
760 s
->setuser
.in
.level
= level
;
761 s
->setuser
.in
.info
= i
;
763 /* send the rpc request */
764 s
->req
= dcerpc_samr_SetUserInfo_send(s
->pipe
, c
, &s
->setuser
);
766 /* callback handler setup */
767 s
->req
->async
.callback
= usermod_handler
;
768 s
->req
->async
.private = c
;
775 * Stage 3: Set new user account data
777 static NTSTATUS
usermod_modify(struct composite_context
*c
,
778 struct usermod_state
*s
)
780 /* receive samr_SetUserInfo result */
781 c
->status
= dcerpc_ndr_request_recv(s
->req
);
782 NT_STATUS_NOT_OK_RETURN(c
->status
);
784 /* return the actual function call status */
785 c
->status
= s
->setuser
.out
.result
;
787 if (s
->change
.fields
== 0) {
788 /* all fields have been set - we're done */
789 c
->state
= COMPOSITE_STATE_DONE
;
791 /* something's still not changed - repeat the procedure */
792 return usermod_change(c
, s
);
800 * Event handler for asynchronous request. Handles transition through
801 * intermediate stages of the call.
803 * @param req rpc call context
806 static void usermod_handler(struct rpc_request
*req
)
808 struct composite_context
*c
;
809 struct usermod_state
*s
;
810 struct monitor_msg msg
;
811 struct msg_rpc_lookup_name
*msg_lookup
;
812 struct msg_rpc_open_user
*msg_open
;
814 c
= talloc_get_type(req
->async
.private, struct composite_context
);
815 s
= talloc_get_type(c
->private_data
, struct usermod_state
);
819 c
->status
= usermod_lookup(c
, s
);
821 if (NT_STATUS_IS_OK(c
->status
)) {
822 /* monitor message */
823 msg
.type
= rpc_lookup_name
;
824 msg_lookup
= talloc(s
, struct msg_rpc_lookup_name
);
826 msg_lookup
->rid
= s
->lookupname
.out
.rids
.ids
;
827 msg_lookup
->count
= s
->lookupname
.out
.rids
.count
;
828 msg
.data
= (void*)msg_lookup
;
829 msg
.data_size
= sizeof(*msg_lookup
);
834 c
->status
= usermod_open(c
, s
);
836 if (NT_STATUS_IS_OK(c
->status
)) {
837 /* monitor message */
838 msg
.type
= rpc_open_user
;
839 msg_open
= talloc(s
, struct msg_rpc_open_user
);
841 msg_open
->rid
= s
->openuser
.in
.rid
;
842 msg_open
->access_mask
= s
->openuser
.in
.rid
;
843 msg
.data
= (void*)msg_open
;
844 msg
.data_size
= sizeof(*msg_open
);
849 c
->status
= usermod_query(c
, s
);
851 if (NT_STATUS_IS_OK(c
->status
)) {
852 /* monitor message */
853 msg
.type
= rpc_query_user
;
860 c
->status
= usermod_modify(c
, s
);
862 if (NT_STATUS_IS_OK(c
->status
)) {
863 /* monitor message */
864 msg
.type
= rpc_set_user
;
871 /* are we ok, so far ? */
872 if (!NT_STATUS_IS_OK(c
->status
)) {
873 c
->state
= COMPOSITE_STATE_ERROR
;
876 /* call monitor function provided the pointer has been passed */
881 /* are we done yet ? */
882 if (c
->state
>= COMPOSITE_STATE_DONE
&&
890 * Sends asynchronous usermod request
892 * @param p dce/rpc call pipe
893 * @param io arguments and results of the call
894 * @param monitor monitor function for providing information about the progress
897 struct composite_context
*libnet_rpc_usermod_send(struct dcerpc_pipe
*p
,
898 struct libnet_rpc_usermod
*io
,
899 void (*monitor
)(struct monitor_msg
*))
901 struct composite_context
*c
;
902 struct usermod_state
*s
;
904 /* composite context allocation and setup */
905 c
= talloc_zero(p
, struct composite_context
);
906 if (c
== NULL
) return NULL
;
908 s
= talloc_zero(c
, struct usermod_state
);
909 if (composite_nomem(s
, c
)) return c
;
911 c
->state
= COMPOSITE_STATE_IN_PROGRESS
;
913 c
->event_ctx
= dcerpc_event_context(p
);
915 /* store parameters in the call structure */
917 s
->domain_handle
= io
->in
.domain_handle
;
918 s
->change
= io
->in
.change
;
919 s
->monitor_fn
= monitor
;
921 /* prepare rpc call arguments */
922 s
->lookupname
.in
.domain_handle
= &io
->in
.domain_handle
;
923 s
->lookupname
.in
.num_names
= 1;
924 s
->lookupname
.in
.names
= talloc_zero(s
, struct lsa_String
);
925 s
->lookupname
.in
.names
->string
= io
->in
.username
;
927 /* send the rpc request */
928 s
->req
= dcerpc_samr_LookupNames_send(p
, c
, &s
->lookupname
);
930 /* callback handler setup */
931 s
->req
->async
.callback
= usermod_handler
;
932 s
->req
->async
.private = c
;
933 s
->stage
= USERMOD_LOOKUP
;
940 * Waits for and receives results of asynchronous usermod call
942 * @param c composite context returned by asynchronous usermod call
943 * @param mem_ctx memory context of the call
944 * @param io pointer to results (and arguments) of the call
945 * @return nt status code of execution
948 NTSTATUS
libnet_rpc_usermod_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
949 struct libnet_rpc_usermod
*io
)
953 status
= composite_wait(c
);
961 * Synchronous version of usermod call
963 * @param pipe dce/rpc call pipe
964 * @param mem_ctx memory context for the call
965 * @param io arguments and results of the call
966 * @return nt status code of execution
969 NTSTATUS
libnet_rpc_usermod(struct dcerpc_pipe
*p
,
971 struct libnet_rpc_usermod
*io
)
973 struct composite_context
*c
= libnet_rpc_usermod_send(p
, io
, NULL
);
974 return libnet_rpc_usermod_recv(c
, mem_ctx
, io
);