[SSSD] [PATCHES] Views: apply user SSH public key override

Sumit Bose sbose at redhat.com
Tue Nov 4 13:29:13 UTC 2014


On Tue, Nov 04, 2014 at 10:07:12AM +0100, Jakub Hrozek wrote:
> On Tue, Oct 28, 2014 at 04:41:44PM +0100, Sumit Bose wrote:
> > Hi,
> > 
> > this series of patches add support for SSH public key overrides. The
> > main part is in patch 004. The others mainly enhance the exiting
> > functions with respect to multi-values and variable attribute lists.
> > 
> > In contrast to other overrides the SSH public keys from the override
> > attributes do not override any existing ones but are added to the
> > existing ones. Please tell me if you think this is not a good idea so
> > that I can change it.
> > 
> > bye,
> > Sumit
> 
> I'm still running some tests and because I ran into issues updating my
> devel server, I'm sending code-wise review now to speed up the process.
> 
> btw I discussed the old format of ssh keys with Honza and even though
> neither of us tested them, the code is going to handle them fine,
> because the conversion is happening as late as the client libraries
> (sss_ssh_*).
> 
> > From c4fda98f9df7dd665e28f3c71097125bbf2ba07c Mon Sep 17 00:00:00 2001
> > From: Sumit Bose <sbose at redhat.com>
> > Date: Mon, 27 Oct 2014 16:53:44 +0100
> > Subject: [PATCH 1/5] Add add_strings_lists() utilty function
> > 
> > ---
> >  src/tests/cmocka/test_utils.c | 111 ++++++++++++++++++++++++++++++++++++++++++
> 
> Thanks for the unit tests!

Thank you for the review.

> 
> >  src/util/util.c               |  60 +++++++++++++++++++++++
> >  src/util/util.h               |  18 +++++++
> >  3 files changed, 189 insertions(+)
> > 
> 
> [...]
> 
> > +/**
> > + * @brief Add two list of strings
> > + *
> > + * Create a new NULL-termintated list of strings by adding two lists together.
> > + *
> > + * @param[in] mem_ctx      Talloc memory context for the new list.
> > + * @param[in] l1           First NULL-termintated list of strings.
> > + * @param[in] l2           Second NULL-termintated list of strings.
> > + * @param[in] copy_strings If set to 'true' the list items will be copied
> > + *                         otherwise only the pointers to the items are
> > + *                         copied.
> > + * @param[out] new_list    New NULL-terminated list of strings. Must be freed
> > + *                         with talloc_free() by the caller. If copy_strings
> > + *                         is 'true' the new elements will be freed as well.
> > + */
> > +errno_t add_strings_lists(TALLOC_CTX *mem_ctx, const char **l1, const char **l2,
> > +                          bool copy_strings, char ***new_list);
> > +
> 
> Can you prefix the output variable with a leading underscore? I know in
> this case it's clear from the name it's an output variable, but the
> prefix is more or less a convention we follow.

done

> 
> There is also a typo in the commit message (utilty).

done

> 
> Otherwise ACK.
> 
> > From 93b96813267feb55c9d12bdddefd58fc4e4f1f2b Mon Sep 17 00:00:00 2001
> > From: Sumit Bose <sbose at redhat.com>
> > Date: Mon, 27 Oct 2014 13:33:08 +0100
> > Subject: [PATCH 2/5] sysdb_get_user_attr_with_views: add mandatory override
> >  attributes
> 
> ACK. I don't see an easy way around the discard_const either 
> 
> > From 3cebae5b5569dc559896945e244e0ae9575b04d1 Mon Sep 17 00:00:00 2001
> > From: Sumit Bose <sbose at redhat.com>
> > Date: Mon, 27 Oct 2014 15:11:08 +0100
> > Subject: [PATCH 3/5] sysdb_add_overrides_to_object: add new parameter and
> >  multi-value support
> 
> Can you add the new parameter to the doxygen description of
> sysdb_add_overrides_to_object() ?

done

> 
> > 

...

> > +++ b/src/db/sysdb_search.c
> > @@ -124,7 +124,8 @@ errno_t sysdb_getpwnam_with_views(TALLOC_CTX *mem_ctx,
> >       * 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]);
> > +                          override_obj == NULL ? NULL : override_obj ->msgs[0],
> 
> Is the space after override_obj intentional? It looks a bit odd ...

fixed

> 
> > +                          NULL);
> >          if (ret != EOK && ret != ENOENT) {
> >              DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
> >              goto done;
> 
> The rest of the patch looks good to me.
> 
> > From 2d14490b0369e98afb17c1e340e2555d79187faa Mon Sep 17 00:00:00 2001
> > From: Sumit Bose <sbose at redhat.com>
> > Date: Thu, 16 Oct 2014 13:17:37 +0200

...

> > -                if (ret != EOK) {
> > -                    DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_val failed.\n");
> > -                    goto done;
> > +                num_values = el->num_values;
> > +                /* Only SYSDB_SSH_PUBKEY is allowed to have multiple values. */
> > +                if (strcmp(allowed_attrs[c], SYSDB_SSH_PUBKEY) != 0
> > +                        && num_values != 1) {
> > +                    DEBUG(SSSDBG_MINOR_FAILURE,
> > +                          "Override attribute for [%s] has more [%d] " \
> > +                          "than one value, using onlye the first.\n",
>                                                     ^^^^^
>                                                     Typo..

fixed

> 
> Also adds a compilation warning:
> src/db/sysdb_views.c: In function 'sysdb_apply_default_override':
> src/db/sysdb_views.c:616:21: warning: format '%d' expects argument of type 'int', but argument 7 has type 'size_t' [-Wformat=]

fixed

> 
> > +                          allowed_attrs[c], num_values);
> > +                    num_values = 1;
> > +                }
> > +

The new version contains a 6th patch which adds the public key to the
attribute list of the getorigbyname request so that the extdom plugin can
send the SSH key from the default view to the client.

bye,
Sumit
-------------- next part --------------
From af409207bf299c28d14093ee92e8824c894c4a11 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Mon, 27 Oct 2014 16:53:44 +0100
Subject: [PATCH 1/6] Add add_strings_lists() utility function

---
 src/tests/cmocka/test_utils.c | 111 ++++++++++++++++++++++++++++++++++++++++++
 src/util/util.c               |  60 +++++++++++++++++++++++
 src/util/util.h               |  18 +++++++
 3 files changed, 189 insertions(+)

diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
index 9d6cbf3..d978137 100644
--- a/src/tests/cmocka/test_utils.c
+++ b/src/tests/cmocka/test_utils.c
@@ -875,6 +875,114 @@ void test_expand_homedir_template(void **state)
     talloc_free(tmp_ctx);
 }
 
+void setup_add_strings_lists(void **state)
+{
+    assert_true(leak_check_setup());
+
+    check_leaks_push(global_talloc_context);
+}
+
+void teardown_add_strings_lists(void **state)
+{
+    assert_true(check_leaks_pop(global_talloc_context) == true);
+    assert_true(leak_check_teardown());
+}
+
+void test_add_strings_lists(void **state)
+{
+    const char *l1[] = {"a", "b", "c", NULL};
+    const char *l2[] = {"1", "2", "3", NULL};
+    char **res;
+    int ret;
+    size_t c;
+    size_t d;
+
+    ret = add_strings_lists(global_talloc_context, NULL, NULL, true, &res);
+    assert_int_equal(ret, EOK);
+    assert_non_null(res);
+    assert_null(res[0]);
+    talloc_free(res);
+
+    ret = add_strings_lists(global_talloc_context, NULL, NULL, false, &res);
+    assert_int_equal(ret, EOK);
+    assert_non_null(res);
+    assert_null(res[0]);
+    talloc_free(res);
+
+    ret = add_strings_lists(global_talloc_context, l1, NULL, false, &res);
+    assert_int_equal(ret, EOK);
+    assert_non_null(res);
+    for (c = 0; l1[c] != NULL; c++) {
+        /* 'copy_strings' is 'false', pointers must be equal */
+        assert_int_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0);
+    }
+    assert_null(res[c]);
+    talloc_free(res);
+
+    ret = add_strings_lists(global_talloc_context, l1, NULL, true, &res);
+    assert_int_equal(ret, EOK);
+    assert_non_null(res);
+    for (c = 0; l1[c] != NULL; c++) {
+        /* 'copy_strings' is 'true', pointers must be different, but strings
+         * must be equal */
+        assert_int_not_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0);
+        assert_string_equal(l1[c], res[c]);
+    }
+    assert_null(res[c]);
+    talloc_free(res);
+
+    ret = add_strings_lists(global_talloc_context, NULL, l1, false, &res);
+    assert_int_equal(ret, EOK);
+    assert_non_null(res);
+    for (c = 0; l1[c] != NULL; c++) {
+        /* 'copy_strings' is 'false', pointers must be equal */
+        assert_int_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0);
+    }
+    assert_null(res[c]);
+    talloc_free(res);
+
+    ret = add_strings_lists(global_talloc_context, NULL, l1, true, &res);
+    assert_int_equal(ret, EOK);
+    assert_non_null(res);
+    for (c = 0; l1[c] != NULL; c++) {
+        /* 'copy_strings' is 'true', pointers must be different, but strings
+         * must be equal */
+        assert_int_not_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0);
+        assert_string_equal(l1[c], res[c]);
+    }
+    assert_null(res[c]);
+    talloc_free(res);
+
+    ret = add_strings_lists(global_talloc_context, l1, l2, false, &res);
+    assert_int_equal(ret, EOK);
+    assert_non_null(res);
+    for (c = 0; l1[c] != NULL; c++) {
+        /* 'copy_strings' is 'false', pointers must be equal */
+        assert_int_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0);
+    }
+    for (d = 0; l2[d] != NULL; d++) {
+        assert_int_equal(memcmp(&l2[d], &res[c+d], sizeof(char *)), 0);
+    }
+    assert_null(res[c+d]);
+    talloc_free(res);
+
+    ret = add_strings_lists(global_talloc_context, l1, l2, true, &res);
+    assert_int_equal(ret, EOK);
+    assert_non_null(res);
+    for (c = 0; l1[c] != NULL; c++) {
+        /* 'copy_strings' is 'true', pointers must be different, but strings
+         * must be equal */
+        assert_int_not_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0);
+        assert_string_equal(l1[c], res[c]);
+    }
+    for (d = 0; l2[d] != NULL; d++) {
+        assert_int_not_equal(memcmp(&l2[d], &res[c+d], sizeof(char *)), 0);
+        assert_string_equal(l2[d], res[c+d]);
+    }
+    assert_null(res[c+d]);
+    talloc_free(res);
+}
+
 int main(int argc, const char *argv[])
 {
     poptContext pc;
@@ -919,6 +1027,9 @@ int main(int argc, const char *argv[])
         unit_test(test_textual_public_key),
         unit_test(test_replace_whitespaces),
         unit_test(test_reverse_replace_whitespaces),
+        unit_test_setup_teardown(test_add_strings_lists,
+                                 setup_add_strings_lists,
+                                 teardown_add_strings_lists),
     };
 
     /* Set debug level to invalid value so we can deside if -d 0 was used. */
diff --git a/src/util/util.c b/src/util/util.c
index d78d37d..be106d6 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -815,3 +815,63 @@ const char * const * get_known_services(void)
 
     return svc;
 }
+
+errno_t add_strings_lists(TALLOC_CTX *mem_ctx, const char **l1, const char **l2,
+                          bool copy_strings, char ***_new_list)
+{
+    size_t c;
+    size_t l1_count = 0;
+    size_t l2_count = 0;
+    size_t new_count = 0;
+    char **new;
+    int ret;
+
+    if (l1 != NULL) {
+        for (l1_count = 0; l1[l1_count] != NULL; l1_count++);
+    }
+
+    if (l2 != NULL) {
+        for (l2_count = 0; l2[l2_count] != NULL; l2_count++);
+    }
+
+    new_count = l1_count + l2_count;
+
+    new = talloc_array(mem_ctx, char *, new_count + 1);
+    if (new == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
+        return ENOMEM;
+    }
+    new [new_count] = NULL;
+
+    if (copy_strings) {
+        for(c = 0; c < l1_count; c++) {
+            new[c] = talloc_strdup(new, l1[c]);
+            if (new[c] == NULL) {
+                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+                ret = ENOMEM;
+                goto done;
+            }
+        }
+        for(c = 0; c < l2_count; c++) {
+            new[l1_count + c] = talloc_strdup(new, l2[c]);
+            if (new[l1_count + c] == NULL) {
+                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+                ret = ENOMEM;
+                goto done;
+            }
+        }
+    } else {
+        memcpy(new, l1, sizeof(char *) * l1_count);
+        memcpy(&new[l1_count], l2, sizeof(char *) * l2_count);
+    }
+
+    *_new_list = new;
+    ret = EOK;
+
+done:
+    if (ret != EOK) {
+        talloc_free(new);
+    }
+
+    return ret;
+}
diff --git a/src/util/util.h b/src/util/util.h
index 69074c9..ffc8a87 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -426,6 +426,24 @@ errno_t sss_hash_create_ex(TALLOC_CTX *mem_ctx,
                            hash_delete_callback *delete_callback,
                            void *delete_private_data);
 
+/**
+ * @brief Add two list of strings
+ *
+ * Create a new NULL-termintated list of strings by adding two lists together.
+ *
+ * @param[in] mem_ctx      Talloc memory context for the new list.
+ * @param[in] l1           First NULL-termintated list of strings.
+ * @param[in] l2           Second NULL-termintated list of strings.
+ * @param[in] copy_strings If set to 'true' the list items will be copied
+ *                         otherwise only the pointers to the items are
+ *                         copied.
+ * @param[out] new_list    New NULL-terminated list of strings. Must be freed
+ *                         with talloc_free() by the caller. If copy_strings
+ *                         is 'true' the new elements will be freed as well.
+ */
+errno_t add_strings_lists(TALLOC_CTX *mem_ctx, const char **l1, const char **l2,
+                          bool copy_strings, char ***_new_list);
+
 /* Copy a NULL-terminated string list
  * Returns NULL on out of memory error or invalid input
  */
-- 
1.8.3.1

-------------- next part --------------
From 6867b82521b9ed6de7a5a6a6ff2762f9cd6e4f6b Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Mon, 27 Oct 2014 13:33:08 +0100
Subject: [PATCH 2/6] sysdb_get_user_attr_with_views: add mandatory override
 attributes

This patch add another attribute with is needs for override processing
to the attribute list of sysdb_get_user_attr_with_views(). With two
attribute it does not seem useful to check for existence and add each of
the attributes conditionally. With this patch they are added
unconditionally if the domain has views. Additionally the attributes are
not removed in the end because it is expected that they do not cause any
harm.
---
 src/db/sysdb_search.c | 47 ++++++++---------------------------------------
 1 file changed, 8 insertions(+), 39 deletions(-)

diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
index bbc5af8..dacbd23 100644
--- a/src/db/sysdb_search.c
+++ b/src/db/sysdb_search.c
@@ -1037,11 +1037,11 @@ int sysdb_get_user_attr_with_views(TALLOC_CTX *mem_ctx,
     int ret;
     struct ldb_result *orig_obj = NULL;
     struct ldb_result *override_obj = NULL;
-    struct ldb_message_element *el = NULL;
     const char **attrs = NULL;
-    bool has_override_dn;
+    const char *mandatory_override_attrs[] = {SYSDB_OVERRIDE_DN,
+                                              SYSDB_OVERRIDE_OBJECT_DN,
+                                              NULL};
     TALLOC_CTX *tmp_ctx;
-    int count;
 
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) {
@@ -1049,35 +1049,15 @@ int sysdb_get_user_attr_with_views(TALLOC_CTX *mem_ctx,
         return ENOMEM;
     }
 
-    /* Assume that overrideDN is requested to simplify the code. If no view
-     * is applied it doesn't really matter. */
-    has_override_dn = true;
     attrs = attributes;
 
     /* If there are views we first have to search the overrides for matches */
     if (DOM_HAS_VIEWS(domain)) {
-        /* We need overrideDN for views, so append it if missing. */
-        has_override_dn = false;
-        for (count = 0; attributes[count] != NULL; count++) {
-            if (strcmp(attributes[count], SYSDB_OVERRIDE_DN) == 0) {
-                has_override_dn = true;
-                break;
-            }
-        }
-
-        if (!has_override_dn) {
-            /* Copy original attributes and add overrideDN. */
-            attrs = talloc_zero_array(tmp_ctx, const char *, count + 2);
-            if (attrs == NULL) {
-                ret = ENOMEM;
-                goto done;
-            }
-
-            for (count = 0; attributes[count] != NULL; count++) {
-                attrs[count] = attributes[count];
-            }
-
-            attrs[count] = SYSDB_OVERRIDE_DN;
+        ret = add_strings_lists(tmp_ctx, attributes, mandatory_override_attrs,
+                                false, discard_const(&attrs));
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "add_strings_lists failed.\n");
+            goto done;
         }
 
         ret = sysdb_search_user_override_attrs_by_name(tmp_ctx, domain, name,
@@ -1121,17 +1101,6 @@ int sysdb_get_user_attr_with_views(TALLOC_CTX *mem_ctx,
         }
     }
 
-    /* Remove overrideDN if needed. */
-    if (!has_override_dn && orig_obj != NULL && orig_obj->count == 1) {
-        el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_OVERRIDE_DN);
-        if (el == NULL) {
-            ret = EINVAL;
-            goto done;
-        }
-
-        ldb_msg_remove_element(orig_obj->msgs[0], el);
-    }
-
     *_res = talloc_steal(mem_ctx, orig_obj);
     ret = EOK;
 
-- 
1.8.3.1

-------------- next part --------------
From 3b1617263cd171394004f4ea147d6e0fe969c5e6 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Mon, 27 Oct 2014 15:11:08 +0100
Subject: [PATCH 3/6] sysdb_add_overrides_to_object: add new parameter and
 multi-value support

With the new parameter an attribute list other than the default one can
be used.

Override attributes with multiple values (e.g. SSH public keys) are now
supported as well.
---
 src/db/sysdb.h                 |  3 ++-
 src/db/sysdb_search.c          | 24 ++++++++++++++++--------
 src/db/sysdb_views.c           | 41 +++++++++++++++++++++++++----------------
 src/responder/nss/nsssrv_cmd.c |  2 +-
 4 files changed, 44 insertions(+), 26 deletions(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index ebb1bbe..f582f6a 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -487,7 +487,8 @@ errno_t sysdb_search_group_override_by_gid(TALLOC_CTX *mem_ctx,
 
 errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
                                       struct ldb_message *obj,
-                                      struct ldb_message *override_obj);
+                                      struct ldb_message *override_obj,
+                                      const char **req_attrs);
 
 errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain,
                                          struct ldb_message *obj);
diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
index dacbd23..6772574 100644
--- a/src/db/sysdb_search.c
+++ b/src/db/sysdb_search.c
@@ -124,7 +124,8 @@ errno_t sysdb_getpwnam_with_views(TALLOC_CTX *mem_ctx,
      * 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]);
+                          override_obj == NULL ? NULL : override_obj->msgs[0],
+                          NULL);
         if (ret != EOK && ret != ENOENT) {
             DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
             goto done;
@@ -229,7 +230,8 @@ errno_t sysdb_getpwuid_with_views(TALLOC_CTX *mem_ctx,
      * 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]);
+                           override_obj == NULL ? NULL : override_obj->msgs[0],
+                           NULL);
         if (ret != EOK && ret != ENOENT) {
             DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
             goto done;
@@ -314,7 +316,8 @@ int sysdb_enumpwent_with_views(TALLOC_CTX *mem_ctx,
 
     if (DOM_HAS_VIEWS(domain)) {
         for (c = 0; c < res->count; c++) {
-            ret = sysdb_add_overrides_to_object(domain, res->msgs[c], NULL);
+            ret = sysdb_add_overrides_to_object(domain, res->msgs[c], NULL,
+                                                NULL);
             /* enumeration assumes that the cache is up-to-date, hence we do not
              * need to handle ENOENT separately. */
             if (ret != EOK) {
@@ -426,7 +429,8 @@ int sysdb_getgrnam_with_views(TALLOC_CTX *mem_ctx,
         }
 
         ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0],
-                          override_obj == NULL ? NULL : override_obj ->msgs[0]);
+                          override_obj == NULL ? NULL : override_obj ->msgs[0],
+                          NULL);
         if (ret != EOK) {
             DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
             goto done;
@@ -578,7 +582,8 @@ int sysdb_getgrgid_with_views(TALLOC_CTX *mem_ctx,
         }
 
         ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0],
-                          override_obj == NULL ? NULL : override_obj ->msgs[0]);
+                          override_obj == NULL ? NULL : override_obj ->msgs[0],
+                          NULL);
         if (ret != EOK) {
             DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
             goto done;
@@ -734,7 +739,8 @@ int sysdb_enumgrent_with_views(TALLOC_CTX *mem_ctx,
 
     if (DOM_HAS_VIEWS(domain)) {
         for (c = 0; c < res->count; c++) {
-            ret = sysdb_add_overrides_to_object(domain, res->msgs[c], NULL);
+            ret = sysdb_add_overrides_to_object(domain, res->msgs[c], NULL,
+                                                NULL);
             /* enumeration assumes that the cache is up-to-date, hence we do not
              * need to handle ENOENT separately. */
             if (ret != EOK) {
@@ -956,7 +962,8 @@ int sysdb_initgroups_with_views(TALLOC_CTX *mem_ctx,
     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);
+            ret = sysdb_add_overrides_to_object(domain, res->msgs[c], NULL,
+                                                NULL);
             if (ret != EOK) {
                 DEBUG(SSSDBG_OP_FAILURE,
                       "sysdb_add_overrides_to_object failed.\n");
@@ -1083,7 +1090,8 @@ int sysdb_get_user_attr_with_views(TALLOC_CTX *mem_ctx,
      * 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]);
+                          override_obj == NULL ? NULL : override_obj ->msgs[0],
+                          attrs);
         if (ret != EOK && ret != ENOENT) {
             DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
             return ret;
diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
index a42aa96..f2cf370 100644
--- a/src/db/sysdb_views.c
+++ b/src/db/sysdb_views.c
@@ -948,6 +948,8 @@ errno_t sysdb_search_group_override_by_gid(TALLOC_CTX *mem_ctx,
  * @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
+ * @param[in] req_attrs List of attributes to be requested, if not set a
+ *                      default list dependig on the object type will be used
  *
  * @return EOK - Override data was added successfully
  * @return ENOMEM - There was insufficient memory to complete the operation
@@ -958,7 +960,8 @@ errno_t sysdb_search_group_override_by_gid(TALLOC_CTX *mem_ctx,
  */
 errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
                                       struct ldb_message *obj,
-                                      struct ldb_message *override_obj)
+                                      struct ldb_message *override_obj,
+                                      const char **req_attrs)
 {
     int ret;
     const char *override_dn_str;
@@ -983,7 +986,8 @@ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
         {NULL, NULL}
     };
     size_t c;
-    const char *tmp_str;
+    size_t d;
+    struct ldb_message_element *tmp_el;
 
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) {
@@ -1016,12 +1020,15 @@ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
             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;
+        attrs = req_attrs;
+        if (attrs == NULL) {
+            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,
@@ -1050,14 +1057,16 @@ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
     }
 
     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;
+        tmp_el = ldb_msg_find_element(override, attr_map[c].attr);
+        if (tmp_el != NULL) {
+            for (d = 0; d < tmp_el->num_values; d++) {
+                ret = ldb_msg_add_steal_value(obj, attr_map[c].new_attr,
+                                              &tmp_el->values[d]);
+                if (ret != LDB_SUCCESS) {
+                    DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_value failed.\n");
+                    ret = sysdb_error_to_errno(ret);
+                    goto done;
+                }
             }
         }
     }
diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 28275ac..5fe498a 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -4035,7 +4035,7 @@ static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
             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);
+                                                        NULL, NULL);
                     if (ret != EOK) {
                         DEBUG(SSSDBG_OP_FAILURE,
                               "sysdb_add_overrides_to_object failed.\n");
-- 
1.8.3.1

-------------- next part --------------
From 2e94de268de9bafa24aeb969699a272b3c6e3119 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Thu, 16 Oct 2014 13:17:37 +0200
Subject: [PATCH 4/6] Views: apply user SSH public key override

With this patch the SSH public key override attribute is read from the
FreeIPA server and saved in the cache with the other override data.

Since it is possible to have multiple public SSH keys this override
value does not replace any other data but will be added to existing
values.

Fixes https://fedorahosted.org/sssd/ticket/2454
---
 src/db/sysdb_views.c           |  38 +++++++++----
 src/man/sssd-ipa.5.xml         |   3 +
 src/providers/ipa/ipa_common.h |   1 +
 src/providers/ipa/ipa_opts.h   |   1 +
 src/responder/ssh/sshsrv_cmd.c | 123 +++++++++++++++++++++++++++++++----------
 5 files changed, 126 insertions(+), 40 deletions(-)

diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
index f2cf370..27b5870 100644
--- a/src/db/sysdb_views.c
+++ b/src/db/sysdb_views.c
@@ -560,6 +560,8 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain,
     TALLOC_CTX *tmp_ctx;
     struct sysdb_attrs *attrs;
     size_t c;
+    size_t d;
+    size_t num_values;
     struct ldb_message_element *el = NULL;
     const char *allowed_attrs[] = { SYSDB_UIDNUM,
                                     SYSDB_GIDNUM,
@@ -567,6 +569,7 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain,
                                     SYSDB_HOMEDIR,
                                     SYSDB_SHELL,
                                     SYSDB_NAME,
+                                    SYSDB_SSH_PUBKEY,
                                     NULL };
     bool override_attrs_found = false;
 
@@ -584,7 +587,6 @@ 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) {
@@ -607,17 +609,30 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain,
                     goto done;
                 }
             } else {
-                ret = sysdb_attrs_add_val(attrs,  allowed_attrs[c],
-                                          &el->values[0]);
-                if (ret != EOK) {
-                    DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_val failed.\n");
-                    goto done;
+                num_values = el->num_values;
+                /* Only SYSDB_SSH_PUBKEY is allowed to have multiple values. */
+                if (strcmp(allowed_attrs[c], SYSDB_SSH_PUBKEY) != 0
+                        && num_values != 1) {
+                    DEBUG(SSSDBG_MINOR_FAILURE,
+                          "Override attribute for [%s] has more [%zd] " \
+                          "than one value, using only the first.\n",
+                          allowed_attrs[c], num_values);
+                    num_values = 1;
+                }
+
+                for (d = 0; d < num_values; d++) {
+                    ret = sysdb_attrs_add_val(attrs,  allowed_attrs[c],
+                                              &el->values[d]);
+                    if (ret != EOK) {
+                        DEBUG(SSSDBG_OP_FAILURE,
+                              "sysdb_attrs_add_val failed.\n");
+                        goto done;
+                    }
+                    DEBUG(SSSDBG_TRACE_ALL,
+                          "Override [%s] with [%.*s] for [%s].\n",
+                          allowed_attrs[c], (int) el->values[d].length,
+                          el->values[d].data, ldb_dn_get_linearized(obj_dn));
                 }
-                DEBUG(SSSDBG_TRACE_ALL, "Override [%s] with [%.*s] for [%s].\n",
-                                        allowed_attrs[c],
-                                        (int) el->values[0].length,
-                                        el->values[0].data,
-                                        ldb_dn_get_linearized(obj_dn));
             }
         } else if (ret != ENOENT) {
             DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el_ext failed.\n");
@@ -983,6 +998,7 @@ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
         {SYSDB_HOMEDIR, OVERRIDE_PREFIX SYSDB_HOMEDIR},
         {SYSDB_SHELL, OVERRIDE_PREFIX SYSDB_SHELL},
         {SYSDB_NAME, OVERRIDE_PREFIX SYSDB_NAME},
+        {SYSDB_SSH_PUBKEY, OVERRIDE_PREFIX SYSDB_SSH_PUBKEY},
         {NULL, NULL}
     };
     size_t c;
diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
index 51f14f8..e8a716c 100644
--- a/src/man/sssd-ipa.5.xml
+++ b/src/man/sssd-ipa.5.xml
@@ -626,6 +626,9 @@
                                     <listitem>
                                         <para>ldap_user_shell</para>
                                     </listitem>
+                                    <listitem>
+                                        <para>ldap_user_ssh_public_key</para>
+                                    </listitem>
                                 </itemizedlist>
                             </para>
                             <para>
diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
index 0e9324f..4952765 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -128,6 +128,7 @@ enum ipa_override_attrs {
     IPA_AT_OVERRIDE_SHELL,
     IPA_AT_OVERRIDE_GROUP_NAME,
     IPA_AT_OVERRIDE_GROUP_GID_NUMBER,
+    IPA_AT_OVERRIDE_USER_SSH_PUBLIC_KEY,
 
     IPA_OPTS_OVERRIDE
 };
diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
index 4785e01..32f5ebe 100644
--- a/src/providers/ipa/ipa_opts.h
+++ b/src/providers/ipa/ipa_opts.h
@@ -283,6 +283,7 @@ struct sdap_attr_map ipa_override_map[] = {
     { "ldap_user_shell", "loginShell", SYSDB_SHELL, NULL },
     { "ldap_group_name", "cn", SYSDB_NAME, NULL },
     { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
+    { "ldap_user_ssh_public_key", "ipaSshPubKey", SYSDB_SSH_PUBKEY, NULL },
     SDAP_ATTR_MAP_TERMINATOR
 };
 
diff --git a/src/responder/ssh/sshsrv_cmd.c b/src/responder/ssh/sshsrv_cmd.c
index ad83163..5bed2e0 100644
--- a/src/responder/ssh/sshsrv_cmd.c
+++ b/src/responder/ssh/sshsrv_cmd.c
@@ -232,8 +232,8 @@ ssh_user_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx)
         return EFAULT;
     }
 
-    ret = sysdb_get_user_attr(cmd_ctx, cmd_ctx->domain,
-                              cmd_ctx->name, attrs, &res);
+    ret = sysdb_get_user_attr_with_views(cmd_ctx, cmd_ctx->domain,
+                                         cmd_ctx->name, attrs, &res);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE,
               "Failed to make request to our cache!\n");
@@ -782,6 +782,65 @@ ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx)
     return EOK;
 }
 
+static errno_t decode_and_add_base64_data(struct ssh_cmd_ctx *cmd_ctx,
+                                          struct ldb_message_element *el,
+                                          size_t fqname_len,
+                                          const char *fqname,
+                                          size_t *c)
+{
+    struct cli_ctx *cctx = cmd_ctx->cctx;
+    uint8_t *key;
+    size_t key_len;
+    uint8_t *body;
+    size_t body_len;
+    int ret;
+    size_t d;
+    TALLOC_CTX *tmp_ctx;
+
+    if (el == NULL) {
+        DEBUG(SSSDBG_TRACE_ALL, "Mssing element, nothing to do.\n");
+        return EOK;
+    }
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+        return ENOMEM;
+    }
+
+    for (d = 0; d < el->num_values; d++) {
+        key = sss_base64_decode(tmp_ctx, (const char *) el->values[d].data,
+                                &key_len);
+        if (key == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+
+        ret = sss_packet_grow(cctx->creq->out,
+                              3*sizeof(uint32_t) + key_len + fqname_len);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n");
+            goto done;
+        }
+        sss_packet_get_body(cctx->creq->out, &body, &body_len);
+
+        SAFEALIGN_SET_UINT32(body+(*c), 0, c);
+        SAFEALIGN_SET_UINT32(body+(*c), fqname_len, c);
+        safealign_memcpy(body+(*c), fqname, fqname_len, c);
+        SAFEALIGN_SET_UINT32(body+(*c), key_len, c);
+        safealign_memcpy(body+(*c), key, key_len, c);
+
+    }
+
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+
+    return ret;
+}
+
 static errno_t
 ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx)
 {
@@ -790,14 +849,13 @@ ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx)
     uint8_t *body;
     size_t body_len;
     size_t c = 0;
-    unsigned int i;
-    struct ldb_message_element *el;
+    struct ldb_message_element *el = NULL;
+    struct ldb_message_element *el_override = NULL;
+    struct ldb_message_element *el_orig = NULL;
     uint32_t count = 0;
     const char *name;
     char *fqname;
     uint32_t fqname_len;
-    uint8_t *key;
-    size_t key_len;
 
     ret = sss_packet_new(cctx->creq, 0,
                          sss_packet_get_cmd(cctx->creq->in),
@@ -811,6 +869,20 @@ ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx)
         count = el->num_values;
     }
 
+    el_orig = ldb_msg_find_element(cmd_ctx->result,
+                                  ORIGINALAD_PREFIX SYSDB_SSH_PUBKEY);
+    if (el_orig) {
+        count = el_orig->num_values;
+    }
+
+    if (DOM_HAS_VIEWS(cmd_ctx->domain)) {
+        el_override = ldb_msg_find_element(cmd_ctx->result,
+                                           OVERRIDE_PREFIX SYSDB_SSH_PUBKEY);
+        if (el_override) {
+            count += el_override->num_values;
+        }
+    }
+
     ret = sss_packet_grow(cctx->creq->out, 2*sizeof(uint32_t));
     if (ret != EOK) {
         return ret;
@@ -820,7 +892,7 @@ ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx)
     SAFEALIGN_SET_UINT32(body+c, count, &c);
     SAFEALIGN_SET_UINT32(body+c, 0, &c);
 
-    if (!el) {
+    if (count == 0) {
         return EOK;
     }
 
@@ -840,30 +912,23 @@ ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx)
 
     fqname_len = strlen(fqname)+1;
 
-    for (i = 0; i < el->num_values; i++) {
-        key = sss_base64_decode(cmd_ctx,
-                                (const char *)el->values[i].data,
-                                &key_len);
-        if (!key) {
-            return ENOMEM;
-        }
-
-        ret = sss_packet_grow(cctx->creq->out,
-                              3*sizeof(uint32_t) + key_len + fqname_len);
-        if (ret != EOK) {
-            talloc_free(key);
-            return ret;
-        }
-        sss_packet_get_body(cctx->creq->out, &body, &body_len);
+    ret = decode_and_add_base64_data(cmd_ctx, el, fqname_len, fqname, &c);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n");
+        return ret;
+    }
 
-        SAFEALIGN_SET_UINT32(body+c, 0, &c);
-        SAFEALIGN_SET_UINT32(body+c, fqname_len, &c);
-        safealign_memcpy(body+c, fqname, fqname_len, &c);
-        SAFEALIGN_SET_UINT32(body+c, key_len, &c);
-        safealign_memcpy(body+c, key, key_len, &c);
+    ret = decode_and_add_base64_data(cmd_ctx, el_orig, fqname_len, fqname, &c);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n");
+        return ret;
+    }
 
-        talloc_free(key);
-        count++;
+    ret = decode_and_add_base64_data(cmd_ctx, el_override, fqname_len, fqname,
+                                     &c);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n");
+        return ret;
     }
 
     return EOK;
-- 
1.8.3.1

-------------- next part --------------
From d21b192e1ad2b6a0bf4621aed9437164bc1ea525 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Tue, 28 Oct 2014 15:53:16 +0100
Subject: [PATCH 5/6] Add test for sysdb_add_overrides_to_object()

---
 Makefile.am                         |  15 +++
 src/tests/cmocka/test_sysdb_views.c | 235 ++++++++++++++++++++++++++++++++++++
 2 files changed, 250 insertions(+)
 create mode 100644 src/tests/cmocka/test_sysdb_views.c

diff --git a/Makefile.am b/Makefile.am
index 3c81295..6842e23 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -215,6 +215,7 @@ if HAVE_CMOCKA
         sss_sifp-tests \
         test_search_bases \
         sdap-tests \
+        test_sysdb_views \
         $(NULL)
 
 if BUILD_IFP
@@ -2058,6 +2059,20 @@ sss_sifp_tests_LDADD = \
     $(SSSD_INTERNAL_LTLIBS)
 endif # BUILD_IFP
 
+test_sysdb_views_SOURCES = \
+    src/tests/cmocka/test_sysdb_views.c \
+    $(NULL)
+test_sysdb_views_CFLAGS = \
+    $(AM_CFLAGS) \
+    $(NULL)
+test_sysdb_views_LDADD = \
+    $(CMOCKA_LIBS) \
+    $(POPT_LIBS) \
+    $(TALLOC_LIBS) \
+    $(SSSD_INTERNAL_LTLIBS) \
+    libsss_test_common.la \
+    $(NULL)
+
 endif # HAVE_CMOCKA
 
 noinst_PROGRAMS = pam_test_client
diff --git a/src/tests/cmocka/test_sysdb_views.c b/src/tests/cmocka/test_sysdb_views.c
new file mode 100644
index 0000000..38525d6
--- /dev/null
+++ b/src/tests/cmocka/test_sysdb_views.c
@@ -0,0 +1,235 @@
+/*
+    SSSD
+
+    sysdb_views - Tests for view and override related sysdb calls
+
+    Authors:
+        Sumit Bose <sbose at redhat.com>
+
+    Copyright (C) 2014 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <popt.h>
+
+#include "tests/cmocka/common_mock.h"
+
+#define TESTS_PATH "tests_sysdb"
+#define TEST_CONF_FILE "tests_conf.ldb"
+
+struct sysdb_test_ctx {
+    struct sysdb_ctx *sysdb;
+    struct confdb_ctx *confdb;
+    struct tevent_context *ev;
+    struct sss_domain_info *domain;
+};
+
+static int _setup_sysdb_tests(struct sysdb_test_ctx **ctx, bool enumerate)
+{
+    struct sysdb_test_ctx *test_ctx;
+    char *conf_db;
+    int ret;
+
+    const char *val[2];
+    val[1] = NULL;
+
+    /* Create tests directory if it doesn't exist */
+    /* (relative to current dir) */
+    ret = mkdir(TESTS_PATH, 0775);
+    assert_true(ret == 0 || errno == EEXIST);
+
+    test_ctx = talloc_zero(global_talloc_context, struct sysdb_test_ctx);
+    assert_non_null(test_ctx);
+
+    /* Create an event context
+     * It will not be used except in confdb_init and sysdb_init
+     */
+    test_ctx->ev = tevent_context_init(test_ctx);
+    assert_non_null(test_ctx->ev);
+
+    conf_db = talloc_asprintf(test_ctx, "%s/%s", TESTS_PATH, TEST_CONF_FILE);
+    assert_non_null(conf_db);
+    DEBUG(SSSDBG_MINOR_FAILURE, "CONFDB: %s\n", conf_db);
+
+    /* Connect to the conf db */
+    ret = confdb_init(test_ctx, &test_ctx->confdb, conf_db);
+    assert_int_equal(ret, EOK);
+
+    val[0] = "LOCAL";
+    ret = confdb_add_param(test_ctx->confdb, true,
+                           "config/sssd", "domains", val);
+    assert_int_equal(ret, EOK);
+
+    val[0] = "local";
+    ret = confdb_add_param(test_ctx->confdb, true,
+                           "config/domain/LOCAL", "id_provider", val);
+    assert_int_equal(ret, EOK);
+
+    val[0] = enumerate ? "TRUE" : "FALSE";
+    ret = confdb_add_param(test_ctx->confdb, true,
+                           "config/domain/LOCAL", "enumerate", val);
+    assert_int_equal(ret, EOK);
+
+    val[0] = "TRUE";
+    ret = confdb_add_param(test_ctx->confdb, true,
+                           "config/domain/LOCAL", "cache_credentials", val);
+    assert_int_equal(ret, EOK);
+
+    ret = sssd_domain_init(test_ctx, test_ctx->confdb, "local",
+                           TESTS_PATH, &test_ctx->domain);
+    assert_int_equal(ret, EOK);
+
+    test_ctx->sysdb = test_ctx->domain->sysdb;
+
+    *ctx = test_ctx;
+    return EOK;
+}
+
+#define setup_sysdb_tests(ctx) _setup_sysdb_tests((ctx), false)
+
+static void test_sysdb_setup(void **state)
+{
+    int ret;
+    struct sysdb_test_ctx *test_ctx;
+
+    assert_true(leak_check_setup());
+
+    ret = setup_sysdb_tests(&test_ctx);
+    assert_int_equal(ret, EOK);
+
+    *state = (void *) test_ctx;
+}
+
+static void test_sysdb_teardown(void **state)
+{
+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct sysdb_test_ctx);
+
+    talloc_free(test_ctx);
+    assert_true(leak_check_teardown());
+}
+
+void test_sysdb_add_overrides_to_object(void **state)
+{
+    int ret;
+    struct ldb_message *orig;
+    struct ldb_message *override;
+    struct ldb_message_element *el;
+    char *tmp_str;
+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct sysdb_test_ctx);
+
+    orig = ldb_msg_new(test_ctx);
+    assert_non_null(orig);
+
+    tmp_str = talloc_strdup(orig,  "ORIGNAME");
+    ret = ldb_msg_add_string(orig, SYSDB_NAME, tmp_str);
+    assert_int_equal(ret, EOK);
+
+    tmp_str = talloc_strdup(orig,  "ORIGGECOS");
+    ret = ldb_msg_add_string(orig, SYSDB_GECOS, tmp_str);
+    assert_int_equal(ret, EOK);
+
+    override = ldb_msg_new(test_ctx);
+    assert_non_null(override);
+
+    tmp_str = talloc_strdup(override, "OVERRIDENAME");
+    ret = ldb_msg_add_string(override, SYSDB_NAME, tmp_str);
+    assert_int_equal(ret, EOK);
+
+    tmp_str = talloc_strdup(override, "OVERRIDEGECOS");
+    ret = ldb_msg_add_string(override, SYSDB_GECOS, tmp_str);
+    assert_int_equal(ret, EOK);
+
+    tmp_str = talloc_strdup(override, "OVERRIDEKEY1");
+    ret = ldb_msg_add_string(override, SYSDB_SSH_PUBKEY, tmp_str);
+    assert_int_equal(ret, EOK);
+
+    tmp_str = talloc_strdup(override, "OVERRIDEKEY2");
+    ret = ldb_msg_add_string(override, SYSDB_SSH_PUBKEY, tmp_str);
+    assert_int_equal(ret, EOK);
+
+
+    ret = sysdb_add_overrides_to_object(test_ctx->domain, orig, override, NULL);
+    assert_int_equal(ret, EOK);
+
+    assert_string_equal(ldb_msg_find_attr_as_string(orig, SYSDB_NAME, NULL),
+                        "ORIGNAME");
+    assert_string_equal(ldb_msg_find_attr_as_string(orig, SYSDB_GECOS, NULL),
+                        "ORIGGECOS");
+    assert_string_equal(ldb_msg_find_attr_as_string(orig,
+                                                    OVERRIDE_PREFIX SYSDB_NAME,
+                                                    NULL),
+                        "OVERRIDENAME");
+    assert_string_equal(ldb_msg_find_attr_as_string(orig,
+                                                    OVERRIDE_PREFIX SYSDB_GECOS,
+                                                    NULL),
+                        "OVERRIDEGECOS");
+
+    el = ldb_msg_find_element(orig, OVERRIDE_PREFIX SYSDB_SSH_PUBKEY);
+    assert_non_null(el);
+    assert_int_equal(el->num_values, 2);
+    assert_int_equal(ldb_val_string_cmp(&el->values[0], "OVERRIDEKEY1"), 0);
+    assert_int_equal(ldb_val_string_cmp(&el->values[1], "OVERRIDEKEY2"), 0);
+}
+
+int main(int argc, const char *argv[])
+{
+    int rv;
+    int no_cleanup = 0;
+    poptContext pc;
+    int opt;
+    struct poptOption long_options[] = {
+        POPT_AUTOHELP
+        SSSD_DEBUG_OPTS
+        {"no-cleanup", 'n', POPT_ARG_NONE, &no_cleanup, 0,
+         _("Do not delete the test database after a test run"), NULL },
+        POPT_TABLEEND
+    };
+
+    const UnitTest tests[] = {
+        unit_test_setup_teardown(test_sysdb_add_overrides_to_object,
+                                 test_sysdb_setup, test_sysdb_teardown),
+    };
+
+    /* Set debug level to invalid value so we can deside if -d 0 was used. */
+    debug_level = SSSDBG_INVALID;
+
+    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+    while((opt = poptGetNextOpt(pc)) != -1) {
+        switch(opt) {
+        default:
+            fprintf(stderr, "\nInvalid option %s: %s\n\n",
+                    poptBadOption(pc, 0), poptStrerror(opt));
+            poptPrintUsage(pc, stderr, 0);
+            return 1;
+        }
+    }
+    poptFreeContext(pc);
+
+    DEBUG_CLI_INIT(debug_level);
+
+    tests_set_cwd();
+    rv = run_tests(tests);
+
+    if (rv == 0 && no_cleanup == 0) {
+        test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_FILE, LOCAL_SYSDB_FILE);
+    }
+    return rv;
+}
-- 
1.8.3.1

-------------- next part --------------
From fc81e59f58a568af1bc6a21aced45f6b8c26db24 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Tue, 4 Nov 2014 13:58:39 +0100
Subject: [PATCH 6/6] Add ssh pubkey to origbyname request

Since the IPA clients expects that the extdom plugin delivers the
default view data for a given user this patch adds the public SSH key to
the list of returned attributes of the getorigbyname request so that it
can be send back to the clients.
---
 src/responder/nss/nsssrv_cmd.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 5fe498a..d50b5a9 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -4130,6 +4130,7 @@ static errno_t nss_cmd_getsidby_search(struct nss_dom_ctx *dctx)
                                    SYSDB_DEFAULT_OVERRIDE_NAME,
                                    SYSDB_AD_ACCOUNT_EXPIRES,
                                    SYSDB_AD_USER_ACCOUNT_CONTROL,
+                                   SYSDB_SSH_PUBKEY,
                                    SYSDB_DEFAULT_ATTRS, NULL};
     const char **attrs;
     bool user_found = false;
@@ -4603,6 +4604,7 @@ static errno_t fill_orig(struct sss_packet *packet,
                                     SYSDB_DEFAULT_OVERRIDE_NAME,
                                     SYSDB_AD_ACCOUNT_EXPIRES,
                                     SYSDB_AD_USER_ACCOUNT_CONTROL,
+                                    SYSDB_SSH_PUBKEY,
                                     NULL};
     struct sized_string *keys;
     struct sized_string *vals;
-- 
1.8.3.1



More information about the sssd-devel mailing list