[SSSD] [PATCHES] Make nss responder aware of views and overrides

Sumit Bose sbose at redhat.com
Tue Oct 14 15:57:36 UTC 2014


Hi,

this patches make the nss responder view aware. A number of new sysdb
calls is added as drop in replacements from existing ones. I preferred
this instead of modifying the existing ones to not break their usage in
other places. But I think they are a good targets, together with the
other user and group related sysdb calls, for a refactoring in an
upcoming version.

bye,
Sumit
-------------- next part --------------
From d38bddc59d7ff728b16fe8cf20400fe0c2f57da9 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Wed, 24 Sep 2014 13:01:20 +0200
Subject: [PATCH 01/12] confdb: add has_views and view_name to sss_domain_info

To let the responders know which view is applied and to make view
handling more efficiently especially when no view is applied/available
two new member are added to the sss_domain_info struct.

view_name is the name of the view if available. has_views is only true
if the client has a specific view applied, i.e. it is false for the case
when there are no views at all (e.g. plain LDAP provider) or the client
has the FreeIPA default view. This allows the responders to easily
bypass any view related code.
---
 src/confdb/confdb.c | 3 +++
 src/confdb/confdb.h | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
index 0adff2b..8443fe5 100644
--- a/src/confdb/confdb.c
+++ b/src/confdb/confdb.c
@@ -1205,6 +1205,9 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
         goto done;
     }
 
+    domain->has_views = false;
+    domain->view_name = NULL;
+
     *_domain = domain;
     ret = EOK;
 done:
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 720b7dc..34d4610 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -255,6 +255,9 @@ struct sss_domain_info {
     char *forest;
     struct timeval subdomains_last_checked;
 
+    bool has_views;
+    char *view_name;
+
     struct sss_domain_info *prev;
     struct sss_domain_info *next;
 
-- 
1.8.3.1

-------------- next part --------------
From b50b216e1b71d9d73628895ecbc0d4942b4a05a3 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Wed, 24 Sep 2014 13:03:53 +0200
Subject: [PATCH 02/12] new_subdomain: copy view data from parent

Since a view applies to the whole domain-subdomain tree the view data is
copied from the parent the new created domains.
---
 src/util/domain_info_utils.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
index 520feb3..a1553d8 100644
--- a/src/util/domain_info_utils.c
+++ b/src/util/domain_info_utils.c
@@ -220,6 +220,17 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
     }
 
     dom->parent = parent;
+
+    /* Sub-domains always have the same view as the parent */
+    dom->has_views = parent->has_views;
+    if (parent->view_name != NULL) {
+        dom->view_name = talloc_strdup(dom, parent->view_name);
+        if (dom->view_name == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "Failed to copy parent's view name.\n");
+            goto fail;
+        }
+    }
+
     dom->name = talloc_strdup(dom, name);
     if (dom->name == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, "Failed to copy domain name.\n");
-- 
1.8.3.1

-------------- next part --------------
From 474101f98dab1bbb9d6adc2be9178fd37779fd93 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Wed, 24 Sep 2014 13:35:29 +0200
Subject: [PATCH 03/12] sysdb: add view data to domains

The information about view is read from the cache and added to the
domain structs accordingly.
---
 src/db/sysdb_subdomains.c                | 106 +++++++++++++++++++++++++++++++
 src/tests/cmocka/test_responder_common.c |   7 ++
 2 files changed, 113 insertions(+)

diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
index e0ad22f..e32b75f 100644
--- a/src/db/sysdb_subdomains.c
+++ b/src/db/sysdb_subdomains.c
@@ -175,6 +175,35 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
                     }
                 }
 
+                if (!dom->has_views && dom->view_name == NULL) {
+                    /* maybe views are not initialized, copy from parent */
+                    dom->has_views = dom->parent->has_views;
+                    if (dom->parent->view_name != NULL) {
+                        dom->view_name = talloc_strdup(dom,
+                                                       dom->parent->view_name);
+                        if (dom->view_name == NULL) {
+                            DEBUG(SSSDBG_OP_FAILURE,
+                                  "Failed to copy parent's view name.\n");
+                            ret = ENOMEM;
+                            goto done;
+                        }
+                    }
+                } else {
+                    if (dom->has_views != dom->parent->has_views
+                            || strcmp(dom->view_name,
+                                      dom->parent->view_name) != 0) {
+                        DEBUG(SSSDBG_CRIT_FAILURE,
+                            "Sub-domain [%s][%s] and parent [%s][%s] " \
+                            "views are different.\n",
+                            dom->has_views ? "has view" : "has no view",
+                            dom->view_name,
+                            dom->parent->has_views ? "has view" : "has no view",
+                            dom->parent->view_name);
+                        ret = EINVAL;
+                        goto done;
+                    }
+                }
+
                 break;
             }
         }
@@ -210,6 +239,7 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain)
                            SYSDB_SUBDOMAIN_ID,
                            SYSDB_SUBDOMAIN_FOREST,
                            NULL};
+    char *view_name = NULL;
 
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) {
@@ -292,6 +322,82 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain)
         }
     }
 
+    ret = sysdb_get_view_name(tmp_ctx, domain->sysdb, &view_name);
+    if (ret != EOK && ret != ENOENT) {
+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_view_name failed.\n");
+        goto done;
+    }
+
+    if (ret == ENOENT || view_name == NULL
+            || (view_name != NULL
+                && strcmp(view_name, SYSDB_DEFAULT_VIEW_NAME) == 0)) {
+        /* handle default view */
+        if (domain->has_views) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "View name change is currently not supported. " \
+                  "New view is the default view while current view is [%s]. " \
+                  "View name is not changed!\n", domain->view_name);
+        } else {
+            if (domain->view_name == NULL) {
+                domain->view_name = talloc_strdup(domain,
+                                                  SYSDB_DEFAULT_VIEW_NAME);
+                if (domain->view_name == NULL) {
+                    DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+                    ret = ENOMEM;
+                    goto done;
+                }
+            } else {
+                if (strcmp(domain->view_name, SYSDB_DEFAULT_VIEW_NAME) != 0) {
+                    DEBUG(SSSDBG_CRIT_FAILURE,
+                          "Domain [%s] has no view but view name [%s] " \
+                          "is not the default view name [%s].\n",
+                          domain->name, domain->view_name,
+                          SYSDB_DEFAULT_VIEW_NAME);
+                    ret = EINVAL;
+                    goto done;
+                }
+            }
+        }
+    } else {
+        /* handle view other than default */
+        if (domain->has_views) {
+            if (strcmp(domain->view_name, view_name) != 0) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      "View name change is currently not supported. " \
+                      "New view is [%s] while current view is [%s]. " \
+                      "View name is not changed!\n",
+                      view_name, domain->view_name);
+            }
+        } else {
+            if (domain->view_name == NULL) {
+                domain->has_views = true;
+                domain->view_name = talloc_steal(domain, view_name);
+                if (domain->view_name == NULL) {
+                    DEBUG(SSSDBG_OP_FAILURE, "talloc_steal failed.\n");
+                    ret = ENOMEM;
+                    goto done;
+                }
+            } else {
+                if (strcmp(domain->view_name, SYSDB_DEFAULT_VIEW_NAME) == 0) {
+                    DEBUG(SSSDBG_CRIT_FAILURE,
+                        "View name change is currently not supported. " \
+                        "New view is [%s] while current is the default view. " \
+                        "View name is not changed!\n", view_name);
+                } else {
+                    DEBUG(SSSDBG_CRIT_FAILURE,
+                          "Domain currently has no views, " \
+                          "but current view name is set to [%s] " \
+                          "and new view name is [%s].\n",
+                          domain->view_name, view_name);
+                    ret = EINVAL;
+                    goto done;
+                }
+            }
+        }
+    }
+
+    ret = EOK;
+
 done:
     talloc_free(tmp_ctx);
     return ret;
diff --git a/src/tests/cmocka/test_responder_common.c b/src/tests/cmocka/test_responder_common.c
index 7743760..a6f642a 100644
--- a/src/tests/cmocka/test_responder_common.c
+++ b/src/tests/cmocka/test_responder_common.c
@@ -87,6 +87,7 @@ struct parse_inp_test_ctx {
 void parse_inp_test_setup(void **state)
 {
     struct parse_inp_test_ctx *parse_inp_ctx;
+    int ret;
 
     assert_true(leak_check_setup());
     parse_inp_ctx = talloc_zero(global_talloc_context, struct parse_inp_test_ctx);
@@ -106,6 +107,12 @@ void parse_inp_test_setup(void **state)
     /* Testing the request race condition should be a special case */
     gettimeofday(&parse_inp_ctx->rctx->get_domains_last_call, NULL);
 
+    /* sysdb_master_domain_update sets the view name, if we do not call it
+     * here we get a leak check warning when sysdb_master_domain_update is
+     * called later while processing the tests. */
+    ret = sysdb_master_domain_update(parse_inp_ctx->tctx->dom);
+    assert_int_equal(ret, EOK);
+
     check_leaks_push(parse_inp_ctx);
     *state = parse_inp_ctx;
 }
-- 
1.8.3.1

-------------- next part --------------
From 2bd70969ee5a0460d14e71bb3337c20a7da9335b Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Thu, 25 Sep 2014 09:36:51 +0200
Subject: [PATCH 04/12] sysdb: add overide lookup calls

sysdb_search_user_override_by_name() and
sysdb_search_group_override_by_name() search for overrides in the given
view.

sysdb_add_overrides_to_object() adds the data from the override object
to the original object and makes them available for further processing.
---
 src/db/sysdb.h       |  24 ++++-
 src/db/sysdb_views.c | 286 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/util/util.h      |   3 +
 3 files changed, 312 insertions(+), 1 deletion(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 6bb25de..8d4759e 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -43,6 +43,7 @@
 #define SYSDB_TMPL_NETGROUP_BASE SYSDB_NETGROUP_CONTAINER","SYSDB_DOM_BASE
 #define SYSDB_TMPL_RANGE_BASE SYSDB_RANGE_CONTAINER","SYSDB_BASE
 #define SYSDB_TMPL_VIEW_BASE SYSDB_VIEW_CONTAINER","SYSDB_BASE
+#define SYSDB_TMPL_VIEW_SEARCH_BASE "cn=%s,"SYSDB_TMPL_VIEW_BASE
 
 #define SYSDB_SUBDOMAIN_CLASS "subdomain"
 #define SYSDB_USER_CLASS "user"
@@ -199,12 +200,17 @@
                         SYSDB_PRIMARY_GROUP_GIDNUM, \
                         SYSDB_SID_STR, \
                         SYSDB_UPN, \
+                        SYSDB_OVERRIDE_DN, \
+                        SYSDB_DEFAULT_OVERRIDE_NAME, \
                         NULL}
 
 #define SYSDB_GRSRC_ATTRS {SYSDB_NAME, SYSDB_GIDNUM, \
                            SYSDB_MEMBERUID, \
                            SYSDB_GHOST, \
                            SYSDB_DEFAULT_ATTRS, \
+                           SYSDB_SID_STR, \
+                           SYSDB_OVERRIDE_DN, \
+                           SYSDB_DEFAULT_OVERRIDE_NAME, \
                            NULL}
 
 #define SYSDB_NETGR_ATTRS {SYSDB_NAME, SYSDB_NETGROUP_TRIPLE, \
@@ -226,7 +232,7 @@
 #define SYSDB_TMPL_CUSTOM_SUBTREE "cn=%s,"SYSDB_TMPL_CUSTOM_BASE
 #define SYSDB_TMPL_CUSTOM SYSDB_NAME"=%s,cn=%s,"SYSDB_TMPL_CUSTOM_BASE
 #define SYSDB_TMPL_RANGE SYSDB_NAME"=%s,"SYSDB_TMPL_RANGE_BASE
-#define SYSDB_TMPL_OVERRIDE SYSDB_OVERRIDE_ANCHOR_UUID"=%s,cn=%s,"SYSDB_TMPL_VIEW_BASE
+#define SYSDB_TMPL_OVERRIDE SYSDB_OVERRIDE_ANCHOR_UUID"=%s,"SYSDB_TMPL_VIEW_SEARCH_BASE
 
 #define SYSDB_MOD_ADD LDB_FLAG_MOD_ADD
 #define SYSDB_MOD_DEL LDB_FLAG_MOD_DELETE
@@ -438,6 +444,22 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain,
                                      struct sysdb_attrs *override_attrs,
                                      struct ldb_dn *obj_dn);
 
+errno_t sysdb_search_user_override_by_name(TALLOC_CTX *mem_ctx,
+                                           struct sss_domain_info *domain,
+                                           const char *name,
+                                           struct ldb_result **override_obj,
+                                           struct ldb_result **orig_obj);
+
+errno_t sysdb_search_group_override_by_name(TALLOC_CTX *mem_ctx,
+                                            struct sss_domain_info *domain,
+                                            const char *name,
+                                            struct ldb_result **override_obj,
+                                            struct ldb_result **orig_obj);
+
+errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
+                                      struct ldb_message *obj,
+                                      struct ldb_message *override_obj);
+
 /* Sysdb initialization.
  * call this function *only* once to initialize the database and get
  * the sysdb ctx */
diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
index 97c04af..72aa3e2 100644
--- a/src/db/sysdb_views.c
+++ b/src/db/sysdb_views.c
@@ -371,6 +371,7 @@ errno_t sysdb_store_override(struct sss_domain_info *domain,
             goto done;
         }
 
+        /* TODO: add nameAlias for case-insentitive searches */
         for (c = 0; c < attrs->num; c++) {
             msg->elements[c] = attrs->a[c];
             msg->elements[c].flags = LDB_FLAG_MOD_ADD;
@@ -583,6 +584,7 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain,
     }
 
     for (c = 0; allowed_attrs[c] != NULL; c++) {
+        /* TODO: add nameAlias for case-insentitive searches */
         ret = sysdb_attrs_get_el_ext(override_attrs, allowed_attrs[c], false,
                                      &el);
         if (ret == EOK) {
@@ -643,3 +645,287 @@ done:
     talloc_free(tmp_ctx);
     return ret;
 }
+
+
+#define SYSDB_USER_NAME_OVERRIDE_FILTER "(&(objectClass="SYSDB_OVERRIDE_USER_CLASS")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
+#define SYSDB_GROUP_NAME_OVERRIDE_FILTER "(&(objectClass="SYSDB_OVERRIDE_GROUP_CLASS")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
+
+enum override_object_type {
+    OO_TYPE_UNDEF = 0,
+    OO_TYPE_USER,
+    OO_TYPE_GROUP
+};
+
+static errno_t sysdb_search_override_by_name(TALLOC_CTX *mem_ctx,
+                                             struct sss_domain_info *domain,
+                                             const char *name,
+                                             enum override_object_type type,
+                                             struct ldb_result **override_obj,
+                                             struct ldb_result **orig_obj)
+{
+    TALLOC_CTX *tmp_ctx;
+    static const char *user_attrs[] = SYSDB_PW_ATTRS;
+    static const char *group_attrs[] = SYSDB_GRSRC_ATTRS;
+    const char **attrs;
+    struct ldb_dn *base_dn;
+    struct ldb_result *override_res;
+    struct ldb_result *orig_res;
+    char *sanitized_name;
+    char *lc_sanitized_name;
+    const char *src_name;
+    int ret;
+    const char *orig_obj_dn;
+    const char *filter;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
+                             SYSDB_TMPL_VIEW_SEARCH_BASE, domain->view_name);
+    if (base_dn == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new_fmt failed.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    /* If this is a subdomain we need to use fully qualified names for the
+     * search as well by default */
+    src_name = sss_get_domain_name(tmp_ctx, name, domain);
+    if (src_name == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "sss_get_domain_name failed.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = sss_filter_sanitize_for_dom(tmp_ctx, src_name, domain,
+                                      &sanitized_name, &lc_sanitized_name);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "sss_filter_sanitize_for_dom failed.\n");
+        goto done;
+    }
+
+    switch(type) {
+    case OO_TYPE_USER:
+        filter = SYSDB_USER_NAME_OVERRIDE_FILTER;
+        attrs = user_attrs;
+        break;
+    case OO_TYPE_GROUP:
+        filter = SYSDB_GROUP_NAME_OVERRIDE_FILTER;
+        attrs = group_attrs;
+        break;
+    default:
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected override object type [%d].\n",
+                                   type);
+        ret = EINVAL;
+        goto done;
+    }
+
+    ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &override_res, base_dn,
+                     LDB_SCOPE_SUBTREE, attrs, filter,
+                     lc_sanitized_name,
+                     sanitized_name, sanitized_name);
+    if (ret != LDB_SUCCESS) {
+        ret = sysdb_error_to_errno(ret);
+        goto done;
+    }
+
+    if (override_res->count == 0) {
+        DEBUG(SSSDBG_TRACE_FUNC, "No user override found for name [%s].\n",
+                                 name);
+        ret = ENOENT;
+        goto done;
+    } else if (override_res->count > 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Found more than one override for name [%s]\n.", name);
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (orig_obj != NULL) {
+        orig_obj_dn = ldb_msg_find_attr_as_string(override_res->msgs[0],
+                                                  SYSDB_OVERRIDE_OBJECT_DN,
+                                                  NULL);
+        if (orig_obj_dn == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Missing link to original object in override [%s].\n",
+                  ldb_dn_get_linearized(override_res->msgs[0]->dn));
+            ret = EINVAL;
+            goto done;
+        }
+
+        base_dn = ldb_dn_new(tmp_ctx, domain->sysdb->ldb, orig_obj_dn);
+        if (base_dn == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+
+        ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &orig_res, base_dn,
+                         LDB_SCOPE_BASE, attrs, NULL);
+        if (ret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+
+        *orig_obj = talloc_steal(mem_ctx, orig_res);
+    }
+
+
+    *override_obj = talloc_steal(mem_ctx, override_res);
+
+    ret = EOK;
+
+done:
+    talloc_zfree(tmp_ctx);
+    return ret;
+}
+
+errno_t sysdb_search_user_override_by_name(TALLOC_CTX *mem_ctx,
+                                           struct sss_domain_info *domain,
+                                           const char *name,
+                                           struct ldb_result **override_obj,
+                                           struct ldb_result **orig_obj)
+{
+    return sysdb_search_override_by_name(mem_ctx, domain, name, OO_TYPE_USER,
+                                         override_obj, orig_obj);
+}
+
+errno_t sysdb_search_group_override_by_name(TALLOC_CTX *mem_ctx,
+                                            struct sss_domain_info *domain,
+                                            const char *name,
+                                            struct ldb_result **override_obj,
+                                            struct ldb_result **orig_obj)
+{
+    return sysdb_search_override_by_name(mem_ctx, domain, name, OO_TYPE_GROUP,
+                                         override_obj, orig_obj);
+}
+
+/**
+ * @brief Add override data to the original object
+ *
+ * @param[in] domain Domain struct, needed to access the cache
+ * @oaram[in] obj The original object
+ * @param[in] override_obj The object with the override data, may be NULL
+ *
+ * @return EOK - Override data was added successfully
+ * @return ENOMEM - There was insufficient memory to complete the operation
+ * @return ENOENT - The original object did not have the SYSDB_OVERRIDE_DN
+ *                  attribute or the value of the attribute points an object
+ *                  which does not exists. Both conditions indicate that the
+ *                  cache must be refreshed.
+ */
+errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
+                                      struct ldb_message *obj,
+                                      struct ldb_message *override_obj)
+{
+    int ret;
+    const char *override_dn_str;
+    struct ldb_dn *override_dn;
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_result *res;
+    struct ldb_message *override;
+    uint64_t uid;
+    static const char *user_attrs[] = SYSDB_PW_ATTRS;
+    static const char *group_attrs[] = SYSDB_GRSRC_ATTRS;
+    const char **attrs;
+    struct attr_map {
+        const char *attr;
+        const char *new_attr;
+    } attr_map[] = {
+        {SYSDB_UIDNUM, OVERRIDE_PREFIX SYSDB_UIDNUM},
+        {SYSDB_GIDNUM, OVERRIDE_PREFIX SYSDB_GIDNUM},
+        {SYSDB_GECOS, OVERRIDE_PREFIX SYSDB_GECOS},
+        {SYSDB_HOMEDIR, OVERRIDE_PREFIX SYSDB_HOMEDIR},
+        {SYSDB_SHELL, OVERRIDE_PREFIX SYSDB_SHELL},
+        {SYSDB_NAME, OVERRIDE_PREFIX SYSDB_NAME},
+        {NULL, NULL}
+    };
+    size_t c;
+    const char *tmp_str;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+        return ENOMEM;
+    }
+
+    if (override_obj == NULL) {
+        override_dn_str = ldb_msg_find_attr_as_string(obj,
+                                                      SYSDB_OVERRIDE_DN, NULL);
+        if (override_dn_str == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Missing override DN for objext [%s].\n",
+                  ldb_dn_get_linearized(obj->dn));
+            ret = ENOENT;
+            goto done;
+        }
+
+        override_dn = ldb_dn_new(tmp_ctx, domain->sysdb->ldb, override_dn_str);
+        if (override_dn == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+
+        if (ldb_dn_compare(obj->dn, override_dn) == 0) {
+            DEBUG(SSSDBG_TRACE_ALL, "Object [%s] has no overrides.\n",
+                                    ldb_dn_get_linearized(obj->dn));
+            ret = EOK;
+            goto done;
+        }
+
+        uid = ldb_msg_find_attr_as_uint64(obj, SYSDB_UIDNUM, 0);
+        if (uid == 0) {
+            /* No UID hence group object */
+            attrs = group_attrs;
+        } else {
+            attrs = user_attrs;
+        }
+
+        ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, override_dn,
+                         LDB_SCOPE_BASE, attrs, NULL);
+        if (ret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+
+        if (res->count == 1) {
+            override = res->msgs[0];
+        } else if (res->count == 0) {
+            DEBUG(SSSDBG_TRACE_FUNC, "Override object [%s] does not exists.\n",
+                                     override_dn_str);
+            ret = ENOENT;
+            goto done;
+        } else {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Base search for override object returned [%d] results.\n",
+                  res->count);
+            ret = EINVAL;
+            goto done;
+        }
+    } else {
+        override = override_obj;
+    }
+
+    for (c = 0; attr_map[c].attr != NULL; c++) {
+        tmp_str = ldb_msg_find_attr_as_string(override, attr_map[c].attr, NULL);
+        if (tmp_str != NULL) {
+            talloc_steal(obj, tmp_str);
+            ret = ldb_msg_add_string(obj, attr_map[c].new_attr, tmp_str);
+            if (ret != LDB_SUCCESS) {
+                DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_string failed.\n");
+                ret = sysdb_error_to_errno(ret);
+                goto done;
+            }
+        }
+    }
+
+    ret = EOK;
+done:
+    talloc_free(tmp_ctx);
+
+    return ret;
+}
+
diff --git a/src/util/util.h b/src/util/util.h
index c497f60..4ba8045 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -546,6 +546,9 @@ errno_t sssd_domain_init(TALLOC_CTX *mem_ctx,
 
 #define IS_SUBDOMAIN(dom) ((dom)->parent != NULL)
 
+/* Currently views are only supported for subdomains */
+#define DOM_HAS_VIEWS(dom) ((dom)->has_views && IS_SUBDOMAIN(dom))
+
 errno_t sss_write_domain_mappings(struct sss_domain_info *domain,
                                   bool add_capaths);
 
-- 
1.8.3.1

-------------- next part --------------
From f442357df86ea36e2f4b69068be88c939f66cd98 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Thu, 25 Sep 2014 09:38:26 +0200
Subject: [PATCH 05/12] sysdb: add sysdb_getpwnam/uid_with_views()

View-aware drop-in replacements for sysdb_getpwnam() and
sysdb_getpwuid().
---
 src/db/sysdb.h        |  24 +++++++++
 src/db/sysdb_search.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/db/sysdb_views.c  | 128 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 290 insertions(+)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 8d4759e..2db1a1c 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -201,6 +201,7 @@
                         SYSDB_SID_STR, \
                         SYSDB_UPN, \
                         SYSDB_OVERRIDE_DN, \
+                        SYSDB_OVERRIDE_OBJECT_DN, \
                         SYSDB_DEFAULT_OVERRIDE_NAME, \
                         NULL}
 
@@ -210,6 +211,7 @@
                            SYSDB_DEFAULT_ATTRS, \
                            SYSDB_SID_STR, \
                            SYSDB_OVERRIDE_DN, \
+                           SYSDB_OVERRIDE_OBJECT_DN, \
                            SYSDB_DEFAULT_OVERRIDE_NAME, \
                            NULL}
 
@@ -456,10 +458,32 @@ errno_t sysdb_search_group_override_by_name(TALLOC_CTX *mem_ctx,
                                             struct ldb_result **override_obj,
                                             struct ldb_result **orig_obj);
 
+errno_t sysdb_search_user_override_by_uid(TALLOC_CTX *mem_ctx,
+                                          struct sss_domain_info *domain,
+                                          uid_t uid,
+                                           struct ldb_result **override_obj,
+                                           struct ldb_result **orig_obj);
+
+errno_t sysdb_search_group_override_by_gid(TALLOC_CTX *mem_ctx,
+                                            struct sss_domain_info *domain,
+                                            gid_t gid,
+                                            struct ldb_result **override_obj,
+                                            struct ldb_result **orig_obj);
+
 errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
                                       struct ldb_message *obj,
                                       struct ldb_message *override_obj);
 
+errno_t sysdb_getpwnam_with_views(TALLOC_CTX *mem_ctx,
+                                  struct sss_domain_info *domain,
+                                  const char *name,
+                                  struct ldb_result **res);
+
+errno_t sysdb_getpwuid_with_views(TALLOC_CTX *mem_ctx,
+                                  struct sss_domain_info *domain,
+                                  uid_t uid,
+                                  struct ldb_result **res);
+
 /* Sysdb initialization.
  * call this function *only* once to initialize the database and get
  * the sysdb ctx */
diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
index d51d213..4329a8b 100644
--- a/src/db/sysdb_search.c
+++ b/src/db/sysdb_search.c
@@ -83,6 +83,75 @@ done:
     return ret;
 }
 
+errno_t sysdb_getpwnam_with_views(TALLOC_CTX *mem_ctx,
+                                  struct sss_domain_info *domain,
+                                  const char *name,
+                                  struct ldb_result **res)
+{
+    int ret;
+    struct ldb_result *orig_obj = NULL;
+    struct ldb_result *override_obj = NULL;
+    TALLOC_CTX *tmp_ctx;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+        return ENOMEM;
+    }
+
+    /* If there are views we first have to search the overrides for matches */
+    if (DOM_HAS_VIEWS(domain)) {
+        ret = sysdb_search_user_override_by_name(tmp_ctx, domain, name,
+                                                 &override_obj, &orig_obj);
+        if (ret != EOK && ret != ENOENT) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "sysdb_search_override_by_name failed.\n");
+            return ret;
+        }
+    }
+
+    /* If there are no views or nothing was found in the overrides the
+     * original objects are searched. */
+    if (orig_obj == NULL) {
+        ret = sysdb_getpwnam(tmp_ctx, domain, name, &orig_obj);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_getpwnam failed.\n");
+            return ret;
+        }
+    }
+
+    /* If there are views we have to check if override values must be added to
+     * the original object. */
+    if (DOM_HAS_VIEWS(domain) && orig_obj->count == 1) {
+        ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0],
+                          override_obj == NULL ? NULL : override_obj ->msgs[0]);
+        if (ret != EOK && ret != ENOENT) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
+            return ret;
+        }
+
+        if (ret == ENOENT) {
+            *res = talloc_zero(mem_ctx, struct ldb_result);
+            if (*res == NULL) {
+                DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
+                ret = ENOMEM;
+            } else {
+                ret = EOK;
+            }
+            goto done;
+        }
+    }
+
+    *res = talloc_steal(mem_ctx, orig_obj);
+    ret = EOK;
+    /* TODO: check if EOK is returned even if orig_obj is empty, i.e nothgin
+     * found. */
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
 int sysdb_getpwuid(TALLOC_CTX *mem_ctx,
                    struct sss_domain_info *domain,
                    uid_t uid,
@@ -121,6 +190,75 @@ done:
     return ret;
 }
 
+errno_t sysdb_getpwuid_with_views(TALLOC_CTX *mem_ctx,
+                                  struct sss_domain_info *domain,
+                                  uid_t uid,
+                                  struct ldb_result **res)
+{
+    int ret;
+    struct ldb_result *orig_obj = NULL;
+    struct ldb_result *override_obj = NULL;
+    TALLOC_CTX *tmp_ctx;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+        return ENOMEM;
+    }
+
+    /* If there are views we first have to search the overrides for matches */
+    if (DOM_HAS_VIEWS(domain)) {
+        ret = sysdb_search_user_override_by_uid(tmp_ctx, domain, uid,
+                                                &override_obj, &orig_obj);
+        if (ret != EOK && ret != ENOENT) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "sysdb_search_user_override_by_uid failed.\n");
+            return ret;
+        }
+    }
+
+    /* If there are no views or nothing was found in the overrides the
+     * original objects are searched. */
+    if (orig_obj == NULL) {
+        ret = sysdb_getpwuid(tmp_ctx, domain, uid, &orig_obj);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_getpwuid failed.\n");
+            return ret;
+        }
+    }
+
+    /* If there are views we have to check if override values must be added to
+     * the original object. */
+    if (DOM_HAS_VIEWS(domain) && orig_obj->count == 1) {
+        ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0],
+                           override_obj == NULL ? NULL : override_obj->msgs[0]);
+        if (ret != EOK && ret != ENOENT) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
+            return ret;
+        }
+
+        if (ret == ENOENT) {
+            *res = talloc_zero(mem_ctx, struct ldb_result);
+            if (*res == NULL) {
+                DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
+                ret = ENOMEM;
+            } else {
+                ret = EOK;
+            }
+            goto done;
+        }
+    }
+
+    *res = talloc_steal(mem_ctx, orig_obj);
+    ret = EOK;
+    /* TODO: check if EOK is returned even if orig_obj is empty, i.e nothing
+     * found. */
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
 int sysdb_enumpwent(TALLOC_CTX *mem_ctx,
                     struct sss_domain_info *domain,
                     struct ldb_result **_res)
diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
index 72aa3e2..f182391 100644
--- a/src/db/sysdb_views.c
+++ b/src/db/sysdb_views.c
@@ -648,7 +648,9 @@ done:
 
 
 #define SYSDB_USER_NAME_OVERRIDE_FILTER "(&(objectClass="SYSDB_OVERRIDE_USER_CLASS")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
+#define SYSDB_USER_UID_OVERRIDE_FILTER "(&(objectClass="SYSDB_OVERRIDE_USER_CLASS")("SYSDB_UIDNUM"=%lu))"
 #define SYSDB_GROUP_NAME_OVERRIDE_FILTER "(&(objectClass="SYSDB_OVERRIDE_GROUP_CLASS")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
+#define SYSDB_GROUP_GID_OVERRIDE_FILTER "(&(objectClass="SYSDB_OVERRIDE_GROUP_CLASS")("SYSDB_GIDNUM"=%lu))"
 
 enum override_object_type {
     OO_TYPE_UNDEF = 0,
@@ -802,6 +804,132 @@ errno_t sysdb_search_group_override_by_name(TALLOC_CTX *mem_ctx,
                                          override_obj, orig_obj);
 }
 
+static errno_t sysdb_search_override_by_id(TALLOC_CTX *mem_ctx,
+                                           struct sss_domain_info *domain,
+                                           unsigned long int id,
+                                           enum override_object_type type,
+                                           struct ldb_result **override_obj,
+                                           struct ldb_result **orig_obj)
+{
+    TALLOC_CTX *tmp_ctx;
+    static const char *user_attrs[] = SYSDB_PW_ATTRS;
+    static const char *group_attrs[] = SYSDB_GRSRC_ATTRS;
+    const char **attrs;
+    struct ldb_dn *base_dn;
+    struct ldb_result *override_res;
+    struct ldb_result *orig_res;
+    int ret;
+    const char *orig_obj_dn;
+    const char *filter;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
+                             SYSDB_TMPL_VIEW_SEARCH_BASE, domain->view_name);
+    if (base_dn == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new_fmt failed.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    switch(type) {
+    case OO_TYPE_USER:
+        filter = SYSDB_USER_UID_OVERRIDE_FILTER;
+        attrs = user_attrs;
+        break;
+    case OO_TYPE_GROUP:
+        filter = SYSDB_GROUP_GID_OVERRIDE_FILTER;
+        attrs = group_attrs;
+        break;
+    default:
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected override object type [%d].\n",
+                                   type);
+        ret = EINVAL;
+        goto done;
+    }
+
+    ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &override_res, base_dn,
+                     LDB_SCOPE_SUBTREE, attrs, filter, id);
+    if (ret != LDB_SUCCESS) {
+        ret = sysdb_error_to_errno(ret);
+        goto done;
+    }
+
+    if (override_res->count == 0) {
+        DEBUG(SSSDBG_TRACE_FUNC,
+              "No user override found for %s with id [%lu].\n",
+              (type == OO_TYPE_USER ? "user" : "group"), id);
+        ret = ENOENT;
+        goto done;
+    } else if (override_res->count > 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Found more than one override for id [%lu]\n.", id);
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (orig_obj != NULL) {
+        orig_obj_dn = ldb_msg_find_attr_as_string(override_res->msgs[0],
+                                                  SYSDB_OVERRIDE_OBJECT_DN,
+                                                  NULL);
+        if (orig_obj_dn == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Missing link to original object in override [%s].\n",
+                  ldb_dn_get_linearized(override_res->msgs[0]->dn));
+            ret = EINVAL;
+            goto done;
+        }
+
+        base_dn = ldb_dn_new(tmp_ctx, domain->sysdb->ldb, orig_obj_dn);
+        if (base_dn == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+
+        ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &orig_res, base_dn,
+                         LDB_SCOPE_BASE, attrs, NULL);
+        if (ret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+
+        *orig_obj = talloc_steal(mem_ctx, orig_res);
+    }
+
+
+    *override_obj = talloc_steal(mem_ctx, override_res);
+
+    ret = EOK;
+
+done:
+    talloc_zfree(tmp_ctx);
+    return ret;
+}
+
+errno_t sysdb_search_user_override_by_uid(TALLOC_CTX *mem_ctx,
+                                          struct sss_domain_info *domain,
+                                          uid_t uid,
+                                           struct ldb_result **override_obj,
+                                           struct ldb_result **orig_obj)
+{
+    return sysdb_search_override_by_id(mem_ctx, domain, uid, OO_TYPE_USER,
+                                       override_obj, orig_obj);
+}
+
+errno_t sysdb_search_group_override_by_gid(TALLOC_CTX *mem_ctx,
+                                            struct sss_domain_info *domain,
+                                            gid_t gid,
+                                            struct ldb_result **override_obj,
+                                            struct ldb_result **orig_obj)
+{
+    return sysdb_search_override_by_id(mem_ctx, domain, gid, OO_TYPE_GROUP,
+                                       override_obj, orig_obj);
+}
+
 /**
  * @brief Add override data to the original object
  *
-- 
1.8.3.1

-------------- next part --------------
From 32a3d248aee2f5355e57440e382916b4aa389eb8 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Fri, 26 Sep 2014 20:09:25 +0200
Subject: [PATCH 06/12] sysdb: add
 sss_view_ldb_msg_find_element/attr_as_string/uint64

Override-aware replacements for the corresponding ldb_msg_find_* calls.
First it is check if an override value is available before the original
value is returned.
---
 src/db/sysdb.h       |  15 +++++++
 src/db/sysdb_views.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 131 insertions(+)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 2db1a1c..8d2894a 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -484,6 +484,21 @@ errno_t sysdb_getpwuid_with_views(TALLOC_CTX *mem_ctx,
                                   uid_t uid,
                                   struct ldb_result **res);
 
+struct ldb_message_element *
+sss_view_ldb_msg_find_element(struct sss_domain_info *dom,
+                              const struct ldb_message *msg,
+                              const char *attr_name);
+
+const char *sss_view_ldb_msg_find_attr_as_string(struct sss_domain_info *dom,
+                                                 const struct ldb_message *msg,
+                                                 const char *attr_name,
+                                                 const char * default_value);
+
+uint64_t sss_view_ldb_msg_find_attr_as_uint64(struct sss_domain_info *dom,
+                                              const struct ldb_message *msg,
+                                              const char *attr_name,
+                                              uint64_t default_value);
+
 /* Sysdb initialization.
  * call this function *only* once to initialize the database and get
  * the sysdb ctx */
diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
index f182391..d778f9d 100644
--- a/src/db/sysdb_views.c
+++ b/src/db/sysdb_views.c
@@ -1057,3 +1057,119 @@ done:
     return ret;
 }
 
+struct ldb_message_element *
+sss_view_ldb_msg_find_element(struct sss_domain_info *dom,
+                                              const struct ldb_message *msg,
+                                              const char *attr_name)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    struct ldb_message_element *val;
+    char *override_attr_name;
+
+    if (DOM_HAS_VIEWS(dom)) {
+        tmp_ctx = talloc_new(NULL);
+        if (tmp_ctx == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+            val = NULL;
+            goto done;
+        }
+
+        override_attr_name = talloc_asprintf(tmp_ctx, "%s%s", OVERRIDE_PREFIX,
+                                                              attr_name);
+        if (override_attr_name == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+            val = NULL;
+            goto done;
+        }
+
+        val = ldb_msg_find_element(msg, override_attr_name);
+        if (val != NULL) {
+            goto done;
+        }
+    }
+
+    val = ldb_msg_find_element(msg, attr_name);
+
+done:
+    talloc_free(tmp_ctx);
+    return val;
+}
+
+uint64_t sss_view_ldb_msg_find_attr_as_uint64(struct sss_domain_info *dom,
+                                              const struct ldb_message *msg,
+                                              const char *attr_name,
+                                              uint64_t default_value)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    uint64_t val;
+    char *override_attr_name;
+
+    if (DOM_HAS_VIEWS(dom)) {
+        tmp_ctx = talloc_new(NULL);
+        if (tmp_ctx == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+            val = default_value;
+            goto done;
+        }
+
+        override_attr_name = talloc_asprintf(tmp_ctx, "%s%s", OVERRIDE_PREFIX,
+                                                              attr_name);
+        if (override_attr_name == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+            val = default_value;
+            goto done;
+        }
+
+        if (ldb_msg_find_element(msg, override_attr_name) != NULL) {
+            val = ldb_msg_find_attr_as_uint64(msg, override_attr_name,
+                                              default_value);
+            goto done;
+        }
+    }
+
+    val = ldb_msg_find_attr_as_uint64(msg, attr_name, default_value);
+
+done:
+    talloc_free(tmp_ctx);
+    return val;
+}
+
+const char *sss_view_ldb_msg_find_attr_as_string(struct sss_domain_info *dom,
+                                                 const struct ldb_message *msg,
+                                                 const char *attr_name,
+                                                 const char * default_value)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    const char *val;
+    char *override_attr_name;
+
+    if (DOM_HAS_VIEWS(dom)) {
+        tmp_ctx = talloc_new(NULL);
+        if (tmp_ctx == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+            val = default_value;
+            goto done;
+        }
+
+        override_attr_name = talloc_asprintf(tmp_ctx, "%s%s", OVERRIDE_PREFIX,
+                                                              attr_name);
+        if (override_attr_name == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+            val = default_value;
+            goto done;
+        }
+
+        if (ldb_msg_find_element(msg, override_attr_name) != NULL) {
+            val = ldb_msg_find_attr_as_string(msg, override_attr_name,
+                                              default_value);
+            goto done;
+        }
+    }
+
+    val = ldb_msg_find_attr_as_string(msg, attr_name, default_value);
+
+done:
+    talloc_free(tmp_ctx);
+    return val;
+}
+
-- 
1.8.3.1

-------------- next part --------------
From 7a041f6543c0ff50644813f984649af75e62cd65 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Thu, 25 Sep 2014 09:38:44 +0200
Subject: [PATCH 07/12] nss: add view support for getpwnam/getpwuid requests

For user lookups view and override aware calls to search the cache and
read attribute values are used.

Relates to https://fedorahosted.org/sssd/ticket/2375
---
 src/responder/nss/nsssrv_cmd.c | 128 ++++++++++++++++++++++++++++++-----------
 1 file changed, 95 insertions(+), 33 deletions(-)

diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 78ef1c5..7ac78a0 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -339,9 +339,50 @@ static int fill_pwent(struct sss_packet *packet,
         msg = msgs[i];
 
         upn = ldb_msg_find_attr_as_string(msg, SYSDB_UPN, NULL);
-        orig_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
-        uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);
-        gid = get_gid_override(msg, dom);
+
+        if (DOM_HAS_VIEWS(dom)) {
+            orig_name = ldb_msg_find_attr_as_string(msg,
+                                                    OVERRIDE_PREFIX SYSDB_NAME,
+                                                    NULL);
+            uid = ldb_msg_find_attr_as_uint64(msg,
+                                              OVERRIDE_PREFIX SYSDB_UIDNUM, 0);
+            gid = ldb_msg_find_attr_as_uint64(msg,
+                                              OVERRIDE_PREFIX SYSDB_GIDNUM, 0);
+            tmpstr = ldb_msg_find_attr_as_string(msg,
+                                                OVERRIDE_PREFIX SYSDB_GECOS,
+                                                NULL);
+            to_sized_string(&gecos, tmpstr);
+            tmpstr = ldb_msg_find_attr_as_string(msg,
+                                                  OVERRIDE_PREFIX SYSDB_HOMEDIR,
+                                                  NULL);
+            to_sized_string(&homedir, tmpstr);
+            tmpstr = ldb_msg_find_attr_as_string(msg,
+                                                    OVERRIDE_PREFIX SYSDB_SHELL,
+                                                    NULL);
+            to_sized_string(&shell, tmpstr);
+        } else {
+            orig_name = NULL;
+            uid = 0;
+            gid = 0;
+            ZERO_STRUCT(gecos);
+            ZERO_STRUCT(homedir);
+            ZERO_STRUCT(shell);
+        }
+
+        if (orig_name == NULL) {
+            orig_name = ldb_msg_find_attr_as_string(msg,
+                                                    SYSDB_DEFAULT_OVERRIDE_NAME,
+                                                    NULL);
+            if (orig_name == NULL) {
+                orig_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+            }
+        }
+        if (uid == 0) {
+            uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);
+        }
+        if (gid == 0) {
+            gid = get_gid_override(msg, dom);
+        }
 
         if (!orig_name || !uid || !gid) {
             DEBUG(SSSDBG_OP_FAILURE, "Incomplete user object for %s[%llu]! Skipping\n",
@@ -385,31 +426,38 @@ static int fill_pwent(struct sss_packet *packet,
 
         to_sized_string(&name, tmpstr);
 
-        tmpstr = ldb_msg_find_attr_as_string(msg, SYSDB_GECOS, NULL);
-        if (!tmpstr) {
-            to_sized_string(&gecos, "");
-        } else {
-            to_sized_string(&gecos, tmpstr);
+        if (gecos.str == NULL) {
+            tmpstr = ldb_msg_find_attr_as_string(msg, SYSDB_GECOS, NULL);
+            if (!tmpstr) {
+                to_sized_string(&gecos, "");
+            } else {
+                to_sized_string(&gecos, tmpstr);
+            }
         }
 
-        ZERO_STRUCT(homedir_ctx);
+        if (homedir.str == NULL) {
+            ZERO_STRUCT(homedir_ctx);
 
-        homedir_ctx.username = name.str;
-        homedir_ctx.uid = uid;
-        homedir_ctx.domain = dom->name;
-        homedir_ctx.upn = upn;
+            homedir_ctx.username = name.str;
+            homedir_ctx.uid = uid;
+            homedir_ctx.domain = dom->name;
+            homedir_ctx.upn = upn;
 
-        tmpstr = get_homedir_override(tmp_ctx, msg, nctx, dom, &homedir_ctx);
-        if (!tmpstr) {
-            to_sized_string(&homedir, "/");
-        } else {
-            to_sized_string(&homedir, tmpstr);
+            tmpstr = get_homedir_override(tmp_ctx, msg, nctx, dom, &homedir_ctx);
+            if (!tmpstr) {
+                to_sized_string(&homedir, "/");
+            } else {
+                to_sized_string(&homedir, tmpstr);
+            }
         }
-        tmpstr = get_shell_override(tmp_ctx, msg, nctx, dom);
-        if (!tmpstr) {
-            to_sized_string(&shell, "");
-        } else {
-            to_sized_string(&shell, tmpstr);
+
+        if (shell.str == NULL) {
+            tmpstr = get_shell_override(tmp_ctx, msg, nctx, dom);
+            if (!tmpstr) {
+                to_sized_string(&shell, "");
+            } else {
+                to_sized_string(&shell, tmpstr);
+            }
         }
 
         rsize = 2 * sizeof(uint32_t) + name.len + gecos.len +
@@ -734,6 +782,7 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
     int ret;
     static const char *user_attrs[] = SYSDB_PW_ATTRS;
     struct ldb_message *msg;
+    const char *extra_flag = NULL;
 
     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
@@ -827,7 +876,7 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
                 dctx->res->msgs[0] = talloc_steal(dctx->res->msgs, msg);
             }
         } else {
-            ret = sysdb_getpwnam(cmdctx, dom, name, &dctx->res);
+            ret = sysdb_getpwnam_with_views(cmdctx, dom, name, &dctx->res);
         }
         if (ret != EOK) {
             DEBUG(SSSDBG_CRIT_FAILURE,
@@ -871,11 +920,17 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
         /* if this is a caching provider (or if we haven't checked the cache
          * yet) then verify that the cache is uptodate */
         if (dctx->check_provider) {
-            ret = check_cache(dctx, nctx, dctx->res,
-                              SSS_DP_USER, name, 0,
-                              cmdctx->name_is_upn ? EXTRA_NAME_IS_UPN : NULL,
-                              nss_cmd_getby_dp_callback,
-                              dctx);
+
+            if (cmdctx->name_is_upn) {
+                extra_flag = EXTRA_NAME_IS_UPN;
+            } else if (DOM_HAS_VIEWS(dom) && dctx->res->count == 0) {
+                extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
+            } else {
+                extra_flag = NULL;
+            }
+
+            ret = check_cache(dctx, nctx, dctx->res, SSS_DP_USER, name, 0,
+                              extra_flag, nss_cmd_getby_dp_callback, dctx);
             if (ret != EOK) {
                 /* Anything but EOK means we should reenter the mainloop
                  * because we may be refreshing the cache
@@ -1453,6 +1508,7 @@ static int nss_cmd_getpwuid_search(struct nss_dom_ctx *dctx)
     struct nss_ctx *nctx;
     int ret;
     int err;
+    const char *extra_flag = NULL;
 
     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
@@ -1492,7 +1548,7 @@ static int nss_cmd_getpwuid_search(struct nss_dom_ctx *dctx)
             goto done;
         }
 
-        ret = sysdb_getpwuid(cmdctx, dom, cmdctx->id, &dctx->res);
+        ret = sysdb_getpwuid_with_views(cmdctx, dom, cmdctx->id, &dctx->res);
         if (ret != EOK) {
             DEBUG(SSSDBG_CRIT_FAILURE,
                   "Failed to make request to our cache!\n");
@@ -1523,9 +1579,15 @@ static int nss_cmd_getpwuid_search(struct nss_dom_ctx *dctx)
         /* if this is a caching provider (or if we haven't checked the cache
          * yet) then verify that the cache is uptodate */
         if (dctx->check_provider) {
-            ret = check_cache(dctx, nctx, dctx->res,
-                              SSS_DP_USER, NULL, cmdctx->id, NULL,
-                              nss_cmd_getby_dp_callback,
+
+            if (DOM_HAS_VIEWS(dom) && dctx->res->count == 0) {
+                extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
+            } else {
+                extra_flag = NULL;
+            }
+
+            ret = check_cache(dctx, nctx, dctx->res, SSS_DP_USER, NULL,
+                              cmdctx->id, extra_flag, nss_cmd_getby_dp_callback,
                               dctx);
             if (ret != EOK) {
                 /* Anything but EOK means we should reenter the mainloop
-- 
1.8.3.1

-------------- next part --------------
From 632a811db4fb37b77a82144fc40645333215c03c Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Fri, 26 Sep 2014 14:01:04 +0200
Subject: [PATCH 08/12] sysdb: add sysdb_initgroups_with_views()

---
 src/db/sysdb.h        |   6 +++
 src/db/sysdb_search.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 8d2894a..b65fa1d 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -226,6 +226,7 @@
                             SYSDB_ORIG_DN, \
                             SYSDB_SID_STR, \
                             SYSDB_NAME, \
+                            SYSDB_OVERRIDE_DN, \
                             NULL}
 
 #define SYSDB_TMPL_USER SYSDB_NAME"=%s,"SYSDB_TMPL_USER_BASE
@@ -565,6 +566,11 @@ int sysdb_initgroups(TALLOC_CTX *mem_ctx,
                      const char *name,
                      struct ldb_result **res);
 
+int sysdb_initgroups_with_views(TALLOC_CTX *mem_ctx,
+                                struct sss_domain_info *domain,
+                                const char *name,
+                                struct ldb_result **res);
+
 int sysdb_get_user_attr(TALLOC_CTX *mem_ctx,
                         struct sss_domain_info *domain,
                         const char *name,
diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
index 4329a8b..e8587ec 100644
--- a/src/db/sysdb_search.c
+++ b/src/db/sysdb_search.c
@@ -607,6 +607,119 @@ done:
     return ret;
 }
 
+int sysdb_initgroups_with_views(TALLOC_CTX *mem_ctx,
+                                struct sss_domain_info *domain,
+                                const char *name,
+                                struct ldb_result **_res)
+{
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_result *res;
+    struct ldb_dn *user_dn;
+    struct ldb_request *req;
+    struct ldb_control **ctrl;
+    struct ldb_asq_control *control;
+    static const char *attrs[] = SYSDB_INITGR_ATTRS;
+    int ret;
+    size_t c;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    ret = sysdb_getpwnam_with_views(tmp_ctx, domain, name, &res);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_getpwnam failed: [%d][%s]\n",
+                  ret, strerror(ret));
+        goto done;
+    }
+
+    if (res->count == 0) {
+        /* User is not cached yet */
+        *_res = talloc_steal(mem_ctx, res);
+        ret = EOK;
+        goto done;
+
+    } else if (res->count != 1) {
+        ret = EIO;
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "sysdb_getpwnam returned count: [%d]\n", res->count);
+        goto done;
+    }
+
+    /* no need to steal the dn, we are not freeing the result */
+    user_dn = res->msgs[0]->dn;
+
+    /* note we count on the fact that the default search callback
+     * will just keep appending values. This is by design and can't
+     * change so it is ok to already have a result (from the getpwnam)
+     * even before we call the next search */
+
+    ctrl = talloc_array(tmp_ctx, struct ldb_control *, 2);
+    if (!ctrl) {
+        ret = ENOMEM;
+        goto done;
+    }
+    ctrl[1] = NULL;
+    ctrl[0] = talloc(ctrl, struct ldb_control);
+    if (!ctrl[0]) {
+        ret = ENOMEM;
+        goto done;
+    }
+    ctrl[0]->oid = LDB_CONTROL_ASQ_OID;
+    ctrl[0]->critical = 1;
+    control = talloc(ctrl[0], struct ldb_asq_control);
+    if (!control) {
+        ret = ENOMEM;
+        goto done;
+    }
+    control->request = 1;
+    control->source_attribute = talloc_strdup(control, SYSDB_INITGR_ATTR);
+    if (!control->source_attribute) {
+        ret = ENOMEM;
+        goto done;
+    }
+    control->src_attr_len = strlen(control->source_attribute);
+    ctrl[0]->data = control;
+
+    ret = ldb_build_search_req(&req, domain->sysdb->ldb, tmp_ctx,
+                               user_dn, LDB_SCOPE_BASE,
+                               SYSDB_INITGR_FILTER, attrs, ctrl,
+                               res, ldb_search_default_callback,
+                               NULL);
+    if (ret != LDB_SUCCESS) {
+        ret = sysdb_error_to_errno(ret);
+        goto done;
+    }
+
+    ret = ldb_request(domain->sysdb->ldb, req);
+    if (ret == LDB_SUCCESS) {
+        ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+    }
+    if (ret != LDB_SUCCESS) {
+        ret = sysdb_error_to_errno(ret);
+        goto done;
+    }
+
+    if (DOM_HAS_VIEWS(domain)) {
+        /* Skip user entry because it already has override values added */
+        for (c = 1; c < res->count; c++) {
+            ret = sysdb_add_overrides_to_object(domain, res->msgs[c], NULL);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE,
+                      "sysdb_add_overrides_to_object failed.\n");
+                goto done;
+            }
+        }
+    }
+
+    *_res = talloc_steal(mem_ctx, res);
+
+done:
+    talloc_zfree(tmp_ctx);
+    return ret;
+}
+
 int sysdb_get_user_attr(TALLOC_CTX *mem_ctx,
                         struct sss_domain_info *domain,
                         const char *name,
-- 
1.8.3.1

-------------- next part --------------
From 1aa8a234ca779152615798c0f6520f8918c1f7b4 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Fri, 26 Sep 2014 20:16:51 +0200
Subject: [PATCH 09/12] nss: add view support to initgroups request

Make sysdb request view and override aware.

Relates to https://fedorahosted.org/sssd/ticket/2375
---
 src/responder/nss/nsssrv_cmd.c | 51 ++++++++++++++++++++++++++++++------------
 1 file changed, 37 insertions(+), 14 deletions(-)

diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 7ac78a0..5dbf65a 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -3798,7 +3798,8 @@ done:
 
 /* FIXME: what about mpg, should we return the user's GID ? */
 /* FIXME: should we filter out GIDs ? */
-static int fill_initgr(struct sss_packet *packet, struct ldb_result *res)
+static int fill_initgr(struct sss_packet *packet, struct sss_domain_info *dom,
+                       struct ldb_result *res)
 {
     uint8_t *body;
     size_t blen;
@@ -3822,14 +3823,15 @@ static int fill_initgr(struct sss_packet *packet, struct ldb_result *res)
     }
     sss_packet_get_body(packet, &body, &blen);
 
-    orig_primary_gid = ldb_msg_find_attr_as_uint64(res->msgs[0],
-                                                   SYSDB_PRIMARY_GROUP_GIDNUM,
-                                                   0);
+    orig_primary_gid = sss_view_ldb_msg_find_attr_as_uint64(dom, res->msgs[0],
+                                                     SYSDB_PRIMARY_GROUP_GIDNUM,
+                                                     0);
 
     /* If the GID of the original primary group is available but equal to the
     * current primary GID it must not be added. */
     if (orig_primary_gid != 0) {
-        gid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM, 0);
+        gid = sss_view_ldb_msg_find_attr_as_uint64(dom, res->msgs[0],
+                                                   SYSDB_GIDNUM, 0);
 
         if (orig_primary_gid == gid) {
             orig_primary_gid = 0;
@@ -3842,8 +3844,10 @@ 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);
+        gid = sss_view_ldb_msg_find_attr_as_uint64(dom, res->msgs[i + 1],
+                                                   SYSDB_GIDNUM, 0);
+        posix = ldb_msg_find_attr_as_string(res->msgs[i + 1],
+                                            SYSDB_POSIX, NULL);
         if (!gid) {
             if (posix && strcmp(posix, "FALSE") == 0) {
                 skipped++;
@@ -3894,7 +3898,7 @@ static int nss_cmd_initgr_send_reply(struct nss_dom_ctx *dctx)
         return EFAULT;
     }
 
-    ret = fill_initgr(cctx->creq->out, dctx->res);
+    ret = fill_initgr(cctx->creq->out, dctx->domain, dctx->res);
     if (ret) {
         return ret;
     }
@@ -3914,6 +3918,8 @@ static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
     static const char *user_attrs[] = SYSDB_PW_ATTRS;
     struct ldb_message *msg;
     const char *sysdb_name;
+    size_t c;
+    const char *extra_flag = NULL;
 
     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
@@ -3993,8 +3999,19 @@ static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
             }
 
             ret = sysdb_initgroups(cmdctx, dom, sysdb_name, &dctx->res);
+            if (ret == EOK && DOM_HAS_VIEWS(dom)) {
+                for (c = 0; c < dctx->res->count; c++) {
+                    ret = sysdb_add_overrides_to_object(dom, dctx->res->msgs[c],
+                                                        NULL);
+                    if (ret != EOK) {
+                        DEBUG(SSSDBG_OP_FAILURE,
+                              "sysdb_add_overrides_to_object failed.\n");
+                        return ret;
+                    }
+                }
+            }
         } else {
-            ret = sysdb_initgroups(cmdctx, dom, name, &dctx->res);
+            ret = sysdb_initgroups_with_views(cmdctx, dom, name, &dctx->res);
         }
         if (ret != EOK) {
             DEBUG(SSSDBG_CRIT_FAILURE,
@@ -4025,11 +4042,17 @@ static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
         /* if this is a caching provider (or if we haven't checked the cache
          * yet) then verify that the cache is uptodate */
         if (dctx->check_provider) {
-            ret = check_cache(dctx, nctx, dctx->res,
-                              SSS_DP_INITGROUPS, name, 0,
-                              cmdctx->name_is_upn ? EXTRA_NAME_IS_UPN : NULL,
-                              nss_cmd_getby_dp_callback,
-                              dctx);
+
+            if (cmdctx->name_is_upn) {
+                extra_flag = EXTRA_NAME_IS_UPN;
+            } else if (DOM_HAS_VIEWS(dom) && dctx->res->count == 0) {
+                extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
+            } else {
+                extra_flag = NULL;
+            }
+
+            ret = check_cache(dctx, nctx, dctx->res, SSS_DP_INITGROUPS, name, 0,
+                              extra_flag, nss_cmd_getby_dp_callback, dctx);
             if (ret != EOK) {
                 /* Anything but EOK means we should reenter the mainloop
                  * because we may be refreshing the cache
-- 
1.8.3.1

-------------- next part --------------
From 167d66f0a87e5a0922697cf4577c2e0b21f15831 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Mon, 29 Sep 2014 12:12:01 +0200
Subject: [PATCH 10/12] sysdb: add sysdb_getgrnam_with_views and
 sysdb_getgrgid_with_views

---
 src/db/sysdb.h        |  13 ++++
 src/db/sysdb_search.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/db/sysdb_views.c  | 130 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 315 insertions(+)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index b65fa1d..f7e507c 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -475,6 +475,9 @@ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
                                       struct ldb_message *obj,
                                       struct ldb_message *override_obj);
 
+errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
+                                         struct ldb_message *obj);
+
 errno_t sysdb_getpwnam_with_views(TALLOC_CTX *mem_ctx,
                                   struct sss_domain_info *domain,
                                   const char *name,
@@ -485,6 +488,16 @@ errno_t sysdb_getpwuid_with_views(TALLOC_CTX *mem_ctx,
                                   uid_t uid,
                                   struct ldb_result **res);
 
+int sysdb_getgrnam_with_views(TALLOC_CTX *mem_ctx,
+                              struct sss_domain_info *domain,
+                              const char *name,
+                              struct ldb_result **res);
+
+int sysdb_getgrgid_with_views(TALLOC_CTX *mem_ctx,
+                              struct sss_domain_info *domain,
+                              gid_t gid,
+                              struct ldb_result **res);
+
 struct ldb_message_element *
 sss_view_ldb_msg_find_element(struct sss_domain_info *dom,
                               const struct ldb_message *msg,
diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
index e8587ec..b5033a4 100644
--- a/src/db/sysdb_search.c
+++ b/src/db/sysdb_search.c
@@ -339,6 +339,92 @@ static int mpg_res_convert(struct ldb_result *res)
     return EOK;
 }
 
+int sysdb_getgrnam_with_views(TALLOC_CTX *mem_ctx,
+                              struct sss_domain_info *domain,
+                              const char *name,
+                              struct ldb_result **res)
+{
+    TALLOC_CTX *tmp_ctx;
+    int ret;
+    struct ldb_result *orig_obj = NULL;
+    struct ldb_result *override_obj = NULL;
+    struct ldb_message_element *el;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    /* If there are views we first have to search the overrides for matches */
+    if (DOM_HAS_VIEWS(domain)) {
+        ret = sysdb_search_group_override_by_name(tmp_ctx, domain, name,
+                                                  &override_obj, &orig_obj);
+        if (ret != EOK && ret != ENOENT) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "sysdb_search_group_override_by_name failed.\n");
+            return ret;
+        }
+    }
+
+    /* If there are no views or nothing was found in the overrides the
+     * original objects are searched. */
+    if (orig_obj == NULL) {
+        ret = sysdb_getgrnam(tmp_ctx, domain, name, &orig_obj);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_getgrnam failed.\n");
+            return ret;
+        }
+    }
+
+    /* If there are views we have to check if override values must be added to
+     * the original object. */
+    if (DOM_HAS_VIEWS(domain) && orig_obj->count == 1) {
+        el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_GHOST);
+        if (el != NULL && el->num_values != 0) {
+            DEBUG(SSSDBG_TRACE_ALL,
+                  "Group object [%s], contains ghost entries which must be " \
+                  "resolved before overrides can be applied.\n",
+                   ldb_dn_get_linearized(orig_obj->msgs[0]->dn));
+            ret = ENOENT;
+            goto done;
+        }
+
+        ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0],
+                          override_obj == NULL ? NULL : override_obj ->msgs[0]);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
+            return ret;
+        }
+
+        ret = sysdb_add_group_member_overrides(domain, orig_obj->msgs[0]);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "sysdb_add_group_member_overrides failed.\n");
+            goto done;
+        }
+    }
+
+    *res = talloc_steal(mem_ctx, orig_obj);
+    ret = EOK;
+    /* TODO: check if EOK is returned even if orig_obj is empty, i.e nothing
+     * found. */
+
+done:
+    if (ret == ENOENT) {
+        DEBUG(SSSDBG_TRACE_ALL, "Returning empty result.\n");
+        *res = talloc_zero(mem_ctx, struct ldb_result);
+        if (*res == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
+            ret = ENOMEM;
+        } else {
+            ret = EOK;
+        }
+    }
+
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
 int sysdb_getgrnam(TALLOC_CTX *mem_ctx,
                    struct sss_domain_info *domain,
                    const char *name,
@@ -407,6 +493,92 @@ done:
     return ret;
 }
 
+int sysdb_getgrgid_with_views(TALLOC_CTX *mem_ctx,
+                              struct sss_domain_info *domain,
+                              gid_t gid,
+                              struct ldb_result **res)
+{
+    TALLOC_CTX *tmp_ctx;
+    int ret;
+    struct ldb_result *orig_obj = NULL;
+    struct ldb_result *override_obj = NULL;
+    struct ldb_message_element *el;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    /* If there are views we first have to search the overrides for matches */
+    if (DOM_HAS_VIEWS(domain)) {
+        ret = sysdb_search_group_override_by_gid(tmp_ctx, domain, gid,
+                                                 &override_obj, &orig_obj);
+        if (ret != EOK && ret != ENOENT) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "sysdb_search_group_override_by_gid failed.\n");
+            return ret;
+        }
+    }
+
+    /* If there are no views or nothing was found in the overrides the
+     * original objects are searched. */
+    if (orig_obj == NULL) {
+        ret = sysdb_getgrgid(tmp_ctx, domain, gid, &orig_obj);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_getgrgid failed.\n");
+            return ret;
+        }
+    }
+
+    /* If there are views we have to check if override values must be added to
+     * the original object. */
+    if (DOM_HAS_VIEWS(domain) && orig_obj->count == 1) {
+        el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_GHOST);
+        if (el != NULL && el->num_values != 0) {
+            DEBUG(SSSDBG_TRACE_ALL,
+                  "Group object [%s], contains ghost entries which must be " \
+                  "resolved before overrides can be applied.\n",
+                   ldb_dn_get_linearized(orig_obj->msgs[0]->dn));
+            ret = ENOENT;
+            goto done;
+        }
+
+        ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0],
+                          override_obj == NULL ? NULL : override_obj ->msgs[0]);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
+            return ret;
+        }
+
+        ret = sysdb_add_group_member_overrides(domain, orig_obj->msgs[0]);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "sysdb_add_group_member_overrides failed.\n");
+            goto done;
+        }
+    }
+
+    *res = talloc_steal(mem_ctx, orig_obj);
+    ret = EOK;
+    /* TODO: check if EOK is returned even if orig_obj is empty, i.e nothing
+     * found. */
+
+done:
+    if (ret == ENOENT) {
+        DEBUG(SSSDBG_TRACE_ALL, "Returning empty result.\n");
+        *res = talloc_zero(mem_ctx, struct ldb_result);
+        if (*res == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
+            ret = ENOMEM;
+        } else {
+            ret = EOK;
+        }
+    }
+
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
 int sysdb_getgrgid(TALLOC_CTX *mem_ctx,
                    struct sss_domain_info *domain,
                    gid_t gid,
diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
index d778f9d..092a07b 100644
--- a/src/db/sysdb_views.c
+++ b/src/db/sysdb_views.c
@@ -1057,6 +1057,136 @@ done:
     return ret;
 }
 
+errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
+                                         struct ldb_message *obj)
+{
+    int ret;
+    size_t c;
+    struct ldb_message_element *members;
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_dn *member_dn;
+    struct ldb_result *member_obj;
+    struct ldb_result *override_obj;
+    static const char *member_attrs[] = SYSDB_PW_ATTRS;
+    const char *override_dn_str;
+    struct ldb_dn *override_dn;
+    const char *memberuid;
+
+    members = ldb_msg_find_element(obj, SYSDB_MEMBER);
+    if (members == NULL || members->num_values == 0) {
+        DEBUG(SSSDBG_TRACE_ALL, "Group has no members.\n");
+        return EOK;
+    }
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    for (c = 0; c < members->num_values; c++) {
+        member_dn = ldb_dn_from_ldb_val(tmp_ctx, domain->sysdb->ldb,
+                                        &members->values[c]);
+        if (member_dn == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_from_ldb_val failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+
+        ret = ldb_search(domain->sysdb->ldb, member_dn, &member_obj, member_dn,
+                         LDB_SCOPE_BASE, member_attrs, NULL);
+        if (ret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+
+        if (member_obj->count != 1) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Base search for member object returned [%d] results.\n",
+                  member_obj->count);
+            ret = EINVAL;
+            goto done;
+        }
+
+        override_dn_str = ldb_msg_find_attr_as_string(member_obj->msgs[0],
+                                                      SYSDB_OVERRIDE_DN, NULL);
+        if (override_dn_str == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Missing override DN for objext [%s].\n",
+                  ldb_dn_get_linearized(member_obj->msgs[0]->dn));
+            ret = ENOENT;
+            goto done;
+        }
+
+        override_dn = ldb_dn_new(member_obj, domain->sysdb->ldb,
+                                 override_dn_str);
+        if (override_dn == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+
+        memberuid = NULL;
+        if (ldb_dn_compare(member_obj->msgs[0]->dn, override_dn) != 0) {
+            DEBUG(SSSDBG_TRACE_ALL, "Checking override for object [%s].\n",
+                  ldb_dn_get_linearized(member_obj->msgs[0]->dn));
+
+            ret = ldb_search(domain->sysdb->ldb, member_obj, &override_obj,
+                             override_dn, LDB_SCOPE_BASE, member_attrs, NULL);
+            if (ret != LDB_SUCCESS) {
+                ret = sysdb_error_to_errno(ret);
+                goto done;
+            }
+
+            if (override_obj->count != 1) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                     "Base search for override object returned [%d] results.\n",
+                     member_obj->count);
+                ret = EINVAL;
+                goto done;
+            }
+
+            memberuid = ldb_msg_find_attr_as_string(override_obj->msgs[0],
+                                                    SYSDB_NAME,
+                                                    NULL);
+        }
+
+        if (memberuid == NULL) {
+            DEBUG(SSSDBG_TRACE_ALL, "No override name available.\n");
+
+            memberuid = ldb_msg_find_attr_as_string(member_obj->msgs[0],
+                                                    SYSDB_NAME,
+                                                    NULL);
+            if (memberuid == NULL) {
+                DEBUG(SSSDBG_CRIT_FAILURE, "Object [%s] has no name.\n",
+                      ldb_dn_get_linearized(member_obj->msgs[0]->dn));
+                ret = EINVAL;
+                goto done;
+            }
+        }
+
+        ret = ldb_msg_add_string(obj, OVERRIDE_PREFIX SYSDB_MEMBERUID,
+                                 memberuid);
+        if (ret != LDB_SUCCESS) {
+            DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_string failed.\n");
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+
+        /* Free all temporary data of the current member to avoid memory usage
+         * spikes. All temporary data should be allocated below member_dn. */
+        talloc_free(member_dn);
+    }
+
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+
+    return ret;
+}
+
 struct ldb_message_element *
 sss_view_ldb_msg_find_element(struct sss_domain_info *dom,
                                               const struct ldb_message *msg,
-- 
1.8.3.1

-------------- next part --------------
From 6bf40cf2302339a98439cb24f2ffb29798df34de Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Mon, 29 Sep 2014 14:52:03 +0200
Subject: [PATCH 11/12] nss: add view support for getgr* requests

Make group lookups view and override aware.

Relates to https://fedorahosted.org/sssd/ticket/2375
---
 src/responder/nss/nsssrv_cmd.c | 60 +++++++++++++++++++++++++++++++++---------
 1 file changed, 47 insertions(+), 13 deletions(-)

diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 5dbf65a..f9a479b 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -2633,7 +2633,7 @@ static int fill_grent(struct sss_packet *packet,
     size_t blen;
     uint32_t gid;
     const char *tmpstr;
-    const char *orig_name;
+    const char *orig_name = NULL;
     struct sized_string name;
     struct sized_string pwfield;
     struct sized_string fullname;
@@ -2676,8 +2676,21 @@ static int fill_grent(struct sss_packet *packet,
         rsize = 0;
 
         /* find group name/gid */
-        orig_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
-        gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
+        if (DOM_HAS_VIEWS(dom)) {
+            orig_name = ldb_msg_find_attr_as_string(msg,
+                                                    OVERRIDE_PREFIX SYSDB_NAME,
+                                                    NULL);
+        }
+        if (orig_name == NULL) {
+            orig_name = ldb_msg_find_attr_as_string(msg,
+                                                    SYSDB_DEFAULT_OVERRIDE_NAME,
+                                                    NULL);
+            if (orig_name == NULL) {
+                orig_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+            }
+        }
+
+        gid = sss_view_ldb_msg_find_attr_as_uint64(dom, msg, SYSDB_GIDNUM, 0);
         if (!orig_name || !gid) {
             DEBUG(SSSDBG_OP_FAILURE,
                   "Incomplete group object for %s[%llu]! Skipping\n",
@@ -2769,7 +2782,7 @@ static int fill_grent(struct sss_packet *packet,
 
         memnum = 0;
         if (!dom->ignore_group_members) {
-            el = ldb_msg_find_element(msg, SYSDB_MEMBERUID);
+            el = sss_view_ldb_msg_find_element(dom, msg, SYSDB_MEMBERUID);
             if (el) {
                 ret = fill_members(packet, dom, nctx, el, &rzero, &rsize,
                                    &memnum);
@@ -2781,6 +2794,14 @@ static int fill_grent(struct sss_packet *packet,
             }
             el = ldb_msg_find_element(msg, SYSDB_GHOST);
             if (el) {
+                if (DOM_HAS_VIEWS(dom) && el->num_values != 0) {
+                    DEBUG(SSSDBG_CRIT_FAILURE,
+                          "Domain has a view [%s] but group [%s] still has " \
+                          "ghost members.\n", dom->view_name, orig_name);
+                    num = 0;
+                    ret = EINVAL;
+                    goto done;
+                }
                 ret = fill_members(packet, dom, nctx, el, &rzero, &rsize,
                                    &memnum);
                 if (ret != EOK) {
@@ -2880,6 +2901,7 @@ static int nss_cmd_getgrnam_search(struct nss_dom_ctx *dctx)
     char *name = NULL;
     struct nss_ctx *nctx;
     int ret;
+    const char *extra_flag = NULL;
 
     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
@@ -2943,7 +2965,7 @@ static int nss_cmd_getgrnam_search(struct nss_dom_ctx *dctx)
             return EIO;
         }
 
-        ret = sysdb_getgrnam(cmdctx, dom, name, &dctx->res);
+        ret = sysdb_getgrnam_with_views(cmdctx, dom, name, &dctx->res);
         if (ret != EOK) {
             DEBUG(SSSDBG_CRIT_FAILURE,
                   "Failed to make request to our cache!\n");
@@ -2987,10 +3009,15 @@ static int nss_cmd_getgrnam_search(struct nss_dom_ctx *dctx)
         /* if this is a caching provider (or if we haven't checked the cache
          * yet) then verify that the cache is uptodate */
         if (dctx->check_provider) {
-            ret = check_cache(dctx, nctx, dctx->res,
-                              SSS_DP_GROUP, name, 0, NULL,
-                              nss_cmd_getby_dp_callback,
-                              dctx);
+
+            if (DOM_HAS_VIEWS(dom) && dctx->res->count == 0) {
+                extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
+            } else {
+                extra_flag = NULL;
+            }
+
+            ret = check_cache(dctx, nctx, dctx->res, SSS_DP_GROUP, name, 0,
+                              extra_flag, nss_cmd_getby_dp_callback, dctx);
             if (ret != EOK) {
                 /* Anything but EOK means we should reenter the mainloop
                  * because we may be refreshing the cache
@@ -3032,6 +3059,7 @@ static int nss_cmd_getgrgid_search(struct nss_dom_ctx *dctx)
     struct nss_ctx *nctx;
     int ret;
     int err;
+    const char *extra_flag = NULL;
 
     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
@@ -3071,7 +3099,7 @@ static int nss_cmd_getgrgid_search(struct nss_dom_ctx *dctx)
             goto done;
         }
 
-        ret = sysdb_getgrgid(cmdctx, dom, cmdctx->id, &dctx->res);
+        ret = sysdb_getgrgid_with_views(cmdctx, dom, cmdctx->id, &dctx->res);
         if (ret != EOK) {
             DEBUG(SSSDBG_CRIT_FAILURE,
                   "Failed to make request to our cache!\n");
@@ -3102,9 +3130,15 @@ static int nss_cmd_getgrgid_search(struct nss_dom_ctx *dctx)
         /* if this is a caching provider (or if we haven't checked the cache
          * yet) then verify that the cache is uptodate */
         if (dctx->check_provider) {
-            ret = check_cache(dctx, nctx, dctx->res,
-                              SSS_DP_GROUP, NULL, cmdctx->id, NULL,
-                              nss_cmd_getby_dp_callback,
+
+            if (DOM_HAS_VIEWS(dom) && dctx->res->count == 0) {
+                extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
+            } else {
+                extra_flag = NULL;
+            }
+
+            ret = check_cache(dctx, nctx, dctx->res, SSS_DP_GROUP, NULL,
+                              cmdctx->id, extra_flag, nss_cmd_getby_dp_callback,
                               dctx);
             if (ret != EOK) {
                 /* Anything but EOK means we should reenter the mainloop
-- 
1.8.3.1

-------------- next part --------------
From 6ee90ee30cd6f5ad2630f87f0f9abe195082da2c Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Thu, 2 Oct 2014 18:10:39 +0200
Subject: [PATCH 12/12] sid2name: return name without views applied

Make sure that the original name of an object without any overrides
applied is returned by sid2name requests.
---
 src/db/sysdb_ops.c             |  1 +
 src/responder/nss/nsssrv_cmd.c | 14 ++++++++++++--
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index 1d51119..c88ff9b 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -3507,6 +3507,7 @@ errno_t sysdb_search_object_by_sid(TALLOC_CTX *mem_ctx,
 {
     TALLOC_CTX *tmp_ctx;
     const char *def_attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, SYSDB_GIDNUM,
+                                ORIGINALAD_PREFIX SYSDB_NAME,
                                 SYSDB_OBJECTCLASS, NULL };
     struct ldb_dn *basedn;
     int ret;
diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index f9a479b..7b18c85 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -4628,11 +4628,12 @@ static errno_t fill_orig(struct sss_packet *packet,
 static errno_t fill_name(struct sss_packet *packet,
                          struct sss_domain_info *dom,
                          enum sss_id_type id_type,
+                         bool apply_no_view,
                          struct ldb_message *msg)
 {
     int ret;
     TALLOC_CTX *tmp_ctx = NULL;
-    const char *orig_name;
+    const char *orig_name = NULL;
     const char *cased_name;
     const char *fq_name;
     struct sized_string name;
@@ -4641,7 +4642,15 @@ static errno_t fill_name(struct sss_packet *packet,
     size_t blen;
     size_t pctr = 0;
 
-    orig_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+    if (apply_no_view) {
+        orig_name = ldb_msg_find_attr_as_string(msg,
+                                                ORIGINALAD_PREFIX SYSDB_NAME,
+                                                NULL);
+    }
+
+    if (orig_name == NULL) {
+        orig_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+    }
     if (orig_name == NULL) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Missing name.\n");
         return EINVAL;
@@ -4760,6 +4769,7 @@ static errno_t nss_cmd_getbysid_send_reply(struct nss_dom_ctx *dctx)
         ret = fill_name(cctx->creq->out,
                         dctx->domain,
                         id_type,
+                        true,
                         dctx->res->msgs[0]);
         break;
     case SSS_NSS_GETIDBYSID:
-- 
1.8.3.1



More information about the sssd-devel mailing list