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