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