r8759: Another couple of fields in usermod routine.
[jra/samba/.git] / source4 / libnet / userman.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Rafal Szczesniak 2005
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /*
22   a composite functions for user management operations (add/del/chg)
23 */
24
25 #include "includes.h"
26 #include "libcli/raw/libcliraw.h"
27 #include "libcli/composite/composite.h"
28 #include "libcli/composite/monitor.h"
29 #include "librpc/gen_ndr/ndr_samr.h"
30 #include "libnet/composite.h"
31
32 /*
33  * Composite user add function
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
50
51 /**
52  * Stage 1 (and the only one for now): Create user account.
53  */
54 static NTSTATUS useradd_create(struct composite_context *c,
55                                struct useradd_state *s)
56 {
57         c->status = dcerpc_ndr_request_recv(s->req);
58         NT_STATUS_NOT_OK_RETURN(c->status);
59         
60         c->state = SMBCLI_REQUEST_DONE;
61         return NT_STATUS_OK;
62 }
63
64
65 /**
66  * Event handler for asynchronous request. Handles transition through
67  * intermediate stages of the call.
68  *
69  * @param req rpc call context
70  */
71 static void useradd_handler(struct rpc_request *req)
72 {
73         struct composite_context *c = req->async.private;
74         struct useradd_state *s = talloc_get_type(c->private, struct useradd_state);
75         struct monitor_msg msg;
76         
77         switch (s->stage) {
78         case USERADD_CREATE:
79                 c->status = useradd_create(c, s);
80                 msg.type = rpc_create_user;
81                 msg.data.rpc_create_user.rid = *s->createuser.out.rid;
82                 break;
83         }
84
85         if (!NT_STATUS_IS_OK(c->status)) {
86                 c->state = SMBCLI_REQUEST_ERROR;
87         }
88
89         if (c->monitor_fn) {
90                 c->monitor_fn(&msg);
91         }
92
93         if (c->state >= SMBCLI_REQUEST_DONE &&
94             c->async.fn) {
95                 c->async.fn(c);
96         }
97 }
98
99
100 /**
101  * Sends asynchronous useradd request
102  *
103  * @param p dce/rpc call pipe 
104  * @param io arguments and results of the call
105  */
106
107 struct composite_context *libnet_rpc_useradd_send(struct dcerpc_pipe *p,
108                                                   struct libnet_rpc_useradd *io,
109                                                   void (*monitor)(struct monitor_msg*))
110 {
111         struct composite_context *c;
112         struct useradd_state *s;
113         
114         c = talloc_zero(p, struct composite_context);
115         if (c == NULL) goto failure;
116         
117         s = talloc_zero(c, struct useradd_state);
118         if (s == NULL) goto failure;
119         
120         s->domain_handle = io->in.domain_handle;
121         s->pipe          = p;
122         
123         c->state       = SMBCLI_REQUEST_SEND;
124         c->private     = s;
125         c->event_ctx   = dcerpc_event_context(p);
126         c->monitor_fn  = monitor;
127
128         /* preparing parameters to send rpc request */
129         s->createuser.in.domain_handle         = &io->in.domain_handle;
130         s->createuser.in.account_name          = talloc_zero(c, struct lsa_String);
131         s->createuser.in.account_name->string  = talloc_strdup(c, io->in.username);
132         s->createuser.out.user_handle          = &s->user_handle;
133         s->createuser.out.rid                  = &s->user_rid;
134
135         /* send request */
136         s->req = dcerpc_samr_CreateUser_send(p, c, &s->createuser);
137
138         /* callback handler */
139         s->req->async.callback = useradd_handler;
140         s->req->async.private  = c;
141         s->stage = USERADD_CREATE;
142
143         return c;
144         
145 failure:
146         talloc_free(c);
147         return NULL;
148 }
149
150
151 /**
152  * Waits for and receives result of asynchronous useradd call
153  * 
154  * @param c composite context returned by asynchronous useradd call
155  * @param mem_ctx memory context of the call
156  * @param io pointer to results (and arguments) of the call
157  * @return nt status code of execution
158  */
159
160 NTSTATUS libnet_rpc_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
161                                     struct libnet_rpc_useradd *io)
162 {
163         NTSTATUS status;
164         struct useradd_state *s;
165         
166         status = composite_wait(c);
167         
168         if (NT_STATUS_IS_OK(status) && io) {
169                 /* get and return result of the call */
170                 s = talloc_get_type(c->private, struct useradd_state);
171                 io->out.user_handle = s->user_handle;
172         }
173
174         talloc_free(c);
175         return status;
176 }
177
178
179 /**
180  * Synchronous version of useradd call
181  *
182  * @param pipe dce/rpc call pipe
183  * @param mem_ctx memory context for the call
184  * @param io arguments and results of the call
185  * @return nt status code of execution
186  */
187
188 NTSTATUS libnet_rpc_useradd(struct dcerpc_pipe *pipe,
189                                TALLOC_CTX *mem_ctx,
190                                struct libnet_rpc_useradd *io)
191 {
192         struct composite_context *c = libnet_rpc_useradd_send(pipe, io, NULL);
193         return libnet_rpc_useradd_recv(c, mem_ctx, io);
194 }
195
196
197 /*
198  * Composite user delete function
199  */
200
201 static void userdel_handler(struct rpc_request*);
202
203 enum userdel_stage { USERDEL_LOOKUP, USERDEL_OPEN, USERDEL_DELETE };
204
205 struct userdel_state {
206         enum userdel_stage        stage;
207         struct dcerpc_pipe        *pipe;
208         struct rpc_request        *req;
209         struct policy_handle      domain_handle;
210         struct policy_handle      user_handle;
211         struct samr_LookupNames   lookupname;
212         struct samr_OpenUser      openuser;
213         struct samr_DeleteUser    deleteuser;
214 };
215
216
217 /**
218  * Stage 1: Lookup the user name and resolve it to rid
219  */
220 static NTSTATUS userdel_lookup(struct composite_context *c,
221                                struct userdel_state *s)
222 {
223         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
224
225         c->status = dcerpc_ndr_request_recv(s->req);
226         NT_STATUS_NOT_OK_RETURN(c->status);
227         
228         if (!s->lookupname.out.rids.count) {
229                 /* TODO: no such user */
230                 status = NT_STATUS_NO_SUCH_USER;
231
232         } else if (!s->lookupname.out.rids.count > 1) {
233                 /* TODO: ambiguous username */
234                 status = NT_STATUS_INVALID_ACCOUNT_NAME;
235         }
236         
237         s->openuser.in.domain_handle = &s->domain_handle;
238         s->openuser.in.rid           = s->lookupname.out.rids.ids[0];
239         s->openuser.in.access_mask   = SEC_FLAG_MAXIMUM_ALLOWED;
240         s->openuser.out.user_handle  = &s->user_handle;
241
242         s->req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
243         
244         s->req->async.callback = userdel_handler;
245         s->req->async.private  = c;
246         s->stage = USERDEL_OPEN;
247         
248         return NT_STATUS_OK;
249 }
250
251
252 /**
253  * Stage 2: Open user account.
254  */
255 static NTSTATUS userdel_open(struct composite_context *c,
256                              struct userdel_state *s)
257 {
258         c->status = dcerpc_ndr_request_recv(s->req);
259         NT_STATUS_NOT_OK_RETURN(c->status);
260         
261         s->deleteuser.in.user_handle   = &s->user_handle;
262         s->deleteuser.out.user_handle  = &s->user_handle;
263         
264         s->req = dcerpc_samr_DeleteUser_send(s->pipe, c, &s->deleteuser);
265         
266         s->req->async.callback = userdel_handler;
267         s->req->async.private  = c;
268         s->stage = USERDEL_DELETE;
269         
270         return NT_STATUS_OK;
271 }
272
273
274 /**
275  * Stage 3: Delete user account
276  */
277 static NTSTATUS userdel_delete(struct composite_context *c,
278                                struct userdel_state *s)
279 {
280         c->status = dcerpc_ndr_request_recv(s->req);
281         NT_STATUS_NOT_OK_RETURN(c->status);
282         
283         c->state = SMBCLI_REQUEST_DONE;
284
285         return NT_STATUS_OK;
286 }
287
288
289 /**
290  * Event handler for asynchronous request. Handles transition through
291  * intermediate stages of the call.
292  *
293  * @param req rpc call context
294  */
295 static void userdel_handler(struct rpc_request *req)
296 {
297         struct composite_context *c = req->async.private;
298         struct userdel_state *s = talloc_get_type(c->private, struct userdel_state);
299         struct monitor_msg msg;
300         
301         switch (s->stage) {
302         case USERDEL_LOOKUP:
303                 c->status = userdel_lookup(c, s);
304                 break;
305         case USERDEL_OPEN:
306                 c->status = userdel_open(c, s);
307                 break;
308         case USERDEL_DELETE:
309                 c->status = userdel_delete(c, s);
310                 break;
311         }
312
313         if (!NT_STATUS_IS_OK(c->status)) {
314                 c->state = SMBCLI_REQUEST_ERROR;
315         }
316
317         if (c->monitor_fn) {
318                 c->monitor_fn(&msg);
319         }
320
321         if (c->state >= SMBCLI_REQUEST_DONE &&
322             c->async.fn) {
323                 c->async.fn(c);
324         }
325 }
326
327
328 /**
329  * Sends asynchronous userdel request
330  *
331  * @param p dce/rpc call pipe
332  * @param io arguments and results of the call
333  */
334
335 struct composite_context *libnet_rpc_userdel_send(struct dcerpc_pipe *p,
336                                                   struct libnet_rpc_userdel *io)
337 {
338         struct composite_context *c;
339         struct userdel_state *s;
340         
341         c = talloc_zero(p, struct composite_context);
342         if (c == NULL) goto failure;
343
344         s = talloc_zero(c, struct userdel_state);
345         if (s == NULL) goto failure;
346
347         c->state      = SMBCLI_REQUEST_SEND;
348         c->private    = s;
349         c->event_ctx  = dcerpc_event_context(p);
350
351         s->pipe          = p;
352         s->domain_handle = io->in.domain_handle;
353         
354         /* preparing parameters to send rpc request */
355         s->lookupname.in.domain_handle = &io->in.domain_handle;
356         s->lookupname.in.num_names     = 1;
357         s->lookupname.in.names         = talloc_zero(s, struct lsa_String);
358         s->lookupname.in.names->string = io->in.username;
359
360         /* send the request */
361         s->req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
362
363         /* callback handler */
364         s->req->async.callback = userdel_handler;
365         s->req->async.private  = c;
366         s->stage = USERDEL_LOOKUP;
367
368         return c;
369
370 failure:
371         talloc_free(c);
372         return NULL;
373 }
374
375
376 /**
377  * Waits for and receives results of asynchronous userdel call
378  *
379  * @param c composite context returned by asynchronous userdel call
380  * @param mem_ctx memory context of the call
381  * @param io pointer to results (and arguments) of the call
382  * @return nt status code of execution
383  */
384
385 NTSTATUS libnet_rpc_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
386                                  struct libnet_rpc_userdel *io)
387 {
388         NTSTATUS status;
389         struct userdel_state *s;
390         
391         status = composite_wait(c);
392
393         if (NT_STATUS_IS_OK(status) && io) {
394                 s  = talloc_get_type(c->private, struct userdel_state);
395                 io->out.user_handle = s->user_handle;
396         }
397
398         talloc_free(c);
399         return status;
400 }
401
402
403 /**
404  * Synchronous version of userdel call
405  *
406  * @param pipe dce/rpc call pipe
407  * @param mem_ctx memory context for the call
408  * @param io arguments and results of the call
409  * @return nt status code of execution
410  */
411
412 NTSTATUS libnet_rpc_userdel(struct dcerpc_pipe *pipe,
413                             TALLOC_CTX *mem_ctx,
414                             struct libnet_rpc_userdel *io)
415 {
416         struct composite_context *c = libnet_rpc_userdel_send(pipe, io);
417         return libnet_rpc_userdel_recv(c, mem_ctx, io);
418 }
419
420
421 static void usermod_handler(struct rpc_request*);
422
423 enum usermod_stage { USERMOD_LOOKUP, USERMOD_OPEN, USERMOD_MODIFY };
424
425 struct usermod_state {
426         enum usermod_stage        stage;
427         struct dcerpc_pipe        *pipe;
428         struct rpc_request        *req;
429         struct policy_handle      domain_handle;
430         struct policy_handle      user_handle;
431         struct usermod_change     change;
432         union  samr_UserInfo      info;
433         struct samr_LookupNames   lookupname;
434         struct samr_OpenUser      openuser;
435         struct samr_SetUserInfo   setuser;
436 };
437
438
439 static NTSTATUS usermod_lookup(struct composite_context *c,
440                                struct usermod_state *s)
441 {
442         NTSTATUS status;
443
444         c->status = dcerpc_ndr_request_recv(s->req);
445         NT_STATUS_NOT_OK_RETURN(c->status);
446
447         if (!s->lookupname.out.rids.count) {
448                 /* TODO: no such user */
449                 status = NT_STATUS_NO_SUCH_USER;
450
451         } else if (!s->lookupname.out.rids.count > 1) {
452                 /* TODO: ambiguous username */
453                 status = NT_STATUS_INVALID_ACCOUNT_NAME;
454         }
455
456         s->openuser.in.domain_handle = &s->domain_handle;
457         s->openuser.in.rid           = s->lookupname.out.rids.ids[0];
458         s->openuser.in.access_mask   = SEC_FLAG_MAXIMUM_ALLOWED;
459         s->openuser.out.user_handle  = &s->user_handle;
460
461         s->req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
462
463         s->req->async.callback = usermod_handler;
464         s->req->async.private  = c;
465         s->stage = USERMOD_OPEN;
466         
467         return NT_STATUS_OK;
468 }
469
470
471 static NTSTATUS usermod_open(struct composite_context *c,
472                              struct usermod_state *s)
473 {
474         union samr_UserInfo *i = &s->info;
475         uint16_t level;
476
477         c->status = dcerpc_ndr_request_recv(s->req);
478         NT_STATUS_NOT_OK_RETURN(c->status);
479
480         s->setuser.in.user_handle  = &s->user_handle;
481
482         /* Prepare UserInfo level and data based on bitmask field */
483         if (s->change.fields) {
484                 if (s->change.fields & USERMOD_FIELD_ACCOUNT_NAME) {
485                         level = 7;
486                         i->info7.account_name.length = 2*strlen_m(s->change.account_name);
487                         i->info7.account_name.size   = 2*strlen_m(s->change.account_name);
488                         i->info7.account_name.string = s->change.account_name;
489
490                         s->change.fields ^= USERMOD_FIELD_ACCOUNT_NAME;
491
492                 } else if (s->change.fields & USERMOD_FIELD_FULL_NAME) {
493                         level = 8;
494                         i->info8.full_name.length = 2*strlen_m(s->change.full_name);
495                         i->info8.full_name.size   = 2*strlen_m(s->change.full_name);
496                         i->info8.full_name.string = s->change.full_name;
497                         
498                         s->change.fields ^= USERMOD_FIELD_FULL_NAME;
499
500                 } else if (s->change.fields & USERMOD_FIELD_DESCRIPTION) {
501                         level = 13;
502                         i->info13.description.length = 2*strlen_m(s->change.description);
503                         i->info13.description.size   = 2*strlen_m(s->change.description);
504                         i->info13.description.string = s->change.description;
505                         
506                         s->change.fields ^= USERMOD_FIELD_DESCRIPTION;
507
508                 } else if (s->change.fields & USERMOD_FIELD_LOGON_SCRIPT) {
509                         level = 11;
510                         i->info11.logon_script.length = 2*strlen_m(s->change.logon_script);
511                         i->info11.logon_script.size   = 2*strlen_m(s->change.logon_script);
512                         i->info11.logon_script.string = s->change.logon_script;
513                         
514                         s->change.fields ^= USERMOD_FIELD_LOGON_SCRIPT;
515
516                 } else if (s->change.fields & USERMOD_FIELD_PROFILE_PATH) {
517                         level = 12;
518                         i->info12.profile_path.length = 2*strlen_m(s->change.profile_path);
519                         i->info12.profile_path.size   = 2*strlen_m(s->change.profile_path);
520                         i->info12.profile_path.string = s->change.profile_path;
521
522                         s->change.fields ^= USERMOD_FIELD_PROFILE_PATH;
523                 }
524         }
525
526         s->setuser.in.level        = level;
527         s->setuser.in.info         = i;
528
529         s->req = dcerpc_samr_SetUserInfo_send(s->pipe, c, &s->setuser);
530
531         s->req->async.callback = usermod_handler;
532         s->req->async.private  = c;
533
534         /* Get back here again unless all fields have been set */
535         if (s->change.fields) {
536                 s->stage = USERMOD_OPEN;
537         } else {
538                 s->stage = USERMOD_MODIFY;
539         }
540
541         return NT_STATUS_OK;
542 }
543
544
545 static NTSTATUS usermod_modify(struct composite_context *c,
546                                struct usermod_state *s)
547 {
548         c->status = dcerpc_ndr_request_recv(s->req);
549         NT_STATUS_NOT_OK_RETURN(c->status);
550
551         c->state = SMBCLI_REQUEST_DONE;
552
553         return NT_STATUS_OK;
554 }
555
556
557 static void usermod_handler(struct rpc_request *req)
558 {
559         struct composite_context *c = req->async.private;
560         struct usermod_state *s = talloc_get_type(c->private, struct usermod_state);
561         struct monitor_msg msg;
562
563         switch (s->stage) {
564         case USERMOD_LOOKUP:
565                 c->status = usermod_lookup(c, s);
566                 break;
567         case USERMOD_OPEN:
568                 c->status = usermod_open(c, s);
569                 break;
570         case USERMOD_MODIFY:
571                 c->status = usermod_modify(c, s);
572                 break;
573         }
574
575         if (!NT_STATUS_IS_OK(c->status)) {
576                 c->state = SMBCLI_REQUEST_ERROR;
577         }
578
579         if (c->monitor_fn) {
580                 c->monitor_fn(&msg);
581         }
582
583         if (c->state >= SMBCLI_REQUEST_DONE &&
584             c->async.fn) {
585                 c->async.fn(c);
586         }
587 }
588
589
590 struct composite_context *libnet_rpc_usermod_send(struct dcerpc_pipe *p,
591                                                   struct libnet_rpc_usermod *io)
592 {
593         struct composite_context *c;
594         struct usermod_state *s;
595         
596         c = talloc_zero(p, struct composite_context);
597         if (c == NULL) goto failure;
598
599         s = talloc_zero(c, struct usermod_state);
600         if (s == NULL) goto failure;
601
602         c->state      = SMBCLI_REQUEST_SEND;
603         c->private    = s;
604         c->event_ctx  = dcerpc_event_context(p);
605
606         s->pipe          = p;
607         s->domain_handle = io->in.domain_handle;
608         s->change        = io->in.change;
609         
610         s->lookupname.in.domain_handle = &io->in.domain_handle;
611         s->lookupname.in.num_names     = 1;
612         s->lookupname.in.names         = talloc_zero(s, struct lsa_String);
613         s->lookupname.in.names->string = io->in.username;
614         
615         s->req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
616         
617         s->req->async.callback = usermod_handler;
618         s->req->async.private  = c;
619         s->stage = USERMOD_LOOKUP;
620
621         return c;
622
623 failure:
624         talloc_free(c);
625         return NULL;
626 }
627
628
629 NTSTATUS libnet_rpc_usermod_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
630                                  struct libnet_rpc_usermod *io)
631 {
632         NTSTATUS status;
633         struct usermod_state *s;
634         
635         status = composite_wait(c);
636
637         talloc_free(c);
638         return status;
639 }
640
641
642 NTSTATUS libnet_rpc_usermod(struct dcerpc_pipe *pipe,
643                             TALLOC_CTX *mem_ctx,
644                             struct libnet_rpc_usermod *io)
645 {
646         struct composite_context *c = libnet_rpc_usermod_send(pipe, io);
647         return libnet_rpc_usermod_recv(c, mem_ctx, io);
648 }