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