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