From 4fa3ef8d8a8a3cddf8025d306c3b90b37dd431bc Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Wed, 18 Apr 2012 07:05:29 -0400 Subject: SSH: Add support for hashed known_hosts https://fedorahosted.org/sssd/ticket/1203 --- src/confdb/confdb.h | 2 + src/config/SSSDConfig.py | 3 + src/config/etc/sssd.api.conf | 1 + src/man/sssd.conf.5.xml | 25 ++++ src/responder/ssh/sshsrv.c | 13 ++ src/responder/ssh/sshsrv_cmd.c | 192 ++++++++++++++++++++++------ src/responder/ssh/sshsrv_private.h | 2 + src/sss_client/ssh/sss_ssh_authorizedkeys.c | 2 +- src/util/sss_ssh.c | 9 +- src/util/sss_ssh.h | 3 +- 10 files changed, 212 insertions(+), 40 deletions(-) diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h index 78e375102..b90db303a 100644 --- a/src/confdb/confdb.h +++ b/src/confdb/confdb.h @@ -109,6 +109,8 @@ /* SSH */ #define CONFDB_SSH_CONF_ENTRY "config/ssh" +#define CONFDB_SSH_HASH_KNOWN_HOSTS "ssh_hash_known_hosts" +#define CONFDB_DEFAULT_SSH_HASH_KNOWN_HOSTS true /* Data Provider */ #define CONFDB_DP_CONF_ENTRY "config/dp" diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py index 20cd2a28a..d38014c28 100644 --- a/src/config/SSSDConfig.py +++ b/src/config/SSSDConfig.py @@ -82,6 +82,9 @@ option_strings = { # [autofs] 'autofs_negative_timeout' : _('Negative cache timeout length (seconds)'), + # [ssh] + 'ssh_hash_known_hosts': _('Whether to hash host names and adresses in the known_hosts file'), + # [provider] 'id_provider' : _('Identity provider'), 'auth_provider' : _('Authentication provider'), diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf index 17750ef9f..a7bece99a 100644 --- a/src/config/etc/sssd.api.conf +++ b/src/config/etc/sssd.api.conf @@ -58,6 +58,7 @@ autofs_negative_timeout = int, None, false [ssh] # ssh service +ssh_hash_known_hosts = bool, None, false [provider] #Available provider types diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml index 43eb36325..ef7490d94 100644 --- a/src/man/sssd.conf.5.xml +++ b/src/man/sssd.conf.5.xml @@ -729,6 +729,31 @@ + + SSH configuration options + + These options can be used to configure the SSH service. + + + + + + + + ssh_hash_known_hosts (bool) + + + Whether or not to hash host names and adresses in + the managed known_hosts file. + + + Default: true + + + + + + diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c index f0cee9f03..a423231b5 100644 --- a/src/responder/ssh/sshsrv.c +++ b/src/responder/ssh/sshsrv.c @@ -128,6 +128,19 @@ int ssh_process_init(TALLOC_CTX *mem_ctx, ssh_dp_reconnect_init, iter); } + /* Get responder options */ + + /* Get ssh_hash_known_hosts option */ + ret = confdb_get_bool(ssh_ctx->rctx->cdb, + CONFDB_SSH_CONF_ENTRY, CONFDB_SSH_HASH_KNOWN_HOSTS, + CONFDB_DEFAULT_SSH_HASH_KNOWN_HOSTS, + &ssh_ctx->hash_known_hosts); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, ("Error reading from confdb (%d) [%s]\n", + ret, strerror(ret))); + return ret; + } + DEBUG(SSSDBG_TRACE_FUNC, ("SSH Initialization complete\n")); return EOK; diff --git a/src/responder/ssh/sshsrv_cmd.c b/src/responder/ssh/sshsrv_cmd.c index 91b888ef4..4766ed8b5 100644 --- a/src/responder/ssh/sshsrv_cmd.c +++ b/src/responder/ssh/sshsrv_cmd.c @@ -417,6 +417,139 @@ ssh_host_pubkeys_search_dp_callback(uint16_t err_maj, ssh_cmd_done(cmd_ctx, ret); } +static char * +ssh_host_pubkeys_format_known_host_plain(TALLOC_CTX *mem_ctx, + struct sss_ssh_ent *ent) +{ + TALLOC_CTX *tmp_ctx; + char *name, *pubkey, *result; + size_t i; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + return NULL; + } + + name = talloc_strdup(tmp_ctx, ent->name); + if (!name) { + goto done; + } + + for (i = 0; i < ent->num_aliases; i++) { + name = talloc_asprintf_append(name, ",%s", ent->aliases[i]); + if (!name) { + goto done; + } + } + + result = talloc_strdup(tmp_ctx, ""); + if (!result) { + goto done; + } + + for (i = 0; i < ent->num_pubkeys; i++) { + pubkey = sss_ssh_format_pubkey(tmp_ctx, ent, &ent->pubkeys[i], + SSS_SSH_FORMAT_OPENSSH, ""); + if (!pubkey) { + result = NULL; + goto done; + } + + result = talloc_asprintf_append(result, "%s %s\n", name, pubkey); + if (!result) { + goto done; + } + + talloc_free(pubkey); + } + + talloc_steal(mem_ctx, result); + +done: + talloc_free(tmp_ctx); + + return result; +} + +static char * +ssh_host_pubkeys_format_known_host_hashed(TALLOC_CTX *mem_ctx, + struct sss_ssh_ent *ent) +{ + TALLOC_CTX *tmp_ctx; + errno_t ret; + char *name, *pubkey, *saltstr, *hashstr, *result; + unsigned char salt[SSS_SHA1_LENGTH], hash[SSS_SHA1_LENGTH]; + size_t i, j, k; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + return NULL; + } + + result = talloc_strdup(tmp_ctx, ""); + if (!result) { + goto done; + } + + for (i = 0; i < ent->num_pubkeys; i++) { + pubkey = sss_ssh_format_pubkey(tmp_ctx, ent, &ent->pubkeys[i], + SSS_SSH_FORMAT_OPENSSH, ""); + if (!pubkey) { + result = NULL; + goto done; + } + + for (j = 0; j <= ent->num_aliases; j++) { + name = (j == 0 ? ent->name : ent->aliases[j-1]); + + for (k = 0; k < SSS_SHA1_LENGTH; k++) { + salt[k] = rand(); + } + + ret = sss_hmac_sha1(salt, SSS_SHA1_LENGTH, + (unsigned char *)name, strlen(name), + hash); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("sss_hmac_sha1() failed (%d): %s\n", + ret, strerror(ret))); + result = NULL; + goto done; + } + + saltstr = sss_base64_encode(tmp_ctx, salt, SSS_SHA1_LENGTH); + if (!saltstr) { + result = NULL; + goto done; + } + + hashstr = sss_base64_encode(tmp_ctx, hash, SSS_SHA1_LENGTH); + if (!hashstr) { + result = NULL; + goto done; + } + + result = talloc_asprintf_append(result, "|1|%s|%s %s\n", + saltstr, hashstr, pubkey); + if (!result) { + goto done; + } + + talloc_free(saltstr); + talloc_free(hashstr); + } + + talloc_free(pubkey); + } + + talloc_steal(mem_ctx, result); + +done: + talloc_free(tmp_ctx); + + return result; +} + static errno_t ssh_host_pubkeys_update_known_hosts(struct ssh_cmd_ctx *cmd_ctx) { @@ -430,12 +563,13 @@ ssh_host_pubkeys_update_known_hosts(struct ssh_cmd_ctx *cmd_ctx) }; struct cli_ctx *cctx = cmd_ctx->cctx; struct sss_domain_info *dom = cctx->rctx->domains; + struct ssh_ctx *ssh_ctx = (struct ssh_ctx *)cctx->rctx->pvt_ctx; struct sysdb_ctx *sysdb; struct ldb_message **hosts; - size_t num_hosts, i, j, k; + size_t num_hosts, i; struct sss_ssh_ent *ent; int fd = -1; - char *filename, *pubkey, *line; + char *filename, *entstr; ssize_t wret; mode_t old_mask; @@ -487,43 +621,29 @@ ssh_host_pubkeys_update_known_hosts(struct ssh_cmd_ctx *cmd_ctx) continue; } - for (j = 0; j < ent->num_pubkeys; j++) { - pubkey = sss_ssh_format_pubkey(tmp_ctx, ent, &ent->pubkeys[j], - SSS_SSH_FORMAT_OPENSSH); - if (!pubkey) { - DEBUG(SSSDBG_OP_FAILURE, - ("Out of memory formatting SSH public key\n")); - continue; - } - - line = talloc_strdup(tmp_ctx, ent->name); - if (!line) { - ret = ENOMEM; - goto done; - } - - for (k = 0; k < ent->num_aliases; k++) { - line = talloc_asprintf_append(line, ",%s", ent->aliases[k]); - if (!line) { - ret = ENOMEM; - goto done; - } - } - - line = talloc_asprintf_append(line, " %s\n", pubkey); - if (!line) { - ret = ENOMEM; - goto done; - } - - wret = sss_atomic_write_s(fd, line, strlen(line)); - if (wret == -1) { - ret = errno; - goto done; - } + if (ssh_ctx->hash_known_hosts) { + entstr = ssh_host_pubkeys_format_known_host_hashed(ent, ent); + } else { + entstr = ssh_host_pubkeys_format_known_host_plain(ent, ent); + } + if (!entstr) { + DEBUG(SSSDBG_OP_FAILURE, + ("Failed to format known_hosts data for [%s]\n", + ent->name)); + continue; } + + wret = sss_atomic_write_s(fd, entstr, strlen(entstr)); + if (wret == -1) { + ret = errno; + goto done; + } + + talloc_free(ent); } + talloc_free(hosts); + dom = dom->next; } diff --git a/src/responder/ssh/sshsrv_private.h b/src/responder/ssh/sshsrv_private.h index ab9edf7c3..d74b49250 100644 --- a/src/responder/ssh/sshsrv_private.h +++ b/src/responder/ssh/sshsrv_private.h @@ -31,6 +31,8 @@ struct ssh_ctx { struct resp_ctx *rctx; + + bool hash_known_hosts; }; struct ssh_cmd_ctx { diff --git a/src/sss_client/ssh/sss_ssh_authorizedkeys.c b/src/sss_client/ssh/sss_ssh_authorizedkeys.c index b64bbc3d2..dd9a06281 100644 --- a/src/sss_client/ssh/sss_ssh_authorizedkeys.c +++ b/src/sss_client/ssh/sss_ssh_authorizedkeys.c @@ -110,7 +110,7 @@ int main(int argc, const char **argv) /* print results */ for (i = 0; i < ent->num_pubkeys; i++) { repr = sss_ssh_format_pubkey(mem_ctx, ent, &ent->pubkeys[i], - SSS_SSH_FORMAT_OPENSSH); + SSS_SSH_FORMAT_OPENSSH, NULL); if (!repr) { ERROR("Not enough memory\n"); ret = EXIT_FAILURE; diff --git a/src/util/sss_ssh.c b/src/util/sss_ssh.c index 0163c1d89..60ed5878a 100644 --- a/src/util/sss_ssh.c +++ b/src/util/sss_ssh.c @@ -136,13 +136,18 @@ char * sss_ssh_format_pubkey(TALLOC_CTX *mem_ctx, struct sss_ssh_ent *ent, struct sss_ssh_pubkey *pubkey, - enum sss_ssh_pubkey_format format) + enum sss_ssh_pubkey_format format, + const char *comment) { TALLOC_CTX *tmp_ctx; char *blob; char *algo; char *result = NULL; + if (!comment) { + comment = ent->name; + } + tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { return NULL; @@ -166,7 +171,7 @@ sss_ssh_format_pubkey(TALLOC_CTX *mem_ctx, goto done; } - result = talloc_asprintf(mem_ctx, "%s %s %s", algo, blob, ent->name); + result = talloc_asprintf(mem_ctx, "%s %s %s", algo, blob, comment); break; } diff --git a/src/util/sss_ssh.h b/src/util/sss_ssh.h index a4ac73915..29743a085 100644 --- a/src/util/sss_ssh.h +++ b/src/util/sss_ssh.h @@ -54,6 +54,7 @@ char * sss_ssh_format_pubkey(TALLOC_CTX *mem_ctx, struct sss_ssh_ent *ent, struct sss_ssh_pubkey *pubkey, - enum sss_ssh_pubkey_format format); + enum sss_ssh_pubkey_format format, + const char *comment); #endif /* _SSS_SSH_H_ */ -- cgit