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