From f803c3237635880694d668d9ce3c29b46c311d43 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 25 Feb 2003 02:20:46 +0000 Subject: Fix a really nasty bug where some users in AD domains (particularly child domains) would not have the tokenGroups or memberOf attributes filled in. This would cause a user to have no supplementary group membership. Detect this by the fact that the primaryGid must be present in the tokenGroups, and if it isn't (ie, if there is no tokenGroups at all), do a server-side search on all groups using the 'member' attribute and the user's DN. Andrew Bartlett (This used to be commit a074f74e627e1d947a76bcf3a39e3c5df4d4ffe5) --- source3/nsswitch/winbindd_ads.c | 104 ++++++++++++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 14 deletions(-) (limited to 'source3') diff --git a/source3/nsswitch/winbindd_ads.c b/source3/nsswitch/winbindd_ads.c index 9fd391870b..93c9babd5e 100644 --- a/source3/nsswitch/winbindd_ads.c +++ b/source3/nsswitch/winbindd_ads.c @@ -455,8 +455,10 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, ADS_STRUCT *ads = NULL; const char *attrs[] = {"distinguishedName", NULL}; const char *attrs2[] = {"tokenGroups", "primaryGroupID", NULL}; + const char *group_attrs[] = {"objectSid", "cn", NULL}; ADS_STATUS rc; int count; + void *res = NULL; void *msg = NULL; char *exp; char *user_dn; @@ -467,22 +469,30 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, char *sidstr; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; - *num_groups = 0; - DEBUG(3,("ads: lookup_usergroups\n")); - - (*num_groups) = 0; + *num_groups = 0; sid_from_rid(domain, user_rid, &sid); ads = ads_cached_connection(domain); if (!ads) goto done; - sidstr = sid_binstring(&sid); - asprintf(&exp, "(objectSid=%s)", sidstr); + if (!(sidstr = sid_binstring(&sid))) { + DEBUG(1,("lookup_usergroups(rid=%d) sid_binstring returned NULL\n", user_rid)); + status = NT_STATUS_NO_MEMORY; + goto done; + } + if (asprintf(&exp, "(objectSid=%s)", sidstr) == -1) { + free(sidstr); + DEBUG(1,("lookup_usergroups(rid=%d) asprintf failed!\n", user_rid)); + status = NT_STATUS_NO_MEMORY; + goto done; + } + rc = ads_search_retry(ads, &msg, exp, attrs); free(exp); free(sidstr); + if (!ADS_ERR_OK(rc)) { DEBUG(1,("lookup_usergroups(rid=%d) ads_search: %s\n", user_rid, ads_errstr(rc))); goto done; @@ -507,20 +517,86 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, goto done; } - count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids) + 1; - (*user_gids) = (uint32 *)talloc_zero(mem_ctx, sizeof(uint32) * count); - (*user_gids)[(*num_groups)++] = primary_group; + count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids); - for (i=1;isid, &sids[i-1], &rid)) continue; - (*user_gids)[*num_groups] = rid; - (*num_groups)++; + if (msg) ads_msgfree(ads, msg); + + /* there must always be at least one group in the token, + unless we are talking to a buggy Win2k server */ + if (count == 0) { + /* buggy server, no tokenGroups. Instead lookup what groups this user + is a member of by DN search on member*/ + if (asprintf(&exp, "(&(member=%s)(objectClass=group))", user_dn) == -1) { + free(sidstr); + DEBUG(1,("lookup_usergroups(rid=%d) asprintf failed!\n", user_rid)); + status = NT_STATUS_NO_MEMORY; + goto done; + } + + rc = ads_search_retry(ads, &res, exp, group_attrs); + free(exp); + + if (!ADS_ERR_OK(rc)) { + DEBUG(1,("lookup_usergroups(rid=%d) ads_search member=%s: %s\n", user_rid, user_dn, ads_errstr(rc))); + goto done; + } + + count = ads_count_replies(ads, res); + if (count == 0) { + DEBUG(5,("lookup_usergroups: No supp groups found\n")); + goto done; + } + + (*user_gids) = (uint32 *)talloc_zero(mem_ctx, sizeof(uint32) * (count + 1)); + (*user_gids)[0] = primary_group; + + *num_groups = 1; + + for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { + uint32 rid; + DOM_SID group_sid; + fstring sid_string; + const char *cn; + + cn = ads_pull_string(ads, mem_ctx, msg, "cn"); + if (!cn) { + cn = ""; + } + + if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) { + DEBUG(1,("No sid for %s !?\n", cn)); + continue; + } + + if (!sid_peek_check_rid(&domain->sid, &group_sid, &rid)) { + DEBUG(5,("sid for %s is out of domain or invalid\n", sid_to_string(sid_string, &sid))); + continue; + } + if (rid == primary_group) continue; + + (*user_gids)[*num_groups] = rid; + (*num_groups)++; + + } + } else { + (*user_gids) = (uint32 *)talloc_zero(mem_ctx, sizeof(uint32) * (count + 1)); + (*user_gids)[0] = primary_group; + + *num_groups = 1; + + for (i=0;isid, &sids[i-1], &rid)) continue; + if (rid == primary_group) continue; + (*user_gids)[*num_groups] = rid; + (*num_groups)++; + } } status = NT_STATUS_OK; DEBUG(3,("ads lookup_usergroups for rid=%d\n", user_rid)); done: + if (res) ads_msgfree(ads, res); if (msg) ads_msgfree(ads, msg); return status; -- cgit