From 7ce1b2fd69fca60e74ddeb382548f2ff25273949 Mon Sep 17 00:00:00 2001
From: Jan Zeleny <jzeleny@redhat.com>
Date: Fri, 27 May 2011 07:33:09 -0400
Subject: [PATCH 2/2] Non-posix group processing - ldap provider and nss responder

---
 src/providers/ldap/ldap_id_cleanup.c     |   24 ++++----
 src/providers/ldap/sdap_async_accounts.c |   83 ++++++++++++++++++++++++------
 src/responder/nss/nsssrv_cmd.c           |   14 ++++-
 3 files changed, 90 insertions(+), 31 deletions(-)

diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c
index 7f7a02c64bb54314363da459acc8e7e34d8850c4..d31dace557042dfc4028ac82d0877a7ae0fa2131 100644
--- a/src/providers/ldap/ldap_id_cleanup.c
+++ b/src/providers/ldap/ldap_id_cleanup.c
@@ -395,6 +395,7 @@ static int cleanup_groups(TALLOC_CTX *memctx,
     size_t u_count;
     int ret;
     int i;
+    const char *posix;
 
     tmpctx = talloc_new(memctx);
     if (!tmpctx) {
@@ -433,19 +434,18 @@ static int cleanup_groups(TALLOC_CTX *memctx,
             goto done;
         }
 
-        gid = (gid_t) ldb_msg_find_attr_as_uint(msgs[i], SYSDB_GIDNUM, 0);
-        if (!gid) {
-            DEBUG(2, ("Entry has no GID\n"));
-            ret = EIO;
-            goto done;
+        posix = ldb_msg_find_attr_as_string(msgs[i], SYSDB_POSIX, NULL);
+        if (!posix || strcmp(posix, "TRUE") == 0) {
+            /* Search for users that are members of this group, or
+             * that have this group as their primary GID
+             */
+            gid = (gid_t) ldb_msg_find_attr_as_uint(msgs[i], SYSDB_GIDNUM, 0);
+            subfilter = talloc_asprintf(tmpctx, "(|(%s=%s)(%s=%lu))",
+                                        SYSDB_MEMBEROF, dn,
+                                        SYSDB_GIDNUM, (long unsigned) gid);
+        } else {
+            subfilter = talloc_asprintf(tmpctx, "(%s=%s)", SYSDB_MEMBEROF, dn);
         }
-
-        /* Search for users that are members of this group, or
-         * that have this group as their primary GID
-         */
-        subfilter = talloc_asprintf(tmpctx, "(|(%s=%s)(%s=%lu))",
-                                    SYSDB_MEMBEROF, dn,
-                                    SYSDB_GIDNUM, (long unsigned) gid);
         if (!subfilter) {
             DEBUG(2, ("Failed to build filter\n"));
             ret = ENOMEM;
diff --git a/src/providers/ldap/sdap_async_accounts.c b/src/providers/ldap/sdap_async_accounts.c
index 13311642c4d910107797df7f4f7e0ee3f10eff5d..a8f95fdd171726c35b03104ffd41c65bdbc12ee5 100644
--- a/src/providers/ldap/sdap_async_accounts.c
+++ b/src/providers/ldap/sdap_async_accounts.c
@@ -679,6 +679,7 @@ static int sdap_save_group(TALLOC_CTX *memctx,
     int ret;
     char *usn_value = NULL;
     TALLOC_CTX *tmpctx = NULL;
+    bool posix_group;
 
     tmpctx = talloc_new(memctx);
     if (!tmpctx) {
@@ -700,6 +701,19 @@ static int sdap_save_group(TALLOC_CTX *memctx,
         goto fail;
     }
 
+    ret = sysdb_attrs_get_bool(attrs, SYSDB_POSIX, &posix_group);
+    if (ret == ENOENT) {
+        posix_group = true;
+    } else if (ret != EOK) {
+        goto fail;
+    }
+
+    DEBUG(8, ("This is%s a posix group\n", (posix_group)?"":" not"));
+    ret = sysdb_attrs_add_bool(group_attrs, SYSDB_POSIX, posix_group);
+    if (ret != EOK) {
+        goto fail;
+    }
+
     ret = sysdb_attrs_get_uint32_t(attrs,
                                    opts->group_map[SDAP_AT_GROUP_GID].sys_name,
                                    &gid);
@@ -711,7 +725,8 @@ static int sdap_save_group(TALLOC_CTX *memctx,
     }
 
     /* check that the gid is valid for this domain */
-    if (OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
+    if ((posix_group || gid != 0) &&
+        OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
             DEBUG(2, ("Group [%s] filtered out! (id out of range)\n",
                       name));
         ret = EINVAL;
@@ -2055,6 +2070,7 @@ static errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
     gid_t gid;
     int ret;
     bool in_transaction = false;
+    bool posix;
 
     /* There are no groups in LDAP but we should add user to groups ?? */
     if (ldap_groups_count == 0) return EOK;
@@ -2114,11 +2130,15 @@ static errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
             }
 
             if (strcmp(name, missing[i]) == 0) {
+                posix = true;
                 ret = sysdb_attrs_get_uint32_t(ldap_groups[ai],
                                                SYSDB_GIDNUM,
                                                &gid);
-                if (ret) {
-                    DEBUG(1, ("The GID attribute is missing or malformed\n"));
+                if (ret == ENOENT) {
+                    gid = 0;
+                    posix = false;
+                } else if (ret) {
+                    DEBUG(1, ("The GID attribute is malformed\n"));
                     goto fail;
                 }
 
@@ -2132,7 +2152,7 @@ static errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
 
                 DEBUG(8, ("Adding fake group %s to sysdb\n", name));
                 ret = sysdb_add_incomplete_group(sysdb, dom, name,
-                                                 gid, original_dn);
+                                                 gid, original_dn, posix);
                 if (ret != EOK) {
                     goto fail;
                 }
@@ -2468,10 +2488,9 @@ static struct tevent_req *sdap_initgr_nested_send(TALLOC_CTX *memctx,
         return NULL;
     }
 
-    state->filter = talloc_asprintf(state, "(&(objectclass=%s)(%s=*)(%s=*))",
+    state->filter = talloc_asprintf(state, "(&(objectclass=%s)(%s=*))",
                                     opts->group_map[SDAP_OC_GROUP].name,
-                                    opts->group_map[SDAP_AT_GROUP_NAME].name,
-                                    opts->group_map[SDAP_AT_GROUP_GID].name);
+                                    opts->group_map[SDAP_AT_GROUP_NAME].name);
     if (!state->filter) {
         talloc_zfree(req);
         return NULL;
@@ -3344,6 +3363,7 @@ static struct tevent_req *sdap_nested_group_process_send(
     const char *groupname;
     hash_key_t key;
     hash_value_t value;
+    gid_t gid;
 
     req = tevent_req_create(mem_ctx, &state, struct sdap_nested_group_ctx);
     if (!req) {
@@ -3392,6 +3412,28 @@ static struct tevent_req *sdap_nested_group_process_send(
         goto immediate;
     }
 
+    ret = sysdb_attrs_get_uint32_t(group,
+                                   opts->group_map[SDAP_AT_GROUP_GID].name,
+                                   &gid);
+    if (ret == ENOENT) {
+        DEBUG(8, ("Marking group as non-posix and setting GID=0!\n"));
+        ret = sysdb_attrs_add_uint32(group,
+                                     opts->group_map[SDAP_AT_GROUP_GID].name,
+                                     0);
+        if (ret != EOK) {
+            DEBUG(1, ("Failed to add a GID to non-posix group!\n"));
+            goto immediate;
+        }
+
+        ret = sysdb_attrs_add_bool(group, SYSDB_POSIX, false);
+        if (ret != EOK) {
+            DEBUG(2, ("Error: Failed to mark group as non-posix!\n"));
+            goto immediate;
+        }
+    } else if (ret) {
+        goto immediate;
+    }
+
     value.type = HASH_VALUE_PTR;
     value.ptr = talloc_steal(groups, group);
 
@@ -4002,10 +4044,9 @@ static errno_t sdap_nested_group_lookup_group(struct tevent_req *req)
     }
 
     filter = talloc_asprintf(
-            sdap_attrs, "(&(objectclass=%s)(%s=*)(%s=*))",
+            sdap_attrs, "(&(objectclass=%s)(%s=*))",
             state->opts->group_map[SDAP_OC_GROUP].name,
-            state->opts->group_map[SDAP_AT_GROUP_NAME].name,
-            state->opts->group_map[SDAP_AT_GROUP_GID].name);
+            state->opts->group_map[SDAP_AT_GROUP_NAME].name);
     if (!filter) {
         talloc_free(sdap_attrs);
         return ENOMEM;
@@ -4370,6 +4411,7 @@ sdap_nested_group_process_deref_result(struct tevent_req *req)
     const char *orig_dn;
     errno_t ret;
     struct sdap_deref_ctx *dctx = state->derefctx;
+    const char *tmp_name;
 
     while (dctx->result_index < dctx->num_results) {
         if (dctx->deref_result[dctx->result_index]->map == \
@@ -4399,6 +4441,15 @@ sdap_nested_group_process_deref_result(struct tevent_req *req)
             dctx->result_index++;
         } else if (dctx->deref_result[dctx->result_index]->map == \
                    state->opts->group_map) {
+            ret = sysdb_attrs_get_string(dctx->deref_result[dctx->result_index]->attrs,
+                                       state->opts->group_map[SDAP_AT_GROUP_NAME].name,
+                                       &tmp_name);
+            if (ret == ENOENT) {
+                DEBUG(7, ("Dereferenced a group without name, skipping ...\n"));
+            } else if (ret) {
+                return EIO;
+            }
+
             DEBUG(6, ("Recursing down a nested group\n"));
             subreq = sdap_nested_group_process_send(state, state->ev,
                                 state->domain, state->sysdb,
@@ -4505,12 +4556,11 @@ static struct tevent_req *sdap_initgr_rfc2307bis_send(
         return NULL;
     }
 
-    filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s)(%s=*)(%s=*))",
+    filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s)(%s=*))",
                              opts->group_map[SDAP_AT_GROUP_MEMBER].name,
                              clean_orig_dn,
                              opts->group_map[SDAP_OC_GROUP].name,
-                             opts->group_map[SDAP_AT_GROUP_NAME].name,
-                             opts->group_map[SDAP_AT_GROUP_GID].name);
+                             opts->group_map[SDAP_AT_GROUP_NAME].name);
     if (!filter) {
         talloc_zfree(req);
         return NULL;
@@ -4706,6 +4756,7 @@ errno_t save_rfc2307bis_user_memberships(
         goto error;
     }
 
+    DEBUG(8, ("Updating memberships for %s\n", state->name));
     ret = sysdb_update_members(state->sysdb, state->dom, state->name,
                                SYSDB_MEMBER_USER,
                                (const char *const *)add_groups,
@@ -4916,12 +4967,11 @@ static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req)
     }
 
     filter = talloc_asprintf(
-            tmp_ctx, "(&(%s=%s)(objectclass=%s)(%s=*)(%s=*))",
+            tmp_ctx, "(&(%s=%s)(objectclass=%s)(%s=*))",
             state->opts->group_map[SDAP_AT_GROUP_MEMBER].name,
             clean_orig_dn,
             state->opts->group_map[SDAP_OC_GROUP].name,
-            state->opts->group_map[SDAP_AT_GROUP_NAME].name,
-            state->opts->group_map[SDAP_AT_GROUP_GID].name);
+            state->opts->group_map[SDAP_AT_GROUP_NAME].name);
     if (!filter) {
         ret = ENOMEM;
         goto error;
@@ -5200,6 +5250,7 @@ static errno_t rfc2307bis_nested_groups_update_sysdb(
     talloc_free(ldap_grouplist);
     talloc_free(sysdb_grouplist);
 
+    DEBUG(8, ("Updating memberships for %s\n", name));
     ret = sysdb_update_members(state->sysdb, state->dom, name,
                                SYSDB_MEMBER_GROUP,
                                (const char *const *)add_groups,
diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index e698b5ec1e0bd11e46b5e8290ea2b0d393172870..cfc60262c2165b185e9e62c8b3975b3bda58cfd0 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -2922,6 +2922,8 @@ static int fill_initgr(struct sss_packet *packet, struct ldb_result *res)
     size_t blen;
     gid_t gid;
     int ret, i, num;
+    int skipped = 0;
+    const char *posix;
 
     if (res->count == 0) {
         return ENOENT;
@@ -2939,14 +2941,20 @@ static int fill_initgr(struct sss_packet *packet, struct ldb_result *res)
     /* skip first entry, it's the user entry */
     for (i = 0; i < num; i++) {
         gid = ldb_msg_find_attr_as_uint64(res->msgs[i + 1], SYSDB_GIDNUM, 0);
+        posix = ldb_msg_find_attr_as_string(res->msgs[i + 1], SYSDB_POSIX, NULL);
         if (!gid) {
-            DEBUG(1, ("Incomplete group object for initgroups! Aborting\n"));
-            return EFAULT;
+            if (posix && strcmp(posix, "FALSE") == 0) {
+                skipped++;
+                continue;
+            } else {
+                DEBUG(1, ("Incomplete group object for initgroups! Aborting\n"));
+                return EFAULT;
+            }
         }
         ((uint32_t *)body)[2 + i] = gid;
     }
 
-    ((uint32_t *)body)[0] = num; /* num results */
+    ((uint32_t *)body)[0] = num-skipped; /* num results */
     ((uint32_t *)body)[1] = 0; /* reserved */
 
     return EOK;
-- 
1.7.4.1

