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