=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/sshconnect.c,v retrieving revision 1.168.2.1 retrieving revision 1.168.2.2 diff -u -r1.168.2.1 -r1.168.2.2 --- src/usr.bin/ssh/sshconnect.c 2006/02/03 03:01:58 1.168.2.1 +++ src/usr.bin/ssh/sshconnect.c 2006/10/06 03:19:33 1.168.2.2 @@ -1,3 +1,4 @@ +/* $OpenBSD: sshconnect.c,v 1.168.2.2 2006/10/06 03:19:33 brad Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -12,13 +13,27 @@ * called by a name other than "ssh" or "Secure Shell". */ -#include "includes.h" -RCSID("$OpenBSD: sshconnect.c,v 1.168.2.1 2006/02/03 03:01:58 brad Exp $"); +#include +#include +#include +#include +#include -#include +#include -#include "ssh.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "xmalloc.h" +#include "ssh.h" #include "rsa.h" #include "buffer.h" #include "packet.h" @@ -32,6 +47,7 @@ #include "atomicio.h" #include "misc.h" #include "dns.h" +#include "version.h" char *client_version_string = NULL; char *server_version_string = NULL; @@ -58,7 +74,6 @@ int pin[2], pout[2]; pid_t pid; char strport[NI_MAXSERV]; - size_t len; /* Convert the port number into a string. */ snprintf(strport, sizeof strport, "%hu", port); @@ -70,10 +85,7 @@ * Use "exec" to avoid "sh -c" processes on some platforms * (e.g. Solaris) */ - len = strlen(proxy_command) + 6; - tmp = xmalloc(len); - strlcpy(tmp, "exec ", len); - strlcat(tmp, proxy_command, len); + xasprintf(&tmp, "exec %s", proxy_command); command_string = percent_expand(tmp, "h", host, "p", strport, (char *)NULL); xfree(tmp); @@ -90,8 +102,7 @@ char *argv[10]; /* Child. Permanently give up superuser privileges. */ - seteuid(original_real_uid); - setuid(original_real_uid); + permanently_drop_suid(original_real_uid); /* Redirect stdin and stdout. */ close(pin[1]); @@ -201,7 +212,7 @@ fd_set *fdset; struct timeval tv; socklen_t optlen; - int fdsetsz, optval, rc, result = -1; + int optval, rc, result = -1; if (timeout <= 0) return (connect(sockfd, serv_addr, addrlen)); @@ -215,10 +226,8 @@ if (errno != EINPROGRESS) return (-1); - fdsetsz = howmany(sockfd + 1, NFDBITS) * sizeof(fd_mask); - fdset = (fd_set *)xmalloc(fdsetsz); - - memset(fdset, 0, fdsetsz); + fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS), + sizeof(fd_mask)); FD_SET(sockfd, fdset); tv.tv_sec = timeout; tv.tv_usec = 0; @@ -301,17 +310,14 @@ fatal("%s: %.100s: %s", __progname, host, gai_strerror(gaierr)); - /* - * Try to connect several times. On some machines, the first time - * will sometimes fail. In general socket code appears to behave - * quite magically on many machines. - */ - for (attempt = 0; ;) { + for (attempt = 0; attempt < connection_attempts; attempt++) { if (attempt > 0) debug("Trying again..."); - /* Loop through addresses for this host, and try each one in - sequence until the connection succeeds. */ + /* + * Loop through addresses for this host, and try each one in + * sequence until the connection succeeds. + */ for (ai = aitop; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) continue; @@ -338,21 +344,13 @@ } else { debug("connect to address %s port %s: %s", ntop, strport, strerror(errno)); - /* - * Close the failed socket; there appear to - * be some problems when reusing a socket for - * which connect() has already returned an - * error. - */ close(sock); + sock = -1; } } - if (ai) + if (sock != -1) break; /* Successful connection. */ - attempt++; - if (attempt >= connection_attempts) - break; /* Sleep a moment before retrying. */ sleep(1); } @@ -360,7 +358,7 @@ freeaddrinfo(aitop); /* Return failure if we didn't get a successful connection. */ - if (attempt >= connection_attempts) { + if (sock == -1) { error("ssh: connect to host %s port %s: %s", host, strport, strerror(errno)); return (-1); @@ -392,10 +390,10 @@ int connection_in = packet_get_connection_in(); int connection_out = packet_get_connection_out(); int minor1 = PROTOCOL_MINOR_1; - u_int i; + u_int i, n; /* Read other side's version identification. */ - for (;;) { + for (n = 0;;) { for (i = 0; i < sizeof(buf) - 1; i++) { size_t len = atomicio(read, connection_in, &buf[i], 1); @@ -412,6 +410,8 @@ buf[i + 1] = 0; break; } + if (++n > 65536) + fatal("ssh_exchange_identification: No banner received"); } buf[sizeof(buf) - 1] = 0; if (strncmp(buf, "SSH-", 4) == 0) @@ -513,13 +513,17 @@ * check whether the supplied host key is valid, return -1 if the key * is not valid. the user_hostfile will not be updated if 'readonly' is true. */ +#define RDRW 0 +#define RDONLY 1 +#define ROQUIET 2 static int -check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, - int readonly, const char *user_hostfile, const char *system_hostfile) +check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, + Key *host_key, int readonly, const char *user_hostfile, + const char *system_hostfile) { Key *file_key; const char *type = key_type(host_key); - char *ip = NULL; + char *ip = NULL, *host = NULL; char hostline[1000], *hostp, *fp; HostStatus host_status; HostStatus ip_status; @@ -566,7 +570,7 @@ if (getnameinfo(hostaddr, hostaddr->sa_len, ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0) fatal("check_host_key: getnameinfo failed"); - ip = xstrdup(ntop); + ip = put_host_port(ntop, port); } else { ip = xstrdup(""); } @@ -574,18 +578,21 @@ * Turn off check_host_ip if the connection is to localhost, via proxy * command or if we don't have a hostname to compare with */ - if (options.check_host_ip && - (local || strcmp(host, ip) == 0 || options.proxy_command != NULL)) + if (options.check_host_ip && (local || + strcmp(hostname, ip) == 0 || options.proxy_command != NULL)) options.check_host_ip = 0; /* - * Allow the user to record the key under a different name. This is - * useful for ssh tunneling over forwarded connections or if you run - * multiple sshd's on different ports on the same machine. + * Allow the user to record the key under a different name or + * differentiate a non-standard port. This is useful for ssh + * tunneling over forwarded connections or if you run multiple + * sshd's on different ports on the same machine. */ if (options.host_key_alias != NULL) { - host = options.host_key_alias; + host = xstrdup(options.host_key_alias); debug("using hostkeyalias: %s", host); + } else { + host = put_host_port(hostname, port); } /* @@ -654,6 +661,15 @@ } break; case HOST_NEW: + if (options.host_key_alias == NULL && port != 0 && + port != SSH_DEFAULT_PORT) { + debug("checking without port identifier"); + if (check_host_key(hostname, hostaddr, 0, host_key, 2, + user_hostfile, system_hostfile) == 0) { + debug("found matching key w/out port"); + break; + } + } if (readonly) goto fail; /* The host is new. */ @@ -733,6 +749,8 @@ "list of known hosts.", hostp, type); break; case HOST_CHANGED: + if (readonly == ROQUIET) + goto fail; if (options.check_host_ip && host_ip_differ) { char *key_msg; if (ip_status == HOST_NEW) @@ -771,7 +789,7 @@ /* * If strict host key checking has not been requested, allow * the connection but without MITM-able authentication or - * agent forwarding. + * forwarding. */ if (options.password_authentication) { error("Password authentication is disabled to avoid " @@ -806,6 +824,11 @@ options.num_local_forwards = options.num_remote_forwards = 0; } + if (options.tun_open != SSH_TUNMODE_NO) { + error("Tunnel forwarding is disabled to avoid " + "man-in-the-middle attacks."); + options.tun_open = SSH_TUNMODE_NO; + } /* * XXX Should permit the user to change to use the new id. * This could be done by converting the host key to an @@ -847,10 +870,12 @@ } xfree(ip); + xfree(host); return 0; fail: xfree(ip); + xfree(host); return -1; } @@ -884,12 +909,13 @@ /* return ok if the key can be found in an old keyfile */ if (stat(options.system_hostfile2, &st) == 0 || stat(options.user_hostfile2, &st) == 0) { - if (check_host_key(host, hostaddr, host_key, /*readonly*/ 1, - options.user_hostfile2, options.system_hostfile2) == 0) + if (check_host_key(host, hostaddr, options.port, host_key, + RDONLY, options.user_hostfile2, + options.system_hostfile2) == 0) return 0; } - return check_host_key(host, hostaddr, host_key, /*readonly*/ 0, - options.user_hostfile, options.system_hostfile); + return check_host_key(host, hostaddr, options.port, host_key, + RDRW, options.user_hostfile, options.system_hostfile); } /* @@ -913,7 +939,7 @@ host = xstrdup(orighost); for (cp = host; *cp; cp++) if (isupper(*cp)) - *cp = tolower(*cp); + *cp = (char)tolower(*cp); /* Exchange protocol version identification strings with the server. */ ssh_exchange_identification(); @@ -930,6 +956,7 @@ ssh_kex(host, hostaddr); ssh_userauth1(local_user, server_user, host, sensitive); } + xfree(local_user); } void @@ -943,8 +970,7 @@ return; } size = roundup(strlen(password) + 1, 32); - padded = xmalloc(size); - memset(padded, 0, size); + padded = xcalloc(1, size); strlcpy(padded, password, size); packet_put_string(padded, size); memset(padded, 0, size);