r17856: The two new functions - libnet_LookupName and libnet_UserInfo.
[bbaumbach/samba-autobuild/.git] / source4 / libnet / libnet_user.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    Copyright (C) Rafal Szczesniak <mimir@samba.org> 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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21
22 #include "includes.h"
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.h"
29
30
31 /**
32  * Verify, before actually doing anything with user accounts, whether
33  * required domain is already opened and thus ready for operation.
34  * If it is not, or if the opened domain is not the one requested, open
35  * the requested domain.
36  */
37 static struct composite_context* domain_opened(struct libnet_context *ctx,
38                                                const char *domain_name,
39                                                struct composite_context *parent_ctx,
40                                                struct libnet_DomainOpen *domain_open,
41                                                void (*continue_fn)(struct composite_context*),
42                                                void (*monitor)(struct monitor_msg*))
43 {
44         struct composite_context *domopen_req;
45
46         if (domain_name == NULL) {
47                 /*
48                  * Try to guess the domain name from credentials,
49                  * if it's not been explicitly specified.
50                  */
51
52                 if (policy_handle_empty(&ctx->samr.handle)) {
53                         domain_open->in.domain_name = cli_credentials_get_domain(ctx->cred);
54                         domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
55
56                 } else {
57                         composite_error(parent_ctx, NT_STATUS_INVALID_PARAMETER);
58                         return parent_ctx;
59                 }
60
61         } else {
62                 /*
63                  * The domain name has been specified, so check whether the same
64                  * domain is already opened. If it is - just return NULL. Start
65                  * opening a new domain otherwise.
66                  */
67
68                 if (policy_handle_empty(&ctx->samr.handle) ||
69                     !strequal(domain_name, ctx->samr.name)) {
70                         domain_open->in.domain_name = domain_name;
71                         domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;                 
72
73                 } else {
74                         /* domain has already been opened and it's the same domain
75                            as requested */
76                         return NULL;
77                 }
78         }
79
80         /* send request to open the domain */
81         domopen_req = libnet_DomainOpen_send(ctx, domain_open, monitor);
82         if (composite_nomem(domopen_req, parent_ctx)) return parent_ctx;
83         
84         composite_continue(parent_ctx, domopen_req, continue_fn, parent_ctx);
85         return parent_ctx;
86 }
87
88
89 struct create_user_state {
90         struct libnet_CreateUser r;
91         struct libnet_DomainOpen domain_open;
92         struct libnet_rpc_useradd user_add;
93         struct libnet_context *ctx;
94
95         /* information about the progress */
96         void (*monitor_fn)(struct monitor_msg *);
97 };
98
99
100 static void continue_rpc_useradd(struct composite_context *ctx);
101 static void continue_domain_open_create(struct composite_context *ctx);
102
103
104 /**
105  * Sends request to create user account
106  *
107  * @param ctx initialised libnet context
108  * @param mem_ctx memory context of this call
109  * @param r pointer to a structure containing arguments and results of this call
110  * @param monitor function pointer for receiving monitor messages
111  * @return compostite context of this request
112  */
113 struct composite_context* libnet_CreateUser_send(struct libnet_context *ctx,
114                                                  TALLOC_CTX *mem_ctx,
115                                                  struct libnet_CreateUser *r,
116                                                  void (*monitor)(struct monitor_msg*))
117 {
118         struct composite_context *c;
119         struct create_user_state *s;
120         struct composite_context *create_req;
121         struct composite_context *prereq_ctx;
122
123         /* composite context allocation and setup */
124         c = talloc_zero(mem_ctx, struct composite_context);
125         if (c == NULL) return NULL;
126
127         s = talloc_zero(c, struct create_user_state);
128         if (composite_nomem(s, c)) return c;
129
130         c->state = COMPOSITE_STATE_IN_PROGRESS;
131         c->private_data = s;
132         c->event_ctx = ctx->event_ctx;
133
134         /* store arguments in the state structure */
135         s->ctx = ctx;
136         s->r   = *r;
137         ZERO_STRUCT(s->r.out);
138
139         /* prerequisite: make sure the domain is opened */
140         prereq_ctx = domain_opened(ctx, s->r.in.domain_name, c, &s->domain_open,
141                                    continue_domain_open_create, monitor);
142         if (prereq_ctx) return prereq_ctx;
143
144         /* prepare arguments for useradd call */
145         s->user_add.in.username       = r->in.user_name;
146         s->user_add.in.domain_handle  = ctx->samr.handle;
147
148         /* send the request */
149         create_req = libnet_rpc_useradd_send(ctx->samr.pipe, &s->user_add, monitor);
150         if (composite_nomem(create_req, c)) return c;
151
152         /* set the next stage */
153         composite_continue(c, create_req, continue_rpc_useradd, c);
154         return c;
155 }
156
157
158 /*
159  * Stage 0.5 (optional): receive result of domain open request
160  * and send useradd request
161  */
162 static void continue_domain_open_create(struct composite_context *ctx)
163 {
164         struct composite_context *c;
165         struct create_user_state *s;
166         struct composite_context *create_req;
167         struct monitor_msg msg;
168
169         c = talloc_get_type(ctx->async.private_data, struct composite_context);
170         s = talloc_get_type(c->private_data, struct create_user_state);
171
172         /* receive result of DomainOpen call */
173         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
174         if (!composite_is_ok(c)) return;
175
176         /* send monitor message */
177         if (s->monitor_fn) s->monitor_fn(&msg);
178         
179         /* prepare arguments for useradd call */
180         s->user_add.in.username       = s->r.in.user_name;
181         s->user_add.in.domain_handle  = s->ctx->samr.handle;
182
183         /* send the request */
184         create_req = libnet_rpc_useradd_send(s->ctx->samr.pipe, &s->user_add, s->monitor_fn);
185         if (composite_nomem(create_req, c)) return;
186
187         /* set the next stage */
188         composite_continue(c, create_req, continue_rpc_useradd, c);
189 }
190
191
192 /*
193  * Stage 1: receive result of useradd call
194  */
195 static void continue_rpc_useradd(struct composite_context *ctx)
196 {
197         struct composite_context *c;
198         struct create_user_state *s;
199         struct monitor_msg msg;
200
201         c = talloc_get_type(ctx->async.private_data, struct composite_context);
202         s = talloc_get_type(c->private_data, struct create_user_state);
203         
204         /* receive result of the call */
205         c->status = libnet_rpc_useradd_recv(ctx, c, &s->user_add);
206         if (!composite_is_ok(c)) return;
207
208         /* send monitor message */
209         if (s->monitor_fn) s->monitor_fn(&msg);
210
211         /* we're done */
212         composite_done(c);
213 }
214
215
216 /**
217  * Receive result of CreateUser call
218  *
219  * @param c composite context returned by send request routine
220  * @param mem_ctx memory context of this call
221  * @param r pointer to a structure containing arguments and result of this call
222  * @return nt status
223  */
224 NTSTATUS libnet_CreateUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
225                                 struct libnet_CreateUser *r)
226 {
227         NTSTATUS status;
228         struct create_user_state *s;
229
230         r->out.error_string = NULL;
231
232         /* wait for result of async request and check status code */
233         status = composite_wait(c);
234         if (!NT_STATUS_IS_OK(status)) {
235                 s = talloc_get_type(c->private_data, struct create_user_state);
236                 r->out.error_string = talloc_strdup(mem_ctx, nt_errstr(status));
237         }
238
239         return status;
240 }
241
242
243 /**
244  * Synchronous version of CreateUser call
245  *
246  * @param ctx initialised libnet context
247  * @param mem_ctx memory context of this call
248  * @param r pointer to a structure containing arguments and result of this call
249  * @return nt status
250  */
251 NTSTATUS libnet_CreateUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
252                            struct libnet_CreateUser *r)
253 {
254         struct composite_context *c;
255
256         c = libnet_CreateUser_send(ctx, mem_ctx, r, NULL);
257         return libnet_CreateUser_recv(c, mem_ctx, r);
258 }
259
260
261 struct delete_user_state {
262         struct libnet_DeleteUser r;
263         struct libnet_context *ctx;
264         struct libnet_DomainOpen domain_open;
265         struct libnet_rpc_userdel user_del;
266
267         /* information about the progress */
268         void (*monitor_fn)(struct monitor_msg *);
269 };
270
271
272 static void continue_rpc_userdel(struct composite_context *ctx);
273 static void continue_domain_open_delete(struct composite_context *ctx);
274
275
276 /**
277  * Sends request to delete user account
278  *
279  * @param ctx initialised libnet context
280  * @param mem_ctx memory context of this call
281  * @param r pointer to structure containing arguments and result of this call
282  * @param monitor function pointer for receiving monitor messages
283  */
284 struct composite_context *libnet_DeleteUser_send(struct libnet_context *ctx,
285                                                  TALLOC_CTX *mem_ctx,
286                                                  struct libnet_DeleteUser *r,
287                                                  void (*monitor)(struct monitor_msg*))
288 {
289         struct composite_context *c;
290         struct delete_user_state *s;
291         struct composite_context *delete_req;
292         struct composite_context *prereq_ctx;
293
294         /* composite context allocation and setup */
295         c = talloc_zero(mem_ctx, struct composite_context);
296         if (c == NULL) return NULL;
297
298         s = talloc_zero(c, struct delete_user_state);
299         if (composite_nomem(s, c)) return c;
300
301         c->private_data = s;
302         c->state = COMPOSITE_STATE_IN_PROGRESS;
303         c->event_ctx = ctx->event_ctx;
304
305         /* store arguments in state structure */
306         s->ctx = ctx;
307         s->r   = *r;
308         ZERO_STRUCT(s->r.out);
309         
310         /* prerequisite: make sure the domain is opened before proceeding */
311         prereq_ctx = domain_opened(ctx, s->r.in.domain_name, c, &s->domain_open,
312                                    continue_domain_open_delete, monitor);
313         if (prereq_ctx) return prereq_ctx;
314
315         /* prepare arguments for userdel call */
316         s->user_del.in.username       = r->in.user_name;
317         s->user_del.in.domain_handle  = ctx->samr.handle;
318
319         /* send request */
320         delete_req = libnet_rpc_userdel_send(ctx->samr.pipe, &s->user_del, monitor);
321         if (composite_nomem(delete_req, c)) return c;
322         
323         /* set the next stage */
324         composite_continue(c, delete_req, continue_rpc_userdel, c);
325         return c;
326 }
327
328
329 /*
330  * Stage 0.5 (optional): receive result of domain open request
331  * and send useradd request
332  */
333 static void continue_domain_open_delete(struct composite_context *ctx)
334 {
335         struct composite_context *c;
336         struct delete_user_state *s;
337         struct composite_context *delete_req;
338         struct monitor_msg msg;
339
340         c = talloc_get_type(ctx->async.private_data, struct composite_context);
341         s = talloc_get_type(c->private_data, struct delete_user_state);
342
343         /* receive result of DomainOpen call */
344         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
345         if (!composite_is_ok(c)) return;
346         
347         /* send monitor message */
348         if (s->monitor_fn) s->monitor_fn(&msg);
349
350         /* prepare arguments for userdel call */
351         s->user_del.in.username       = s->r.in.user_name;
352         s->user_del.in.domain_handle  = s->ctx->samr.handle;
353
354         /* send request */
355         delete_req = libnet_rpc_userdel_send(s->ctx->samr.pipe, &s->user_del, s->monitor_fn);
356         if (composite_nomem(delete_req, c)) return;
357
358         /* set the next stage */
359         composite_continue(c, delete_req, continue_rpc_userdel, c);
360 }
361
362
363 static void continue_rpc_userdel(struct composite_context *ctx)
364 {
365         struct composite_context *c;
366         struct delete_user_state *s;
367         struct monitor_msg msg;
368
369         c = talloc_get_type(ctx->async.private_data, struct composite_context);
370         s = talloc_get_type(c->private_data, struct delete_user_state);
371
372         /* receive result of userdel call */
373         c->status = libnet_rpc_userdel_recv(ctx, c, &s->user_del);
374         if (!composite_is_ok(c)) return;
375
376         /* send monitor message */
377         if (s->monitor_fn) s->monitor_fn(&msg);
378
379         /* we're done */
380         composite_done(c);
381 }
382
383
384 /**
385  * Receives result of asynchronous DeleteUser call
386  *
387  * @param c composite context returned by async DeleteUser call
388  * @param mem_ctx memory context of this call
389  * @param r pointer to structure containing arguments and result
390  */
391 NTSTATUS libnet_DeleteUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
392                                 struct libnet_DeleteUser *r)
393 {
394         NTSTATUS status;
395         struct delete_user_state *s;
396
397         r->out.error_string = NULL;
398
399         /* wait for result of async request and check status code */
400         status = composite_wait(c);
401         if (!NT_STATUS_IS_OK(status)) {
402                 s = talloc_get_type(c->private_data, struct delete_user_state);
403                 r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
404         }
405         
406         return status;
407 }
408
409
410 /**
411  * Synchronous version of DeleteUser call
412  *
413  * @param ctx initialised libnet context
414  * @param mem_ctx memory context of this call
415  * @param r pointer to structure containing arguments and result
416  */
417 NTSTATUS libnet_DeleteUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
418                            struct libnet_DeleteUser *r)
419 {
420         struct composite_context *c;
421         
422         c = libnet_DeleteUser_send(ctx, mem_ctx, r, NULL);
423         return libnet_DeleteUser_recv(c, mem_ctx, r);
424 }
425
426
427 struct modify_user_state {
428         struct libnet_ModifyUser r;
429         struct libnet_context *ctx;
430         struct libnet_DomainOpen domain_open;
431         struct libnet_rpc_userinfo user_info;
432         struct libnet_rpc_usermod user_mod;
433
434         void (*monitor_fn)(struct monitor_msg *);
435 };
436
437
438 static void continue_rpc_usermod(struct composite_context *ctx);
439 static void continue_domain_open_modify(struct composite_context *ctx);
440 static NTSTATUS set_user_changes(TALLOC_CTX *mem_ctx, struct usermod_change *mod,
441                                  struct libnet_rpc_userinfo *info, struct libnet_ModifyUser *r);
442 static void continue_rpc_userinfo(struct composite_context *ctx);
443
444
445 struct composite_context *libnet_ModifyUser_send(struct libnet_context *ctx,
446                                                  TALLOC_CTX *mem_ctx,
447                                                  struct libnet_ModifyUser *r,
448                                                  void (*monitor)(struct monitor_msg*))
449 {
450         struct composite_context *c;
451         struct modify_user_state *s;
452         struct composite_context *prereq_ctx;
453         struct composite_context *userinfo_req;
454
455         c = talloc_zero(mem_ctx, struct composite_context);
456         if (c == NULL) return NULL;
457
458         s = talloc_zero(c, struct modify_user_state);
459         if (composite_nomem(s, c)) return c;
460
461         c->state = COMPOSITE_STATE_IN_PROGRESS;
462         c->private_data = s;
463         c->event_ctx = ctx->event_ctx;
464
465         s->ctx = ctx;
466         s->r = *r;
467
468         prereq_ctx = domain_opened(ctx, s->r.in.domain_name, c, &s->domain_open,
469                                    continue_domain_open_modify, monitor);
470         if (prereq_ctx) return prereq_ctx;
471
472         s->user_mod.in.username      = r->in.user_name;
473         s->user_mod.in.domain_handle = ctx->samr.handle;
474
475         userinfo_req = libnet_rpc_userinfo_send(ctx->samr.pipe, &s->user_info, monitor);
476         if (composite_nomem(userinfo_req, c)) return c;
477
478         composite_continue(c, userinfo_req, continue_rpc_userinfo, c);
479         return c;
480 }
481
482
483 static void continue_domain_open_modify(struct composite_context *ctx)
484 {
485         const uint16_t level = 21;
486         struct composite_context *c;
487         struct modify_user_state *s;
488         struct composite_context *userinfo_req;
489         struct monitor_msg msg;
490
491         c = talloc_get_type(ctx->async.private_data, struct composite_context);
492         s = talloc_get_type(c->private_data, struct modify_user_state);
493
494         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
495         if (!composite_is_ok(c)) return;
496
497         if (s->monitor_fn) s->monitor_fn(&msg);
498         
499         s->user_info.in.domain_handle  = s->ctx->samr.handle;
500         s->user_info.in.username       = s->r.in.user_name;
501         s->user_info.in.level          = level;
502
503         userinfo_req = libnet_rpc_userinfo_send(s->ctx->samr.pipe, &s->user_info, s->monitor_fn);
504         if (composite_nomem(userinfo_req, c)) return;
505         
506         composite_continue(c, userinfo_req, continue_rpc_userinfo, c);
507 }
508
509
510 static void continue_rpc_userinfo(struct composite_context *ctx)
511 {
512         struct composite_context *c;
513         struct modify_user_state *s;
514         struct composite_context *usermod_req;
515
516         c = talloc_get_type(ctx->async.private_data, struct composite_context);
517         s = talloc_get_type(c->private_data, struct modify_user_state);
518
519         c->status = libnet_rpc_userinfo_recv(ctx, c, &s->user_info);
520         if (!composite_is_ok(c)) return;
521
522         s->user_mod.in.domain_handle = s->ctx->samr.handle;
523         s->user_mod.in.username      = s->r.in.user_name;
524
525         c->status = set_user_changes(c, &s->user_mod.in.change, &s->user_info, &s->r);
526
527         usermod_req = libnet_rpc_usermod_send(s->ctx->samr.pipe, &s->user_mod, s->monitor_fn);
528         if (composite_nomem(usermod_req, c)) return;
529
530         composite_continue(c, usermod_req, continue_rpc_usermod, c);
531 }
532
533
534 static NTSTATUS set_user_changes(TALLOC_CTX *mem_ctx, struct usermod_change *mod,
535                                  struct libnet_rpc_userinfo *info, struct libnet_ModifyUser *r)
536 {
537         struct samr_UserInfo21 *user;
538
539         if (mod == NULL || info == NULL || r == NULL || info->in.level != 21) {
540                 return NT_STATUS_INVALID_PARAMETER;
541         }
542
543         user = &info->out.info.info21;
544         mod->fields = 0;        /* reset flag field before setting individual flags */
545
546         /* account name change */
547         SET_FIELD_LSA_STRING(r->in, user, mod, account_name, USERMOD_FIELD_ACCOUNT_NAME);
548
549         /* full name change */
550         SET_FIELD_LSA_STRING(r->in, user, mod, full_name, USERMOD_FIELD_FULL_NAME);
551
552         /* description change */
553         SET_FIELD_LSA_STRING(r->in, user, mod, comment, USERMOD_FIELD_DESCRIPTION);
554
555         /* comment change */
556         SET_FIELD_LSA_STRING(r->in, user, mod, comment, USERMOD_FIELD_COMMENT);
557
558         /* home directory change */
559         SET_FIELD_LSA_STRING(r->in, user, mod, home_directory, USERMOD_FIELD_HOME_DIRECTORY);
560
561         /* home drive change */
562         SET_FIELD_LSA_STRING(r->in, user, mod, home_drive, USERMOD_FIELD_HOME_DRIVE);
563
564         /* logon script change */
565         SET_FIELD_LSA_STRING(r->in, user, mod, logon_script, USERMOD_FIELD_LOGON_SCRIPT);
566
567         /* profile path change */
568         SET_FIELD_LSA_STRING(r->in, user, mod, profile_path, USERMOD_FIELD_PROFILE_PATH);
569
570         /* allow password change time */
571         SET_FIELD_NTTIME(r->in, user, mod, allow_password_change, USERMOD_FIELD_ALLOW_PASS_CHG);
572
573         /* force password change time */
574         SET_FIELD_NTTIME(r->in, user, mod, force_password_change, USERMOD_FIELD_FORCE_PASS_CHG);
575
576         /* account expiry change */
577         SET_FIELD_NTTIME(r->in, user, mod, acct_expiry, USERMOD_FIELD_ACCT_EXPIRY);
578
579         return NT_STATUS_OK;
580 }
581
582
583 static void continue_rpc_usermod(struct composite_context *ctx)
584 {
585         struct composite_context *c;
586         struct modify_user_state *s;
587         struct monitor_msg msg;
588
589         c = talloc_get_type(ctx->async.private_data, struct composite_context);
590         s = talloc_get_type(c->private_data, struct modify_user_state);
591         
592         c->status = libnet_rpc_usermod_recv(ctx, c, &s->user_mod);
593         if (!composite_is_ok(c)) return;
594         
595         if (s->monitor_fn) s->monitor_fn(&msg);
596         composite_done(c);
597 }
598
599
600 NTSTATUS libnet_ModifyUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
601                                 struct libnet_ModifyUser *r)
602 {
603         NTSTATUS status = composite_wait(c);
604         return status;
605 }
606
607
608 NTSTATUS libnet_ModifyUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
609                            struct libnet_ModifyUser *r)
610 {
611         struct composite_context *c;
612
613         c = libnet_ModifyUser_send(ctx, mem_ctx, r, NULL);
614         return libnet_ModifyUser_recv(c, mem_ctx, r);
615 }
616
617
618 struct user_info_state {
619         struct libnet_context *ctx;
620         const char *domain_name;
621         struct libnet_LookupName lookup;
622         struct libnet_DomainOpen domopen;
623         struct libnet_rpc_userinfo userinfo;
624
625         /* information about the progress */
626         void (*monitor_fn)(struct monitor_msg *);
627 };
628
629
630 static void continue_name_found(struct composite_context *ctx);
631 static void continue_domain_opened(struct composite_context *ctx);
632 static void continue_info_received(struct composite_context *ctx);
633
634
635 struct composite_context* libnet_UserInfo_send(struct libnet_context *ctx,
636                                                TALLOC_CTX *mem_ctx,
637                                                struct libnet_UserInfo *r,
638                                                void (*monitor)(struct monitor_msg*))
639 {
640         struct composite_context *c;
641         struct user_info_state *s;
642         struct composite_context *lookup_req;
643
644         c = composite_create(mem_ctx, ctx->event_ctx);
645         if (c == NULL) return NULL;
646
647         s = talloc_zero(c, struct user_info_state);
648         if (composite_nomem(s, c)) return c;
649
650         c->private_data = s;
651
652         s->monitor_fn = monitor;
653         s->ctx = ctx;
654         s->domain_name = talloc_strdup(c, r->in.domain_name);
655
656         s->lookup.in.domain_name = s->domain_name;
657         s->lookup.in.name        = talloc_strdup(c, r->in.user_name);
658
659         lookup_req = libnet_LookupName_send(ctx, c, &s->lookup, s->monitor_fn);
660         if (composite_nomem(lookup_req, c)) return c;
661
662         composite_continue(c, lookup_req, continue_name_found, c);
663         return c;
664 }
665
666
667 static void continue_name_found(struct composite_context *ctx)
668 {
669         struct composite_context *c;
670         struct user_info_state *s;
671         struct composite_context *domopen_req;
672
673         c = talloc_get_type(ctx->async.private_data, struct composite_context);
674         s = talloc_get_type(c->private_data, struct user_info_state);
675
676         c->status = libnet_LookupName_recv(ctx, c, &s->lookup);
677         if (!composite_is_ok(c)) return;
678
679         if (s->lookup.out.sid_type != SID_NAME_USER) {
680                 composite_error(c, NT_STATUS_NO_SUCH_USER);
681                 return;
682         }
683
684         s->domopen.in.type = DOMAIN_SAMR;
685         s->domopen.in.domain_name = s->domain_name;
686         s->domopen.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
687
688         domopen_req = libnet_DomainOpen_send(s->ctx, &s->domopen, s->monitor_fn);
689         if (composite_nomem(domopen_req, c)) return;
690         
691         composite_continue(c, domopen_req, continue_domain_opened, c);
692 }
693
694
695 static void continue_domain_opened(struct composite_context *ctx)
696 {
697         struct composite_context *c;
698         struct user_info_state *s;
699         struct composite_context *info_req;
700
701         c = talloc_get_type(ctx->async.private_data, struct composite_context);
702         s = talloc_get_type(c->private_data, struct user_info_state);
703
704         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domopen);
705         if (!composite_is_ok(c)) return;
706
707         s->userinfo.in.domain_handle = s->ctx->samr.handle;
708         s->userinfo.in.sid = s->lookup.out.sidstr;
709         s->userinfo.in.level = 21;
710
711         info_req = libnet_rpc_userinfo_send(s->ctx->samr.pipe, &s->userinfo, s->monitor_fn);
712         if (composite_nomem(info_req, c)) return;
713
714         composite_continue(c, info_req, continue_info_received, c);
715 }
716
717
718 static void continue_info_received(struct composite_context *ctx)
719 {
720         struct composite_context *c;
721         struct user_info_state *s;
722
723         c = talloc_get_type(ctx->async.private_data, struct composite_context);
724         s = talloc_get_type(c->private_data, struct user_info_state);
725         
726         c->status = libnet_rpc_userinfo_recv(ctx, c, &s->userinfo);
727         if (!composite_is_ok(c)) return;
728
729         composite_done(c);
730 }
731
732
733 NTSTATUS libnet_UserInfo_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
734                               struct libnet_UserInfo *r)
735 {
736         NTSTATUS status;
737         struct user_info_state *s;
738
739         status = composite_wait(c);
740
741         if (NT_STATUS_IS_OK(status) && r != NULL) {
742                 struct samr_UserInfo21 *info;
743
744                 s = talloc_get_type(c->private_data, struct user_info_state);
745                 info = &s->userinfo.out.info.info21;
746
747                 r->out.account_name   = talloc_steal(mem_ctx, info->account_name.string);
748                 r->out.full_name      = talloc_steal(mem_ctx, info->full_name.string);
749                 r->out.description    = talloc_steal(mem_ctx, info->description.string);
750                 r->out.home_directory = talloc_steal(mem_ctx, info->home_directory.string);
751                 r->out.home_drive     = talloc_steal(mem_ctx, info->home_drive.string);
752                 r->out.comment        = talloc_steal(mem_ctx, info->comment.string);
753                 r->out.logon_script   = talloc_steal(mem_ctx, info->logon_script.string);
754                 r->out.profile_path   = talloc_steal(mem_ctx, info->profile_path.string);
755
756                 r->out.error_string = talloc_strdup(mem_ctx, "Success");
757         }
758
759         talloc_free(c);
760         
761         return status;
762 }
763
764
765 NTSTATUS libnet_UserInfo(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
766                          struct libnet_UserInfo *r)
767 {
768         struct composite_context *c;
769         
770         c = libnet_UserInfo_send(ctx, mem_ctx, r, NULL);
771         return libnet_UserInfo_recv(c, mem_ctx, r);
772 }