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