r6709: Add monitor messages to useradd composite useradd function.
[samba.git] / source / 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 *rpc_composite_useradd_send(struct dcerpc_pipe *p,
108                                                      struct rpc_composite_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 samr_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 rpc_composite_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
161                                     struct rpc_composite_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 rpc_composite_useradd(struct dcerpc_pipe *pipe,
189                                TALLOC_CTX *mem_ctx,
190                                struct rpc_composite_useradd *io)
191 {
192         struct composite_context *c = rpc_composite_useradd_send(pipe, io, NULL);
193         return rpc_composite_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 failure:
250         talloc_free(c);
251         return status;
252 }
253
254
255 /**
256  * Stage 2: Open user account.
257  */
258 static NTSTATUS userdel_open(struct composite_context *c,
259                              struct userdel_state *s)
260 {
261         c->status = dcerpc_ndr_request_recv(s->req);
262         NT_STATUS_NOT_OK_RETURN(c->status);
263         
264         s->deleteuser.in.user_handle   = &s->user_handle;
265         s->deleteuser.out.user_handle  = &s->user_handle;
266         
267         s->req = dcerpc_samr_DeleteUser_send(s->pipe, c, &s->deleteuser);
268         
269         s->req->async.callback = userdel_handler;
270         s->req->async.private  = c;
271         s->stage = USERDEL_DELETE;
272         
273         return NT_STATUS_OK;
274 }
275
276
277 /**
278  * Stage 3: Delete user account
279  */
280 static NTSTATUS userdel_delete(struct composite_context *c,
281                                struct userdel_state *s)
282 {
283         c->status = dcerpc_ndr_request_recv(s->req);
284         NT_STATUS_NOT_OK_RETURN(c->status);
285         
286         c->state = SMBCLI_REQUEST_DONE;
287
288         return NT_STATUS_OK;
289 }
290
291
292 /**
293  * Event handler for asynchronous request. Handles transition through
294  * intermediate stages of the call.
295  *
296  * @param req rpc call context
297  */
298 static void userdel_handler(struct rpc_request *req)
299 {
300         struct composite_context *c = req->async.private;
301         struct userdel_state *s = talloc_get_type(c->private, struct userdel_state);
302         
303         switch (s->stage) {
304         case USERDEL_LOOKUP:
305                 c->status = userdel_lookup(c, s);
306                 break;
307         case USERDEL_OPEN:
308                 c->status = userdel_open(c, s);
309                 break;
310         case USERDEL_DELETE:
311                 c->status = userdel_delete(c, s);
312                 break;
313         }
314
315         if (!NT_STATUS_IS_OK(c->status)) {
316                 c->state = SMBCLI_REQUEST_ERROR;
317         }
318
319         if (c->state >= SMBCLI_REQUEST_DONE &&
320             c->async.fn) {
321                 c->async.fn(c);
322         }
323 }
324
325
326 /**
327  * Sends asynchronous userdel request
328  *
329  * @param p dce/rpc call pipe
330  * @param io arguments and results of the call
331  */
332
333 struct composite_context *rpc_composite_userdel_send(struct dcerpc_pipe *p,
334                                                      struct rpc_composite_userdel *io)
335 {
336         struct composite_context *c;
337         struct userdel_state *s;
338         
339         c = talloc_zero(p, struct composite_context);
340         if (c == NULL) goto failure;
341
342         s = talloc_zero(c, struct userdel_state);
343         if (s == NULL) goto failure;
344
345         c->state      = SMBCLI_REQUEST_SEND;
346         c->private    = s;
347         c->event_ctx  = dcerpc_event_context(p);
348
349         s->pipe          = p;
350         s->domain_handle = io->in.domain_handle;
351         
352         /* preparing parameters to send rpc request */
353         s->lookupname.in.domain_handle = &io->in.domain_handle;
354         s->lookupname.in.num_names     = 1;
355         s->lookupname.in.names         = talloc_zero(s, struct samr_String);
356         s->lookupname.in.names->string = io->in.username;
357
358         /* send the request */
359         s->req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
360
361         /* callback handler */
362         s->req->async.callback = userdel_handler;
363         s->req->async.private  = c;
364         s->stage = USERDEL_LOOKUP;
365
366         return c;
367
368 failure:
369         talloc_free(c);
370         return NULL;
371 }
372
373
374 /**
375  * Waits for and receives results of asynchronous userdel call
376  *
377  * @param c composite context returned by asynchronous userdel call
378  * @param mem_ctx memory context of the call
379  * @param io pointer to results (and arguments) of the call
380  * @return nt status code of execution
381  */
382
383 NTSTATUS rpc_composite_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
384                                     struct rpc_composite_userdel *io)
385 {
386         NTSTATUS status;
387         struct userdel_state *s;
388         
389         status = composite_wait(c);
390
391         if (NT_STATUS_IS_OK(status) && io) {
392                 s  = talloc_get_type(c->private, struct userdel_state);
393                 io->out.user_handle = s->user_handle;
394         }
395
396         talloc_free(c);
397         return status;
398 }
399
400
401 /**
402  * Synchronous version of userdel call
403  *
404  * @param pipe dce/rpc call pipe
405  * @param mem_ctx memory context for the call
406  * @param io arguments and results of the call
407  * @return nt status code of execution
408  */
409
410 NTSTATUS rpc_composite_userdel(struct dcerpc_pipe *pipe,
411                                TALLOC_CTX *mem_ctx,
412                                struct rpc_composite_userdel *io)
413 {
414         struct composite_context *c = rpc_composite_userdel_send(pipe, io);
415         return rpc_composite_userdel_recv(c, mem_ctx, io);
416 }