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

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