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
, c
, 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(s
, s
->ctx
->event_ctx
,
92 ctx
->samr
.samr_handle
,
93 &s
->user_add
, monitor
);
94 if (composite_nomem(create_req
, c
)) return c
;
96 /* set the next stage */
97 composite_continue(c
, create_req
, continue_rpc_useradd
, c
);
103 * Stage 0.5 (optional): receive result of domain open request
104 * and send useradd request
106 static void continue_domain_open_create(struct composite_context
*ctx
)
108 struct composite_context
*c
;
109 struct create_user_state
*s
;
110 struct composite_context
*create_req
;
111 struct monitor_msg msg
;
113 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
114 s
= talloc_get_type_abort(c
->private_data
, struct create_user_state
);
116 /* receive result of DomainOpen call */
117 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
118 if (!composite_is_ok(c
)) return;
120 /* send monitor message */
121 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
123 /* prepare arguments for useradd call */
124 s
->user_add
.in
.username
= s
->r
.in
.user_name
;
125 s
->user_add
.in
.domain_handle
= s
->ctx
->samr
.handle
;
127 /* send the request */
128 create_req
= libnet_rpc_useradd_send(s
, s
->ctx
->event_ctx
,
129 s
->ctx
->samr
.samr_handle
,
130 &s
->user_add
, s
->monitor_fn
);
131 if (composite_nomem(create_req
, c
)) return;
133 /* set the next stage */
134 composite_continue(c
, create_req
, continue_rpc_useradd
, c
);
139 * Stage 1: receive result of useradd call
141 static void continue_rpc_useradd(struct composite_context
*ctx
)
143 struct composite_context
*c
;
144 struct create_user_state
*s
;
145 struct monitor_msg msg
;
147 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
148 s
= talloc_get_type_abort(c
->private_data
, struct create_user_state
);
150 /* receive result of the call */
151 c
->status
= libnet_rpc_useradd_recv(ctx
, c
, &s
->user_add
);
152 if (!composite_is_ok(c
)) return;
154 /* send monitor message */
155 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
163 * Receive result of CreateUser call
165 * @param c composite context returned by send request routine
166 * @param mem_ctx memory context of this call
167 * @param r pointer to a structure containing arguments and result of this call
170 NTSTATUS
libnet_CreateUser_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
171 struct libnet_CreateUser
*r
)
175 r
->out
.error_string
= NULL
;
177 /* wait for result of async request and check status code */
178 status
= composite_wait(c
);
179 if (!NT_STATUS_IS_OK(status
)) {
180 r
->out
.error_string
= talloc_strdup(mem_ctx
, nt_errstr(status
));
189 * Synchronous version of CreateUser call
191 * @param ctx initialised libnet context
192 * @param mem_ctx memory context of this call
193 * @param r pointer to a structure containing arguments and result of this call
196 NTSTATUS
libnet_CreateUser(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
197 struct libnet_CreateUser
*r
)
199 struct composite_context
*c
;
201 c
= libnet_CreateUser_send(ctx
, mem_ctx
, r
, NULL
);
202 return libnet_CreateUser_recv(c
, mem_ctx
, r
);
206 struct delete_user_state
{
207 struct libnet_DeleteUser r
;
208 struct libnet_context
*ctx
;
209 struct libnet_DomainOpen domain_open
;
210 struct libnet_rpc_userdel user_del
;
212 /* information about the progress */
213 void (*monitor_fn
)(struct monitor_msg
*);
217 static void continue_rpc_userdel(struct composite_context
*ctx
);
218 static void continue_domain_open_delete(struct composite_context
*ctx
);
222 * Sends request to delete user account
224 * @param ctx initialised libnet context
225 * @param mem_ctx memory context of this call
226 * @param r pointer to structure containing arguments and result of this call
227 * @param monitor function pointer for receiving monitor messages
229 struct composite_context
*libnet_DeleteUser_send(struct libnet_context
*ctx
,
231 struct libnet_DeleteUser
*r
,
232 void (*monitor
)(struct monitor_msg
*))
234 struct composite_context
*c
;
235 struct delete_user_state
*s
;
236 struct composite_context
*delete_req
;
237 bool prereq_met
= false;
239 /* composite context allocation and setup */
240 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
241 if (c
== NULL
) return NULL
;
243 s
= talloc_zero(c
, struct delete_user_state
);
244 if (composite_nomem(s
, c
)) return c
;
248 /* store arguments in state structure */
251 ZERO_STRUCT(s
->r
.out
);
253 /* prerequisite: make sure the domain is opened before proceeding */
254 prereq_met
= samr_domain_opened(ctx
, c
, s
->r
.in
.domain_name
, &c
, &s
->domain_open
,
255 continue_domain_open_delete
, monitor
);
256 if (!prereq_met
) return c
;
258 /* prepare arguments for userdel call */
259 s
->user_del
.in
.username
= r
->in
.user_name
;
260 s
->user_del
.in
.domain_handle
= ctx
->samr
.handle
;
263 delete_req
= libnet_rpc_userdel_send(s
, s
->ctx
->event_ctx
,
264 ctx
->samr
.samr_handle
,
265 &s
->user_del
, monitor
);
266 if (composite_nomem(delete_req
, c
)) return c
;
268 /* set the next stage */
269 composite_continue(c
, delete_req
, continue_rpc_userdel
, c
);
275 * Stage 0.5 (optional): receive result of domain open request
276 * and send useradd request
278 static void continue_domain_open_delete(struct composite_context
*ctx
)
280 struct composite_context
*c
;
281 struct delete_user_state
*s
;
282 struct composite_context
*delete_req
;
283 struct monitor_msg msg
;
285 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
286 s
= talloc_get_type_abort(c
->private_data
, struct delete_user_state
);
288 /* receive result of DomainOpen call */
289 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
290 if (!composite_is_ok(c
)) return;
292 /* send monitor message */
293 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
295 /* prepare arguments for userdel call */
296 s
->user_del
.in
.username
= s
->r
.in
.user_name
;
297 s
->user_del
.in
.domain_handle
= s
->ctx
->samr
.handle
;
300 delete_req
= libnet_rpc_userdel_send(s
, s
->ctx
->event_ctx
,
301 s
->ctx
->samr
.samr_handle
,
302 &s
->user_del
, s
->monitor_fn
);
303 if (composite_nomem(delete_req
, c
)) return;
305 /* set the next stage */
306 composite_continue(c
, delete_req
, continue_rpc_userdel
, c
);
311 * Stage 1: receive result of userdel call and finish the composite function
313 static void continue_rpc_userdel(struct composite_context
*ctx
)
315 struct composite_context
*c
;
316 struct delete_user_state
*s
;
317 struct monitor_msg msg
;
319 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
320 s
= talloc_get_type_abort(c
->private_data
, struct delete_user_state
);
322 /* receive result of userdel call */
323 c
->status
= libnet_rpc_userdel_recv(ctx
, c
, &s
->user_del
);
324 if (!composite_is_ok(c
)) return;
326 /* send monitor message */
327 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
335 * Receives result of asynchronous DeleteUser call
337 * @param c composite context returned by async DeleteUser call
338 * @param mem_ctx memory context of this call
339 * @param r pointer to structure containing arguments and result
341 NTSTATUS
libnet_DeleteUser_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
342 struct libnet_DeleteUser
*r
)
345 struct delete_user_state
*s
;
347 r
->out
.error_string
= NULL
;
349 /* wait for result of async request and check status code */
350 status
= composite_wait(c
);
351 if (!NT_STATUS_IS_OK(status
)) {
352 s
= talloc_get_type_abort(c
->private_data
, struct delete_user_state
);
353 r
->out
.error_string
= talloc_steal(mem_ctx
, s
->r
.out
.error_string
);
362 * Synchronous version of DeleteUser call
364 * @param ctx initialised libnet context
365 * @param mem_ctx memory context of this call
366 * @param r pointer to structure containing arguments and result
368 NTSTATUS
libnet_DeleteUser(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
369 struct libnet_DeleteUser
*r
)
371 struct composite_context
*c
;
373 c
= libnet_DeleteUser_send(ctx
, mem_ctx
, r
, NULL
);
374 return libnet_DeleteUser_recv(c
, mem_ctx
, r
);
378 struct modify_user_state
{
379 struct libnet_ModifyUser r
;
380 struct libnet_context
*ctx
;
381 struct libnet_DomainOpen domain_open
;
382 struct libnet_rpc_userinfo user_info
;
383 struct libnet_rpc_usermod user_mod
;
385 void (*monitor_fn
)(struct monitor_msg
*);
389 static void continue_rpc_usermod(struct composite_context
*ctx
);
390 static void continue_domain_open_modify(struct composite_context
*ctx
);
391 static NTSTATUS
set_user_changes(TALLOC_CTX
*mem_ctx
, struct usermod_change
*mod
,
392 struct libnet_rpc_userinfo
*info
, struct libnet_ModifyUser
*r
);
393 static void continue_rpc_userinfo(struct composite_context
*ctx
);
397 * Sends request to modify user account
399 * @param ctx initialised libnet context
400 * @param mem_ctx memory context of this call
401 * @param r pointer to structure containing arguments and result of this call
402 * @param monitor function pointer for receiving monitor messages
404 struct composite_context
*libnet_ModifyUser_send(struct libnet_context
*ctx
,
406 struct libnet_ModifyUser
*r
,
407 void (*monitor
)(struct monitor_msg
*))
409 const uint16_t level
= 21;
410 struct composite_context
*c
;
411 struct modify_user_state
*s
;
412 struct composite_context
*userinfo_req
;
413 bool prereq_met
= false;
415 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
416 if (c
== NULL
) return NULL
;
418 s
= talloc_zero(c
, struct modify_user_state
);
419 if (composite_nomem(s
, c
)) return c
;
426 prereq_met
= samr_domain_opened(ctx
, c
, s
->r
.in
.domain_name
, &c
, &s
->domain_open
,
427 continue_domain_open_modify
, monitor
);
428 if (!prereq_met
) return c
;
430 s
->user_info
.in
.username
= r
->in
.user_name
;
431 s
->user_info
.in
.domain_handle
= ctx
->samr
.handle
;
432 s
->user_info
.in
.level
= level
;
434 userinfo_req
= libnet_rpc_userinfo_send(s
, s
->ctx
->event_ctx
,
435 ctx
->samr
.samr_handle
,
436 &s
->user_info
, monitor
);
437 if (composite_nomem(userinfo_req
, c
)) return c
;
439 composite_continue(c
, userinfo_req
, continue_rpc_userinfo
, c
);
445 * Stage 0.5 (optional): receive result of domain open request
446 * and send userinfo request
448 static void continue_domain_open_modify(struct composite_context
*ctx
)
450 const uint16_t level
= 21;
451 struct composite_context
*c
;
452 struct modify_user_state
*s
;
453 struct composite_context
*userinfo_req
;
454 struct monitor_msg msg
;
456 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
457 s
= talloc_get_type_abort(c
->private_data
, struct modify_user_state
);
459 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
460 if (!composite_is_ok(c
)) return;
462 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
464 s
->user_info
.in
.domain_handle
= s
->ctx
->samr
.handle
;
465 s
->user_info
.in
.username
= s
->r
.in
.user_name
;
466 s
->user_info
.in
.level
= level
;
468 userinfo_req
= libnet_rpc_userinfo_send(s
, s
->ctx
->event_ctx
,
469 s
->ctx
->samr
.samr_handle
,
470 &s
->user_info
, s
->monitor_fn
);
471 if (composite_nomem(userinfo_req
, c
)) return;
473 composite_continue(c
, userinfo_req
, continue_rpc_userinfo
, c
);
478 * Stage 1: receive result of userinfo call, prepare user changes
479 * (set the fields a caller required to change) and send usermod request
481 static void continue_rpc_userinfo(struct composite_context
*ctx
)
483 struct composite_context
*c
;
484 struct modify_user_state
*s
;
485 struct composite_context
*usermod_req
;
487 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
488 s
= talloc_get_type_abort(c
->private_data
, struct modify_user_state
);
490 c
->status
= libnet_rpc_userinfo_recv(ctx
, c
, &s
->user_info
);
491 if (!composite_is_ok(c
)) return;
493 s
->user_mod
.in
.domain_handle
= s
->ctx
->samr
.handle
;
494 s
->user_mod
.in
.username
= s
->r
.in
.user_name
;
496 c
->status
= set_user_changes(c
, &s
->user_mod
.in
.change
, &s
->user_info
, &s
->r
);
498 usermod_req
= libnet_rpc_usermod_send(s
, s
->ctx
->event_ctx
,
499 s
->ctx
->samr
.samr_handle
,
500 &s
->user_mod
, s
->monitor_fn
);
501 if (composite_nomem(usermod_req
, c
)) return;
503 composite_continue(c
, usermod_req
, continue_rpc_usermod
, c
);
508 * Prepare user changes: compare userinfo result to requested changes and
509 * set the field values and flags accordingly for user modify call
511 static NTSTATUS
set_user_changes(TALLOC_CTX
*mem_ctx
, struct usermod_change
*mod
,
512 struct libnet_rpc_userinfo
*info
, struct libnet_ModifyUser
*r
)
514 struct samr_UserInfo21
*user
;
516 if (mod
== NULL
|| info
== NULL
|| r
== NULL
|| info
->in
.level
!= 21) {
517 return NT_STATUS_INVALID_PARAMETER
;
520 user
= &info
->out
.info
.info21
;
521 mod
->fields
= 0; /* reset flag field before setting individual flags */
523 /* account name change */
524 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, account_name
, USERMOD_FIELD_ACCOUNT_NAME
);
526 /* full name change */
527 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, full_name
, USERMOD_FIELD_FULL_NAME
);
529 /* description change */
530 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, description
, USERMOD_FIELD_DESCRIPTION
);
533 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, comment
, USERMOD_FIELD_COMMENT
);
535 /* home directory change */
536 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, home_directory
, USERMOD_FIELD_HOME_DIRECTORY
);
538 /* home drive change */
539 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, home_drive
, USERMOD_FIELD_HOME_DRIVE
);
541 /* logon script change */
542 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, logon_script
, USERMOD_FIELD_LOGON_SCRIPT
);
544 /* profile path change */
545 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, profile_path
, USERMOD_FIELD_PROFILE_PATH
);
547 /* account expiry change */
548 SET_FIELD_NTTIME(r
->in
, user
, mod
, acct_expiry
, USERMOD_FIELD_ACCT_EXPIRY
);
550 /* account flags change */
551 SET_FIELD_ACCT_FLAGS(r
->in
, user
, mod
, acct_flags
, USERMOD_FIELD_ACCT_FLAGS
);
558 * Stage 2: receive result of usermod request and finish the composite function
560 static void continue_rpc_usermod(struct composite_context
*ctx
)
562 struct composite_context
*c
;
563 struct modify_user_state
*s
;
564 struct monitor_msg msg
;
566 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
567 s
= talloc_get_type_abort(c
->private_data
, struct modify_user_state
);
569 c
->status
= libnet_rpc_usermod_recv(ctx
, c
, &s
->user_mod
);
570 if (!composite_is_ok(c
)) return;
572 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
578 * Receive result of ModifyUser call
580 * @param c composite context returned by send request routine
581 * @param mem_ctx memory context of this call
582 * @param r pointer to a structure containing arguments and result of this call
585 NTSTATUS
libnet_ModifyUser_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
586 struct libnet_ModifyUser
*r
)
588 NTSTATUS status
= composite_wait(c
);
596 * Synchronous version of ModifyUser call
598 * @param ctx initialised libnet context
599 * @param mem_ctx memory context of this call
600 * @param r pointer to a structure containing arguments and result of this call
603 NTSTATUS
libnet_ModifyUser(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
604 struct libnet_ModifyUser
*r
)
606 struct composite_context
*c
;
608 c
= libnet_ModifyUser_send(ctx
, mem_ctx
, r
, NULL
);
609 return libnet_ModifyUser_recv(c
, mem_ctx
, r
);
613 struct user_info_state
{
614 struct libnet_context
*ctx
;
615 const char *domain_name
;
616 enum libnet_UserInfo_level level
;
617 const char *user_name
;
618 const char *sid_string
;
619 struct libnet_LookupName lookup
;
620 struct libnet_DomainOpen domopen
;
621 struct libnet_rpc_userinfo userinfo
;
623 /* information about the progress */
624 void (*monitor_fn
)(struct monitor_msg
*);
628 static void continue_name_found(struct composite_context
*ctx
);
629 static void continue_domain_open_info(struct composite_context
*ctx
);
630 static void continue_info_received(struct composite_context
*ctx
);
634 * Sends request to get user account information
636 * @param ctx initialised libnet context
637 * @param mem_ctx memory context of this call
638 * @param r pointer to a structure containing arguments and results of this call
639 * @param monitor function pointer for receiving monitor messages
640 * @return compostite context of this request
642 struct composite_context
* libnet_UserInfo_send(struct libnet_context
*ctx
,
644 struct libnet_UserInfo
*r
,
645 void (*monitor
)(struct monitor_msg
*))
647 struct composite_context
*c
;
648 struct user_info_state
*s
;
649 struct composite_context
*lookup_req
, *info_req
;
650 bool prereq_met
= false;
652 /* composite context allocation and setup */
653 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
654 if (c
== NULL
) return NULL
;
656 s
= talloc_zero(c
, struct user_info_state
);
657 if (composite_nomem(s
, c
)) return c
;
661 /* store arguments in the state structure */
662 s
->monitor_fn
= monitor
;
664 s
->domain_name
= talloc_strdup(c
, r
->in
.domain_name
);
665 s
->level
= r
->in
.level
;
667 case USER_INFO_BY_NAME
:
668 s
->user_name
= talloc_strdup(c
, r
->in
.data
.user_name
);
669 s
->sid_string
= NULL
;
671 case USER_INFO_BY_SID
:
673 s
->sid_string
= dom_sid_string(c
, r
->in
.data
.user_sid
);
677 /* prerequisite: make sure the domain is opened */
678 prereq_met
= samr_domain_opened(ctx
, c
, s
->domain_name
, &c
, &s
->domopen
,
679 continue_domain_open_info
, monitor
);
680 if (!prereq_met
) return c
;
683 case USER_INFO_BY_NAME
:
684 /* prepare arguments for LookupName call */
685 s
->lookup
.in
.domain_name
= s
->domain_name
;
686 s
->lookup
.in
.name
= s
->user_name
;
688 /* send the request */
689 lookup_req
= libnet_LookupName_send(ctx
, c
, &s
->lookup
,
691 if (composite_nomem(lookup_req
, c
)) return c
;
693 /* set the next stage */
694 composite_continue(c
, lookup_req
, continue_name_found
, c
);
696 case USER_INFO_BY_SID
:
697 /* prepare arguments for UserInfo call */
698 s
->userinfo
.in
.domain_handle
= s
->ctx
->samr
.handle
;
699 s
->userinfo
.in
.sid
= s
->sid_string
;
700 s
->userinfo
.in
.level
= 21;
702 /* send the request */
703 info_req
= libnet_rpc_userinfo_send(s
, s
->ctx
->event_ctx
,
704 s
->ctx
->samr
.samr_handle
,
707 if (composite_nomem(info_req
, c
)) return c
;
709 /* set the next stage */
710 composite_continue(c
, info_req
, continue_info_received
, c
);
719 * Stage 0.5 (optional): receive result of domain open request
720 * and send LookupName request
722 static void continue_domain_open_info(struct composite_context
*ctx
)
724 struct composite_context
*c
;
725 struct user_info_state
*s
;
726 struct composite_context
*lookup_req
, *info_req
;
727 struct monitor_msg msg
;
729 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
730 s
= talloc_get_type_abort(c
->private_data
, struct user_info_state
);
732 /* receive result of DomainOpen call */
733 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domopen
);
734 if (!composite_is_ok(c
)) return;
736 /* send monitor message */
737 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
740 case USER_INFO_BY_NAME
:
741 /* prepare arguments for LookupName call */
742 s
->lookup
.in
.domain_name
= s
->domain_name
;
743 s
->lookup
.in
.name
= s
->user_name
;
745 /* send the request */
746 lookup_req
= libnet_LookupName_send(s
->ctx
, c
, &s
->lookup
, s
->monitor_fn
);
747 if (composite_nomem(lookup_req
, c
)) return;
749 /* set the next stage */
750 composite_continue(c
, lookup_req
, continue_name_found
, c
);
753 case USER_INFO_BY_SID
:
754 /* prepare arguments for UserInfo call */
755 s
->userinfo
.in
.domain_handle
= s
->ctx
->samr
.handle
;
756 s
->userinfo
.in
.sid
= s
->sid_string
;
757 s
->userinfo
.in
.level
= 21;
759 /* send the request */
760 info_req
= libnet_rpc_userinfo_send(s
, s
->ctx
->event_ctx
,
761 s
->ctx
->samr
.samr_handle
,
764 if (composite_nomem(info_req
, c
)) return;
766 /* set the next stage */
767 composite_continue(c
, info_req
, continue_info_received
, c
);
774 * Stage 1: receive the name (if found) and send userinfo request
776 static void continue_name_found(struct composite_context
*ctx
)
778 struct composite_context
*c
;
779 struct user_info_state
*s
;
780 struct composite_context
*info_req
;
782 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
783 s
= talloc_get_type_abort(c
->private_data
, struct user_info_state
);
785 /* receive result of LookupName call */
786 c
->status
= libnet_LookupName_recv(ctx
, c
, &s
->lookup
);
787 if (!composite_is_ok(c
)) return;
789 /* we're only interested in user accounts this time */
790 if (s
->lookup
.out
.sid_type
!= SID_NAME_USER
) {
791 composite_error(c
, NT_STATUS_NO_SUCH_USER
);
795 /* prepare arguments for UserInfo call */
796 s
->userinfo
.in
.domain_handle
= s
->ctx
->samr
.handle
;
797 s
->userinfo
.in
.sid
= s
->lookup
.out
.sidstr
;
798 s
->userinfo
.in
.level
= 21;
800 /* send the request */
801 info_req
= libnet_rpc_userinfo_send(s
, s
->ctx
->event_ctx
,
802 s
->ctx
->samr
.samr_handle
,
803 &s
->userinfo
, s
->monitor_fn
);
804 if (composite_nomem(info_req
, c
)) return;
806 /* set the next stage */
807 composite_continue(c
, info_req
, continue_info_received
, c
);
812 * Stage 2: receive user account information and finish the composite function
814 static void continue_info_received(struct composite_context
*ctx
)
816 struct composite_context
*c
;
817 struct user_info_state
*s
;
819 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
820 s
= talloc_get_type_abort(c
->private_data
, struct user_info_state
);
822 /* receive result of userinfo call */
823 c
->status
= libnet_rpc_userinfo_recv(ctx
, c
, &s
->userinfo
);
824 if (!composite_is_ok(c
)) return;
831 * Receive result of UserInfo call
833 * @param c composite context returned by send request routine
834 * @param mem_ctx memory context of this call
835 * @param r pointer to a structure containing arguments and result of this call
838 NTSTATUS
libnet_UserInfo_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
839 struct libnet_UserInfo
*r
)
842 struct user_info_state
*s
;
844 status
= composite_wait(c
);
846 if (NT_STATUS_IS_OK(status
) && r
!= NULL
) {
847 struct samr_UserInfo21
*info
;
849 s
= talloc_get_type_abort(c
->private_data
, struct user_info_state
);
850 info
= &s
->userinfo
.out
.info
.info21
;
852 r
->out
.user_sid
= dom_sid_add_rid(mem_ctx
, s
->ctx
->samr
.sid
, info
->rid
);
853 r
->out
.primary_group_sid
= dom_sid_add_rid(mem_ctx
, s
->ctx
->samr
.sid
, info
->primary_gid
);
856 r
->out
.account_name
= talloc_steal(mem_ctx
, info
->account_name
.string
);
857 r
->out
.full_name
= talloc_steal(mem_ctx
, info
->full_name
.string
);
858 r
->out
.description
= talloc_steal(mem_ctx
, info
->description
.string
);
859 r
->out
.home_directory
= talloc_steal(mem_ctx
, info
->home_directory
.string
);
860 r
->out
.home_drive
= talloc_steal(mem_ctx
, info
->home_drive
.string
);
861 r
->out
.comment
= talloc_steal(mem_ctx
, info
->comment
.string
);
862 r
->out
.logon_script
= talloc_steal(mem_ctx
, info
->logon_script
.string
);
863 r
->out
.profile_path
= talloc_steal(mem_ctx
, info
->profile_path
.string
);
865 /* time fields (allocation) */
866 r
->out
.acct_expiry
= talloc(mem_ctx
, struct timeval
);
867 r
->out
.allow_password_change
= talloc(mem_ctx
, struct timeval
);
868 r
->out
.force_password_change
= talloc(mem_ctx
, struct timeval
);
869 r
->out
.last_logon
= talloc(mem_ctx
, struct timeval
);
870 r
->out
.last_logoff
= talloc(mem_ctx
, struct timeval
);
871 r
->out
.last_password_change
= talloc(mem_ctx
, struct timeval
);
873 /* time fields (converting) */
874 nttime_to_timeval(r
->out
.acct_expiry
, info
->acct_expiry
);
875 nttime_to_timeval(r
->out
.allow_password_change
, info
->allow_password_change
);
876 nttime_to_timeval(r
->out
.force_password_change
, info
->force_password_change
);
877 nttime_to_timeval(r
->out
.last_logon
, info
->last_logon
);
878 nttime_to_timeval(r
->out
.last_logoff
, info
->last_logoff
);
879 nttime_to_timeval(r
->out
.last_password_change
, info
->last_password_change
);
881 /* flag and number fields */
882 r
->out
.acct_flags
= info
->acct_flags
;
884 r
->out
.error_string
= talloc_strdup(mem_ctx
, "Success");
887 r
->out
.error_string
= talloc_asprintf(mem_ctx
, "Error: %s", nt_errstr(status
));
896 * Synchronous version of UserInfo call
898 * @param ctx initialised libnet context
899 * @param mem_ctx memory context of this call
900 * @param r pointer to a structure containing arguments and result of this call
903 NTSTATUS
libnet_UserInfo(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
904 struct libnet_UserInfo
*r
)
906 struct composite_context
*c
;
908 c
= libnet_UserInfo_send(ctx
, mem_ctx
, r
, NULL
);
909 return libnet_UserInfo_recv(c
, mem_ctx
, r
);
913 struct userlist_state
{
914 struct libnet_context
*ctx
;
915 const char *domain_name
;
916 struct lsa_DomainInfo dominfo
;
918 uint32_t resume_index
;
919 struct userlist
*users
;
922 struct libnet_DomainOpen domain_open
;
923 struct lsa_QueryInfoPolicy query_domain
;
924 struct samr_EnumDomainUsers user_list
;
926 void (*monitor_fn
)(struct monitor_msg
*);
930 static void continue_lsa_domain_opened(struct composite_context
*ctx
);
931 static void continue_domain_queried(struct tevent_req
*subreq
);
932 static void continue_samr_domain_opened(struct composite_context
*ctx
);
933 static void continue_users_enumerated(struct tevent_req
*subreq
);
937 * Sends request to list (enumerate) user accounts
939 * @param ctx initialised libnet context
940 * @param mem_ctx memory context of this call
941 * @param r pointer to structure containing arguments and results of this call
942 * @param monitor function pointer for receiving monitor messages
943 * @return compostite context of this request
945 struct composite_context
* libnet_UserList_send(struct libnet_context
*ctx
,
947 struct libnet_UserList
*r
,
948 void (*monitor
)(struct monitor_msg
*))
950 struct composite_context
*c
;
951 struct userlist_state
*s
;
952 struct tevent_req
*subreq
;
953 bool prereq_met
= false;
955 /* composite context allocation and setup */
956 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
957 if (c
== NULL
) return NULL
;
959 s
= talloc_zero(c
, struct userlist_state
);
960 if (composite_nomem(s
, c
)) return c
;
964 /* store the arguments in the state structure */
966 s
->page_size
= r
->in
.page_size
;
967 s
->resume_index
= r
->in
.resume_index
;
968 s
->domain_name
= talloc_strdup(c
, r
->in
.domain_name
);
969 s
->monitor_fn
= monitor
;
971 /* make sure we have lsa domain handle before doing anything */
972 prereq_met
= lsa_domain_opened(ctx
, c
, s
->domain_name
, &c
, &s
->domain_open
,
973 continue_lsa_domain_opened
, monitor
);
974 if (!prereq_met
) return c
;
976 /* prepare arguments of QueryDomainInfo call */
977 s
->query_domain
.in
.handle
= &ctx
->lsa
.handle
;
978 s
->query_domain
.in
.level
= LSA_POLICY_INFO_DOMAIN
;
979 s
->query_domain
.out
.info
= talloc_zero(c
, union lsa_PolicyInformation
*);
980 if (composite_nomem(s
->query_domain
.out
.info
, c
)) return c
;
982 /* send the request */
983 subreq
= dcerpc_lsa_QueryInfoPolicy_r_send(s
, c
->event_ctx
,
984 ctx
->lsa
.pipe
->binding_handle
,
986 if (composite_nomem(subreq
, c
)) return c
;
988 tevent_req_set_callback(subreq
, continue_domain_queried
, c
);
994 * Stage 0.5 (optional): receive lsa domain handle and send
995 * request to query domain info
997 static void continue_lsa_domain_opened(struct composite_context
*ctx
)
999 struct composite_context
*c
;
1000 struct userlist_state
*s
;
1001 struct tevent_req
*subreq
;
1003 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
1004 s
= talloc_get_type_abort(c
->private_data
, struct userlist_state
);
1006 /* receive lsa domain handle */
1007 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
1008 if (!composite_is_ok(c
)) return;
1010 /* prepare arguments of QueryDomainInfo call */
1011 s
->query_domain
.in
.handle
= &s
->ctx
->lsa
.handle
;
1012 s
->query_domain
.in
.level
= LSA_POLICY_INFO_DOMAIN
;
1013 s
->query_domain
.out
.info
= talloc_zero(c
, union lsa_PolicyInformation
*);
1014 if (composite_nomem(s
->query_domain
.out
.info
, c
)) return;
1016 /* send the request */
1017 subreq
= dcerpc_lsa_QueryInfoPolicy_r_send(s
, c
->event_ctx
,
1018 s
->ctx
->lsa
.pipe
->binding_handle
,
1020 if (composite_nomem(subreq
, c
)) return;
1022 tevent_req_set_callback(subreq
, continue_domain_queried
, c
);
1027 * Stage 1: receive domain info and request to enum users,
1028 * provided a valid samr handle is opened
1030 static void continue_domain_queried(struct tevent_req
*subreq
)
1032 struct composite_context
*c
;
1033 struct userlist_state
*s
;
1034 bool prereq_met
= false;
1036 c
= tevent_req_callback_data(subreq
, struct composite_context
);
1037 s
= talloc_get_type_abort(c
->private_data
, struct userlist_state
);
1039 /* receive result of rpc request */
1040 c
->status
= dcerpc_lsa_QueryInfoPolicy_r_recv(subreq
, s
);
1041 TALLOC_FREE(subreq
);
1042 if (!composite_is_ok(c
)) return;
1044 /* get the returned domain info */
1045 s
->dominfo
= (*s
->query_domain
.out
.info
)->domain
;
1047 /* make sure we have samr domain handle before continuing */
1048 prereq_met
= samr_domain_opened(s
->ctx
, c
, s
->domain_name
, &c
, &s
->domain_open
,
1049 continue_samr_domain_opened
, s
->monitor_fn
);
1050 if (!prereq_met
) return;
1052 /* prepare arguments of EnumDomainUsers call */
1053 s
->user_list
.in
.domain_handle
= &s
->ctx
->samr
.handle
;
1054 s
->user_list
.in
.max_size
= s
->page_size
;
1055 s
->user_list
.in
.resume_handle
= &s
->resume_index
;
1056 s
->user_list
.in
.acct_flags
= ACB_NORMAL
;
1057 s
->user_list
.out
.resume_handle
= &s
->resume_index
;
1058 s
->user_list
.out
.num_entries
= talloc(s
, uint32_t);
1059 if (composite_nomem(s
->user_list
.out
.num_entries
, c
)) return;
1060 s
->user_list
.out
.sam
= talloc(s
, struct samr_SamArray
*);
1061 if (composite_nomem(s
->user_list
.out
.sam
, c
)) return;
1063 /* send the request */
1064 subreq
= dcerpc_samr_EnumDomainUsers_r_send(s
, c
->event_ctx
,
1065 s
->ctx
->samr
.pipe
->binding_handle
,
1067 if (composite_nomem(subreq
, c
)) return;
1069 tevent_req_set_callback(subreq
, continue_users_enumerated
, c
);
1074 * Stage 1.5 (optional): receive samr domain handle
1075 * and request to enumerate accounts
1077 static void continue_samr_domain_opened(struct composite_context
*ctx
)
1079 struct composite_context
*c
;
1080 struct userlist_state
*s
;
1081 struct tevent_req
*subreq
;
1083 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
1084 s
= talloc_get_type_abort(c
->private_data
, struct userlist_state
);
1086 /* receive samr domain handle */
1087 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
1088 if (!composite_is_ok(c
)) return;
1090 /* prepare arguments of EnumDomainUsers call */
1091 s
->user_list
.in
.domain_handle
= &s
->ctx
->samr
.handle
;
1092 s
->user_list
.in
.max_size
= s
->page_size
;
1093 s
->user_list
.in
.resume_handle
= &s
->resume_index
;
1094 s
->user_list
.in
.acct_flags
= ACB_NORMAL
;
1095 s
->user_list
.out
.resume_handle
= &s
->resume_index
;
1096 s
->user_list
.out
.sam
= talloc(s
, struct samr_SamArray
*);
1097 if (composite_nomem(s
->user_list
.out
.sam
, c
)) return;
1098 s
->user_list
.out
.num_entries
= talloc(s
, uint32_t);
1099 if (composite_nomem(s
->user_list
.out
.num_entries
, c
)) return;
1101 /* send the request */
1102 subreq
= dcerpc_samr_EnumDomainUsers_r_send(s
, c
->event_ctx
,
1103 s
->ctx
->samr
.pipe
->binding_handle
,
1105 if (composite_nomem(subreq
, c
)) return;
1107 tevent_req_set_callback(subreq
, continue_users_enumerated
, c
);
1112 * Stage 2: receive enumerated users and their rids
1114 static void continue_users_enumerated(struct tevent_req
*subreq
)
1116 struct composite_context
*c
;
1117 struct userlist_state
*s
;
1120 c
= tevent_req_callback_data(subreq
, struct composite_context
);
1121 s
= talloc_get_type_abort(c
->private_data
, struct userlist_state
);
1123 /* receive result of rpc request */
1124 c
->status
= dcerpc_samr_EnumDomainUsers_r_recv(subreq
, s
);
1125 TALLOC_FREE(subreq
);
1126 if (!composite_is_ok(c
)) return;
1128 /* get the actual status of the rpc call result
1129 (instead of rpc layer status) */
1130 c
->status
= s
->user_list
.out
.result
;
1132 /* we're interested in status "ok" as well as two
1133 enum-specific status codes */
1134 if (NT_STATUS_IS_OK(c
->status
) ||
1135 NT_STATUS_EQUAL(c
->status
, STATUS_MORE_ENTRIES
) ||
1136 NT_STATUS_EQUAL(c
->status
, NT_STATUS_NO_MORE_ENTRIES
)) {
1138 /* get enumerated accounts counter and resume handle (the latter allows
1139 making subsequent call to continue enumeration) */
1140 s
->resume_index
= *s
->user_list
.out
.resume_handle
;
1141 s
->count
= *s
->user_list
.out
.num_entries
;
1143 /* prepare returned user accounts array */
1144 s
->users
= talloc_array(c
, struct userlist
, (*s
->user_list
.out
.sam
)->count
);
1145 if (composite_nomem(s
->users
, c
)) return;
1147 for (i
= 0; i
< (*s
->user_list
.out
.sam
)->count
; i
++) {
1148 struct dom_sid
*user_sid
;
1149 struct samr_SamEntry
*entry
= &(*s
->user_list
.out
.sam
)->entries
[i
];
1150 struct dom_sid
*domain_sid
= (*s
->query_domain
.out
.info
)->domain
.sid
;
1152 /* construct user sid from returned rid and queried domain sid */
1153 user_sid
= dom_sid_add_rid(c
, domain_sid
, entry
->idx
);
1154 if (composite_nomem(user_sid
, c
)) return;
1157 s
->users
[i
].username
= talloc_strdup(s
->users
, entry
->name
.string
);
1158 if (composite_nomem(s
->users
[i
].username
, c
)) return;
1161 s
->users
[i
].sid
= dom_sid_string(s
->users
, user_sid
);
1162 if (composite_nomem(s
->users
[i
].sid
, c
)) return;
1170 /* something went wrong */
1171 composite_error(c
, c
->status
);
1178 * Receive result of UserList call
1180 * @param c composite context returned by send request routine
1181 * @param mem_ctx memory context of this call
1182 * @param r pointer to structure containing arguments and result of this call
1185 NTSTATUS
libnet_UserList_recv(struct composite_context
* c
, TALLOC_CTX
*mem_ctx
,
1186 struct libnet_UserList
*r
)
1189 struct userlist_state
*s
;
1191 if (c
== NULL
|| mem_ctx
== NULL
|| r
== NULL
) {
1193 return NT_STATUS_INVALID_PARAMETER
;
1196 status
= composite_wait(c
);
1197 if (NT_STATUS_IS_OK(status
) ||
1198 NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
) ||
1199 NT_STATUS_EQUAL(status
, NT_STATUS_NO_MORE_ENTRIES
)) {
1201 s
= talloc_get_type_abort(c
->private_data
, struct userlist_state
);
1203 /* get results from composite context */
1204 r
->out
.count
= s
->count
;
1205 r
->out
.resume_index
= s
->resume_index
;
1206 r
->out
.users
= talloc_steal(mem_ctx
, s
->users
);
1208 if (NT_STATUS_IS_OK(status
)) {
1209 r
->out
.error_string
= talloc_strdup(mem_ctx
, "Success");
1211 /* success, but we're not done yet */
1212 r
->out
.error_string
= talloc_asprintf(mem_ctx
, "Success (status: %s)",
1217 r
->out
.error_string
= talloc_asprintf(mem_ctx
, "Error: %s", nt_errstr(status
));
1226 * Synchronous version of UserList call
1228 * @param ctx initialised libnet context
1229 * @param mem_ctx memory context of this call
1230 * @param r pointer to structure containing arguments and result of this call
1233 NTSTATUS
libnet_UserList(struct libnet_context
*ctx
,
1234 TALLOC_CTX
*mem_ctx
,
1235 struct libnet_UserList
*r
)
1237 struct composite_context
*c
;
1239 c
= libnet_UserList_send(ctx
, mem_ctx
, r
, NULL
);
1240 return libnet_UserList_recv(c
, mem_ctx
, r
);