62d4e0edd21d9928a2905333e5e1fbed4f7039ea
[bbaumbach/samba-autobuild/.git] / source4 / libnet / userman.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   a composite functions for user management operations (add/del/chg)
22 */
23
24 #include "includes.h"
25 #include "libcli/composite/composite.h"
26 #include "libnet/libnet.h"
27 #include "librpc/gen_ndr/ndr_samr_c.h"
28
29 /*
30  * Composite USER ADD functionality
31  */
32
33 struct useradd_state {
34         struct dcerpc_pipe       *pipe;
35         struct rpc_request       *req;
36         struct policy_handle     domain_handle;
37         struct samr_CreateUser   createuser;
38         struct policy_handle     user_handle;
39         uint32_t                 user_rid;
40
41         /* information about the progress */
42         void (*monitor_fn)(struct monitor_msg *);
43 };
44
45
46 static void continue_useradd_create(struct rpc_request *req);
47
48
49 /**
50  * Stage 1 (and the only one for now): Create user account.
51  */
52 static void continue_useradd_create(struct rpc_request *req)
53 {
54         struct composite_context *c;
55         struct useradd_state *s;
56
57         c = talloc_get_type(req->async.private_data, struct composite_context);
58         s = talloc_get_type(c->private_data, struct useradd_state);
59
60         /* check rpc layer status code */
61         c->status = dcerpc_ndr_request_recv(s->req);
62         if (!composite_is_ok(c)) return;
63
64         /* check create user call status code */
65         c->status = s->createuser.out.result;
66
67         /* get created user account data */
68         s->user_handle = *s->createuser.out.user_handle;
69         s->user_rid    = *s->createuser.out.rid;
70
71         /* issue a monitor message */
72         if (s->monitor_fn) {
73                 struct monitor_msg msg;
74                 struct msg_rpc_create_user rpc_create;
75
76                 rpc_create.rid = *s->createuser.out.rid;
77
78                 msg.type      = mon_SamrCreateUser;
79                 msg.data      = (void*)&rpc_create;
80                 msg.data_size = sizeof(rpc_create);
81                 
82                 s->monitor_fn(&msg);
83         }
84         
85         composite_done(c);
86 }
87
88
89 /**
90  * Sends asynchronous useradd request
91  *
92  * @param p dce/rpc call pipe 
93  * @param io arguments and results of the call
94  * @param monitor monitor function for providing information about the progress
95  */
96
97 struct composite_context *libnet_rpc_useradd_send(struct dcerpc_pipe *p,
98                                                   struct libnet_rpc_useradd *io,
99                                                   void (*monitor)(struct monitor_msg*))
100 {
101         struct composite_context *c;
102         struct useradd_state *s;
103
104         if (!p || !io) return NULL;
105
106         /* composite allocation and setup */
107         c = composite_create(p, dcerpc_event_context(p));
108         if (c == NULL) return NULL;
109         
110         s = talloc_zero(c, struct useradd_state);
111         if (composite_nomem(s, c)) return c;
112         
113         c->private_data = s;
114
115         /* put passed arguments to the state structure */
116         s->domain_handle = io->in.domain_handle;
117         s->pipe          = p;
118         s->monitor_fn    = monitor;
119         
120         /* preparing parameters to send rpc request */
121         s->createuser.in.domain_handle         = &io->in.domain_handle;
122
123         s->createuser.in.account_name          = talloc_zero(c, struct lsa_String);
124         if (composite_nomem(s->createuser.in.account_name, c)) return c;
125
126         s->createuser.in.account_name->string  = talloc_strdup(c, io->in.username);
127         if (composite_nomem(s->createuser.in.account_name->string, c)) return c;
128
129         s->createuser.out.user_handle          = &s->user_handle;
130         s->createuser.out.rid                  = &s->user_rid;
131
132         /* send the request */
133         s->req = dcerpc_samr_CreateUser_send(p, c, &s->createuser);
134         if (composite_nomem(s->req, c)) return c;
135
136         composite_continue_rpc(c, s->req, continue_useradd_create, c);
137         return c;
138 }
139
140
141 /**
142  * Waits for and receives result of asynchronous useradd call
143  * 
144  * @param c composite context returned by asynchronous useradd call
145  * @param mem_ctx memory context of the call
146  * @param io pointer to results (and arguments) of the call
147  * @return nt status code of execution
148  */
149
150 NTSTATUS libnet_rpc_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
151                                  struct libnet_rpc_useradd *io)
152 {
153         NTSTATUS status;
154         struct useradd_state *s;
155         
156         status = composite_wait(c);
157         
158         if (NT_STATUS_IS_OK(status) && io) {
159                 /* get and return result of the call */
160                 s = talloc_get_type(c->private_data, struct useradd_state);
161                 io->out.user_handle = s->user_handle;
162         }
163
164         talloc_free(c);
165         return status;
166 }
167
168
169 /**
170  * Synchronous version of useradd call
171  *
172  * @param pipe dce/rpc call pipe
173  * @param mem_ctx memory context for the call
174  * @param io arguments and results of the call
175  * @return nt status code of execution
176  */
177
178 NTSTATUS libnet_rpc_useradd(struct dcerpc_pipe *p,
179                             TALLOC_CTX *mem_ctx,
180                             struct libnet_rpc_useradd *io)
181 {
182         struct composite_context *c = libnet_rpc_useradd_send(p, io, NULL);
183         return libnet_rpc_useradd_recv(c, mem_ctx, io);
184 }
185
186
187
188 /*
189  * Composite USER DELETE functionality
190  */
191
192
193 struct userdel_state {
194         struct dcerpc_pipe        *pipe;
195         struct policy_handle      domain_handle;
196         struct policy_handle      user_handle;
197         struct samr_LookupNames   lookupname;
198         struct samr_OpenUser      openuser;
199         struct samr_DeleteUser    deleteuser;
200
201         /* information about the progress */
202         void (*monitor_fn)(struct monitor_msg *);
203 };
204
205
206 static void continue_userdel_name_found(struct rpc_request *req);
207 static void continue_userdel_user_opened(struct rpc_request* req);
208 static void continue_userdel_deleted(struct rpc_request *req);
209
210
211 /**
212  * Stage 1: Lookup the user name and resolve it to rid
213  */
214 static void continue_userdel_name_found(struct rpc_request *req)
215 {
216         struct composite_context *c;
217         struct userdel_state *s;
218         struct rpc_request *openuser_req;
219         struct monitor_msg msg;
220
221         c = talloc_get_type(req->async.private_data, struct composite_context);
222         s = talloc_get_type(c->private_data, struct userdel_state);
223
224         /* receive samr_LookupNames result */
225         c->status = dcerpc_ndr_request_recv(req);
226         if (!composite_is_ok(c)) return;
227
228         c->status = s->lookupname.out.result;
229         if (!NT_STATUS_IS_OK(c->status)) {
230                 composite_error(c, c->status);
231                 return;
232         }
233
234         /* what to do when there's no user account to delete
235            and what if there's more than one rid resolved */
236         if (!s->lookupname.out.rids->count) {
237                 c->status = NT_STATUS_NO_SUCH_USER;
238                 composite_error(c, c->status);
239                 return;
240
241         } else if (!s->lookupname.out.rids->count > 1) {
242                 c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
243                 composite_error(c, c->status);
244                 return;
245         }
246
247         /* issue a monitor message */
248         if (s->monitor_fn) {
249                 struct msg_rpc_lookup_name msg_lookup;
250
251                 msg_lookup.rid   = s->lookupname.out.rids->ids;
252                 msg_lookup.count = s->lookupname.out.rids->count;
253
254                 msg.type      = mon_SamrLookupName;
255                 msg.data      = (void*)&msg_lookup;
256                 msg.data_size = sizeof(msg_lookup);
257                 s->monitor_fn(&msg);
258         }
259
260         /* prepare the arguments for rpc call */
261         s->openuser.in.domain_handle = &s->domain_handle;
262         s->openuser.in.rid           = s->lookupname.out.rids->ids[0];
263         s->openuser.in.access_mask   = SEC_FLAG_MAXIMUM_ALLOWED;
264         s->openuser.out.user_handle  = &s->user_handle;
265
266         /* send rpc request */
267         openuser_req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
268         if (composite_nomem(openuser_req, c)) return;
269
270         composite_continue_rpc(c, openuser_req, continue_userdel_user_opened, c);
271 }
272
273
274 /**
275  * Stage 2: Open user account.
276  */
277 static void continue_userdel_user_opened(struct rpc_request* req)
278 {
279         struct composite_context *c;
280         struct userdel_state *s;
281         struct rpc_request *deluser_req;
282         struct monitor_msg msg;
283
284         c = talloc_get_type(req->async.private_data, struct composite_context);
285         s = talloc_get_type(c->private_data, struct userdel_state);
286
287         /* receive samr_OpenUser result */
288         c->status = dcerpc_ndr_request_recv(req);
289         if (!composite_is_ok(c)) return;
290
291         c->status = s->openuser.out.result;
292         if (!NT_STATUS_IS_OK(c->status)) {
293                 composite_error(c, c->status);
294                 return;
295         }
296         
297         /* issue a monitor message */
298         if (s->monitor_fn) {
299                 struct msg_rpc_open_user msg_open;
300
301                 msg_open.rid         = s->openuser.in.rid;
302                 msg_open.access_mask = s->openuser.in.access_mask;
303
304                 msg.type      = mon_SamrOpenUser;
305                 msg.data      = (void*)&msg_open;
306                 msg.data_size = sizeof(msg_open);
307                 s->monitor_fn(&msg);
308         }
309
310         /* prepare the final rpc call arguments */
311         s->deleteuser.in.user_handle   = &s->user_handle;
312         s->deleteuser.out.user_handle  = &s->user_handle;
313         
314         /* send rpc request */
315         deluser_req = dcerpc_samr_DeleteUser_send(s->pipe, c, &s->deleteuser);
316         if (composite_nomem(deluser_req, c)) return;
317
318         /* callback handler setup */
319         composite_continue_rpc(c, deluser_req, continue_userdel_deleted, c);
320 }
321
322
323 /**
324  * Stage 3: Delete user account
325  */
326 static void continue_userdel_deleted(struct rpc_request *req)
327 {
328         struct composite_context *c;
329         struct userdel_state *s;
330         struct monitor_msg msg;
331
332         c = talloc_get_type(req->async.private_data, struct composite_context);
333         s = talloc_get_type(c->private_data, struct userdel_state);
334
335         /* receive samr_DeleteUser result */
336         c->status = dcerpc_ndr_request_recv(req);
337         if (!composite_is_ok(c)) return;
338
339         /* return the actual function call status */
340         c->status = s->deleteuser.out.result;
341         if (!NT_STATUS_IS_OK(c->status)) {
342                 composite_error(c, c->status);
343                 return;
344         }
345         
346         /* issue a monitor message */
347         if (s->monitor_fn) {
348                 msg.type      = mon_SamrDeleteUser;
349                 msg.data      = NULL;
350                 msg.data_size = 0;
351                 s->monitor_fn(&msg);
352         }
353
354         composite_done(c);
355 }
356
357
358 /**
359  * Sends asynchronous userdel request
360  *
361  * @param p dce/rpc call pipe
362  * @param io arguments and results of the call
363  * @param monitor monitor function for providing information about the progress
364  */
365
366 struct composite_context *libnet_rpc_userdel_send(struct dcerpc_pipe *p,
367                                                   struct libnet_rpc_userdel *io,
368                                                   void (*monitor)(struct monitor_msg*))
369 {
370         struct composite_context *c;
371         struct userdel_state *s;
372         struct rpc_request *lookup_req;
373
374         /* composite context allocation and setup */
375         c = composite_create(p, dcerpc_event_context(p));
376         if (c == NULL) return NULL;
377
378         s = talloc_zero(c, struct userdel_state);
379         if (composite_nomem(s, c)) return c;
380
381         c->private_data  = s;
382
383         /* store function parameters in the state structure */
384         s->pipe          = p;
385         s->domain_handle = io->in.domain_handle;
386         s->monitor_fn    = monitor;
387         
388         /* preparing parameters to send rpc request */
389         s->lookupname.in.domain_handle = &io->in.domain_handle;
390         s->lookupname.in.num_names     = 1;
391         s->lookupname.in.names         = talloc_zero(s, struct lsa_String);
392         s->lookupname.in.names->string = io->in.username;
393         s->lookupname.out.rids         = talloc_zero(s, struct samr_Ids);
394         s->lookupname.out.types        = talloc_zero(s, struct samr_Ids);
395         if (composite_nomem(s->lookupname.out.rids, c)) return c;
396         if (composite_nomem(s->lookupname.out.types, c)) return c;
397
398         /* send the request */
399         lookup_req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
400         if (composite_nomem(lookup_req, c)) return c;
401
402         /* set the next stage */
403         composite_continue_rpc(c, lookup_req, continue_userdel_name_found, c);
404         return c;
405 }
406
407
408 /**
409  * Waits for and receives results of asynchronous userdel call
410  *
411  * @param c composite context returned by asynchronous userdel call
412  * @param mem_ctx memory context of the call
413  * @param io pointer to results (and arguments) of the call
414  * @return nt status code of execution
415  */
416
417 NTSTATUS libnet_rpc_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
418                                  struct libnet_rpc_userdel *io)
419 {
420         NTSTATUS status;
421         struct userdel_state *s;
422         
423         status = composite_wait(c);
424
425         if (NT_STATUS_IS_OK(status) && io) {
426                 s  = talloc_get_type(c->private_data, struct userdel_state);
427                 io->out.user_handle = s->user_handle;
428         }
429
430         talloc_free(c);
431         return status;
432 }
433
434
435 /**
436  * Synchronous version of userdel call
437  *
438  * @param pipe dce/rpc call pipe
439  * @param mem_ctx memory context for the call
440  * @param io arguments and results of the call
441  * @return nt status code of execution
442  */
443
444 NTSTATUS libnet_rpc_userdel(struct dcerpc_pipe *p,
445                             TALLOC_CTX *mem_ctx,
446                             struct libnet_rpc_userdel *io)
447 {
448         struct composite_context *c = libnet_rpc_userdel_send(p, io, NULL);
449         return libnet_rpc_userdel_recv(c, mem_ctx, io);
450 }
451
452
453 /*
454  * USER MODIFY functionality
455  */
456
457 static void continue_usermod_name_found(struct rpc_request *req);
458 static void continue_usermod_user_opened(struct rpc_request *req);
459 static void continue_usermod_user_queried(struct rpc_request *req);
460 static void continue_usermod_user_changed(struct rpc_request *req);
461
462
463 struct usermod_state {
464         struct dcerpc_pipe         *pipe;
465         struct policy_handle       domain_handle;
466         struct policy_handle       user_handle;
467         struct usermod_change      change;
468         union  samr_UserInfo       info;
469         struct samr_LookupNames    lookupname;
470         struct samr_OpenUser       openuser;
471         struct samr_SetUserInfo    setuser;
472         struct samr_QueryUserInfo  queryuser;
473
474         /* information about the progress */
475         void (*monitor_fn)(struct monitor_msg *);
476 };
477
478
479 /**
480  * Step 1: Lookup user name
481  */
482 static void continue_usermod_name_found(struct rpc_request *req)
483 {
484         struct composite_context *c;
485         struct usermod_state *s;
486         struct rpc_request *openuser_req;
487         struct monitor_msg msg;
488
489         c = talloc_get_type(req->async.private_data, struct composite_context);
490         s = talloc_get_type(c->private_data, struct usermod_state);
491
492         /* receive samr_LookupNames result */
493         c->status = dcerpc_ndr_request_recv(req);
494         if (!composite_is_ok(c)) return;
495
496         c->status = s->lookupname.out.result;
497         if (!NT_STATUS_IS_OK(c->status)) {
498                 composite_error(c, c->status);
499                 return;
500         }
501
502         /* what to do when there's no user account to delete
503            and what if there's more than one rid resolved */
504         if (!s->lookupname.out.rids->count) {
505                 c->status = NT_STATUS_NO_SUCH_USER;
506                 composite_error(c, c->status);
507                 return;
508
509         } else if (!s->lookupname.out.rids->count > 1) {
510                 c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
511                 composite_error(c, c->status);
512                 return;
513         }
514
515         /* issue a monitor message */
516         if (s->monitor_fn) {
517                 struct msg_rpc_lookup_name msg_lookup;
518
519                 msg_lookup.rid   = s->lookupname.out.rids->ids;
520                 msg_lookup.count = s->lookupname.out.rids->count;
521
522                 msg.type      = mon_SamrLookupName;
523                 msg.data      = (void*)&msg_lookup;
524                 msg.data_size = sizeof(msg_lookup);
525                 s->monitor_fn(&msg);
526         }
527
528         /* prepare the next rpc call */
529         s->openuser.in.domain_handle = &s->domain_handle;
530         s->openuser.in.rid           = s->lookupname.out.rids->ids[0];
531         s->openuser.in.access_mask   = SEC_FLAG_MAXIMUM_ALLOWED;
532         s->openuser.out.user_handle  = &s->user_handle;
533
534         /* send the rpc request */
535         openuser_req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
536         if (composite_nomem(openuser_req, c)) return;
537
538         composite_continue_rpc(c, openuser_req, continue_usermod_user_opened, c);
539 }
540
541
542 /**
543  * Choose a proper level of samr_UserInfo structure depending on required
544  * change specified by means of flags field. Subsequent calls of this
545  * function are made until there's no flags set meaning that all of the
546  * changes have been made.
547  */
548 static bool usermod_setfields(struct usermod_state *s, uint16_t *level,
549                               union samr_UserInfo *i, bool queried)
550 {
551         if (s->change.fields == 0) return s->change.fields;
552
553         *level = 0;
554
555         if ((s->change.fields & USERMOD_FIELD_ACCOUNT_NAME) &&
556             (*level == 0 || *level == 7)) {
557                 *level = 7;
558                 i->info7.account_name.string = s->change.account_name;
559                 
560                 s->change.fields ^= USERMOD_FIELD_ACCOUNT_NAME;
561         }
562
563         if ((s->change.fields & USERMOD_FIELD_FULL_NAME) &&
564             (*level == 0 || *level == 8)) {
565                 *level = 8;
566                 i->info8.full_name.string = s->change.full_name;
567                 
568                 s->change.fields ^= USERMOD_FIELD_FULL_NAME;
569         }
570         
571         if ((s->change.fields & USERMOD_FIELD_DESCRIPTION) &&
572             (*level == 0 || *level == 13)) {
573                 *level = 13;
574                 i->info13.description.string = s->change.description;
575                 
576                 s->change.fields ^= USERMOD_FIELD_DESCRIPTION;          
577         }
578
579         if ((s->change.fields & USERMOD_FIELD_COMMENT) &&
580             (*level == 0 || *level == 2)) {
581                 *level = 2;
582                 
583                 if (queried) {
584                         /* the user info is obtained, so now set the required field */
585                         i->info2.comment.string = s->change.comment;
586                         s->change.fields ^= USERMOD_FIELD_COMMENT;
587                         
588                 } else {
589                         /* we need to query the user info before setting one field in it */
590                         return false;
591                 }
592         }
593
594         if ((s->change.fields & USERMOD_FIELD_LOGON_SCRIPT) &&
595             (*level == 0 || *level == 11)) {
596                 *level = 11;
597                 i->info11.logon_script.string = s->change.logon_script;
598                 
599                 s->change.fields ^= USERMOD_FIELD_LOGON_SCRIPT;
600         }
601
602         if ((s->change.fields & USERMOD_FIELD_PROFILE_PATH) &&
603             (*level == 0 || *level == 12)) {
604                 *level = 12;
605                 i->info12.profile_path.string = s->change.profile_path;
606                 
607                 s->change.fields ^= USERMOD_FIELD_PROFILE_PATH;
608         }
609
610         if ((s->change.fields & USERMOD_FIELD_HOME_DIRECTORY) &&
611             (*level == 0 || *level == 10)) {
612                 *level = 10;
613                 
614                 if (queried) {
615                         i->info10.home_directory.string = s->change.home_directory;
616                         s->change.fields ^= USERMOD_FIELD_HOME_DIRECTORY;
617                 } else {
618                         return false;
619                 }
620         }
621
622         if ((s->change.fields & USERMOD_FIELD_HOME_DRIVE) &&
623             (*level == 0 || *level == 10)) {
624                 *level = 10;
625                 
626                 if (queried) {
627                         i->info10.home_drive.string = s->change.home_drive;
628                         s->change.fields ^= USERMOD_FIELD_HOME_DRIVE;
629                 } else {
630                         return false;
631                 }
632         }
633         
634         if ((s->change.fields & USERMOD_FIELD_ACCT_EXPIRY) &&
635             (*level == 0 || *level == 17)) {
636                 *level = 17;
637                 i->info17.acct_expiry = timeval_to_nttime(s->change.acct_expiry);
638                 
639                 s->change.fields ^= USERMOD_FIELD_ACCT_EXPIRY;
640         }
641
642         if ((s->change.fields & USERMOD_FIELD_ACCT_FLAGS) &&
643             (*level == 0 || *level == 16)) {
644                 *level = 16;
645                 i->info16.acct_flags = s->change.acct_flags;
646                 
647                 s->change.fields ^= USERMOD_FIELD_ACCT_FLAGS;
648         }
649
650         /* We're going to be here back again soon unless all fields have been set */
651         return true;
652 }
653
654
655 static NTSTATUS usermod_change(struct composite_context *c,
656                                struct usermod_state *s)
657 {
658         struct rpc_request *query_req, *setuser_req;
659         bool do_set;
660         union samr_UserInfo *i = &s->info;
661
662         /* set the level to invalid value, so that unless setfields routine 
663            gives it a valid value we report the error correctly */
664         uint16_t level = 27;
665
666         /* prepare UserInfo level and data based on bitmask field */
667         do_set = usermod_setfields(s, &level, i, false);
668
669         if (level < 1 || level > 26) {
670                 /* apparently there's a field that the setfields routine
671                    does not know how to set */
672                 return NT_STATUS_INVALID_PARAMETER;
673         }
674
675         /* If some specific level is used to set user account data and the change
676            itself does not cover all fields then we need to query the user info
677            first, right before changing the data. Otherwise we could set required
678            fields and accidentally reset the others.
679         */
680         if (!do_set) {
681                 s->queryuser.in.user_handle = &s->user_handle;
682                 s->queryuser.in.level       = level;
683                 s->queryuser.out.info       = talloc(s, union samr_UserInfo *);
684                 if (composite_nomem(s->queryuser.out.info, c)) return NT_STATUS_NO_MEMORY;
685
686
687                 /* send query user info request to retrieve complete data of
688                    a particular info level */
689                 query_req = dcerpc_samr_QueryUserInfo_send(s->pipe, c, &s->queryuser);
690                 composite_continue_rpc(c, query_req, continue_usermod_user_queried, c);
691
692         } else {
693                 s->setuser.in.user_handle  = &s->user_handle;
694                 s->setuser.in.level        = level;
695                 s->setuser.in.info         = i;
696
697                 /* send set user info request after making required change */
698                 setuser_req = dcerpc_samr_SetUserInfo_send(s->pipe, c, &s->setuser);
699                 composite_continue_rpc(c, setuser_req, continue_usermod_user_changed, c);
700         }
701         
702         return NT_STATUS_OK;
703 }
704
705
706 /**
707  * Stage 2: Open user account
708  */
709 static void continue_usermod_user_opened(struct rpc_request *req)
710 {
711         struct composite_context *c;
712         struct usermod_state *s;
713
714         c = talloc_get_type(req->async.private_data, struct composite_context);
715         s = talloc_get_type(c->private_data, struct usermod_state);
716
717         c->status = dcerpc_ndr_request_recv(req);
718         if (!composite_is_ok(c)) return;
719
720         c->status = s->openuser.out.result;
721         if (!NT_STATUS_IS_OK(c->status)) {
722                 composite_error(c, c->status);
723                 return;
724         }
725
726         c->status = usermod_change(c, s);
727 }
728
729
730 /**
731  * Stage 2a (optional): Query the user information
732  */
733 static void continue_usermod_user_queried(struct rpc_request *req)
734 {
735         struct composite_context *c;
736         struct usermod_state *s;
737         union samr_UserInfo *i;
738         uint16_t level;
739         struct rpc_request *setuser_req;
740         
741         c = talloc_get_type(req->async.private_data, struct composite_context);
742         s = talloc_get_type(c->private_data, struct usermod_state);
743
744         i = &s->info;
745
746         /* receive samr_QueryUserInfo result */
747         c->status = dcerpc_ndr_request_recv(req);
748         if (!composite_is_ok(c)) return;
749
750         c->status = s->queryuser.out.result;
751         if (!NT_STATUS_IS_OK(c->status)) {
752                 composite_error(c, c->status);
753                 return;
754         }
755
756         /* get returned user data and make a change (potentially one
757            of many) */
758         s->info = *(*s->queryuser.out.info);
759
760         usermod_setfields(s, &level, i, true);
761
762         /* prepare rpc call arguments */
763         s->setuser.in.user_handle  = &s->user_handle;
764         s->setuser.in.level        = level;
765         s->setuser.in.info         = i;
766
767         /* send the rpc request */
768         setuser_req = dcerpc_samr_SetUserInfo_send(s->pipe, c, &s->setuser);
769         composite_continue_rpc(c, setuser_req, continue_usermod_user_changed, c);
770 }
771
772
773 /**
774  * Stage 3: Set new user account data
775  */
776 static void continue_usermod_user_changed(struct rpc_request *req)
777 {
778         struct composite_context *c;
779         struct usermod_state *s;
780         
781         c = talloc_get_type(req->async.private_data, struct composite_context);
782         s = talloc_get_type(c->private_data, struct usermod_state);
783
784         /* receive samr_SetUserInfo result */
785         c->status = dcerpc_ndr_request_recv(req);
786         if (!composite_is_ok(c)) return;
787
788         /* return the actual function call status */
789         c->status = s->setuser.out.result;
790         if (!NT_STATUS_IS_OK(c->status)) {
791                 composite_error(c, c->status);
792                 return;
793         }
794
795         if (s->change.fields == 0) {
796                 /* all fields have been set - we're done */
797                 composite_done(c);
798
799         } else {
800                 /* something's still not changed - repeat the procedure */
801                 c->status = usermod_change(c, s);
802         }
803 }
804
805
806 /**
807  * Sends asynchronous usermod request
808  *
809  * @param p dce/rpc call pipe
810  * @param io arguments and results of the call
811  * @param monitor monitor function for providing information about the progress
812  */
813
814 struct composite_context *libnet_rpc_usermod_send(struct dcerpc_pipe *p,
815                                                   struct libnet_rpc_usermod *io,
816                                                   void (*monitor)(struct monitor_msg*))
817 {
818         struct composite_context *c;
819         struct usermod_state *s;
820         struct rpc_request *lookup_req;
821
822         /* composite context allocation and setup */
823         c = composite_create(p, dcerpc_event_context(p));
824         if (c == NULL) return NULL;
825         s = talloc_zero(c, struct usermod_state);
826         if (composite_nomem(s, c)) return c;
827
828         c->private_data = s;
829
830         /* store parameters in the call structure */
831         s->pipe          = p;
832         s->domain_handle = io->in.domain_handle;
833         s->change        = io->in.change;
834         s->monitor_fn    = monitor;
835         
836         /* prepare rpc call arguments */
837         s->lookupname.in.domain_handle = &io->in.domain_handle;
838         s->lookupname.in.num_names     = 1;
839         s->lookupname.in.names         = talloc_zero(s, struct lsa_String);
840         s->lookupname.in.names->string = io->in.username;
841         s->lookupname.out.rids         = talloc_zero(s, struct samr_Ids);
842         s->lookupname.out.types        = talloc_zero(s, struct samr_Ids);
843         if (composite_nomem(s->lookupname.out.rids, c)) return c;
844         if (composite_nomem(s->lookupname.out.types, c)) return c;
845
846         /* send the rpc request */
847         lookup_req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
848         if (composite_nomem(lookup_req, c)) return c;
849         
850         /* callback handler setup */
851         composite_continue_rpc(c, lookup_req, continue_usermod_name_found, c);
852         return c;
853 }
854
855
856 /**
857  * Waits for and receives results of asynchronous usermod call
858  *
859  * @param c composite context returned by asynchronous usermod call
860  * @param mem_ctx memory context of the call
861  * @param io pointer to results (and arguments) of the call
862  * @return nt status code of execution
863  */
864
865 NTSTATUS libnet_rpc_usermod_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
866                                  struct libnet_rpc_usermod *io)
867 {
868         NTSTATUS status;
869         
870         status = composite_wait(c);
871
872         talloc_free(c);
873         return status;
874 }
875
876
877 /**
878  * Synchronous version of usermod call
879  *
880  * @param pipe dce/rpc call pipe
881  * @param mem_ctx memory context for the call
882  * @param io arguments and results of the call
883  * @return nt status code of execution
884  */
885
886 NTSTATUS libnet_rpc_usermod(struct dcerpc_pipe *p,
887                             TALLOC_CTX *mem_ctx,
888                             struct libnet_rpc_usermod *io)
889 {
890         struct composite_context *c = libnet_rpc_usermod_send(p, io, NULL);
891         return libnet_rpc_usermod_recv(c, mem_ctx, io);
892 }