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
));
187 * Synchronous version of CreateUser call
189 * @param ctx initialised libnet context
190 * @param mem_ctx memory context of this call
191 * @param r pointer to a structure containing arguments and result of this call
194 NTSTATUS
libnet_CreateUser(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
195 struct libnet_CreateUser
*r
)
197 struct composite_context
*c
;
199 c
= libnet_CreateUser_send(ctx
, mem_ctx
, r
, NULL
);
200 return libnet_CreateUser_recv(c
, mem_ctx
, r
);
204 struct delete_user_state
{
205 struct libnet_DeleteUser r
;
206 struct libnet_context
*ctx
;
207 struct libnet_DomainOpen domain_open
;
208 struct libnet_rpc_userdel user_del
;
210 /* information about the progress */
211 void (*monitor_fn
)(struct monitor_msg
*);
215 static void continue_rpc_userdel(struct composite_context
*ctx
);
216 static void continue_domain_open_delete(struct composite_context
*ctx
);
220 * Sends request to delete user account
222 * @param ctx initialised libnet context
223 * @param mem_ctx memory context of this call
224 * @param r pointer to structure containing arguments and result of this call
225 * @param monitor function pointer for receiving monitor messages
227 struct composite_context
*libnet_DeleteUser_send(struct libnet_context
*ctx
,
229 struct libnet_DeleteUser
*r
,
230 void (*monitor
)(struct monitor_msg
*))
232 struct composite_context
*c
;
233 struct delete_user_state
*s
;
234 struct composite_context
*delete_req
;
235 bool prereq_met
= false;
237 /* composite context allocation and setup */
238 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
239 if (c
== NULL
) return NULL
;
241 s
= talloc_zero(c
, struct delete_user_state
);
242 if (composite_nomem(s
, c
)) return c
;
246 /* store arguments in state structure */
249 ZERO_STRUCT(s
->r
.out
);
251 /* prerequisite: make sure the domain is opened before proceeding */
252 prereq_met
= samr_domain_opened(ctx
, s
->r
.in
.domain_name
, &c
, &s
->domain_open
,
253 continue_domain_open_delete
, monitor
);
254 if (!prereq_met
) return c
;
256 /* prepare arguments for userdel call */
257 s
->user_del
.in
.username
= r
->in
.user_name
;
258 s
->user_del
.in
.domain_handle
= ctx
->samr
.handle
;
261 delete_req
= libnet_rpc_userdel_send(ctx
->samr
.pipe
, &s
->user_del
, monitor
);
262 if (composite_nomem(delete_req
, c
)) return c
;
264 /* set the next stage */
265 composite_continue(c
, delete_req
, continue_rpc_userdel
, c
);
271 * Stage 0.5 (optional): receive result of domain open request
272 * and send useradd request
274 static void continue_domain_open_delete(struct composite_context
*ctx
)
276 struct composite_context
*c
;
277 struct delete_user_state
*s
;
278 struct composite_context
*delete_req
;
279 struct monitor_msg msg
;
281 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
282 s
= talloc_get_type(c
->private_data
, struct delete_user_state
);
284 /* receive result of DomainOpen call */
285 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
286 if (!composite_is_ok(c
)) return;
288 /* send monitor message */
289 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
291 /* prepare arguments for userdel call */
292 s
->user_del
.in
.username
= s
->r
.in
.user_name
;
293 s
->user_del
.in
.domain_handle
= s
->ctx
->samr
.handle
;
296 delete_req
= libnet_rpc_userdel_send(s
->ctx
->samr
.pipe
, &s
->user_del
, s
->monitor_fn
);
297 if (composite_nomem(delete_req
, c
)) return;
299 /* set the next stage */
300 composite_continue(c
, delete_req
, continue_rpc_userdel
, c
);
305 * Stage 1: receive result of userdel call and finish the composite function
307 static void continue_rpc_userdel(struct composite_context
*ctx
)
309 struct composite_context
*c
;
310 struct delete_user_state
*s
;
311 struct monitor_msg msg
;
313 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
314 s
= talloc_get_type(c
->private_data
, struct delete_user_state
);
316 /* receive result of userdel call */
317 c
->status
= libnet_rpc_userdel_recv(ctx
, c
, &s
->user_del
);
318 if (!composite_is_ok(c
)) return;
320 /* send monitor message */
321 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
329 * Receives result of asynchronous DeleteUser call
331 * @param c composite context returned by async DeleteUser call
332 * @param mem_ctx memory context of this call
333 * @param r pointer to structure containing arguments and result
335 NTSTATUS
libnet_DeleteUser_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
336 struct libnet_DeleteUser
*r
)
339 struct delete_user_state
*s
;
341 r
->out
.error_string
= NULL
;
343 /* wait for result of async request and check status code */
344 status
= composite_wait(c
);
345 if (!NT_STATUS_IS_OK(status
)) {
346 s
= talloc_get_type(c
->private_data
, struct delete_user_state
);
347 r
->out
.error_string
= talloc_steal(mem_ctx
, s
->r
.out
.error_string
);
356 * Synchronous version of DeleteUser call
358 * @param ctx initialised libnet context
359 * @param mem_ctx memory context of this call
360 * @param r pointer to structure containing arguments and result
362 NTSTATUS
libnet_DeleteUser(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
363 struct libnet_DeleteUser
*r
)
365 struct composite_context
*c
;
367 c
= libnet_DeleteUser_send(ctx
, mem_ctx
, r
, NULL
);
368 return libnet_DeleteUser_recv(c
, mem_ctx
, r
);
372 struct modify_user_state
{
373 struct libnet_ModifyUser r
;
374 struct libnet_context
*ctx
;
375 struct libnet_DomainOpen domain_open
;
376 struct libnet_rpc_userinfo user_info
;
377 struct libnet_rpc_usermod user_mod
;
379 void (*monitor_fn
)(struct monitor_msg
*);
383 static void continue_rpc_usermod(struct composite_context
*ctx
);
384 static void continue_domain_open_modify(struct composite_context
*ctx
);
385 static NTSTATUS
set_user_changes(TALLOC_CTX
*mem_ctx
, struct usermod_change
*mod
,
386 struct libnet_rpc_userinfo
*info
, struct libnet_ModifyUser
*r
);
387 static void continue_rpc_userinfo(struct composite_context
*ctx
);
391 * Sends request to modify user account
393 * @param ctx initialised libnet context
394 * @param mem_ctx memory context of this call
395 * @param r pointer to structure containing arguments and result of this call
396 * @param monitor function pointer for receiving monitor messages
398 struct composite_context
*libnet_ModifyUser_send(struct libnet_context
*ctx
,
400 struct libnet_ModifyUser
*r
,
401 void (*monitor
)(struct monitor_msg
*))
403 const uint16_t level
= 21;
404 struct composite_context
*c
;
405 struct modify_user_state
*s
;
406 struct composite_context
*userinfo_req
;
407 bool prereq_met
= false;
409 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
410 if (c
== NULL
) return NULL
;
412 s
= talloc_zero(c
, struct modify_user_state
);
413 if (composite_nomem(s
, c
)) return c
;
420 prereq_met
= samr_domain_opened(ctx
, s
->r
.in
.domain_name
, &c
, &s
->domain_open
,
421 continue_domain_open_modify
, monitor
);
422 if (!prereq_met
) return c
;
424 s
->user_info
.in
.username
= r
->in
.user_name
;
425 s
->user_info
.in
.domain_handle
= ctx
->samr
.handle
;
426 s
->user_info
.in
.level
= level
;
428 userinfo_req
= libnet_rpc_userinfo_send(ctx
->samr
.pipe
, &s
->user_info
, monitor
);
429 if (composite_nomem(userinfo_req
, c
)) return c
;
431 composite_continue(c
, userinfo_req
, continue_rpc_userinfo
, c
);
437 * Stage 0.5 (optional): receive result of domain open request
438 * and send userinfo request
440 static void continue_domain_open_modify(struct composite_context
*ctx
)
442 const uint16_t level
= 21;
443 struct composite_context
*c
;
444 struct modify_user_state
*s
;
445 struct composite_context
*userinfo_req
;
446 struct monitor_msg msg
;
448 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
449 s
= talloc_get_type(c
->private_data
, struct modify_user_state
);
451 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
452 if (!composite_is_ok(c
)) return;
454 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
456 s
->user_info
.in
.domain_handle
= s
->ctx
->samr
.handle
;
457 s
->user_info
.in
.username
= s
->r
.in
.user_name
;
458 s
->user_info
.in
.level
= level
;
460 userinfo_req
= libnet_rpc_userinfo_send(s
->ctx
->samr
.pipe
, &s
->user_info
, s
->monitor_fn
);
461 if (composite_nomem(userinfo_req
, c
)) return;
463 composite_continue(c
, userinfo_req
, continue_rpc_userinfo
, c
);
468 * Stage 1: receive result of userinfo call, prepare user changes
469 * (set the fields a caller required to change) and send usermod request
471 static void continue_rpc_userinfo(struct composite_context
*ctx
)
473 struct composite_context
*c
;
474 struct modify_user_state
*s
;
475 struct composite_context
*usermod_req
;
477 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
478 s
= talloc_get_type(c
->private_data
, struct modify_user_state
);
480 c
->status
= libnet_rpc_userinfo_recv(ctx
, c
, &s
->user_info
);
481 if (!composite_is_ok(c
)) return;
483 s
->user_mod
.in
.domain_handle
= s
->ctx
->samr
.handle
;
484 s
->user_mod
.in
.username
= s
->r
.in
.user_name
;
486 c
->status
= set_user_changes(c
, &s
->user_mod
.in
.change
, &s
->user_info
, &s
->r
);
488 usermod_req
= libnet_rpc_usermod_send(s
->ctx
->samr
.pipe
, &s
->user_mod
, s
->monitor_fn
);
489 if (composite_nomem(usermod_req
, c
)) return;
491 composite_continue(c
, usermod_req
, continue_rpc_usermod
, c
);
496 * Prepare user changes: compare userinfo result to requested changes and
497 * set the field values and flags accordingly for user modify call
499 static NTSTATUS
set_user_changes(TALLOC_CTX
*mem_ctx
, struct usermod_change
*mod
,
500 struct libnet_rpc_userinfo
*info
, struct libnet_ModifyUser
*r
)
502 struct samr_UserInfo21
*user
;
504 if (mod
== NULL
|| info
== NULL
|| r
== NULL
|| info
->in
.level
!= 21) {
505 return NT_STATUS_INVALID_PARAMETER
;
508 user
= &info
->out
.info
.info21
;
509 mod
->fields
= 0; /* reset flag field before setting individual flags */
511 /* account name change */
512 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, account_name
, USERMOD_FIELD_ACCOUNT_NAME
);
514 /* full name change */
515 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, full_name
, USERMOD_FIELD_FULL_NAME
);
517 /* description change */
518 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, description
, USERMOD_FIELD_DESCRIPTION
);
521 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, comment
, USERMOD_FIELD_COMMENT
);
523 /* home directory change */
524 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, home_directory
, USERMOD_FIELD_HOME_DIRECTORY
);
526 /* home drive change */
527 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, home_drive
, USERMOD_FIELD_HOME_DRIVE
);
529 /* logon script change */
530 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, logon_script
, USERMOD_FIELD_LOGON_SCRIPT
);
532 /* profile path change */
533 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, profile_path
, USERMOD_FIELD_PROFILE_PATH
);
535 /* account expiry change */
536 SET_FIELD_NTTIME(r
->in
, user
, mod
, acct_expiry
, USERMOD_FIELD_ACCT_EXPIRY
);
538 /* account flags change */
539 SET_FIELD_ACCT_FLAGS(r
->in
, user
, mod
, acct_flags
, USERMOD_FIELD_ACCT_FLAGS
);
546 * Stage 2: receive result of usermod request and finish the composite function
548 static void continue_rpc_usermod(struct composite_context
*ctx
)
550 struct composite_context
*c
;
551 struct modify_user_state
*s
;
552 struct monitor_msg msg
;
554 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
555 s
= talloc_get_type(c
->private_data
, struct modify_user_state
);
557 c
->status
= libnet_rpc_usermod_recv(ctx
, c
, &s
->user_mod
);
558 if (!composite_is_ok(c
)) return;
560 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
566 * Receive result of ModifyUser call
568 * @param c composite context returned by send request routine
569 * @param mem_ctx memory context of this call
570 * @param r pointer to a structure containing arguments and result of this call
573 NTSTATUS
libnet_ModifyUser_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
574 struct libnet_ModifyUser
*r
)
576 NTSTATUS status
= composite_wait(c
);
584 * Synchronous version of ModifyUser call
586 * @param ctx initialised libnet context
587 * @param mem_ctx memory context of this call
588 * @param r pointer to a structure containing arguments and result of this call
591 NTSTATUS
libnet_ModifyUser(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
592 struct libnet_ModifyUser
*r
)
594 struct composite_context
*c
;
596 c
= libnet_ModifyUser_send(ctx
, mem_ctx
, r
, NULL
);
597 return libnet_ModifyUser_recv(c
, mem_ctx
, r
);
601 struct user_info_state
{
602 struct libnet_context
*ctx
;
603 const char *domain_name
;
604 enum libnet_UserInfo_level level
;
605 const char *user_name
;
606 const char *sid_string
;
607 struct libnet_LookupName lookup
;
608 struct libnet_DomainOpen domopen
;
609 struct libnet_rpc_userinfo userinfo
;
611 /* information about the progress */
612 void (*monitor_fn
)(struct monitor_msg
*);
616 static void continue_name_found(struct composite_context
*ctx
);
617 static void continue_domain_open_info(struct composite_context
*ctx
);
618 static void continue_info_received(struct composite_context
*ctx
);
622 * Sends request to get user account information
624 * @param ctx initialised libnet context
625 * @param mem_ctx memory context of this call
626 * @param r pointer to a structure containing arguments and results of this call
627 * @param monitor function pointer for receiving monitor messages
628 * @return compostite context of this request
630 struct composite_context
* libnet_UserInfo_send(struct libnet_context
*ctx
,
632 struct libnet_UserInfo
*r
,
633 void (*monitor
)(struct monitor_msg
*))
635 struct composite_context
*c
;
636 struct user_info_state
*s
;
637 struct composite_context
*lookup_req
, *info_req
;
638 bool prereq_met
= false;
640 /* composite context allocation and setup */
641 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
642 if (c
== NULL
) return NULL
;
644 s
= talloc_zero(c
, struct user_info_state
);
645 if (composite_nomem(s
, c
)) return c
;
649 /* store arguments in the state structure */
650 s
->monitor_fn
= monitor
;
652 s
->domain_name
= talloc_strdup(c
, r
->in
.domain_name
);
653 s
->level
= r
->in
.level
;
655 case USER_INFO_BY_NAME
:
656 s
->user_name
= talloc_strdup(c
, r
->in
.data
.user_name
);
657 s
->sid_string
= NULL
;
659 case USER_INFO_BY_SID
:
661 s
->sid_string
= dom_sid_string(c
, r
->in
.data
.user_sid
);
665 /* prerequisite: make sure the domain is opened */
666 prereq_met
= samr_domain_opened(ctx
, s
->domain_name
, &c
, &s
->domopen
,
667 continue_domain_open_info
, monitor
);
668 if (!prereq_met
) return c
;
671 case USER_INFO_BY_NAME
:
672 /* prepare arguments for LookupName call */
673 s
->lookup
.in
.domain_name
= s
->domain_name
;
674 s
->lookup
.in
.name
= s
->user_name
;
676 /* send the request */
677 lookup_req
= libnet_LookupName_send(ctx
, c
, &s
->lookup
,
679 if (composite_nomem(lookup_req
, c
)) return c
;
681 /* set the next stage */
682 composite_continue(c
, lookup_req
, continue_name_found
, c
);
684 case USER_INFO_BY_SID
:
685 /* prepare arguments for UserInfo call */
686 s
->userinfo
.in
.domain_handle
= s
->ctx
->samr
.handle
;
687 s
->userinfo
.in
.sid
= s
->sid_string
;
688 s
->userinfo
.in
.level
= 21;
690 /* send the request */
691 info_req
= libnet_rpc_userinfo_send(s
->ctx
->samr
.pipe
,
694 if (composite_nomem(info_req
, c
)) return c
;
696 /* set the next stage */
697 composite_continue(c
, info_req
, continue_info_received
, c
);
706 * Stage 0.5 (optional): receive result of domain open request
707 * and send LookupName request
709 static void continue_domain_open_info(struct composite_context
*ctx
)
711 struct composite_context
*c
;
712 struct user_info_state
*s
;
713 struct composite_context
*lookup_req
, *info_req
;
714 struct monitor_msg msg
;
716 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
717 s
= talloc_get_type(c
->private_data
, struct user_info_state
);
719 /* receive result of DomainOpen call */
720 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domopen
);
721 if (!composite_is_ok(c
)) return;
723 /* send monitor message */
724 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
727 case USER_INFO_BY_NAME
:
728 /* prepare arguments for LookupName call */
729 s
->lookup
.in
.domain_name
= s
->domain_name
;
730 s
->lookup
.in
.name
= s
->user_name
;
732 /* send the request */
733 lookup_req
= libnet_LookupName_send(s
->ctx
, c
, &s
->lookup
, s
->monitor_fn
);
734 if (composite_nomem(lookup_req
, c
)) return;
736 /* set the next stage */
737 composite_continue(c
, lookup_req
, continue_name_found
, c
);
740 case USER_INFO_BY_SID
:
741 /* prepare arguments for UserInfo call */
742 s
->userinfo
.in
.domain_handle
= s
->ctx
->samr
.handle
;
743 s
->userinfo
.in
.sid
= s
->sid_string
;
744 s
->userinfo
.in
.level
= 21;
746 /* send the request */
747 info_req
= libnet_rpc_userinfo_send(s
->ctx
->samr
.pipe
,
750 if (composite_nomem(info_req
, c
)) return;
752 /* set the next stage */
753 composite_continue(c
, info_req
, continue_info_received
, c
);
760 * Stage 1: receive the name (if found) and send userinfo request
762 static void continue_name_found(struct composite_context
*ctx
)
764 struct composite_context
*c
;
765 struct user_info_state
*s
;
766 struct composite_context
*info_req
;
768 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
769 s
= talloc_get_type(c
->private_data
, struct user_info_state
);
771 /* receive result of LookupName call */
772 c
->status
= libnet_LookupName_recv(ctx
, c
, &s
->lookup
);
773 if (!composite_is_ok(c
)) return;
775 /* we're only interested in user accounts this time */
776 if (s
->lookup
.out
.sid_type
!= SID_NAME_USER
) {
777 composite_error(c
, NT_STATUS_NO_SUCH_USER
);
781 /* prepare arguments for UserInfo call */
782 s
->userinfo
.in
.domain_handle
= s
->ctx
->samr
.handle
;
783 s
->userinfo
.in
.sid
= s
->lookup
.out
.sidstr
;
784 s
->userinfo
.in
.level
= 21;
786 /* send the request */
787 info_req
= libnet_rpc_userinfo_send(s
->ctx
->samr
.pipe
, &s
->userinfo
, s
->monitor_fn
);
788 if (composite_nomem(info_req
, c
)) return;
790 /* set the next stage */
791 composite_continue(c
, info_req
, continue_info_received
, c
);
796 * Stage 2: receive user account information and finish the composite function
798 static void continue_info_received(struct composite_context
*ctx
)
800 struct composite_context
*c
;
801 struct user_info_state
*s
;
803 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
804 s
= talloc_get_type(c
->private_data
, struct user_info_state
);
806 /* receive result of userinfo call */
807 c
->status
= libnet_rpc_userinfo_recv(ctx
, c
, &s
->userinfo
);
808 if (!composite_is_ok(c
)) return;
815 * Receive result of UserInfo call
817 * @param c composite context returned by send request routine
818 * @param mem_ctx memory context of this call
819 * @param r pointer to a structure containing arguments and result of this call
822 NTSTATUS
libnet_UserInfo_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
823 struct libnet_UserInfo
*r
)
826 struct user_info_state
*s
;
828 status
= composite_wait(c
);
830 if (NT_STATUS_IS_OK(status
) && r
!= NULL
) {
831 struct samr_UserInfo21
*info
;
833 s
= talloc_get_type(c
->private_data
, struct user_info_state
);
834 info
= &s
->userinfo
.out
.info
.info21
;
836 r
->out
.user_sid
= dom_sid_add_rid(mem_ctx
, s
->ctx
->samr
.sid
, info
->rid
);
837 r
->out
.primary_group_sid
= dom_sid_add_rid(mem_ctx
, s
->ctx
->samr
.sid
, info
->primary_gid
);
840 r
->out
.account_name
= talloc_steal(mem_ctx
, info
->account_name
.string
);
841 r
->out
.full_name
= talloc_steal(mem_ctx
, info
->full_name
.string
);
842 r
->out
.description
= talloc_steal(mem_ctx
, info
->description
.string
);
843 r
->out
.home_directory
= talloc_steal(mem_ctx
, info
->home_directory
.string
);
844 r
->out
.home_drive
= talloc_steal(mem_ctx
, info
->home_drive
.string
);
845 r
->out
.comment
= talloc_steal(mem_ctx
, info
->comment
.string
);
846 r
->out
.logon_script
= talloc_steal(mem_ctx
, info
->logon_script
.string
);
847 r
->out
.profile_path
= talloc_steal(mem_ctx
, info
->profile_path
.string
);
849 /* time fields (allocation) */
850 r
->out
.acct_expiry
= talloc(mem_ctx
, struct timeval
);
851 r
->out
.allow_password_change
= talloc(mem_ctx
, struct timeval
);
852 r
->out
.force_password_change
= talloc(mem_ctx
, struct timeval
);
853 r
->out
.last_logon
= talloc(mem_ctx
, struct timeval
);
854 r
->out
.last_logoff
= talloc(mem_ctx
, struct timeval
);
855 r
->out
.last_password_change
= talloc(mem_ctx
, struct timeval
);
857 /* time fields (converting) */
858 nttime_to_timeval(r
->out
.acct_expiry
, info
->acct_expiry
);
859 nttime_to_timeval(r
->out
.allow_password_change
, info
->allow_password_change
);
860 nttime_to_timeval(r
->out
.force_password_change
, info
->force_password_change
);
861 nttime_to_timeval(r
->out
.last_logon
, info
->last_logon
);
862 nttime_to_timeval(r
->out
.last_logoff
, info
->last_logoff
);
863 nttime_to_timeval(r
->out
.last_password_change
, info
->last_password_change
);
865 /* flag and number fields */
866 r
->out
.acct_flags
= info
->acct_flags
;
868 r
->out
.error_string
= talloc_strdup(mem_ctx
, "Success");
871 r
->out
.error_string
= talloc_asprintf(mem_ctx
, "Error: %s", nt_errstr(status
));
880 * Synchronous version of UserInfo call
882 * @param ctx initialised libnet context
883 * @param mem_ctx memory context of this call
884 * @param r pointer to a structure containing arguments and result of this call
887 NTSTATUS
libnet_UserInfo(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
888 struct libnet_UserInfo
*r
)
890 struct composite_context
*c
;
892 c
= libnet_UserInfo_send(ctx
, mem_ctx
, r
, NULL
);
893 return libnet_UserInfo_recv(c
, mem_ctx
, r
);
897 struct userlist_state
{
898 struct libnet_context
*ctx
;
899 const char *domain_name
;
900 struct lsa_DomainInfo dominfo
;
902 uint32_t resume_index
;
903 struct userlist
*users
;
906 struct libnet_DomainOpen domain_open
;
907 struct lsa_QueryInfoPolicy query_domain
;
908 struct samr_EnumDomainUsers user_list
;
910 void (*monitor_fn
)(struct monitor_msg
*);
914 static void continue_lsa_domain_opened(struct composite_context
*ctx
);
915 static void continue_domain_queried(struct tevent_req
*subreq
);
916 static void continue_samr_domain_opened(struct composite_context
*ctx
);
917 static void continue_users_enumerated(struct tevent_req
*subreq
);
921 * Sends request to list (enumerate) user accounts
923 * @param ctx initialised libnet context
924 * @param mem_ctx memory context of this call
925 * @param r pointer to structure containing arguments and results of this call
926 * @param monitor function pointer for receiving monitor messages
927 * @return compostite context of this request
929 struct composite_context
* libnet_UserList_send(struct libnet_context
*ctx
,
931 struct libnet_UserList
*r
,
932 void (*monitor
)(struct monitor_msg
*))
934 struct composite_context
*c
;
935 struct userlist_state
*s
;
936 struct tevent_req
*subreq
;
937 bool prereq_met
= false;
939 /* composite context allocation and setup */
940 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
941 if (c
== NULL
) return NULL
;
943 s
= talloc_zero(c
, struct userlist_state
);
944 if (composite_nomem(s
, c
)) return c
;
948 /* store the arguments in the state structure */
950 s
->page_size
= r
->in
.page_size
;
951 s
->resume_index
= r
->in
.resume_index
;
952 s
->domain_name
= talloc_strdup(c
, r
->in
.domain_name
);
953 s
->monitor_fn
= monitor
;
955 /* make sure we have lsa domain handle before doing anything */
956 prereq_met
= lsa_domain_opened(ctx
, s
->domain_name
, &c
, &s
->domain_open
,
957 continue_lsa_domain_opened
, monitor
);
958 if (!prereq_met
) return c
;
960 /* prepare arguments of QueryDomainInfo call */
961 s
->query_domain
.in
.handle
= &ctx
->lsa
.handle
;
962 s
->query_domain
.in
.level
= LSA_POLICY_INFO_DOMAIN
;
963 s
->query_domain
.out
.info
= talloc_zero(c
, union lsa_PolicyInformation
*);
964 if (composite_nomem(s
->query_domain
.out
.info
, c
)) return c
;
966 /* send the request */
967 subreq
= dcerpc_lsa_QueryInfoPolicy_r_send(s
, c
->event_ctx
,
968 ctx
->lsa
.pipe
->binding_handle
,
970 if (composite_nomem(subreq
, c
)) return c
;
972 tevent_req_set_callback(subreq
, continue_domain_queried
, c
);
978 * Stage 0.5 (optional): receive lsa domain handle and send
979 * request to query domain info
981 static void continue_lsa_domain_opened(struct composite_context
*ctx
)
983 struct composite_context
*c
;
984 struct userlist_state
*s
;
985 struct tevent_req
*subreq
;
987 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
988 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
990 /* receive lsa domain handle */
991 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
992 if (!composite_is_ok(c
)) return;
994 /* prepare arguments of QueryDomainInfo call */
995 s
->query_domain
.in
.handle
= &s
->ctx
->lsa
.handle
;
996 s
->query_domain
.in
.level
= LSA_POLICY_INFO_DOMAIN
;
997 s
->query_domain
.out
.info
= talloc_zero(c
, union lsa_PolicyInformation
*);
998 if (composite_nomem(s
->query_domain
.out
.info
, c
)) return;
1000 /* send the request */
1001 subreq
= dcerpc_lsa_QueryInfoPolicy_r_send(s
, c
->event_ctx
,
1002 s
->ctx
->lsa
.pipe
->binding_handle
,
1004 if (composite_nomem(subreq
, c
)) return;
1006 tevent_req_set_callback(subreq
, continue_domain_queried
, c
);
1011 * Stage 1: receive domain info and request to enum users,
1012 * provided a valid samr handle is opened
1014 static void continue_domain_queried(struct tevent_req
*subreq
)
1016 struct composite_context
*c
;
1017 struct userlist_state
*s
;
1018 bool prereq_met
= false;
1020 c
= tevent_req_callback_data(subreq
, struct composite_context
);
1021 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1023 /* receive result of rpc request */
1024 c
->status
= dcerpc_lsa_QueryInfoPolicy_r_recv(subreq
, s
);
1025 TALLOC_FREE(subreq
);
1026 if (!composite_is_ok(c
)) return;
1028 /* get the returned domain info */
1029 s
->dominfo
= (*s
->query_domain
.out
.info
)->domain
;
1031 /* make sure we have samr domain handle before continuing */
1032 prereq_met
= samr_domain_opened(s
->ctx
, s
->domain_name
, &c
, &s
->domain_open
,
1033 continue_samr_domain_opened
, s
->monitor_fn
);
1034 if (!prereq_met
) return;
1036 /* prepare arguments of EnumDomainUsers call */
1037 s
->user_list
.in
.domain_handle
= &s
->ctx
->samr
.handle
;
1038 s
->user_list
.in
.max_size
= s
->page_size
;
1039 s
->user_list
.in
.resume_handle
= &s
->resume_index
;
1040 s
->user_list
.in
.acct_flags
= ACB_NORMAL
;
1041 s
->user_list
.out
.resume_handle
= &s
->resume_index
;
1042 s
->user_list
.out
.num_entries
= talloc(s
, uint32_t);
1043 if (composite_nomem(s
->user_list
.out
.num_entries
, c
)) return;
1044 s
->user_list
.out
.sam
= talloc(s
, struct samr_SamArray
*);
1045 if (composite_nomem(s
->user_list
.out
.sam
, c
)) return;
1047 /* send the request */
1048 subreq
= dcerpc_samr_EnumDomainUsers_r_send(s
, c
->event_ctx
,
1049 s
->ctx
->samr
.pipe
->binding_handle
,
1051 if (composite_nomem(subreq
, c
)) return;
1053 tevent_req_set_callback(subreq
, continue_users_enumerated
, c
);
1058 * Stage 1.5 (optional): receive samr domain handle
1059 * and request to enumerate accounts
1061 static void continue_samr_domain_opened(struct composite_context
*ctx
)
1063 struct composite_context
*c
;
1064 struct userlist_state
*s
;
1065 struct tevent_req
*subreq
;
1067 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
1068 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1070 /* receive samr domain handle */
1071 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
1072 if (!composite_is_ok(c
)) return;
1074 /* prepare arguments of EnumDomainUsers call */
1075 s
->user_list
.in
.domain_handle
= &s
->ctx
->samr
.handle
;
1076 s
->user_list
.in
.max_size
= s
->page_size
;
1077 s
->user_list
.in
.resume_handle
= &s
->resume_index
;
1078 s
->user_list
.in
.acct_flags
= ACB_NORMAL
;
1079 s
->user_list
.out
.resume_handle
= &s
->resume_index
;
1080 s
->user_list
.out
.sam
= talloc(s
, struct samr_SamArray
*);
1081 if (composite_nomem(s
->user_list
.out
.sam
, c
)) return;
1082 s
->user_list
.out
.num_entries
= talloc(s
, uint32_t);
1083 if (composite_nomem(s
->user_list
.out
.num_entries
, c
)) return;
1085 /* send the request */
1086 subreq
= dcerpc_samr_EnumDomainUsers_r_send(s
, c
->event_ctx
,
1087 s
->ctx
->samr
.pipe
->binding_handle
,
1089 if (composite_nomem(subreq
, c
)) return;
1091 tevent_req_set_callback(subreq
, continue_users_enumerated
, c
);
1096 * Stage 2: receive enumerated users and their rids
1098 static void continue_users_enumerated(struct tevent_req
*subreq
)
1100 struct composite_context
*c
;
1101 struct userlist_state
*s
;
1104 c
= tevent_req_callback_data(subreq
, struct composite_context
);
1105 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1107 /* receive result of rpc request */
1108 c
->status
= dcerpc_samr_EnumDomainUsers_r_recv(subreq
, s
);
1109 TALLOC_FREE(subreq
);
1110 if (!composite_is_ok(c
)) return;
1112 /* get the actual status of the rpc call result
1113 (instead of rpc layer status) */
1114 c
->status
= s
->user_list
.out
.result
;
1116 /* we're interested in status "ok" as well as two
1117 enum-specific status codes */
1118 if (NT_STATUS_IS_OK(c
->status
) ||
1119 NT_STATUS_EQUAL(c
->status
, STATUS_MORE_ENTRIES
) ||
1120 NT_STATUS_EQUAL(c
->status
, NT_STATUS_NO_MORE_ENTRIES
)) {
1122 /* get enumerated accounts counter and resume handle (the latter allows
1123 making subsequent call to continue enumeration) */
1124 s
->resume_index
= *s
->user_list
.out
.resume_handle
;
1125 s
->count
= *s
->user_list
.out
.num_entries
;
1127 /* prepare returned user accounts array */
1128 s
->users
= talloc_array(c
, struct userlist
, (*s
->user_list
.out
.sam
)->count
);
1129 if (composite_nomem(s
->users
, c
)) return;
1131 for (i
= 0; i
< (*s
->user_list
.out
.sam
)->count
; i
++) {
1132 struct dom_sid
*user_sid
;
1133 struct samr_SamEntry
*entry
= &(*s
->user_list
.out
.sam
)->entries
[i
];
1134 struct dom_sid
*domain_sid
= (*s
->query_domain
.out
.info
)->domain
.sid
;
1136 /* construct user sid from returned rid and queried domain sid */
1137 user_sid
= dom_sid_add_rid(c
, domain_sid
, entry
->idx
);
1138 if (composite_nomem(user_sid
, c
)) return;
1141 s
->users
[i
].username
= talloc_strdup(s
->users
, entry
->name
.string
);
1142 if (composite_nomem(s
->users
[i
].username
, c
)) return;
1145 s
->users
[i
].sid
= dom_sid_string(s
->users
, user_sid
);
1146 if (composite_nomem(s
->users
[i
].sid
, c
)) return;
1153 /* something went wrong */
1154 composite_error(c
, c
->status
);
1160 * Receive result of UserList call
1162 * @param c composite context returned by send request routine
1163 * @param mem_ctx memory context of this call
1164 * @param r pointer to structure containing arguments and result of this call
1167 NTSTATUS
libnet_UserList_recv(struct composite_context
* c
, TALLOC_CTX
*mem_ctx
,
1168 struct libnet_UserList
*r
)
1171 struct userlist_state
*s
;
1173 if (c
== NULL
|| mem_ctx
== NULL
|| r
== NULL
) {
1175 return NT_STATUS_INVALID_PARAMETER
;
1178 status
= composite_wait(c
);
1179 if (NT_STATUS_IS_OK(status
) ||
1180 NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
) ||
1181 NT_STATUS_EQUAL(status
, NT_STATUS_NO_MORE_ENTRIES
)) {
1183 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1185 /* get results from composite context */
1186 r
->out
.count
= s
->count
;
1187 r
->out
.resume_index
= s
->resume_index
;
1188 r
->out
.users
= talloc_steal(mem_ctx
, s
->users
);
1190 if (NT_STATUS_IS_OK(status
)) {
1191 r
->out
.error_string
= talloc_strdup(mem_ctx
, "Success");
1193 /* success, but we're not done yet */
1194 r
->out
.error_string
= talloc_asprintf(mem_ctx
, "Success (status: %s)",
1199 r
->out
.error_string
= talloc_asprintf(mem_ctx
, "Error: %s", nt_errstr(status
));
1208 * Synchronous version of UserList call
1210 * @param ctx initialised libnet context
1211 * @param mem_ctx memory context of this call
1212 * @param r pointer to structure containing arguments and result of this call
1215 NTSTATUS
libnet_UserList(struct libnet_context
*ctx
,
1216 TALLOC_CTX
*mem_ctx
,
1217 struct libnet_UserList
*r
)
1219 struct composite_context
*c
;
1221 c
= libnet_UserList_send(ctx
, mem_ctx
, r
, NULL
);
1222 return libnet_UserList_recv(c
, mem_ctx
, r
);