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