diff --git a/auth-options.c b/auth-options.c index edbaf80bb..b399b91e3 100644 --- a/auth-options.c +++ b/auth-options.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-options.c,v 1.70 2015/12/10 17:08:40 mmcc Exp $ */ +/* $OpenBSD: auth-options.c,v 1.71 2016/03/07 19:02:43 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -29,6 +29,7 @@ #include "ssherr.h" #include "log.h" #include "canohost.h" +#include "packet.h" #include "sshbuf.h" #include "misc.h" #include "channels.h" @@ -120,6 +121,7 @@ match_flag(const char *opt, int allow_negate, char **optsp, const char *msg) int auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) { + struct ssh *ssh = active_state; /* XXX */ const char *cp; int i, r; @@ -273,9 +275,9 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) } cp = "from=\""; if (strncasecmp(opts, cp, strlen(cp)) == 0) { - const char *remote_ip = get_remote_ipaddr(); - const char *remote_host = get_canonical_hostname( - options.use_dns); + const char *remote_ip = ssh_remote_ipaddr(ssh); + const char *remote_host = auth_get_canonical_hostname( + ssh, options.use_dns); char *patterns = xmalloc(strlen(opts) + 1); opts += strlen(cp); @@ -457,6 +459,7 @@ parse_option_list(struct sshbuf *oblob, struct passwd *pw, char **cert_forced_command, int *cert_source_address_done) { + struct ssh *ssh = active_state; /* XXX */ char *command, *allowed; const char *remote_ip; char *name = NULL; @@ -530,7 +533,7 @@ parse_option_list(struct sshbuf *oblob, struct passwd *pw, free(allowed); goto out; } - remote_ip = get_remote_ipaddr(); + remote_ip = ssh_remote_ipaddr(ssh); result = addr_match_cidr_list(remote_ip, allowed); free(allowed); diff --git a/auth-rh-rsa.c b/auth-rh-rsa.c index 2e20396ea..057335ba4 100644 --- a/auth-rh-rsa.c +++ b/auth-rh-rsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-rh-rsa.c,v 1.44 2014/07/15 15:54:14 millert Exp $ */ +/* $OpenBSD: auth-rh-rsa.c,v 1.45 2016/03/07 19:02:43 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -42,8 +42,8 @@ extern ServerOptions options; int -auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost, - Key *client_host_key) +auth_rhosts_rsa_key_allowed(struct passwd *pw, const char *cuser, + const char *chost, Key *client_host_key) { HostStatus host_status; @@ -68,7 +68,8 @@ auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost, int auth_rhosts_rsa(Authctxt *authctxt, char *cuser, Key *client_host_key) { - char *chost; + struct ssh *ssh = active_state; /* XXX */ + const char *chost; struct passwd *pw = authctxt->pw; debug("Trying rhosts with RSA host authentication for client user %.100s", @@ -78,7 +79,7 @@ auth_rhosts_rsa(Authctxt *authctxt, char *cuser, Key *client_host_key) client_host_key->rsa == NULL) return 0; - chost = (char *)get_canonical_hostname(options.use_dns); + chost = auth_get_canonical_hostname(ssh, options.use_dns); debug("Rhosts RSA authentication: canonical host %.900s", chost); if (!PRIVSEP(auth_rhosts_rsa_key_allowed(pw, cuser, chost, client_host_key))) { diff --git a/auth-rhosts.c b/auth-rhosts.c index ee9e827af..0ef344712 100644 --- a/auth-rhosts.c +++ b/auth-rhosts.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-rhosts.c,v 1.46 2014/12/23 22:42:48 djm Exp $ */ +/* $OpenBSD: auth-rhosts.c,v 1.47 2016/03/07 19:02:43 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -30,14 +30,15 @@ #include #include "packet.h" -#include "buffer.h" #include "uidswap.h" #include "pathnames.h" #include "log.h" #include "misc.h" +#include "buffer.h" /* XXX */ +#include "key.h" /* XXX */ #include "servconf.h" #include "canohost.h" -#include "key.h" +#include "sshkey.h" #include "hostfile.h" #include "auth.h" @@ -189,10 +190,11 @@ check_rhosts_file(const char *filename, const char *hostname, int auth_rhosts(struct passwd *pw, const char *client_user) { + struct ssh *ssh = active_state; /* XXX */ const char *hostname, *ipaddr; - hostname = get_canonical_hostname(options.use_dns); - ipaddr = get_remote_ipaddr(); + hostname = auth_get_canonical_hostname(ssh, options.use_dns); + ipaddr = ssh_remote_ipaddr(ssh); return auth_rhosts2(pw, client_user, hostname, ipaddr); } diff --git a/auth.c b/auth.c index 214c2c708..aae0593e7 100644 --- a/auth.c +++ b/auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth.c,v 1.113 2015/08/21 03:42:19 djm Exp $ */ +/* $OpenBSD: auth.c,v 1.114 2016/03/07 19:02:43 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -27,6 +27,7 @@ #include #include +#include #include @@ -50,6 +51,7 @@ #include #include #include +#include #include "xmalloc.h" #include "match.h" @@ -97,6 +99,7 @@ int auth_debug_init; int allowed_user(struct passwd * pw) { + struct ssh *ssh = active_state; /* XXX */ struct stat st; const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL; u_int i; @@ -182,8 +185,8 @@ allowed_user(struct passwd * pw) if (options.num_deny_users > 0 || options.num_allow_users > 0 || options.num_deny_groups > 0 || options.num_allow_groups > 0) { - hostname = get_canonical_hostname(options.use_dns); - ipaddr = get_remote_ipaddr(); + hostname = auth_get_canonical_hostname(ssh, options.use_dns); + ipaddr = ssh_remote_ipaddr(ssh); } /* Return false if user is listed in DenyUsers */ @@ -274,6 +277,7 @@ void auth_log(Authctxt *authctxt, int authenticated, int partial, const char *method, const char *submethod) { + struct ssh *ssh = active_state; /* XXX */ void (*authlog) (const char *fmt,...) = verbose; char *authmsg; @@ -300,8 +304,8 @@ auth_log(Authctxt *authctxt, int authenticated, int partial, submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod, authctxt->valid ? "" : "invalid user ", authctxt->user, - get_remote_ipaddr(), - get_remote_port(), + ssh_remote_ipaddr(ssh), + ssh_remote_port(ssh), compat20 ? "ssh2" : "ssh1", authctxt->info != NULL ? ": " : "", authctxt->info != NULL ? authctxt->info : ""); @@ -331,12 +335,14 @@ auth_log(Authctxt *authctxt, int authenticated, int partial, void auth_maxtries_exceeded(Authctxt *authctxt) { + struct ssh *ssh = active_state; /* XXX */ + error("maximum authentication attempts exceeded for " "%s%.100s from %.200s port %d %s", authctxt->valid ? "" : "invalid user ", authctxt->user, - get_remote_ipaddr(), - get_remote_port(), + ssh_remote_ipaddr(ssh), + ssh_remote_port(ssh), compat20 ? "ssh2" : "ssh1"); packet_disconnect("Too many authentication failures"); /* NOTREACHED */ @@ -348,6 +354,8 @@ auth_maxtries_exceeded(Authctxt *authctxt) int auth_root_allowed(const char *method) { + struct ssh *ssh = active_state; /* XXX */ + switch (options.permit_root_login) { case PERMIT_YES: return 1; @@ -364,7 +372,8 @@ auth_root_allowed(const char *method) } break; } - logit("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr()); + logit("ROOT LOGIN REFUSED FROM %.200s port %d", + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); return 0; } @@ -604,6 +613,7 @@ auth_openprincipals(const char *file, struct passwd *pw, int strict_modes) struct passwd * getpwnamallow(const char *user) { + struct ssh *ssh = active_state; /* XXX */ #ifdef HAVE_LOGIN_CAP extern login_cap_t *lc; #ifdef BSD_AUTH @@ -639,8 +649,8 @@ getpwnamallow(const char *user) } #endif if (pw == NULL) { - logit("Invalid user %.100s from %.100s", - user, get_remote_ipaddr()); + logit("Invalid user %.100s from %.100s port %d", + user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); #ifdef CUSTOM_FAILED_LOGIN record_failed_login(user, get_canonical_hostname(options.use_dns), "ssh"); @@ -773,3 +783,118 @@ fakepw(void) return (&fake); } + +/* + * Returns the remote DNS hostname as a string. The returned string must not + * be freed. NB. this will usually trigger a DNS query the first time it is + * called. + * This function does additional checks on the hostname to mitigate some + * attacks on legacy rhosts-style authentication. + * XXX is RhostsRSAAuthentication vulnerable to these? + * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?) + */ + +static char * +remote_hostname(struct ssh *ssh) +{ + struct sockaddr_storage from; + socklen_t fromlen; + struct addrinfo hints, *ai, *aitop; + char name[NI_MAXHOST], ntop2[NI_MAXHOST]; + const char *ntop = ssh_remote_ipaddr(ssh); + + /* Get IP address of client. */ + fromlen = sizeof(from); + memset(&from, 0, sizeof(from)); + if (getpeername(ssh_packet_get_connection_in(ssh), + (struct sockaddr *)&from, &fromlen) < 0) { + debug("getpeername failed: %.100s", strerror(errno)); + return strdup(ntop); + } + + ipv64_normalise_mapped(&from, &fromlen); + if (from.ss_family == AF_INET6) + fromlen = sizeof(struct sockaddr_in6); + + debug3("Trying to reverse map address %.100s.", ntop); + /* Map the IP address to a host name. */ + if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), + NULL, 0, NI_NAMEREQD) != 0) { + /* Host name not found. Use ip address. */ + return strdup(ntop); + } + + /* + * if reverse lookup result looks like a numeric hostname, + * someone is trying to trick us by PTR record like following: + * 1.1.1.10.in-addr.arpa. IN PTR 2.3.4.5 + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(name, NULL, &hints, &ai) == 0) { + logit("Nasty PTR record \"%s\" is set up for %s, ignoring", + name, ntop); + freeaddrinfo(ai); + return strdup(ntop); + } + + /* Names are stored in lowercase. */ + lowercase(name); + + /* + * Map it back to an IP address and check that the given + * address actually is an address of this host. This is + * necessary because anyone with access to a name server can + * define arbitrary names for an IP address. Mapping from + * name to IP address can be trusted better (but can still be + * fooled if the intruder has access to the name server of + * the domain). + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = from.ss_family; + hints.ai_socktype = SOCK_STREAM; + if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { + logit("reverse mapping checking getaddrinfo for %.700s " + "[%s] failed - POSSIBLE BREAK-IN ATTEMPT!", name, ntop); + return strdup(ntop); + } + /* Look for the address from the list of addresses. */ + for (ai = aitop; ai; ai = ai->ai_next) { + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, + sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && + (strcmp(ntop, ntop2) == 0)) + break; + } + freeaddrinfo(aitop); + /* If we reached the end of the list, the address was not there. */ + if (ai == NULL) { + /* Address not found for the host name. */ + logit("Address %.100s maps to %.600s, but this does not " + "map back to the address - POSSIBLE BREAK-IN ATTEMPT!", + ntop, name); + return strdup(ntop); + } + return strdup(name); +} + +/* + * Return the canonical name of the host in the other side of the current + * connection. The host name is cached, so it is efficient to call this + * several times. + */ + +const char * +auth_get_canonical_hostname(struct ssh *ssh, int use_dns) +{ + static char *dnsname; + + if (!use_dns) + return ssh_remote_ipaddr(ssh); + else if (dnsname != NULL) + return dnsname; + else { + dnsname = remote_hostname(ssh); + return dnsname; + } +} diff --git a/auth.h b/auth.h index 2160154f4..038b59293 100644 --- a/auth.h +++ b/auth.h @@ -1,4 +1,4 @@ -/* $OpenBSD: auth.h,v 1.86 2015/12/04 16:41:28 markus Exp $ */ +/* $OpenBSD: auth.h,v 1.87 2016/03/07 19:02:43 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -197,6 +197,8 @@ FILE *auth_openkeyfile(const char *, struct passwd *, int); FILE *auth_openprincipals(const char *, struct passwd *, int); int auth_key_is_revoked(Key *); +const char *auth_get_canonical_hostname(struct ssh *, int); + HostStatus check_key_in_hostfiles(struct passwd *, Key *, const char *, const char *, const char *); diff --git a/auth2-hostbased.c b/auth2-hostbased.c index e2327cf77..1b3c3b202 100644 --- a/auth2-hostbased.c +++ b/auth2-hostbased.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-hostbased.c,v 1.25 2015/05/04 06:10:48 djm Exp $ */ +/* $OpenBSD: auth2-hostbased.c,v 1.26 2016/03/07 19:02:43 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -160,6 +160,7 @@ int hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, Key *key) { + struct ssh *ssh = active_state; /* XXX */ const char *resolvedname, *ipaddr, *lookup, *reason; HostStatus host_status; int len; @@ -168,8 +169,8 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, if (auth_key_is_revoked(key)) return 0; - resolvedname = get_canonical_hostname(options.use_dns); - ipaddr = get_remote_ipaddr(); + resolvedname = auth_get_canonical_hostname(ssh, options.use_dns); + ipaddr = ssh_remote_ipaddr(ssh); debug2("%s: chost %s resolvedname %s ipaddr %s", __func__, chost, resolvedname, ipaddr); diff --git a/canohost.c b/canohost.c index 223964ea3..f71a08568 100644 --- a/canohost.c +++ b/canohost.c @@ -1,4 +1,4 @@ -/* $OpenBSD: canohost.c,v 1.72 2015/03/01 15:44:40 millert Exp $ */ +/* $OpenBSD: canohost.c,v 1.73 2016/03/07 19:02:43 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -35,147 +35,6 @@ #include "canohost.h" #include "misc.h" -static void check_ip_options(int, char *); -static char *canonical_host_ip = NULL; -static int cached_port = -1; - -/* - * Return the canonical name of the host at the other end of the socket. The - * caller should free the returned string. - */ - -static char * -get_remote_hostname(int sock, int use_dns) -{ - struct sockaddr_storage from; - socklen_t fromlen; - struct addrinfo hints, *ai, *aitop; - char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST]; - - /* Get IP address of client. */ - fromlen = sizeof(from); - memset(&from, 0, sizeof(from)); - if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) { - debug("getpeername failed: %.100s", strerror(errno)); - cleanup_exit(255); - } - - if (from.ss_family == AF_INET) - check_ip_options(sock, ntop); - - ipv64_normalise_mapped(&from, &fromlen); - - if (from.ss_family == AF_INET6) - fromlen = sizeof(struct sockaddr_in6); - - if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop), - NULL, 0, NI_NUMERICHOST) != 0) - fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed"); - - if (!use_dns) - return xstrdup(ntop); - - debug3("Trying to reverse map address %.100s.", ntop); - /* Map the IP address to a host name. */ - if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), - NULL, 0, NI_NAMEREQD) != 0) { - /* Host name not found. Use ip address. */ - return xstrdup(ntop); - } - - /* - * if reverse lookup result looks like a numeric hostname, - * someone is trying to trick us by PTR record like following: - * 1.1.1.10.in-addr.arpa. IN PTR 2.3.4.5 - */ - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - hints.ai_flags = AI_NUMERICHOST; - if (getaddrinfo(name, NULL, &hints, &ai) == 0) { - logit("Nasty PTR record \"%s\" is set up for %s, ignoring", - name, ntop); - freeaddrinfo(ai); - return xstrdup(ntop); - } - - /* Names are stores in lowercase. */ - lowercase(name); - - /* - * Map it back to an IP address and check that the given - * address actually is an address of this host. This is - * necessary because anyone with access to a name server can - * define arbitrary names for an IP address. Mapping from - * name to IP address can be trusted better (but can still be - * fooled if the intruder has access to the name server of - * the domain). - */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = from.ss_family; - hints.ai_socktype = SOCK_STREAM; - if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { - logit("reverse mapping checking getaddrinfo for %.700s " - "[%s] failed - POSSIBLE BREAK-IN ATTEMPT!", name, ntop); - return xstrdup(ntop); - } - /* Look for the address from the list of addresses. */ - for (ai = aitop; ai; ai = ai->ai_next) { - if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, - sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && - (strcmp(ntop, ntop2) == 0)) - break; - } - freeaddrinfo(aitop); - /* If we reached the end of the list, the address was not there. */ - if (!ai) { - /* Address not found for the host name. */ - logit("Address %.100s maps to %.600s, but this does not " - "map back to the address - POSSIBLE BREAK-IN ATTEMPT!", - ntop, name); - return xstrdup(ntop); - } - return xstrdup(name); -} - -/* - * If IP options are supported, make sure there are none (log and - * disconnect them if any are found). Basically we are worried about - * source routing; it can be used to pretend you are somebody - * (ip-address) you are not. That itself may be "almost acceptable" - * under certain circumstances, but rhosts autentication is useless - * if source routing is accepted. Notice also that if we just dropped - * source routing here, the other side could use IP spoofing to do - * rest of the interaction and could still bypass security. So we - * exit here if we detect any IP options. - */ -/* IPv4 only */ -static void -check_ip_options(int sock, char *ipaddr) -{ -#ifdef IP_OPTIONS - u_char options[200]; - char text[sizeof(options) * 3 + 1]; - socklen_t option_size, i; - int ipproto; - struct protoent *ip; - - if ((ip = getprotobyname("ip")) != NULL) - ipproto = ip->p_proto; - else - ipproto = IPPROTO_IP; - option_size = sizeof(options); - if (getsockopt(sock, ipproto, IP_OPTIONS, options, - &option_size) >= 0 && option_size != 0) { - text[0] = '\0'; - for (i = 0; i < option_size; i++) - snprintf(text + i*3, sizeof(text) - i*3, - " %2.2x", options[i]); - fatal("Connection from %.100s with IP options:%.800s", - ipaddr, text); - } -#endif /* IP_OPTIONS */ -} - void ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len) { @@ -201,38 +60,6 @@ ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len) a4->sin_port = port; } -/* - * Return the canonical name of the host in the other side of the current - * connection. The host name is cached, so it is efficient to call this - * several times. - */ - -const char * -get_canonical_hostname(int use_dns) -{ - char *host; - static char *canonical_host_name = NULL; - static char *remote_ip = NULL; - - /* Check if we have previously retrieved name with same option. */ - if (use_dns && canonical_host_name != NULL) - return canonical_host_name; - if (!use_dns && remote_ip != NULL) - return remote_ip; - - /* Get the real hostname if socket; otherwise return UNKNOWN. */ - if (packet_connection_is_on_socket()) - host = get_remote_hostname(packet_get_connection_in(), use_dns); - else - host = "UNKNOWN"; - - if (use_dns) - canonical_host_name = host; - else - remote_ip = host; - return host; -} - /* * Returns the local/remote IP-address/hostname of socket as a string. * The returned string must be freed. @@ -250,12 +77,10 @@ get_socket_address(int sock, int remote, int flags) memset(&addr, 0, sizeof(addr)); if (remote) { - if (getpeername(sock, (struct sockaddr *)&addr, &addrlen) - < 0) + if (getpeername(sock, (struct sockaddr *)&addr, &addrlen) != 0) return NULL; } else { - if (getsockname(sock, (struct sockaddr *)&addr, &addrlen) - < 0) + if (getsockname(sock, (struct sockaddr *)&addr, &addrlen) != 0) return NULL; } @@ -271,7 +96,7 @@ get_socket_address(int sock, int remote, int flags) /* Get the address in ascii. */ if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ntop, sizeof(ntop), NULL, 0, flags)) != 0) { - error("get_socket_address: getnameinfo %d failed: %s", + error("%s: getnameinfo %d failed: %s", __func__, flags, ssh_gai_strerror(r)); return NULL; } @@ -316,7 +141,8 @@ get_local_name(int fd) /* Handle the case where we were passed a pipe */ if (gethostname(myname, sizeof(myname)) == -1) { - verbose("get_local_name: gethostname: %s", strerror(errno)); + verbose("%s: gethostname: %s", __func__, strerror(errno)); + host = xstrdup("UNKNOWN"); } else { host = xstrdup(myname); } @@ -324,51 +150,9 @@ get_local_name(int fd) return host; } -void -clear_cached_addr(void) -{ - free(canonical_host_ip); - canonical_host_ip = NULL; - cached_port = -1; -} - -/* - * Returns the IP-address of the remote host as a string. The returned - * string must not be freed. - */ - -const char * -get_remote_ipaddr(void) -{ - /* Check whether we have cached the ipaddr. */ - if (canonical_host_ip == NULL) { - if (packet_connection_is_on_socket()) { - canonical_host_ip = - get_peer_ipaddr(packet_get_connection_in()); - if (canonical_host_ip == NULL) - cleanup_exit(255); - } else { - /* If not on socket, return UNKNOWN. */ - canonical_host_ip = xstrdup("UNKNOWN"); - } - } - return canonical_host_ip; -} - -const char * -get_remote_name_or_ip(u_int utmp_len, int use_dns) -{ - static const char *remote = ""; - if (utmp_len > 0) - remote = get_canonical_hostname(use_dns); - if (utmp_len == 0 || strlen(remote) > utmp_len) - remote = get_remote_ipaddr(); - return remote; -} - /* Returns the local/remote port for the socket. */ -int +static int get_sock_port(int sock, int local) { struct sockaddr_storage from; @@ -402,27 +186,11 @@ get_sock_port(int sock, int local) /* Return port number. */ if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0, strport, sizeof(strport), NI_NUMERICSERV)) != 0) - fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed: %s", + fatal("%s: getnameinfo NI_NUMERICSERV failed: %s", __func__, ssh_gai_strerror(r)); return atoi(strport); } -/* Returns remote/local port number for the current connection. */ - -static int -get_port(int local) -{ - /* - * If the connection is not a socket, return 65535. This is - * intentionally chosen to be an unprivileged port number. - */ - if (!packet_connection_is_on_socket()) - return 65535; - - /* Get socket and return the port number. */ - return get_sock_port(packet_get_connection_in(), local); -} - int get_peer_port(int sock) { @@ -430,17 +198,7 @@ get_peer_port(int sock) } int -get_remote_port(void) +get_local_port(int sock) { - /* Cache to avoid getpeername() on a dead connection */ - if (cached_port == -1) - cached_port = get_port(0); - - return cached_port; -} - -int -get_local_port(void) -{ - return get_port(1); + return get_sock_port(sock, 1); } diff --git a/canohost.h b/canohost.h index 4c8636f42..26d62855a 100644 --- a/canohost.h +++ b/canohost.h @@ -1,4 +1,4 @@ -/* $OpenBSD: canohost.h,v 1.11 2009/05/27 06:31:25 andreas Exp $ */ +/* $OpenBSD: canohost.h,v 1.12 2016/03/07 19:02:43 djm Exp $ */ /* * Author: Tatu Ylonen @@ -12,18 +12,15 @@ * called by a name other than "ssh" or "Secure Shell". */ -const char *get_canonical_hostname(int); -const char *get_remote_ipaddr(void); -const char *get_remote_name_or_ip(u_int, int); +#ifndef _CANOHOST_H +#define _CANOHOST_H char *get_peer_ipaddr(int); int get_peer_port(int); char *get_local_ipaddr(int); char *get_local_name(int); +int get_local_port(int); -int get_remote_port(void); -int get_local_port(void); -int get_sock_port(int, int); -void clear_cached_addr(void); +#endif /* _CANOHOST_H */ void ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *); diff --git a/channels.c b/channels.c index c9d2015ee..7ee1f98d0 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.349 2016/02/05 13:28:19 naddy Exp $ */ +/* $OpenBSD: channels.c,v 1.350 2016/03/07 19:02:43 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1416,7 +1416,7 @@ port_open_helper(Channel *c, char *rtype) { char buf[1024]; char *local_ipaddr = get_local_ipaddr(c->sock); - int local_port = c->sock == -1 ? 65536 : get_sock_port(c->sock, 1); + int local_port = c->sock == -1 ? 65536 : get_local_port(c->sock); char *remote_ipaddr = get_peer_ipaddr(c->sock); int remote_port = get_peer_port(c->sock); @@ -2935,7 +2935,7 @@ channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd, if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 && allocated_listen_port != NULL && *allocated_listen_port == 0) { - *allocated_listen_port = get_sock_port(sock, 1); + *allocated_listen_port = get_local_port(sock); debug("Allocated listen port %d", *allocated_listen_port); } diff --git a/monitor.c b/monitor.c index ac7dd3099..6b780e480 100644 --- a/monitor.c +++ b/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.157 2016/02/15 23:32:37 djm Exp $ */ +/* $OpenBSD: monitor.c,v 1.158 2016/03/07 19:02:43 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -1469,6 +1469,7 @@ mm_answer_keyverify(int sock, Buffer *m) static void mm_record_login(Session *s, struct passwd *pw) { + struct ssh *ssh = active_state; /* XXX */ socklen_t fromlen; struct sockaddr_storage from; @@ -1490,7 +1491,7 @@ mm_record_login(Session *s, struct passwd *pw) } /* Record that there was a login on that tty from the remote host. */ record_login(s->pid, s->tty, pw->pw_name, pw->pw_uid, - get_remote_name_or_ip(utmp_len, options.use_dns), + session_get_remote_name_or_ip(ssh, utmp_len, options.use_dns), (struct sockaddr *)&from, fromlen); } diff --git a/monitor_wrap.c b/monitor_wrap.c index c5db6df48..552004902 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.c,v 1.87 2016/01/14 16:17:40 markus Exp $ */ +/* $OpenBSD: monitor_wrap.c,v 1.88 2016/03/07 19:02:43 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -378,15 +378,15 @@ mm_user_key_allowed(struct passwd *pw, Key *key, int pubkey_auth_attempt) } int -mm_hostbased_key_allowed(struct passwd *pw, char *user, char *host, +mm_hostbased_key_allowed(struct passwd *pw, const char *user, const char *host, Key *key) { return (mm_key_allowed(MM_HOSTKEY, user, host, key, 0)); } int -mm_auth_rhosts_rsa_key_allowed(struct passwd *pw, char *user, - char *host, Key *key) +mm_auth_rhosts_rsa_key_allowed(struct passwd *pw, const char *user, + const char *host, Key *key) { int ret; @@ -397,8 +397,8 @@ mm_auth_rhosts_rsa_key_allowed(struct passwd *pw, char *user, } int -mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key, - int pubkey_auth_attempt) +mm_key_allowed(enum mm_keytype type, const char *user, const char *host, + Key *key, int pubkey_auth_attempt) { Buffer m; u_char *blob; diff --git a/monitor_wrap.h b/monitor_wrap.h index eb820aeea..9fd02b30c 100644 --- a/monitor_wrap.h +++ b/monitor_wrap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.h,v 1.29 2015/12/04 16:41:28 markus Exp $ */ +/* $OpenBSD: monitor_wrap.h,v 1.30 2016/03/07 19:02:43 djm Exp $ */ /* * Copyright 2002 Niels Provos @@ -45,10 +45,12 @@ void mm_inform_authserv(char *, char *); struct passwd *mm_getpwnamallow(const char *); char *mm_auth2_read_banner(void); int mm_auth_password(struct Authctxt *, char *); -int mm_key_allowed(enum mm_keytype, char *, char *, Key *, int); +int mm_key_allowed(enum mm_keytype, const char *, const char *, Key *, int); int mm_user_key_allowed(struct passwd *, Key *, int); -int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *); -int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *); +int mm_hostbased_key_allowed(struct passwd *, const char *, + const char *, Key *); +int mm_auth_rhosts_rsa_key_allowed(struct passwd *, const char *, + const char *, Key *); int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int); int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **); int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *); diff --git a/opacket.h b/opacket.h index c26ade44c..16322ec6f 100644 --- a/opacket.h +++ b/opacket.h @@ -144,10 +144,6 @@ void packet_disconnect(const char *, ...) ssh_packet_get_state(active_state, m) #define packet_set_state(m) \ ssh_packet_set_state(active_state, m) -#if 0 -#define get_remote_ipaddr() \ - ssh_remote_ipaddr(active_state) -#endif #define packet_get_raw(lenp) \ sshpkt_ptr(active_state, lenp) #define packet_get_ecpoint(c,p) \ diff --git a/packet.c b/packet.c index f406c0755..48111bb15 100644 --- a/packet.c +++ b/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.229 2016/02/17 22:20:14 djm Exp $ */ +/* $OpenBSD: packet.c,v 1.230 2016/03/07 19:02:43 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -52,6 +52,7 @@ #include #include +#include #include #include #include @@ -296,7 +297,7 @@ ssh_packet_set_connection(struct ssh *ssh, int fd_in, int fd_out) (r = cipher_init(&state->receive_context, none, (const u_char *)"", 0, NULL, 0, CIPHER_DECRYPT)) != 0) { error("%s: cipher_init failed: %s", __func__, ssh_err(r)); - free(ssh); + free(ssh); /* XXX need ssh_free_session_state? */ return NULL; } state->newkeys[MODE_IN] = state->newkeys[MODE_OUT] = NULL; @@ -379,6 +380,9 @@ ssh_packet_connection_is_on_socket(struct ssh *ssh) struct sockaddr_storage from, to; socklen_t fromlen, tolen; + if (state->connection_in == -1 || state->connection_out == -1) + return 0; + /* filedescriptors in and out are the same, so it's a socket */ if (state->connection_in == state->connection_out) return 1; @@ -468,10 +472,14 @@ ssh_remote_ipaddr(struct ssh *ssh) if (ssh->remote_ipaddr == NULL) { if (ssh_packet_connection_is_on_socket(ssh)) { ssh->remote_ipaddr = get_peer_ipaddr(sock); - ssh->remote_port = get_sock_port(sock, 0); + ssh->remote_port = get_peer_port(sock); + ssh->local_ipaddr = get_local_ipaddr(sock); + ssh->local_port = get_local_port(sock); } else { ssh->remote_ipaddr = strdup("UNKNOWN"); - ssh->remote_port = 0; + ssh->remote_port = 65535; + ssh->local_ipaddr = strdup("UNKNOWN"); + ssh->local_port = 65535; } } return ssh->remote_ipaddr; @@ -486,6 +494,27 @@ ssh_remote_port(struct ssh *ssh) return ssh->remote_port; } +/* + * Returns the IP-address of the local host as a string. The returned + * string must not be freed. + */ + +const char * +ssh_local_ipaddr(struct ssh *ssh) +{ + (void)ssh_remote_ipaddr(ssh); /* Will lookup and cache. */ + return ssh->local_ipaddr; +} + +/* Returns the port number of the local host. */ + +int +ssh_local_port(struct ssh *ssh) +{ + (void)ssh_remote_ipaddr(ssh); /* Will lookup and cache. */ + return ssh->local_port; +} + /* Closes the connection and clears and frees internal data structures. */ void diff --git a/packet.h b/packet.h index 28516a553..464d83b1a 100644 --- a/packet.h +++ b/packet.h @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.h,v 1.70 2016/02/08 10:57:07 djm Exp $ */ +/* $OpenBSD: packet.h,v 1.71 2016/03/07 19:02:43 djm Exp $ */ /* * Author: Tatu Ylonen @@ -56,9 +56,11 @@ struct ssh { /* Key exchange */ struct kex *kex; - /* cached remote ip address and port*/ + /* cached local and remote ip addresses and ports */ char *remote_ipaddr; int remote_port; + char *local_ipaddr; + int local_port; /* Dispatcher table */ dispatch_fn *dispatch[DISPATCH_MAX]; @@ -145,6 +147,8 @@ int ssh_packet_set_state(struct ssh *, struct sshbuf *); const char *ssh_remote_ipaddr(struct ssh *); int ssh_remote_port(struct ssh *); +const char *ssh_local_ipaddr(struct ssh *); +int ssh_local_port(struct ssh *); void ssh_packet_set_rekey_limits(struct ssh *, u_int64_t, time_t); time_t ssh_packet_get_rekey_timeout(struct ssh *); diff --git a/servconf.c b/servconf.c index b19d30e18..ba39dce1d 100644 --- a/servconf.c +++ b/servconf.c @@ -1,5 +1,5 @@ -/* $OpenBSD: servconf.c,v 1.285 2016/02/17 05:29:04 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.286 2016/03/07 19:02:43 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -706,14 +706,15 @@ process_queued_listen_addrs(ServerOptions *options) struct connection_info * get_connection_info(int populate, int use_dns) { + struct ssh *ssh = active_state; /* XXX */ static struct connection_info ci; if (!populate) return &ci; - ci.host = get_canonical_hostname(use_dns); - ci.address = get_remote_ipaddr(); - ci.laddress = get_local_ipaddr(packet_get_connection_in()); - ci.lport = get_local_port(); + ci.host = auth_get_canonical_hostname(ssh, use_dns); + ci.address = ssh_remote_ipaddr(ssh); + ci.laddress = ssh_local_ipaddr(ssh); + ci.lport = ssh_local_port(ssh); return &ci; } diff --git a/serverloop.c b/serverloop.c index e6a92476f..f9e3e5d14 100644 --- a/serverloop.c +++ b/serverloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: serverloop.c,v 1.183 2016/03/04 03:35:44 djm Exp $ */ +/* $OpenBSD: serverloop.c,v 1.184 2016/03/07 19:02:43 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -395,6 +395,7 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, static void process_input(fd_set *readset) { + struct ssh *ssh = active_state; /* XXX */ int len; char buf[16384]; @@ -402,8 +403,8 @@ process_input(fd_set *readset) if (FD_ISSET(connection_in, readset)) { len = read(connection_in, buf, sizeof(buf)); if (len == 0) { - verbose("Connection closed by %.100s", - get_remote_ipaddr()); + verbose("Connection closed by %.100s port %d", + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); connection_closed = 1; if (compat20) return; @@ -412,8 +413,9 @@ process_input(fd_set *readset) if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { verbose("Read error from remote host " - "%.100s: %.100s", - get_remote_ipaddr(), strerror(errno)); + "%.100s port %d: %.100s", + ssh_remote_ipaddr(ssh), + ssh_remote_port(ssh), strerror(errno)); cleanup_exit(255); } } else { diff --git a/session.c b/session.c index 7a02500ab..9a75c622e 100644 --- a/session.c +++ b/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.280 2016/02/16 03:37:48 djm Exp $ */ +/* $OpenBSD: session.c,v 1.281 2016/03/07 19:02:43 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -778,6 +778,7 @@ do_pre_login(Session *s) int do_exec(Session *s, const char *command) { + struct ssh *ssh = active_state; /* XXX */ int ret; const char *forced = NULL, *tty = NULL; char session_type[1024]; @@ -820,8 +821,8 @@ do_exec(Session *s, const char *command) tty == NULL ? "" : " on ", tty == NULL ? "" : tty, s->pw->pw_name, - get_remote_ipaddr(), - get_remote_port(), + ssh_remote_ipaddr(ssh), + ssh_remote_port(ssh), s->self); #ifdef SSH_AUDIT_EVENTS @@ -856,6 +857,7 @@ do_exec(Session *s, const char *command) void do_login(Session *s, const char *command) { + struct ssh *ssh = active_state; /* XXX */ socklen_t fromlen; struct sockaddr_storage from; struct passwd * pw = s->pw; @@ -878,7 +880,7 @@ do_login(Session *s, const char *command) /* Record that there was a login on that tty from the remote host. */ if (!use_privsep) record_login(pid, s->tty, pw->pw_name, pw->pw_uid, - get_remote_name_or_ip(utmp_len, + session_get_remote_name_or_ip(ssh, utmp_len, options.use_dns), (struct sockaddr *)&from, fromlen); @@ -1139,6 +1141,7 @@ copy_environment(char **source, char ***env, u_int *envsize) static char ** do_setup_env(Session *s, const char *shell) { + struct ssh *ssh = active_state; /* XXX */ char buf[256]; u_int i, envsize; char **env, *laddr; @@ -1240,12 +1243,14 @@ do_setup_env(Session *s, const char *shell) /* SSH_CLIENT deprecated */ snprintf(buf, sizeof buf, "%.50s %d %d", - get_remote_ipaddr(), get_remote_port(), get_local_port()); + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), + ssh_local_port(ssh)); child_set_env(&env, &envsize, "SSH_CLIENT", buf); laddr = get_local_ipaddr(packet_get_connection_in()); snprintf(buf, sizeof buf, "%.50s %d %.50s %d", - get_remote_ipaddr(), get_remote_port(), laddr, get_local_port()); + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), + laddr, ssh_local_port(ssh)); free(laddr); child_set_env(&env, &envsize, "SSH_CONNECTION", buf); @@ -1662,6 +1667,7 @@ child_close_fds(void) void do_child(Session *s, const char *command) { + struct ssh *ssh = active_state; /* XXX */ extern char **environ; char **env; char *argv[ARGV_MAX]; @@ -1738,14 +1744,14 @@ do_child(Session *s, const char *command) /* we have to stash the hostname before we close our socket. */ if (options.use_login) - hostname = get_remote_name_or_ip(utmp_len, + hostname = session_get_remote_name_or_ip(ssh, utmp_len, options.use_dns); /* * Close the connection descriptors; note that this is the child, and * the server will still have the socket open, and it is important * that we do not shutdown it. Note that the descriptors cannot be * closed before building the environment, as we call - * get_remote_ipaddr there. + * ssh_remote_ipaddr there. */ child_close_fds(); @@ -2498,12 +2504,13 @@ session_exit_message(Session *s, int status) void session_close(Session *s) { + struct ssh *ssh = active_state; /* XXX */ u_int i; verbose("Close session: user %s from %.200s port %d id %d", s->pw->pw_name, - get_remote_ipaddr(), - get_remote_port(), + ssh_remote_ipaddr(ssh), + ssh_remote_port(ssh), s->self); if (s->ttyfd != -1) @@ -2772,3 +2779,18 @@ do_cleanup(Authctxt *authctxt) if (!use_privsep || mm_is_monitor()) session_destroy_all(session_pty_cleanup2); } + +/* Return a name for the remote host that fits inside utmp_size */ + +const char * +session_get_remote_name_or_ip(struct ssh *ssh, u_int utmp_size, int use_dns) +{ + const char *remote = ""; + + if (utmp_size > 0) + remote = auth_get_canonical_hostname(ssh, use_dns); + if (utmp_size == 0 || strlen(remote) > utmp_size) + remote = ssh_remote_ipaddr(ssh); + return remote; +} + diff --git a/session.h b/session.h index 6a2f35e41..f18eaf329 100644 --- a/session.h +++ b/session.h @@ -1,4 +1,4 @@ -/* $OpenBSD: session.h,v 1.31 2013/10/14 21:20:52 djm Exp $ */ +/* $OpenBSD: session.h,v 1.32 2016/03/07 19:02:43 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -81,4 +81,6 @@ void do_setusercontext(struct passwd *); void child_set_env(char ***envp, u_int *envsizep, const char *name, const char *value); +const char *session_get_remote_name_or_ip(struct ssh *, u_int, int); + #endif diff --git a/ssh.c b/ssh.c index f9ff91f04..a999d5079 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.436 2016/02/15 09:47:49 dtucker Exp $ */ +/* $OpenBSD: ssh.c,v 1.437 2016/03/07 19:02:43 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -513,6 +513,7 @@ set_addrinfo_port(struct addrinfo *addrs, int port) int main(int ac, char **av) { + struct ssh *ssh = NULL; int i, r, opt, exit_status, use_syslog, config_test = 0; char *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile; char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; @@ -1220,6 +1221,8 @@ main(int ac, char **av) packet_set_timeout(options.server_alive_interval, options.server_alive_count_max); + ssh = active_state; /* XXX */ + if (timeout_ms > 0) debug3("timeout: %d ms remain after connect", timeout_ms); @@ -1346,7 +1349,7 @@ main(int ac, char **av) if (packet_connection_is_on_socket()) { verbose("Authenticated to %s ([%s]:%d).", host, - get_remote_ipaddr(), get_remote_port()); + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); } else { verbose("Authenticated to %s (via proxy).", host); } diff --git a/sshd.c b/sshd.c index 430569c46..d21aed515 100644 --- a/sshd.c +++ b/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.465 2016/02/15 09:47:49 dtucker Exp $ */ +/* $OpenBSD: sshd.c,v 1.466 2016/03/07 19:02:43 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -371,7 +371,8 @@ grace_alarm_handler(int sig) } /* Log error and exit. */ - sigdie("Timeout before authentication for %s", get_remote_ipaddr()); + sigdie("Timeout before authentication for %s port %d", + ssh_remote_ipaddr(active_state), ssh_remote_port(active_state)); } /* @@ -407,7 +408,7 @@ key_regeneration_alarm(int sig) } static void -sshd_exchange_identification(int sock_in, int sock_out) +sshd_exchange_identification(struct ssh *ssh, int sock_in, int sock_out) { u_int i; int mismatch; @@ -439,7 +440,8 @@ sshd_exchange_identification(int sock_in, int sock_out) if (atomicio(vwrite, sock_out, server_version_string, strlen(server_version_string)) != strlen(server_version_string)) { - logit("Could not write ident string to %s", get_remote_ipaddr()); + logit("Could not write ident string to %s port %d", + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); cleanup_exit(255); } @@ -447,8 +449,9 @@ sshd_exchange_identification(int sock_in, int sock_out) memset(buf, 0, sizeof(buf)); for (i = 0; i < sizeof(buf) - 1; i++) { if (atomicio(read, sock_in, &buf[i], 1) != 1) { - logit("Did not receive identification string from %s", - get_remote_ipaddr()); + logit("Did not receive identification string " + "from %s port %d", + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); cleanup_exit(255); } if (buf[i] == '\r') { @@ -477,7 +480,7 @@ sshd_exchange_identification(int sock_in, int sock_out) (void) atomicio(vwrite, sock_out, s, strlen(s)); logit("Bad protocol version identification '%.100s' " "from %s port %d", client_version_string, - get_remote_ipaddr(), get_remote_port()); + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); close(sock_in); close(sock_out); cleanup_exit(255); @@ -485,23 +488,25 @@ sshd_exchange_identification(int sock_in, int sock_out) debug("Client protocol version %d.%d; client software version %.100s", remote_major, remote_minor, remote_version); - active_state->compat = compat_datafellows(remote_version); + ssh->compat = compat_datafellows(remote_version); - if ((datafellows & SSH_BUG_PROBE) != 0) { - logit("probed from %s with %s. Don't panic.", - get_remote_ipaddr(), client_version_string); + if ((ssh->compat & SSH_BUG_PROBE) != 0) { + logit("probed from %s port %d with %s. Don't panic.", + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), + client_version_string); cleanup_exit(255); } - if ((datafellows & SSH_BUG_SCANNER) != 0) { - logit("scanned from %s with %s. Don't panic.", - get_remote_ipaddr(), client_version_string); + if ((ssh->compat & SSH_BUG_SCANNER) != 0) { + logit("scanned from %s port %d with %s. Don't panic.", + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), + client_version_string); cleanup_exit(255); } - if ((datafellows & SSH_BUG_RSASIGMD5) != 0) { + if ((ssh->compat & SSH_BUG_RSASIGMD5) != 0) { logit("Client version \"%.100s\" uses unsafe RSA signature " "scheme; disabling use of RSA keys", remote_version); } - if ((datafellows & SSH_BUG_DERIVEKEY) != 0) { + if ((ssh->compat & SSH_BUG_DERIVEKEY) != 0) { fatal("Client version \"%.100s\" uses unsafe key agreement; " "refusing connection", remote_version); } @@ -546,8 +551,9 @@ sshd_exchange_identification(int sock_in, int sock_out) (void) atomicio(vwrite, sock_out, s, strlen(s)); close(sock_in); close(sock_out); - logit("Protocol major versions differ for %s: %.200s vs. %.200s", - get_remote_ipaddr(), + logit("Protocol major versions differ for %s port %d: " + "%.200s vs. %.200s", + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), server_version_string, client_version_string); cleanup_exit(255); } @@ -1452,6 +1458,47 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) } } +/* + * If IP options are supported, make sure there are none (log and + * return an error if any are found). Basically we are worried about + * source routing; it can be used to pretend you are somebody + * (ip-address) you are not. That itself may be "almost acceptable" + * under certain circumstances, but rhosts autentication is useless + * if source routing is accepted. Notice also that if we just dropped + * source routing here, the other side could use IP spoofing to do + * rest of the interaction and could still bypass security. So we + * exit here if we detect any IP options. + */ +static void +check_ip_options(struct ssh *ssh) +{ +#ifdef IP_OPTIONS + int sock_in = ssh_packet_get_connection_in(ssh); + struct sockaddr_storage from; + socklen_t option_size, i, fromlen = sizeof(from); + u_char opts[200]; + char text[sizeof(opts) * 3 + 1]; + + memset(&from, 0, sizeof(from)); + if (getpeername(sock_in, (struct sockaddr *)&from, + &fromlen) < 0) + return; + if (from.ss_family != AF_INET) + return; + /* XXX IPv6 options? */ + + if (getsockopt(sock_in, IPPROTO_IP, IP_OPTIONS, opts, + &option_size) >= 0 && option_size != 0) { + text[0] = '\0'; + for (i = 0; i < option_size; i++) + snprintf(text + i*3, sizeof(text) - i*3, + " %2.2x", opts[i]); + fatal("Connection from %.100s port %d with IP opts: %.800s", + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), text); + } + return; +#endif /* IP_OPTIONS */ +} /* * Main program for the daemon. @@ -1459,6 +1506,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) int main(int ac, char **av) { + struct ssh *ssh = NULL; extern char *optarg; extern int optind; int r, opt, i, j, on = 1; @@ -2118,28 +2166,25 @@ main(int ac, char **av) */ packet_set_connection(sock_in, sock_out); packet_set_server(); + ssh = active_state; /* XXX */ + check_ip_options(ssh); /* Set SO_KEEPALIVE if requested. */ if (options.tcp_keep_alive && packet_connection_is_on_socket() && setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0) error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); - if ((remote_port = get_remote_port()) < 0) { - debug("get_remote_port failed"); + if ((remote_port = ssh_remote_port(ssh)) < 0) { + debug("ssh_remote_port failed"); cleanup_exit(255); } - /* - * We use get_canonical_hostname with usedns = 0 instead of - * get_remote_ipaddr here so IP options will be checked. - */ - (void) get_canonical_hostname(0); /* * The rest of the code depends on the fact that - * get_remote_ipaddr() caches the remote ip, even if + * ssh_remote_ipaddr() caches the remote ip, even if * the socket goes away. */ - remote_ip = get_remote_ipaddr(); + remote_ip = ssh_remote_ipaddr(ssh); #ifdef SSH_AUDIT_EVENTS audit_connection_from(remote_ip, remote_port); @@ -2148,7 +2193,7 @@ main(int ac, char **av) /* Log the connection. */ laddr = get_local_ipaddr(sock_in); verbose("Connection from %s port %d on %s port %d", - remote_ip, remote_port, laddr, get_local_port()); + remote_ip, remote_port, laddr, ssh_local_port(ssh)); free(laddr); /* @@ -2163,7 +2208,7 @@ main(int ac, char **av) if (!debug_flag) alarm(options.login_grace_time); - sshd_exchange_identification(sock_in, sock_out); + sshd_exchange_identification(ssh, sock_in, sock_out); /* In inetd mode, generate ephemeral key only for proto 1 connections */ if (!compat20 && inetd_flag && sensitive_data.server_key == NULL) @@ -2299,6 +2344,7 @@ main(int ac, char **av) int ssh1_session_key(BIGNUM *session_key_int) { + struct ssh *ssh = active_state; /* XXX */ int rsafail = 0; if (BN_cmp(sensitive_data.server_key->rsa->n, @@ -2307,9 +2353,9 @@ ssh1_session_key(BIGNUM *session_key_int) if (BN_num_bits(sensitive_data.server_key->rsa->n) < BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { - fatal("do_connection: %s: " + fatal("do_connection: %s port %d: " "server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", - get_remote_ipaddr(), + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), BN_num_bits(sensitive_data.server_key->rsa->n), BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), SSH_KEY_BITS_RESERVED); @@ -2325,9 +2371,9 @@ ssh1_session_key(BIGNUM *session_key_int) if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) < BN_num_bits(sensitive_data.server_key->rsa->n) + SSH_KEY_BITS_RESERVED) { - fatal("do_connection: %s: " + fatal("do_connection: %s port %d: " "host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d", - get_remote_ipaddr(), + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), BN_num_bits(sensitive_data.server_key->rsa->n), SSH_KEY_BITS_RESERVED); @@ -2348,6 +2394,7 @@ ssh1_session_key(BIGNUM *session_key_int) static void do_ssh1_kex(void) { + struct ssh *ssh = active_state; /* XXX */ int i, len; int rsafail = 0; BIGNUM *session_key_int, *fake_key_int, *real_key_int; @@ -2465,9 +2512,10 @@ do_ssh1_kex(void) (void) BN_mask_bits(session_key_int, sizeof(session_key) * 8); len = BN_num_bytes(session_key_int); if (len < 0 || (u_int)len > sizeof(session_key)) { - error("do_ssh1_kex: bad session key len from %s: " - "session_key_int %d > sizeof(session_key) %lu", - get_remote_ipaddr(), len, (u_long)sizeof(session_key)); + error("%s: bad session key len from %s port %d: " + "session_key_int %d > sizeof(session_key) %lu", __func__, + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), + len, (u_long)sizeof(session_key)); rsafail++; } else { explicit_bzero(session_key, sizeof(session_key));