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