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"
34 struct create_user_state {
35 struct libnet_CreateUser r;
36 struct libnet_DomainOpen domain_open;
37 struct libnet_rpc_useradd user_add;
38 struct libnet_context *ctx;
40 /* information about the progress */
41 void (*monitor_fn)(struct monitor_msg *);
45 static void continue_rpc_useradd(struct composite_context *ctx);
46 static void continue_domain_open_create(struct composite_context *ctx);
50 * Sends request to create user account
52 * @param ctx initialised libnet context
53 * @param mem_ctx memory context of this call
54 * @param r pointer to a structure containing arguments and results of this call
55 * @param monitor function pointer for receiving monitor messages
56 * @return compostite context of this request
58 struct composite_context* libnet_CreateUser_send(struct libnet_context *ctx,
60 struct libnet_CreateUser *r,
61 void (*monitor)(struct monitor_msg*))
63 struct composite_context *c;
64 struct create_user_state *s;
65 struct composite_context *create_req;
66 BOOL prereq_met = False;
68 /* composite context allocation and setup */
69 c = composite_create(mem_ctx, ctx->event_ctx);
70 if (c == NULL) return NULL;
72 s = talloc_zero(c, struct create_user_state);
73 if (composite_nomem(s, c)) return c;
77 /* store arguments in the state structure */
80 ZERO_STRUCT(s->r.out);
82 /* prerequisite: make sure the domain is opened */
83 prereq_met = samr_domain_opened(ctx, s->r.in.domain_name, &c, &s->domain_open,
84 continue_domain_open_create, monitor);
85 if (!prereq_met) return c;
87 /* prepare arguments for useradd call */
88 s->user_add.in.username = r->in.user_name;
89 s->user_add.in.domain_handle = ctx->samr.handle;
91 /* send the request */
92 create_req = libnet_rpc_useradd_send(ctx->samr.pipe, &s->user_add, monitor);
93 if (composite_nomem(create_req, c)) return c;
95 /* set the next stage */
96 composite_continue(c, create_req, continue_rpc_useradd, c);
102 * Stage 0.5 (optional): receive result of domain open request
103 * and send useradd request
105 static void continue_domain_open_create(struct composite_context *ctx)
107 struct composite_context *c;
108 struct create_user_state *s;
109 struct composite_context *create_req;
110 struct monitor_msg msg;
112 c = talloc_get_type(ctx->async.private_data, struct composite_context);
113 s = talloc_get_type(c->private_data, struct create_user_state);
115 /* receive result of DomainOpen call */
116 c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
117 if (!composite_is_ok(c)) return;
119 /* send monitor message */
120 if (s->monitor_fn) s->monitor_fn(&msg);
122 /* prepare arguments for useradd call */
123 s->user_add.in.username = s->r.in.user_name;
124 s->user_add.in.domain_handle = s->ctx->samr.handle;
126 /* send the request */
127 create_req = libnet_rpc_useradd_send(s->ctx->samr.pipe, &s->user_add, s->monitor_fn);
128 if (composite_nomem(create_req, c)) return;
130 /* set the next stage */
131 composite_continue(c, create_req, continue_rpc_useradd, c);
136 * Stage 1: receive result of useradd call
138 static void continue_rpc_useradd(struct composite_context *ctx)
140 struct composite_context *c;
141 struct create_user_state *s;
142 struct monitor_msg msg;
144 c = talloc_get_type(ctx->async.private_data, struct composite_context);
145 s = talloc_get_type(c->private_data, struct create_user_state);
147 /* receive result of the call */
148 c->status = libnet_rpc_useradd_recv(ctx, c, &s->user_add);
149 if (!composite_is_ok(c)) return;
151 /* send monitor message */
152 if (s->monitor_fn) s->monitor_fn(&msg);
160 * Receive result of CreateUser call
162 * @param c composite context returned by send request routine
163 * @param mem_ctx memory context of this call
164 * @param r pointer to a structure containing arguments and result of this call
167 NTSTATUS libnet_CreateUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
168 struct libnet_CreateUser *r)
171 struct create_user_state *s;
173 r->out.error_string = NULL;
175 /* wait for result of async request and check status code */
176 status = composite_wait(c);
177 if (!NT_STATUS_IS_OK(status)) {
178 s = talloc_get_type(c->private_data, struct create_user_state);
179 r->out.error_string = talloc_strdup(mem_ctx, nt_errstr(status));
187 * Synchronous version of CreateUser call
189 * @param ctx initialised libnet context
190 * @param mem_ctx memory context of this call
191 * @param r pointer to a structure containing arguments and result of this call
194 NTSTATUS libnet_CreateUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
195 struct libnet_CreateUser *r)
197 struct composite_context *c;
199 c = libnet_CreateUser_send(ctx, mem_ctx, r, NULL);
200 return libnet_CreateUser_recv(c, mem_ctx, r);
204 struct delete_user_state {
205 struct libnet_DeleteUser r;
206 struct libnet_context *ctx;
207 struct libnet_DomainOpen domain_open;
208 struct libnet_rpc_userdel user_del;
210 /* information about the progress */
211 void (*monitor_fn)(struct monitor_msg *);
215 static void continue_rpc_userdel(struct composite_context *ctx);
216 static void continue_domain_open_delete(struct composite_context *ctx);
220 * Sends request to delete user account
222 * @param ctx initialised libnet context
223 * @param mem_ctx memory context of this call
224 * @param r pointer to structure containing arguments and result of this call
225 * @param monitor function pointer for receiving monitor messages
227 struct composite_context *libnet_DeleteUser_send(struct libnet_context *ctx,
229 struct libnet_DeleteUser *r,
230 void (*monitor)(struct monitor_msg*))
232 struct composite_context *c;
233 struct delete_user_state *s;
234 struct composite_context *delete_req;
235 BOOL prereq_met = False;
237 /* composite context allocation and setup */
238 c = composite_create(mem_ctx, ctx->event_ctx);
239 if (c == NULL) return NULL;
241 s = talloc_zero(c, struct delete_user_state);
242 if (composite_nomem(s, c)) return c;
246 /* store arguments in state structure */
249 ZERO_STRUCT(s->r.out);
251 /* prerequisite: make sure the domain is opened before proceeding */
252 prereq_met = samr_domain_opened(ctx, s->r.in.domain_name, &c, &s->domain_open,
253 continue_domain_open_delete, monitor);
254 if (!prereq_met) return c;
256 /* prepare arguments for userdel call */
257 s->user_del.in.username = r->in.user_name;
258 s->user_del.in.domain_handle = ctx->samr.handle;
261 delete_req = libnet_rpc_userdel_send(ctx->samr.pipe, &s->user_del, monitor);
262 if (composite_nomem(delete_req, c)) return c;
264 /* set the next stage */
265 composite_continue(c, delete_req, continue_rpc_userdel, c);
271 * Stage 0.5 (optional): receive result of domain open request
272 * and send useradd request
274 static void continue_domain_open_delete(struct composite_context *ctx)
276 struct composite_context *c;
277 struct delete_user_state *s;
278 struct composite_context *delete_req;
279 struct monitor_msg msg;
281 c = talloc_get_type(ctx->async.private_data, struct composite_context);
282 s = talloc_get_type(c->private_data, struct delete_user_state);
284 /* receive result of DomainOpen call */
285 c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
286 if (!composite_is_ok(c)) return;
288 /* send monitor message */
289 if (s->monitor_fn) s->monitor_fn(&msg);
291 /* prepare arguments for userdel call */
292 s->user_del.in.username = s->r.in.user_name;
293 s->user_del.in.domain_handle = s->ctx->samr.handle;
296 delete_req = libnet_rpc_userdel_send(s->ctx->samr.pipe, &s->user_del, s->monitor_fn);
297 if (composite_nomem(delete_req, c)) return;
299 /* set the next stage */
300 composite_continue(c, delete_req, continue_rpc_userdel, c);
305 * Stage 1: receive result of userdel call and finish the composite function
307 static void continue_rpc_userdel(struct composite_context *ctx)
309 struct composite_context *c;
310 struct delete_user_state *s;
311 struct monitor_msg msg;
313 c = talloc_get_type(ctx->async.private_data, struct composite_context);
314 s = talloc_get_type(c->private_data, struct delete_user_state);
316 /* receive result of userdel call */
317 c->status = libnet_rpc_userdel_recv(ctx, c, &s->user_del);
318 if (!composite_is_ok(c)) return;
320 /* send monitor message */
321 if (s->monitor_fn) s->monitor_fn(&msg);
329 * Receives result of asynchronous DeleteUser call
331 * @param c composite context returned by async DeleteUser call
332 * @param mem_ctx memory context of this call
333 * @param r pointer to structure containing arguments and result
335 NTSTATUS libnet_DeleteUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
336 struct libnet_DeleteUser *r)
339 struct delete_user_state *s;
341 r->out.error_string = NULL;
343 /* wait for result of async request and check status code */
344 status = composite_wait(c);
345 if (!NT_STATUS_IS_OK(status)) {
346 s = talloc_get_type(c->private_data, struct delete_user_state);
347 r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
355 * Synchronous version of DeleteUser call
357 * @param ctx initialised libnet context
358 * @param mem_ctx memory context of this call
359 * @param r pointer to structure containing arguments and result
361 NTSTATUS libnet_DeleteUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
362 struct libnet_DeleteUser *r)
364 struct composite_context *c;
366 c = libnet_DeleteUser_send(ctx, mem_ctx, r, NULL);
367 return libnet_DeleteUser_recv(c, mem_ctx, r);
371 struct modify_user_state {
372 struct libnet_ModifyUser r;
373 struct libnet_context *ctx;
374 struct libnet_DomainOpen domain_open;
375 struct libnet_rpc_userinfo user_info;
376 struct libnet_rpc_usermod user_mod;
378 void (*monitor_fn)(struct monitor_msg *);
382 static void continue_rpc_usermod(struct composite_context *ctx);
383 static void continue_domain_open_modify(struct composite_context *ctx);
384 static NTSTATUS set_user_changes(TALLOC_CTX *mem_ctx, struct usermod_change *mod,
385 struct libnet_rpc_userinfo *info, struct libnet_ModifyUser *r);
386 static void continue_rpc_userinfo(struct composite_context *ctx);
390 * Sends request to modify user account
392 * @param ctx initialised libnet context
393 * @param mem_ctx memory context of this call
394 * @param r pointer to structure containing arguments and result of this call
395 * @param monitor function pointer for receiving monitor messages
397 struct composite_context *libnet_ModifyUser_send(struct libnet_context *ctx,
399 struct libnet_ModifyUser *r,
400 void (*monitor)(struct monitor_msg*))
402 const uint16_t level = 21;
403 struct composite_context *c;
404 struct modify_user_state *s;
405 struct composite_context *userinfo_req;
406 BOOL prereq_met = False;
408 c = composite_create(mem_ctx, ctx->event_ctx);
409 if (c == NULL) return NULL;
411 s = talloc_zero(c, struct modify_user_state);
412 if (composite_nomem(s, c)) return c;
419 prereq_met = samr_domain_opened(ctx, s->r.in.domain_name, &c, &s->domain_open,
420 continue_domain_open_modify, monitor);
421 if (!prereq_met) return c;
423 s->user_info.in.username = r->in.user_name;
424 s->user_info.in.domain_handle = ctx->samr.handle;
425 s->user_info.in.level = level;
427 userinfo_req = libnet_rpc_userinfo_send(ctx->samr.pipe, &s->user_info, monitor);
428 if (composite_nomem(userinfo_req, c)) return c;
430 composite_continue(c, userinfo_req, continue_rpc_userinfo, c);
436 * Stage 0.5 (optional): receive result of domain open request
437 * and send userinfo request
439 static void continue_domain_open_modify(struct composite_context *ctx)
441 const uint16_t level = 21;
442 struct composite_context *c;
443 struct modify_user_state *s;
444 struct composite_context *userinfo_req;
445 struct monitor_msg msg;
447 c = talloc_get_type(ctx->async.private_data, struct composite_context);
448 s = talloc_get_type(c->private_data, struct modify_user_state);
450 c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
451 if (!composite_is_ok(c)) return;
453 if (s->monitor_fn) s->monitor_fn(&msg);
455 s->user_info.in.domain_handle = s->ctx->samr.handle;
456 s->user_info.in.username = s->r.in.user_name;
457 s->user_info.in.level = level;
459 userinfo_req = libnet_rpc_userinfo_send(s->ctx->samr.pipe, &s->user_info, s->monitor_fn);
460 if (composite_nomem(userinfo_req, c)) return;
462 composite_continue(c, userinfo_req, continue_rpc_userinfo, c);
467 * Stage 1: receive result of userinfo call, prepare user changes
468 * (set the fields a caller required to change) and send usermod request
470 static void continue_rpc_userinfo(struct composite_context *ctx)
472 struct composite_context *c;
473 struct modify_user_state *s;
474 struct composite_context *usermod_req;
476 c = talloc_get_type(ctx->async.private_data, struct composite_context);
477 s = talloc_get_type(c->private_data, struct modify_user_state);
479 c->status = libnet_rpc_userinfo_recv(ctx, c, &s->user_info);
480 if (!composite_is_ok(c)) return;
482 s->user_mod.in.domain_handle = s->ctx->samr.handle;
483 s->user_mod.in.username = s->r.in.user_name;
485 c->status = set_user_changes(c, &s->user_mod.in.change, &s->user_info, &s->r);
487 usermod_req = libnet_rpc_usermod_send(s->ctx->samr.pipe, &s->user_mod, s->monitor_fn);
488 if (composite_nomem(usermod_req, c)) return;
490 composite_continue(c, usermod_req, continue_rpc_usermod, c);
495 * Prepare user changes: compare userinfo result to requested changes and
496 * set the field values and flags accordingly for user modify call
498 static NTSTATUS set_user_changes(TALLOC_CTX *mem_ctx, struct usermod_change *mod,
499 struct libnet_rpc_userinfo *info, struct libnet_ModifyUser *r)
501 struct samr_UserInfo21 *user;
503 if (mod == NULL || info == NULL || r == NULL || info->in.level != 21) {
504 return NT_STATUS_INVALID_PARAMETER;
507 user = &info->out.info.info21;
508 mod->fields = 0; /* reset flag field before setting individual flags */
510 /* account name change */
511 SET_FIELD_LSA_STRING(r->in, user, mod, account_name, USERMOD_FIELD_ACCOUNT_NAME);
513 /* full name change */
514 SET_FIELD_LSA_STRING(r->in, user, mod, full_name, USERMOD_FIELD_FULL_NAME);
516 /* description change */
517 SET_FIELD_LSA_STRING(r->in, user, mod, description, USERMOD_FIELD_DESCRIPTION);
520 SET_FIELD_LSA_STRING(r->in, user, mod, comment, USERMOD_FIELD_COMMENT);
522 /* home directory change */
523 SET_FIELD_LSA_STRING(r->in, user, mod, home_directory, USERMOD_FIELD_HOME_DIRECTORY);
525 /* home drive change */
526 SET_FIELD_LSA_STRING(r->in, user, mod, home_drive, USERMOD_FIELD_HOME_DRIVE);
528 /* logon script change */
529 SET_FIELD_LSA_STRING(r->in, user, mod, logon_script, USERMOD_FIELD_LOGON_SCRIPT);
531 /* profile path change */
532 SET_FIELD_LSA_STRING(r->in, user, mod, profile_path, USERMOD_FIELD_PROFILE_PATH);
534 /* account expiry change */
535 SET_FIELD_NTTIME(r->in, user, mod, acct_expiry, USERMOD_FIELD_ACCT_EXPIRY);
542 * Stage 2: receive result of usermod request and finish the composite function
544 static void continue_rpc_usermod(struct composite_context *ctx)
546 struct composite_context *c;
547 struct modify_user_state *s;
548 struct monitor_msg msg;
550 c = talloc_get_type(ctx->async.private_data, struct composite_context);
551 s = talloc_get_type(c->private_data, struct modify_user_state);
553 c->status = libnet_rpc_usermod_recv(ctx, c, &s->user_mod);
554 if (!composite_is_ok(c)) return;
556 if (s->monitor_fn) s->monitor_fn(&msg);
562 * Receive result of ModifyUser call
564 * @param c composite context returned by send request routine
565 * @param mem_ctx memory context of this call
566 * @param r pointer to a structure containing arguments and result of this call
569 NTSTATUS libnet_ModifyUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
570 struct libnet_ModifyUser *r)
572 NTSTATUS status = composite_wait(c);
578 * Synchronous version of ModifyUser call
580 * @param ctx initialised libnet context
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(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
586 struct libnet_ModifyUser *r)
588 struct composite_context *c;
590 c = libnet_ModifyUser_send(ctx, mem_ctx, r, NULL);
591 return libnet_ModifyUser_recv(c, mem_ctx, r);
595 struct user_info_state {
596 struct libnet_context *ctx;
597 const char *domain_name;
598 const char *user_name;
599 struct libnet_LookupName lookup;
600 struct libnet_DomainOpen domopen;
601 struct libnet_rpc_userinfo userinfo;
603 /* information about the progress */
604 void (*monitor_fn)(struct monitor_msg *);
608 static void continue_name_found(struct composite_context *ctx);
609 static void continue_domain_open_info(struct composite_context *ctx);
610 static void continue_info_received(struct composite_context *ctx);
614 * Sends request to get user account information
616 * @param ctx initialised libnet context
617 * @param mem_ctx memory context of this call
618 * @param r pointer to a structure containing arguments and results of this call
619 * @param monitor function pointer for receiving monitor messages
620 * @return compostite context of this request
622 struct composite_context* libnet_UserInfo_send(struct libnet_context *ctx,
624 struct libnet_UserInfo *r,
625 void (*monitor)(struct monitor_msg*))
627 struct composite_context *c;
628 struct user_info_state *s;
629 struct composite_context *lookup_req;
630 BOOL prereq_met = False;
632 /* composite context allocation and setup */
633 c = composite_create(mem_ctx, ctx->event_ctx);
634 if (c == NULL) return NULL;
636 s = talloc_zero(c, struct user_info_state);
637 if (composite_nomem(s, c)) return c;
641 /* store arguments in the state structure */
642 s->monitor_fn = monitor;
644 s->domain_name = talloc_strdup(c, r->in.domain_name);
645 s->user_name = talloc_strdup(c, r->in.user_name);
647 /* prerequisite: make sure the domain is opened */
648 prereq_met = samr_domain_opened(ctx, s->domain_name, &c, &s->domopen,
649 continue_domain_open_info, monitor);
650 if (!prereq_met) return c;
652 /* prepare arguments for LookupName call */
653 s->lookup.in.domain_name = s->domain_name;
654 s->lookup.in.name = s->user_name;
656 /* send the request */
657 lookup_req = libnet_LookupName_send(ctx, c, &s->lookup, s->monitor_fn);
658 if (composite_nomem(lookup_req, c)) return c;
660 /* set the next stage */
661 composite_continue(c, lookup_req, continue_name_found, c);
667 * Stage 0.5 (optional): receive result of domain open request
668 * and send LookupName request
670 static void continue_domain_open_info(struct composite_context *ctx)
672 struct composite_context *c;
673 struct user_info_state *s;
674 struct composite_context *lookup_req;
675 struct monitor_msg msg;
677 c = talloc_get_type(ctx->async.private_data, struct composite_context);
678 s = talloc_get_type(c->private_data, struct user_info_state);
680 /* receive result of DomainOpen call */
681 c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domopen);
682 if (!composite_is_ok(c)) return;
684 /* send monitor message */
685 if (s->monitor_fn) s->monitor_fn(&msg);
687 /* prepare arguments for LookupName call */
688 s->lookup.in.domain_name = s->domain_name;
689 s->lookup.in.name = s->user_name;
691 /* send the request */
692 lookup_req = libnet_LookupName_send(s->ctx, c, &s->lookup, s->monitor_fn);
693 if (composite_nomem(lookup_req, c)) return;
695 /* set the next stage */
696 composite_continue(c, lookup_req, continue_name_found, c);
701 * Stage 1: receive the name (if found) and send userinfo request
703 static void continue_name_found(struct composite_context *ctx)
705 struct composite_context *c;
706 struct user_info_state *s;
707 struct composite_context *info_req;
709 c = talloc_get_type(ctx->async.private_data, struct composite_context);
710 s = talloc_get_type(c->private_data, struct user_info_state);
712 /* receive result of LookupName call */
713 c->status = libnet_LookupName_recv(ctx, c, &s->lookup);
714 if (!composite_is_ok(c)) return;
716 /* we're only interested in user accounts this time */
717 if (s->lookup.out.sid_type != SID_NAME_USER) {
718 composite_error(c, NT_STATUS_NO_SUCH_USER);
722 /* prepare arguments for UserInfo call */
723 s->userinfo.in.domain_handle = s->ctx->samr.handle;
724 s->userinfo.in.sid = s->lookup.out.sidstr;
725 s->userinfo.in.level = 21;
727 /* send the request */
728 info_req = libnet_rpc_userinfo_send(s->ctx->samr.pipe, &s->userinfo, s->monitor_fn);
729 if (composite_nomem(info_req, c)) return;
731 /* set the next stage */
732 composite_continue(c, info_req, continue_info_received, c);
737 * Stage 2: receive user account information and finish the composite function
739 static void continue_info_received(struct composite_context *ctx)
741 struct composite_context *c;
742 struct user_info_state *s;
744 c = talloc_get_type(ctx->async.private_data, struct composite_context);
745 s = talloc_get_type(c->private_data, struct user_info_state);
747 /* receive result of userinfo call */
748 c->status = libnet_rpc_userinfo_recv(ctx, c, &s->userinfo);
749 if (!composite_is_ok(c)) return;
756 * Receive result of UserInfo call
758 * @param c composite context returned by send request routine
759 * @param mem_ctx memory context of this call
760 * @param r pointer to a structure containing arguments and result of this call
763 NTSTATUS libnet_UserInfo_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
764 struct libnet_UserInfo *r)
767 struct user_info_state *s;
769 status = composite_wait(c);
771 if (NT_STATUS_IS_OK(status) && r != NULL) {
772 struct samr_UserInfo21 *info;
774 s = talloc_get_type(c->private_data, struct user_info_state);
775 info = &s->userinfo.out.info.info21;
778 r->out.account_name = talloc_steal(mem_ctx, info->account_name.string);
779 r->out.full_name = talloc_steal(mem_ctx, info->full_name.string);
780 r->out.description = talloc_steal(mem_ctx, info->description.string);
781 r->out.home_directory = talloc_steal(mem_ctx, info->home_directory.string);
782 r->out.home_drive = talloc_steal(mem_ctx, info->home_drive.string);
783 r->out.comment = talloc_steal(mem_ctx, info->comment.string);
784 r->out.logon_script = talloc_steal(mem_ctx, info->logon_script.string);
785 r->out.profile_path = talloc_steal(mem_ctx, info->profile_path.string);
787 /* time fields (allocation) */
788 r->out.acct_expiry = talloc(mem_ctx, struct timeval);
789 r->out.allow_password_change = talloc(mem_ctx, struct timeval);
790 r->out.force_password_change = talloc(mem_ctx, struct timeval);
791 r->out.last_logon = talloc(mem_ctx, struct timeval);
792 r->out.last_logoff = talloc(mem_ctx, struct timeval);
793 r->out.last_password_change = talloc(mem_ctx, struct timeval);
795 /* time fields (converting) */
796 nttime_to_timeval(r->out.acct_expiry, info->acct_expiry);
797 nttime_to_timeval(r->out.allow_password_change, info->allow_password_change);
798 nttime_to_timeval(r->out.force_password_change, info->force_password_change);
799 nttime_to_timeval(r->out.last_logon, info->last_logon);
800 nttime_to_timeval(r->out.last_logoff, info->last_logoff);
801 nttime_to_timeval(r->out.last_password_change, info->last_password_change);
803 /* flag and number fields */
804 r->out.acct_flags = info->acct_flags;
806 r->out.error_string = talloc_strdup(mem_ctx, "Success");
809 r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
819 * Synchronous version of UserInfo call
821 * @param ctx initialised libnet context
822 * @param mem_ctx memory context of this call
823 * @param r pointer to a structure containing arguments and result of this call
826 NTSTATUS libnet_UserInfo(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
827 struct libnet_UserInfo *r)
829 struct composite_context *c;
831 c = libnet_UserInfo_send(ctx, mem_ctx, r, NULL);
832 return libnet_UserInfo_recv(c, mem_ctx, r);
836 struct userlist_state {
837 struct libnet_context *ctx;
838 const char *domain_name;
839 struct lsa_DomainInfo dominfo;
841 uint32_t resume_index;
842 struct userlist *users;
845 struct libnet_DomainOpen domain_open;
846 struct lsa_QueryInfoPolicy query_domain;
847 struct samr_EnumDomainUsers user_list;
849 void (*monitor_fn)(struct monitor_msg*);
853 static void continue_lsa_domain_opened(struct composite_context *ctx);
854 static void continue_domain_queried(struct rpc_request *req);
855 static void continue_samr_domain_opened(struct composite_context *ctx);
856 static void continue_users_enumerated(struct rpc_request *req);
860 * Sends request to list (enumerate) user accounts
862 * @param ctx initialised libnet context
863 * @param mem_ctx memory context of this call
864 * @param r pointer to a structure containing arguments and results of this call
865 * @param monitor function pointer for receiving monitor messages
866 * @return compostite context of this request
868 struct composite_context* libnet_UserList_send(struct libnet_context *ctx,
870 struct libnet_UserList *r,
871 void (*monitor)(struct monitor_msg*))
873 struct composite_context *c;
874 struct userlist_state *s;
875 struct rpc_request *query_req;
876 BOOL prereq_met = False;
878 /* composite context allocation and setup */
879 c = composite_create(mem_ctx, ctx->event_ctx);
880 if (c == NULL) return NULL;
882 s = talloc_zero(c, struct userlist_state);
883 if (composite_nomem(s, c)) return c;
887 /* store the arguments in the state structure */
889 s->page_size = r->in.page_size;
890 s->resume_index = (uint32_t)r->in.resume_index;
891 s->domain_name = talloc_strdup(c, r->in.domain_name);
892 s->monitor_fn = monitor;
894 /* make sure we have lsa domain handle before doing anything */
895 prereq_met = lsa_domain_opened(ctx, s->domain_name, &c, &s->domain_open,
896 continue_lsa_domain_opened, monitor);
897 if (!prereq_met) return c;
899 /* prepare arguments of QueryDomainInfo call */
900 s->query_domain.in.handle = &ctx->lsa.handle;
901 s->query_domain.in.level = LSA_POLICY_INFO_DOMAIN;
903 /* send the request */
904 query_req = dcerpc_lsa_QueryInfoPolicy_send(ctx->lsa.pipe, c, &s->query_domain);
905 if (composite_nomem(query_req, c)) return c;
907 composite_continue_rpc(c, query_req, continue_domain_queried, c);
913 * Stage 0.5 (optional): receive lsa domain handle and send
914 * request to query domain info
916 static void continue_lsa_domain_opened(struct composite_context *ctx)
918 struct composite_context *c;
919 struct userlist_state *s;
920 struct rpc_request *query_req;
922 c = talloc_get_type(ctx->async.private_data, struct composite_context);
923 s = talloc_get_type(c->private_data, struct userlist_state);
925 /* receive lsa domain handle */
926 c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
927 if (!composite_is_ok(c)) return;
929 /* prepare arguments of QueryDomainInfo call */
930 s->query_domain.in.handle = &s->ctx->lsa.handle;
931 s->query_domain.in.level = LSA_POLICY_INFO_DOMAIN;
933 /* send the request */
934 query_req = dcerpc_lsa_QueryInfoPolicy_send(s->ctx->lsa.pipe, c, &s->query_domain);
935 if (composite_nomem(query_req, c)) return;
937 composite_continue_rpc(c, query_req, continue_domain_queried, c);
942 * Stage 1: receive domain info and request to enum users,
943 * provided a valid samr handle is opened
945 static void continue_domain_queried(struct rpc_request *req)
947 struct composite_context *c;
948 struct userlist_state *s;
949 struct rpc_request *enum_req;
950 BOOL prereq_met = False;
952 c = talloc_get_type(req->async.private_data, struct composite_context);
953 s = talloc_get_type(c->private_data, struct userlist_state);
955 /* receive result of rpc request */
956 c->status = dcerpc_ndr_request_recv(req);
957 if (!composite_is_ok(c)) return;
959 /* get the returned domain info */
960 s->dominfo = s->query_domain.out.info->domain;
962 /* make sure we have samr domain handle before continuing */
963 prereq_met = samr_domain_opened(s->ctx, s->domain_name, &c, &s->domain_open,
964 continue_samr_domain_opened, s->monitor_fn);
965 if (!prereq_met) return;
967 /* prepare arguments od EnumDomainUsers call */
968 s->user_list.in.domain_handle = &s->ctx->samr.handle;
969 s->user_list.in.max_size = s->page_size;
970 s->user_list.in.resume_handle = &s->resume_index;
971 s->user_list.in.acct_flags = ACB_NORMAL;
972 s->user_list.out.resume_handle = &s->resume_index;
974 /* send the request */
975 enum_req = dcerpc_samr_EnumDomainUsers_send(s->ctx->samr.pipe, c, &s->user_list);
976 if (composite_nomem(enum_req, c)) return;
978 composite_continue_rpc(c, enum_req, continue_users_enumerated, c);
983 * Stage 1.5 (optional): receive samr domain handle
984 * and request to enumerate accounts
986 static void continue_samr_domain_opened(struct composite_context *ctx)
988 struct composite_context *c;
989 struct userlist_state *s;
990 struct rpc_request *enum_req;
992 c = talloc_get_type(ctx->async.private_data, struct composite_context);
993 s = talloc_get_type(c->private_data, struct userlist_state);
995 /* receive samr domain handle */
996 c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
997 if (!composite_is_ok(c)) return;
999 /* prepare arguments od EnumDomainUsers call */
1000 s->user_list.in.domain_handle = &s->ctx->samr.handle;
1001 s->user_list.in.max_size = s->page_size;
1002 s->user_list.in.resume_handle = &s->resume_index;
1003 s->user_list.in.acct_flags = ACB_NORMAL;
1004 s->user_list.out.resume_handle = &s->resume_index;
1006 /* send the request */
1007 enum_req = dcerpc_samr_EnumDomainUsers_send(s->ctx->samr.pipe, c, &s->user_list);
1008 if (composite_nomem(enum_req, c)) return;
1010 composite_continue_rpc(c, enum_req, continue_users_enumerated, c);
1015 * Stage 2: receive enumerated users and their rids
1017 static void continue_users_enumerated(struct rpc_request *req)
1019 struct composite_context *c;
1020 struct userlist_state *s;
1023 c = talloc_get_type(req->async.private_data, struct composite_context);
1024 s = talloc_get_type(c->private_data, struct userlist_state);
1026 /* receive result of rpc request */
1027 c->status = dcerpc_ndr_request_recv(req);
1028 if (!composite_is_ok(c)) return;
1030 /* get the actual status of the rpc call result (instead of rpc layer status) */
1031 c->status = s->user_list.out.result;
1033 /* we're interested in status "ok" as well as two enum-specific status codes */
1034 if (NT_STATUS_IS_OK(c->status) ||
1035 NT_STATUS_EQUAL(c->status, STATUS_MORE_ENTRIES) ||
1036 NT_STATUS_EQUAL(c->status, NT_STATUS_NO_MORE_ENTRIES)) {
1038 /* get enumerated accounts counter and resume handle (the latter allows
1039 making subsequent call to continue enumeration) */
1040 s->resume_index = *s->user_list.out.resume_handle;
1041 s->count = s->user_list.out.num_entries;
1043 /* prepare returned user accounts array */
1044 s->users = talloc_array(c, struct userlist, s->user_list.out.sam->count);
1045 if (composite_nomem(s->users, c)) return;
1047 for (i = 0; i < s->user_list.out.sam->count; i++) {
1048 struct dom_sid *user_sid;
1049 struct samr_SamEntry *entry = &s->user_list.out.sam->entries[i];
1050 struct dom_sid *domain_sid = s->query_domain.out.info->domain.sid;
1052 /* construct user sid from returned rid and queried domain sid */
1053 user_sid = dom_sid_add_rid(c, domain_sid, entry->idx);
1054 if (composite_nomem(user_sid, c)) return;
1057 s->users[i].username = talloc_strdup(c, entry->name.string);
1058 if (composite_nomem(s->users[i].username, c)) return;
1061 s->users[i].sid = dom_sid_string(c, user_sid);
1062 if (composite_nomem(s->users[i].sid, c)) return;
1069 /* something went wrong */
1070 composite_error(c, c->status);
1076 * Receive result of UserList call
1078 * @param c composite context returned by send request routine
1079 * @param mem_ctx memory context of this call
1080 * @param r pointer to a structure containing arguments and result of this call
1083 NTSTATUS libnet_UserList_recv(struct composite_context* c, TALLOC_CTX *mem_ctx,
1084 struct libnet_UserList *r)
1087 struct userlist_state *s;
1089 if (c == NULL || mem_ctx == NULL || r == NULL) {
1090 return NT_STATUS_INVALID_PARAMETER;
1093 status = composite_wait(c);
1094 if (NT_STATUS_IS_OK(status) ||
1095 NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) ||
1096 NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
1098 s = talloc_get_type(c->private_data, struct userlist_state);
1100 /* get results from composite context */
1101 r->out.count = s->count;
1102 r->out.resume_index = s->resume_index;
1103 r->out.users = talloc_steal(mem_ctx, s->users);
1105 if (NT_STATUS_IS_OK(status)) {
1106 r->out.error_string = talloc_strdup(mem_ctx, "Success");
1108 /* success, but we're not done yet */
1109 r->out.error_string = talloc_asprintf(mem_ctx, "Success (status: %s)",
1114 r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
1122 * Synchronous version of UserList call
1124 * @param ctx initialised libnet context
1125 * @param mem_ctx memory context of this call
1126 * @param r pointer to a structure containing arguments and result of this call
1129 NTSTATUS libnet_UserList(struct libnet_context *ctx,
1130 TALLOC_CTX *mem_ctx,
1131 struct libnet_UserList *r)
1133 struct composite_context *c;
1135 c = libnet_UserList_send(ctx, mem_ctx, r, NULL);
1136 return libnet_UserList_recv(c, mem_ctx, r);