From 96c0d81f51e80fdb7ddab1fbf870d71843e7425f Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Wed, 14 Mar 2012 07:54:16 -0400 Subject: SSH: Canonicalize host name and do reverse DNS lookup SSH: Allow clients to explicitly specify host alias This change removes the need to canonicalize host names on the responder side - the relevant code was removed. SSH: Canonicalize host name and do reverse DNS lookup in sss_ssh_knownhostsproxy https://fedorahosted.org/sssd/ticket/1245 --- Makefile.am | 4 +- src/responder/ssh/sshsrv.c | 7 -- src/responder/ssh/sshsrv_cmd.c | 97 +++++++++++----------------- src/responder/ssh/sshsrv_private.h | 1 - src/sss_client/ssh/sss_ssh_authorizedkeys.c | 9 +-- src/sss_client/ssh/sss_ssh_client.c | 18 +++++- src/sss_client/ssh/sss_ssh_client.h | 1 + src/sss_client/ssh/sss_ssh_knownhostsproxy.c | 65 +++++++++++-------- 8 files changed, 101 insertions(+), 101 deletions(-) diff --git a/Makefile.am b/Makefile.am index f44296580..a4d3fc12c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -533,11 +533,9 @@ if BUILD_SSH sssd_ssh_SOURCES = \ src/responder/ssh/sshsrv.c \ src/responder/ssh/sshsrv_cmd.c \ - $(SSSD_RESPONDER_OBJ) \ - $(SSSD_RESOLV_OBJ) + $(SSSD_RESPONDER_OBJ) sssd_ssh_LDADD = \ $(SSSD_LIBS) \ - $(CARES_LIBS) \ libsss_util.la endif diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c index 242704530..28a5e9c01 100644 --- a/src/responder/ssh/sshsrv.c +++ b/src/responder/ssh/sshsrv.c @@ -26,7 +26,6 @@ #include "responder/common/responder.h" #include "responder/ssh/sshsrv_private.h" #include "providers/data_provider.h" -#include "resolv/async_resolv.h" struct sbus_method monitor_ssh_methods[] = { { MON_CLI_METHOD_PING, monitor_common_pong }, @@ -129,12 +128,6 @@ int ssh_process_init(TALLOC_CTX *mem_ctx, ssh_dp_reconnect_init, iter); } - ret = resolv_init(ssh_ctx, ev, RESOLV_DEFAULT_TIMEOUT, &ssh_ctx->resolv); - if (ret != EOK) { - DEBUG(SSSDBG_FATAL_FAILURE, ("Could not set up resolver context\n")); - 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 be79f0c9c..9d553f73e 100644 --- a/src/responder/ssh/sshsrv_cmd.c +++ b/src/responder/ssh/sshsrv_cmd.c @@ -33,7 +33,6 @@ #include "responder/common/responder.h" #include "responder/common/responder_packet.h" #include "responder/ssh/sshsrv_private.h" -#include "resolv/async_resolv.h" static errno_t ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx); @@ -85,16 +84,14 @@ done: return ssh_cmd_done(cmd_ctx, ret); } -static void -ssh_host_pubkeys_resolv_done(struct tevent_req *req); +static errno_t +ssh_host_pubkeys_search(struct ssh_cmd_ctx *cmd_ctx); static int sss_ssh_cmd_get_host_pubkeys(struct cli_ctx *cctx) { - struct ssh_ctx *ssh_ctx = cctx->rctx->pvt_ctx; - struct ssh_cmd_ctx *cmd_ctx; errno_t ret; - struct tevent_req *req; + struct ssh_cmd_ctx *cmd_ctx; cmd_ctx = talloc_zero(cctx, struct ssh_cmd_ctx); if (!cmd_ctx) { @@ -109,8 +106,9 @@ sss_ssh_cmd_get_host_pubkeys(struct cli_ctx *cctx) } DEBUG(SSSDBG_TRACE_FUNC, - ("Requesting SSH host public keys for [%s] from [%s]\n", - cmd_ctx->name, cmd_ctx->domname ? cmd_ctx->domname : "")); + ("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 : "")); if (cmd_ctx->domname) { cmd_ctx->domain = responder_get_domain(cctx->rctx->domains, @@ -124,54 +122,12 @@ sss_ssh_cmd_get_host_pubkeys(struct cli_ctx *cctx) cmd_ctx->check_next = true; } - /* canonicalize host name */ - req = resolv_gethostbyname_send(cmd_ctx, cctx->rctx->ev, ssh_ctx->resolv, - cmd_ctx->name, IPV4_FIRST, - default_host_dbs); - if (!req) { - ret = ENOMEM; - DEBUG(SSSDBG_OP_FAILURE, - ("Out of memory sending resolver request\n")); - goto done; - } - - tevent_req_set_callback(req, ssh_host_pubkeys_resolv_done, cmd_ctx); - ret = EAGAIN; + ret = ssh_host_pubkeys_search(cmd_ctx); done: return ssh_cmd_done(cmd_ctx, ret); } -static errno_t -ssh_host_pubkeys_search(struct ssh_cmd_ctx *cmd_ctx); - -static void -ssh_host_pubkeys_resolv_done(struct tevent_req *req) -{ - struct ssh_cmd_ctx *cmd_ctx = tevent_req_callback_data(req, - struct ssh_cmd_ctx); - errno_t ret; - int resolv_status; - struct resolv_hostent *hostent; - - ret = resolv_gethostbyname_recv(req, cmd_ctx, - &resolv_status, NULL, &hostent); - talloc_zfree(req); - if (ret == EOK) { - if (strcmp(cmd_ctx->name, hostent->name) != 0) { - cmd_ctx->alias = cmd_ctx->name; - cmd_ctx->name = hostent->name; - } - } else { - DEBUG(SSSDBG_OP_FAILURE, - ("Failed to resolve [%s]: %s\n", cmd_ctx->name, - resolv_strerror(resolv_status))); - } - - ret = ssh_host_pubkeys_search(cmd_ctx); - ssh_cmd_done(cmd_ctx, ret); -} - static void ssh_dp_send_req_done(struct tevent_req *req) { @@ -600,28 +556,30 @@ ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx) uint8_t *body; size_t body_len; size_t c = 0; - uint32_t reserved; + uint32_t flags; uint32_t name_len; char *name; + uint32_t alias_len; + char *alias; sss_packet_get_body(cctx->creq->in, &body, &body_len); - SAFEALIGN_COPY_UINT32_CHECK(&reserved, body+c, body_len, &c); - if (reserved != 0) { + SAFEALIGN_COPY_UINT32_CHECK(&flags, body+c, body_len, &c); + if (flags > 1) { + 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) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Zero-length name is not valid\n")); return EINVAL; } name = (char *)(body+c); - if (!sss_utf8_check((const uint8_t *)name, name_len-1)) { - DEBUG(SSSDBG_CRIT_FAILURE, ("Supplied data is not valid UTF-8 string\n")); - return EINVAL; - } - if (strnlen(name, name_len) != name_len-1) { + 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; @@ -633,6 +591,27 @@ ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx) return ENOENT; } + if (flags & 1) { + SAFEALIGN_COPY_UINT32_CHECK(&alias_len, body+c, body_len, &c); + if (alias_len == 0) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Zero-length alias is not valid\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 (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/responder/ssh/sshsrv_private.h b/src/responder/ssh/sshsrv_private.h index 315e4f294..ab9edf7c3 100644 --- a/src/responder/ssh/sshsrv_private.h +++ b/src/responder/ssh/sshsrv_private.h @@ -31,7 +31,6 @@ struct ssh_ctx { struct resp_ctx *rctx; - struct resolv_ctx *resolv; }; 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 de9454221..19a1ac6a7 100644 --- a/src/sss_client/ssh/sss_ssh_authorizedkeys.c +++ b/src/sss_client/ssh/sss_ssh_authorizedkeys.c @@ -97,7 +97,8 @@ int main(int argc, const char **argv) } /* look up public keys */ - ret = sss_ssh_get_ent(mem_ctx, SSS_SSH_GET_USER_PUBKEYS, user, &ent); + ret = sss_ssh_get_ent(mem_ctx, SSS_SSH_GET_USER_PUBKEYS, + user, NULL, &ent); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("sss_ssh_get_ent() failed (%d): %s\n", ret, strerror(ret))); @@ -111,9 +112,9 @@ int main(int argc, const char **argv) repr = sss_ssh_format_pubkey(mem_ctx, ent, &ent->pubkeys[i], SSS_SSH_FORMAT_OPENSSH); if (!repr) { - DEBUG(SSSDBG_OP_FAILURE, - ("Out of memory formatting SSH public key\n")); - continue; + ERROR("Not enough memory\n"); + ret = EXIT_FAILURE; + goto fini; } printf("%s\n", repr); diff --git a/src/sss_client/ssh/sss_ssh_client.c b/src/sss_client/ssh/sss_ssh_client.c index 82507787d..f8b82d83b 100644 --- a/src/sss_client/ssh/sss_ssh_client.c +++ b/src/sss_client/ssh/sss_ssh_client.c @@ -70,9 +70,13 @@ int set_locale(void) /* SSH public key request: * - * 0..3: flags (unsigned int, must be 0) + * 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) + * } * * SSH public key reply: * @@ -89,6 +93,7 @@ errno_t sss_ssh_get_ent(TALLOC_CTX *mem_ctx, enum sss_cli_command command, const char *name, + const char *alias, struct sss_ssh_ent **result) { TALLOC_CTX *tmp_ctx; @@ -96,6 +101,7 @@ sss_ssh_get_ent(TALLOC_CTX *mem_ctx, errno_t ret; uint32_t flags; uint32_t name_len; + uint32_t alias_len; size_t req_len; uint8_t *req = NULL; size_t c = 0; @@ -115,6 +121,12 @@ sss_ssh_get_ent(TALLOC_CTX *mem_ctx, name_len = strlen(name)+1; req_len = 2*sizeof(uint32_t) + name_len; + if (alias) { + flags |= 1; + alias_len = strlen(alias)+1; + req_len += sizeof(uint32_t) + alias_len; + } + req = talloc_array(tmp_ctx, uint8_t, req_len); if (!req) { ret = ENOMEM; @@ -124,6 +136,10 @@ sss_ssh_get_ent(TALLOC_CTX *mem_ctx, SAFEALIGN_SET_UINT32(req+c, flags, &c); SAFEALIGN_SET_UINT32(req+c, name_len, &c); safealign_memcpy(req+c, name, name_len, &c); + if (alias) { + SAFEALIGN_SET_UINT32(req+c, alias_len, &c); + safealign_memcpy(req+c, alias, alias_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 1c8db1ff3..7ffc3983e 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 *alias, struct sss_ssh_ent **result); #endif /* _SSS_SSH_CLIENT_H_ */ diff --git a/src/sss_client/ssh/sss_ssh_knownhostsproxy.c b/src/sss_client/ssh/sss_ssh_knownhostsproxy.c index 9dae3cb6c..1e4a934ea 100644 --- a/src/sss_client/ssh/sss_ssh_knownhostsproxy.c +++ b/src/sss_client/ssh/sss_ssh_knownhostsproxy.c @@ -40,11 +40,8 @@ /* connect to server using socket */ static int -connect_socket(const char *host, - const char *port) +connect_socket(int family, struct sockaddr *addr, size_t addr_len) { - struct addrinfo ai_hint; - struct addrinfo *ai = NULL; int flags; int sock = -1; struct pollfd fds[2]; @@ -53,21 +50,6 @@ connect_socket(const char *host, ssize_t res; int ret; - /* get 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_ADDRCONFIG | AI_NUMERICSERV; - - ret = getaddrinfo(host, port, &ai_hint, &ai); - if (ret) { - DEBUG(SSSDBG_CRIT_FAILURE, - ("getaddrinfo() failed (%d): %s\n", ret, gai_strerror(ret))); - ret = ENOENT; - goto done; - } - /* set O_NONBLOCK on standard input */ flags = fcntl(0, F_GETFL); if (flags == -1) { @@ -86,7 +68,7 @@ connect_socket(const char *host, } /* create socket */ - sock = socket(ai[0].ai_family, SOCK_STREAM, IPPROTO_TCP); + sock = socket(family, SOCK_STREAM, IPPROTO_TCP); if (sock == -1) { ret = errno; DEBUG(SSSDBG_OP_FAILURE, ("socket() failed (%d): %s\n", @@ -96,7 +78,7 @@ connect_socket(const char *host, } /* connect to the server */ - ret = connect(sock, ai[0].ai_addr, ai[0].ai_addrlen); + ret = connect(sock, addr, addr_len); if (ret == -1) { ret = errno; DEBUG(SSSDBG_OP_FAILURE, ("connect() failed (%d): %s\n", @@ -175,7 +157,6 @@ connect_socket(const char *host, DEBUG(SSSDBG_TRACE_FUNC, ("Connection closed\n")); done: - if (ai) freeaddrinfo(ai); if (sock >= 0) close(sock); return ret; @@ -216,6 +197,9 @@ int main(int argc, const char **argv) POPT_TABLEEND }; poptContext pc = NULL; + struct addrinfo ai_hint; + struct addrinfo *ai = NULL; + char canonhost[NI_MAXHOST]; const char *host; struct sss_ssh_ent *ent; int ret; @@ -262,20 +246,48 @@ int main(int argc, const char **argv) ret, fini); } + /* get 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_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("Host name cannot be resolved\n"); + ret = EXIT_FAILURE; + goto fini; + } + + /* canonicalize hostname */ + ret = getnameinfo(ai[0].ai_addr, ai[0].ai_addrlen, + canonhost, NI_MAXHOST, NULL, 0, NI_NAMEREQD); + if (ret) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("getaddrinfo() failed (%d): %s\n", ret, gai_strerror(ret))); + ERROR("Reverse lookup failed\n"); + ret = EXIT_FAILURE; + goto fini; + } + /* append domain to hostname if domain is specified */ if (pc_domain) { - host = talloc_asprintf(mem_ctx, "%s@%s", pc_host, pc_domain); + host = talloc_asprintf(mem_ctx, "%s@%s", canonhost, pc_domain); if (!host) { ERROR("Not enough memory\n"); ret = EXIT_FAILURE; goto fini; } } else { - host = pc_host; + host = canonhost; } /* look up public keys */ - ret = sss_ssh_get_ent(mem_ctx, SSS_SSH_GET_HOST_PUBKEYS, host, &ent); + ret = sss_ssh_get_ent(mem_ctx, SSS_SSH_GET_HOST_PUBKEYS, + host, pc_host, &ent); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("sss_ssh_get_ent() failed (%d): %s\n", ret, strerror(ret))); @@ -286,12 +298,13 @@ int main(int argc, const char **argv) if (pc_args) { ret = connect_proxy_command(discard_const(pc_args)); } else { - ret = connect_socket(pc_host, pc_port); + ret = connect_socket(ai[0].ai_family, ai[0].ai_addr, ai[0].ai_addrlen); } ret = (ret == EOK) ? EXIT_SUCCESS : EXIT_FAILURE; fini: poptFreeContext(pc); + if (ai) freeaddrinfo(ai); talloc_free(mem_ctx); return ret; -- cgit