>From 6d9ead715e08e50678084c221605cbd40a662546 Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jcholast@redhat.com>
Date: Fri, 24 Aug 2012 03:07:56 -0400
Subject: [PATCH] SSH: Parse OpenSSH formatted public keys

---
 src/util/sss_ssh.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 src/util/sss_ssh.h |  5 +--
 2 files changed, 95 insertions(+), 8 deletions(-)

diff --git a/src/util/sss_ssh.c b/src/util/sss_ssh.c
index 60ed587..ba1a4bc 100644
--- a/src/util/sss_ssh.c
+++ b/src/util/sss_ssh.c
@@ -111,25 +111,99 @@ done:
     return ret;
 }
 
-char *
+errno_t
 sss_ssh_get_pubkey_algorithm(TALLOC_CTX *mem_ctx,
-                             struct sss_ssh_pubkey *pubkey)
+                             struct sss_ssh_pubkey *pubkey,
+                             char **result)
 {
     size_t c = 0;
     uint32_t algo_len;
     char *algo;
 
+    if (pubkey->data_len < 4) {
+        return EINVAL;
+    }
+
     SAFEALIGN_COPY_UINT32(&algo_len, pubkey->data, &c);
     algo_len = ntohl(algo_len);
+    if (algo_len > pubkey->data_len - 4) {
+        return EINVAL;
+    }
 
     algo = talloc_zero_array(mem_ctx, char, algo_len+1);
     if (!algo) {
-        return NULL;
+        return ENOMEM;
     }
 
     memcpy(algo, pubkey->data+c, algo_len);
 
-    return algo;
+    *result = algo;
+    return EOK;
+}
+
+static errno_t
+sss_ssh_parse_openssh_pubkey(TALLOC_CTX *mem_ctx,
+                             const char *pubkeystr,
+                             struct sss_ssh_pubkey *result)
+{
+    TALLOC_CTX *tmp_ctx;
+    errno_t ret;
+    char *data, *algo_start, *algo_end, *key_start, *key_end, *key_algo;
+    struct sss_ssh_pubkey pubkey;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    data = talloc_asprintf(tmp_ctx, "%s ", pubkeystr);
+    if (!data) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    key_start = data;
+    key_end = strchr(key_start, ' ');
+    if (!key_end) {
+        ret = EINVAL;
+        goto done;
+    }
+    *key_end = 0;
+
+    while (1) {
+        algo_start = key_start;
+        algo_end = key_end;
+
+        key_start = algo_end + 1;
+        key_end = strchr(key_start, ' ');
+        if (!key_end) {
+            ret = EINVAL;
+            goto done;
+        }
+        *key_end = 0;
+
+        pubkey.data = sss_base64_decode(tmp_ctx, key_start, &pubkey.data_len);
+        if (!pubkey.data) {
+            continue;
+        }
+
+        ret = sss_ssh_get_pubkey_algorithm(tmp_ctx, &pubkey, &key_algo);
+        if (ret == EOK && strcmp(key_algo, algo_start) == 0) {
+            break;
+        }
+
+        talloc_free(pubkey.data);
+        talloc_free(key_algo);
+    }
+
+    result->data = talloc_steal(mem_ctx, pubkey.data);
+    result->data_len = pubkey.data_len;
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+
+    return ret;
 }
 
 char *
@@ -140,6 +214,9 @@ sss_ssh_format_pubkey(TALLOC_CTX *mem_ctx,
                       const char *comment)
 {
     TALLOC_CTX *tmp_ctx;
+    errno_t ret;
+    size_t len;
+    struct sss_ssh_pubkey parsed;
     char *blob;
     char *algo;
     char *result = NULL;
@@ -153,6 +230,15 @@ sss_ssh_format_pubkey(TALLOC_CTX *mem_ctx,
         return NULL;
     }
 
+    len = strnlen((const char *)pubkey->data, pubkey->data_len + 1);
+    if (len == pubkey->data_len) {
+        ret = sss_ssh_parse_openssh_pubkey(tmp_ctx, (const char *)pubkey->data,
+                                           &parsed);
+        if (ret == EOK) {
+            pubkey = &parsed;
+        }
+    }
+
     blob = sss_base64_encode(tmp_ctx, pubkey->data, pubkey->data_len);
     if (!blob) {
         goto done;
@@ -166,8 +252,8 @@ sss_ssh_format_pubkey(TALLOC_CTX *mem_ctx,
 
     case SSS_SSH_FORMAT_OPENSSH:
         /* OpenSSH authorized_keys/known_hosts format */
-        algo = sss_ssh_get_pubkey_algorithm(tmp_ctx, pubkey);
-        if (!algo) {
+        ret = sss_ssh_get_pubkey_algorithm(tmp_ctx, pubkey, &algo);
+        if (ret != EOK) {
             goto done;
         }
 
diff --git a/src/util/sss_ssh.h b/src/util/sss_ssh.h
index 29743a0..6aa04c2 100644
--- a/src/util/sss_ssh.h
+++ b/src/util/sss_ssh.h
@@ -41,9 +41,10 @@ sss_ssh_make_ent(TALLOC_CTX *mem_ctx,
                  struct ldb_message *msg,
                  struct sss_ssh_ent **result);
 
-char *
+errno_t
 sss_ssh_get_pubkey_algorithm(TALLOC_CTX *mem_ctx,
-                             struct sss_ssh_pubkey *pubkey);
+                             struct sss_ssh_pubkey *pubkey,
+                             char **result);
 
 enum sss_ssh_pubkey_format {
     SSS_SSH_FORMAT_RAW,
-- 
1.7.11.4


