Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-gmake3
[bbaumbach/samba-autobuild/.git] / source4 / libnet / libnet_user.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    Copyright (C) Rafal Szczesniak  2005
5    
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.
10    
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.
15    
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/>.
18 */
19
20
21 #include "includes.h"
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"
31
32
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;
38
39         /* information about the progress */
40         void (*monitor_fn)(struct monitor_msg *);
41 };
42
43
44 static void continue_rpc_useradd(struct composite_context *ctx);
45 static void continue_domain_open_create(struct composite_context *ctx);
46
47
48 /**
49  * Sends request to create user account
50  *
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
56  */
57 struct composite_context* libnet_CreateUser_send(struct libnet_context *ctx,
58                                                  TALLOC_CTX *mem_ctx,
59                                                  struct libnet_CreateUser *r,
60                                                  void (*monitor)(struct monitor_msg*))
61 {
62         struct composite_context *c;
63         struct create_user_state *s;
64         struct composite_context *create_req;
65         bool prereq_met = false;
66
67         /* composite context allocation and setup */
68         c = composite_create(mem_ctx, ctx->event_ctx);
69         if (c == NULL) return NULL;
70
71         s = talloc_zero(c, struct create_user_state);
72         if (composite_nomem(s, c)) return c;
73
74         c->private_data = s;
75
76         /* store arguments in the state structure */
77         s->ctx = ctx;
78         s->r   = *r;
79         ZERO_STRUCT(s->r.out);
80
81         /* prerequisite: make sure the domain is opened */
82         prereq_met = samr_domain_opened(ctx, s->r.in.domain_name, &c, &s->domain_open,
83                                         continue_domain_open_create, monitor);
84         if (!prereq_met) return c;
85
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;
89
90         /* send the request */
91         create_req = libnet_rpc_useradd_send(ctx->samr.pipe, &s->user_add, monitor);
92         if (composite_nomem(create_req, c)) return c;
93
94         /* set the next stage */
95         composite_continue(c, create_req, continue_rpc_useradd, c);
96         return c;
97 }
98
99
100 /*
101  * Stage 0.5 (optional): receive result of domain open request
102  * and send useradd request
103  */
104 static void continue_domain_open_create(struct composite_context *ctx)
105 {
106         struct composite_context *c;
107         struct create_user_state *s;
108         struct composite_context *create_req;
109         struct monitor_msg msg;
110
111         c = talloc_get_type(ctx->async.private_data, struct composite_context);
112         s = talloc_get_type(c->private_data, struct create_user_state);
113
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;
117
118         /* send monitor message */
119         if (s->monitor_fn) s->monitor_fn(&msg);
120         
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;
124
125         /* send the request */
126         create_req = libnet_rpc_useradd_send(s->ctx->samr.pipe, &s->user_add, s->monitor_fn);
127         if (composite_nomem(create_req, c)) return;
128
129         /* set the next stage */
130         composite_continue(c, create_req, continue_rpc_useradd, c);
131 }
132
133
134 /*
135  * Stage 1: receive result of useradd call
136  */
137 static void continue_rpc_useradd(struct composite_context *ctx)
138 {
139         struct composite_context *c;
140         struct create_user_state *s;
141         struct monitor_msg msg;
142
143         c = talloc_get_type(ctx->async.private_data, struct composite_context);
144         s = talloc_get_type(c->private_data, struct create_user_state);
145         
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;
149
150         /* send monitor message */
151         if (s->monitor_fn) s->monitor_fn(&msg);
152
153         /* we're done */
154         composite_done(c);
155 }
156
157
158 /**
159  * Receive result of CreateUser call
160  *
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
164  * @return nt status
165  */
166 NTSTATUS libnet_CreateUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
167                                 struct libnet_CreateUser *r)
168 {
169         NTSTATUS status;
170         struct create_user_state *s;
171
172         r->out.error_string = NULL;
173
174         /* wait for result of async request and check status code */
175         status = composite_wait(c);
176         if (!NT_STATUS_IS_OK(status)) {
177                 s = talloc_get_type(c->private_data, struct create_user_state);
178                 r->out.error_string = talloc_strdup(mem_ctx, nt_errstr(status));
179         }
180
181         return status;
182 }
183
184
185 /**
186  * Synchronous version of CreateUser call
187  *
188  * @param ctx initialised libnet context
189  * @param mem_ctx memory context of this call
190  * @param r pointer to a structure containing arguments and result of this call
191  * @return nt status
192  */
193 NTSTATUS libnet_CreateUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
194                            struct libnet_CreateUser *r)
195 {
196         struct composite_context *c;
197
198         c = libnet_CreateUser_send(ctx, mem_ctx, r, NULL);
199         return libnet_CreateUser_recv(c, mem_ctx, r);
200 }
201
202
203 struct delete_user_state {
204         struct libnet_DeleteUser r;
205         struct libnet_context *ctx;
206         struct libnet_DomainOpen domain_open;
207         struct libnet_rpc_userdel user_del;
208
209         /* information about the progress */
210         void (*monitor_fn)(struct monitor_msg *);
211 };
212
213
214 static void continue_rpc_userdel(struct composite_context *ctx);
215 static void continue_domain_open_delete(struct composite_context *ctx);
216
217
218 /**
219  * Sends request to delete user account
220  *
221  * @param ctx initialised libnet context
222  * @param mem_ctx memory context of this call
223  * @param r pointer to structure containing arguments and result of this call
224  * @param monitor function pointer for receiving monitor messages
225  */
226 struct composite_context *libnet_DeleteUser_send(struct libnet_context *ctx,
227                                                  TALLOC_CTX *mem_ctx,
228                                                  struct libnet_DeleteUser *r,
229                                                  void (*monitor)(struct monitor_msg*))
230 {
231         struct composite_context *c;
232         struct delete_user_state *s;
233         struct composite_context *delete_req;
234         bool prereq_met = false;
235
236         /* composite context allocation and setup */
237         c = composite_create(mem_ctx, ctx->event_ctx);
238         if (c == NULL) return NULL;
239
240         s = talloc_zero(c, struct delete_user_state);
241         if (composite_nomem(s, c)) return c;
242
243         c->private_data = s;
244
245         /* store arguments in state structure */
246         s->ctx = ctx;
247         s->r   = *r;
248         ZERO_STRUCT(s->r.out);
249         
250         /* prerequisite: make sure the domain is opened before proceeding */
251         prereq_met = samr_domain_opened(ctx, s->r.in.domain_name, &c, &s->domain_open,
252                                         continue_domain_open_delete, monitor);
253         if (!prereq_met) return c;
254
255         /* prepare arguments for userdel call */
256         s->user_del.in.username       = r->in.user_name;
257         s->user_del.in.domain_handle  = ctx->samr.handle;
258
259         /* send request */
260         delete_req = libnet_rpc_userdel_send(ctx->samr.pipe, &s->user_del, monitor);
261         if (composite_nomem(delete_req, c)) return c;
262         
263         /* set the next stage */
264         composite_continue(c, delete_req, continue_rpc_userdel, c);
265         return c;
266 }
267
268
269 /*
270  * Stage 0.5 (optional): receive result of domain open request
271  * and send useradd request
272  */
273 static void continue_domain_open_delete(struct composite_context *ctx)
274 {
275         struct composite_context *c;
276         struct delete_user_state *s;
277         struct composite_context *delete_req;
278         struct monitor_msg msg;
279
280         c = talloc_get_type(ctx->async.private_data, struct composite_context);
281         s = talloc_get_type(c->private_data, struct delete_user_state);
282
283         /* receive result of DomainOpen call */
284         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
285         if (!composite_is_ok(c)) return;
286         
287         /* send monitor message */
288         if (s->monitor_fn) s->monitor_fn(&msg);
289
290         /* prepare arguments for userdel call */
291         s->user_del.in.username       = s->r.in.user_name;
292         s->user_del.in.domain_handle  = s->ctx->samr.handle;
293
294         /* send request */
295         delete_req = libnet_rpc_userdel_send(s->ctx->samr.pipe, &s->user_del, s->monitor_fn);
296         if (composite_nomem(delete_req, c)) return;
297
298         /* set the next stage */
299         composite_continue(c, delete_req, continue_rpc_userdel, c);
300 }
301
302
303 /*
304  * Stage 1: receive result of userdel call and finish the composite function
305  */
306 static void continue_rpc_userdel(struct composite_context *ctx)
307 {
308         struct composite_context *c;
309         struct delete_user_state *s;
310         struct monitor_msg msg;
311
312         c = talloc_get_type(ctx->async.private_data, struct composite_context);
313         s = talloc_get_type(c->private_data, struct delete_user_state);
314
315         /* receive result of userdel call */
316         c->status = libnet_rpc_userdel_recv(ctx, c, &s->user_del);
317         if (!composite_is_ok(c)) return;
318
319         /* send monitor message */
320         if (s->monitor_fn) s->monitor_fn(&msg);
321
322         /* we're done */
323         composite_done(c);
324 }
325
326
327 /**
328  * Receives result of asynchronous DeleteUser call
329  *
330  * @param c composite context returned by async DeleteUser call
331  * @param mem_ctx memory context of this call
332  * @param r pointer to structure containing arguments and result
333  */
334 NTSTATUS libnet_DeleteUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
335                                 struct libnet_DeleteUser *r)
336 {
337         NTSTATUS status;
338         struct delete_user_state *s;
339
340         r->out.error_string = NULL;
341
342         /* wait for result of async request and check status code */
343         status = composite_wait(c);
344         if (!NT_STATUS_IS_OK(status)) {
345                 s = talloc_get_type(c->private_data, struct delete_user_state);
346                 r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
347         }
348         
349         return status;
350 }
351
352
353 /**
354  * Synchronous version of DeleteUser call
355  *
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
359  */
360 NTSTATUS libnet_DeleteUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
361                            struct libnet_DeleteUser *r)
362 {
363         struct composite_context *c;
364         
365         c = libnet_DeleteUser_send(ctx, mem_ctx, r, NULL);
366         return libnet_DeleteUser_recv(c, mem_ctx, r);
367 }
368
369
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;
376
377         void (*monitor_fn)(struct monitor_msg *);
378 };
379
380
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);
386
387
388 /**
389  * Sends request to modify user account
390  *
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
395  */
396 struct composite_context *libnet_ModifyUser_send(struct libnet_context *ctx,
397                                                  TALLOC_CTX *mem_ctx,
398                                                  struct libnet_ModifyUser *r,
399                                                  void (*monitor)(struct monitor_msg*))
400 {
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;
406
407         c = composite_create(mem_ctx, ctx->event_ctx);
408         if (c == NULL) return NULL;
409
410         s = talloc_zero(c, struct modify_user_state);
411         if (composite_nomem(s, c)) return c;
412
413         c->private_data = s;
414
415         s->ctx = ctx;
416         s->r = *r;
417
418         prereq_met = samr_domain_opened(ctx, s->r.in.domain_name, &c, &s->domain_open,
419                                         continue_domain_open_modify, monitor);
420         if (!prereq_met) return c;
421
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;
425
426         userinfo_req = libnet_rpc_userinfo_send(ctx->samr.pipe, &s->user_info, monitor);
427         if (composite_nomem(userinfo_req, c)) return c;
428
429         composite_continue(c, userinfo_req, continue_rpc_userinfo, c);
430         return c;
431 }
432
433
434 /*
435  * Stage 0.5 (optional): receive result of domain open request
436  * and send userinfo request
437  */
438 static void continue_domain_open_modify(struct composite_context *ctx)
439 {
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;
445
446         c = talloc_get_type(ctx->async.private_data, struct composite_context);
447         s = talloc_get_type(c->private_data, struct modify_user_state);
448
449         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
450         if (!composite_is_ok(c)) return;
451
452         if (s->monitor_fn) s->monitor_fn(&msg);
453         
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;
457
458         userinfo_req = libnet_rpc_userinfo_send(s->ctx->samr.pipe, &s->user_info, s->monitor_fn);
459         if (composite_nomem(userinfo_req, c)) return;
460         
461         composite_continue(c, userinfo_req, continue_rpc_userinfo, c);
462 }
463
464
465 /*
466  * Stage 1: receive result of userinfo call, prepare user changes
467  * (set the fields a caller required to change) and send usermod request
468  */
469 static void continue_rpc_userinfo(struct composite_context *ctx)
470 {
471         struct composite_context *c;
472         struct modify_user_state *s;
473         struct composite_context *usermod_req;
474
475         c = talloc_get_type(ctx->async.private_data, struct composite_context);
476         s = talloc_get_type(c->private_data, struct modify_user_state);
477
478         c->status = libnet_rpc_userinfo_recv(ctx, c, &s->user_info);
479         if (!composite_is_ok(c)) return;
480
481         s->user_mod.in.domain_handle = s->ctx->samr.handle;
482         s->user_mod.in.username      = s->r.in.user_name;
483
484         c->status = set_user_changes(c, &s->user_mod.in.change, &s->user_info, &s->r);
485
486         usermod_req = libnet_rpc_usermod_send(s->ctx->samr.pipe, &s->user_mod, s->monitor_fn);
487         if (composite_nomem(usermod_req, c)) return;
488
489         composite_continue(c, usermod_req, continue_rpc_usermod, c);
490 }
491
492
493 /*
494  * Prepare user changes: compare userinfo result to requested changes and
495  * set the field values and flags accordingly for user modify call
496  */
497 static NTSTATUS set_user_changes(TALLOC_CTX *mem_ctx, struct usermod_change *mod,
498                                  struct libnet_rpc_userinfo *info, struct libnet_ModifyUser *r)
499 {
500         struct samr_UserInfo21 *user;
501
502         if (mod == NULL || info == NULL || r == NULL || info->in.level != 21) {
503                 return NT_STATUS_INVALID_PARAMETER;
504         }
505
506         user = &info->out.info.info21;
507         mod->fields = 0;        /* reset flag field before setting individual flags */
508
509         /* account name change */
510         SET_FIELD_LSA_STRING(r->in, user, mod, account_name, USERMOD_FIELD_ACCOUNT_NAME);
511
512         /* full name change */
513         SET_FIELD_LSA_STRING(r->in, user, mod, full_name, USERMOD_FIELD_FULL_NAME);
514
515         /* description change */
516         SET_FIELD_LSA_STRING(r->in, user, mod, description, USERMOD_FIELD_DESCRIPTION);
517
518         /* comment change */
519         SET_FIELD_LSA_STRING(r->in, user, mod, comment, USERMOD_FIELD_COMMENT);
520
521         /* home directory change */
522         SET_FIELD_LSA_STRING(r->in, user, mod, home_directory, USERMOD_FIELD_HOME_DIRECTORY);
523
524         /* home drive change */
525         SET_FIELD_LSA_STRING(r->in, user, mod, home_drive, USERMOD_FIELD_HOME_DRIVE);
526
527         /* logon script change */
528         SET_FIELD_LSA_STRING(r->in, user, mod, logon_script, USERMOD_FIELD_LOGON_SCRIPT);
529
530         /* profile path change */
531         SET_FIELD_LSA_STRING(r->in, user, mod, profile_path, USERMOD_FIELD_PROFILE_PATH);
532
533         /* account expiry change */
534         SET_FIELD_NTTIME(r->in, user, mod, acct_expiry, USERMOD_FIELD_ACCT_EXPIRY);
535
536         /* account flags change */
537         SET_FIELD_ACCT_FLAGS(r->in, user, mod, acct_flags, USERMOD_FIELD_ACCT_FLAGS);
538
539         return NT_STATUS_OK;
540 }
541
542
543 /*
544  * Stage 2: receive result of usermod request and finish the composite function
545  */
546 static void continue_rpc_usermod(struct composite_context *ctx)
547 {
548         struct composite_context *c;
549         struct modify_user_state *s;
550         struct monitor_msg msg;
551
552         c = talloc_get_type(ctx->async.private_data, struct composite_context);
553         s = talloc_get_type(c->private_data, struct modify_user_state);
554         
555         c->status = libnet_rpc_usermod_recv(ctx, c, &s->user_mod);
556         if (!composite_is_ok(c)) return;
557         
558         if (s->monitor_fn) s->monitor_fn(&msg);
559         composite_done(c);
560 }
561
562
563 /**
564  * Receive result of ModifyUser call
565  *
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
569  * @return nt status
570  */
571 NTSTATUS libnet_ModifyUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
572                                 struct libnet_ModifyUser *r)
573 {
574         NTSTATUS status = composite_wait(c);
575         return status;
576 }
577
578
579 /**
580  * Synchronous version of ModifyUser call
581  *
582  * @param ctx initialised libnet context
583  * @param mem_ctx memory context of this call
584  * @param r pointer to a structure containing arguments and result of this call
585  * @return nt status
586  */
587 NTSTATUS libnet_ModifyUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
588                            struct libnet_ModifyUser *r)
589 {
590         struct composite_context *c;
591
592         c = libnet_ModifyUser_send(ctx, mem_ctx, r, NULL);
593         return libnet_ModifyUser_recv(c, mem_ctx, r);
594 }
595
596
597 struct user_info_state {
598         struct libnet_context *ctx;
599         const char *domain_name;
600         const char *user_name;
601         struct libnet_LookupName lookup;
602         struct libnet_DomainOpen domopen;
603         struct libnet_rpc_userinfo userinfo;
604
605         /* information about the progress */
606         void (*monitor_fn)(struct monitor_msg *);
607 };
608
609
610 static void continue_name_found(struct composite_context *ctx);
611 static void continue_domain_open_info(struct composite_context *ctx);
612 static void continue_info_received(struct composite_context *ctx);
613
614
615 /**
616  * Sends request to get user account information
617  *
618  * @param ctx initialised libnet context
619  * @param mem_ctx memory context of this call
620  * @param r pointer to a structure containing arguments and results of this call
621  * @param monitor function pointer for receiving monitor messages
622  * @return compostite context of this request
623  */
624 struct composite_context* libnet_UserInfo_send(struct libnet_context *ctx,
625                                                TALLOC_CTX *mem_ctx,
626                                                struct libnet_UserInfo *r,
627                                                void (*monitor)(struct monitor_msg*))
628 {
629         struct composite_context *c;
630         struct user_info_state *s;
631         struct composite_context *lookup_req;
632         bool prereq_met = false;
633
634         /* composite context allocation and setup */
635         c = composite_create(mem_ctx, ctx->event_ctx);
636         if (c == NULL) return NULL;
637
638         s = talloc_zero(c, struct user_info_state);
639         if (composite_nomem(s, c)) return c;
640
641         c->private_data = s;
642
643         /* store arguments in the state structure */
644         s->monitor_fn = monitor;
645         s->ctx = ctx;
646         s->domain_name = talloc_strdup(c, r->in.domain_name);
647         s->user_name = talloc_strdup(c, r->in.user_name);
648
649         /* prerequisite: make sure the domain is opened */
650         prereq_met = samr_domain_opened(ctx, s->domain_name, &c, &s->domopen,
651                                         continue_domain_open_info, monitor);
652         if (!prereq_met) return c;
653
654         /* prepare arguments for LookupName call */
655         s->lookup.in.domain_name = s->domain_name;
656         s->lookup.in.name        = s->user_name;
657
658         /* send the request */
659         lookup_req = libnet_LookupName_send(ctx, c, &s->lookup, s->monitor_fn);
660         if (composite_nomem(lookup_req, c)) return c;
661
662         /* set the next stage */
663         composite_continue(c, lookup_req, continue_name_found, c);
664         return c;
665 }
666
667
668 /*
669  * Stage 0.5 (optional): receive result of domain open request
670  * and send LookupName request
671  */
672 static void continue_domain_open_info(struct composite_context *ctx)
673 {
674         struct composite_context *c;
675         struct user_info_state *s;
676         struct composite_context *lookup_req;
677         struct monitor_msg msg;
678
679         c = talloc_get_type(ctx->async.private_data, struct composite_context);
680         s = talloc_get_type(c->private_data, struct user_info_state);
681
682         /* receive result of DomainOpen call */
683         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domopen);
684         if (!composite_is_ok(c)) return;
685
686         /* send monitor message */
687         if (s->monitor_fn) s->monitor_fn(&msg);
688
689         /* prepare arguments for LookupName call */
690         s->lookup.in.domain_name = s->domain_name;
691         s->lookup.in.name        = s->user_name;
692         
693         /* send the request */
694         lookup_req = libnet_LookupName_send(s->ctx, c, &s->lookup, s->monitor_fn);
695         if (composite_nomem(lookup_req, c)) return;
696
697         /* set the next stage */
698         composite_continue(c, lookup_req, continue_name_found, c);
699 }
700
701
702 /*
703  * Stage 1: receive the name (if found) and send userinfo request
704  */
705 static void continue_name_found(struct composite_context *ctx)
706 {
707         struct composite_context *c;
708         struct user_info_state *s;
709         struct composite_context *info_req;
710
711         c = talloc_get_type(ctx->async.private_data, struct composite_context);
712         s = talloc_get_type(c->private_data, struct user_info_state);
713
714         /* receive result of LookupName call */
715         c->status = libnet_LookupName_recv(ctx, c, &s->lookup);
716         if (!composite_is_ok(c)) return;
717
718         /* we're only interested in user accounts this time */
719         if (s->lookup.out.sid_type != SID_NAME_USER) {
720                 composite_error(c, NT_STATUS_NO_SUCH_USER);
721                 return;
722         }
723
724         /* prepare arguments for UserInfo call */
725         s->userinfo.in.domain_handle = s->ctx->samr.handle;
726         s->userinfo.in.sid = s->lookup.out.sidstr;
727         s->userinfo.in.level = 21;
728
729         /* send the request */
730         info_req = libnet_rpc_userinfo_send(s->ctx->samr.pipe, &s->userinfo, s->monitor_fn);
731         if (composite_nomem(info_req, c)) return;
732
733         /* set the next stage */
734         composite_continue(c, info_req, continue_info_received, c);
735 }
736
737
738 /*
739  * Stage 2: receive user account information and finish the composite function
740  */
741 static void continue_info_received(struct composite_context *ctx)
742 {
743         struct composite_context *c;
744         struct user_info_state *s;
745
746         c = talloc_get_type(ctx->async.private_data, struct composite_context);
747         s = talloc_get_type(c->private_data, struct user_info_state);
748         
749         /* receive result of userinfo call */
750         c->status = libnet_rpc_userinfo_recv(ctx, c, &s->userinfo);
751         if (!composite_is_ok(c)) return;
752
753         composite_done(c);
754 }
755
756
757 /**
758  * Receive result of UserInfo call
759  *
760  * @param c composite context returned by send request routine
761  * @param mem_ctx memory context of this call
762  * @param r pointer to a structure containing arguments and result of this call
763  * @return nt status
764  */
765 NTSTATUS libnet_UserInfo_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
766                               struct libnet_UserInfo *r)
767 {
768         NTSTATUS status;
769         struct user_info_state *s;
770
771         status = composite_wait(c);
772
773         if (NT_STATUS_IS_OK(status) && r != NULL) {
774                 struct samr_UserInfo21 *info;
775
776                 s = talloc_get_type(c->private_data, struct user_info_state);
777                 info = &s->userinfo.out.info.info21;
778
779                 r->out.user_sid = dom_sid_add_rid(mem_ctx, s->ctx->samr.sid, info->rid);
780                 r->out.primary_group_sid = dom_sid_add_rid(mem_ctx, s->ctx->samr.sid, info->primary_gid);
781
782                 /* string fields */
783                 r->out.account_name   = talloc_steal(mem_ctx, info->account_name.string);
784                 r->out.full_name      = talloc_steal(mem_ctx, info->full_name.string);
785                 r->out.description    = talloc_steal(mem_ctx, info->description.string);
786                 r->out.home_directory = talloc_steal(mem_ctx, info->home_directory.string);
787                 r->out.home_drive     = talloc_steal(mem_ctx, info->home_drive.string);
788                 r->out.comment        = talloc_steal(mem_ctx, info->comment.string);
789                 r->out.logon_script   = talloc_steal(mem_ctx, info->logon_script.string);
790                 r->out.profile_path   = talloc_steal(mem_ctx, info->profile_path.string);
791
792                 /* time fields (allocation) */
793                 r->out.acct_expiry           = talloc(mem_ctx, struct timeval);
794                 r->out.allow_password_change = talloc(mem_ctx, struct timeval);
795                 r->out.force_password_change = talloc(mem_ctx, struct timeval);
796                 r->out.last_logon            = talloc(mem_ctx, struct timeval);
797                 r->out.last_logoff           = talloc(mem_ctx, struct timeval);
798                 r->out.last_password_change  = talloc(mem_ctx, struct timeval);
799                 
800                 /* time fields (converting) */
801                 nttime_to_timeval(r->out.acct_expiry, info->acct_expiry);
802                 nttime_to_timeval(r->out.allow_password_change, info->allow_password_change);
803                 nttime_to_timeval(r->out.force_password_change, info->force_password_change);
804                 nttime_to_timeval(r->out.last_logon, info->last_logon);
805                 nttime_to_timeval(r->out.last_logoff, info->last_logoff);
806                 nttime_to_timeval(r->out.last_password_change, info->last_password_change);
807
808                 /* flag and number fields */
809                 r->out.acct_flags = info->acct_flags;
810
811                 r->out.error_string = talloc_strdup(mem_ctx, "Success");
812
813         } else {
814                 r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
815         }
816
817         talloc_free(c);
818         
819         return status;
820 }
821
822
823 /**
824  * Synchronous version of UserInfo call
825  *
826  * @param ctx initialised libnet context
827  * @param mem_ctx memory context of this call
828  * @param r pointer to a structure containing arguments and result of this call
829  * @return nt status
830  */
831 NTSTATUS libnet_UserInfo(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
832                          struct libnet_UserInfo *r)
833 {
834         struct composite_context *c;
835         
836         c = libnet_UserInfo_send(ctx, mem_ctx, r, NULL);
837         return libnet_UserInfo_recv(c, mem_ctx, r);
838 }
839
840
841 struct userlist_state {
842         struct libnet_context *ctx;
843         const char *domain_name;
844         struct lsa_DomainInfo dominfo;
845         int page_size;
846         uint32_t resume_index;
847         struct userlist *users;
848         uint32_t count;
849
850         struct libnet_DomainOpen domain_open;
851         struct lsa_QueryInfoPolicy query_domain;
852         struct samr_EnumDomainUsers user_list;
853
854         void (*monitor_fn)(struct monitor_msg*);
855 };
856
857
858 static void continue_lsa_domain_opened(struct composite_context *ctx);
859 static void continue_domain_queried(struct rpc_request *req);
860 static void continue_samr_domain_opened(struct composite_context *ctx);
861 static void continue_users_enumerated(struct rpc_request *req);
862
863
864 /**
865  * Sends request to list (enumerate) user accounts
866  *
867  * @param ctx initialised libnet context
868  * @param mem_ctx memory context of this call
869  * @param r pointer to structure containing arguments and results of this call
870  * @param monitor function pointer for receiving monitor messages
871  * @return compostite context of this request
872  */
873 struct composite_context* libnet_UserList_send(struct libnet_context *ctx,
874                                                TALLOC_CTX *mem_ctx,
875                                                struct libnet_UserList *r,
876                                                void (*monitor)(struct monitor_msg*))
877 {
878         struct composite_context *c;
879         struct userlist_state *s;
880         struct rpc_request *query_req;
881         bool prereq_met = false;
882
883         /* composite context allocation and setup */
884         c = composite_create(mem_ctx, ctx->event_ctx);
885         if (c == NULL) return NULL;
886
887         s = talloc_zero(c, struct userlist_state);
888         if (composite_nomem(s, c)) return c;
889
890         c->private_data = s;
891
892         /* store the arguments in the state structure */
893         s->ctx          = ctx;
894         s->page_size    = r->in.page_size;
895         s->resume_index = (uint32_t)r->in.resume_index;
896         s->domain_name  = talloc_strdup(c, r->in.domain_name);
897         s->monitor_fn   = monitor;
898
899         /* make sure we have lsa domain handle before doing anything */
900         prereq_met = lsa_domain_opened(ctx, s->domain_name, &c, &s->domain_open,
901                                        continue_lsa_domain_opened, monitor);
902         if (!prereq_met) return c;
903
904         /* prepare arguments of QueryDomainInfo call */
905         s->query_domain.in.handle = &ctx->lsa.handle;
906         s->query_domain.in.level  = LSA_POLICY_INFO_DOMAIN;
907         
908         /* send the request */
909         query_req = dcerpc_lsa_QueryInfoPolicy_send(ctx->lsa.pipe, c, &s->query_domain);
910         if (composite_nomem(query_req, c)) return c;
911
912         composite_continue_rpc(c, query_req, continue_domain_queried, c);
913         return c;
914 }
915
916
917 /*
918  * Stage 0.5 (optional): receive lsa domain handle and send
919  * request to query domain info
920  */
921 static void continue_lsa_domain_opened(struct composite_context *ctx)
922 {
923         struct composite_context *c;
924         struct userlist_state *s;
925         struct rpc_request *query_req;
926         
927         c = talloc_get_type(ctx->async.private_data, struct composite_context);
928         s = talloc_get_type(c->private_data, struct userlist_state);
929         
930         /* receive lsa domain handle */
931         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
932         if (!composite_is_ok(c)) return;
933
934         /* prepare arguments of QueryDomainInfo call */
935         s->query_domain.in.handle = &s->ctx->lsa.handle;
936         s->query_domain.in.level  = LSA_POLICY_INFO_DOMAIN;
937
938         /* send the request */
939         query_req = dcerpc_lsa_QueryInfoPolicy_send(s->ctx->lsa.pipe, c, &s->query_domain);
940         if (composite_nomem(query_req, c)) return;
941
942         composite_continue_rpc(c, query_req, continue_domain_queried, c);
943 }
944
945
946 /*
947  * Stage 1: receive domain info and request to enum users,
948  * provided a valid samr handle is opened
949  */
950 static void continue_domain_queried(struct rpc_request *req)
951 {
952         struct composite_context *c;
953         struct userlist_state *s;
954         struct rpc_request *enum_req;
955         bool prereq_met = false;
956         
957         c = talloc_get_type(req->async.private_data, struct composite_context);
958         s = talloc_get_type(c->private_data, struct userlist_state);
959
960         /* receive result of rpc request */
961         c->status = dcerpc_ndr_request_recv(req);
962         if (!composite_is_ok(c)) return;
963
964         /* get the returned domain info */
965         s->dominfo = s->query_domain.out.info->domain;
966
967         /* make sure we have samr domain handle before continuing */
968         prereq_met = samr_domain_opened(s->ctx, s->domain_name, &c, &s->domain_open,
969                                         continue_samr_domain_opened, s->monitor_fn);
970         if (!prereq_met) return;
971
972         /* prepare arguments of EnumDomainUsers call */
973         s->user_list.in.domain_handle = &s->ctx->samr.handle;
974         s->user_list.in.max_size = s->page_size;
975         s->user_list.in.resume_handle = &s->resume_index;
976         s->user_list.in.acct_flags = ACB_NORMAL;
977         s->user_list.out.resume_handle = &s->resume_index;
978
979         /* send the request */
980         enum_req = dcerpc_samr_EnumDomainUsers_send(s->ctx->samr.pipe, c, &s->user_list);
981         if (composite_nomem(enum_req, c)) return;
982
983         composite_continue_rpc(c, enum_req, continue_users_enumerated, c);
984 }
985
986
987 /*
988  * Stage 1.5 (optional): receive samr domain handle
989  * and request to enumerate accounts
990  */
991 static void continue_samr_domain_opened(struct composite_context *ctx)
992 {
993         struct composite_context *c;
994         struct userlist_state *s;
995         struct rpc_request *enum_req;
996
997         c = talloc_get_type(ctx->async.private_data, struct composite_context);
998         s = talloc_get_type(c->private_data, struct userlist_state);
999
1000         /* receive samr domain handle */
1001         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
1002         if (!composite_is_ok(c)) return;
1003
1004         /* prepare arguments of EnumDomainUsers call */
1005         s->user_list.in.domain_handle = &s->ctx->samr.handle;
1006         s->user_list.in.max_size = s->page_size;
1007         s->user_list.in.resume_handle = &s->resume_index;
1008         s->user_list.in.acct_flags = ACB_NORMAL;
1009         s->user_list.out.resume_handle = &s->resume_index;
1010         
1011         /* send the request */
1012         enum_req = dcerpc_samr_EnumDomainUsers_send(s->ctx->samr.pipe, c, &s->user_list);
1013         if (composite_nomem(enum_req, c)) return;
1014
1015         composite_continue_rpc(c, enum_req, continue_users_enumerated, c);
1016 }
1017
1018
1019 /*
1020  * Stage 2: receive enumerated users and their rids
1021  */
1022 static void continue_users_enumerated(struct rpc_request *req)
1023 {
1024         struct composite_context *c;
1025         struct userlist_state *s;
1026         int i;
1027
1028         c = talloc_get_type(req->async.private_data, struct composite_context);
1029         s = talloc_get_type(c->private_data, struct userlist_state);
1030
1031         /* receive result of rpc request */
1032         c->status = dcerpc_ndr_request_recv(req);
1033         if (!composite_is_ok(c)) return;
1034
1035         /* get the actual status of the rpc call result
1036            (instead of rpc layer status) */
1037         c->status = s->user_list.out.result;
1038
1039         /* we're interested in status "ok" as well as two
1040            enum-specific status codes */
1041         if (NT_STATUS_IS_OK(c->status) ||
1042             NT_STATUS_EQUAL(c->status, STATUS_MORE_ENTRIES) ||
1043             NT_STATUS_EQUAL(c->status, NT_STATUS_NO_MORE_ENTRIES)) {
1044
1045                 /* get enumerated accounts counter and resume handle (the latter allows
1046                    making subsequent call to continue enumeration) */
1047                 s->resume_index = *s->user_list.out.resume_handle;
1048                 s->count        = s->user_list.out.num_entries;
1049                 
1050                 /* prepare returned user accounts array */
1051                 s->users        = talloc_array(c, struct userlist, s->user_list.out.sam->count);
1052                 if (composite_nomem(s->users, c)) return;
1053
1054                 for (i = 0; i < s->user_list.out.sam->count; i++) {
1055                         struct dom_sid *user_sid;
1056                         struct samr_SamEntry *entry = &s->user_list.out.sam->entries[i];
1057                         struct dom_sid *domain_sid = s->query_domain.out.info->domain.sid;
1058                         
1059                         /* construct user sid from returned rid and queried domain sid */
1060                         user_sid = dom_sid_add_rid(c, domain_sid, entry->idx);
1061                         if (composite_nomem(user_sid, c)) return;
1062                         
1063                         /* username */
1064                         s->users[i].username = talloc_strdup(c, entry->name.string);
1065                         if (composite_nomem(s->users[i].username, c)) return;
1066
1067                         /* sid string */
1068                         s->users[i].sid = dom_sid_string(c, user_sid);
1069                         if (composite_nomem(s->users[i].sid, c)) return;
1070                 }
1071                 
1072                 /* that's it */
1073                 composite_done(c);
1074
1075         } else {
1076                 /* something went wrong */
1077                 composite_error(c, c->status);
1078         }
1079 }
1080
1081
1082 /**
1083  * Receive result of UserList call
1084  *
1085  * @param c composite context returned by send request routine
1086  * @param mem_ctx memory context of this call
1087  * @param r pointer to structure containing arguments and result of this call
1088  * @return nt status
1089  */
1090 NTSTATUS libnet_UserList_recv(struct composite_context* c, TALLOC_CTX *mem_ctx,
1091                               struct libnet_UserList *r)
1092 {
1093         NTSTATUS status;
1094         struct userlist_state *s;
1095
1096         if (c == NULL || mem_ctx == NULL || r == NULL) {
1097                 return NT_STATUS_INVALID_PARAMETER;
1098         }
1099         
1100         status = composite_wait(c);
1101         if (NT_STATUS_IS_OK(status) ||
1102             NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) ||
1103             NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
1104                 
1105                 s = talloc_get_type(c->private_data, struct userlist_state);
1106                 
1107                 /* get results from composite context */
1108                 r->out.count = s->count;
1109                 r->out.resume_index = s->resume_index;
1110                 r->out.users = talloc_steal(mem_ctx, s->users);
1111                 
1112                 if (NT_STATUS_IS_OK(status)) {
1113                         r->out.error_string = talloc_strdup(mem_ctx, "Success");
1114                 } else {
1115                         /* success, but we're not done yet */
1116                         r->out.error_string = talloc_asprintf(mem_ctx, "Success (status: %s)",
1117                                                               nt_errstr(status));
1118                 }
1119
1120         } else {
1121                 r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
1122         }
1123
1124         return status;
1125 }
1126
1127
1128 /**
1129  * Synchronous version of UserList call
1130  *
1131  * @param ctx initialised libnet context
1132  * @param mem_ctx memory context of this call
1133  * @param r pointer to structure containing arguments and result of this call
1134  * @return nt status
1135  */
1136 NTSTATUS libnet_UserList(struct libnet_context *ctx,
1137                          TALLOC_CTX *mem_ctx,
1138                          struct libnet_UserList *r)
1139 {
1140         struct composite_context *c;
1141
1142         c = libnet_UserList_send(ctx, mem_ctx, r, NULL);
1143         return libnet_UserList_recv(c, mem_ctx, r);
1144 }