diff options
| author | Pavel Březina <pbrezina@redhat.com> | 2017-01-18 12:49:48 +0100 |
|---|---|---|
| committer | Jakub Hrozek <jhrozek@redhat.com> | 2017-02-08 11:05:51 +0100 |
| commit | a8191ce7ad5364801ad9458c3194075a7ca77b8a (patch) | |
| tree | 8d79b66acfca8f981a0ad76b82ebd2efaee833f0 /src/responder/ssh | |
| parent | 53c31b83e4d06ea4c2813eec2f1e647a613b4a2b (diff) | |
| download | sssd-a8191ce7ad5364801ad9458c3194075a7ca77b8a.tar.gz sssd-a8191ce7ad5364801ad9458c3194075a7ca77b8a.tar.xz sssd-a8191ce7ad5364801ad9458c3194075a7ca77b8a.zip | |
ssh: rewrite ssh responder to use cache_req
This is a bigger change since both supported commands could be
rewritten for cache_req and the logic could be deleted. I decided
to also split the file into more modules and follow similar pattern
as with nss responder.
Resolves:
https://fedorahosted.org/sssd/ticket/1126
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Diffstat (limited to 'src/responder/ssh')
| -rw-r--r-- | src/responder/ssh/ssh_cmd.c | 256 | ||||
| -rw-r--r-- | src/responder/ssh/ssh_known_hosts.c | 329 | ||||
| -rw-r--r-- | src/responder/ssh/ssh_private.h (renamed from src/responder/ssh/sshsrv_private.h) | 41 | ||||
| -rw-r--r-- | src/responder/ssh/ssh_protocol.c | 217 | ||||
| -rw-r--r-- | src/responder/ssh/ssh_reply.c | 333 | ||||
| -rw-r--r-- | src/responder/ssh/sshsrv.c | 2 | ||||
| -rw-r--r-- | src/responder/ssh/sshsrv_cmd.c | 1203 |
7 files changed, 1165 insertions, 1216 deletions
diff --git a/src/responder/ssh/ssh_cmd.c b/src/responder/ssh/ssh_cmd.c new file mode 100644 index 000000000..a1188280d --- /dev/null +++ b/src/responder/ssh/ssh_cmd.c @@ -0,0 +1,256 @@ +/* + Authors: + Pavel Březina <pbrezina@redhat.com> + + Copyright (C) 2016 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "config.h" + +#include <talloc.h> +#include <string.h> +#include <pwd.h> + +#include "util/util.h" +#include "responder/common/responder.h" +#include "responder/common/cache_req/cache_req.h" +#include "responder/ssh/ssh_private.h" + +struct ssh_cmd_ctx { + struct cli_ctx *cli_ctx; + const char *name; + const char *alias; + const char *domain; +}; + +static errno_t +ssh_check_non_sssd_user(const char *username) +{ + struct passwd *pwd; + + pwd = getpwnam(username); + if (pwd != NULL) { + DEBUG(SSSDBG_TRACE_ALL, "%s is a non-SSSD user\n", username); + return ERR_NON_SSSD_USER; + } + + return ENOENT; +} + + +static struct sss_domain_info * +ssh_get_result_domain(struct resp_ctx *rctx, + struct cache_req_result *result, + const char *name) +{ + if (result != NULL) { + return result->domain; + } + + return find_domain_by_name(rctx->domains, name, true); +} + +static void ssh_cmd_get_user_pubkeys_done(struct tevent_req *subreq); + +static errno_t ssh_cmd_get_user_pubkeys(struct cli_ctx *cli_ctx) +{ + struct ssh_cmd_ctx *cmd_ctx; + struct tevent_req *subreq; + errno_t ret; + + static const char *attrs[] = { SYSDB_NAME, SYSDB_SSH_PUBKEY, + SYSDB_USER_CERT, NULL }; + + cmd_ctx = talloc_zero(cli_ctx, struct ssh_cmd_ctx); + if (cmd_ctx == NULL) { + ret = ENOMEM; + goto done; + } + + cmd_ctx->cli_ctx = cli_ctx; + + ret = ssh_protocol_parse_user(cli_ctx, cli_ctx->rctx->default_domain, + &cmd_ctx->name, &cmd_ctx->domain); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request message!\n"); + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, + "Requesting SSH user public keys for [%s] from [%s]\n", + cmd_ctx->name, cmd_ctx->domain ? cmd_ctx->domain : "<ALL>"); + + if (strcmp(cmd_ctx->name, "root") == 0) { + ret = ERR_NON_SSSD_USER; + goto done; + } + + subreq = cache_req_user_by_name_attrs_send(cmd_ctx, cli_ctx->ev, + cli_ctx->rctx, + cli_ctx->rctx->ncache, 0, + cmd_ctx->domain, + cmd_ctx->name, attrs); + if (subreq == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); + ret = ENOMEM; + goto done; + } + + tevent_req_set_callback(subreq, ssh_cmd_get_user_pubkeys_done, cmd_ctx); + + ret = EOK; + +done: + if (ret != EOK) { + talloc_free(cmd_ctx); + return ssh_protocol_done(cli_ctx, ret); + } + + return ret; +} + +static void ssh_cmd_get_user_pubkeys_done(struct tevent_req *subreq) +{ + struct cache_req_result *result; + struct ssh_cmd_ctx *cmd_ctx; + errno_t ret; + + cmd_ctx = tevent_req_callback_data(subreq, struct ssh_cmd_ctx); + + ret = cache_req_user_by_name_attrs_recv(cmd_ctx, subreq, &result); + talloc_zfree(subreq); + if (ret != EOK) { + if (ret == ENOENT) { + /* Check if it is a non SSSD user. */ + ret = ssh_check_non_sssd_user(cmd_ctx->name); + } + + ssh_protocol_done(cmd_ctx->cli_ctx, ret); + goto done; + } + + ssh_protocol_reply(cmd_ctx->cli_ctx, result); + +done: + talloc_free(cmd_ctx); +} + +static void ssh_cmd_get_host_pubkeys_done(struct tevent_req *subreq); + +static errno_t ssh_cmd_get_host_pubkeys(struct cli_ctx *cli_ctx) +{ + struct ssh_cmd_ctx *cmd_ctx; + struct tevent_req *subreq; + errno_t ret; + + static const char *attrs[] = { SYSDB_NAME, SYSDB_SSH_PUBKEY, NULL }; + + cmd_ctx = talloc_zero(cli_ctx, struct ssh_cmd_ctx); + if (cmd_ctx == NULL) { + ret = ENOMEM; + goto done; + } + + cmd_ctx->cli_ctx = cli_ctx; + + ret = ssh_protocol_parse_host(cli_ctx, &cmd_ctx->name, &cmd_ctx->alias, + &cmd_ctx->domain); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request message!\n"); + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, + "Requesting SSH host public keys for [%s] from [%s]\n", + cmd_ctx->name, cmd_ctx->domain ? cmd_ctx->domain : "<ALL>"); + + subreq = cache_req_host_by_name_send(cmd_ctx, cli_ctx->ev, + cli_ctx->rctx, + cli_ctx->rctx->ncache, 0, + cmd_ctx->domain, + cmd_ctx->name, + cmd_ctx->alias, attrs); + if (subreq == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); + ret = ENOMEM; + goto done; + } + + tevent_req_set_callback(subreq, ssh_cmd_get_host_pubkeys_done, cmd_ctx); + + ret = EOK; + +done: + if (ret != EOK) { + talloc_free(cmd_ctx); + return ssh_protocol_done(cli_ctx, ret); + } + + return ret; +} + +static void ssh_cmd_get_host_pubkeys_done(struct tevent_req *subreq) +{ + struct cache_req_result *result = NULL; + struct sss_domain_info *domain; + struct ssh_cmd_ctx *cmd_ctx; + struct ssh_ctx *ssh_ctx; + errno_t ret; + + cmd_ctx = tevent_req_callback_data(subreq, struct ssh_cmd_ctx); + ssh_ctx = talloc_get_type(cmd_ctx->cli_ctx->rctx->pvt_ctx, struct ssh_ctx); + + ret = cache_req_user_by_name_attrs_recv(cmd_ctx, subreq, &result); + talloc_zfree(subreq); + + if (ret == EOK || ret == ENOENT) { + domain = ssh_get_result_domain(ssh_ctx->rctx, result, cmd_ctx->domain); + + ssh_update_known_hosts_file(ssh_ctx->rctx->domains, domain, + cmd_ctx->name, ssh_ctx->hash_known_hosts, + ssh_ctx->known_hosts_timeout); + } + + if (ret != EOK) { + ssh_protocol_done(cmd_ctx->cli_ctx, ret); + goto done; + } + + ssh_protocol_reply(cmd_ctx->cli_ctx, result); + +done: + talloc_free(cmd_ctx); +} + +struct cli_protocol_version *register_cli_protocol_version(void) +{ + static struct cli_protocol_version ssh_cli_protocol_version[] = { + {0, NULL, NULL} + }; + + return ssh_cli_protocol_version; +} + +struct sss_cmd_table *get_ssh_cmds(void) { + static struct sss_cmd_table ssh_cmds[] = { + {SSS_GET_VERSION, sss_cmd_get_version}, + {SSS_SSH_GET_USER_PUBKEYS, ssh_cmd_get_user_pubkeys}, + {SSS_SSH_GET_HOST_PUBKEYS, ssh_cmd_get_host_pubkeys}, + {SSS_CLI_NULL, NULL} + }; + + return ssh_cmds; +} diff --git a/src/responder/ssh/ssh_known_hosts.c b/src/responder/ssh/ssh_known_hosts.c new file mode 100644 index 000000000..ca0872264 --- /dev/null +++ b/src/responder/ssh/ssh_known_hosts.c @@ -0,0 +1,329 @@ +/* + Authors: + Jan Cholasta <jcholast@redhat.com> + + Copyright (C) 2012 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "config.h" + +#include <talloc.h> + +#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 "responder/ssh/ssh_private.h" + +static char * +ssh_host_pubkeys_format_known_host_plain(TALLOC_CTX *mem_ctx, + struct sss_ssh_ent *ent) +{ + TALLOC_CTX *tmp_ctx; + errno_t ret; + char *name, *pubkey; + char *result = NULL; + 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++) { + ret = sss_ssh_format_pubkey(tmp_ctx, &ent->pubkeys[i], &pubkey); + if (ret != EOK) { + 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++) { + ret = sss_ssh_format_pubkey(tmp_ctx, &ent->pubkeys[i], &pubkey); + if (ret != EOK) { + 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_write_known_hosts(struct sss_domain_info *domains, + bool hash_known_hosts, + time_t now, + int fd) +{ + TALLOC_CTX *tmp_ctx; + struct sss_domain_info *dom; + struct ldb_message **hosts; + struct sysdb_ctx *sysdb; + struct sss_ssh_ent *ent; + char *entstr; + size_t num_hosts; + size_t i; + ssize_t wret; + errno_t ret; + + static const char *attrs[] = { + SYSDB_NAME, + SYSDB_NAME_ALIAS, + SYSDB_SSH_PUBKEY, + NULL + }; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n"); + return ENOMEM; + } + + for (dom = domains; dom != NULL; dom = get_next_domain(dom, false)) { + sysdb = dom->sysdb; + if (sysdb == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Fatal: Sysdb CTX not found for this domain!\n"); + ret = EFAULT; + goto done; + } + + ret = sysdb_get_ssh_known_hosts(tmp_ctx, dom, now, attrs, + &hosts, &num_hosts); + if (ret == ENOENT) { + continue; + } else if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Host search failed for domain " + "%s [%d]: %s\n", dom->name, ret, sss_strerror(ret)); + continue; + } + + for (i = 0; i < num_hosts; i++) { + ret = sss_ssh_make_ent(tmp_ctx, hosts[i], &ent); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Failed to get SSH host public keys\n"); + continue; + } + + if (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 == NULL) { + 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); + } + + ret = EOK; + +done: + talloc_free(tmp_ctx); + + return ret; +} + +errno_t +ssh_update_known_hosts_file(struct sss_domain_info *domains, + struct sss_domain_info *domain, + const char *name, + bool hash_known_hosts, + int known_hosts_timeout) +{ + TALLOC_CTX *tmp_ctx; + char *filename; + errno_t ret; + time_t now; + int fd = -1; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n"); + return ENOMEM; + } + + now = time(NULL); + + /* Update host's expiration time. */ + if (domain != NULL) { + ret = sysdb_update_ssh_known_host_expire(domain, name, now, + known_hosts_timeout); + if (ret != EOK && ret != ENOENT) { + goto done; + } + } + + /* Create temporary known hosts file. */ + filename = talloc_strdup(tmp_ctx, SSS_SSH_KNOWN_HOSTS_TEMP_TMPL); + if (filename == NULL) { + ret = ENOMEM; + goto done; + } + + fd = sss_unique_file_ex(tmp_ctx, filename, 0133, &ret); + if (fd == -1) { + filename = NULL; + goto done; + } + + /* Write contents. */ + ret = ssh_write_known_hosts(domains, hash_known_hosts, now, fd); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to write known hosts file " + "[%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + + + /* Rename to SSH known hosts file. */ + ret = fchmod(fd, 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: + talloc_free(tmp_ctx); + + if (fd != -1) { + close(fd); + } + + return ret; +} diff --git a/src/responder/ssh/sshsrv_private.h b/src/responder/ssh/ssh_private.h index 3ea895536..f32112e89 100644 --- a/src/responder/ssh/sshsrv_private.h +++ b/src/responder/ssh/ssh_private.h @@ -22,6 +22,7 @@ #define _SSHSRV_PRIVATE_H_ #include "responder/common/responder.h" +#include "responder/common/cache_req/cache_req.h" #define SSS_SSH_KNOWN_HOSTS_PATH PUBCONF_PATH"/known_hosts" #define SSS_SSH_KNOWN_HOSTS_TEMP_TMPL PUBCONF_PATH"/.known_hosts.XXXXXX" @@ -35,20 +36,36 @@ struct ssh_ctx { char *ca_db; }; -struct ssh_cmd_ctx { - struct cli_ctx *cctx; - char *name; - char *alias; - char *domname; - bool is_user; +struct sss_cmd_table *get_ssh_cmds(void); - struct sss_domain_info *domain; - bool check_next; - char *fqdn; +errno_t +ssh_protocol_parse_user(struct cli_ctx *cli_ctx, + const char *default_domain, + const char **_name, + const char **_domain); - struct ldb_message *result; -}; +errno_t +ssh_protocol_parse_host(struct cli_ctx *cli_ctx, + const char **_name, + const char **_alias, + const char **_domain); -struct sss_cmd_table *get_ssh_cmds(void); +void ssh_protocol_reply(struct cli_ctx *cli_ctx, + struct cache_req_result *result); + +errno_t +ssh_protocol_done(struct cli_ctx *cli_ctx, errno_t error); + +errno_t +ssh_protocol_build_reply(struct sss_packet *packet, + struct ssh_ctx *ssh_ctx, + struct cache_req_result *result); + +errno_t +ssh_update_known_hosts_file(struct sss_domain_info *domains, + struct sss_domain_info *domain, + const char *name, + bool hash_known_hosts, + int known_hosts_timeout); #endif /* _SSHSRV_PRIVATE_H_ */ diff --git a/src/responder/ssh/ssh_protocol.c b/src/responder/ssh/ssh_protocol.c new file mode 100644 index 000000000..4198f8214 --- /dev/null +++ b/src/responder/ssh/ssh_protocol.c @@ -0,0 +1,217 @@ +/* + Authors: + Pavel Březina <pbrezina@redhat.com> + + Copyright (C) 2017 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "config.h" + +#include <talloc.h> + +#include "util/util.h" +#include "util/sss_ssh.h" +#include "responder/common/responder.h" +#include "responder/common/responder_packet.h" +#include "responder/common/cache_req/cache_req.h" +#include "responder/ssh/ssh_private.h" + +errno_t +ssh_protocol_done(struct cli_ctx *cli_ctx, errno_t error) +{ + struct cli_protocol *pctx; + errno_t ret; + + pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol); + + switch (error) { + case EOK: + /* Create empty packet if none was provided. */ + if (pctx->creq->out == NULL) { + ret = sss_packet_new(pctx->creq, 0, + sss_packet_get_cmd(pctx->creq->in), + &pctx->creq->out); + if (ret != EOK) { + goto done; + } + + sss_packet_set_error(pctx->creq->out, EOK); + } + + DEBUG(SSSDBG_TRACE_ALL, "Sending reply: success\n"); + ret = EOK; + goto done; + default: + DEBUG(SSSDBG_TRACE_ALL, "Sending reply: error [%d]: %s\n", + error, sss_strerror(error)); + ret = sss_cmd_send_error(cli_ctx, error); + goto done; + } + +done: + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send reply [%d]: %s!\n", + ret, sss_strerror(ret)); + return ret; + } + + sss_cmd_done(cli_ctx, NULL); + return EOK; +} + +void ssh_protocol_reply(struct cli_ctx *cli_ctx, + struct cache_req_result *result) +{ + struct cli_protocol *pctx; + struct ssh_ctx *ssh_ctx; + errno_t ret; + + pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol); + ssh_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct ssh_ctx); + + ret = sss_packet_new(pctx->creq, 0, sss_packet_get_cmd(pctx->creq->in), + &pctx->creq->out); + if (ret != EOK) { + goto done; + } + + ret = ssh_protocol_build_reply(pctx->creq->out, ssh_ctx, result); + if (ret != EOK) { + goto done; + } + + sss_packet_set_error(pctx->creq->out, EOK); + +done: + ssh_protocol_done(cli_ctx, ret); +} + +static errno_t +ssh_protocol_parse_request(struct cli_ctx *cli_ctx, + const char *default_domain, + const char **_name, + const char **_alias, + const char **_domain) +{ + struct cli_protocol *pctx; + const char *name = NULL; + const char *alias = NULL; + const char *domain = NULL; + uint32_t flags; + uint32_t name_len; + uint32_t alias_len; + uint32_t domain_len; + size_t body_len; + uint8_t *body; + size_t c = 0; + + pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol); + + sss_packet_get_body(pctx->creq->in, &body, &body_len); + + SAFEALIGN_COPY_UINT32_CHECK(&flags, body + c, body_len, &c); + if (flags & ~(uint32_t)SSS_SSH_REQ_MASK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid flags received [0x%x]\n", flags); + return EINVAL; + } + + SAFEALIGN_COPY_UINT32_CHECK(&name_len, body + c, body_len, &c); + if (name_len == 0 || name_len > body_len - c) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid name length\n"); + return EINVAL; + } + + name = (const char *)(body + c); + if (!sss_utf8_check((const uint8_t *)name, name_len-1) || + name[name_len - 1] != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "Name is not valid UTF-8 string\n"); + return EINVAL; + } + c += name_len; + + 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"); + return EINVAL; + } + + alias = (const char *)(body+c); + if (!sss_utf8_check((const uint8_t *)alias, alias_len - 1) || + alias[alias_len - 1] != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "Alias is not valid UTF-8 string\n"); + return EINVAL; + } + c += alias_len; + } + + 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 = (const 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; + } else { + domain = default_domain; + } + + DEBUG(SSSDBG_TRACE_FUNC, + "Requested domain [%s]\n", domain ? domain : "<ALL>"); + } + + if (_name != NULL) { + *_name = name; + } + + if (_alias != NULL) { + *_alias = alias; + } + + if (_domain != NULL) { + *_domain = domain; + } + + return EOK; +} + +errno_t +ssh_protocol_parse_user(struct cli_ctx *cli_ctx, + const char *default_domain, + const char **_name, + const char **_domain) +{ + return ssh_protocol_parse_request(cli_ctx, default_domain, + _name, NULL, _domain); +} + +errno_t +ssh_protocol_parse_host(struct cli_ctx *cli_ctx, + const char **_name, + const char **_alias, + const char **_domain) +{ + return ssh_protocol_parse_request(cli_ctx, NULL, _name, _alias, _domain); +} diff --git a/src/responder/ssh/ssh_reply.c b/src/responder/ssh/ssh_reply.c new file mode 100644 index 000000000..807f4ee07 --- /dev/null +++ b/src/responder/ssh/ssh_reply.c @@ -0,0 +1,333 @@ +/* + Authors: + Jan Cholasta <jcholast@redhat.com> + + Copyright (C) 2012 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "config.h" + +#include <talloc.h> +#include <ldb.h> + +#include "util/util.h" +#include "util/crypto/sss_crypto.h" +#include "util/sss_ssh.h" +#include "util/cert.h" +#include "responder/common/responder.h" +#include "responder/common/responder_packet.h" +#include "responder/common/cache_req/cache_req.h" +#include "responder/ssh/ssh_private.h" + +static errno_t get_valid_certs_keys(TALLOC_CTX *mem_ctx, + struct ssh_ctx *ssh_ctx, + struct ldb_message_element *el_cert, + struct ldb_message_element **_el_res) +{ + TALLOC_CTX *tmp_ctx; + uint8_t *key; + size_t key_len; + char *cert_verification_opts; + struct cert_verify_opts *cert_verify_opts; + int ret; + struct ldb_message_element *el_res; + size_t d; + + if (el_cert == NULL) { + DEBUG(SSSDBG_TRACE_ALL, "Mssing element, nothing to do.\n"); + return EOK; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + return ENOMEM; + } + + ret = confdb_get_string(ssh_ctx->rctx->cdb, tmp_ctx, + CONFDB_MONITOR_CONF_ENTRY, + CONFDB_MONITOR_CERT_VERIFICATION, NULL, + &cert_verification_opts); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to read p11_child_timeout from confdb: [%d] %s\n", + ret, sss_strerror(ret)); + goto done; + } + + ret = parse_cert_verify_opts(tmp_ctx, cert_verification_opts, + &cert_verify_opts); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to parse verifiy option.\n"); + goto done; + } + + el_res = talloc_zero(tmp_ctx, struct ldb_message_element); + if (el_res == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n"); + ret = ENOMEM; + goto done; + } + + el_res->values = talloc_array(el_res, struct ldb_val, el_cert->num_values); + if (el_res->values == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n"); + ret = ENOMEM; + goto done; + } + + for (d = 0; d < el_cert->num_values; d++) { + ret = cert_to_ssh_key(tmp_ctx, ssh_ctx->ca_db, + el_cert->values[d].data, + el_cert->values[d].length, + cert_verify_opts, &key, &key_len); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "cert_to_ssh_key failed, ignoring.\n"); + continue; + } + + el_res->values[el_res->num_values].data = + talloc_steal(el_res->values, key); + el_res->values[el_res->num_values].length = key_len; + el_res->num_values++; + } + + if (el_res->num_values == 0) { + *_el_res = NULL; + } else { + *_el_res = talloc_steal(mem_ctx, el_res); + } + + ret = EOK; + +done: + + talloc_free(tmp_ctx); + + return ret; +} + +static errno_t decode_and_add_base64_data(struct sss_packet *packet, + struct ldb_message_element *el, + bool skip_base64_decode, + size_t fqname_len, + const char *fqname, + size_t *c) +{ + uint8_t *key; + size_t key_len; + uint8_t *body; + size_t body_len; + int ret; + size_t d; + TALLOC_CTX *tmp_ctx; + + if (el == NULL) { + DEBUG(SSSDBG_TRACE_ALL, "Mssing element, nothing to do.\n"); + return EOK; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + return ENOMEM; + } + + for (d = 0; d < el->num_values; d++) { + if (skip_base64_decode) { + key = el->values[d].data; + key_len = el->values[d].length; + } else { + key = sss_base64_decode(tmp_ctx, (const char *) el->values[d].data, + &key_len); + if (key == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n"); + ret = ENOMEM; + goto done; + } + } + + ret = sss_packet_grow(packet, + 3*sizeof(uint32_t) + key_len + fqname_len); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n"); + goto done; + } + sss_packet_get_body(packet, &body, &body_len); + + SAFEALIGN_SET_UINT32(body+(*c), 0, c); + SAFEALIGN_SET_UINT32(body+(*c), fqname_len, c); + safealign_memcpy(body+(*c), fqname, fqname_len, c); + SAFEALIGN_SET_UINT32(body+(*c), key_len, c); + safealign_memcpy(body+(*c), key, key_len, c); + + } + + ret = EOK; + +done: + talloc_free(tmp_ctx); + + return ret; +} + +static errno_t +ssh_get_output_keys(TALLOC_CTX *mem_ctx, + struct ssh_ctx *ssh_ctx, + struct sss_domain_info *domain, + struct ldb_message *msg, + struct ldb_message_element ***_elements, + uint32_t *_num_keys) +{ + struct ldb_message_element **elements; + struct ldb_message_element *user_cert; + uint32_t num_keys = 0; + uint32_t i = 0; + errno_t ret; + + elements = talloc_zero_array(mem_ctx, struct ldb_message_element *, 5); + if (elements == NULL) { + return ENOMEM; + } + + elements[i] = ldb_msg_find_element(msg, SYSDB_SSH_PUBKEY); + if (elements[i] != NULL) { + num_keys += elements[i]->num_values; + i++; + } + + elements[i] = ldb_msg_find_element(msg, ORIGINALAD_PREFIX SYSDB_SSH_PUBKEY); + if (elements[i] != NULL) { + num_keys += elements[i]->num_values; + i++; + } + + if (DOM_HAS_VIEWS(domain)) { + elements[i] = ldb_msg_find_element(msg, OVERRIDE_PREFIX SYSDB_SSH_PUBKEY); + if (elements[i] != NULL) { + num_keys += elements[i]->num_values; + i++; + } + } + + user_cert = ldb_msg_find_element(msg, SYSDB_USER_CERT); + if (user_cert != NULL) { + ret = get_valid_certs_keys(elements, ssh_ctx, user_cert, &elements[i]); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "get_valid_certs_keys failed.\n"); + goto done; + } + + if (elements[i] != NULL) { + num_keys += elements[i]->num_values; + i++; + } + } + + *_elements = elements; + *_num_keys = num_keys; + + ret = EOK; + +done: + if (ret != EOK) { + talloc_free(elements); + } + + return ret; +} + +static errno_t +ssh_get_name(struct ldb_message *msg, + struct sized_string *sz_name) +{ + const char *name; + + name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); + if (name == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Got unnamed result!\n"); + return ENOENT; + } + + to_sized_string(sz_name, name); + + return EOK; +} + +errno_t +ssh_protocol_build_reply(struct sss_packet *packet, + struct ssh_ctx *ssh_ctx, + struct cache_req_result *result) +{ + TALLOC_CTX *tmp_ctx; + struct ldb_message_element **elements; + struct sized_string name; + uint32_t num_keys; + size_t body_len; + uint8_t *body; + size_t c = 0; + errno_t ret; + int i; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n"); + return ENOMEM; + } + + ret = ssh_get_output_keys(tmp_ctx, ssh_ctx, result->domain, + result->msgs[0], &elements, &num_keys); + if (ret != EOK) { + goto done; + } + + ret = ssh_get_name(result->msgs[0], &name); + if (ret != EOK) { + goto done; + } + + ret = sss_packet_grow(packet, 2 * sizeof(uint32_t)); + if (ret != EOK) { + goto done; + } + + sss_packet_get_body(packet, &body, &body_len); + + SAFEALIGN_SET_UINT32(&body[c], num_keys, &c); + SAFEALIGN_SET_UINT32(&body[c], 0, &c); + + if (num_keys == 0) { + ret = EOK; + goto done; + } + + for (i = 0; elements[i] != NULL; i++) { + ret = decode_and_add_base64_data(packet, elements[i], false, + name.len, name.str, &c); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n"); + goto done; + } + } + + ret = EOK; + +done: + talloc_free(tmp_ctx); + + return ret; +} diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c index 80230794a..440f0e2b9 100644 --- a/src/responder/ssh/sshsrv.c +++ b/src/responder/ssh/sshsrv.c @@ -25,7 +25,7 @@ #include "monitor/monitor_interfaces.h" #include "responder/common/responder.h" #include "responder/common/responder_sbus.h" -#include "responder/ssh/sshsrv_private.h" +#include "responder/ssh/ssh_private.h" #include "providers/data_provider.h" struct mon_cli_iface monitor_ssh_methods = { diff --git a/src/responder/ssh/sshsrv_cmd.c b/src/responder/ssh/sshsrv_cmd.c deleted file mode 100644 index 195d5763e..000000000 --- a/src/responder/ssh/sshsrv_cmd.c +++ /dev/null @@ -1,1203 +0,0 @@ -/* - Authors: - Jan Cholasta <jcholast@redhat.com> - - Copyright (C) 2012 Red Hat - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "config.h" - -#include <talloc.h> -#include <string.h> -#include <netdb.h> - -#include "util/util.h" -#include "util/crypto/sss_crypto.h" -#include "util/sss_ssh.h" -#include "util/cert.h" -#include "db/sysdb.h" -#include "db/sysdb_ssh.h" -#include "providers/data_provider.h" -#include "responder/common/responder.h" -#include "responder/common/responder_packet.h" -#include "responder/ssh/sshsrv_private.h" - -static errno_t -ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx, - char *default_domain); - -static errno_t -ssh_user_pubkeys_search(struct ssh_cmd_ctx *cmd_ctx); -static errno_t -ssh_cmd_get_user_pubkeys_done(struct ssh_cmd_ctx *cmd_ctx, - errno_t ret); - -int -sss_ssh_cmd_get_user_pubkeys(struct cli_ctx *cctx) -{ - errno_t ret; - struct ssh_cmd_ctx *cmd_ctx; - - cmd_ctx = talloc_zero(cctx, struct ssh_cmd_ctx); - if (!cmd_ctx) { - return ENOMEM; - } - cmd_ctx->cctx = cctx; - cmd_ctx->is_user = true; - - ret = ssh_cmd_parse_request(cmd_ctx, cctx->rctx->default_domain); - if (ret != EOK) { - goto done; - } - - DEBUG(SSSDBG_TRACE_FUNC, - "Requesting SSH user public keys for [%s] from [%s]\n", - cmd_ctx->name, cmd_ctx->domname ? cmd_ctx->domname : "<ALL>"); - - if (strcmp(cmd_ctx->name, "root") == 0) { - ret = ERR_NON_SSSD_USER; - goto done; - } - - if (cmd_ctx->domname) { - cmd_ctx->domain = responder_get_domain(cctx->rctx, cmd_ctx->domname); - if (!cmd_ctx->domain) { - ret = ENOENT; - goto done; - } - } else { - cmd_ctx->domain = cctx->rctx->domains; - cmd_ctx->check_next = true; - } - - ret = ssh_user_pubkeys_search(cmd_ctx); - -done: - return ssh_cmd_get_user_pubkeys_done(cmd_ctx, ret); -} - -static errno_t -ssh_host_pubkeys_search(struct ssh_cmd_ctx *cmd_ctx); -static errno_t -ssh_cmd_get_host_pubkeys_done(struct ssh_cmd_ctx *cmd_ctx, - errno_t ret); - -static int -sss_ssh_cmd_get_host_pubkeys(struct cli_ctx *cctx) -{ - errno_t ret; - struct ssh_cmd_ctx *cmd_ctx; - - cmd_ctx = talloc_zero(cctx, struct ssh_cmd_ctx); - if (!cmd_ctx) { - return ENOMEM; - } - cmd_ctx->cctx = cctx; - cmd_ctx->is_user = false; - - ret = ssh_cmd_parse_request(cmd_ctx, NULL); - if (ret != EOK) { - goto done; - } - - DEBUG(SSSDBG_TRACE_FUNC, - "Requesting SSH host public keys for [%s][%s] from [%s]\n", - cmd_ctx->name, cmd_ctx->alias ? cmd_ctx->alias : "", - cmd_ctx->domname ? cmd_ctx->domname : "<ALL>"); - - if (cmd_ctx->domname) { - cmd_ctx->domain = responder_get_domain(cctx->rctx, cmd_ctx->domname); - if (!cmd_ctx->domain) { - ret = ENOENT; - goto done; - } - } else { - cmd_ctx->domain = cctx->rctx->domains; - cmd_ctx->check_next = true; - } - - ret = ssh_host_pubkeys_search(cmd_ctx); - -done: - return ssh_cmd_get_host_pubkeys_done(cmd_ctx, ret); -} - -static void -ssh_dp_send_req_done(struct tevent_req *req) -{ - struct dp_callback_ctx *cb_ctx = - tevent_req_callback_data(req, struct dp_callback_ctx); - - errno_t ret; - dbus_uint16_t err_maj; - dbus_uint32_t err_min; - char *err_msg; - - ret = sss_dp_get_ssh_host_recv(cb_ctx->mem_ctx, req, - &err_maj, &err_min, - &err_msg); - talloc_zfree(req); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Fatal error, killing connection!\n"); - talloc_free(cb_ctx->cctx); - return; - } - - cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr); -} - -static errno_t -ssh_user_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx); -static void -ssh_user_pubkeys_search_dp_callback(uint16_t err_maj, - uint32_t err_min, - const char *err_msg, - void *ptr); - -static errno_t -ssh_user_handle_not_found(const char *username) -{ - struct passwd *pwd; - - pwd = getpwnam(username); - if (pwd != NULL) { - DEBUG(SSSDBG_TRACE_ALL, "%s is a non-SSSD user\n", username); - return ERR_NON_SSSD_USER; - } - - return ENOENT; -} - -static errno_t -ssh_user_pubkeys_search(struct ssh_cmd_ctx *cmd_ctx) -{ - struct tevent_req *req; - struct dp_callback_ctx *cb_ctx; - - /* if it is a domainless search, skip domains that require fully - * qualified names instead */ - while (cmd_ctx->domain && cmd_ctx->check_next && cmd_ctx->domain->fqnames) { - cmd_ctx->domain = get_next_domain(cmd_ctx->domain, false); - } - - if (!cmd_ctx->domain) { - DEBUG(SSSDBG_OP_FAILURE, - "No matching domain found for [%s], fail!\n", cmd_ctx->name); - return ssh_user_handle_not_found(cmd_ctx->name); - } - - talloc_zfree(cmd_ctx->fqdn); - cmd_ctx->fqdn = sss_resp_create_fqname(cmd_ctx, cmd_ctx->cctx->rctx, - cmd_ctx->domain, false, cmd_ctx->name); - if (cmd_ctx->fqdn == NULL) { - return ENOMEM; - } - - /* refresh the user's cache entry */ - if (NEED_CHECK_PROVIDER(cmd_ctx->domain->provider)) { - req = sss_dp_get_account_send(cmd_ctx, cmd_ctx->cctx->rctx, - cmd_ctx->domain, false, SSS_DP_USER, - cmd_ctx->fqdn, 0, NULL); - if (!req) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Out of memory sending data provider request\n"); - return ENOMEM; - } - - cb_ctx = talloc_zero(cmd_ctx, struct dp_callback_ctx); - if (!cb_ctx) { - talloc_zfree(req); - return ENOMEM; - } - - cb_ctx->callback = ssh_user_pubkeys_search_dp_callback; - cb_ctx->ptr = cmd_ctx; - cb_ctx->cctx = cmd_ctx->cctx; - cb_ctx->mem_ctx = cmd_ctx; - - tevent_req_set_callback(req, ssh_dp_send_req_done, cb_ctx); - - /* tell caller we are in an async call */ - return EAGAIN; - } - - return ssh_user_pubkeys_search_next(cmd_ctx); -} - -static errno_t -ssh_user_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx) -{ - errno_t ret; - const char *attrs[] = { SYSDB_NAME, SYSDB_SSH_PUBKEY, SYSDB_USER_CERT, - NULL }; - struct ldb_result *res; - - DEBUG(SSSDBG_TRACE_FUNC, - "Requesting SSH user public keys for [%s@%s]\n", - cmd_ctx->name, cmd_ctx->domain->name); - - if (cmd_ctx->domain->sysdb == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE, - "Fatal: Sysdb CTX not found for this domain!\n"); - return EFAULT; - } - - ret = sysdb_get_user_attr_with_views(cmd_ctx, cmd_ctx->domain, - cmd_ctx->fqdn, attrs, &res); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Failed to make request to our cache!\n"); - return EIO; - } - - if (res->count > 1) { - DEBUG(SSSDBG_FATAL_FAILURE, - "User search by name (%s) returned > 1 results!\n", - cmd_ctx->name); - return EINVAL; - } - - if (!res->count) { - /* if a multidomain search, try with next */ - if (cmd_ctx->check_next) { - cmd_ctx->domain = get_next_domain(cmd_ctx->domain, false); - return ssh_user_pubkeys_search(cmd_ctx); - } - - DEBUG(SSSDBG_MINOR_FAILURE, - "No attributes for user [%s] found.\n", cmd_ctx->name); - - return ssh_user_handle_not_found(cmd_ctx->name); - } - - cmd_ctx->result = res->msgs[0]; - - /* one result found */ - return EOK; -} - -static void -ssh_user_pubkeys_search_dp_callback(uint16_t err_maj, - uint32_t err_min, - const char *err_msg, - void *ptr) -{ - struct ssh_cmd_ctx *cmd_ctx = talloc_get_type(ptr, struct ssh_cmd_ctx); - errno_t ret; - - if (err_maj) { - DEBUG(SSSDBG_OP_FAILURE, - "Unable to get information from Data Provider\n" - "Error: %u, %u, %s\n", - (unsigned int)err_maj, (unsigned int)err_min, err_msg); - } - - ret = ssh_user_pubkeys_search_next(cmd_ctx); - ssh_cmd_get_user_pubkeys_done(cmd_ctx, ret); -} - -static errno_t -ssh_host_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx); -static void -ssh_host_pubkeys_search_dp_callback(uint16_t err_maj, - uint32_t err_min, - const char *err_msg, - void *ptr); - -static errno_t -ssh_host_pubkeys_search(struct ssh_cmd_ctx *cmd_ctx) -{ - struct tevent_req *req; - struct dp_callback_ctx *cb_ctx; - - if (!cmd_ctx->domain) { - DEBUG(SSSDBG_OP_FAILURE, - "No matching domain found for [%s], fail!\n", cmd_ctx->name); - return ENOENT; - } - - /* refresh the host's cache entry */ - if (NEED_CHECK_PROVIDER(cmd_ctx->domain->provider)) { - req = sss_dp_get_ssh_host_send(cmd_ctx, cmd_ctx->cctx->rctx, - cmd_ctx->domain, false, - cmd_ctx->name, cmd_ctx->alias); - if (!req) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Out of memory sending data provider request\n"); - return ENOMEM; - } - - cb_ctx = talloc_zero(cmd_ctx, struct dp_callback_ctx); - if (!cb_ctx) { - talloc_zfree(req); - return ENOMEM; - } - - cb_ctx->callback = ssh_host_pubkeys_search_dp_callback; - cb_ctx->ptr = cmd_ctx; - cb_ctx->cctx = cmd_ctx->cctx; - cb_ctx->mem_ctx = cmd_ctx; - - tevent_req_set_callback(req, ssh_dp_send_req_done, cb_ctx); - - /* tell caller we are in an async call */ - return EAGAIN; - } - - return ssh_host_pubkeys_search_next(cmd_ctx); -} - -static errno_t -ssh_host_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx) -{ - errno_t ret; - struct sysdb_ctx *sysdb; - const char *attrs[] = { SYSDB_NAME, SYSDB_SSH_PUBKEY, NULL }; - - DEBUG(SSSDBG_TRACE_FUNC, - "Requesting SSH host public keys for [%s@%s]\n", - cmd_ctx->name, cmd_ctx->domain->name); - - sysdb = cmd_ctx->domain->sysdb; - if (sysdb == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE, - "Fatal: Sysdb CTX not found for this domain!\n"); - return EFAULT; - } - - ret = sysdb_get_ssh_host(cmd_ctx, cmd_ctx->domain, - cmd_ctx->name, attrs, &cmd_ctx->result); - if (ret != EOK && ret != ENOENT) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Failed to make request to our cache!\n"); - return EIO; - } - - if (ret == ENOENT) { - /* if a multidomain search, try with next */ - if (cmd_ctx->check_next) { - cmd_ctx->domain = get_next_domain(cmd_ctx->domain, false); - return ssh_host_pubkeys_search(cmd_ctx); - } - - DEBUG(SSSDBG_OP_FAILURE, - "No attributes for host [%s] found.\n", cmd_ctx->name); - - return ENOENT; - } - - return EOK; -} - -static void -ssh_host_pubkeys_search_dp_callback(uint16_t err_maj, - uint32_t err_min, - const char *err_msg, - void *ptr) -{ - struct ssh_cmd_ctx *cmd_ctx = talloc_get_type(ptr, struct ssh_cmd_ctx); - errno_t ret; - - if (err_maj) { - DEBUG(SSSDBG_OP_FAILURE, - "Unable to get information from Data Provider\n" - "Error: %u, %u, %s\n", - (unsigned int)err_maj, (unsigned int)err_min, err_msg); - } - - ret = ssh_host_pubkeys_search_next(cmd_ctx); - ssh_cmd_get_host_pubkeys_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; - errno_t ret; - char *name, *pubkey; - char *result = NULL; - 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++) { - ret = sss_ssh_format_pubkey(tmp_ctx, &ent->pubkeys[i], &pubkey); - if (ret != EOK) { - 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++) { - ret = sss_ssh_format_pubkey(tmp_ctx, &ent->pubkeys[i], &pubkey); - if (ret != EOK) { - 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) -{ - 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 ssh_ctx *ssh_ctx = (struct ssh_ctx *)cctx->rctx->pvt_ctx; - struct sysdb_ctx *sysdb; - time_t now = time(NULL); - struct ldb_message **hosts; - size_t num_hosts, i; - struct sss_ssh_ent *ent; - int fd = -1; - char *filename = NULL; - char *entstr; - ssize_t wret; - - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - return ENOMEM; - } - - if (cmd_ctx->domain) { - ret = sysdb_update_ssh_known_host_expire(cmd_ctx->domain, - cmd_ctx->name, now, - ssh_ctx->known_hosts_timeout); - if (ret != EOK && ret != ENOENT) { - goto done; - } - } - - /* write known_hosts file */ - filename = talloc_strdup(tmp_ctx, SSS_SSH_KNOWN_HOSTS_TEMP_TMPL); - if (!filename) { - ret = ENOMEM; - goto done; - } - - fd = sss_unique_file_ex(tmp_ctx, filename, 0133, &ret); - if (fd == -1) { - filename = NULL; - goto done; - } - - for (; dom; dom = get_next_domain(dom, false)) { - sysdb = dom->sysdb; - if (sysdb == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE, - "Fatal: Sysdb CTX not found for this domain!\n"); - ret = EFAULT; - goto done; - } - - ret = sysdb_get_ssh_known_hosts(tmp_ctx, dom, now, attrs, - &hosts, &num_hosts); - if (ret != EOK) { - if (ret != ENOENT) { - DEBUG(SSSDBG_OP_FAILURE, - "Host search failed for domain [%s]\n", dom->name); - } - continue; - } - - for (i = 0; i < num_hosts; i++) { - ret = sss_ssh_make_ent(tmp_ctx, hosts[i], &ent); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "Failed to get SSH host public keys\n"); - continue; - } - - 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); - } - - ret = fchmod(fd, 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); - } - talloc_free(tmp_ctx); - - return ret; -} - -static errno_t -ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx, - char *default_domain) -{ - struct cli_protocol *pctx; - struct ssh_ctx *ssh_ctx; - errno_t ret; - uint8_t *body; - size_t body_len; - size_t c = 0; - uint32_t flags; - uint32_t name_len; - char *name; - uint32_t alias_len; - char *alias = NULL; - uint32_t domain_len; - char *domain = NULL; - - ssh_ctx = talloc_get_type(cmd_ctx->cctx->rctx->pvt_ctx, struct ssh_ctx); - pctx = talloc_get_type(cmd_ctx->cctx->protocol_ctx, struct cli_protocol); - - sss_packet_get_body(pctx->creq->in, &body, &body_len); - - SAFEALIGN_COPY_UINT32_CHECK(&flags, body+c, body_len, &c); - if (flags & ~(uint32_t)SSS_SSH_REQ_MASK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Invalid flags received [0x%x]\n", flags); - return EINVAL; - } - - SAFEALIGN_COPY_UINT32_CHECK(&name_len, body+c, body_len, &c); - if (name_len == 0 || name_len > body_len - c) { - DEBUG(SSSDBG_CRIT_FAILURE, "Invalid name length\n"); - return EINVAL; - } - - name = (char *)(body+c); - if (!sss_utf8_check((const uint8_t *)name, name_len-1) || - name[name_len-1] != 0) { - DEBUG(SSSDBG_CRIT_FAILURE, "Name is not valid UTF-8 string\n"); - return EINVAL; - } - c += name_len; - - 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"); - return EINVAL; - } - - alias = (char *)(body+c); - if (!sss_utf8_check((const uint8_t *)alias, alias_len-1) || - alias[alias_len-1] != 0) { - DEBUG(SSSDBG_CRIT_FAILURE, "Alias is not valid UTF-8 string\n"); - return EINVAL; - } - c += alias_len; - } - - 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; - } else { - domain = default_domain; - } - - 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, - 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->name = talloc_strdup(cmd_ctx, name); - if (!cmd_ctx->name) return ENOMEM; - } - - if (cmd_ctx->domname == NULL && 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; -} - -static errno_t get_valid_certs_keys(TALLOC_CTX *mem_ctx, - struct ssh_cmd_ctx *cmd_ctx, - struct ldb_message_element *el_cert, - struct ssh_ctx *ssh_ctx, - struct ldb_message_element **_el_res) -{ - TALLOC_CTX *tmp_ctx; - uint8_t *key; - size_t key_len; - char *cert_verification_opts; - struct cert_verify_opts *cert_verify_opts; - int ret; - struct ldb_message_element *el_res; - struct cli_ctx *cctx = cmd_ctx->cctx; - size_t d; - - if (el_cert == NULL) { - DEBUG(SSSDBG_TRACE_ALL, "Mssing element, nothing to do.\n"); - return EOK; - } - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); - return ENOMEM; - } - - ret = confdb_get_string(cctx->rctx->cdb, tmp_ctx, - CONFDB_MONITOR_CONF_ENTRY, - CONFDB_MONITOR_CERT_VERIFICATION, NULL, - &cert_verification_opts); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Failed to read p11_child_timeout from confdb: [%d] %s\n", - ret, sss_strerror(ret)); - goto done; - } - - ret = parse_cert_verify_opts(tmp_ctx, cert_verification_opts, - &cert_verify_opts); - if (ret != EOK) { - DEBUG(SSSDBG_FATAL_FAILURE, - "Failed to parse verifiy option.\n"); - goto done; - } - - el_res = talloc_zero(tmp_ctx, struct ldb_message_element); - if (el_res == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n"); - ret = ENOMEM; - goto done; - } - - el_res->values = talloc_array(el_res, struct ldb_val, el_cert->num_values); - if (el_res->values == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n"); - ret = ENOMEM; - goto done; - } - - for (d = 0; d < el_cert->num_values; d++) { - ret = cert_to_ssh_key(tmp_ctx, ssh_ctx->ca_db, - el_cert->values[d].data, - el_cert->values[d].length, - cert_verify_opts, &key, &key_len); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "cert_to_ssh_key failed, ignoring.\n"); - continue; - } - - el_res->values[el_res->num_values].data = - talloc_steal(el_res->values, key); - el_res->values[el_res->num_values].length = key_len; - el_res->num_values++; - } - - if (el_res->num_values == 0) { - *_el_res = NULL; - } else { - *_el_res = talloc_steal(mem_ctx, el_res); - } - - ret = EOK; - -done: - - talloc_free(tmp_ctx); - - return ret; -} - -static errno_t decode_and_add_base64_data(struct ssh_cmd_ctx *cmd_ctx, - struct ldb_message_element *el, - bool skip_base64_decode, - struct ssh_ctx *ssh_ctx, - size_t fqname_len, - const char *fqname, - size_t *c) -{ - struct cli_protocol *pctx; - uint8_t *key; - size_t key_len; - uint8_t *body; - size_t body_len; - int ret; - size_t d; - TALLOC_CTX *tmp_ctx; - - if (el == NULL) { - DEBUG(SSSDBG_TRACE_ALL, "Mssing element, nothing to do.\n"); - return EOK; - } - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); - return ENOMEM; - } - - pctx = talloc_get_type(cmd_ctx->cctx->protocol_ctx, struct cli_protocol); - - for (d = 0; d < el->num_values; d++) { - if (skip_base64_decode) { - key = el->values[d].data; - key_len = el->values[d].length; - } else { - key = sss_base64_decode(tmp_ctx, (const char *) el->values[d].data, - &key_len); - if (key == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n"); - ret = ENOMEM; - goto done; - } - } - - ret = sss_packet_grow(pctx->creq->out, - 3*sizeof(uint32_t) + key_len + fqname_len); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n"); - goto done; - } - sss_packet_get_body(pctx->creq->out, &body, &body_len); - - SAFEALIGN_SET_UINT32(body+(*c), 0, c); - SAFEALIGN_SET_UINT32(body+(*c), fqname_len, c); - safealign_memcpy(body+(*c), fqname, fqname_len, c); - SAFEALIGN_SET_UINT32(body+(*c), key_len, c); - safealign_memcpy(body+(*c), key, key_len, c); - - } - - ret = EOK; - -done: - talloc_free(tmp_ctx); - - return ret; -} - -static errno_t -ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx) -{ - errno_t ret; - uint8_t *body; - size_t body_len; - size_t c = 0; - struct ldb_message_element *el = NULL; - struct ldb_message_element *el_override = NULL; - struct ldb_message_element *el_orig = NULL; - struct ldb_message_element *el_user_cert = NULL; - struct ldb_message_element *el_user_cert_keys = NULL; - uint32_t count = 0; - const char *name; - uint32_t name_len; - TALLOC_CTX *tmp_ctx; - struct ssh_ctx *ssh_ctx; - struct cli_protocol *pctx; - - ssh_ctx = talloc_get_type(cmd_ctx->cctx->rctx->pvt_ctx, struct ssh_ctx); - pctx = talloc_get_type(cmd_ctx->cctx->protocol_ctx, struct cli_protocol); - - ret = sss_packet_new(pctx->creq, 0, - sss_packet_get_cmd(pctx->creq->in), - &pctx->creq->out); - if (ret != EOK) { - return ret; - } - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); - return ENOMEM; - } - - el = ldb_msg_find_element(cmd_ctx->result, SYSDB_SSH_PUBKEY); - if (el) { - count = el->num_values; - } - - el_orig = ldb_msg_find_element(cmd_ctx->result, - ORIGINALAD_PREFIX SYSDB_SSH_PUBKEY); - if (el_orig) { - count += el_orig->num_values; - } - - if (DOM_HAS_VIEWS(cmd_ctx->domain)) { - el_override = ldb_msg_find_element(cmd_ctx->result, - OVERRIDE_PREFIX SYSDB_SSH_PUBKEY); - if (el_override) { - count += el_override->num_values; - } - } - - el_user_cert = ldb_msg_find_element(cmd_ctx->result, SYSDB_USER_CERT); - if (el_user_cert) { - ret = get_valid_certs_keys(cmd_ctx, cmd_ctx, el_user_cert, ssh_ctx, - &el_user_cert_keys); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "get_valid_certs_keys failed.\n"); - goto done; - } - - if (el_user_cert_keys) { - count += el_user_cert_keys->num_values; - } - } - - ret = sss_packet_grow(pctx->creq->out, 2*sizeof(uint32_t)); - if (ret != EOK) { - goto done; - } - sss_packet_get_body(pctx->creq->out, &body, &body_len); - - SAFEALIGN_SET_UINT32(body+c, count, &c); - SAFEALIGN_SET_UINT32(body+c, 0, &c); - - if (count == 0) { - ret = EOK; - goto done; - } - - name = ldb_msg_find_attr_as_string(cmd_ctx->result, SYSDB_NAME, NULL); - if (!name) { - DEBUG(SSSDBG_OP_FAILURE, - "Got unnamed result for [%s@%s]\n", - cmd_ctx->name, cmd_ctx->domain->name); - ret = ENOENT; - goto done; - } - - name_len = strlen(name) + 1; - - ret = decode_and_add_base64_data(cmd_ctx, el, false, ssh_ctx, - name_len, name, &c); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n"); - goto done; - } - - ret = decode_and_add_base64_data(cmd_ctx, el_orig, false, ssh_ctx, - name_len, name, &c); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n"); - goto done; - } - - ret = decode_and_add_base64_data(cmd_ctx, el_override, false, ssh_ctx, - name_len, name, &c); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n"); - goto done; - } - - ret = decode_and_add_base64_data(cmd_ctx, el_user_cert_keys, true, ssh_ctx, - name_len, name, &c); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n"); - goto done; - } - - ret = EOK; - -done: - - talloc_free(tmp_ctx); - - return ret; -} - -static errno_t -ssh_cmd_send_error(struct ssh_cmd_ctx *cmd_ctx, - errno_t error) -{ - struct cli_ctx *cctx = cmd_ctx->cctx; - errno_t ret; - - ret = sss_cmd_send_error(cctx, error); - if (ret != EOK) { - return ret; - } - - sss_cmd_done(cctx, cmd_ctx); - - return EOK; -} - -static errno_t -ssh_cmd_send_reply(struct ssh_cmd_ctx *cmd_ctx) -{ - struct cli_protocol *pctx; - errno_t ret; - - pctx = talloc_get_type(cmd_ctx->cctx->protocol_ctx, struct cli_protocol); - - /* create response packet */ - ret = ssh_cmd_build_reply(cmd_ctx); - if (ret != EOK) { - return ret; - } - - sss_packet_set_error(pctx->creq->out, EOK); - sss_cmd_done(cmd_ctx->cctx, cmd_ctx); - - return EOK; -} - -static errno_t -ssh_cmd_done(struct ssh_cmd_ctx *cmd_ctx, - errno_t ret) -{ - switch (ret) { - case EOK: - ret = ssh_cmd_send_reply(cmd_ctx); - break; - - case EAGAIN: - return EOK; - - case EFAULT: - break; - - default: - ret = ssh_cmd_send_error(cmd_ctx, ret); - break; - } - - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Fatal error, killing connection!\n"); - talloc_free(cmd_ctx->cctx); - return EFAULT; - } - - return EOK; -} - -static errno_t -ssh_cmd_get_user_pubkeys_done(struct ssh_cmd_ctx *cmd_ctx, - errno_t ret) -{ - return ssh_cmd_done(cmd_ctx, ret); -} - -static errno_t -ssh_cmd_get_host_pubkeys_done(struct ssh_cmd_ctx *cmd_ctx, - errno_t ret) -{ - if (ret == EOK || ret == ENOENT) { - ssh_host_pubkeys_update_known_hosts(cmd_ctx); - } - - return ssh_cmd_done(cmd_ctx, ret); -} - -struct cli_protocol_version *register_cli_protocol_version(void) -{ - static struct cli_protocol_version ssh_cli_protocol_version[] = { - {0, NULL, NULL} - }; - - return ssh_cli_protocol_version; -} - -struct sss_cmd_table *get_ssh_cmds(void) { - static struct sss_cmd_table ssh_cmds[] = { - {SSS_GET_VERSION, sss_cmd_get_version}, - {SSS_SSH_GET_USER_PUBKEYS, sss_ssh_cmd_get_user_pubkeys}, - {SSS_SSH_GET_HOST_PUBKEYS, sss_ssh_cmd_get_host_pubkeys}, - {SSS_CLI_NULL, NULL} - }; - - return ssh_cmds; -} |
