2 Unix SMB/CIFS implementation.
3 async lookupgroupmembers
4 Copyright (C) Volker Lendecke 2009
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.
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.
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/>.
22 #include "librpc/gen_ndr/cli_wbint.h"
25 * We have 3 sets of routines here:
27 * wb_lookupgroupmem is the low-level one-group routine
29 * wb_groups_members walks a list of groups
31 * wb_group_members finally is the high-level routine expanding groups
36 * Look up members of a single group. Essentially a wrapper around the
37 * lookup_groupmem winbindd_methods routine.
40 struct wb_lookupgroupmem_state {
42 struct wbint_GroupMembers members;
45 static void wb_lookupgroupmem_done(struct tevent_req *subreq);
47 static struct tevent_req *wb_lookupgroupmem_send(TALLOC_CTX *mem_ctx,
48 struct tevent_context *ev,
49 const struct dom_sid *group_sid,
50 enum lsa_SidType type)
52 struct tevent_req *req, *subreq;
53 struct wb_lookupgroupmem_state *state;
54 struct winbindd_domain *domain;
56 struct dom_sid *sid_mem;
61 req = tevent_req_create(mem_ctx, &state,
62 struct wb_lookupgroupmem_state);
66 sid_copy(&state->sid, group_sid);
68 domain = find_domain_from_sid_noinit(group_sid);
70 tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
71 return tevent_req_post(req, ev);
74 status = wcache_lookup_groupmem(domain, state, &state->sid, &num_names,
75 &sid_mem, &names, &name_types);
76 if (NT_STATUS_IS_OK(status)) {
78 state->members.members = talloc_array(
79 state, struct wbint_GroupMember, num_names);
80 if (tevent_req_nomem(state->members.members, req)) {
81 return tevent_req_post(req, ev);
83 state->members.num_members = num_names;
84 for (i=0; i<num_names; i++) {
85 struct wbint_GroupMember *m;
87 m = &state->members.members[i];
88 sid_copy(&m->sid, &sid_mem[i]);
90 m->name = talloc_move(state->members.members, &name);
91 m->type = (enum lsa_SidType)name_types[i];
95 TALLOC_FREE(name_types);
97 return tevent_req_post(req, ev);
100 subreq = rpccli_wbint_LookupGroupMembers_send(
101 state, ev, domain->child.rpccli, &state->sid, type,
103 if (tevent_req_nomem(subreq, req)) {
104 return tevent_req_post(req, ev);
106 tevent_req_set_callback(subreq, wb_lookupgroupmem_done, req);
110 static void wb_lookupgroupmem_done(struct tevent_req *subreq)
112 struct tevent_req *req = tevent_req_callback_data(
113 subreq, struct tevent_req);
114 struct wb_lookupgroupmem_state *state = tevent_req_data(
115 req, struct wb_lookupgroupmem_state);
116 NTSTATUS status, result;
118 status = rpccli_wbint_LookupGroupMembers_recv(subreq, state, &result);
120 if (!NT_STATUS_IS_OK(status)) {
121 tevent_req_nterror(req, status);
124 if (!NT_STATUS_IS_OK(result)) {
125 tevent_req_nterror(req, result);
128 tevent_req_done(req);
131 static NTSTATUS wb_lookupgroupmem_recv(struct tevent_req *req,
134 struct wbint_GroupMember **members)
136 struct wb_lookupgroupmem_state *state = tevent_req_data(
137 req, struct wb_lookupgroupmem_state);
140 if (tevent_req_is_nterror(req, &status)) {
144 *num_members = state->members.num_members;
145 *members = talloc_move(mem_ctx, &state->members.members);
150 * Same as wb_lookupgroupmem for a list of groups
153 struct wb_groups_members_state {
154 struct tevent_context *ev;
155 struct wbint_GroupMember *groups;
158 struct wbint_GroupMember *all_members;
161 static NTSTATUS wb_groups_members_next_subreq(
162 struct wb_groups_members_state *state,
163 TALLOC_CTX *mem_ctx, struct tevent_req **psubreq);
164 static void wb_groups_members_done(struct tevent_req *subreq);
166 static struct tevent_req *wb_groups_members_send(TALLOC_CTX *mem_ctx,
167 struct tevent_context *ev,
169 struct wbint_GroupMember *groups)
171 struct tevent_req *req, *subreq;
172 struct wb_groups_members_state *state;
175 req = tevent_req_create(mem_ctx, &state,
176 struct wb_groups_members_state);
181 state->groups = groups;
182 state->num_groups = num_groups;
183 state->next_group = 0;
184 state->all_members = NULL;
186 status = wb_groups_members_next_subreq(state, state, &subreq);
187 if (!NT_STATUS_IS_OK(status)) {
188 tevent_req_nterror(req, status);
189 return tevent_req_post(req, ev);
191 if (subreq == NULL) {
192 tevent_req_done(req);
193 return tevent_req_post(req, ev);
195 tevent_req_set_callback(subreq, wb_groups_members_done, req);
199 static NTSTATUS wb_groups_members_next_subreq(
200 struct wb_groups_members_state *state,
201 TALLOC_CTX *mem_ctx, struct tevent_req **psubreq)
203 struct tevent_req *subreq;
204 struct wbint_GroupMember *g;
206 if (state->next_group >= state->num_groups) {
211 g = &state->groups[state->next_group];
212 state->next_group += 1;
214 subreq = wb_lookupgroupmem_send(mem_ctx, state->ev, &g->sid,
216 if (subreq == NULL) {
217 return NT_STATUS_NO_MEMORY;
223 static void wb_groups_members_done(struct tevent_req *subreq)
225 struct tevent_req *req = tevent_req_callback_data(
226 subreq, struct tevent_req);
227 struct wb_groups_members_state *state = tevent_req_data(
228 req, struct wb_groups_members_state);
229 int i, num_all_members;
231 struct wbint_GroupMember *members = NULL;
234 status = wb_lookupgroupmem_recv(subreq, state, &num_members,
239 * In this error handling here we might have to be a bit more generous
240 * and just continue if an error occured.
243 if (!NT_STATUS_IS_OK(status)) {
244 tevent_req_nterror(req, status);
248 num_all_members = talloc_array_length(state->all_members);
250 state->all_members = talloc_realloc(
251 state, state->all_members, struct wbint_GroupMember,
252 num_all_members + num_members);
253 if ((num_all_members + num_members != 0)
254 && tevent_req_nomem(state->all_members, req)) {
257 for (i=0; i<num_members; i++) {
258 struct wbint_GroupMember *src, *dst;
260 dst = &state->all_members[num_all_members + i];
261 sid_copy(&dst->sid, &src->sid);
262 dst->name = talloc_move(state->all_members, &src->name);
263 dst->type = src->type;
265 TALLOC_FREE(members);
267 status = wb_groups_members_next_subreq(state, state, &subreq);
268 if (!NT_STATUS_IS_OK(status)) {
269 tevent_req_nterror(req, status);
272 if (subreq == NULL) {
273 tevent_req_done(req);
276 tevent_req_set_callback(subreq, wb_groups_members_done, req);
279 static NTSTATUS wb_groups_members_recv(struct tevent_req *req,
282 struct wbint_GroupMember **members)
284 struct wb_groups_members_state *state = tevent_req_data(
285 req, struct wb_groups_members_state);
288 if (tevent_req_is_nterror(req, &status)) {
291 *num_members = talloc_array_length(state->all_members);
292 *members = talloc_move(mem_ctx, &state->all_members);
298 * This is the routine expanding a list of groups up to a certain level. We
299 * collect the users in a talloc_dict: We have to add them without duplicates,
300 * and and talloc_dict is an indexed (here indexed by SID) data structure.
303 struct wb_group_members_state {
304 struct tevent_context *ev;
306 struct talloc_dict *users;
307 struct wbint_GroupMember *groups;
310 static NTSTATUS wb_group_members_next_subreq(
311 struct wb_group_members_state *state,
312 TALLOC_CTX *mem_ctx, struct tevent_req **psubreq);
313 static void wb_group_members_done(struct tevent_req *subreq);
315 struct tevent_req *wb_group_members_send(TALLOC_CTX *mem_ctx,
316 struct tevent_context *ev,
317 const struct dom_sid *sid,
318 enum lsa_SidType type,
321 struct tevent_req *req, *subreq;
322 struct wb_group_members_state *state;
325 req = tevent_req_create(mem_ctx, &state,
326 struct wb_group_members_state);
331 state->depth = max_depth;
332 state->users = talloc_dict_init(state);
333 if (tevent_req_nomem(state->users, req)) {
334 return tevent_req_post(req, ev);
337 state->groups = talloc(state, struct wbint_GroupMember);
338 if (tevent_req_nomem(state->groups, req)) {
339 return tevent_req_post(req, ev);
341 state->groups->name = NULL;
342 sid_copy(&state->groups->sid, sid);
343 state->groups->type = type;
345 status = wb_group_members_next_subreq(state, state, &subreq);
346 if (!NT_STATUS_IS_OK(status)) {
347 tevent_req_nterror(req, status);
348 return tevent_req_post(req, ev);
350 if (subreq == NULL) {
351 tevent_req_done(req);
352 return tevent_req_post(req, ev);
354 tevent_req_set_callback(subreq, wb_group_members_done, req);
358 static NTSTATUS wb_group_members_next_subreq(
359 struct wb_group_members_state *state,
360 TALLOC_CTX *mem_ctx, struct tevent_req **psubreq)
362 struct tevent_req *subreq;
364 if ((talloc_array_length(state->groups) == 0)
365 || (state->depth <= 0)) {
371 subreq = wb_groups_members_send(
372 mem_ctx, state->ev, talloc_array_length(state->groups),
374 if (subreq == NULL) {
375 return NT_STATUS_NO_MEMORY;
381 static void wb_group_members_done(struct tevent_req *subreq)
383 struct tevent_req *req = tevent_req_callback_data(
384 subreq, struct tevent_req);
385 struct wb_group_members_state *state = tevent_req_data(
386 req, struct wb_group_members_state);
387 int i, num_groups, new_users, new_groups;
389 struct wbint_GroupMember *members = NULL;
392 status = wb_groups_members_recv(subreq, state, &num_members, &members);
394 if (!NT_STATUS_IS_OK(status)) {
395 tevent_req_nterror(req, status);
399 new_users = new_groups = 0;
400 for (i=0; i<num_members; i++) {
401 switch (members[i].type) {
402 case SID_NAME_DOM_GRP:
404 case SID_NAME_WKN_GRP:
408 /* Ignore everything else */
414 TALLOC_FREE(state->groups);
415 state->groups = talloc_array(state, struct wbint_GroupMember,
419 * Collect the users into state->users and the groups into
420 * state->groups for the next iteration.
423 for (i=0; i<num_members; i++) {
424 switch (members[i].type) {
426 case SID_NAME_COMPUTER: {
428 * Add a copy of members[i] to state->users
430 struct wbint_GroupMember *m;
434 m = talloc(talloc_tos(), struct wbint_GroupMember);
435 if (tevent_req_nomem(m, req)) {
438 sid_copy(&m->sid, &members[i].sid);
439 m->name = talloc_move(m, &members[i].name);
440 m->type = members[i].type;
442 sid = &members[i].sid;
443 key = data_blob_const(
444 sid, ndr_size_dom_sid(sid, NULL, 0));
446 if (!talloc_dict_set(state->users, key, &m)) {
447 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
452 case SID_NAME_DOM_GRP:
454 case SID_NAME_WKN_GRP: {
455 struct wbint_GroupMember *g;
457 * Save members[i] for the next round
459 g = &state->groups[num_groups];
460 sid_copy(&g->sid, &members[i].sid);
461 g->name = talloc_move(state->groups, &members[i].name);
462 g->type = members[i].type;
467 /* Ignore everything else */
472 status = wb_group_members_next_subreq(state, state, &subreq);
473 if (!NT_STATUS_IS_OK(status)) {
474 tevent_req_nterror(req, status);
477 if (subreq == NULL) {
478 tevent_req_done(req);
481 tevent_req_set_callback(subreq, wb_group_members_done, req);
484 NTSTATUS wb_group_members_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
485 struct talloc_dict **members)
487 struct wb_group_members_state *state = tevent_req_data(
488 req, struct wb_group_members_state);
491 if (tevent_req_is_nterror(req, &status)) {
494 *members = talloc_move(mem_ctx, &state->users);