Merge branch 'master' of git://git.samba.org/samba
[samba.git] / source4 / libnet / groupinfo.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 getting group information via samr pipe
22 */
23
24
25 #include "includes.h"
26 #include "libcli/composite/composite.h"
27 #include "libnet/composite.h"
28 #include "librpc/gen_ndr/security.h"
29 #include "libcli/security/security.h"
30 #include "libnet/userman.h"
31 #include "libnet/groupinfo.h"
32 #include "librpc/gen_ndr/ndr_samr_c.h"
33 #include "libnet/libnet_proto.h"
34
35
36 struct groupinfo_state {
37         struct dcerpc_pipe         *pipe;
38         struct policy_handle       domain_handle;
39         struct policy_handle       group_handle;
40         uint16_t                   level;
41         struct samr_LookupNames    lookup;
42         struct samr_OpenGroup      opengroup;
43         struct samr_QueryGroupInfo querygroupinfo;
44         struct samr_Close          samrclose;
45         union  samr_GroupInfo      *info;
46
47         /* information about the progress */
48         void (*monitor_fn)(struct monitor_msg *);
49 };
50
51
52 static void continue_groupinfo_lookup(struct rpc_request *req);
53 static void continue_groupinfo_opengroup(struct rpc_request *req);
54 static void continue_groupinfo_getgroup(struct rpc_request *req);
55 static void continue_groupinfo_closegroup(struct rpc_request *req);
56
57
58 /**
59  * Stage 1 (optional): Look for a group name in SAM server.
60  */
61 static void continue_groupinfo_lookup(struct rpc_request *req)
62 {
63         struct composite_context *c;
64         struct groupinfo_state *s;
65         struct rpc_request *opengroup_req;
66         struct monitor_msg msg;
67         struct msg_rpc_lookup_name *msg_lookup;
68
69         c = talloc_get_type(req->async.private_data, struct composite_context);
70         s = talloc_get_type(c->private_data, struct groupinfo_state);
71
72         /* receive samr_Lookup reply */
73         c->status = dcerpc_ndr_request_recv(req);
74         if (!composite_is_ok(c)) return;
75         
76         /* there could be a problem with name resolving itself */
77         if (!NT_STATUS_IS_OK(s->lookup.out.result)) {
78                 composite_error(c, s->lookup.out.result);
79                 return;
80         }
81
82         /* issue a monitor message */
83         if (s->monitor_fn) {
84                 msg.type = mon_SamrLookupName;
85                 msg_lookup = talloc(s, struct msg_rpc_lookup_name);
86                 msg_lookup->rid = s->lookup.out.rids.ids;
87                 msg_lookup->count = s->lookup.out.rids.count;
88                 msg.data = (void*)msg_lookup;
89                 msg.data_size = sizeof(*msg_lookup);
90                 
91                 s->monitor_fn(&msg);
92         }
93         
94
95         /* have we actually got name resolved
96            - we're looking for only one at the moment */
97         if (s->lookup.out.rids.count == 0) {
98                 composite_error(c, NT_STATUS_NO_SUCH_USER);
99         }
100
101         /* TODO: find proper status code for more than one rid found */
102
103         /* prepare parameters for LookupNames */
104         s->opengroup.in.domain_handle   = &s->domain_handle;
105         s->opengroup.in.access_mask     = SEC_FLAG_MAXIMUM_ALLOWED;
106         s->opengroup.in.rid             = s->lookup.out.rids.ids[0];
107         s->opengroup.out.group_handle   = &s->group_handle;
108
109         /* send request */
110         opengroup_req = dcerpc_samr_OpenGroup_send(s->pipe, c, &s->opengroup);
111         if (composite_nomem(opengroup_req, c)) return;
112
113         composite_continue_rpc(c, opengroup_req, continue_groupinfo_opengroup, c);
114 }
115
116
117 /**
118  * Stage 2: Open group policy handle.
119  */
120 static void continue_groupinfo_opengroup(struct rpc_request *req)
121 {
122         struct composite_context *c;
123         struct groupinfo_state *s;
124         struct rpc_request *querygroup_req;
125         struct monitor_msg msg;
126         struct msg_rpc_open_group *msg_open;
127
128         c = talloc_get_type(req->async.private_data, struct composite_context);
129         s = talloc_get_type(c->private_data, struct groupinfo_state);
130
131         /* receive samr_OpenGroup reply */
132         c->status = dcerpc_ndr_request_recv(req);
133         if (!composite_is_ok(c)) return;
134
135         if (!NT_STATUS_IS_OK(s->querygroupinfo.out.result)) {
136                 composite_error(c, s->querygroupinfo.out.result);
137                 return;
138         }
139
140         /* issue a monitor message */
141         if (s->monitor_fn) {
142                 msg.type = mon_SamrOpenGroup;
143                 msg_open = talloc(s, struct msg_rpc_open_group);
144                 msg_open->rid = s->opengroup.in.rid;
145                 msg_open->access_mask = s->opengroup.in.access_mask;
146                 msg.data = (void*)msg_open;
147                 msg.data_size = sizeof(*msg_open);
148                 
149                 s->monitor_fn(&msg);
150         }
151         
152         /* prepare parameters for QueryGroupInfo call */
153         s->querygroupinfo.in.group_handle = &s->group_handle;
154         s->querygroupinfo.in.level        = s->level;
155         
156         /* queue rpc call, set event handling and new state */
157         querygroup_req = dcerpc_samr_QueryGroupInfo_send(s->pipe, c, &s->querygroupinfo);
158         if (composite_nomem(querygroup_req, c)) return;
159         
160         composite_continue_rpc(c, querygroup_req, continue_groupinfo_getgroup, c);
161 }
162
163
164 /**
165  * Stage 3: Get requested group information.
166  */
167 static void continue_groupinfo_getgroup(struct rpc_request *req)
168 {
169         struct composite_context *c;
170         struct groupinfo_state *s;
171         struct rpc_request *close_req;
172         struct monitor_msg msg;
173         struct msg_rpc_query_group *msg_query;
174
175         c = talloc_get_type(req->async.private_data, struct composite_context);
176         s = talloc_get_type(c->private_data, struct groupinfo_state);
177
178         /* receive samr_QueryGroupInfo reply */
179         c->status = dcerpc_ndr_request_recv(req);
180         if (!composite_is_ok(c)) return;
181
182         /* check if querygroup itself went ok */
183         if (!NT_STATUS_IS_OK(s->querygroupinfo.out.result)) {
184                 composite_error(c, s->querygroupinfo.out.result);
185                 return;
186         }
187
188         s->info = talloc_steal(s, s->querygroupinfo.out.info);
189
190         /* issue a monitor message */
191         if (s->monitor_fn) {
192                 msg.type = mon_SamrQueryGroup;
193                 msg_query = talloc(s, struct msg_rpc_query_group);
194                 msg_query->level = s->querygroupinfo.in.level;
195                 msg.data = (void*)msg_query;
196                 msg.data_size = sizeof(*msg_query);
197                 
198                 s->monitor_fn(&msg);
199         }
200         
201         /* prepare arguments for Close call */
202         s->samrclose.in.handle  = &s->group_handle;
203         s->samrclose.out.handle = &s->group_handle;
204         
205         /* queue rpc call, set event handling and new state */
206         close_req = dcerpc_samr_Close_send(s->pipe, c, &s->samrclose);
207         if (composite_nomem(close_req, c)) return;
208         
209         composite_continue_rpc(c, close_req, continue_groupinfo_closegroup, c);
210 }
211
212
213 /**
214  * Stage 4: Close policy handle associated with opened group.
215  */
216 static void continue_groupinfo_closegroup(struct rpc_request *req)
217 {
218         struct composite_context *c;
219         struct groupinfo_state *s;
220         struct monitor_msg msg;
221         struct msg_rpc_close_group *msg_close;
222
223         c = talloc_get_type(req->async.private_data, struct composite_context);
224         s = talloc_get_type(c->private_data, struct groupinfo_state);
225
226         /* receive samr_Close reply */
227         c->status = dcerpc_ndr_request_recv(req);
228         if (!composite_is_ok(c)) return;
229
230         if (!NT_STATUS_IS_OK(s->samrclose.out.result)) {
231                 composite_error(c, s->samrclose.out.result);
232                 return;
233         }
234
235         /* issue a monitor message */
236         if (s->monitor_fn) {
237                 msg.type = mon_SamrClose;
238                 msg_close = talloc(s, struct msg_rpc_close_group);
239                 msg_close->rid = s->opengroup.in.rid;
240                 msg.data = (void*)msg_close;
241                 msg.data_size = sizeof(*msg_close);
242
243                 s->monitor_fn(&msg);
244         }
245
246         composite_done(c);
247 }
248
249
250 /**
251  * Sends asynchronous groupinfo request
252  *
253  * @param p dce/rpc call pipe 
254  * @param io arguments and results of the call
255  */
256 struct composite_context *libnet_rpc_groupinfo_send(struct dcerpc_pipe *p,
257                                                     struct libnet_rpc_groupinfo *io,
258                                                     void (*monitor)(struct monitor_msg*))
259 {
260         struct composite_context *c;
261         struct groupinfo_state *s;
262         struct dom_sid *sid;
263         struct rpc_request *opengroup_req, *lookup_req;
264
265         if (!p || !io) return NULL;
266         
267         c = composite_create(p, dcerpc_event_context(p));
268         if (c == NULL) return c;
269         
270         s = talloc_zero(c, struct groupinfo_state);
271         if (composite_nomem(s, c)) return c;
272
273         c->private_data = s;
274
275         s->level         = io->in.level;
276         s->pipe          = p;
277         s->domain_handle = io->in.domain_handle;
278         s->monitor_fn    = monitor;
279
280         if (io->in.sid) {
281                 sid = dom_sid_parse_talloc(s, io->in.sid);
282                 if (composite_nomem(sid, c)) return c;
283
284                 s->opengroup.in.domain_handle  = &s->domain_handle;
285                 s->opengroup.in.access_mask    = SEC_FLAG_MAXIMUM_ALLOWED;
286                 s->opengroup.in.rid            = sid->sub_auths[sid->num_auths - 1];
287                 s->opengroup.out.group_handle  = &s->group_handle;
288                 
289                 /* send request */
290                 opengroup_req = dcerpc_samr_OpenGroup_send(p, c, &s->opengroup);
291                 if (composite_nomem(opengroup_req, c)) return c;
292
293                 composite_continue_rpc(c, opengroup_req, continue_groupinfo_opengroup, c);
294
295         } else {
296                 /* preparing parameters to send rpc request */
297                 s->lookup.in.domain_handle    = &s->domain_handle;
298                 s->lookup.in.num_names        = 1;
299                 s->lookup.in.names            = talloc_array(s, struct lsa_String, 1);
300                 if (composite_nomem(s->lookup.in.names, c)) return c;
301
302                 s->lookup.in.names[0].string  = talloc_strdup(s, io->in.groupname);
303                 if (composite_nomem(s->lookup.in.names[0].string, c)) return c;
304                 
305                 /* send request */
306                 lookup_req = dcerpc_samr_LookupNames_send(p, c, &s->lookup);
307                 if (composite_nomem(lookup_req, c)) return c;
308                 
309                 composite_continue_rpc(c, lookup_req, continue_groupinfo_lookup, c);
310         }
311
312         return c;
313 }
314
315
316 /**
317  * Waits for and receives result of asynchronous groupinfo call
318  * 
319  * @param c composite context returned by asynchronous groupinfo call
320  * @param mem_ctx memory context of the call
321  * @param io pointer to results (and arguments) of the call
322  * @return nt status code of execution
323  */
324
325 NTSTATUS libnet_rpc_groupinfo_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
326                                    struct libnet_rpc_groupinfo *io)
327 {
328         NTSTATUS status;
329         struct groupinfo_state *s;
330         
331         /* wait for results of sending request */
332         status = composite_wait(c);
333         
334         if (NT_STATUS_IS_OK(status) && io) {
335                 s = talloc_get_type(c->private_data, struct groupinfo_state);
336                 talloc_steal(mem_ctx, s->info);
337                 io->out.info = *s->info;
338         }
339         
340         /* memory context associated to composite context is no longer needed */
341         talloc_free(c);
342         return status;
343 }
344
345
346 /**
347  * Synchronous version of groupinfo call
348  *
349  * @param pipe dce/rpc call pipe
350  * @param mem_ctx memory context for the call
351  * @param io arguments and results of the call
352  * @return nt status code of execution
353  */
354
355 NTSTATUS libnet_rpc_groupinfo(struct dcerpc_pipe *p,
356                               TALLOC_CTX *mem_ctx,
357                               struct libnet_rpc_groupinfo *io)
358 {
359         struct composite_context *c = libnet_rpc_groupinfo_send(p, io, NULL);
360         return libnet_rpc_groupinfo_recv(c, mem_ctx, io);
361 }