r15726: Comments and a couple of minor formattings in the code.
[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         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                 composite_error(c, c->status);
523
524         } else if (!s->lookupname.out.rids.count > 1) {
525                 c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
526                 composite_error(c, c->status);
527         }
528
529         /* prepare the next rpc call */
530         s->openuser.in.domain_handle = &s->domain_handle;
531         s->openuser.in.rid           = s->lookupname.out.rids.ids[0];
532         s->openuser.in.access_mask   = SEC_FLAG_MAXIMUM_ALLOWED;
533         s->openuser.out.user_handle  = &s->user_handle;
534
535         /* send the rpc request */
536         s->req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
537
538         /* callback handler setup */
539         s->req->async.callback = usermod_handler;
540         s->req->async.private  = c;
541         s->stage = USERMOD_OPEN;
542         
543         return NT_STATUS_OK;
544 }
545
546
547 /**
548  * Choose a proper level of samr_UserInfo structure depending on required
549  * change specified by means of flags field. Subsequent calls of this
550  * function are made until there's no flags set meaning that all of the
551  * changes have been made.
552  */
553 static uint32_t usermod_setfields(struct usermod_state *s, uint16_t *level,
554                                   union samr_UserInfo *i)
555 {
556         if (s->change.fields) {
557                 if (s->change.fields & USERMOD_FIELD_ACCOUNT_NAME) {
558                         *level = 7;
559                         i->info7.account_name.string = s->change.account_name;
560
561                         s->change.fields ^= USERMOD_FIELD_ACCOUNT_NAME;
562
563                 } else if (s->change.fields & USERMOD_FIELD_FULL_NAME) {
564                         *level = 8;
565                         i->info8.full_name.string = s->change.full_name;
566                         
567                         s->change.fields ^= USERMOD_FIELD_FULL_NAME;
568
569                 } else if (s->change.fields & USERMOD_FIELD_DESCRIPTION) {
570                         *level = 13;
571                         i->info13.description.string = s->change.description;
572                         
573                         s->change.fields ^= USERMOD_FIELD_DESCRIPTION;
574
575                 } else if (s->change.fields & USERMOD_FIELD_COMMENT) {
576                         *level = 2;
577
578                         if (s->stage == USERMOD_QUERY) {
579                                 /* the user info is obtained, so now set the required field */
580                                 i->info2.comment.string = s->change.comment;
581                                 s->change.fields ^= USERMOD_FIELD_COMMENT;
582
583                         } else {
584                                 /* we need to query the user info before setting one field in it */
585                                 s->stage = USERMOD_QUERY;
586                                 return s->change.fields;
587                         }
588
589                 } else if (s->change.fields & USERMOD_FIELD_ALLOW_PASS_CHG) {
590                         *level = 3;
591                         
592                         if (s->stage == USERMOD_QUERY) {
593                                 i->info3.allow_password_change = timeval_to_nttime(s->change.allow_password_change);
594                                 s->change.fields ^= USERMOD_FIELD_ALLOW_PASS_CHG;
595
596                         } else {
597                                 s->stage = USERMOD_QUERY;
598                                 return s->change.fields;
599                         }
600
601                 } else if (s->change.fields & USERMOD_FIELD_FORCE_PASS_CHG) {
602                         *level = 3;
603
604                         if (s->stage == USERMOD_QUERY) {
605                                 i->info3.force_password_change = timeval_to_nttime(s->change.force_password_change);
606                                 s->change.fields ^= USERMOD_FIELD_FORCE_PASS_CHG;
607
608                         } else {
609                                 s->stage = USERMOD_QUERY;
610                                 return s->change.fields;
611                         }
612
613                 } else if (s->change.fields & USERMOD_FIELD_LOGON_SCRIPT) {
614                         *level = 11;
615                         i->info11.logon_script.string = s->change.logon_script;
616                         
617                         s->change.fields ^= USERMOD_FIELD_LOGON_SCRIPT;
618
619                 } else if (s->change.fields & USERMOD_FIELD_PROFILE_PATH) {
620                         *level = 12;
621                         i->info12.profile_path.string = s->change.profile_path;
622
623                         s->change.fields ^= USERMOD_FIELD_PROFILE_PATH;
624
625                 } else if (s->change.fields & USERMOD_FIELD_ACCT_EXPIRY) {
626                         *level = 17;
627                         i->info17.acct_expiry = timeval_to_nttime(s->change.acct_expiry);
628
629                         s->change.fields ^= USERMOD_FIELD_ACCT_EXPIRY;
630
631                 } else if (s->change.fields & USERMOD_FIELD_ACCT_FLAGS) {
632                         *level = 16;
633                         i->info16.acct_flags = s->change.acct_flags;
634
635                         s->change.fields ^= USERMOD_FIELD_ACCT_FLAGS;
636                 }
637         }
638
639         /* We're going to be back here again soon unless all fields have been set */
640         if (s->change.fields) {
641                 s->stage = USERMOD_OPEN;
642         } else {
643                 s->stage = USERMOD_MODIFY;
644         }
645
646         return s->change.fields;
647 }
648
649
650 /**
651  * Stage 2: Open user account
652  */
653 static NTSTATUS usermod_open(struct composite_context *c,
654                              struct usermod_state *s)
655 {
656         union samr_UserInfo *i = &s->info;
657         uint16_t level;
658
659         c->status = dcerpc_ndr_request_recv(s->req);
660         NT_STATUS_NOT_OK_RETURN(c->status);
661
662         /* prepare UserInfo level and data based on bitmask field */
663         s->change.fields = usermod_setfields(s, &level, i);
664
665         /* If some specific level is used to set user account data and the change
666            itself does not cover all fields then we need to query the user info
667            first, right before changing the data. Otherwise we could set required
668            fields and accidentally reset the others.
669         */
670         if (s->stage == USERMOD_QUERY) {
671                 s->queryuser.in.user_handle = &s->user_handle;
672                 s->queryuser.in.level       = level;
673
674                 /* send query user info request to retrieve complete data of
675                    a particular info level */
676                 s->req = dcerpc_samr_QueryUserInfo_send(s->pipe, c, &s->queryuser);
677
678         } else {
679                 s->setuser.in.user_handle  = &s->user_handle;
680                 s->setuser.in.level        = level;
681                 s->setuser.in.info         = i;
682
683                 /* send set user info request after making required change */
684                 s->req = dcerpc_samr_SetUserInfo_send(s->pipe, c, &s->setuser);
685         }
686
687         /* callback handler setup */
688         s->req->async.callback = usermod_handler;
689         s->req->async.private  = c;
690
691         return NT_STATUS_OK;
692 }
693
694
695 /**
696  * Stage 2a (optional): Query the user information
697  */
698 static NTSTATUS usermod_query(struct composite_context *c,
699                               struct usermod_state *s)
700 {
701         union samr_UserInfo *i = &s->info;
702         uint16_t level;
703
704         /* receive samr_QueryUserInfo result */
705         c->status = dcerpc_ndr_request_recv(s->req);
706         NT_STATUS_NOT_OK_RETURN(c->status);
707
708         /* get returned user data and make a change (potentially one
709            of many) */
710         s->info = *s->queryuser.out.info;
711
712         s->change.fields = usermod_setfields(s, &level, i);
713
714         /* prepare rpc call arguments */
715         s->setuser.in.user_handle  = &s->user_handle;
716         s->setuser.in.level        = level;
717         s->setuser.in.info         = i;
718
719         /* send the rpc request */
720         s->req = dcerpc_samr_SetUserInfo_send(s->pipe, c, &s->setuser);
721
722         /* callback handler setup */
723         s->req->async.callback = usermod_handler;
724         s->req->async.private  = c;
725
726         return NT_STATUS_OK;
727 }
728
729
730 /**
731  * Stage 3: Set new user account data
732  */
733 static NTSTATUS usermod_modify(struct composite_context *c,
734                                struct usermod_state *s)
735 {
736         /* receive samr_SetUserInfo result */
737         c->status = dcerpc_ndr_request_recv(s->req);
738         NT_STATUS_NOT_OK_RETURN(c->status);
739
740         c->state = COMPOSITE_STATE_DONE;
741
742         return NT_STATUS_OK;
743 }
744
745
746 /**
747  * Event handler for asynchronous request. Handles transition through
748  * intermediate stages of the call.
749  *
750  * @param req rpc call context
751  */
752
753 static void usermod_handler(struct rpc_request *req)
754 {
755         struct composite_context *c;
756         struct usermod_state *s;
757         struct monitor_msg msg;
758         struct msg_rpc_lookup_name *msg_lookup;
759         struct msg_rpc_open_user *msg_open;
760
761         c = talloc_get_type(req->async.private, struct composite_context);
762         s = talloc_get_type(c->private_data, struct usermod_state);
763
764         switch (s->stage) {
765         case USERMOD_LOOKUP:
766                 c->status = usermod_lookup(c, s);
767                 
768                 /* monitor message */
769                 msg.type = rpc_lookup_name;
770                 msg_lookup = talloc(s, struct msg_rpc_lookup_name);
771
772                 msg_lookup->rid   = s->lookupname.out.rids.ids;
773                 msg_lookup->count = s->lookupname.out.rids.count;
774                 msg.data = (void*)msg_lookup;
775                 msg.data_size = sizeof(*msg_lookup);
776                 break;
777
778         case USERMOD_OPEN:
779                 c->status = usermod_open(c, s);
780
781                 /* monitor message */
782                 msg.type = rpc_open_user;
783                 msg_open = talloc(s, struct msg_rpc_open_user);
784
785                 msg_open->rid         = s->openuser.in.rid;
786                 msg_open->access_mask = s->openuser.in.rid;
787                 msg.data = (void*)msg_open;
788                 msg.data_size = sizeof(*msg_open);
789                 break;
790
791         case USERMOD_QUERY:
792                 c->status = usermod_query(c, s);
793
794                 /* monitor message */
795                 msg.type = rpc_query_user;
796                 msg.data = NULL;
797                 msg.data_size = 0;
798                 break;
799
800         case USERMOD_MODIFY:
801                 c->status = usermod_modify(c, s);
802
803                 /* monitor message */
804                 msg.type = rpc_set_user;
805                 msg.data = NULL;
806                 msg.data_size = 0;
807                 break;
808         }
809
810         /* are we ok, so far ? */
811         if (!NT_STATUS_IS_OK(c->status)) {
812                 c->state = COMPOSITE_STATE_ERROR;
813         }
814
815         /* call monitor function provided the pointer has been passed */
816         if (s->monitor_fn) {
817                 s->monitor_fn(&msg);
818         }
819
820         /* are we done yet ? */
821         if (c->state >= COMPOSITE_STATE_DONE &&
822             c->async.fn) {
823                 c->async.fn(c);
824         }
825 }
826
827
828 /**
829  * Sends asynchronous usermod request
830  *
831  * @param p dce/rpc call pipe
832  * @param io arguments and results of the call
833  * @param monitor monitor function for providing information about the progress
834  */
835
836 struct composite_context *libnet_rpc_usermod_send(struct dcerpc_pipe *p,
837                                                   struct libnet_rpc_usermod *io,
838                                                   void (*monitor)(struct monitor_msg*))
839 {
840         struct composite_context *c;
841         struct usermod_state *s;
842
843         /* composite context allocation and setup */
844         c = talloc_zero(p, struct composite_context);
845         if (c == NULL) return NULL;
846
847         s = talloc_zero(c, struct usermod_state);
848         if (composite_nomem(s, c)) return c;
849
850         c->state        = COMPOSITE_STATE_IN_PROGRESS;
851         c->private_data = s;
852         c->event_ctx    = dcerpc_event_context(p);
853
854         /* store parameters in the call structure */
855         s->pipe          = p;
856         s->domain_handle = io->in.domain_handle;
857         s->change        = io->in.change;
858         s->monitor_fn    = monitor;
859         
860         /* prepare rpc call arguments */
861         s->lookupname.in.domain_handle = &io->in.domain_handle;
862         s->lookupname.in.num_names     = 1;
863         s->lookupname.in.names         = talloc_zero(s, struct lsa_String);
864         s->lookupname.in.names->string = io->in.username;
865
866         /* send the rpc request */
867         s->req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
868         
869         /* callback handler setup */
870         s->req->async.callback = usermod_handler;
871         s->req->async.private  = c;
872         s->stage = USERMOD_LOOKUP;
873
874         return c;
875 }
876
877
878 /**
879  * Waits for and receives results of asynchronous usermod call
880  *
881  * @param c composite context returned by asynchronous usermod call
882  * @param mem_ctx memory context of the call
883  * @param io pointer to results (and arguments) of the call
884  * @return nt status code of execution
885  */
886
887 NTSTATUS libnet_rpc_usermod_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
888                                  struct libnet_rpc_usermod *io)
889 {
890         NTSTATUS status;
891         
892         status = composite_wait(c);
893
894         talloc_free(c);
895         return status;
896 }
897
898
899 /**
900  * Synchronous version of usermod call
901  *
902  * @param pipe dce/rpc call pipe
903  * @param mem_ctx memory context for the call
904  * @param io arguments and results of the call
905  * @return nt status code of execution
906  */
907
908 NTSTATUS libnet_rpc_usermod(struct dcerpc_pipe *p,
909                             TALLOC_CTX *mem_ctx,
910                             struct libnet_rpc_usermod *io)
911 {
912         struct composite_context *c = libnet_rpc_usermod_send(p, io, NULL);
913         return libnet_rpc_usermod_recv(c, mem_ctx, io);
914 }