=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/sshconnect.c,v retrieving revision 1.168.2.3 retrieving revision 1.169 diff -u -r1.168.2.3 -r1.169 --- src/usr.bin/ssh/sshconnect.c 2006/11/08 00:44:05 1.168.2.3 +++ src/usr.bin/ssh/sshconnect.c 2005/10/15 15:28:12 1.169 @@ -1,4 +1,3 @@ -/* $OpenBSD: sshconnect.c,v 1.168.2.3 2006/11/08 00:44:05 brad Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -13,27 +12,13 @@ * called by a name other than "ssh" or "Secure Shell". */ -#include -#include -#include -#include -#include +#include "includes.h" +RCSID("$OpenBSD: sshconnect.c,v 1.169 2005/10/15 15:28:12 stevesk Exp $"); -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xmalloc.h" #include "ssh.h" +#include "xmalloc.h" #include "rsa.h" #include "buffer.h" #include "packet.h" @@ -47,7 +32,6 @@ #include "atomicio.h" #include "misc.h" #include "dns.h" -#include "version.h" char *client_version_string = NULL; char *server_version_string = NULL; @@ -74,6 +58,7 @@ 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); @@ -85,7 +70,10 @@ * Use "exec" to avoid "sh -c" processes on some platforms * (e.g. Solaris) */ - xasprintf(&tmp, "exec %s", proxy_command); + len = strlen(proxy_command) + 6; + tmp = xmalloc(len); + strlcpy(tmp, "exec ", len); + strlcat(tmp, proxy_command, len); command_string = percent_expand(tmp, "h", host, "p", strport, (char *)NULL); xfree(tmp); @@ -102,7 +90,8 @@ char *argv[10]; /* Child. Permanently give up superuser privileges. */ - permanently_drop_suid(original_real_uid); + seteuid(original_real_uid); + setuid(original_real_uid); /* Redirect stdin and stdout. */ close(pin[1]); @@ -212,7 +201,7 @@ fd_set *fdset; struct timeval tv; socklen_t optlen; - int optval, rc, result = -1; + int fdsetsz, optval, rc, result = -1; if (timeout <= 0) return (connect(sockfd, serv_addr, addrlen)); @@ -226,8 +215,10 @@ if (errno != EINPROGRESS) return (-1); - fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS), - sizeof(fd_mask)); + fdsetsz = howmany(sockfd + 1, NFDBITS) * sizeof(fd_mask); + fdset = (fd_set *)xmalloc(fdsetsz); + + memset(fdset, 0, fdsetsz); FD_SET(sockfd, fdset); tv.tv_sec = timeout; tv.tv_usec = 0; @@ -310,16 +301,17 @@ fatal("%s: %.100s: %s", __progname, host, gai_strerror(gaierr)); - for (attempt = 0; attempt < connection_attempts; attempt++) { - if (attempt > 0) { - /* Sleep a moment before retrying. */ - sleep(1); - debug("Trying again..."); - } - /* - * Loop through addresses for this host, and try each one in - * sequence until the connection succeeds. + /* + * 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; ;) { + if (attempt > 0) + debug("Trying again..."); + + /* 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; @@ -346,18 +338,29 @@ } 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 (sock != -1) + if (ai) break; /* Successful connection. */ + + attempt++; + if (attempt >= connection_attempts) + break; + /* Sleep a moment before retrying. */ + sleep(1); } freeaddrinfo(aitop); /* Return failure if we didn't get a successful connection. */ - if (sock == -1) { + if (attempt >= connection_attempts) { error("ssh: connect to host %s port %s: %s", host, strport, strerror(errno)); return (-1); @@ -389,10 +392,10 @@ int connection_in = packet_get_connection_in(); int connection_out = packet_get_connection_out(); int minor1 = PROTOCOL_MINOR_1; - u_int i, n; + u_int i; /* Read other side's version identification. */ - for (n = 0;;) { + for (;;) { for (i = 0; i < sizeof(buf) - 1; i++) { size_t len = atomicio(read, connection_in, &buf[i], 1); @@ -409,8 +412,6 @@ 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) @@ -512,17 +513,13 @@ * 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 *hostname, struct sockaddr *hostaddr, u_short port, - Key *host_key, int readonly, const char *user_hostfile, - const char *system_hostfile) +check_host_key(char *host, struct sockaddr *hostaddr, 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, *host = NULL; + char *ip = NULL; char hostline[1000], *hostp, *fp; HostStatus host_status; HostStatus ip_status; @@ -569,7 +566,7 @@ if (getnameinfo(hostaddr, hostaddr->sa_len, ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0) fatal("check_host_key: getnameinfo failed"); - ip = put_host_port(ntop, port); + ip = xstrdup(ntop); } else { ip = xstrdup(""); } @@ -577,21 +574,18 @@ * 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(hostname, ip) == 0 || options.proxy_command != NULL)) + if (options.check_host_ip && + (local || strcmp(host, ip) == 0 || options.proxy_command != NULL)) options.check_host_ip = 0; /* - * 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. + * 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. */ if (options.host_key_alias != NULL) { - host = xstrdup(options.host_key_alias); + host = options.host_key_alias; debug("using hostkeyalias: %s", host); - } else { - host = put_host_port(hostname, port); } /* @@ -601,7 +595,7 @@ file_key = key_new(host_key->type); /* - * Check if the host key is present in the user's list of known + * Check if the host key is present in the user\'s list of known * hosts or in the systemwide list. */ host_file = user_hostfile; @@ -660,15 +654,6 @@ } 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. */ @@ -748,8 +733,6 @@ "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) @@ -788,7 +771,7 @@ /* * If strict host key checking has not been requested, allow * the connection but without MITM-able authentication or - * forwarding. + * agent forwarding. */ if (options.password_authentication) { error("Password authentication is disabled to avoid " @@ -823,11 +806,6 @@ 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 @@ -869,12 +847,10 @@ } xfree(ip); - xfree(host); return 0; fail: xfree(ip); - xfree(host); return -1; } @@ -908,13 +884,12 @@ /* 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, options.port, host_key, - RDONLY, options.user_hostfile2, - options.system_hostfile2) == 0) + if (check_host_key(host, hostaddr, host_key, /*readonly*/ 1, + options.user_hostfile2, options.system_hostfile2) == 0) return 0; } - return check_host_key(host, hostaddr, options.port, host_key, - RDRW, options.user_hostfile, options.system_hostfile); + return check_host_key(host, hostaddr, host_key, /*readonly*/ 0, + options.user_hostfile, options.system_hostfile); } /* @@ -938,7 +913,7 @@ host = xstrdup(orighost); for (cp = host; *cp; cp++) if (isupper(*cp)) - *cp = (char)tolower(*cp); + *cp = tolower(*cp); /* Exchange protocol version identification strings with the server. */ ssh_exchange_identification(); @@ -955,7 +930,6 @@ ssh_kex(host, hostaddr); ssh_userauth1(local_user, server_user, host, sensitive); } - xfree(local_user); } void @@ -969,7 +943,8 @@ return; } size = roundup(strlen(password) + 1, 32); - padded = xcalloc(1, size); + padded = xmalloc(size); + memset(padded, 0, size); strlcpy(padded, password, size); packet_put_string(padded, size); memset(padded, 0, size); @@ -1050,40 +1025,4 @@ error("Please contact your system administrator."); xfree(fp); -} - -/* - * Execute a local command - */ -int -ssh_local_cmd(const char *args) -{ - char *shell; - pid_t pid; - int status; - - if (!options.permit_local_command || - args == NULL || !*args) - return (1); - - if ((shell = getenv("SHELL")) == NULL) - shell = _PATH_BSHELL; - - pid = fork(); - if (pid == 0) { - debug3("Executing %s -c \"%s\"", shell, args); - execl(shell, shell, "-c", args, (char *)NULL); - error("Couldn't execute %s -c \"%s\": %s", - shell, args, strerror(errno)); - _exit(1); - } else if (pid == -1) - fatal("fork failed: %.100s", strerror(errno)); - while (waitpid(pid, &status, 0) == -1) - if (errno != EINTR) - fatal("Couldn't wait for child: %s", strerror(errno)); - - if (!WIFEXITED(status)) - return (1); - - return (WEXITSTATUS(status)); }