diff options
Diffstat (limited to 'source3/nsswitch')
-rw-r--r-- | source3/nsswitch/winbindd_group.c | 129 |
1 files changed, 120 insertions, 9 deletions
diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c index 676bf918b4..79d8e2970e 100644 --- a/source3/nsswitch/winbindd_group.c +++ b/source3/nsswitch/winbindd_group.c @@ -57,6 +57,7 @@ static BOOL fill_grent(struct winbindd_gr *gr, const char *dom_name, /* Fill in the group membership field of a NT group given by group_sid */ static BOOL fill_grent_mem(struct winbindd_domain *domain, + struct winbindd_cli_state *state, DOM_SID *group_sid, enum lsa_SidType group_name_type, size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len) @@ -64,11 +65,12 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain, DOM_SID *sid_mem = NULL; uint32 num_names = 0; uint32 *name_types = NULL; - unsigned int buf_len, buf_ndx, i; - char **names = NULL, *buf; + unsigned int buf_len = 0, buf_ndx = 0, i; + char **names = NULL, *buf = NULL; BOOL result = False; TALLOC_CTX *mem_ctx; NTSTATUS status; + uint32 group_rid; fstring sid_string; if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name))) @@ -98,13 +100,124 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain, goto done; } + /* OPTIMIZATION / HACK. */ + /* If "enum users" is set to false, and the group being looked + up is the Domain Users SID: S-1-5-domain-513, then for the + list of members check if the querying user is in that group, + and if so only return that user as the gr_mem array. + We can change this to a different parameter than "enum users" + if neccessaey, or parameterize the group list we do this for. */ + + sid_peek_rid( group_sid, &group_rid ); + if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) { + DOM_SID querying_user_sid; + DOM_SID *pquerying_user_sid = NULL; + uint32 num_groups = 0; + DOM_SID *user_sids = NULL; + BOOL u_in_group = False; + + DEBUG(10,("fill_grent_mem: optimized lookup for sid %s domain %s\n", + sid_to_string(sid_string, group_sid), domain->name )); + + if (state) { + uid_t ret_uid = (uid_t)-1; + if (sys_getpeereid(state->sock, &ret_uid)==0) { + /* We know who's asking - look up their SID if + it's one we've mapped before. */ + status = idmap_uid_to_sid(&querying_user_sid, + ret_uid, + IDMAP_FLAG_QUERY_ONLY|IDMAP_FLAG_CACHE_ONLY); + if (NT_STATUS_IS_OK(status)) { + pquerying_user_sid = &querying_user_sid; + DEBUG(10,("fill_grent_mem: querying uid %u -> %s\n", + (unsigned int)ret_uid, + sid_to_string(sid_string, pquerying_user_sid) )); + } + } + } + + /* Only look up if it was a winbindd user in this domain. */ + if (pquerying_user_sid && + (sid_compare_domain(pquerying_user_sid, &domain->sid) == 0)) { + + DEBUG(10,("fill_grent_mem: querying user = %s\n", + sid_to_string(sid_string, pquerying_user_sid) )); + + status = domain->methods->lookup_usergroups(domain, + mem_ctx, + pquerying_user_sid, + &num_groups, + &user_sids); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("fill_grent_mem: lookup_usergroups failed " + "for sid %s in domain %s (error: %s)\n", + sid_to_string(sid_string, pquerying_user_sid), + domain->name, + nt_errstr(status))); + goto done; + } + + for (i = 0; i < num_groups; i++) { + if (sid_equal(group_sid, &user_sids[i])) { + /* User is in Domain Users, add their name + as the only group member. */ + u_in_group = True; + break; + } + } + } + + if (u_in_group) { + size_t len = 0; + char *domainname = NULL; + char *username = NULL; + fstring name; + enum lsa_SidType type; + + DEBUG(10,("fill_grent_mem: sid %s in 'Domain Users' in domain %s\n", + sid_to_string(sid_string, pquerying_user_sid), domain->name )); + + status = domain->methods->sid_to_name(domain, mem_ctx, + pquerying_user_sid, + &domainname, + &username, + &type); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("could not lookup username for user " + "sid %s in domain %s (error: %s)\n", + sid_to_string(sid_string, pquerying_user_sid), + domain->name, + nt_errstr(status))); + goto done; + } + fill_domain_username(name, domain->name, username, True); + len = strlen(name); + buf_len = len + 1; + if (!(buf = (char *)SMB_MALLOC(buf_len))) { + DEBUG(1, ("out of memory\n")); + goto done; + } + memcpy(buf, name, buf_len); + + DEBUG(10,("fill_grent_mem: user %s in 'Domain Users' in domain %s\n", + name, domain->name )); + } + + *gr_mem = buf; + *gr_mem_len = buf_len; + + DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem, + (unsigned int)buf_len, *num_gr_mem ? buf : "NULL")); + result = True; + goto done; + } + /* Lookup group members */ status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names, &sid_mem, &names, &name_types); if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("could not lookup membership for group rid %s in domain %s (error: %s)\n", + DEBUG(1, ("could not lookup membership for group sid %s in domain %s (error: %s)\n", sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status))); - goto done; } @@ -119,9 +232,6 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain, /* Add members to list */ - buf = NULL; - buf_len = buf_ndx = 0; - again: for (i = 0; i < num_names; i++) { @@ -311,7 +421,7 @@ void winbindd_getgrnam(struct winbindd_cli_state *state) if (!fill_grent(&state->response.data.gr, name_domain, name_group, gid) || - !fill_grent_mem(domain, &group_sid, name_type, + !fill_grent_mem(domain, state, &group_sid, name_type, &num_gr_mem, &gr_mem, &gr_mem_len)) { request_error(state); @@ -370,7 +480,7 @@ static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid if (!fill_grent(&state->response.data.gr, dom_name, group_name, state->request.data.gid) || - !fill_grent_mem(domain, &group_sid, name_type, + !fill_grent_mem(domain, state, &group_sid, name_type, &num_gr_mem, &gr_mem, &gr_mem_len)) { request_error(state); @@ -802,6 +912,7 @@ void winbindd_getgrent(struct winbindd_cli_state *state) sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid); result = fill_grent_mem( domain, + NULL, &member_sid, SID_NAME_DOM_GRP, &num_gr_mem, |