diff options
author | Andrew Bartlett <abartlet@samba.org> | 2003-02-25 02:20:46 +0000 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2003-02-25 02:20:46 +0000 |
commit | f803c3237635880694d668d9ce3c29b46c311d43 (patch) | |
tree | e4648c72dc75129913bcc01d164ca6cd7e1a9f2a | |
parent | c5871a1893ccaf81116defcdc20d644502e2f98c (diff) | |
download | samba-f803c3237635880694d668d9ce3c29b46c311d43.tar.gz samba-f803c3237635880694d668d9ce3c29b46c311d43.tar.bz2 samba-f803c3237635880694d668d9ce3c29b46c311d43.zip |
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)
-rw-r--r-- | source3/nsswitch/winbindd_ads.c | 104 |
1 files changed, 90 insertions, 14 deletions
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;i<count;i++) { - uint32 rid; - if (!sid_peek_check_rid(&domain->sid, &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 = "<CN NOT AVAILABLE>"; + } + + 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;i<count;i++) { + uint32 rid; + if (!sid_peek_check_rid(&domain->sid, &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; |