Blob Blame History Raw
From a5a3aaafd0c1399f83bd3144344eb9a0da436307 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 16 Oct 2014 13:17:37 +0200
Subject: [PATCH 62/64] 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

Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
 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 f2cf370231b57c3cd2b563eec4ea2a0f3a0935bd..27b58701fe0f9a4f545df5e4bfb884c04517d0d3 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 51f14f8fc16bd2843ef4b426938172c63608176e..e8a716c4104b8038e354b8ae544a04d6773e708b 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 0e9324f5b362085153abebcc4894bef607173607..495276548e57e91f9744dda6d8866971b627b4da 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 0e0eed49cd397fe88ce7bf41579c066088947d04..473eca4f77727e008663d082e954820a9fb0c427 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 ad831639841d42417008ea6c40c1dea045e5d6cf..5bed2e0adca0e6961337bb744729dd3e5a23c629 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 = 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;
+    }
 
-        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_orig, 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);
-
-        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.9.3