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