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