2 Unix SMB/CIFS implementation.
4 Copyright (C) Rafal Szczesniak <mimir@samba.org> 2005
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "libnet/libnet.h"
24 #include "libcli/composite/composite.h"
25 #include "auth/credentials/credentials.h"
26 #include "librpc/ndr/libndr.h"
27 #include "librpc/gen_ndr/samr.h"
28 #include "librpc/gen_ndr/ndr_samr_c.h"
29 #include "librpc/gen_ndr/lsa.h"
30 #include "librpc/gen_ndr/ndr_lsa_c.h"
31 #include "libcli/security/security.h"
35 * Verify, before actually doing anything with user accounts, whether
36 * required domain is already opened and thus ready for operation.
37 * If it is not, or if the opened domain is not the one requested, open
38 * the requested domain.
40 static struct composite_context
* domain_opened(struct libnet_context
*ctx
,
41 const char *domain_name
,
42 struct composite_context
*parent_ctx
,
43 struct libnet_DomainOpen
*domain_open
,
44 void (*continue_fn
)(struct composite_context
*),
45 void (*monitor
)(struct monitor_msg
*))
47 struct composite_context
*domopen_req
;
49 if (domain_name
== NULL
) {
51 * Try to guess the domain name from credentials,
52 * if it's not been explicitly specified.
55 if (policy_handle_empty(&ctx
->samr
.handle
)) {
56 domain_open
->in
.domain_name
= cli_credentials_get_domain(ctx
->cred
);
57 domain_open
->in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
60 composite_error(parent_ctx
, NT_STATUS_INVALID_PARAMETER
);
66 * The domain name has been specified, so check whether the same
67 * domain is already opened. If it is - just return NULL. Start
68 * opening a new domain otherwise.
71 if (policy_handle_empty(&ctx
->samr
.handle
) ||
72 !strequal(domain_name
, ctx
->samr
.name
)) {
73 domain_open
->in
.domain_name
= domain_name
;
74 domain_open
->in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
77 /* domain has already been opened and it's the same domain
83 /* send request to open the domain */
84 domopen_req
= libnet_DomainOpen_send(ctx
, domain_open
, monitor
);
85 if (composite_nomem(domopen_req
, parent_ctx
)) return parent_ctx
;
87 composite_continue(parent_ctx
, domopen_req
, continue_fn
, parent_ctx
);
92 struct create_user_state
{
93 struct libnet_CreateUser r
;
94 struct libnet_DomainOpen domain_open
;
95 struct libnet_rpc_useradd user_add
;
96 struct libnet_context
*ctx
;
98 /* information about the progress */
99 void (*monitor_fn
)(struct monitor_msg
*);
103 static void continue_rpc_useradd(struct composite_context
*ctx
);
104 static void continue_domain_open_create(struct composite_context
*ctx
);
108 * Sends request to create user account
110 * @param ctx initialised libnet context
111 * @param mem_ctx memory context of this call
112 * @param r pointer to a structure containing arguments and results of this call
113 * @param monitor function pointer for receiving monitor messages
114 * @return compostite context of this request
116 struct composite_context
* libnet_CreateUser_send(struct libnet_context
*ctx
,
118 struct libnet_CreateUser
*r
,
119 void (*monitor
)(struct monitor_msg
*))
121 struct composite_context
*c
;
122 struct create_user_state
*s
;
123 struct composite_context
*create_req
;
124 struct composite_context
*prereq_ctx
;
126 /* composite context allocation and setup */
127 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
128 if (c
== NULL
) return NULL
;
130 s
= talloc_zero(c
, struct create_user_state
);
131 if (composite_nomem(s
, c
)) return c
;
135 /* store arguments in the state structure */
138 ZERO_STRUCT(s
->r
.out
);
140 /* prerequisite: make sure the domain is opened */
141 prereq_ctx
= samr_domain_opened(ctx
, s
->r
.in
.domain_name
, c
, &s
->domain_open
,
142 continue_domain_open_create
, monitor
);
143 if (prereq_ctx
) return prereq_ctx
;
145 /* prepare arguments for useradd call */
146 s
->user_add
.in
.username
= r
->in
.user_name
;
147 s
->user_add
.in
.domain_handle
= ctx
->samr
.handle
;
149 /* send the request */
150 create_req
= libnet_rpc_useradd_send(ctx
->samr
.pipe
, &s
->user_add
, monitor
);
151 if (composite_nomem(create_req
, c
)) return c
;
153 /* set the next stage */
154 composite_continue(c
, create_req
, continue_rpc_useradd
, c
);
160 * Stage 0.5 (optional): receive result of domain open request
161 * and send useradd request
163 static void continue_domain_open_create(struct composite_context
*ctx
)
165 struct composite_context
*c
;
166 struct create_user_state
*s
;
167 struct composite_context
*create_req
;
168 struct monitor_msg msg
;
170 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
171 s
= talloc_get_type(c
->private_data
, struct create_user_state
);
173 /* receive result of DomainOpen call */
174 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
175 if (!composite_is_ok(c
)) return;
177 /* send monitor message */
178 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
180 /* prepare arguments for useradd call */
181 s
->user_add
.in
.username
= s
->r
.in
.user_name
;
182 s
->user_add
.in
.domain_handle
= s
->ctx
->samr
.handle
;
184 /* send the request */
185 create_req
= libnet_rpc_useradd_send(s
->ctx
->samr
.pipe
, &s
->user_add
, s
->monitor_fn
);
186 if (composite_nomem(create_req
, c
)) return;
188 /* set the next stage */
189 composite_continue(c
, create_req
, continue_rpc_useradd
, c
);
194 * Stage 1: receive result of useradd call
196 static void continue_rpc_useradd(struct composite_context
*ctx
)
198 struct composite_context
*c
;
199 struct create_user_state
*s
;
200 struct monitor_msg msg
;
202 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
203 s
= talloc_get_type(c
->private_data
, struct create_user_state
);
205 /* receive result of the call */
206 c
->status
= libnet_rpc_useradd_recv(ctx
, c
, &s
->user_add
);
207 if (!composite_is_ok(c
)) return;
209 /* send monitor message */
210 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
218 * Receive result of CreateUser call
220 * @param c composite context returned by send request routine
221 * @param mem_ctx memory context of this call
222 * @param r pointer to a structure containing arguments and result of this call
225 NTSTATUS
libnet_CreateUser_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
226 struct libnet_CreateUser
*r
)
229 struct create_user_state
*s
;
231 r
->out
.error_string
= NULL
;
233 /* wait for result of async request and check status code */
234 status
= composite_wait(c
);
235 if (!NT_STATUS_IS_OK(status
)) {
236 s
= talloc_get_type(c
->private_data
, struct create_user_state
);
237 r
->out
.error_string
= talloc_strdup(mem_ctx
, nt_errstr(status
));
245 * Synchronous version of CreateUser call
247 * @param ctx initialised libnet context
248 * @param mem_ctx memory context of this call
249 * @param r pointer to a structure containing arguments and result of this call
252 NTSTATUS
libnet_CreateUser(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
253 struct libnet_CreateUser
*r
)
255 struct composite_context
*c
;
257 c
= libnet_CreateUser_send(ctx
, mem_ctx
, r
, NULL
);
258 return libnet_CreateUser_recv(c
, mem_ctx
, r
);
262 struct delete_user_state
{
263 struct libnet_DeleteUser r
;
264 struct libnet_context
*ctx
;
265 struct libnet_DomainOpen domain_open
;
266 struct libnet_rpc_userdel user_del
;
268 /* information about the progress */
269 void (*monitor_fn
)(struct monitor_msg
*);
273 static void continue_rpc_userdel(struct composite_context
*ctx
);
274 static void continue_domain_open_delete(struct composite_context
*ctx
);
278 * Sends request to delete user account
280 * @param ctx initialised libnet context
281 * @param mem_ctx memory context of this call
282 * @param r pointer to structure containing arguments and result of this call
283 * @param monitor function pointer for receiving monitor messages
285 struct composite_context
*libnet_DeleteUser_send(struct libnet_context
*ctx
,
287 struct libnet_DeleteUser
*r
,
288 void (*monitor
)(struct monitor_msg
*))
290 struct composite_context
*c
;
291 struct delete_user_state
*s
;
292 struct composite_context
*delete_req
;
293 struct composite_context
*prereq_ctx
;
295 /* composite context allocation and setup */
296 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
297 if (c
== NULL
) return NULL
;
299 s
= talloc_zero(c
, struct delete_user_state
);
300 if (composite_nomem(s
, c
)) return c
;
304 /* store arguments in state structure */
307 ZERO_STRUCT(s
->r
.out
);
309 /* prerequisite: make sure the domain is opened before proceeding */
310 prereq_ctx
= samr_domain_opened(ctx
, s
->r
.in
.domain_name
, c
, &s
->domain_open
,
311 continue_domain_open_delete
, monitor
);
312 if (prereq_ctx
) return prereq_ctx
;
314 /* prepare arguments for userdel call */
315 s
->user_del
.in
.username
= r
->in
.user_name
;
316 s
->user_del
.in
.domain_handle
= ctx
->samr
.handle
;
319 delete_req
= libnet_rpc_userdel_send(ctx
->samr
.pipe
, &s
->user_del
, monitor
);
320 if (composite_nomem(delete_req
, c
)) return c
;
322 /* set the next stage */
323 composite_continue(c
, delete_req
, continue_rpc_userdel
, c
);
329 * Stage 0.5 (optional): receive result of domain open request
330 * and send useradd request
332 static void continue_domain_open_delete(struct composite_context
*ctx
)
334 struct composite_context
*c
;
335 struct delete_user_state
*s
;
336 struct composite_context
*delete_req
;
337 struct monitor_msg msg
;
339 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
340 s
= talloc_get_type(c
->private_data
, struct delete_user_state
);
342 /* receive result of DomainOpen call */
343 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
344 if (!composite_is_ok(c
)) return;
346 /* send monitor message */
347 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
349 /* prepare arguments for userdel call */
350 s
->user_del
.in
.username
= s
->r
.in
.user_name
;
351 s
->user_del
.in
.domain_handle
= s
->ctx
->samr
.handle
;
354 delete_req
= libnet_rpc_userdel_send(s
->ctx
->samr
.pipe
, &s
->user_del
, s
->monitor_fn
);
355 if (composite_nomem(delete_req
, c
)) return;
357 /* set the next stage */
358 composite_continue(c
, delete_req
, continue_rpc_userdel
, c
);
363 * Stage 1: receive result of userdel call and finish the composite function
365 static void continue_rpc_userdel(struct composite_context
*ctx
)
367 struct composite_context
*c
;
368 struct delete_user_state
*s
;
369 struct monitor_msg msg
;
371 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
372 s
= talloc_get_type(c
->private_data
, struct delete_user_state
);
374 /* receive result of userdel call */
375 c
->status
= libnet_rpc_userdel_recv(ctx
, c
, &s
->user_del
);
376 if (!composite_is_ok(c
)) return;
378 /* send monitor message */
379 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
387 * Receives result of asynchronous DeleteUser call
389 * @param c composite context returned by async DeleteUser call
390 * @param mem_ctx memory context of this call
391 * @param r pointer to structure containing arguments and result
393 NTSTATUS
libnet_DeleteUser_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
394 struct libnet_DeleteUser
*r
)
397 struct delete_user_state
*s
;
399 r
->out
.error_string
= NULL
;
401 /* wait for result of async request and check status code */
402 status
= composite_wait(c
);
403 if (!NT_STATUS_IS_OK(status
)) {
404 s
= talloc_get_type(c
->private_data
, struct delete_user_state
);
405 r
->out
.error_string
= talloc_steal(mem_ctx
, s
->r
.out
.error_string
);
413 * Synchronous version of DeleteUser call
415 * @param ctx initialised libnet context
416 * @param mem_ctx memory context of this call
417 * @param r pointer to structure containing arguments and result
419 NTSTATUS
libnet_DeleteUser(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
420 struct libnet_DeleteUser
*r
)
422 struct composite_context
*c
;
424 c
= libnet_DeleteUser_send(ctx
, mem_ctx
, r
, NULL
);
425 return libnet_DeleteUser_recv(c
, mem_ctx
, r
);
429 struct modify_user_state
{
430 struct libnet_ModifyUser r
;
431 struct libnet_context
*ctx
;
432 struct libnet_DomainOpen domain_open
;
433 struct libnet_rpc_userinfo user_info
;
434 struct libnet_rpc_usermod user_mod
;
436 void (*monitor_fn
)(struct monitor_msg
*);
440 static void continue_rpc_usermod(struct composite_context
*ctx
);
441 static void continue_domain_open_modify(struct composite_context
*ctx
);
442 static NTSTATUS
set_user_changes(TALLOC_CTX
*mem_ctx
, struct usermod_change
*mod
,
443 struct libnet_rpc_userinfo
*info
, struct libnet_ModifyUser
*r
);
444 static void continue_rpc_userinfo(struct composite_context
*ctx
);
448 * Sends request to modify user account
450 * @param ctx initialised libnet context
451 * @param mem_ctx memory context of this call
452 * @param r pointer to structure containing arguments and result of this call
453 * @param monitor function pointer for receiving monitor messages
455 struct composite_context
*libnet_ModifyUser_send(struct libnet_context
*ctx
,
457 struct libnet_ModifyUser
*r
,
458 void (*monitor
)(struct monitor_msg
*))
460 const uint16_t level
= 21;
461 struct composite_context
*c
;
462 struct modify_user_state
*s
;
463 struct composite_context
*prereq_ctx
;
464 struct composite_context
*userinfo_req
;
466 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
467 if (c
== NULL
) return NULL
;
469 s
= talloc_zero(c
, struct modify_user_state
);
470 if (composite_nomem(s
, c
)) return c
;
477 prereq_ctx
= samr_domain_opened(ctx
, s
->r
.in
.domain_name
, c
, &s
->domain_open
,
478 continue_domain_open_modify
, monitor
);
479 if (prereq_ctx
) return prereq_ctx
;
481 s
->user_info
.in
.username
= r
->in
.user_name
;
482 s
->user_info
.in
.domain_handle
= ctx
->samr
.handle
;
483 s
->user_info
.in
.level
= level
;
485 userinfo_req
= libnet_rpc_userinfo_send(ctx
->samr
.pipe
, &s
->user_info
, monitor
);
486 if (composite_nomem(userinfo_req
, c
)) return c
;
488 composite_continue(c
, userinfo_req
, continue_rpc_userinfo
, c
);
494 * Stage 0.5 (optional): receive result of domain open request
495 * and send userinfo request
497 static void continue_domain_open_modify(struct composite_context
*ctx
)
499 const uint16_t level
= 21;
500 struct composite_context
*c
;
501 struct modify_user_state
*s
;
502 struct composite_context
*userinfo_req
;
503 struct monitor_msg msg
;
505 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
506 s
= talloc_get_type(c
->private_data
, struct modify_user_state
);
508 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
509 if (!composite_is_ok(c
)) return;
511 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
513 s
->user_info
.in
.domain_handle
= s
->ctx
->samr
.handle
;
514 s
->user_info
.in
.username
= s
->r
.in
.user_name
;
515 s
->user_info
.in
.level
= level
;
517 userinfo_req
= libnet_rpc_userinfo_send(s
->ctx
->samr
.pipe
, &s
->user_info
, s
->monitor_fn
);
518 if (composite_nomem(userinfo_req
, c
)) return;
520 composite_continue(c
, userinfo_req
, continue_rpc_userinfo
, c
);
525 * Stage 1: receive result of userinfo call, prepare user changes
526 * (set the fields a caller required to change) and send usermod request
528 static void continue_rpc_userinfo(struct composite_context
*ctx
)
530 struct composite_context
*c
;
531 struct modify_user_state
*s
;
532 struct composite_context
*usermod_req
;
534 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
535 s
= talloc_get_type(c
->private_data
, struct modify_user_state
);
537 c
->status
= libnet_rpc_userinfo_recv(ctx
, c
, &s
->user_info
);
538 if (!composite_is_ok(c
)) return;
540 s
->user_mod
.in
.domain_handle
= s
->ctx
->samr
.handle
;
541 s
->user_mod
.in
.username
= s
->r
.in
.user_name
;
543 c
->status
= set_user_changes(c
, &s
->user_mod
.in
.change
, &s
->user_info
, &s
->r
);
545 usermod_req
= libnet_rpc_usermod_send(s
->ctx
->samr
.pipe
, &s
->user_mod
, s
->monitor_fn
);
546 if (composite_nomem(usermod_req
, c
)) return;
548 composite_continue(c
, usermod_req
, continue_rpc_usermod
, c
);
553 * Prepare user changes: compare userinfo result to requested changes and
554 * set the field values and flags accordingly for user modify call
556 static NTSTATUS
set_user_changes(TALLOC_CTX
*mem_ctx
, struct usermod_change
*mod
,
557 struct libnet_rpc_userinfo
*info
, struct libnet_ModifyUser
*r
)
559 struct samr_UserInfo21
*user
;
561 if (mod
== NULL
|| info
== NULL
|| r
== NULL
|| info
->in
.level
!= 21) {
562 return NT_STATUS_INVALID_PARAMETER
;
565 user
= &info
->out
.info
.info21
;
566 mod
->fields
= 0; /* reset flag field before setting individual flags */
568 /* account name change */
569 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, account_name
, USERMOD_FIELD_ACCOUNT_NAME
);
571 /* full name change */
572 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, full_name
, USERMOD_FIELD_FULL_NAME
);
574 /* description change */
575 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, description
, USERMOD_FIELD_DESCRIPTION
);
578 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, comment
, USERMOD_FIELD_COMMENT
);
580 /* home directory change */
581 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, home_directory
, USERMOD_FIELD_HOME_DIRECTORY
);
583 /* home drive change */
584 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, home_drive
, USERMOD_FIELD_HOME_DRIVE
);
586 /* logon script change */
587 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, logon_script
, USERMOD_FIELD_LOGON_SCRIPT
);
589 /* profile path change */
590 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, profile_path
, USERMOD_FIELD_PROFILE_PATH
);
592 /* account expiry change */
593 SET_FIELD_NTTIME(r
->in
, user
, mod
, acct_expiry
, USERMOD_FIELD_ACCT_EXPIRY
);
600 * Stage 2: receive result of usermod request and finish the composite function
602 static void continue_rpc_usermod(struct composite_context
*ctx
)
604 struct composite_context
*c
;
605 struct modify_user_state
*s
;
606 struct monitor_msg msg
;
608 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
609 s
= talloc_get_type(c
->private_data
, struct modify_user_state
);
611 c
->status
= libnet_rpc_usermod_recv(ctx
, c
, &s
->user_mod
);
612 if (!composite_is_ok(c
)) return;
614 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
620 * Receive result of ModifyUser call
622 * @param c composite context returned by send request routine
623 * @param mem_ctx memory context of this call
624 * @param r pointer to a structure containing arguments and result of this call
627 NTSTATUS
libnet_ModifyUser_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
628 struct libnet_ModifyUser
*r
)
630 NTSTATUS status
= composite_wait(c
);
636 * Synchronous version of ModifyUser call
638 * @param ctx initialised libnet context
639 * @param mem_ctx memory context of this call
640 * @param r pointer to a structure containing arguments and result of this call
643 NTSTATUS
libnet_ModifyUser(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
644 struct libnet_ModifyUser
*r
)
646 struct composite_context
*c
;
648 c
= libnet_ModifyUser_send(ctx
, mem_ctx
, r
, NULL
);
649 return libnet_ModifyUser_recv(c
, mem_ctx
, r
);
653 struct user_info_state
{
654 struct libnet_context
*ctx
;
655 const char *domain_name
;
656 const char *user_name
;
657 struct libnet_LookupName lookup
;
658 struct libnet_DomainOpen domopen
;
659 struct libnet_rpc_userinfo userinfo
;
661 /* information about the progress */
662 void (*monitor_fn
)(struct monitor_msg
*);
666 static void continue_name_found(struct composite_context
*ctx
);
667 static void continue_domain_open_info(struct composite_context
*ctx
);
668 static void continue_info_received(struct composite_context
*ctx
);
672 * Sends request to get user account information
674 * @param ctx initialised libnet context
675 * @param mem_ctx memory context of this call
676 * @param r pointer to a structure containing arguments and results of this call
677 * @param monitor function pointer for receiving monitor messages
678 * @return compostite context of this request
680 struct composite_context
* libnet_UserInfo_send(struct libnet_context
*ctx
,
682 struct libnet_UserInfo
*r
,
683 void (*monitor
)(struct monitor_msg
*))
685 struct composite_context
*c
;
686 struct user_info_state
*s
;
687 struct composite_context
*prereq_ctx
;
688 struct composite_context
*lookup_req
;
690 /* composite context allocation and setup */
691 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
692 if (c
== NULL
) return NULL
;
694 s
= talloc_zero(c
, struct user_info_state
);
695 if (composite_nomem(s
, c
)) return c
;
699 /* store arguments in the state structure */
700 s
->monitor_fn
= monitor
;
702 s
->domain_name
= talloc_strdup(c
, r
->in
.domain_name
);
703 s
->user_name
= talloc_strdup(c
, r
->in
.user_name
);
705 /* prerequisite: make sure the domain is opened */
706 prereq_ctx
= samr_domain_opened(ctx
, s
->domain_name
, c
, &s
->domopen
,
707 continue_domain_open_info
, monitor
);
708 if (prereq_ctx
) return prereq_ctx
;
710 /* prepare arguments for LookupName call */
711 s
->lookup
.in
.domain_name
= s
->domain_name
;
712 s
->lookup
.in
.name
= s
->user_name
;
714 /* send the request */
715 lookup_req
= libnet_LookupName_send(ctx
, c
, &s
->lookup
, s
->monitor_fn
);
716 if (composite_nomem(lookup_req
, c
)) return c
;
718 /* set the next stage */
719 composite_continue(c
, lookup_req
, continue_name_found
, c
);
725 * Stage 0.5 (optional): receive result of domain open request
726 * and send LookupName request
728 static void continue_domain_open_info(struct composite_context
*ctx
)
730 struct composite_context
*c
;
731 struct user_info_state
*s
;
732 struct composite_context
*lookup_req
;
733 struct monitor_msg msg
;
735 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
736 s
= talloc_get_type(c
->private_data
, struct user_info_state
);
738 /* receive result of DomainOpen call */
739 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domopen
);
740 if (!composite_is_ok(c
)) return;
742 /* send monitor message */
743 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
745 /* prepare arguments for LookupName call */
746 s
->lookup
.in
.domain_name
= s
->domain_name
;
747 s
->lookup
.in
.name
= s
->user_name
;
749 /* send the request */
750 lookup_req
= libnet_LookupName_send(s
->ctx
, c
, &s
->lookup
, s
->monitor_fn
);
751 if (composite_nomem(lookup_req
, c
)) return;
753 /* set the next stage */
754 composite_continue(c
, lookup_req
, continue_name_found
, c
);
759 * Stage 1: receive the name (if found) and send userinfo request
761 static void continue_name_found(struct composite_context
*ctx
)
763 struct composite_context
*c
;
764 struct user_info_state
*s
;
765 struct composite_context
*info_req
;
767 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
768 s
= talloc_get_type(c
->private_data
, struct user_info_state
);
770 /* receive result of LookupName call */
771 c
->status
= libnet_LookupName_recv(ctx
, c
, &s
->lookup
);
772 if (!composite_is_ok(c
)) return;
774 /* we're only interested in user accounts this time */
775 if (s
->lookup
.out
.sid_type
!= SID_NAME_USER
) {
776 composite_error(c
, NT_STATUS_NO_SUCH_USER
);
780 /* prepare arguments for UserInfo call */
781 s
->userinfo
.in
.domain_handle
= s
->ctx
->samr
.handle
;
782 s
->userinfo
.in
.sid
= s
->lookup
.out
.sidstr
;
783 s
->userinfo
.in
.level
= 21;
785 /* send the request */
786 info_req
= libnet_rpc_userinfo_send(s
->ctx
->samr
.pipe
, &s
->userinfo
, s
->monitor_fn
);
787 if (composite_nomem(info_req
, c
)) return;
789 /* set the next stage */
790 composite_continue(c
, info_req
, continue_info_received
, c
);
795 * Stage 2: receive user account information and finish the composite function
797 static void continue_info_received(struct composite_context
*ctx
)
799 struct composite_context
*c
;
800 struct user_info_state
*s
;
802 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
803 s
= talloc_get_type(c
->private_data
, struct user_info_state
);
805 /* receive result of userinfo call */
806 c
->status
= libnet_rpc_userinfo_recv(ctx
, c
, &s
->userinfo
);
807 if (!composite_is_ok(c
)) return;
814 * Receive result of UserInfo call
816 * @param c composite context returned by send request routine
817 * @param mem_ctx memory context of this call
818 * @param r pointer to a structure containing arguments and result of this call
821 NTSTATUS
libnet_UserInfo_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
822 struct libnet_UserInfo
*r
)
825 struct user_info_state
*s
;
827 status
= composite_wait(c
);
829 if (NT_STATUS_IS_OK(status
) && r
!= NULL
) {
830 struct samr_UserInfo21
*info
;
832 s
= talloc_get_type(c
->private_data
, struct user_info_state
);
833 info
= &s
->userinfo
.out
.info
.info21
;
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");
874 * Synchronous version of UserInfo call
876 * @param ctx initialised libnet context
877 * @param mem_ctx memory context of this call
878 * @param r pointer to a structure containing arguments and result of this call
881 NTSTATUS
libnet_UserInfo(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
882 struct libnet_UserInfo
*r
)
884 struct composite_context
*c
;
886 c
= libnet_UserInfo_send(ctx
, mem_ctx
, r
, NULL
);
887 return libnet_UserInfo_recv(c
, mem_ctx
, r
);
891 struct userlist_state
{
892 struct libnet_context
*ctx
;
893 const char *domain_name
;
894 struct lsa_DomainInfo dominfo
;
896 uint32_t resume_index
;
897 struct userlist
*users
;
900 struct libnet_DomainOpen domain_open
;
901 struct lsa_QueryInfoPolicy query_domain
;
902 struct samr_EnumDomainUsers user_list
;
904 void (*monitor_fn
)(struct monitor_msg
*);
908 static void continue_lsa_domain_opened(struct composite_context
*ctx
);
909 static void continue_domain_queried(struct rpc_request
*req
);
910 static void continue_samr_domain_opened(struct composite_context
*ctx
);
911 static void continue_users_enumerated(struct rpc_request
*req
);
915 * Sends request to list (enumerate) user accounts
917 * @param ctx initialised libnet context
918 * @param mem_ctx memory context of this call
919 * @param r pointer to a structure containing arguments and results of this call
920 * @param monitor function pointer for receiving monitor messages
921 * @return compostite context of this request
923 struct composite_context
* libnet_UserList_send(struct libnet_context
*ctx
,
925 struct libnet_UserList
*r
,
926 void (*monitor
)(struct monitor_msg
*))
928 struct composite_context
*c
;
929 struct userlist_state
*s
;
930 struct composite_context
*prereq_ctx
;
931 struct rpc_request
*query_req
;
933 /* composite context allocation and setup */
934 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
935 if (c
== NULL
) return NULL
;
937 s
= talloc_zero(c
, struct userlist_state
);
938 if (composite_nomem(s
, c
)) return c
;
942 /* store the arguments in the state structure */
944 s
->page_size
= r
->in
.page_size
;
945 s
->resume_index
= (uint32_t)r
->in
.resume_index
;
946 s
->domain_name
= talloc_strdup(c
, r
->in
.domain_name
);
947 s
->monitor_fn
= monitor
;
949 /* make sure we have lsa domain handle before doing anything */
950 prereq_ctx
= lsa_domain_opened(ctx
, s
->domain_name
, c
, &s
->domain_open
,
951 continue_lsa_domain_opened
, monitor
);
952 if (prereq_ctx
) return prereq_ctx
;
954 s
->query_domain
.in
.handle
= &ctx
->lsa
.handle
;
955 s
->query_domain
.in
.level
= LSA_POLICY_INFO_DOMAIN
;
957 query_req
= dcerpc_lsa_QueryInfoPolicy_send(ctx
->lsa
.pipe
, c
, &s
->query_domain
);
958 if (composite_nomem(query_req
, c
)) return c
;
960 composite_continue_rpc(c
, query_req
, continue_domain_queried
, c
);
966 * receive samr domain handle and request to enumerate accounts
968 static void continue_lsa_domain_opened(struct composite_context
*ctx
)
970 struct composite_context
*c
;
971 struct userlist_state
*s
;
972 struct rpc_request
*query_req
;
974 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
975 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
977 /* receive lsa domain handle */
978 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
979 if (!composite_is_ok(c
)) return;
981 s
->query_domain
.in
.handle
= &s
->ctx
->lsa
.handle
;
982 s
->query_domain
.in
.level
= LSA_POLICY_INFO_DOMAIN
;
984 query_req
= dcerpc_lsa_QueryInfoPolicy_send(s
->ctx
->lsa
.pipe
, c
, &s
->query_domain
);
985 if (composite_nomem(query_req
, c
)) return;
987 composite_continue_rpc(c
, query_req
, continue_domain_queried
, c
);
992 * receive domain info and request to enum users, provided a valid samr handle is opened
994 static void continue_domain_queried(struct rpc_request
*req
)
996 struct composite_context
*c
;
997 struct userlist_state
*s
;
998 struct composite_context
*prereq_ctx
;
999 struct rpc_request
*enum_req
;
1001 c
= talloc_get_type(req
->async
.private, struct composite_context
);
1002 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1004 c
->status
= dcerpc_ndr_request_recv(req
);
1005 if (!composite_is_ok(c
)) return;
1007 s
->dominfo
= s
->query_domain
.out
.info
->domain
;
1009 prereq_ctx
= samr_domain_opened(s
->ctx
, s
->domain_name
, c
, &s
->domain_open
,
1010 continue_samr_domain_opened
, s
->monitor_fn
);
1011 if (prereq_ctx
) return;
1013 /* prepare arguments */
1014 s
->user_list
.in
.domain_handle
= &s
->ctx
->samr
.handle
;
1015 s
->user_list
.in
.max_size
= s
->page_size
;
1016 s
->user_list
.in
.resume_handle
= &s
->resume_index
;
1017 s
->user_list
.in
.acct_flags
= ACB_NORMAL
;
1018 s
->user_list
.out
.resume_handle
= &s
->resume_index
;
1021 enum_req
= dcerpc_samr_EnumDomainUsers_send(s
->ctx
->samr
.pipe
, c
, &s
->user_list
);
1022 if (composite_nomem(enum_req
, c
)) return;
1024 composite_continue_rpc(c
, enum_req
, continue_users_enumerated
, c
);
1029 * receive samr domain handle and request to enumerate accounts
1031 static void continue_samr_domain_opened(struct composite_context
*ctx
)
1033 struct composite_context
*c
;
1034 struct userlist_state
*s
;
1035 struct rpc_request
*enum_req
;
1037 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
1038 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1040 /* receive lsa domain handle */
1041 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
1042 if (!composite_is_ok(c
)) return;
1044 /* prepare arguments */
1045 s
->user_list
.in
.domain_handle
= &s
->ctx
->samr
.handle
;
1046 s
->user_list
.in
.max_size
= s
->page_size
;
1047 s
->user_list
.in
.resume_handle
= &s
->resume_index
;
1048 s
->user_list
.in
.acct_flags
= ACB_NORMAL
;
1049 s
->user_list
.out
.resume_handle
= &s
->resume_index
;
1052 enum_req
= dcerpc_samr_EnumDomainUsers_send(s
->ctx
->samr
.pipe
, c
, &s
->user_list
);
1053 if (composite_nomem(enum_req
, c
)) return;
1055 composite_continue_rpc(c
, enum_req
, continue_users_enumerated
, c
);
1060 * receive enumerated users and their rids
1062 static void continue_users_enumerated(struct rpc_request
*req
)
1064 struct composite_context
*c
;
1065 struct userlist_state
*s
;
1068 c
= talloc_get_type(req
->async
.private, struct composite_context
);
1069 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1071 /* receive result of lsa_EnumAccounts request */
1072 c
->status
= dcerpc_ndr_request_recv(req
);
1073 if (!composite_is_ok(c
)) return;
1075 /* get the actual status of the rpc call result */
1076 c
->status
= s
->user_list
.out
.result
;
1078 if (NT_STATUS_IS_OK(c
->status
) ||
1079 NT_STATUS_EQUAL(c
->status
, STATUS_MORE_ENTRIES
) ||
1080 NT_STATUS_EQUAL(c
->status
, NT_STATUS_NO_MORE_ENTRIES
)) {
1082 s
->resume_index
= *s
->user_list
.out
.resume_handle
;
1083 s
->count
= s
->user_list
.out
.num_entries
;
1084 s
->users
= talloc_array(c
, struct userlist
, s
->user_list
.out
.sam
->count
);
1085 if (composite_nomem(s
->users
, c
)) return;
1087 for (i
= 0; i
< s
->user_list
.out
.sam
->count
; i
++) {
1088 struct dom_sid
*user_sid
;
1089 struct samr_SamEntry
*entry
= &s
->user_list
.out
.sam
->entries
[i
];
1090 struct dom_sid
*domain_sid
= s
->query_domain
.out
.info
->domain
.sid
;
1092 user_sid
= dom_sid_add_rid(c
, domain_sid
, entry
->idx
);
1093 if (composite_nomem(user_sid
, c
)) return;
1095 s
->users
[i
].username
= talloc_strdup(c
, entry
->name
.string
);
1096 if (composite_nomem(s
->users
[i
].username
, c
)) return;
1098 s
->users
[i
].sid
= dom_sid_string(c
, user_sid
);
1099 if (composite_nomem(s
->users
[i
].sid
, c
)) return;
1105 composite_error(c
, c
->status
);
1111 * Receive result of UserList call
1113 * @param c composite context returned by send request routine
1114 * @param mem_ctx memory context of this call
1115 * @param r pointer to a structure containing arguments and result of this call
1118 NTSTATUS
libnet_UserList_recv(struct composite_context
* c
, TALLOC_CTX
*mem_ctx
,
1119 struct libnet_UserList
*r
)
1122 struct userlist_state
*s
;
1124 if (c
== NULL
|| mem_ctx
== NULL
|| r
== NULL
) {
1125 return NT_STATUS_INVALID_PARAMETER
;
1128 status
= composite_wait(c
);
1129 if (NT_STATUS_IS_OK(status
) ||
1130 NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
) ||
1131 NT_STATUS_EQUAL(status
, NT_STATUS_NO_MORE_ENTRIES
)) {
1133 s
= talloc_get_type(c
->private_data
, struct userlist_state
);
1135 /* get results from composite context */
1136 r
->out
.count
= s
->count
;
1137 r
->out
.resume_index
= s
->resume_index
;
1138 r
->out
.users
= talloc_steal(mem_ctx
, s
->users
);
1140 if (NT_STATUS_IS_OK(status
)) {
1141 r
->out
.error_string
= talloc_strdup(mem_ctx
, "Success");
1143 r
->out
.error_string
= talloc_asprintf(mem_ctx
, "Success (status: %s)",
1148 r
->out
.error_string
= talloc_asprintf(mem_ctx
, "Error: %s", nt_errstr(status
));
1156 * Synchronous version of UserList call
1158 * @param ctx initialised libnet context
1159 * @param mem_ctx memory context of this call
1160 * @param r pointer to a structure containing arguments and result of this call
1163 NTSTATUS
libnet_UserList(struct libnet_context
*ctx
,
1164 TALLOC_CTX
*mem_ctx
,
1165 struct libnet_UserList
*r
)
1167 struct composite_context
*c
;
1169 c
= libnet_UserList_send(ctx
, mem_ctx
, r
, NULL
);
1170 return libnet_UserList_recv(c
, mem_ctx
, r
);