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(ctx
->samr
.pipe
, s
, &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_abort(ctx
->async
.private_data
, struct composite_context
);
112 s
= talloc_get_type_abort(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
, &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_abort(ctx
->async
.private_data
, struct composite_context
);
144 s
= talloc_get_type_abort(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
)
171 r
->out
.error_string
= NULL
;
173 /* wait for result of async request and check status code */
174 status
= composite_wait(c
);
175 if (!NT_STATUS_IS_OK(status
)) {
176 r
->out
.error_string
= talloc_strdup(mem_ctx
, nt_errstr(status
));
185 * Synchronous version of CreateUser call
187 * @param ctx initialised libnet context
188 * @param mem_ctx memory context of this call
189 * @param r pointer to a structure containing arguments and result of this call
192 NTSTATUS
libnet_CreateUser(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
193 struct libnet_CreateUser
*r
)
195 struct composite_context
*c
;
197 c
= libnet_CreateUser_send(ctx
, mem_ctx
, r
, NULL
);
198 return libnet_CreateUser_recv(c
, mem_ctx
, r
);
202 struct delete_user_state
{
203 struct libnet_DeleteUser r
;
204 struct libnet_context
*ctx
;
205 struct libnet_DomainOpen domain_open
;
206 struct libnet_rpc_userdel user_del
;
208 /* information about the progress */
209 void (*monitor_fn
)(struct monitor_msg
*);
213 static void continue_rpc_userdel(struct composite_context
*ctx
);
214 static void continue_domain_open_delete(struct composite_context
*ctx
);
218 * Sends request to delete user account
220 * @param ctx initialised libnet context
221 * @param mem_ctx memory context of this call
222 * @param r pointer to structure containing arguments and result of this call
223 * @param monitor function pointer for receiving monitor messages
225 struct composite_context
*libnet_DeleteUser_send(struct libnet_context
*ctx
,
227 struct libnet_DeleteUser
*r
,
228 void (*monitor
)(struct monitor_msg
*))
230 struct composite_context
*c
;
231 struct delete_user_state
*s
;
232 struct composite_context
*delete_req
;
233 bool prereq_met
= false;
235 /* composite context allocation and setup */
236 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
237 if (c
== NULL
) return NULL
;
239 s
= talloc_zero(c
, struct delete_user_state
);
240 if (composite_nomem(s
, c
)) return c
;
244 /* store arguments in state structure */
247 ZERO_STRUCT(s
->r
.out
);
249 /* prerequisite: make sure the domain is opened before proceeding */
250 prereq_met
= samr_domain_opened(ctx
, c
, s
->r
.in
.domain_name
, &c
, &s
->domain_open
,
251 continue_domain_open_delete
, monitor
);
252 if (!prereq_met
) return c
;
254 /* prepare arguments for userdel call */
255 s
->user_del
.in
.username
= r
->in
.user_name
;
256 s
->user_del
.in
.domain_handle
= ctx
->samr
.handle
;
259 delete_req
= libnet_rpc_userdel_send(ctx
->samr
.pipe
, s
, &s
->user_del
, monitor
);
260 if (composite_nomem(delete_req
, c
)) return c
;
262 /* set the next stage */
263 composite_continue(c
, delete_req
, continue_rpc_userdel
, c
);
269 * Stage 0.5 (optional): receive result of domain open request
270 * and send useradd request
272 static void continue_domain_open_delete(struct composite_context
*ctx
)
274 struct composite_context
*c
;
275 struct delete_user_state
*s
;
276 struct composite_context
*delete_req
;
277 struct monitor_msg msg
;
279 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
280 s
= talloc_get_type_abort(c
->private_data
, struct delete_user_state
);
282 /* receive result of DomainOpen call */
283 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
284 if (!composite_is_ok(c
)) return;
286 /* send monitor message */
287 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
289 /* prepare arguments for userdel call */
290 s
->user_del
.in
.username
= s
->r
.in
.user_name
;
291 s
->user_del
.in
.domain_handle
= s
->ctx
->samr
.handle
;
294 delete_req
= libnet_rpc_userdel_send(s
->ctx
->samr
.pipe
, s
, &s
->user_del
, s
->monitor_fn
);
295 if (composite_nomem(delete_req
, c
)) return;
297 /* set the next stage */
298 composite_continue(c
, delete_req
, continue_rpc_userdel
, c
);
303 * Stage 1: receive result of userdel call and finish the composite function
305 static void continue_rpc_userdel(struct composite_context
*ctx
)
307 struct composite_context
*c
;
308 struct delete_user_state
*s
;
309 struct monitor_msg msg
;
311 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
312 s
= talloc_get_type_abort(c
->private_data
, struct delete_user_state
);
314 /* receive result of userdel call */
315 c
->status
= libnet_rpc_userdel_recv(ctx
, c
, &s
->user_del
);
316 if (!composite_is_ok(c
)) return;
318 /* send monitor message */
319 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
327 * Receives result of asynchronous DeleteUser call
329 * @param c composite context returned by async DeleteUser call
330 * @param mem_ctx memory context of this call
331 * @param r pointer to structure containing arguments and result
333 NTSTATUS
libnet_DeleteUser_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
334 struct libnet_DeleteUser
*r
)
337 struct delete_user_state
*s
;
339 r
->out
.error_string
= NULL
;
341 /* wait for result of async request and check status code */
342 status
= composite_wait(c
);
343 if (!NT_STATUS_IS_OK(status
)) {
344 s
= talloc_get_type_abort(c
->private_data
, struct delete_user_state
);
345 r
->out
.error_string
= talloc_steal(mem_ctx
, s
->r
.out
.error_string
);
354 * Synchronous version of DeleteUser call
356 * @param ctx initialised libnet context
357 * @param mem_ctx memory context of this call
358 * @param r pointer to structure containing arguments and result
360 NTSTATUS
libnet_DeleteUser(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
361 struct libnet_DeleteUser
*r
)
363 struct composite_context
*c
;
365 c
= libnet_DeleteUser_send(ctx
, mem_ctx
, r
, NULL
);
366 return libnet_DeleteUser_recv(c
, mem_ctx
, r
);
370 struct modify_user_state
{
371 struct libnet_ModifyUser r
;
372 struct libnet_context
*ctx
;
373 struct libnet_DomainOpen domain_open
;
374 struct libnet_rpc_userinfo user_info
;
375 struct libnet_rpc_usermod user_mod
;
377 void (*monitor_fn
)(struct monitor_msg
*);
381 static void continue_rpc_usermod(struct composite_context
*ctx
);
382 static void continue_domain_open_modify(struct composite_context
*ctx
);
383 static NTSTATUS
set_user_changes(TALLOC_CTX
*mem_ctx
, struct usermod_change
*mod
,
384 struct libnet_rpc_userinfo
*info
, struct libnet_ModifyUser
*r
);
385 static void continue_rpc_userinfo(struct composite_context
*ctx
);
389 * Sends request to modify user account
391 * @param ctx initialised libnet context
392 * @param mem_ctx memory context of this call
393 * @param r pointer to structure containing arguments and result of this call
394 * @param monitor function pointer for receiving monitor messages
396 struct composite_context
*libnet_ModifyUser_send(struct libnet_context
*ctx
,
398 struct libnet_ModifyUser
*r
,
399 void (*monitor
)(struct monitor_msg
*))
401 const uint16_t level
= 21;
402 struct composite_context
*c
;
403 struct modify_user_state
*s
;
404 struct composite_context
*userinfo_req
;
405 bool prereq_met
= false;
407 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
408 if (c
== NULL
) return NULL
;
410 s
= talloc_zero(c
, struct modify_user_state
);
411 if (composite_nomem(s
, c
)) return c
;
418 prereq_met
= samr_domain_opened(ctx
, c
, s
->r
.in
.domain_name
, &c
, &s
->domain_open
,
419 continue_domain_open_modify
, monitor
);
420 if (!prereq_met
) return c
;
422 s
->user_info
.in
.username
= r
->in
.user_name
;
423 s
->user_info
.in
.domain_handle
= ctx
->samr
.handle
;
424 s
->user_info
.in
.level
= level
;
426 userinfo_req
= libnet_rpc_userinfo_send(ctx
->samr
.pipe
, s
, &s
->user_info
, monitor
);
427 if (composite_nomem(userinfo_req
, c
)) return c
;
429 composite_continue(c
, userinfo_req
, continue_rpc_userinfo
, c
);
435 * Stage 0.5 (optional): receive result of domain open request
436 * and send userinfo request
438 static void continue_domain_open_modify(struct composite_context
*ctx
)
440 const uint16_t level
= 21;
441 struct composite_context
*c
;
442 struct modify_user_state
*s
;
443 struct composite_context
*userinfo_req
;
444 struct monitor_msg msg
;
446 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
447 s
= talloc_get_type_abort(c
->private_data
, struct modify_user_state
);
449 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
450 if (!composite_is_ok(c
)) return;
452 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
454 s
->user_info
.in
.domain_handle
= s
->ctx
->samr
.handle
;
455 s
->user_info
.in
.username
= s
->r
.in
.user_name
;
456 s
->user_info
.in
.level
= level
;
458 userinfo_req
= libnet_rpc_userinfo_send(s
->ctx
->samr
.pipe
, s
, &s
->user_info
, s
->monitor_fn
);
459 if (composite_nomem(userinfo_req
, c
)) return;
461 composite_continue(c
, userinfo_req
, continue_rpc_userinfo
, c
);
466 * Stage 1: receive result of userinfo call, prepare user changes
467 * (set the fields a caller required to change) and send usermod request
469 static void continue_rpc_userinfo(struct composite_context
*ctx
)
471 struct composite_context
*c
;
472 struct modify_user_state
*s
;
473 struct composite_context
*usermod_req
;
475 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
476 s
= talloc_get_type_abort(c
->private_data
, struct modify_user_state
);
478 c
->status
= libnet_rpc_userinfo_recv(ctx
, c
, &s
->user_info
);
479 if (!composite_is_ok(c
)) return;
481 s
->user_mod
.in
.domain_handle
= s
->ctx
->samr
.handle
;
482 s
->user_mod
.in
.username
= s
->r
.in
.user_name
;
484 c
->status
= set_user_changes(c
, &s
->user_mod
.in
.change
, &s
->user_info
, &s
->r
);
486 usermod_req
= libnet_rpc_usermod_send(s
->ctx
->samr
.pipe
, s
, &s
->user_mod
, s
->monitor_fn
);
487 if (composite_nomem(usermod_req
, c
)) return;
489 composite_continue(c
, usermod_req
, continue_rpc_usermod
, c
);
494 * Prepare user changes: compare userinfo result to requested changes and
495 * set the field values and flags accordingly for user modify call
497 static NTSTATUS
set_user_changes(TALLOC_CTX
*mem_ctx
, struct usermod_change
*mod
,
498 struct libnet_rpc_userinfo
*info
, struct libnet_ModifyUser
*r
)
500 struct samr_UserInfo21
*user
;
502 if (mod
== NULL
|| info
== NULL
|| r
== NULL
|| info
->in
.level
!= 21) {
503 return NT_STATUS_INVALID_PARAMETER
;
506 user
= &info
->out
.info
.info21
;
507 mod
->fields
= 0; /* reset flag field before setting individual flags */
509 /* account name change */
510 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, account_name
, USERMOD_FIELD_ACCOUNT_NAME
);
512 /* full name change */
513 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, full_name
, USERMOD_FIELD_FULL_NAME
);
515 /* description change */
516 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, description
, USERMOD_FIELD_DESCRIPTION
);
519 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, comment
, USERMOD_FIELD_COMMENT
);
521 /* home directory change */
522 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, home_directory
, USERMOD_FIELD_HOME_DIRECTORY
);
524 /* home drive change */
525 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, home_drive
, USERMOD_FIELD_HOME_DRIVE
);
527 /* logon script change */
528 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, logon_script
, USERMOD_FIELD_LOGON_SCRIPT
);
530 /* profile path change */
531 SET_FIELD_LSA_STRING(r
->in
, user
, mod
, profile_path
, USERMOD_FIELD_PROFILE_PATH
);
533 /* account expiry change */
534 SET_FIELD_NTTIME(r
->in
, user
, mod
, acct_expiry
, USERMOD_FIELD_ACCT_EXPIRY
);
536 /* account flags change */
537 SET_FIELD_ACCT_FLAGS(r
->in
, user
, mod
, acct_flags
, USERMOD_FIELD_ACCT_FLAGS
);
544 * Stage 2: receive result of usermod request and finish the composite function
546 static void continue_rpc_usermod(struct composite_context
*ctx
)
548 struct composite_context
*c
;
549 struct modify_user_state
*s
;
550 struct monitor_msg msg
;
552 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
553 s
= talloc_get_type_abort(c
->private_data
, struct modify_user_state
);
555 c
->status
= libnet_rpc_usermod_recv(ctx
, c
, &s
->user_mod
);
556 if (!composite_is_ok(c
)) return;
558 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
564 * Receive result of ModifyUser call
566 * @param c composite context returned by send request routine
567 * @param mem_ctx memory context of this call
568 * @param r pointer to a structure containing arguments and result of this call
571 NTSTATUS
libnet_ModifyUser_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
572 struct libnet_ModifyUser
*r
)
574 NTSTATUS status
= composite_wait(c
);
582 * Synchronous version of ModifyUser call
584 * @param ctx initialised libnet context
585 * @param mem_ctx memory context of this call
586 * @param r pointer to a structure containing arguments and result of this call
589 NTSTATUS
libnet_ModifyUser(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
590 struct libnet_ModifyUser
*r
)
592 struct composite_context
*c
;
594 c
= libnet_ModifyUser_send(ctx
, mem_ctx
, r
, NULL
);
595 return libnet_ModifyUser_recv(c
, mem_ctx
, r
);
599 struct user_info_state
{
600 struct libnet_context
*ctx
;
601 const char *domain_name
;
602 enum libnet_UserInfo_level level
;
603 const char *user_name
;
604 const char *sid_string
;
605 struct libnet_LookupName lookup
;
606 struct libnet_DomainOpen domopen
;
607 struct libnet_rpc_userinfo userinfo
;
609 /* information about the progress */
610 void (*monitor_fn
)(struct monitor_msg
*);
614 static void continue_name_found(struct composite_context
*ctx
);
615 static void continue_domain_open_info(struct composite_context
*ctx
);
616 static void continue_info_received(struct composite_context
*ctx
);
620 * Sends request to get user account information
622 * @param ctx initialised libnet context
623 * @param mem_ctx memory context of this call
624 * @param r pointer to a structure containing arguments and results of this call
625 * @param monitor function pointer for receiving monitor messages
626 * @return compostite context of this request
628 struct composite_context
* libnet_UserInfo_send(struct libnet_context
*ctx
,
630 struct libnet_UserInfo
*r
,
631 void (*monitor
)(struct monitor_msg
*))
633 struct composite_context
*c
;
634 struct user_info_state
*s
;
635 struct composite_context
*lookup_req
, *info_req
;
636 bool prereq_met
= false;
638 /* composite context allocation and setup */
639 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
640 if (c
== NULL
) return NULL
;
642 s
= talloc_zero(c
, struct user_info_state
);
643 if (composite_nomem(s
, c
)) return c
;
647 /* store arguments in the state structure */
648 s
->monitor_fn
= monitor
;
650 s
->domain_name
= talloc_strdup(c
, r
->in
.domain_name
);
651 s
->level
= r
->in
.level
;
653 case USER_INFO_BY_NAME
:
654 s
->user_name
= talloc_strdup(c
, r
->in
.data
.user_name
);
655 s
->sid_string
= NULL
;
657 case USER_INFO_BY_SID
:
659 s
->sid_string
= dom_sid_string(c
, r
->in
.data
.user_sid
);
663 /* prerequisite: make sure the domain is opened */
664 prereq_met
= samr_domain_opened(ctx
, c
, s
->domain_name
, &c
, &s
->domopen
,
665 continue_domain_open_info
, monitor
);
666 if (!prereq_met
) return c
;
669 case USER_INFO_BY_NAME
:
670 /* prepare arguments for LookupName call */
671 s
->lookup
.in
.domain_name
= s
->domain_name
;
672 s
->lookup
.in
.name
= s
->user_name
;
674 /* send the request */
675 lookup_req
= libnet_LookupName_send(ctx
, c
, &s
->lookup
,
677 if (composite_nomem(lookup_req
, c
)) return c
;
679 /* set the next stage */
680 composite_continue(c
, lookup_req
, continue_name_found
, c
);
682 case USER_INFO_BY_SID
:
683 /* prepare arguments for UserInfo call */
684 s
->userinfo
.in
.domain_handle
= s
->ctx
->samr
.handle
;
685 s
->userinfo
.in
.sid
= s
->sid_string
;
686 s
->userinfo
.in
.level
= 21;
688 /* send the request */
689 info_req
= libnet_rpc_userinfo_send(s
->ctx
->samr
.pipe
,
693 if (composite_nomem(info_req
, c
)) return c
;
695 /* set the next stage */
696 composite_continue(c
, info_req
, continue_info_received
, c
);
705 * Stage 0.5 (optional): receive result of domain open request
706 * and send LookupName request
708 static void continue_domain_open_info(struct composite_context
*ctx
)
710 struct composite_context
*c
;
711 struct user_info_state
*s
;
712 struct composite_context
*lookup_req
, *info_req
;
713 struct monitor_msg msg
;
715 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
716 s
= talloc_get_type_abort(c
->private_data
, struct user_info_state
);
718 /* receive result of DomainOpen call */
719 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domopen
);
720 if (!composite_is_ok(c
)) return;
722 /* send monitor message */
723 if (s
->monitor_fn
) s
->monitor_fn(&msg
);
726 case USER_INFO_BY_NAME
:
727 /* prepare arguments for LookupName call */
728 s
->lookup
.in
.domain_name
= s
->domain_name
;
729 s
->lookup
.in
.name
= s
->user_name
;
731 /* send the request */
732 lookup_req
= libnet_LookupName_send(s
->ctx
, c
, &s
->lookup
, s
->monitor_fn
);
733 if (composite_nomem(lookup_req
, c
)) return;
735 /* set the next stage */
736 composite_continue(c
, lookup_req
, continue_name_found
, c
);
739 case USER_INFO_BY_SID
:
740 /* prepare arguments for UserInfo call */
741 s
->userinfo
.in
.domain_handle
= s
->ctx
->samr
.handle
;
742 s
->userinfo
.in
.sid
= s
->sid_string
;
743 s
->userinfo
.in
.level
= 21;
745 /* send the request */
746 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_abort(ctx
->async
.private_data
, struct composite_context
);
769 s
= talloc_get_type_abort(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
, &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_abort(ctx
->async
.private_data
, struct composite_context
);
804 s
= talloc_get_type_abort(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_abort(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
, c
, 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_abort(ctx
->async
.private_data
, struct composite_context
);
988 s
= talloc_get_type_abort(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_abort(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
, c
, 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_abort(ctx
->async
.private_data
, struct composite_context
);
1068 s
= talloc_get_type_abort(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_abort(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;
1154 /* something went wrong */
1155 composite_error(c
, c
->status
);
1162 * Receive result of UserList call
1164 * @param c composite context returned by send request routine
1165 * @param mem_ctx memory context of this call
1166 * @param r pointer to structure containing arguments and result of this call
1169 NTSTATUS
libnet_UserList_recv(struct composite_context
* c
, TALLOC_CTX
*mem_ctx
,
1170 struct libnet_UserList
*r
)
1173 struct userlist_state
*s
;
1175 if (c
== NULL
|| mem_ctx
== NULL
|| r
== NULL
) {
1177 return NT_STATUS_INVALID_PARAMETER
;
1180 status
= composite_wait(c
);
1181 if (NT_STATUS_IS_OK(status
) ||
1182 NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
) ||
1183 NT_STATUS_EQUAL(status
, NT_STATUS_NO_MORE_ENTRIES
)) {
1185 s
= talloc_get_type_abort(c
->private_data
, struct userlist_state
);
1187 /* get results from composite context */
1188 r
->out
.count
= s
->count
;
1189 r
->out
.resume_index
= s
->resume_index
;
1190 r
->out
.users
= talloc_steal(mem_ctx
, s
->users
);
1192 if (NT_STATUS_IS_OK(status
)) {
1193 r
->out
.error_string
= talloc_strdup(mem_ctx
, "Success");
1195 /* success, but we're not done yet */
1196 r
->out
.error_string
= talloc_asprintf(mem_ctx
, "Success (status: %s)",
1201 r
->out
.error_string
= talloc_asprintf(mem_ctx
, "Error: %s", nt_errstr(status
));
1210 * Synchronous version of UserList call
1212 * @param ctx initialised libnet context
1213 * @param mem_ctx memory context of this call
1214 * @param r pointer to structure containing arguments and result of this call
1217 NTSTATUS
libnet_UserList(struct libnet_context
*ctx
,
1218 TALLOC_CTX
*mem_ctx
,
1219 struct libnet_UserList
*r
)
1221 struct composite_context
*c
;
1223 c
= libnet_UserList_send(ctx
, mem_ctx
, r
, NULL
);
1224 return libnet_UserList_recv(c
, mem_ctx
, r
);