From 28e55560008f21a532b103b3f612c6fca2a54d76 Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Fri, 26 Apr 2013 10:45:42 +0200 Subject: 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 374abe6c6..d2f889fa6 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 : "")); + } 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 : "")); + + 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 11deff9a6..bc991a837 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 645f29289..5312dba2b 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 7ffc3983e..5ad0643f9 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 600895d1f..e2202b183 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 fec7c732b..1ba50a655 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; -- cgit