diff options
author | Jan Cholasta <jcholast@redhat.com> | 2012-02-24 12:59:45 -0500 |
---|---|---|
committer | Stephen Gallagher <sgallagh@redhat.com> | 2012-02-26 20:34:18 -0500 |
commit | e6ab4b3ded22aca8dd6eb3ce69630d931cddb140 (patch) | |
tree | 0989334454303b0ff42852f5d992d87a54ade348 | |
parent | 1e68ae21e7ae46744700753ccf28bcbcaedbe017 (diff) | |
download | sssd-e6ab4b3ded22aca8dd6eb3ce69630d931cddb140.tar.gz sssd-e6ab4b3ded22aca8dd6eb3ce69630d931cddb140.tar.bz2 sssd-e6ab4b3ded22aca8dd6eb3ce69630d931cddb140.zip |
SSH: Manage global known_hosts file in the responder
https://fedorahosted.org/sssd/ticket/1193
-rw-r--r-- | src/responder/ssh/sshsrv_cmd.c | 131 | ||||
-rw-r--r-- | src/responder/ssh/sshsrv_private.h | 3 | ||||
-rw-r--r-- | src/sss_client/ssh/sss_ssh_knownhostsproxy.c | 80 |
3 files changed, 136 insertions, 78 deletions
diff --git a/src/responder/ssh/sshsrv_cmd.c b/src/responder/ssh/sshsrv_cmd.c index da6a4540..2b281e78 100644 --- a/src/responder/ssh/sshsrv_cmd.c +++ b/src/responder/ssh/sshsrv_cmd.c @@ -26,6 +26,7 @@ #include "util/util.h" #include "util/crypto/sss_crypto.h" +#include "util/sss_ssh.h" #include "db/sysdb.h" #include "db/sysdb_ssh.h" #include "providers/data_provider.h" @@ -364,6 +365,9 @@ ssh_host_pubkeys_search(struct ssh_cmd_ctx *cmd_ctx) } static errno_t +ssh_host_pubkeys_update_known_hosts(struct ssh_cmd_ctx *cmd_ctx); + +static errno_t ssh_host_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx) { errno_t ret; @@ -412,6 +416,8 @@ ssh_host_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx) } /* one result found */ + ssh_host_pubkeys_update_known_hosts(cmd_ctx); + return EOK; } @@ -436,6 +442,131 @@ ssh_host_pubkeys_search_dp_callback(uint16_t err_maj, } static errno_t +ssh_host_pubkeys_update_known_hosts(struct ssh_cmd_ctx *cmd_ctx) +{ + TALLOC_CTX *tmp_ctx; + errno_t ret; + const char *attrs[] = { + SYSDB_NAME, + SYSDB_NAME_ALIAS, + SYSDB_SSH_PUBKEY, + NULL + }; + struct cli_ctx *cctx = cmd_ctx->cctx; + struct sss_domain_info *dom = cctx->rctx->domains; + struct sysdb_ctx *sysdb; + struct ldb_message **hosts; + size_t num_hosts, i, j, k; + struct sss_ssh_ent *ent; + int fd = -1; + char *filename, *pubkey, *line; + ssize_t wret; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + return ENOMEM; + } + + /* write known_hosts file */ + filename = talloc_strdup(tmp_ctx, SSS_SSH_KNOWN_HOSTS_TEMP_TMPL); + if (!filename) { + ret = ENOMEM; + goto done; + } + + fd = mkstemp(filename); + if (fd == -1) { + ret = errno; + goto done; + } + + while (dom) { + ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, dom, &sysdb); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + ("Fatal: Sysdb CTX not found for this domain!\n")); + ret = EFAULT; + goto done; + } + + ret = sysdb_search_ssh_hosts(tmp_ctx, sysdb, "*", attrs, + &hosts, &num_hosts); + if (ret != EOK) { + goto done; + } + + for (i = 0; i < num_hosts; i++) { + ret = sss_ssh_make_ent(tmp_ctx, hosts[i], &ent); + if (ret != EOK) { + 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) { + 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(fd, line, strlen(line)); + if (wret == -1) { + ret = errno; + goto done; + } + } + } + + dom = dom->next; + } + + close(fd); + fd = -1; + + ret = chmod(filename, 0644); + if (ret == -1) { + ret = errno; + goto done; + } + + ret = rename(filename, SSS_SSH_KNOWN_HOSTS_PATH); + if (ret == -1) { + ret = errno; + goto done; + } + + ret = EOK; + +done: + if (fd != -1) { + close(fd); + unlink(filename); + } + talloc_free(tmp_ctx); + + return ret; +} + +static errno_t ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx) { struct cli_ctx *cctx = cmd_ctx->cctx; diff --git a/src/responder/ssh/sshsrv_private.h b/src/responder/ssh/sshsrv_private.h index ffe88eb3..ab9edf7c 100644 --- a/src/responder/ssh/sshsrv_private.h +++ b/src/responder/ssh/sshsrv_private.h @@ -26,6 +26,9 @@ #define SSS_SSH_SBUS_SERVICE_VERSION 0x0001 #define SSS_SSH_SBUS_SERVICE_NAME "ssh" +#define SSS_SSH_KNOWN_HOSTS_PATH PUBCONF_PATH"/known_hosts" +#define SSS_SSH_KNOWN_HOSTS_TEMP_TMPL PUBCONF_PATH"/.known_hosts.XXXXXX" + struct ssh_ctx { struct resp_ctx *rctx; }; diff --git a/src/sss_client/ssh/sss_ssh_knownhostsproxy.c b/src/sss_client/ssh/sss_ssh_knownhostsproxy.c index c9c974b4..544ea719 100644 --- a/src/sss_client/ssh/sss_ssh_knownhostsproxy.c +++ b/src/sss_client/ssh/sss_ssh_knownhostsproxy.c @@ -21,7 +21,6 @@ #include <stdio.h> #include <talloc.h> #include <unistd.h> -#include <pwd.h> #include <fcntl.h> #include <poll.h> #include <sys/types.h> @@ -214,15 +213,8 @@ int main(int argc, const char **argv) POPT_TABLEEND }; poptContext pc = NULL; - const char *file; - struct passwd *pwd; const char *host; - FILE *f; - struct addrinfo ai_hint; - struct addrinfo *ai = NULL; struct sss_ssh_ent *ent; - size_t i; - char *repr; int ret; debug_prg_name = argv[0]; @@ -267,91 +259,24 @@ int main(int argc, const char **argv) ret, fini); } - /* get absolute filename of the known_hosts file */ - if (pc_file && pc_file[0] != '/') { - pwd = getpwuid(getuid()); - if (!pwd) { - ret = errno; - DEBUG(SSSDBG_OP_FAILURE, ("getpwuid() failed (%d): %s\n", - ret, strerror(ret))); - ERROR("Failed to get user's home directory\n"); - ret = EXIT_FAILURE; - goto fini; - } - - file = talloc_asprintf(mem_ctx, "%s/%s", pwd->pw_dir, pc_file); - if (!file) { - ERROR("Not enough memory\n"); - ret = EXIT_FAILURE; - goto fini; - } - } else { - file = pc_file; - } - - /* get canonic hostname and IP addresses of the host */ - memset(&ai_hint, 0, sizeof(struct addrinfo)); - ai_hint.ai_family = AF_UNSPEC; - ai_hint.ai_socktype = SOCK_STREAM; - ai_hint.ai_protocol = IPPROTO_TCP; - ai_hint.ai_flags = AI_CANONNAME | AI_ADDRCONFIG | AI_NUMERICSERV; - - ret = getaddrinfo(pc_host, pc_port, &ai_hint, &ai); - if (ret) { - DEBUG(SSSDBG_CRIT_FAILURE, - ("getaddrinfo() failed (%d): %s\n", ret, gai_strerror(ret))); - ERROR("Error looking up host\n"); - ret = EXIT_FAILURE; - goto fini; - } - /* append domain to hostname if domain is specified */ if (pc_domain) { - host = talloc_asprintf(mem_ctx, "%s@%s", ai[0].ai_canonname, pc_domain); + host = talloc_asprintf(mem_ctx, "%s@%s", pc_host, pc_domain); if (!host) { ERROR("Not enough memory\n"); ret = EXIT_FAILURE; goto fini; } } else { - host = ai[0].ai_canonname; + host = pc_host; } /* look up public keys */ ret = sss_ssh_get_ent(mem_ctx, SSS_SSH_GET_HOST_PUBKEYS, host, &ent); if (ret != EOK) { ERROR("Error looking up public keys\n"); - ret = EXIT_FAILURE; - goto fini; - } - - /* write known_hosts file */ - /* FIXME: Do not overwrite the file, handle concurrent access */ - f = fopen(file, "w"); - if (!f) { - ret = errno; - DEBUG(SSSDBG_OP_FAILURE, ("fopen() failed (%d): %s\n", - ret, strerror(ret))); - ERROR("Can't open known hosts file\n"); - ret = EXIT_FAILURE; - goto fini; - } - - fprintf(f, - "# Generated by sss_ssh_knownhostsproxy. Please do not modify.\n"); - - for (i = 0; i < ent->num_pubkeys; i++) { - repr = sss_ssh_format_pubkey(mem_ctx, ent, &ent->pubkeys[i], - SSS_SSH_FORMAT_OPENSSH); - if (!repr) { - continue; - } - - fprintf(f, "%s %s\n", pc_host, repr); } - fclose(f); - /* connect to server */ if (pc_args) { ret = connect_proxy_command(discard_const(pc_args)); @@ -363,7 +288,6 @@ int main(int argc, const char **argv) fini: poptFreeContext(pc); talloc_free(mem_ctx); - if (ai) freeaddrinfo(ai); return ret; } |