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