r26693: Add (untested) libnet_rpc_groupdel function.
[ira/wip.git] / source / libnet / groupman.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Rafal Szczesniak 2007
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 3 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, see <http://www.gnu.org/licenses/>.
18 */
19
20 /*
21   a composite function for manipulating (add/edit/del) groups via samr pipe
22 */
23
24 #include "includes.h"
25 #include "libcli/composite/composite.h"
26 #include "libnet/composite.h"
27 #include "libnet/groupman.h"
28 #include "librpc/gen_ndr/ndr_samr_c.h"
29
30
31 struct groupadd_state {
32         struct dcerpc_pipe *pipe;
33         struct policy_handle domain_handle;
34         struct samr_CreateDomainGroup creategroup;
35         struct policy_handle group_handle;
36         uint32_t group_rid;
37         
38         void (*monitor_fn)(struct monitor_msg*);
39 };
40
41
42 static void continue_groupadd_created(struct rpc_request *req);
43
44
45 struct composite_context* libnet_rpc_groupadd_send(struct dcerpc_pipe *p,
46                                                    struct libnet_rpc_groupadd *io,
47                                                    void (*monitor)(struct monitor_msg*))
48 {
49         struct composite_context *c;
50         struct groupadd_state *s;
51         struct rpc_request *create_req;
52
53         if (!p || !io) return NULL;
54
55         c = composite_create(p, dcerpc_event_context(p));
56         if (c == NULL) return NULL;
57
58         s = talloc_zero(c, struct groupadd_state);
59         if (composite_nomem(s, c)) return c;
60
61         c->private_data = s;
62
63         s->domain_handle = io->in.domain_handle;
64         s->pipe          = p;
65         s->monitor_fn    = monitor;
66
67         s->creategroup.in.domain_handle  = &s->domain_handle;
68
69         s->creategroup.in.name           = talloc_zero(c, struct lsa_String);
70         if (composite_nomem(s->creategroup.in.name, c)) return c;
71
72         s->creategroup.in.name->string   = talloc_strdup(c, io->in.groupname);
73         if (composite_nomem(s->creategroup.in.name->string, c)) return c;
74         
75         s->creategroup.in.access_mask    = 0;
76         
77         s->creategroup.out.group_handle  = &s->group_handle;
78         s->creategroup.out.rid           = &s->group_rid;
79         
80         create_req = dcerpc_samr_CreateDomainGroup_send(s->pipe, c, &s->creategroup);
81         if (composite_nomem(create_req, c)) return c;
82
83         composite_continue_rpc(c, create_req, continue_groupadd_created, c);
84         return c;
85 }
86
87
88 NTSTATUS libnet_rpc_groupadd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
89                                   struct libnet_rpc_groupadd *io)
90 {
91         NTSTATUS status;
92         struct groupadd_state *s;
93         
94         status = composite_wait(c);
95         if (NT_STATUS_IS_OK(status)) {
96                 s = talloc_get_type(c, struct groupadd_state);
97         }
98
99         return status;
100 }
101
102
103 static void continue_groupadd_created(struct rpc_request *req)
104 {
105         struct composite_context *c;
106         struct groupadd_state *s;
107
108         c = talloc_get_type(req->async.private_data, struct composite_context);
109         s = talloc_get_type(c->private_data, struct groupadd_state);
110
111         c->status = dcerpc_ndr_request_recv(req);
112         if (!composite_is_ok(c)) return;
113
114         c->status = s->creategroup.out.result;
115         if (!composite_is_ok(c)) return;
116         
117         composite_done(c);
118 }
119
120
121 NTSTATUS libnet_rpc_groupadd(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
122                              struct libnet_rpc_groupadd *io)
123 {
124         struct composite_context *c;
125
126         c = libnet_rpc_groupadd_send(p, io, NULL);
127         return libnet_rpc_groupadd_recv(c, mem_ctx, io);
128 }
129
130
131 struct groupdel_state {
132         struct dcerpc_pipe             *pipe;
133         struct policy_handle           domain_handle;
134         struct policy_handle           group_handle;
135         struct samr_LookupNames        lookupname;
136         struct samr_OpenGroup          opengroup;
137         struct samr_DeleteDomainGroup  deletegroup;
138
139         /* information about the progress */
140         void (*monitor_fn)(struct monitor_msg *);
141 };
142
143
144 static void continue_groupdel_name_found(struct rpc_request *req);
145 static void continue_groupdel_group_opened(struct rpc_request *req);
146 static void continue_groupdel_deleted(struct rpc_request *req);
147
148
149 struct composite_context* libnet_rpc_groupdel_send(struct dcerpc_pipe *p,
150                                                    struct libnet_rpc_groupdel *io,
151                                                    void (*monitor)(struct monitor_msg*))
152 {
153         struct composite_context *c;
154         struct groupdel_state *s;
155         struct rpc_request *lookup_req;
156
157         /* composite context allocation and setup */
158         c = composite_create(p, dcerpc_event_context(p));
159         if (c == NULL) return NULL;
160
161         s = talloc_zero(c, struct groupdel_state);
162         if (composite_nomem(s, c)) return c;
163
164         c->private_data  = s;
165
166         /* store function parameters in the state structure */
167         s->pipe          = p;
168         s->domain_handle = io->in.domain_handle;
169         s->monitor_fn    = monitor;
170         
171         /* prepare parameters to send rpc request */
172         s->lookupname.in.domain_handle = &io->in.domain_handle;
173         s->lookupname.in.num_names     = 1;
174         s->lookupname.in.names         = talloc_zero(s, struct lsa_String);
175         s->lookupname.in.names->string = io->in.groupname;
176
177         /* send the request */
178         lookup_req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
179         if (composite_nomem(lookup_req, c)) return c;
180
181         composite_continue_rpc(c, lookup_req, continue_groupdel_name_found, c);
182         return c;
183 }
184
185
186 static void continue_groupdel_name_found(struct rpc_request *req)
187 {
188         struct composite_context *c;
189         struct groupdel_state *s;
190         struct rpc_request *opengroup_req;
191
192         c = talloc_get_type(req->async.private_data, struct composite_context);
193         s = talloc_get_type(c->private_data, struct groupdel_state);
194
195         /* receive samr_LookupNames result */
196         c->status = dcerpc_ndr_request_recv(req);
197         if (!composite_is_ok(c)) return;
198
199         c->status = s->lookupname.out.result;
200         if (!NT_STATUS_IS_OK(c->status)) {
201                 composite_error(c, c->status);
202                 return;
203         }
204
205         /* what to do when there's no group account to delete
206            and what if there's more than one rid resolved */
207         if (!s->lookupname.out.rids.count) {
208                 c->status = NT_STATUS_NO_SUCH_GROUP;
209                 composite_error(c, c->status);
210                 return;
211
212         } else if (!s->lookupname.out.rids.count > 1) {
213                 c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
214                 composite_error(c, c->status);
215                 return;
216         }
217
218         /* prepare the arguments for rpc call */
219         s->opengroup.in.domain_handle = &s->domain_handle;
220         s->opengroup.in.rid           = s->lookupname.out.rids.ids[0];
221         s->opengroup.in.access_mask   = SEC_FLAG_MAXIMUM_ALLOWED;
222         s->opengroup.out.group_handle  = &s->group_handle;
223
224         /* send rpc request */
225         opengroup_req = dcerpc_samr_OpenGroup_send(s->pipe, c, &s->opengroup);
226         if (composite_nomem(opengroup_req, c)) return;
227
228         composite_continue_rpc(c, opengroup_req, continue_groupdel_group_opened, c);
229 }
230
231
232 static void continue_groupdel_group_opened(struct rpc_request *req)
233 {
234         struct composite_context *c;
235         struct groupdel_state *s;
236         struct rpc_request *delgroup_req;
237
238         c = talloc_get_type(req->async.private_data, struct composite_context);
239         s = talloc_get_type(c->private_data, struct groupdel_state);
240
241         /* receive samr_OpenGroup result */
242         c->status = dcerpc_ndr_request_recv(req);
243         if (!composite_is_ok(c)) return;
244
245         c->status = s->opengroup.out.result;
246         if (!NT_STATUS_IS_OK(c->status)) {
247                 composite_error(c, c->status);
248                 return;
249         }
250         
251         /* prepare the final rpc call arguments */
252         s->deletegroup.in.group_handle   = &s->group_handle;
253         s->deletegroup.out.group_handle  = &s->group_handle;
254         
255         /* send rpc request */
256         delgroup_req = dcerpc_samr_DeleteDomainGroup_send(s->pipe, c, &s->deletegroup);
257         if (composite_nomem(delgroup_req, c)) return;
258
259         /* callback handler setup */
260         composite_continue_rpc(c, delgroup_req, continue_groupdel_deleted, c);
261 }
262
263
264 static void continue_groupdel_deleted(struct rpc_request *req)
265 {
266         struct composite_context *c;
267         struct groupdel_state *s;
268
269         c = talloc_get_type(req->async.private_data, struct composite_context);
270         s = talloc_get_type(c->private_data, struct groupdel_state);
271
272         /* receive samr_DeleteGroup result */
273         c->status = dcerpc_ndr_request_recv(req);
274         if (!composite_is_ok(c)) return;
275
276         /* return the actual function call status */
277         c->status = s->deletegroup.out.result;
278         if (!NT_STATUS_IS_OK(c->status)) {
279                 composite_error(c, c->status);
280                 return;
281         }
282         
283         composite_done(c);
284 }
285
286
287 NTSTATUS libnet_rpc_groupdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
288                                   struct libnet_rpc_groupdel *io)
289 {
290         NTSTATUS status;
291         struct groupdel_state *s;
292
293         status = composite_wait(c);
294         if (NT_STATUS_IS_OK(status) && io) {
295                 s = talloc_get_type(c->private_data, struct groupdel_state);
296                 io->out.group_handle = s->group_handle;
297         }
298
299         talloc_free(c);
300         return status;
301 }
302
303
304 NTSTATUS libnet_rpc_groupdel(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
305                              struct libnet_rpc_groupdel *io)
306 {
307         struct composite_context *c;
308
309         c = libnet_rpc_groupdel_send(p, io, NULL);
310         return libnet_rpc_groupdel_recv(c, mem_ctx, io);
311 }