>From e6c2f57356ed636d77187ae0e1721e8fb37482ba Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jcholast@redhat.com>
Date: Fri, 26 Apr 2013 10:45:42 +0200
Subject: [PATCH 3/4] SSH: Use separate field for domain name in client
 requests

Instead of appending @domain to names when the --domain option of sss_ssh_* is
used, put domain name in a separate field in client requests.
---
 src/responder/ssh/sshsrv_cmd.c               | 91 +++++++++++++++++++---------
 src/sss_client/ssh/sss_ssh_authorizedkeys.c  | 15 +----
 src/sss_client/ssh/sss_ssh_client.c          | 38 ++++++++----
 src/sss_client/ssh/sss_ssh_client.h          |  1 +
 src/sss_client/ssh/sss_ssh_knownhostsproxy.c | 12 +---
 src/util/sss_ssh.h                           |  4 ++
 6 files changed, 97 insertions(+), 64 deletions(-)

diff --git a/src/responder/ssh/sshsrv_cmd.c b/src/responder/ssh/sshsrv_cmd.c
index d7e3ed9..91a143d 100644
--- a/src/responder/ssh/sshsrv_cmd.c
+++ b/src/responder/ssh/sshsrv_cmd.c
@@ -685,12 +685,14 @@ ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx)
     uint32_t name_len;
     char *name;
     uint32_t alias_len;
-    char *alias;
+    char *alias = NULL;
+    uint32_t domain_len;
+    char *domain = cctx->rctx->default_domain;
 
     sss_packet_get_body(cctx->creq->in, &body, &body_len);
 
     SAFEALIGN_COPY_UINT32_CHECK(&flags, body+c, body_len, &c);
-    if (flags > 1) {
+    if (flags & ~(uint32_t)SSS_SSH_REQ_MASK) {
         DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid flags received [0x%x]\n", flags));
         return EINVAL;
     }
@@ -709,28 +711,7 @@ ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx)
     }
     c += name_len;
 
-    ret = sss_parse_name(cmd_ctx, ssh_ctx->snctx, name,
-                         &cmd_ctx->domname, &cmd_ctx->name);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE, ("Invalid name received [%s]\n", name));
-        return ENOENT;
-    }
-
-    if (cmd_ctx->is_user && cmd_ctx->domname == NULL) {
-        name = cmd_ctx->name;
-
-        ret = sss_parse_name_for_domains(cmd_ctx, cctx->rctx->domains,
-                                         cctx->rctx->default_domain, name,
-                                         &cmd_ctx->domname,
-                                         &cmd_ctx->name);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_OP_FAILURE,
-                  ("Invalid name received [%s]\n", name));
-            return ENOENT;
-        }
-    }
-
-    if (flags & 1) {
+    if (flags & SSS_SSH_REQ_ALIAS) {
         SAFEALIGN_COPY_UINT32_CHECK(&alias_len, body+c, body_len, &c);
         if (alias_len == 0 || alias_len > body_len - c) {
             DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid alias length\n"));
@@ -744,11 +725,67 @@ ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx)
             return EINVAL;
         }
         c += alias_len;
+    }
 
-        if (strcmp(cmd_ctx->name, alias) != 0) {
-            cmd_ctx->alias = talloc_strdup(cmd_ctx, alias);
-            if (!cmd_ctx->alias) return ENOMEM;
+    if (flags & SSS_SSH_REQ_DOMAIN) {
+        SAFEALIGN_COPY_UINT32_CHECK(&domain_len, body+c, body_len, &c);
+        if (domain_len > 0) {
+            if (domain_len > body_len - c) {
+                DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid domain length\n"));
+                return EINVAL;
+            }
+
+            domain = (char *)(body+c);
+            if (!sss_utf8_check((const uint8_t *)domain, domain_len-1) ||
+                    domain[domain_len-1] != 0) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      ("Domain is not valid UTF-8 string\n"));
+                return EINVAL;
+            }
+            c += domain_len;
         }
+
+        DEBUG(SSSDBG_TRACE_FUNC,
+              ("Requested domain [%s]\n", domain ? domain : "<ALL>"));
+    } else {
+        DEBUG(SSSDBG_TRACE_FUNC, ("Splitting domain from name [%s]\n", name));
+
+        ret = sss_parse_name(cmd_ctx, ssh_ctx->snctx, name,
+                             &cmd_ctx->domname, &cmd_ctx->name);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, ("Invalid name received [%s]\n", name));
+            return ENOENT;
+        }
+
+        name = cmd_ctx->name;
+    }
+
+    if (cmd_ctx->is_user && cmd_ctx->domname == NULL) {
+        DEBUG(SSSDBG_TRACE_FUNC,
+              ("Parsing name [%s][%s]\n", name, domain ? domain : "<ALL>"));
+
+        ret = sss_parse_name_for_domains(cmd_ctx, cctx->rctx->domains,
+                                         domain, name,
+                                         &cmd_ctx->domname,
+                                         &cmd_ctx->name);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  ("Invalid name received [%s]\n", name));
+            return ENOENT;
+        }
+    } else if (cmd_ctx->name == NULL && cmd_ctx->domname == NULL) {
+        cmd_ctx->name = talloc_strdup(cmd_ctx, name);
+        if (!cmd_ctx->name) return ENOMEM;
+
+        if (domain != NULL) {
+            cmd_ctx->domname = talloc_strdup(cmd_ctx, domain);
+            if (!cmd_ctx->domname) return ENOMEM;
+        }
+    }
+
+    if (alias != NULL && strcmp(cmd_ctx->name, alias) != 0) {
+        cmd_ctx->alias = talloc_strdup(cmd_ctx, alias);
+        if (!cmd_ctx->alias) return ENOMEM;
     }
 
     return EOK;
diff --git a/src/sss_client/ssh/sss_ssh_authorizedkeys.c b/src/sss_client/ssh/sss_ssh_authorizedkeys.c
index 11deff9..bc991a8 100644
--- a/src/sss_client/ssh/sss_ssh_authorizedkeys.c
+++ b/src/sss_client/ssh/sss_ssh_authorizedkeys.c
@@ -43,7 +43,6 @@ int main(int argc, const char **argv)
         POPT_TABLEEND
     };
     poptContext pc = NULL;
-    const char *user;
     struct sss_ssh_ent *ent;
     size_t i;
     char *repr;
@@ -84,21 +83,9 @@ int main(int argc, const char **argv)
         BAD_POPT_PARAMS(pc, _("User not specified\n"), ret, fini);
     }
 
-    /* append domain to username if domain is specified */
-    if (pc_domain) {
-        user = talloc_asprintf(mem_ctx, "%s@%s", pc_user, pc_domain);
-        if (!user) {
-            ERROR("Not enough memory\n");
-            ret = EXIT_FAILURE;
-            goto fini;
-        }
-    } else {
-        user = pc_user;
-    }
-
     /* look up public keys */
     ret = sss_ssh_get_ent(mem_ctx, SSS_SSH_GET_USER_PUBKEYS,
-                          user, NULL, &ent);
+                          pc_user, pc_domain, NULL, &ent);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE,
               ("sss_ssh_get_ent() failed (%d): %s\n", ret, strerror(ret)));
diff --git a/src/sss_client/ssh/sss_ssh_client.c b/src/sss_client/ssh/sss_ssh_client.c
index 645f292..5312dba 100644
--- a/src/sss_client/ssh/sss_ssh_client.c
+++ b/src/sss_client/ssh/sss_ssh_client.c
@@ -70,29 +70,34 @@ int set_locale(void)
 
 /* SSH public key request:
  * 
- * 0..3:     flags (unsigned int, must be 0 or 1)
- * 4..7:     name length (unsigned int)
- * 8..(X-1): name (null-terminated UTF-8 string)
- * if (flags & 1) {
- *   X..(X+3): alias length (unsigned int)
- *   (X+4)..Y: alias (null-terminated UTF-8 string)
- * }
+ * header:
+ *   0..3: flags (unsigned int, must be combination of SSS_SSH_REQ_* flags)
+ *   4..7: name length (unsigned int)
+ *   8..X: name (null-terminated UTF-8 string)
+ * alias (only included if flags & SSS_SSH_REQ_ALIAS):
+ *   0..3: alias length (unsigned int)
+ *   4..X: alias (null-terminated UTF-8 string)
+ * domain (ony included if flags & SSS_SSH_REQ_DOMAIN):
+ *   0..3: domain length (unsigned int, 0 means default domain)
+ *   4..X: domain (null-terminated UTF-8 string)
  * 
  * SSH public key reply:
  * 
- * 0..3: number of results (unsigned int)
- * 4..7: reserved (unsigned int, must be 0)
- * 8..$: array of results:
+ * header:
+ *   0..3: number of results (unsigned int)
+ *   4..7: reserved (unsigned int, must be 0)
+ * results (repeated for each result):
  *   0..3:     flags (unsigned int, must be 0)
  *   4..7:     name length (unsigned int)
  *   8..(X-1): name (null-terminated UTF-8 string)
  *   X..(X+3): key length (unsigned int)
- *   (X+4)..Y: key (public key blob as defined in RFC4253, section 6.6)
+ *   (X+4)..Y: key (public key data)
  */
 errno_t
 sss_ssh_get_ent(TALLOC_CTX *mem_ctx,
                 enum sss_cli_command command,
                 const char *name,
+                const char *domain,
                 const char *alias,
                 struct sss_ssh_ent **result)
 {
@@ -102,6 +107,7 @@ sss_ssh_get_ent(TALLOC_CTX *mem_ctx,
     uint32_t flags;
     uint32_t name_len;
     uint32_t alias_len;
+    uint32_t domain_len;
     size_t req_len;
     uint8_t *req = NULL;
     size_t c = 0;
@@ -122,11 +128,15 @@ sss_ssh_get_ent(TALLOC_CTX *mem_ctx,
     req_len = 2*sizeof(uint32_t) + name_len;
 
     if (alias) {
-        flags |= 1;
+        flags |= SSS_SSH_REQ_ALIAS;
         alias_len = strlen(alias)+1;
         req_len += sizeof(uint32_t) + alias_len;
     }
 
+    flags |= SSS_SSH_REQ_DOMAIN;
+    domain_len = domain ? (strlen(domain)+1) : 0;
+    req_len += sizeof(uint32_t) + domain_len;
+
     req = talloc_array(tmp_ctx, uint8_t, req_len);
     if (!req) {
         ret = ENOMEM;
@@ -140,6 +150,10 @@ sss_ssh_get_ent(TALLOC_CTX *mem_ctx,
         SAFEALIGN_SET_UINT32(req+c, alias_len, &c);
         safealign_memcpy(req+c, alias, alias_len, &c);
     }
+    SAFEALIGN_SET_UINT32(req+c, domain_len, &c);
+    if (domain_len > 0) {
+        safealign_memcpy(req+c, domain, domain_len, &c);
+    }
 
     /* send request */
     rd.data = req;
diff --git a/src/sss_client/ssh/sss_ssh_client.h b/src/sss_client/ssh/sss_ssh_client.h
index 7ffc398..5ad0643 100644
--- a/src/sss_client/ssh/sss_ssh_client.h
+++ b/src/sss_client/ssh/sss_ssh_client.h
@@ -34,6 +34,7 @@ errno_t
 sss_ssh_get_ent(TALLOC_CTX *mem_ctx,
                 enum sss_cli_command command,
                 const char *name,
+                const char *domain,
                 const char *alias,
                 struct sss_ssh_ent **result);
 
diff --git a/src/sss_client/ssh/sss_ssh_knownhostsproxy.c b/src/sss_client/ssh/sss_ssh_knownhostsproxy.c
index 600895d..e2202b1 100644
--- a/src/sss_client/ssh/sss_ssh_knownhostsproxy.c
+++ b/src/sss_client/ssh/sss_ssh_knownhostsproxy.c
@@ -282,19 +282,9 @@ int main(int argc, const char **argv)
     }
 
     if (host) {
-        /* append domain to hostname if domain is specified */
-        if (pc_domain) {
-            host = talloc_asprintf(mem_ctx, "%s@%s", host, pc_domain);
-            if (!host) {
-                DEBUG(SSSDBG_CRIT_FAILURE, ("Not enough memory\n"));
-                ret = EXIT_FAILURE;
-                goto fini;
-            }
-        }
-
         /* look up public keys */
         ret = sss_ssh_get_ent(mem_ctx, SSS_SSH_GET_HOST_PUBKEYS,
-                              host, pc_host, &ent);
+                              host, pc_domain, pc_host, &ent);
         if (ret != EOK) {
             DEBUG(SSSDBG_OP_FAILURE,
                   ("sss_ssh_get_ent() failed (%d): %s\n", ret, strerror(ret)));
diff --git a/src/util/sss_ssh.h b/src/util/sss_ssh.h
index fec7c73..1ba50a6 100644
--- a/src/util/sss_ssh.h
+++ b/src/util/sss_ssh.h
@@ -21,6 +21,10 @@
 #ifndef _SSS_SSH_H_
 #define _SSS_SSH_H_
 
+#define SSS_SSH_REQ_ALIAS   0x01
+#define SSS_SSH_REQ_DOMAIN  0x02
+#define SSS_SSH_REQ_MASK    0x03
+
 struct sss_ssh_pubkey {
     uint8_t *data;
     size_t data_len;
-- 
1.8.1.4

