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 rpc_request
*req
);
913 static void continue_samr_domain_opened(struct composite_context
*ctx
);
914 static void continue_users_enumerated(struct rpc_request
*req
);
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 rpc_request
*query_req
;
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 query_req
= dcerpc_lsa_QueryInfoPolicy_send(ctx
->lsa
.pipe
, c
, &s
->query_domain
);
965 if (composite_nomem(query_req
, c
)) return c
;
967 composite_continue_rpc(c
, query_req
, continue_domain_queried
, c
);
973 * Stage 0.5 (optional): receive lsa domain handle and send
974 * request to query domain info
976 static void continue_lsa_domain_opened(struct composite_context
*ctx
)
978 struct composite_context
*c
;
979 struct userlist_state
*s
;
980 struct rpc_request
*query_req
;
982 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
983 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
985 /* receive lsa domain handle */
986 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
987 if (!composite_is_ok(c
)) return;
989 /* prepare arguments of QueryDomainInfo call */
990 s
->query_domain
.in
.handle
= &s
->ctx
->lsa
.handle
;
991 s
->query_domain
.in
.level
= LSA_POLICY_INFO_DOMAIN
;
992 s
->query_domain
.out
.info
= talloc_zero(c
, union lsa_PolicyInformation
*);
993 if (composite_nomem(s
->query_domain
.out
.info
, c
)) return;
995 /* send the request */
996 query_req
= dcerpc_lsa_QueryInfoPolicy_send(s
->ctx
->lsa
.pipe
, c
, &s
->query_domain
);
997 if (composite_nomem(query_req
, c
)) return;
999 composite_continue_rpc(c
, query_req
, continue_domain_queried
, c
);
1004 * Stage 1: receive domain info and request to enum users,
1005 * provided a valid samr handle is opened
1007 static void continue_domain_queried(struct rpc_request
*req
)
1009 struct composite_context
*c
;
1010 struct userlist_state
*s
;
1011 struct rpc_request
*enum_req
;
1012 bool prereq_met
= false;
1014 c
= talloc_get_type(req
->async
.private_data
, struct composite_context
);
1015 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1017 /* receive result of rpc request */
1018 c
->status
= dcerpc_ndr_request_recv(req
);
1019 if (!composite_is_ok(c
)) return;
1021 /* get the returned domain info */
1022 s
->dominfo
= (*s
->query_domain
.out
.info
)->domain
;
1024 /* make sure we have samr domain handle before continuing */
1025 prereq_met
= samr_domain_opened(s
->ctx
, s
->domain_name
, &c
, &s
->domain_open
,
1026 continue_samr_domain_opened
, s
->monitor_fn
);
1027 if (!prereq_met
) return;
1029 /* prepare arguments of EnumDomainUsers call */
1030 s
->user_list
.in
.domain_handle
= &s
->ctx
->samr
.handle
;
1031 s
->user_list
.in
.max_size
= s
->page_size
;
1032 s
->user_list
.in
.resume_handle
= &s
->resume_index
;
1033 s
->user_list
.in
.acct_flags
= ACB_NORMAL
;
1034 s
->user_list
.out
.resume_handle
= &s
->resume_index
;
1035 s
->user_list
.out
.num_entries
= talloc(s
, uint32_t);
1036 if (composite_nomem(s
->user_list
.out
.num_entries
, c
)) return;
1037 s
->user_list
.out
.sam
= talloc(s
, struct samr_SamArray
*);
1038 if (composite_nomem(s
->user_list
.out
.sam
, c
)) return;
1040 /* send the request */
1041 enum_req
= dcerpc_samr_EnumDomainUsers_send(s
->ctx
->samr
.pipe
, c
, &s
->user_list
);
1042 if (composite_nomem(enum_req
, c
)) return;
1044 composite_continue_rpc(c
, enum_req
, continue_users_enumerated
, c
);
1049 * Stage 1.5 (optional): receive samr domain handle
1050 * and request to enumerate accounts
1052 static void continue_samr_domain_opened(struct composite_context
*ctx
)
1054 struct composite_context
*c
;
1055 struct userlist_state
*s
;
1056 struct rpc_request
*enum_req
;
1058 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
1059 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1061 /* receive samr domain handle */
1062 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
1063 if (!composite_is_ok(c
)) return;
1065 /* prepare arguments of EnumDomainUsers call */
1066 s
->user_list
.in
.domain_handle
= &s
->ctx
->samr
.handle
;
1067 s
->user_list
.in
.max_size
= s
->page_size
;
1068 s
->user_list
.in
.resume_handle
= &s
->resume_index
;
1069 s
->user_list
.in
.acct_flags
= ACB_NORMAL
;
1070 s
->user_list
.out
.resume_handle
= &s
->resume_index
;
1071 s
->user_list
.out
.sam
= talloc(s
, struct samr_SamArray
*);
1072 if (composite_nomem(s
->user_list
.out
.sam
, c
)) return;
1073 s
->user_list
.out
.num_entries
= talloc(s
, uint32_t);
1074 if (composite_nomem(s
->user_list
.out
.num_entries
, c
)) return;
1076 /* send the request */
1077 enum_req
= dcerpc_samr_EnumDomainUsers_send(s
->ctx
->samr
.pipe
, c
, &s
->user_list
);
1078 if (composite_nomem(enum_req
, c
)) return;
1080 composite_continue_rpc(c
, enum_req
, continue_users_enumerated
, c
);
1085 * Stage 2: receive enumerated users and their rids
1087 static void continue_users_enumerated(struct rpc_request
*req
)
1089 struct composite_context
*c
;
1090 struct userlist_state
*s
;
1093 c
= talloc_get_type(req
->async
.private_data
, struct composite_context
);
1094 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1096 /* receive result of rpc request */
1097 c
->status
= dcerpc_ndr_request_recv(req
);
1098 if (!composite_is_ok(c
)) return;
1100 /* get the actual status of the rpc call result
1101 (instead of rpc layer status) */
1102 c
->status
= s
->user_list
.out
.result
;
1104 /* we're interested in status "ok" as well as two
1105 enum-specific status codes */
1106 if (NT_STATUS_IS_OK(c
->status
) ||
1107 NT_STATUS_EQUAL(c
->status
, STATUS_MORE_ENTRIES
) ||
1108 NT_STATUS_EQUAL(c
->status
, NT_STATUS_NO_MORE_ENTRIES
)) {
1110 /* get enumerated accounts counter and resume handle (the latter allows
1111 making subsequent call to continue enumeration) */
1112 s
->resume_index
= *s
->user_list
.out
.resume_handle
;
1113 s
->count
= *s
->user_list
.out
.num_entries
;
1115 /* prepare returned user accounts array */
1116 s
->users
= talloc_array(c
, struct userlist
, (*s
->user_list
.out
.sam
)->count
);
1117 if (composite_nomem(s
->users
, c
)) return;
1119 for (i
= 0; i
< (*s
->user_list
.out
.sam
)->count
; i
++) {
1120 struct dom_sid
*user_sid
;
1121 struct samr_SamEntry
*entry
= &(*s
->user_list
.out
.sam
)->entries
[i
];
1122 struct dom_sid
*domain_sid
= (*s
->query_domain
.out
.info
)->domain
.sid
;
1124 /* construct user sid from returned rid and queried domain sid */
1125 user_sid
= dom_sid_add_rid(c
, domain_sid
, entry
->idx
);
1126 if (composite_nomem(user_sid
, c
)) return;
1129 s
->users
[i
].username
= talloc_strdup(c
, entry
->name
.string
);
1130 if (composite_nomem(s
->users
[i
].username
, c
)) return;
1133 s
->users
[i
].sid
= dom_sid_string(c
, user_sid
);
1134 if (composite_nomem(s
->users
[i
].sid
, c
)) return;
1141 /* something went wrong */
1142 composite_error(c
, c
->status
);
1148 * Receive result of UserList call
1150 * @param c composite context returned by send request routine
1151 * @param mem_ctx memory context of this call
1152 * @param r pointer to structure containing arguments and result of this call
1155 NTSTATUS
libnet_UserList_recv(struct composite_context
* c
, TALLOC_CTX
*mem_ctx
,
1156 struct libnet_UserList
*r
)
1159 struct userlist_state
*s
;
1161 if (c
== NULL
|| mem_ctx
== NULL
|| r
== NULL
) {
1162 return NT_STATUS_INVALID_PARAMETER
;
1165 status
= composite_wait(c
);
1166 if (NT_STATUS_IS_OK(status
) ||
1167 NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
) ||
1168 NT_STATUS_EQUAL(status
, NT_STATUS_NO_MORE_ENTRIES
)) {
1170 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1172 /* get results from composite context */
1173 r
->out
.count
= s
->count
;
1174 r
->out
.resume_index
= s
->resume_index
;
1175 r
->out
.users
= talloc_steal(mem_ctx
, s
->users
);
1177 if (NT_STATUS_IS_OK(status
)) {
1178 r
->out
.error_string
= talloc_strdup(mem_ctx
, "Success");
1180 /* success, but we're not done yet */
1181 r
->out
.error_string
= talloc_asprintf(mem_ctx
, "Success (status: %s)",
1186 r
->out
.error_string
= talloc_asprintf(mem_ctx
, "Error: %s", nt_errstr(status
));
1194 * Synchronous version of UserList call
1196 * @param ctx initialised libnet context
1197 * @param mem_ctx memory context of this call
1198 * @param r pointer to structure containing arguments and result of this call
1201 NTSTATUS
libnet_UserList(struct libnet_context
*ctx
,
1202 TALLOC_CTX
*mem_ctx
,
1203 struct libnet_UserList
*r
)
1205 struct composite_context
*c
;
1207 c
= libnet_UserList_send(ctx
, mem_ctx
, r
, NULL
);
1208 return libnet_UserList_recv(c
, mem_ctx
, r
);