Blame SOURCES/0142-HBAC-Do-not-rely-on-originalMemberOf-use-the-sysdb-m.patch

bb7cd1
From c7c087b5485d50e8689d31fd9d52af935ae398be Mon Sep 17 00:00:00 2001
956cae
From: Jakub Hrozek <jhrozek@redhat.com>
956cae
Date: Sun, 9 Apr 2017 20:50:47 +0200
bb7cd1
Subject: [PATCH 142/142] HBAC: Do not rely on originalMemberOf, use the sysdb
956cae
 memberof links instead
956cae
956cae
The IPA HBAC code used to read the group members from the
956cae
originalMemberOf attribute value for performance reasons. However,
956cae
especially on IPA clients trusting an AD domain, the originalMemberOf
956cae
attribute value is often not synchronized correctly.
956cae
956cae
Instead of going through the work of maintaining both member/memberOf
956cae
and originalMemberOf, let's just do an ASQ search for the group names of
956cae
the groups the user is a member of in the cache and read their
956cae
SYSBD_NAME attribute.
956cae
956cae
To avoid clashing between similarly-named groups in IPA and in AD, we
956cae
look at the container of the group.
956cae
956cae
Resolves:
956cae
https://pagure.io/SSSD/sssd/issue/3382
956cae
956cae
Reviewed-by: Sumit Bose <sbose@redhat.com>
956cae
(cherry picked from commit c92e49144978ad3b6c9fffa8803ebdad8f6f5b18)
956cae
---
956cae
 src/providers/ipa/ipa_hbac_common.c | 97 +++++++++++++++++++++++++------------
956cae
 1 file changed, 67 insertions(+), 30 deletions(-)
956cae
956cae
diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c
956cae
index b99b75d322930f16412f6abd4cdf0d7e0b59c32c..ba677965a3eb68a54baf99b1875bca2acbb76c99 100644
956cae
--- a/src/providers/ipa/ipa_hbac_common.c
956cae
+++ b/src/providers/ipa/ipa_hbac_common.c
956cae
@@ -507,15 +507,15 @@ hbac_eval_user_element(TALLOC_CTX *mem_ctx,
956cae
                        struct hbac_request_element **user_element)
956cae
 {
956cae
     errno_t ret;
956cae
-    unsigned int i;
956cae
     unsigned int num_groups = 0;
956cae
     TALLOC_CTX *tmp_ctx;
956cae
-    const char *member_dn;
956cae
     struct hbac_request_element *users;
956cae
-    struct ldb_message *msg;
956cae
-    struct ldb_message_element *el;
956cae
-    const char *attrs[] = { SYSDB_ORIG_MEMBEROF, NULL };
956cae
     char *shortname;
956cae
+    const char *fqgroupname = NULL;
956cae
+    struct sss_domain_info *ipa_domain;
956cae
+    struct ldb_dn *ipa_groups_basedn;
956cae
+    struct ldb_result *res;
956cae
+    int exp_comp;
956cae
 
956cae
     tmp_ctx = talloc_new(mem_ctx);
956cae
     if (tmp_ctx == NULL) return ENOMEM;
956cae
@@ -533,56 +533,93 @@ hbac_eval_user_element(TALLOC_CTX *mem_ctx,
956cae
     }
956cae
     users->name = talloc_steal(users, shortname);
956cae
 
956cae
-    /* Read the originalMemberOf attribute
956cae
-     * This will give us the list of both POSIX and
956cae
-     * non-POSIX groups that this user belongs to.
956cae
+    ipa_domain = get_domains_head(domain);
956cae
+    if (ipa_domain == NULL) {
956cae
+        ret = EINVAL;
956cae
+        goto done;
956cae
+    }
956cae
+
956cae
+    ipa_groups_basedn = ldb_dn_new_fmt(tmp_ctx, sysdb_ctx_get_ldb(domain->sysdb),
956cae
+                                       SYSDB_TMPL_GROUP_BASE, ipa_domain->name);
956cae
+    if (ipa_groups_basedn == NULL) {
956cae
+        ret = ENOMEM;
956cae
+        goto done;
956cae
+    }
956cae
+
956cae
+    /* +1 because there will be a RDN preceding the base DN */
956cae
+    exp_comp = ldb_dn_get_comp_num(ipa_groups_basedn) + 1;
956cae
+
956cae
+    /*
956cae
+     * Get all the groups the user is a member of.
956cae
+     * This includes both POSIX and non-POSIX groups.
956cae
      */
956cae
-    ret = sysdb_search_user_by_name(tmp_ctx, domain, username,
956cae
-                                    attrs, &msg;;
956cae
+    ret = sysdb_initgroups(tmp_ctx, domain, username, &res;;
956cae
     if (ret != EOK) {
956cae
         DEBUG(SSSDBG_CRIT_FAILURE,
956cae
-              "Could not determine user memberships for [%s]\n",
956cae
-                  users->name);
956cae
+              "sysdb_asq_search failed [%d]: %s\n", ret, sss_strerror(ret));
956cae
         goto done;
956cae
     }
956cae
 
956cae
-    el = ldb_msg_find_element(msg, SYSDB_ORIG_MEMBEROF);
956cae
-    if (el == NULL || el->num_values == 0) {
956cae
+    if (res->count == 0) {
956cae
+        /* This should not happen at this point */
956cae
+        DEBUG(SSSDBG_MINOR_FAILURE,
956cae
+              "User [%s] not found in cache.\n", username);
956cae
+        ret = ENOENT;
956cae
+        goto done;
956cae
+    } else if (res->count == 1) {
956cae
+        /* The first item is the user entry */
956cae
         DEBUG(SSSDBG_TRACE_LIBS, "No groups for [%s]\n", users->name);
956cae
         ret = create_empty_grouplist(users);
956cae
         goto done;
956cae
     }
956cae
     DEBUG(SSSDBG_TRACE_LIBS,
956cae
-          "[%d] groups for [%s]\n", el->num_values, users->name);
956cae
+          "[%u] groups for [%s]\n", res->count - 1, username);
956cae
 
956cae
-    users->groups = talloc_array(users, const char *, el->num_values + 1);
956cae
+    /* This also includes the sentinel, b/c we'll skip the user entry below */
956cae
+    users->groups = talloc_array(users, const char *, res->count);
956cae
     if (users->groups == NULL) {
956cae
         ret = ENOMEM;
956cae
         goto done;
956cae
     }
956cae
 
956cae
-    for (i = 0; i < el->num_values; i++) {
956cae
-        member_dn = (const char *)el->values[i].data;
956cae
+    /* Start counting from 1 to exclude the user entry */
956cae
+    for (size_t i = 1; i < res->count; i++) {
956cae
+        /* Only groups from the IPA domain can be referenced from HBAC rules. To
956cae
+         * avoid evaluating groups which might even have the same name, but come
956cae
+         * from a trusted domain, we first copy the DN to a temporary one..
956cae
+         */
956cae
+        if (ldb_dn_get_comp_num(res->msgs[i]->dn) != exp_comp
956cae
+                || ldb_dn_compare_base(ipa_groups_basedn,
956cae
+                                       res->msgs[i]->dn) != 0) {
956cae
+            DEBUG(SSSDBG_FUNC_DATA,
956cae
+                  "Skipping non-IPA group %s\n",
956cae
+                  ldb_dn_get_linearized(res->msgs[i]->dn));
956cae
+            continue;
956cae
+        }
956cae
 
956cae
-        ret = get_ipa_groupname(users->groups, domain->sysdb, member_dn,
956cae
-                                &users->groups[num_groups]);
956cae
-        if (ret != EOK && ret != ERR_UNEXPECTED_ENTRY_TYPE) {
956cae
+        fqgroupname = ldb_msg_find_attr_as_string(res->msgs[i], SYSDB_NAME, NULL);
956cae
+        if (fqgroupname == NULL) {
956cae
             DEBUG(SSSDBG_MINOR_FAILURE,
956cae
-                    "Skipping malformed entry [%s]\n", member_dn);
956cae
+                  "Skipping malformed entry [%s]\n",
956cae
+                  ldb_dn_get_linearized(res->msgs[i]->dn));
956cae
             continue;
956cae
-        } else if (ret == EOK) {
956cae
-            DEBUG(SSSDBG_TRACE_LIBS, "Added group [%s] for user [%s]\n",
956cae
-                      users->groups[num_groups], users->name);
956cae
-            num_groups++;
956cae
+        }
956cae
+
956cae
+        ret = sss_parse_internal_fqname(tmp_ctx, fqgroupname,
956cae
+                                        &shortname, NULL);
956cae
+        if (ret != EOK) {
956cae
+            DEBUG(SSSDBG_MINOR_FAILURE, "Malformed name %s, skipping!\n", fqgroupname);
956cae
             continue;
956cae
         }
956cae
-        /* Skip entries that are not groups */
956cae
-        DEBUG(SSSDBG_TRACE_INTERNAL,
956cae
-              "Skipping non-group memberOf [%s]\n", member_dn);
956cae
+
956cae
+        users->groups[num_groups] = talloc_steal(users->groups, shortname);
956cae
+        DEBUG(SSSDBG_TRACE_LIBS, "Added group [%s] for user [%s]\n",
956cae
+              users->groups[num_groups], users->name);
956cae
+        num_groups++;
956cae
     }
956cae
     users->groups[num_groups] = NULL;
956cae
 
956cae
-    if (num_groups < el->num_values) {
956cae
+    if (num_groups < (res->count - 1)) {
956cae
         /* Shrink the array memory */
956cae
         users->groups = talloc_realloc(users, users->groups, const char *,
956cae
                                        num_groups+1);
956cae
-- 
956cae
2.9.4
956cae