From 71ced481e95a41f1d15869489adaa4a5b87b2c88 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Fri, 24 Jun 2011 13:59:38 -0400
Subject: [PATCH 12/12] Construct usergroups from the originalMemberOf
 attribute

Previously we were relying on initgroups(), but that was limited
to POSIX users. With this approach, we now parse the
originalMemberOf attribute to get just the group name.
---
 src/providers/ipa/ipa_hbac_common.c |   77 ++++++++++++++++++++++++-----------
 src/providers/ipa/ipa_hbac_users.c  |   25 ++++++++---
 2 files changed, 71 insertions(+), 31 deletions(-)

diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c
index 97e7698da8483cccf6cae8fb70ee0dfdb36fb7bc..50f80d787e3ab489e37af1e917ec2f1894c5fa0e 100644
--- a/src/providers/ipa/ipa_hbac_common.c
+++ b/src/providers/ipa/ipa_hbac_common.c
@@ -585,11 +585,14 @@ hbac_eval_user_element(TALLOC_CTX *mem_ctx,
                        struct hbac_request_element **user_element)
 {
     errno_t ret;
-    size_t i;
+    unsigned int i;
+    unsigned int num_groups = 0;
     TALLOC_CTX *tmp_ctx;
+    const char *member_dn;
     struct hbac_request_element *users;
-    struct ldb_result *res;
-    const char *group_name;
+    struct ldb_message *msg;
+    struct ldb_message_element *el;
+    const char *attrs[] = { SYSDB_ORIG_MEMBEROF, NULL };
 
     tmp_ctx = talloc_new(mem_ctx);
     if (tmp_ctx == NULL) return ENOMEM;
@@ -602,45 +605,71 @@ hbac_eval_user_element(TALLOC_CTX *mem_ctx,
 
     users->name = username;
 
-    ret = sysdb_initgroups(tmp_ctx, sysdb, domain,
-                           users->name, &res);
-    if (ret != EOK && ret != ENOENT) {
-        DEBUG(1, ("Could not determine user memberships\n"));
+    /* Read the originalMemberOf attribute
+     * This will give us the list of both POSIX and
+     * non-POSIX groups that this user belongs to.
+     */
+    ret = sysdb_search_user_by_name(tmp_ctx, sysdb, domain,
+                                    users->name, attrs, &msg);
+    if (ret != EOK) {
+        DEBUG(1, ("Could not determine user memberships for [%s]\n",
+                  users->name));
         goto done;
-    } if (ret == ENOENT) {
-        res->count = 0;
     }
 
-    users->groups = talloc_array(username,
-                                 const char *,
-                                 res->count + 1);
+    el = ldb_msg_find_element(msg, SYSDB_ORIG_MEMBEROF);
+    if (el == NULL || el->num_values == 0) {
+        DEBUG(7, ("No groups for [%s]\n", users->name));
+        users->groups = talloc_array(users, const char *, 1);
+        if (users->groups == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+        users->groups[0] = NULL;
+        goto done;
+    }
+    DEBUG(7, ("[%d] groups for [%s]\n", el->num_values, users->name));
+
+    users->groups = talloc_array(users, const char *, el->num_values + 1);
     if (users->groups == NULL) {
         ret = ENOMEM;
         goto done;
     }
 
-    for (i = 0; i < res->count; i++) {
-        group_name = ldb_msg_find_attr_as_string(res->msgs[i],
-                                                 SYSDB_NAME,
-                                                 NULL);
-        if (group_name == NULL) {
-            DEBUG(1, ("Group with no name?\n"));
-            ret = EINVAL;
+    for (i = 0; i < el->num_values; i++) {
+        member_dn = (const char *)el->values[i].data;
+
+        ret = get_ipa_groupname(users->groups, sysdb, member_dn,
+                                &users->groups[num_groups]);
+        if (ret != EOK && ret != ENOENT) {
+            DEBUG(3, ("Parse error on [%s]\n", member_dn));
             goto done;
+        } else if (ret == EOK) {
+            DEBUG(7, ("Added group [%s] for user [%s]\n",
+                      users->groups[num_groups], users->name));
+            num_groups++;
+            continue;
         }
+        /* Skip entries that are not groups */
+        DEBUG(8, ("Skipping non-group memberOf [%s]\n", member_dn));
+    }
+    users->groups[num_groups] = NULL;
 
-        users->groups[i] = talloc_strdup(users->groups,
-                                         group_name);
-        if (users->groups[i] == NULL) {
+    if (num_groups < el->num_values) {
+        /* Shrink the array memory */
+        users->groups = talloc_realloc(users, users->groups, const char *,
+                                       num_groups+1);
+        if (users->groups == NULL) {
             ret = ENOMEM;
             goto done;
         }
     }
-    users->groups[i] = NULL;
 
-    *user_element = talloc_steal(mem_ctx, users);
     ret = EOK;
 done:
+    if (ret == EOK) {
+        *user_element = talloc_steal(mem_ctx, users);
+    }
     talloc_free(tmp_ctx);
     return ret;
 }
diff --git a/src/providers/ipa/ipa_hbac_users.c b/src/providers/ipa/ipa_hbac_users.c
index a94207ca7c5da092a4dae0c1d687ee94be2d22c5..a171e9f6ebc04e0f28b8e8ab2da6a07bc39749e6 100644
--- a/src/providers/ipa/ipa_hbac_users.c
+++ b/src/providers/ipa/ipa_hbac_users.c
@@ -402,6 +402,7 @@ hbac_user_attrs_to_rule(TALLOC_CTX *mem_ctx,
     struct ldb_message **msgs = NULL;
     char *filter;
     char *member_dn;
+    const char *member_user;
     const char *attrs[] = { SYSDB_NAME, NULL };
     size_t num_users = 0;
     size_t num_groups = 0;
@@ -460,9 +461,8 @@ hbac_user_attrs_to_rule(TALLOC_CTX *mem_ctx,
     }
 
     for (i = 0; i < el->num_values; i++) {
-        ret = sss_filter_sanitize(tmp_ctx,
-                                  (const char *)el->values[i].data,
-                                  &member_dn);
+        member_user = (const char *)el->values[i].data;
+        ret = sss_filter_sanitize(tmp_ctx, member_user, &member_dn);
         if (ret != EOK) goto done;
 
         filter = talloc_asprintf(member_dn, "(%s=%s)",
@@ -535,13 +535,24 @@ hbac_user_attrs_to_rule(TALLOC_CTX *mem_ctx,
                     ret = ENOMEM;
                     goto done;
                 }
-                DEBUG(8, ("Added group [%s] to rule [%s]\n",
+                DEBUG(8, ("Added POSIX group [%s] to rule [%s]\n",
                           name, rule_name));
                 num_groups++;
             } else {
-                /* Neither a user nor a group? */
-                DEBUG(1, ("[%s] does not map to either a user or group. "
-                          "Skipping\n", member_dn));
+                /* If the group still matches the group pattern,
+                 * we can assume it is a non-POSIX group.
+                 */
+                ret = get_ipa_groupname(new_users->groups, sysdb, member_user,
+                                        &new_users->groups[num_groups]);
+                if (ret == EOK) {
+                    DEBUG(8, ("Added non-POSIX group [%s] to rule [%s]\n",
+                              name, rule_name));
+                    num_groups++;
+                } else {
+                    /* Not a group, so we don't care about it */
+                    DEBUG(1, ("[%s] does not map to either a user or group. "
+                              "Skipping\n", member_dn));
+                }
             }
         }
         talloc_zfree(member_dn);
-- 
1.7.5.4

