diff options
Diffstat (limited to 'source3/nsswitch/winbindd_group.c')
-rw-r--r-- | source3/nsswitch/winbindd_group.c | 91 |
1 files changed, 62 insertions, 29 deletions
diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c index be95e49ba4..74ede8621b 100644 --- a/source3/nsswitch/winbindd_group.c +++ b/source3/nsswitch/winbindd_group.c @@ -911,6 +911,53 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state) return WINBINDD_OK; } +static void add_gid_to_array_unique(gid_t gid, gid_t **gids, int *num) +{ + int i; + + if ((*num) >= groups_max()) + return; + + for (i=0; i<*num; i++) { + if ((*gids)[i] == gid) + return; + } + + *gids = Realloc(*gids, (*num+1) * sizeof(gid_t)); + + if (*gids == NULL) + return; + + (*gids)[*num] = gid; + *num += 1; +} + +static void add_gids_from_sid(DOM_SID *sid, gid_t **gids, int *num) +{ + gid_t gid; + DOM_SID *aliases; + int j, num_aliases; + + DEBUG(10, ("Adding gids from SID: %s\n", sid_string_static(sid))); + + if (NT_STATUS_IS_OK(idmap_sid_to_gid(sid, &gid, 0))) + add_gid_to_array_unique(gid, gids, num); + + /* Add nested group memberships */ + + if (!pdb_enum_alias_memberships(sid, &aliases, &num_aliases)) + return; + + for (j=0; j<num_aliases; j++) { + + if (!NT_STATUS_IS_OK(sid_to_gid(&aliases[j], &gid))) + continue; + + add_gid_to_array_unique(gid, gids, num); + } + SAFE_FREE(aliases); +} + /* Get user supplementary groups. This is much quicker than trying to invert the groups database. We merge the groups from the gids and other_sids info3 fields as trusted domain, universal group @@ -928,7 +975,7 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) DOM_SID **user_grpsids; struct winbindd_domain *domain; enum winbindd_result result = WINBINDD_ERROR; - gid_t *gid_list; + gid_t *gid_list = NULL; unsigned int i; TALLOC_CTX *mem_ctx; NET_USER_INFO_3 *info3 = NULL; @@ -976,6 +1023,8 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) goto done; } + add_gids_from_sid(&user_sid, &gid_list, &num_gids); + /* Treat the info3 cache as authoritative as the lookup_usergroups() function may return cached data. */ @@ -985,7 +1034,6 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) info3->num_groups2, info3->num_other_sids)); num_groups = info3->num_other_sids + info3->num_groups2; - gid_list = calloc(sizeof(gid_t), num_groups); /* Go through each other sid and convert it to a gid */ @@ -1019,23 +1067,11 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) continue; } - /* Map to a gid */ - - if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&info3->other_sids[i].sid, &gid_list[num_gids], 0)) ) - { - DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n", - sid_string_static(&info3->other_sids[i].sid))); - continue; - } + add_gids_from_sid(&info3->other_sids[i].sid, + &gid_list, &num_gids); - /* We've jumped through a lot of hoops to get here */ - - DEBUG(10, ("winbindd_getgroups: mapped other sid %s to " - "gid %lu\n", sid_string_static( - &info3->other_sids[i].sid), - (unsigned long)gid_list[num_gids])); - - num_gids++; + if (gid_list == NULL) + goto done; } for (i = 0; i < info3->num_groups2; i++) { @@ -1045,12 +1081,10 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) sid_copy( &group_sid, &domain->sid ); sid_append_rid( &group_sid, info3->gids[i].g_rid ); - if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &gid_list[num_gids], 0)) ) { - DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n", - sid_string_static(&group_sid))); - } + add_gids_from_sid(&group_sid, &gid_list, &num_gids); - num_gids++; + if (gid_list == NULL) + goto done; } SAFE_FREE(info3); @@ -1068,12 +1102,11 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) goto done; for (i = 0; i < num_groups; i++) { - if (!NT_STATUS_IS_OK(idmap_sid_to_gid(user_grpsids[i], &gid_list[num_gids], 0))) { - DEBUG(1, ("unable to convert group sid %s to gid\n", - sid_string_static(user_grpsids[i]))); - continue; - } - num_gids++; + add_gids_from_sid(user_grpsids[i], + &gid_list, &num_gids); + + if (gid_list == NULL) + goto done; } } |