r19271: Test the "hack" for "Domain Users" as agreed with
authorJeremy Allison <jra@samba.org>
Sat, 14 Oct 2006 00:33:03 +0000 (00:33 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:15:27 +0000 (12:15 -0500)
Jerry.
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.
Jeremy.

source/nsswitch/winbindd_group.c

index 676bf918b4b631c5dcf7350c36aafc0e31d329ea..79d8e2970ed002b083fa0d108944cf1eefbb18ea 100644 (file)
@@ -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,