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/>.
22 #include "libnet/libnet.h"
23 #include "libcli/composite/composite.h"
24 #include "auth/credentials/credentials.h"
25 #include "librpc/ndr/libndr.h"
26 #include "librpc/gen_ndr/samr.h"
27 #include "librpc/gen_ndr/ndr_samr_c.h"
28 #include "librpc/gen_ndr/lsa.h"
29 #include "librpc/gen_ndr/ndr_lsa_c.h"
30 #include "libcli/security/security.h"
33 struct create_user_state
{
34 struct libnet_CreateUser r
;
35 struct libnet_DomainOpen domain_open
;
36 struct libnet_rpc_useradd user_add
;
37 struct libnet_context
*ctx
;
39 /* information about the progress */
40 void (*monitor_fn
)(struct monitor_msg
*);
44 static void continue_rpc_useradd(struct composite_context
*ctx
);
45 static void continue_domain_open_create(struct composite_context
*ctx
);
49 * Sends request to create user account
51 * @param ctx initialised libnet context
52 * @param mem_ctx memory context of this call
53 * @param r pointer to a structure containing arguments and results of this call
54 * @param monitor function pointer for receiving monitor messages
55 * @return compostite context of this request
57 struct composite_context
* libnet_CreateUser_send(struct libnet_context
*ctx
,
59 struct libnet_CreateUser
*r
,
60 void (*monitor
)(struct monitor_msg
*))
62 struct composite_context
*c
;
63 struct create_user_state
*s
;
64 struct composite_context
*create_req
;
65 bool prereq_met
= false;
67 /* composite context allocation and setup */
68 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
69 if (c
== NULL
) return NULL
;
71 s
= talloc_zero(c
, struct create_user_state
);
72 if (composite_nomem(s
, c
)) return c
;
76 /* store arguments in the state structure */
79 ZERO_STRUCT(s
->r
.out
);
81 /* prerequisite: make sure the domain is opened */
82 prereq_met
= samr_domain_opened(ctx
, s
->r
.in
.domain_name
, &c
, &s
->domain_open
,
83 continue_domain_open_create
, monitor
);
84 if (!prereq_met
) return c
;
86 /* prepare arguments for useradd call */
87 s
->user_add
.in
.username
= r
->in
.user_name
;
88 s
->user_add
.in
.domain_handle
= ctx
->samr
.handle
;
90 /* send the request */
91 create_req
= libnet_rpc_useradd_send(ctx
->samr
.pipe
, &s
->user_add
, monitor
);
92 if (composite_nomem(create_req
, c
)) return c
;
94 /* set the next stage */
95 composite_continue(c
, create_req
, continue_rpc_useradd
, c
);
101 * Stage 0.5 (optional): receive result of domain open request
102 * and send useradd request
104 static void continue_domain_open_create(struct composite_context
*ctx
)
106 struct composite_context
*c
;
107 struct create_user_state
*s
;
108 struct composite_context
*create_req
;
109 struct monitor_msg msg
;
111 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
112 s
= talloc_get_type(c
->private_data
, struct create_user_state
);
114 /* receive result of DomainOpen call */
115 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
116 if (!composite_is_ok(c
)) return;
118 /* send monitor message */
119 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
121 /* prepare arguments for useradd call */
122 s
->user_add
.in
.username
= s
->r
.in
.user_name
;
123 s
->user_add
.in
.domain_handle
= s
->ctx
->samr
.handle
;
125 /* send the request */
126 create_req
= libnet_rpc_useradd_send(s
->ctx
->samr
.pipe
, &s
->user_add
, s
->monitor_fn
);
127 if (composite_nomem(create_req
, c
)) return;
129 /* set the next stage */
130 composite_continue(c
, create_req
, continue_rpc_useradd
, c
);
135 * Stage 1: receive result of useradd call
137 static void continue_rpc_useradd(struct composite_context
*ctx
)
139 struct composite_context
*c
;
140 struct create_user_state
*s
;
141 struct monitor_msg msg
;
143 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
144 s
= talloc_get_type(c
->private_data
, struct create_user_state
);
146 /* receive result of the call */
147 c
->status
= libnet_rpc_useradd_recv(ctx
, c
, &s
->user_add
);
148 if (!composite_is_ok(c
)) return;
150 /* send monitor message */
151 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
159 * Receive result of CreateUser call
161 * @param c composite context returned by send request routine
162 * @param mem_ctx memory context of this call
163 * @param r pointer to a structure containing arguments and result of this call
166 NTSTATUS
libnet_CreateUser_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
167 struct libnet_CreateUser
*r
)
170 struct create_user_state
*s
;
172 r
->out
.error_string
= NULL
;
174 /* wait for result of async request and check status code */
175 status
= composite_wait(c
);
176 if (!NT_STATUS_IS_OK(status
)) {
177 s
= talloc_get_type(c
->private_data
, struct create_user_state
);
178 r
->out
.error_string
= talloc_strdup(mem_ctx
, nt_errstr(status
));
186 * Synchronous version of CreateUser call
188 * @param ctx initialised libnet context
189 * @param mem_ctx memory context of this call
190 * @param r pointer to a structure containing arguments and result of this call
193 NTSTATUS
libnet_CreateUser(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
194 struct libnet_CreateUser
*r
)
196 struct composite_context
*c
;
198 c
= libnet_CreateUser_send(ctx
, mem_ctx
, r
, NULL
);
199 return libnet_CreateUser_recv(c
, mem_ctx
, r
);
203 struct delete_user_state
{
204 struct libnet_DeleteUser r
;
205 struct libnet_context
*ctx
;
206 struct libnet_DomainOpen domain_open
;
207 struct libnet_rpc_userdel user_del
;
209 /* information about the progress */
210 void (*monitor_fn
)(struct monitor_msg
*);
214 static void continue_rpc_userdel(struct composite_context
*ctx
);
215 static void continue_domain_open_delete(struct composite_context
*ctx
);
219 * Sends request to delete user account
221 * @param ctx initialised libnet context
222 * @param mem_ctx memory context of this call
223 * @param r pointer to structure containing arguments and result of this call
224 * @param monitor function pointer for receiving monitor messages
226 struct composite_context
*libnet_DeleteUser_send(struct libnet_context
*ctx
,
228 struct libnet_DeleteUser
*r
,
229 void (*monitor
)(struct monitor_msg
*))
231 struct composite_context
*c
;
232 struct delete_user_state
*s
;
233 struct composite_context
*delete_req
;
234 bool prereq_met
= false;
236 /* composite context allocation and setup */
237 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
238 if (c
== NULL
) return NULL
;
240 s
= talloc_zero(c
, struct delete_user_state
);
241 if (composite_nomem(s
, c
)) return c
;
245 /* store arguments in state structure */
248 ZERO_STRUCT(s
->r
.out
);
250 /* prerequisite: make sure the domain is opened before proceeding */
251 prereq_met
= samr_domain_opened(ctx
, s
->r
.in
.domain_name
, &c
, &s
->domain_open
,
252 continue_domain_open_delete
, monitor
);
253 if (!prereq_met
) return c
;
255 /* prepare arguments for userdel call */
256 s
->user_del
.in
.username
= r
->in
.user_name
;
257 s
->user_del
.in
.domain_handle
= ctx
->samr
.handle
;
260 delete_req
= libnet_rpc_userdel_send(ctx
->samr
.pipe
, &s
->user_del
, monitor
);
261 if (composite_nomem(delete_req
, c
)) return c
;
263 /* set the next stage */
264 composite_continue(c
, delete_req
, continue_rpc_userdel
, c
);
270 * Stage 0.5 (optional): receive result of domain open request
271 * and send useradd request
273 static void continue_domain_open_delete(struct composite_context
*ctx
)
275 struct composite_context
*c
;
276 struct delete_user_state
*s
;
277 struct composite_context
*delete_req
;
278 struct monitor_msg msg
;
280 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
281 s
= talloc_get_type(c
->private_data
, struct delete_user_state
);
283 /* receive result of DomainOpen call */
284 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
285 if (!composite_is_ok(c
)) return;
287 /* send monitor message */
288 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
290 /* prepare arguments for userdel call */
291 s
->user_del
.in
.username
= s
->r
.in
.user_name
;
292 s
->user_del
.in
.domain_handle
= s
->ctx
->samr
.handle
;
295 delete_req
= libnet_rpc_userdel_send(s
->ctx
->samr
.pipe
, &s
->user_del
, s
->monitor_fn
);
296 if (composite_nomem(delete_req
, c
)) return;
298 /* set the next stage */
299 composite_continue(c
, delete_req
, continue_rpc_userdel
, c
);
304 * Stage 1: receive result of userdel call and finish the composite function
306 static void continue_rpc_userdel(struct composite_context
*ctx
)
308 struct composite_context
*c
;
309 struct delete_user_state
*s
;
310 struct monitor_msg msg
;
312 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
313 s
= talloc_get_type(c
->private_data
, struct delete_user_state
);
315 /* receive result of userdel call */
316 c
->status
= libnet_rpc_userdel_recv(ctx
, c
, &s
->user_del
);
317 if (!composite_is_ok(c
)) return;
319 /* send monitor message */
320 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
328 * Receives result of asynchronous DeleteUser call
330 * @param c composite context returned by async DeleteUser call
331 * @param mem_ctx memory context of this call
332 * @param r pointer to structure containing arguments and result
334 NTSTATUS
libnet_DeleteUser_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
335 struct libnet_DeleteUser
*r
)
338 struct delete_user_state
*s
;
340 r
->out
.error_string
= NULL
;
342 /* wait for result of async request and check status code */
343 status
= composite_wait(c
);
344 if (!NT_STATUS_IS_OK(status
)) {
345 s
= talloc_get_type(c
->private_data
, struct delete_user_state
);
346 r
->out
.error_string
= talloc_steal(mem_ctx
, s
->r
.out
.error_string
);
354 * Synchronous version of DeleteUser call
356 * @param ctx initialised libnet context
357 * @param mem_ctx memory context of this call
358 * @param r pointer to structure containing arguments and result
360 NTSTATUS
libnet_DeleteUser(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
361 struct libnet_DeleteUser
*r
)
363 struct composite_context
*c
;
365 c
= libnet_DeleteUser_send(ctx
, mem_ctx
, r
, NULL
);
366 return libnet_DeleteUser_recv(c
, mem_ctx
, r
);
370 struct modify_user_state
{
371 struct libnet_ModifyUser r
;
372 struct libnet_context
*ctx
;
373 struct libnet_DomainOpen domain_open
;
374 struct libnet_rpc_userinfo user_info
;
375 struct libnet_rpc_usermod user_mod
;
377 void (*monitor_fn
)(struct monitor_msg
*);
381 static void continue_rpc_usermod(struct composite_context
*ctx
);
382 static void continue_domain_open_modify(struct composite_context
*ctx
);
383 static NTSTATUS
set_user_changes(TALLOC_CTX
*mem_ctx
, struct usermod_change
*mod
,
384 struct libnet_rpc_userinfo
*info
, struct libnet_ModifyUser
*r
);
385 static void continue_rpc_userinfo(struct composite_context
*ctx
);
389 * Sends request to modify user account
391 * @param ctx initialised libnet context
392 * @param mem_ctx memory context of this call
393 * @param r pointer to structure containing arguments and result of this call
394 * @param monitor function pointer for receiving monitor messages
396 struct composite_context
*libnet_ModifyUser_send(struct libnet_context
*ctx
,
398 struct libnet_ModifyUser
*r
,
399 void (*monitor
)(struct monitor_msg
*))
401 const uint16_t level
= 21;
402 struct composite_context
*c
;
403 struct modify_user_state
*s
;
404 struct composite_context
*userinfo_req
;
405 bool prereq_met
= false;
407 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
408 if (c
== NULL
) return NULL
;
410 s
= talloc_zero(c
, struct modify_user_state
);
411 if (composite_nomem(s
, c
)) return c
;
418 prereq_met
= samr_domain_opened(ctx
, s
->r
.in
.domain_name
, &c
, &s
->domain_open
,
419 continue_domain_open_modify
, monitor
);
420 if (!prereq_met
) return c
;
422 s
->user_info
.in
.username
= r
->in
.user_name
;
423 s
->user_info
.in
.domain_handle
= ctx
->samr
.handle
;
424 s
->user_info
.in
.level
= level
;
426 userinfo_req
= libnet_rpc_userinfo_send(ctx
->samr
.pipe
, &s
->user_info
, monitor
);
427 if (composite_nomem(userinfo_req
, c
)) return c
;
429 composite_continue(c
, userinfo_req
, continue_rpc_userinfo
, c
);
435 * Stage 0.5 (optional): receive result of domain open request
436 * and send userinfo request
438 static void continue_domain_open_modify(struct composite_context
*ctx
)
440 const uint16_t level
= 21;
441 struct composite_context
*c
;
442 struct modify_user_state
*s
;
443 struct composite_context
*userinfo_req
;
444 struct monitor_msg msg
;
446 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
447 s
= talloc_get_type(c
->private_data
, struct modify_user_state
);
449 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
450 if (!composite_is_ok(c
)) return;
452 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
454 s
->user_info
.in
.domain_handle
= s
->ctx
->samr
.handle
;
455 s
->user_info
.in
.username
= s
->r
.in
.user_name
;
456 s
->user_info
.in
.level
= level
;
458 userinfo_req
= libnet_rpc_userinfo_send(s
->ctx
->samr
.pipe
, &s
->user_info
, s
->monitor_fn
);
459 if (composite_nomem(userinfo_req
, c
)) return;
461 composite_continue(c
, userinfo_req
, continue_rpc_userinfo
, c
);
466 * Stage 1: receive result of userinfo call, prepare user changes
467 * (set the fields a caller required to change) and send usermod request
469 static void continue_rpc_userinfo(struct composite_context
*ctx
)
471 struct composite_context
*c
;
472 struct modify_user_state
*s
;
473 struct composite_context
*usermod_req
;
475 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
476 s
= talloc_get_type(c
->private_data
, struct modify_user_state
);
478 c
->status
= libnet_rpc_userinfo_recv(ctx
, c
, &s
->user_info
);
479 if (!composite_is_ok(c
)) return;
481 s
->user_mod
.in
.domain_handle
= s
->ctx
->samr
.handle
;
482 s
->user_mod
.in
.username
= s
->r
.in
.user_name
;
484 c
->status
= set_user_changes(c
, &s
->user_mod
.in
.change
, &s
->user_info
, &s
->r
);
486 usermod_req
= libnet_rpc_usermod_send(s
->ctx
->samr
.pipe
, &s
->user_mod
, s
->monitor_fn
);
487 if (composite_nomem(usermod_req
, c
)) return;
489 composite_continue(c
, usermod_req
, continue_rpc_usermod
, c
);
494 * Prepare user changes: compare userinfo result to requested changes and
495 * set the field values and flags accordingly for user modify call
497 static NTSTATUS
set_user_changes(TALLOC_CTX
*mem_ctx
, struct usermod_change
*mod
,
498 struct libnet_rpc_userinfo
*info
, struct libnet_ModifyUser
*r
)
500 struct samr_UserInfo21
*user
;
502 if (mod
== NULL
|| info
== NULL
|| r
== NULL
|| info
->in
.level
!= 21) {
503 return NT_STATUS_INVALID_PARAMETER
;
506 user
= &info
->out
.info
.info21
;
507 mod
->fields
= 0; /* reset flag field before setting individual flags */
509 /* account name change */
510 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, account_name
, USERMOD_FIELD_ACCOUNT_NAME
);
512 /* full name change */
513 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, full_name
, USERMOD_FIELD_FULL_NAME
);
515 /* description change */
516 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, description
, USERMOD_FIELD_DESCRIPTION
);
519 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, comment
, USERMOD_FIELD_COMMENT
);
521 /* home directory change */
522 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, home_directory
, USERMOD_FIELD_HOME_DIRECTORY
);
524 /* home drive change */
525 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, home_drive
, USERMOD_FIELD_HOME_DRIVE
);
527 /* logon script change */
528 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, logon_script
, USERMOD_FIELD_LOGON_SCRIPT
);
530 /* profile path change */
531 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, profile_path
, USERMOD_FIELD_PROFILE_PATH
);
533 /* account expiry change */
534 SET_FIELD_NTTIME(r
->in
, user
, mod
, acct_expiry
, USERMOD_FIELD_ACCT_EXPIRY
);
536 /* account flags change */
537 SET_FIELD_ACCT_FLAGS(r
->in
, user
, mod
, acct_flags
, USERMOD_FIELD_ACCT_FLAGS
);
544 * Stage 2: receive result of usermod request and finish the composite function
546 static void continue_rpc_usermod(struct composite_context
*ctx
)
548 struct composite_context
*c
;
549 struct modify_user_state
*s
;
550 struct monitor_msg msg
;
552 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
553 s
= talloc_get_type(c
->private_data
, struct modify_user_state
);
555 c
->status
= libnet_rpc_usermod_recv(ctx
, c
, &s
->user_mod
);
556 if (!composite_is_ok(c
)) return;
558 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
564 * Receive result of ModifyUser call
566 * @param c composite context returned by send request routine
567 * @param mem_ctx memory context of this call
568 * @param r pointer to a structure containing arguments and result of this call
571 NTSTATUS
libnet_ModifyUser_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
572 struct libnet_ModifyUser
*r
)
574 NTSTATUS status
= composite_wait(c
);
580 * Synchronous version of ModifyUser call
582 * @param ctx initialised libnet context
583 * @param mem_ctx memory context of this call
584 * @param r pointer to a structure containing arguments and result of this call
587 NTSTATUS
libnet_ModifyUser(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
588 struct libnet_ModifyUser
*r
)
590 struct composite_context
*c
;
592 c
= libnet_ModifyUser_send(ctx
, mem_ctx
, r
, NULL
);
593 return libnet_ModifyUser_recv(c
, mem_ctx
, r
);
597 struct user_info_state
{
598 struct libnet_context
*ctx
;
599 const char *domain_name
;
600 enum libnet_UserInfo_level level
;
601 const char *user_name
;
602 const char *sid_string
;
603 struct libnet_LookupName lookup
;
604 struct libnet_DomainOpen domopen
;
605 struct libnet_rpc_userinfo userinfo
;
607 /* information about the progress */
608 void (*monitor_fn
)(struct monitor_msg
*);
612 static void continue_name_found(struct composite_context
*ctx
);
613 static void continue_domain_open_info(struct composite_context
*ctx
);
614 static void continue_info_received(struct composite_context
*ctx
);
618 * Sends request to get user account information
620 * @param ctx initialised libnet context
621 * @param mem_ctx memory context of this call
622 * @param r pointer to a structure containing arguments and results of this call
623 * @param monitor function pointer for receiving monitor messages
624 * @return compostite context of this request
626 struct composite_context
* libnet_UserInfo_send(struct libnet_context
*ctx
,
628 struct libnet_UserInfo
*r
,
629 void (*monitor
)(struct monitor_msg
*))
631 struct composite_context
*c
;
632 struct user_info_state
*s
;
633 struct composite_context
*lookup_req
, *info_req
;
634 bool prereq_met
= false;
636 /* composite context allocation and setup */
637 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
638 if (c
== NULL
) return NULL
;
640 s
= talloc_zero(c
, struct user_info_state
);
641 if (composite_nomem(s
, c
)) return c
;
645 /* store arguments in the state structure */
646 s
->monitor_fn
= monitor
;
648 s
->domain_name
= talloc_strdup(c
, r
->in
.domain_name
);
649 s
->level
= r
->in
.level
;
651 case USER_INFO_BY_NAME
:
652 s
->user_name
= talloc_strdup(c
, r
->in
.data
.user_name
);
653 s
->sid_string
= NULL
;
655 case USER_INFO_BY_SID
:
657 s
->sid_string
= dom_sid_string(c
, r
->in
.data
.user_sid
);
661 /* prerequisite: make sure the domain is opened */
662 prereq_met
= samr_domain_opened(ctx
, s
->domain_name
, &c
, &s
->domopen
,
663 continue_domain_open_info
, monitor
);
664 if (!prereq_met
) return c
;
667 case USER_INFO_BY_NAME
:
668 /* prepare arguments for LookupName call */
669 s
->lookup
.in
.domain_name
= s
->domain_name
;
670 s
->lookup
.in
.name
= s
->user_name
;
672 /* send the request */
673 lookup_req
= libnet_LookupName_send(ctx
, c
, &s
->lookup
,
675 if (composite_nomem(lookup_req
, c
)) return c
;
677 /* set the next stage */
678 composite_continue(c
, lookup_req
, continue_name_found
, c
);
680 case USER_INFO_BY_SID
:
681 /* prepare arguments for UserInfo call */
682 s
->userinfo
.in
.domain_handle
= s
->ctx
->samr
.handle
;
683 s
->userinfo
.in
.sid
= s
->sid_string
;
684 s
->userinfo
.in
.level
= 21;
686 /* send the request */
687 info_req
= libnet_rpc_userinfo_send(s
->ctx
->samr
.pipe
,
690 if (composite_nomem(info_req
, c
)) return c
;
692 /* set the next stage */
693 composite_continue(c
, info_req
, continue_info_received
, c
);
702 * Stage 0.5 (optional): receive result of domain open request
703 * and send LookupName request
705 static void continue_domain_open_info(struct composite_context
*ctx
)
707 struct composite_context
*c
;
708 struct user_info_state
*s
;
709 struct composite_context
*lookup_req
, *info_req
;
710 struct monitor_msg msg
;
712 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
713 s
= talloc_get_type(c
->private_data
, struct user_info_state
);
715 /* receive result of DomainOpen call */
716 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domopen
);
717 if (!composite_is_ok(c
)) return;
719 /* send monitor message */
720 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
723 case USER_INFO_BY_NAME
:
724 /* prepare arguments for LookupName call */
725 s
->lookup
.in
.domain_name
= s
->domain_name
;
726 s
->lookup
.in
.name
= s
->user_name
;
728 /* send the request */
729 lookup_req
= libnet_LookupName_send(s
->ctx
, c
, &s
->lookup
, s
->monitor_fn
);
730 if (composite_nomem(lookup_req
, c
)) return;
732 /* set the next stage */
733 composite_continue(c
, lookup_req
, continue_name_found
, c
);
736 case USER_INFO_BY_SID
:
737 /* prepare arguments for UserInfo call */
738 s
->userinfo
.in
.domain_handle
= s
->ctx
->samr
.handle
;
739 s
->userinfo
.in
.sid
= s
->sid_string
;
740 s
->userinfo
.in
.level
= 21;
742 /* send the request */
743 info_req
= libnet_rpc_userinfo_send(s
->ctx
->samr
.pipe
,
746 if (composite_nomem(info_req
, c
)) return;
748 /* set the next stage */
749 composite_continue(c
, info_req
, continue_info_received
, c
);
756 * Stage 1: receive the name (if found) and send userinfo request
758 static void continue_name_found(struct composite_context
*ctx
)
760 struct composite_context
*c
;
761 struct user_info_state
*s
;
762 struct composite_context
*info_req
;
764 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
765 s
= talloc_get_type(c
->private_data
, struct user_info_state
);
767 /* receive result of LookupName call */
768 c
->status
= libnet_LookupName_recv(ctx
, c
, &s
->lookup
);
769 if (!composite_is_ok(c
)) return;
771 /* we're only interested in user accounts this time */
772 if (s
->lookup
.out
.sid_type
!= SID_NAME_USER
) {
773 composite_error(c
, NT_STATUS_NO_SUCH_USER
);
777 /* prepare arguments for UserInfo call */
778 s
->userinfo
.in
.domain_handle
= s
->ctx
->samr
.handle
;
779 s
->userinfo
.in
.sid
= s
->lookup
.out
.sidstr
;
780 s
->userinfo
.in
.level
= 21;
782 /* send the request */
783 info_req
= libnet_rpc_userinfo_send(s
->ctx
->samr
.pipe
, &s
->userinfo
, s
->monitor_fn
);
784 if (composite_nomem(info_req
, c
)) return;
786 /* set the next stage */
787 composite_continue(c
, info_req
, continue_info_received
, c
);
792 * Stage 2: receive user account information and finish the composite function
794 static void continue_info_received(struct composite_context
*ctx
)
796 struct composite_context
*c
;
797 struct user_info_state
*s
;
799 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
800 s
= talloc_get_type(c
->private_data
, struct user_info_state
);
802 /* receive result of userinfo call */
803 c
->status
= libnet_rpc_userinfo_recv(ctx
, c
, &s
->userinfo
);
804 if (!composite_is_ok(c
)) return;
811 * Receive result of UserInfo call
813 * @param c composite context returned by send request routine
814 * @param mem_ctx memory context of this call
815 * @param r pointer to a structure containing arguments and result of this call
818 NTSTATUS
libnet_UserInfo_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
819 struct libnet_UserInfo
*r
)
822 struct user_info_state
*s
;
824 status
= composite_wait(c
);
826 if (NT_STATUS_IS_OK(status
) && r
!= NULL
) {
827 struct samr_UserInfo21
*info
;
829 s
= talloc_get_type(c
->private_data
, struct user_info_state
);
830 info
= &s
->userinfo
.out
.info
.info21
;
832 r
->out
.user_sid
= dom_sid_add_rid(mem_ctx
, s
->ctx
->samr
.sid
, info
->rid
);
833 r
->out
.primary_group_sid
= dom_sid_add_rid(mem_ctx
, s
->ctx
->samr
.sid
, info
->primary_gid
);
836 r
->out
.account_name
= talloc_steal(mem_ctx
, info
->account_name
.string
);
837 r
->out
.full_name
= talloc_steal(mem_ctx
, info
->full_name
.string
);
838 r
->out
.description
= talloc_steal(mem_ctx
, info
->description
.string
);
839 r
->out
.home_directory
= talloc_steal(mem_ctx
, info
->home_directory
.string
);
840 r
->out
.home_drive
= talloc_steal(mem_ctx
, info
->home_drive
.string
);
841 r
->out
.comment
= talloc_steal(mem_ctx
, info
->comment
.string
);
842 r
->out
.logon_script
= talloc_steal(mem_ctx
, info
->logon_script
.string
);
843 r
->out
.profile_path
= talloc_steal(mem_ctx
, info
->profile_path
.string
);
845 /* time fields (allocation) */
846 r
->out
.acct_expiry
= talloc(mem_ctx
, struct timeval
);
847 r
->out
.allow_password_change
= talloc(mem_ctx
, struct timeval
);
848 r
->out
.force_password_change
= talloc(mem_ctx
, struct timeval
);
849 r
->out
.last_logon
= talloc(mem_ctx
, struct timeval
);
850 r
->out
.last_logoff
= talloc(mem_ctx
, struct timeval
);
851 r
->out
.last_password_change
= talloc(mem_ctx
, struct timeval
);
853 /* time fields (converting) */
854 nttime_to_timeval(r
->out
.acct_expiry
, info
->acct_expiry
);
855 nttime_to_timeval(r
->out
.allow_password_change
, info
->allow_password_change
);
856 nttime_to_timeval(r
->out
.force_password_change
, info
->force_password_change
);
857 nttime_to_timeval(r
->out
.last_logon
, info
->last_logon
);
858 nttime_to_timeval(r
->out
.last_logoff
, info
->last_logoff
);
859 nttime_to_timeval(r
->out
.last_password_change
, info
->last_password_change
);
861 /* flag and number fields */
862 r
->out
.acct_flags
= info
->acct_flags
;
864 r
->out
.error_string
= talloc_strdup(mem_ctx
, "Success");
867 r
->out
.error_string
= talloc_asprintf(mem_ctx
, "Error: %s", nt_errstr(status
));
877 * Synchronous version of UserInfo call
879 * @param ctx initialised libnet context
880 * @param mem_ctx memory context of this call
881 * @param r pointer to a structure containing arguments and result of this call
884 NTSTATUS
libnet_UserInfo(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
885 struct libnet_UserInfo
*r
)
887 struct composite_context
*c
;
889 c
= libnet_UserInfo_send(ctx
, mem_ctx
, r
, NULL
);
890 return libnet_UserInfo_recv(c
, mem_ctx
, r
);
894 struct userlist_state
{
895 struct libnet_context
*ctx
;
896 const char *domain_name
;
897 struct lsa_DomainInfo dominfo
;
899 uint32_t resume_index
;
900 struct userlist
*users
;
903 struct libnet_DomainOpen domain_open
;
904 struct lsa_QueryInfoPolicy query_domain
;
905 struct samr_EnumDomainUsers user_list
;
907 void (*monitor_fn
)(struct monitor_msg
*);
911 static void continue_lsa_domain_opened(struct composite_context
*ctx
);
912 static void continue_domain_queried(struct tevent_req
*subreq
);
913 static void continue_samr_domain_opened(struct composite_context
*ctx
);
914 static void continue_users_enumerated(struct tevent_req
*subreq
);
918 * Sends request to list (enumerate) user accounts
920 * @param ctx initialised libnet context
921 * @param mem_ctx memory context of this call
922 * @param r pointer to structure containing arguments and results of this call
923 * @param monitor function pointer for receiving monitor messages
924 * @return compostite context of this request
926 struct composite_context
* libnet_UserList_send(struct libnet_context
*ctx
,
928 struct libnet_UserList
*r
,
929 void (*monitor
)(struct monitor_msg
*))
931 struct composite_context
*c
;
932 struct userlist_state
*s
;
933 struct tevent_req
*subreq
;
934 bool prereq_met
= false;
936 /* composite context allocation and setup */
937 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
938 if (c
== NULL
) return NULL
;
940 s
= talloc_zero(c
, struct userlist_state
);
941 if (composite_nomem(s
, c
)) return c
;
945 /* store the arguments in the state structure */
947 s
->page_size
= r
->in
.page_size
;
948 s
->resume_index
= r
->in
.resume_index
;
949 s
->domain_name
= talloc_strdup(c
, r
->in
.domain_name
);
950 s
->monitor_fn
= monitor
;
952 /* make sure we have lsa domain handle before doing anything */
953 prereq_met
= lsa_domain_opened(ctx
, s
->domain_name
, &c
, &s
->domain_open
,
954 continue_lsa_domain_opened
, monitor
);
955 if (!prereq_met
) return c
;
957 /* prepare arguments of QueryDomainInfo call */
958 s
->query_domain
.in
.handle
= &ctx
->lsa
.handle
;
959 s
->query_domain
.in
.level
= LSA_POLICY_INFO_DOMAIN
;
960 s
->query_domain
.out
.info
= talloc_zero(c
, union lsa_PolicyInformation
*);
961 if (composite_nomem(s
->query_domain
.out
.info
, c
)) return c
;
963 /* send the request */
964 subreq
= dcerpc_lsa_QueryInfoPolicy_r_send(s
, c
->event_ctx
,
965 ctx
->lsa
.pipe
->binding_handle
,
967 if (composite_nomem(subreq
, c
)) return c
;
969 tevent_req_set_callback(subreq
, continue_domain_queried
, c
);
975 * Stage 0.5 (optional): receive lsa domain handle and send
976 * request to query domain info
978 static void continue_lsa_domain_opened(struct composite_context
*ctx
)
980 struct composite_context
*c
;
981 struct userlist_state
*s
;
982 struct tevent_req
*subreq
;
984 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
985 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
987 /* receive lsa domain handle */
988 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
989 if (!composite_is_ok(c
)) return;
991 /* prepare arguments of QueryDomainInfo call */
992 s
->query_domain
.in
.handle
= &s
->ctx
->lsa
.handle
;
993 s
->query_domain
.in
.level
= LSA_POLICY_INFO_DOMAIN
;
994 s
->query_domain
.out
.info
= talloc_zero(c
, union lsa_PolicyInformation
*);
995 if (composite_nomem(s
->query_domain
.out
.info
, c
)) return;
997 /* send the request */
998 subreq
= dcerpc_lsa_QueryInfoPolicy_r_send(s
, c
->event_ctx
,
999 s
->ctx
->lsa
.pipe
->binding_handle
,
1001 if (composite_nomem(subreq
, c
)) return;
1003 tevent_req_set_callback(subreq
, continue_domain_queried
, c
);
1008 * Stage 1: receive domain info and request to enum users,
1009 * provided a valid samr handle is opened
1011 static void continue_domain_queried(struct tevent_req
*subreq
)
1013 struct composite_context
*c
;
1014 struct userlist_state
*s
;
1015 bool prereq_met
= false;
1017 c
= tevent_req_callback_data(subreq
, struct composite_context
);
1018 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1020 /* receive result of rpc request */
1021 c
->status
= dcerpc_lsa_QueryInfoPolicy_r_recv(subreq
, s
);
1022 TALLOC_FREE(subreq
);
1023 if (!composite_is_ok(c
)) return;
1025 /* get the returned domain info */
1026 s
->dominfo
= (*s
->query_domain
.out
.info
)->domain
;
1028 /* make sure we have samr domain handle before continuing */
1029 prereq_met
= samr_domain_opened(s
->ctx
, s
->domain_name
, &c
, &s
->domain_open
,
1030 continue_samr_domain_opened
, s
->monitor_fn
);
1031 if (!prereq_met
) return;
1033 /* prepare arguments of EnumDomainUsers call */
1034 s
->user_list
.in
.domain_handle
= &s
->ctx
->samr
.handle
;
1035 s
->user_list
.in
.max_size
= s
->page_size
;
1036 s
->user_list
.in
.resume_handle
= &s
->resume_index
;
1037 s
->user_list
.in
.acct_flags
= ACB_NORMAL
;
1038 s
->user_list
.out
.resume_handle
= &s
->resume_index
;
1039 s
->user_list
.out
.num_entries
= talloc(s
, uint32_t);
1040 if (composite_nomem(s
->user_list
.out
.num_entries
, c
)) return;
1041 s
->user_list
.out
.sam
= talloc(s
, struct samr_SamArray
*);
1042 if (composite_nomem(s
->user_list
.out
.sam
, c
)) return;
1044 /* send the request */
1045 subreq
= dcerpc_samr_EnumDomainUsers_r_send(s
, c
->event_ctx
,
1046 s
->ctx
->samr
.pipe
->binding_handle
,
1048 if (composite_nomem(subreq
, c
)) return;
1050 tevent_req_set_callback(subreq
, continue_users_enumerated
, c
);
1055 * Stage 1.5 (optional): receive samr domain handle
1056 * and request to enumerate accounts
1058 static void continue_samr_domain_opened(struct composite_context
*ctx
)
1060 struct composite_context
*c
;
1061 struct userlist_state
*s
;
1062 struct tevent_req
*subreq
;
1064 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
1065 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1067 /* receive samr domain handle */
1068 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
1069 if (!composite_is_ok(c
)) return;
1071 /* prepare arguments of EnumDomainUsers call */
1072 s
->user_list
.in
.domain_handle
= &s
->ctx
->samr
.handle
;
1073 s
->user_list
.in
.max_size
= s
->page_size
;
1074 s
->user_list
.in
.resume_handle
= &s
->resume_index
;
1075 s
->user_list
.in
.acct_flags
= ACB_NORMAL
;
1076 s
->user_list
.out
.resume_handle
= &s
->resume_index
;
1077 s
->user_list
.out
.sam
= talloc(s
, struct samr_SamArray
*);
1078 if (composite_nomem(s
->user_list
.out
.sam
, c
)) return;
1079 s
->user_list
.out
.num_entries
= talloc(s
, uint32_t);
1080 if (composite_nomem(s
->user_list
.out
.num_entries
, c
)) return;
1082 /* send the request */
1083 subreq
= dcerpc_samr_EnumDomainUsers_r_send(s
, c
->event_ctx
,
1084 s
->ctx
->samr
.pipe
->binding_handle
,
1086 if (composite_nomem(subreq
, c
)) return;
1088 tevent_req_set_callback(subreq
, continue_users_enumerated
, c
);
1093 * Stage 2: receive enumerated users and their rids
1095 static void continue_users_enumerated(struct tevent_req
*subreq
)
1097 struct composite_context
*c
;
1098 struct userlist_state
*s
;
1101 c
= tevent_req_callback_data(subreq
, struct composite_context
);
1102 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1104 /* receive result of rpc request */
1105 c
->status
= dcerpc_samr_EnumDomainUsers_r_recv(subreq
, s
);
1106 TALLOC_FREE(subreq
);
1107 if (!composite_is_ok(c
)) return;
1109 /* get the actual status of the rpc call result
1110 (instead of rpc layer status) */
1111 c
->status
= s
->user_list
.out
.result
;
1113 /* we're interested in status "ok" as well as two
1114 enum-specific status codes */
1115 if (NT_STATUS_IS_OK(c
->status
) ||
1116 NT_STATUS_EQUAL(c
->status
, STATUS_MORE_ENTRIES
) ||
1117 NT_STATUS_EQUAL(c
->status
, NT_STATUS_NO_MORE_ENTRIES
)) {
1119 /* get enumerated accounts counter and resume handle (the latter allows
1120 making subsequent call to continue enumeration) */
1121 s
->resume_index
= *s
->user_list
.out
.resume_handle
;
1122 s
->count
= *s
->user_list
.out
.num_entries
;
1124 /* prepare returned user accounts array */
1125 s
->users
= talloc_array(c
, struct userlist
, (*s
->user_list
.out
.sam
)->count
);
1126 if (composite_nomem(s
->users
, c
)) return;
1128 for (i
= 0; i
< (*s
->user_list
.out
.sam
)->count
; i
++) {
1129 struct dom_sid
*user_sid
;
1130 struct samr_SamEntry
*entry
= &(*s
->user_list
.out
.sam
)->entries
[i
];
1131 struct dom_sid
*domain_sid
= (*s
->query_domain
.out
.info
)->domain
.sid
;
1133 /* construct user sid from returned rid and queried domain sid */
1134 user_sid
= dom_sid_add_rid(c
, domain_sid
, entry
->idx
);
1135 if (composite_nomem(user_sid
, c
)) return;
1138 s
->users
[i
].username
= talloc_strdup(c
, entry
->name
.string
);
1139 if (composite_nomem(s
->users
[i
].username
, c
)) return;
1142 s
->users
[i
].sid
= dom_sid_string(c
, user_sid
);
1143 if (composite_nomem(s
->users
[i
].sid
, c
)) return;
1150 /* something went wrong */
1151 composite_error(c
, c
->status
);
1157 * Receive result of UserList call
1159 * @param c composite context returned by send request routine
1160 * @param mem_ctx memory context of this call
1161 * @param r pointer to structure containing arguments and result of this call
1164 NTSTATUS
libnet_UserList_recv(struct composite_context
* c
, TALLOC_CTX
*mem_ctx
,
1165 struct libnet_UserList
*r
)
1168 struct userlist_state
*s
;
1170 if (c
== NULL
|| mem_ctx
== NULL
|| r
== NULL
) {
1171 return NT_STATUS_INVALID_PARAMETER
;
1174 status
= composite_wait(c
);
1175 if (NT_STATUS_IS_OK(status
) ||
1176 NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
) ||
1177 NT_STATUS_EQUAL(status
, NT_STATUS_NO_MORE_ENTRIES
)) {
1179 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1181 /* get results from composite context */
1182 r
->out
.count
= s
->count
;
1183 r
->out
.resume_index
= s
->resume_index
;
1184 r
->out
.users
= talloc_steal(mem_ctx
, s
->users
);
1186 if (NT_STATUS_IS_OK(status
)) {
1187 r
->out
.error_string
= talloc_strdup(mem_ctx
, "Success");
1189 /* success, but we're not done yet */
1190 r
->out
.error_string
= talloc_asprintf(mem_ctx
, "Success (status: %s)",
1195 r
->out
.error_string
= talloc_asprintf(mem_ctx
, "Error: %s", nt_errstr(status
));
1203 * Synchronous version of UserList call
1205 * @param ctx initialised libnet context
1206 * @param mem_ctx memory context of this call
1207 * @param r pointer to structure containing arguments and result of this call
1210 NTSTATUS
libnet_UserList(struct libnet_context
*ctx
,
1211 TALLOC_CTX
*mem_ctx
,
1212 struct libnet_UserList
*r
)
1214 struct composite_context
*c
;
1216 c
= libnet_UserList_send(ctx
, mem_ctx
, r
, NULL
);
1217 return libnet_UserList_recv(c
, mem_ctx
, r
);