r16692: More comments and further code in set_user_changes routine.
[bbaumbach/samba-autobuild/.git] / source4 / libnet / libnet_user.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    Copyright (C) Rafal Szczesniak <mimir@samba.org> 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 #include "includes.h"
23 #include "libnet/libnet.h"
24 #include "libcli/composite/composite.h"
25 #include "auth/credentials/credentials.h"
26 #include "librpc/ndr/libndr.h"
27 #include "librpc/gen_ndr/samr.h"
28 #include "librpc/gen_ndr/ndr_samr.h"
29
30
31 /**
32  * Verify, before actually doing anything with user accounts, whether
33  * required domain is already opened and thus ready for operation.
34  * If it is not, or if the opened domain is not the one requested, open
35  * the requested domain.
36  */
37 static struct composite_context* domain_opened(struct libnet_context *ctx,
38                                                const char *domain_name,
39                                                struct composite_context *parent_ctx,
40                                                struct libnet_DomainOpen *domain_open,
41                                                void (*continue_fn)(struct composite_context*),
42                                                void (*monitor)(struct monitor_msg*))
43 {
44         struct composite_context *domopen_req;
45
46         if (domain_name == NULL) {
47                 /*
48                  * Try to guess the domain name from credentials,
49                  * if it's not been explicitly specified.
50                  */
51
52                 if (policy_handle_empty(&ctx->domain.handle)) {
53                         domain_open->in.domain_name = cli_credentials_get_domain(ctx->cred);
54                         domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
55
56                 } else {
57                         composite_error(parent_ctx, NT_STATUS_INVALID_PARAMETER);
58                         return parent_ctx;
59                 }
60
61         } else {
62                 /*
63                  * The domain name has been specified, so check whether the same
64                  * domain is already opened. If it is - just return NULL. Start
65                  * opening a new domain otherwise.
66                  */
67
68                 if (policy_handle_empty(&ctx->domain.handle) ||
69                     !strequal(domain_name, ctx->domain.name)) {
70                         domain_open->in.domain_name = domain_name;
71                         domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;                 
72
73                 } else {
74                         /* domain has already been opened and it's the same domain
75                            as requested */
76                         return NULL;
77                 }
78         }
79
80         /* send request to open the domain */
81         domopen_req = libnet_DomainOpen_send(ctx, domain_open, monitor);
82         if (composite_nomem(domopen_req, parent_ctx)) return parent_ctx;
83         
84         composite_continue(parent_ctx, domopen_req, continue_fn, parent_ctx);
85         return parent_ctx;
86 }
87
88
89 struct create_user_state {
90         struct libnet_CreateUser r;
91         struct libnet_DomainOpen domain_open;
92         struct libnet_rpc_useradd user_add;
93         struct libnet_context *ctx;
94
95         /* information about the progress */
96         void (*monitor_fn)(struct monitor_msg *);
97 };
98
99
100 static void continue_rpc_useradd(struct composite_context *ctx);
101 static void continue_domain_open_create(struct composite_context *ctx);
102
103
104 /**
105  * Sends request to create user account
106  *
107  * @param ctx initialised libnet context
108  * @param mem_ctx memory context of this call
109  * @param r pointer to a structure containing arguments and results of this call
110  * @param monitor function pointer for receiving monitor messages
111  * @return compostite context of this request
112  */
113 struct composite_context* libnet_CreateUser_send(struct libnet_context *ctx,
114                                                  TALLOC_CTX *mem_ctx,
115                                                  struct libnet_CreateUser *r,
116                                                  void (*monitor)(struct monitor_msg*))
117 {
118         struct composite_context *c;
119         struct create_user_state *s;
120         struct composite_context *create_req;
121         struct composite_context *prereq_ctx;
122
123         /* composite context allocation and setup */
124         c = talloc_zero(mem_ctx, struct composite_context);
125         if (c == NULL) return NULL;
126
127         s = talloc_zero(c, struct create_user_state);
128         if (composite_nomem(s, c)) return c;
129
130         c->state = COMPOSITE_STATE_IN_PROGRESS;
131         c->private_data = s;
132         c->event_ctx = ctx->event_ctx;
133
134         /* store arguments in the state structure */
135         s->ctx = ctx;
136         s->r   = *r;
137         ZERO_STRUCT(s->r.out);
138
139         /* prerequisite: make sure the domain is opened */
140         prereq_ctx = domain_opened(ctx, s->r.in.domain_name, c, &s->domain_open,
141                                    continue_domain_open_create, monitor);
142         if (prereq_ctx) return prereq_ctx;
143
144         /* prepare arguments for useradd call */
145         s->user_add.in.username       = r->in.user_name;
146         s->user_add.in.domain_handle  = ctx->domain.handle;
147
148         /* send the request */
149         create_req = libnet_rpc_useradd_send(ctx->samr_pipe, &s->user_add, monitor);
150         if (composite_nomem(create_req, c)) return c;
151
152         /* set the next stage */
153         composite_continue(c, create_req, continue_rpc_useradd, c);
154         return c;
155 }
156
157
158 /*
159  * Stage 0.5 (optional): receive result of domain open request
160  * and send useradd request
161  */
162 static void continue_domain_open_create(struct composite_context *ctx)
163 {
164         struct composite_context *c;
165         struct create_user_state *s;
166         struct composite_context *create_req;
167         struct monitor_msg msg;
168
169         c = talloc_get_type(ctx->async.private_data, struct composite_context);
170         s = talloc_get_type(c->private_data, struct create_user_state);
171
172         /* receive result of DomainOpen call */
173         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
174         if (!composite_is_ok(c)) return;
175
176         /* send monitor message */
177         if (s->monitor_fn) s->monitor_fn(&msg);
178         
179         /* prepare arguments for useradd call */
180         s->user_add.in.username       = s->r.in.user_name;
181         s->user_add.in.domain_handle  = s->ctx->domain.handle;
182
183         /* send the request */
184         create_req = libnet_rpc_useradd_send(s->ctx->samr_pipe, &s->user_add, s->monitor_fn);
185         if (composite_nomem(create_req, c)) return;
186
187         /* set the next stage */
188         composite_continue(c, create_req, continue_rpc_useradd, c);
189 }
190
191
192 /*
193  * Stage 1: receive result of useradd call
194  */
195 static void continue_rpc_useradd(struct composite_context *ctx)
196 {
197         struct composite_context *c;
198         struct create_user_state *s;
199         struct monitor_msg msg;
200
201         c = talloc_get_type(ctx->async.private_data, struct composite_context);
202         s = talloc_get_type(c->private_data, struct create_user_state);
203         
204         /* receive result of the call */
205         c->status = libnet_rpc_useradd_recv(ctx, c, &s->user_add);
206         if (!composite_is_ok(c)) return;
207
208         /* send monitor message */
209         if (s->monitor_fn) s->monitor_fn(&msg);
210
211         /* we're done */
212         composite_done(c);
213 }
214
215
216 /**
217  * Receive result of CreateUser call
218  *
219  * @param c composite context returned by send request routine
220  * @param mem_ctx memory context of this call
221  * @param r pointer to a structure containing arguments and result of this call
222  * @return nt status
223  */
224 NTSTATUS libnet_CreateUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
225                                 struct libnet_CreateUser *r)
226 {
227         NTSTATUS status;
228         struct create_user_state *s;
229
230         r->out.error_string = NULL;
231
232         /* wait for result of async request and check status code */
233         status = composite_wait(c);
234         if (!NT_STATUS_IS_OK(status)) {
235                 s = talloc_get_type(c->private_data, struct create_user_state);
236                 r->out.error_string = talloc_strdup(mem_ctx, nt_errstr(status));
237         }
238
239         return status;
240 }
241
242
243 /**
244  * Synchronous version of CreateUser call
245  *
246  * @param ctx initialised libnet context
247  * @param mem_ctx memory context of this call
248  * @param r pointer to a structure containing arguments and result of this call
249  * @return nt status
250  */
251 NTSTATUS libnet_CreateUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
252                            struct libnet_CreateUser *r)
253 {
254         struct composite_context *c;
255
256         c = libnet_CreateUser_send(ctx, mem_ctx, r, NULL);
257         return libnet_CreateUser_recv(c, mem_ctx, r);
258 }
259
260
261 struct delete_user_state {
262         struct libnet_DeleteUser r;
263         struct libnet_context *ctx;
264         struct libnet_DomainOpen domain_open;
265         struct libnet_rpc_userdel user_del;
266
267         /* information about the progress */
268         void (*monitor_fn)(struct monitor_msg *);
269 };
270
271
272 static void continue_rpc_userdel(struct composite_context *ctx);
273 static void continue_domain_open_delete(struct composite_context *ctx);
274
275
276 /**
277  * Sends request to delete user account
278  *
279  * @param ctx initialised libnet context
280  * @param mem_ctx memory context of this call
281  * @param r pointer to structure containing arguments and result of this call
282  * @param monitor function pointer for receiving monitor messages
283  */
284 struct composite_context *libnet_DeleteUser_send(struct libnet_context *ctx,
285                                                  TALLOC_CTX *mem_ctx,
286                                                  struct libnet_DeleteUser *r,
287                                                  void (*monitor)(struct monitor_msg*))
288 {
289         struct composite_context *c;
290         struct delete_user_state *s;
291         struct composite_context *delete_req;
292         struct composite_context *prereq_ctx;
293
294         /* composite context allocation and setup */
295         c = talloc_zero(mem_ctx, struct composite_context);
296         if (c == NULL) return NULL;
297
298         s = talloc_zero(c, struct delete_user_state);
299         if (composite_nomem(s, c)) return c;
300
301         c->private_data = s;
302         c->state = COMPOSITE_STATE_IN_PROGRESS;
303         c->event_ctx = ctx->event_ctx;
304
305         /* store arguments in state structure */
306         s->ctx = ctx;
307         s->r   = *r;
308         ZERO_STRUCT(s->r.out);
309         
310         /* prerequisite: make sure the domain is opened before proceeding */
311         prereq_ctx = domain_opened(ctx, s->r.in.domain_name, c, &s->domain_open,
312                                    continue_domain_open_delete, monitor);
313         if (prereq_ctx) return prereq_ctx;
314
315         /* prepare arguments for userdel call */
316         s->user_del.in.username       = r->in.user_name;
317         s->user_del.in.domain_handle  = ctx->domain.handle;
318
319         /* send request */
320         delete_req = libnet_rpc_userdel_send(ctx->samr_pipe, &s->user_del, monitor);
321         if (composite_nomem(delete_req, c)) return c;
322         
323         /* set the next stage */
324         composite_continue(c, delete_req, continue_rpc_userdel, c);
325         return c;
326 }
327
328
329 /*
330  * Stage 0.5 (optional): receive result of domain open request
331  * and send useradd request
332  */
333 static void continue_domain_open_delete(struct composite_context *ctx)
334 {
335         struct composite_context *c;
336         struct delete_user_state *s;
337         struct composite_context *delete_req;
338         struct monitor_msg msg;
339
340         c = talloc_get_type(ctx->async.private_data, struct composite_context);
341         s = talloc_get_type(c->private_data, struct delete_user_state);
342
343         /* receive result of DomainOpen call */
344         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
345         if (!composite_is_ok(c)) return;
346         
347         /* send monitor message */
348         if (s->monitor_fn) s->monitor_fn(&msg);
349
350         /* prepare arguments for userdel call */
351         s->user_del.in.username       = s->r.in.user_name;
352         s->user_del.in.domain_handle  = s->ctx->domain.handle;
353
354         /* send request */
355         delete_req = libnet_rpc_userdel_send(s->ctx->samr_pipe, &s->user_del, s->monitor_fn);
356         if (composite_nomem(delete_req, c)) return;
357
358         /* set the next stage */
359         composite_continue(c, delete_req, continue_rpc_userdel, c);
360 }
361
362
363 static void continue_rpc_userdel(struct composite_context *ctx)
364 {
365         struct composite_context *c;
366         struct delete_user_state *s;
367         struct monitor_msg msg;
368
369         c = talloc_get_type(ctx->async.private_data, struct composite_context);
370         s = talloc_get_type(c->private_data, struct delete_user_state);
371
372         /* receive result of userdel call */
373         c->status = libnet_rpc_userdel_recv(ctx, c, &s->user_del);
374         if (!composite_is_ok(c)) return;
375
376         /* send monitor message */
377         if (s->monitor_fn) s->monitor_fn(&msg);
378
379         /* we're done */
380         composite_done(c);
381 }
382
383
384 /**
385  * Receives result of asynchronous DeleteUser call
386  *
387  * @param c composite context returned by async DeleteUser call
388  * @param mem_ctx memory context of this call
389  * @param r pointer to structure containing arguments and result
390  */
391 NTSTATUS libnet_DeleteUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
392                                 struct libnet_DeleteUser *r)
393 {
394         NTSTATUS status;
395         struct delete_user_state *s;
396
397         r->out.error_string = NULL;
398
399         /* wait for result of async request and check status code */
400         status = composite_wait(c);
401         if (!NT_STATUS_IS_OK(status)) {
402                 s = talloc_get_type(c->private_data, struct delete_user_state);
403                 r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
404         }
405         
406         return status;
407 }
408
409
410 /**
411  * Synchronous version of DeleteUser call
412  *
413  * @param ctx initialised libnet context
414  * @param mem_ctx memory context of this call
415  * @param r pointer to structure containing arguments and result
416  */
417 NTSTATUS libnet_DeleteUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
418                            struct libnet_DeleteUser *r)
419 {
420         struct composite_context *c;
421         
422         c = libnet_DeleteUser_send(ctx, mem_ctx, r, NULL);
423         return libnet_DeleteUser_recv(c, mem_ctx, r);
424 }
425
426
427 struct modify_user_state {
428         struct libnet_ModifyUser r;
429         struct libnet_context *ctx;
430         struct libnet_DomainOpen domain_open;
431         struct libnet_rpc_userinfo user_info;
432         struct libnet_rpc_usermod user_mod;
433
434         void (*monitor_fn)(struct monitor_msg *);
435 };
436
437
438 static void continue_rpc_usermod(struct composite_context *ctx);
439 static void continue_domain_open_modify(struct composite_context *ctx);
440 static NTSTATUS set_user_changes(TALLOC_CTX *mem_ctx, struct usermod_change *mod,
441                                  struct libnet_rpc_userinfo *info, struct libnet_ModifyUser *r);
442 static void continue_rpc_userinfo(struct composite_context *ctx);
443
444
445 struct composite_context *libnet_ModifyUser_send(struct libnet_context *ctx,
446                                                  TALLOC_CTX *mem_ctx,
447                                                  struct libnet_ModifyUser *r,
448                                                  void (*monitor)(struct monitor_msg*))
449 {
450         struct composite_context *c;
451         struct modify_user_state *s;
452         struct composite_context *prereq_ctx;
453         struct composite_context *userinfo_req;
454
455         c = talloc_zero(mem_ctx, struct composite_context);
456         if (c == NULL) return NULL;
457
458         s = talloc_zero(c, struct modify_user_state);
459         if (composite_nomem(s, c)) return c;
460
461         c->state = COMPOSITE_STATE_IN_PROGRESS;
462         c->private_data = s;
463         c->event_ctx = ctx->event_ctx;
464
465         s->ctx = ctx;
466         s->r = *r;
467
468         prereq_ctx = domain_opened(ctx, s->r.in.domain_name, c, &s->domain_open,
469                                    continue_domain_open_modify, monitor);
470         if (prereq_ctx) return prereq_ctx;
471
472         s->user_mod.in.username      = r->in.user_name;
473         s->user_mod.in.domain_handle = ctx->domain.handle;
474
475         userinfo_req = libnet_rpc_userinfo_send(ctx->samr_pipe, &s->user_info, monitor);
476         if (composite_nomem(userinfo_req, c)) return c;
477
478         composite_continue(c, userinfo_req, continue_rpc_userinfo, c);
479         return c;
480 }
481
482
483 static void continue_domain_open_modify(struct composite_context *ctx)
484 {
485         const uint16_t level = 21;
486         struct composite_context *c;
487         struct modify_user_state *s;
488         struct composite_context *userinfo_req;
489         struct monitor_msg msg;
490
491         c = talloc_get_type(ctx->async.private_data, struct composite_context);
492         s = talloc_get_type(c->private_data, struct modify_user_state);
493
494         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
495         if (!composite_is_ok(c)) return;
496
497         if (s->monitor_fn) s->monitor_fn(&msg);
498         
499         s->user_info.in.domain_handle  = s->ctx->domain.handle;
500         s->user_info.in.username       = s->r.in.user_name;
501         s->user_info.in.level          = level;
502
503         userinfo_req = libnet_rpc_userinfo_send(s->ctx->samr_pipe, &s->user_info, s->monitor_fn);
504         if (composite_nomem(userinfo_req, c)) return;
505         
506         composite_continue(c, userinfo_req, continue_rpc_userinfo, c);
507 }
508
509
510 static void continue_rpc_userinfo(struct composite_context *ctx)
511 {
512         struct composite_context *c;
513         struct modify_user_state *s;
514         struct composite_context *usermod_req;
515
516         c = talloc_get_type(ctx->async.private_data, struct composite_context);
517         s = talloc_get_type(c->private_data, struct modify_user_state);
518
519         c->status = libnet_rpc_userinfo_recv(ctx, c, &s->user_info);
520         if (!composite_is_ok(c)) return;
521
522         s->user_mod.in.domain_handle = s->ctx->domain.handle;
523         s->user_mod.in.username      = s->r.in.user_name;
524
525         c->status = set_user_changes(c, &s->user_mod.in.change, &s->user_info, &s->r);
526
527         usermod_req = libnet_rpc_usermod_send(s->ctx->samr_pipe, &s->user_mod, s->monitor_fn);
528         if (composite_nomem(usermod_req, c)) return;
529
530         composite_continue(c, usermod_req, continue_rpc_usermod, c);
531 }
532
533
534 static NTSTATUS set_user_changes(TALLOC_CTX *mem_ctx, struct usermod_change *mod,
535                                  struct libnet_rpc_userinfo *info, struct libnet_ModifyUser *r)
536 {
537         struct samr_UserInfo21 *user;
538
539         if (mod == NULL || info == NULL || r == NULL || info->in.level != 21) {
540                 return NT_STATUS_INVALID_PARAMETER;
541         }
542
543         user = &info->out.info.info21;
544         mod->fields = 0;        /* reset flag field before setting individual flags */
545
546         /*
547          * account name change
548          */
549         if (r->in.account_name != NULL &&
550             !strequal_w(user->account_name.string, r->in.account_name)) {
551
552                 mod->account_name = talloc_strdup(mem_ctx, r->in.account_name);
553                 if (mod->account_name == NULL) return NT_STATUS_NO_MEMORY;
554
555                 mod->fields |= USERMOD_FIELD_ACCOUNT_NAME;
556         }
557
558         /*
559          * full name change
560          */
561         if (r->in.full_name != NULL &&
562             !strequal_w(user->full_name.string, r->in.full_name)) {
563                 
564                 mod->full_name = talloc_strdup(mem_ctx, r->in.full_name);
565                 if (mod->full_name == NULL) return NT_STATUS_NO_MEMORY;
566
567                 mod->fields |= USERMOD_FIELD_FULL_NAME;
568         }
569
570         /*
571          * description change
572          */
573         if (r->in.description != NULL &&
574             !strequal_w(user->description.string, r->in.description)) {
575
576                 mod->description = talloc_strdup(mem_ctx, r->in.description);
577                 if (mod->description == NULL) return NT_STATUS_NO_MEMORY;
578
579                 mod->fields |= USERMOD_FIELD_DESCRIPTION;
580         }
581
582         return NT_STATUS_OK;
583 }
584
585
586 static void continue_rpc_usermod(struct composite_context *ctx)
587 {
588         struct composite_context *c;
589         struct modify_user_state *s;
590         struct monitor_msg msg;
591
592         c = talloc_get_type(ctx->async.private_data, struct composite_context);
593         s = talloc_get_type(c->private_data, struct modify_user_state);
594         
595         c->status = libnet_rpc_usermod_recv(ctx, c, &s->user_mod);
596         if (!composite_is_ok(c)) return;
597         
598         if (s->monitor_fn) s->monitor_fn(&msg);
599         composite_done(c);
600 }
601
602
603 NTSTATUS libnet_ModifyUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
604                                 struct libnet_ModifyUser *r)
605 {
606         NTSTATUS status = composite_wait(c);
607         return status;
608 }
609
610
611 NTSTATUS libnet_ModifyUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
612                            struct libnet_ModifyUser *r)
613 {
614         struct composite_context *c;
615
616         c = libnet_ModifyUser_send(ctx, mem_ctx, r, NULL);
617         return libnet_ModifyUser_recv(c, mem_ctx, r);
618 }