8d2cc0de022730cdfd428376495c60a63dd77d5b
[jelmer/samba4-debian.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 *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 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 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         
300         switch (s->stage) {
301         case USERDEL_LOOKUP:
302                 c->status = userdel_lookup(c, s);
303                 break;
304         case USERDEL_OPEN:
305                 c->status = userdel_open(c, s);
306                 break;
307         case USERDEL_DELETE:
308                 c->status = userdel_delete(c, s);
309                 break;
310         }
311
312         if (!NT_STATUS_IS_OK(c->status)) {
313                 c->state = SMBCLI_REQUEST_ERROR;
314         }
315
316         if (c->state >= SMBCLI_REQUEST_DONE &&
317             c->async.fn) {
318                 c->async.fn(c);
319         }
320 }
321
322
323 /**
324  * Sends asynchronous userdel request
325  *
326  * @param p dce/rpc call pipe
327  * @param io arguments and results of the call
328  */
329
330 struct composite_context *libnet_rpc_userdel_send(struct dcerpc_pipe *p,
331                                                      struct libnet_rpc_userdel *io)
332 {
333         struct composite_context *c;
334         struct userdel_state *s;
335         
336         c = talloc_zero(p, struct composite_context);
337         if (c == NULL) goto failure;
338
339         s = talloc_zero(c, struct userdel_state);
340         if (s == NULL) goto failure;
341
342         c->state      = SMBCLI_REQUEST_SEND;
343         c->private    = s;
344         c->event_ctx  = dcerpc_event_context(p);
345
346         s->pipe          = p;
347         s->domain_handle = io->in.domain_handle;
348         
349         /* preparing parameters to send rpc request */
350         s->lookupname.in.domain_handle = &io->in.domain_handle;
351         s->lookupname.in.num_names     = 1;
352         s->lookupname.in.names         = talloc_zero(s, struct samr_String);
353         s->lookupname.in.names->string = io->in.username;
354
355         /* send the request */
356         s->req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
357
358         /* callback handler */
359         s->req->async.callback = userdel_handler;
360         s->req->async.private  = c;
361         s->stage = USERDEL_LOOKUP;
362
363         return c;
364
365 failure:
366         talloc_free(c);
367         return NULL;
368 }
369
370
371 /**
372  * Waits for and receives results of asynchronous userdel call
373  *
374  * @param c composite context returned by asynchronous userdel call
375  * @param mem_ctx memory context of the call
376  * @param io pointer to results (and arguments) of the call
377  * @return nt status code of execution
378  */
379
380 NTSTATUS libnet_rpc_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
381                                     struct libnet_rpc_userdel *io)
382 {
383         NTSTATUS status;
384         struct userdel_state *s;
385         
386         status = composite_wait(c);
387
388         if (NT_STATUS_IS_OK(status) && io) {
389                 s  = talloc_get_type(c->private, struct userdel_state);
390                 io->out.user_handle = s->user_handle;
391         }
392
393         talloc_free(c);
394         return status;
395 }
396
397
398 /**
399  * Synchronous version of userdel call
400  *
401  * @param pipe dce/rpc call pipe
402  * @param mem_ctx memory context for the call
403  * @param io arguments and results of the call
404  * @return nt status code of execution
405  */
406
407 NTSTATUS libnet_rpc_userdel(struct dcerpc_pipe *pipe,
408                                TALLOC_CTX *mem_ctx,
409                                struct libnet_rpc_userdel *io)
410 {
411         struct composite_context *c = libnet_rpc_userdel_send(pipe, io);
412         return libnet_rpc_userdel_recv(c, mem_ctx, io);
413 }