=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/sshconnect.c,v retrieving revision 1.119.2.3 retrieving revision 1.120 diff -u -r1.119.2.3 -r1.120 --- src/usr.bin/ssh/sshconnect.c 2003/04/03 22:35:18 1.119.2.3 +++ src/usr.bin/ssh/sshconnect.c 2002/05/23 19:24:30 1.120 @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect.c,v 1.119.2.3 2003/04/03 22:35:18 miod Exp $"); +RCSID("$OpenBSD: sshconnect.c,v 1.120 2002/05/23 19:24:30 markus Exp $"); #include @@ -36,20 +36,36 @@ char *client_version_string = NULL; char *server_version_string = NULL; -/* import */ extern Options options; extern char *__progname; -extern uid_t original_real_uid; -extern uid_t original_effective_uid; -extern pid_t proxy_command_pid; -static int show_other_keys(const char *, Key *); +static const char * +sockaddr_ntop(struct sockaddr *sa) +{ + void *addr; + static char addrbuf[INET6_ADDRSTRLEN]; + switch (sa->sa_family) { + case AF_INET: + addr = &((struct sockaddr_in *)sa)->sin_addr; + break; + case AF_INET6: + addr = &((struct sockaddr_in6 *)sa)->sin6_addr; + break; + default: + /* This case should be protected against elsewhere */ + abort(); /* XXX abort is bad -- do something else */ + } + inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf)); + return addrbuf; +} + /* * Connect to the given ssh server using a proxy command. */ static int -ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) +ssh_proxy_connect(const char *host, u_short port, struct passwd *pw, + const char *proxy_command) { Buffer command; const char *cp; @@ -61,16 +77,9 @@ /* Convert the port number into a string. */ snprintf(strport, sizeof strport, "%hu", port); - /* - * Build the final command string in the buffer by making the - * appropriate substitutions to the given proxy command. - * - * Use "exec" to avoid "sh -c" processes on some platforms - * (e.g. Solaris) - */ + /* Build the final command string in the buffer by making the + appropriate substitutions to the given proxy command. */ buffer_init(&command); - buffer_append(&command, "exec ", 5); - for (cp = proxy_command; *cp; cp++) { if (cp[0] == '%' && cp[1] == '%') { buffer_append(&command, "%", 1); @@ -106,8 +115,7 @@ char *argv[10]; /* Child. Permanently give up superuser privileges. */ - seteuid(original_real_uid); - setuid(original_real_uid); + permanently_set_uid(pw); /* Redirect stdin and stdout. */ close(pin[1]); @@ -138,8 +146,6 @@ /* Parent. */ if (pid < 0) fatal("fork failed: %.100s", strerror(errno)); - else - proxy_command_pid = pid; /* save pid to clean up later */ /* Close child side of the descriptors. */ close(pin[0]); @@ -159,7 +165,7 @@ * Creates a (possibly privileged) socket for use as the ssh connection. */ static int -ssh_create_socket(int privileged, int family) +ssh_create_socket(struct passwd *pw, int privileged, int family) { int sock, gaierr; struct addrinfo hints, *res; @@ -170,18 +176,22 @@ */ if (privileged) { int p = IPPORT_RESERVED - 1; - PRIV_START; sock = rresvport_af(&p, family); - PRIV_END; if (sock < 0) error("rresvport: af=%d %.100s", family, strerror(errno)); else debug("Allocated local port %d.", p); return sock; } + /* + * Just create an ordinary socket on arbitrary port. We use + * the user's uid to create the socket. + */ + temporarily_use_uid(pw); sock = socket(family, SOCK_STREAM, 0); if (sock < 0) error("socket: %.100s", strerror(errno)); + restore_uid(); /* Bind the socket to an alternative local IP address */ if (options.bind_address == NULL) @@ -211,9 +221,9 @@ /* * Opens a TCP/IP connection to the remote server on the given host. * The address of the remote host will be returned in hostaddr. - * If port is 0, the default port will be used. If needpriv is true, + * If port is 0, the default port will be used. If anonymous is zero, * a privileged port will be allocated to make the connection. - * This requires super-user privileges if needpriv is true. + * This requires super-user privileges if anonymous is false. * Connection_attempts specifies the maximum number of tries (one per * second). If proxy_command is non-NULL, it specifies the command (with %h * and %p substituted for host and port, respectively) to use to contact @@ -228,13 +238,14 @@ int ssh_connect(const char *host, struct sockaddr_storage * hostaddr, u_short port, int family, int connection_attempts, - int needpriv, const char *proxy_command) + int anonymous, struct passwd *pw, const char *proxy_command) { int gaierr; int on = 1; int sock = -1, attempt; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; struct addrinfo hints, *ai, *aitop; + struct linger linger; struct servent *sp; /* * Did we get only other errors than "Connection refused" (which @@ -243,7 +254,8 @@ */ int full_failure = 1; - debug2("ssh_connect: needpriv %d", needpriv); + debug("ssh_connect: getuid %u geteuid %u anon %d", + (u_int) getuid(), (u_int) geteuid(), anonymous); /* Get default port if port has not been set. */ if (port == 0) { @@ -255,14 +267,14 @@ } /* If a proxy command is given, connect using it. */ if (proxy_command != NULL) - return ssh_proxy_connect(host, port, proxy_command); + return ssh_proxy_connect(host, port, pw, proxy_command); /* No proxy command. */ memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; - snprintf(strport, sizeof strport, "%u", port); + snprintf(strport, sizeof strport, "%d", port); if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) fatal("%s: %.100s: %s", __progname, host, gai_strerror(gaierr)); @@ -291,20 +303,30 @@ host, ntop, strport); /* Create a socket for connecting. */ - sock = ssh_create_socket(needpriv, ai->ai_family); + sock = ssh_create_socket(pw, + !anonymous && geteuid() == 0, + ai->ai_family); if (sock < 0) /* Any error is already output */ continue; + /* Connect to the host. We use the user's uid in the + * hope that it will help with tcp_wrappers showing + * the remote uid as root. + */ + temporarily_use_uid(pw); if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) { /* Successful connection. */ memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); + restore_uid(); break; } else { if (errno == ECONNREFUSED) full_failure = 0; - debug("connect to address %s port %s: %s", - ntop, strport, strerror(errno)); + log("ssh: connect to address %s port %s: %s", + sockaddr_ntop(ai->ai_addr), strport, + strerror(errno)); + restore_uid(); /* * Close the failed socket; there appear to * be some problems when reusing a socket for @@ -327,14 +349,20 @@ freeaddrinfo(aitop); /* Return failure if we didn't get a successful connection. */ - if (attempt >= connection_attempts) { - log("ssh: connect to host %s port %s: %s", - host, strport, strerror(errno)); + if (attempt >= connection_attempts) return full_failure ? ECONNABORTED : ECONNREFUSED; - } debug("Connection established."); + /* + * Set socket options. We would like the socket to disappear as soon + * as it has been closed for whatever reason. + */ + /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */ + linger.l_onoff = 1; + linger.l_linger = 5; + setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); + /* Set keepalives if requested. */ if (options.keepalives && setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, @@ -465,7 +493,7 @@ (p[0] == '\0') || (p[0] == '\n') || strncasecmp(p, "no", 2) == 0) ret = 0; - if (p && strncasecmp(p, "yes", 3) == 0) + if (strncasecmp(p, "yes", 3) == 0) ret = 1; if (p) xfree(p); @@ -478,6 +506,7 @@ * 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. */ + static int check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, int readonly, const char *user_hostfile, const char *system_hostfile) @@ -491,7 +520,7 @@ int local = 0, host_ip_differ = 0; char ntop[NI_MAXHOST]; char msg[1024]; - int len, host_line, ip_line, has_keys; + int len, host_line, ip_line; const char *host_file = NULL, *ip_file = NULL; /* @@ -632,19 +661,14 @@ "have requested strict checking.", type, host); goto fail; } else if (options.strict_host_key_checking == 2) { - has_keys = show_other_keys(host, host_key); /* The default */ fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); snprintf(msg, sizeof(msg), "The authenticity of host '%.200s (%s)' can't be " - "established%s\n" + "established.\n" "%s key fingerprint is %s.\n" "Are you sure you want to continue connecting " - "(yes/no)? ", - host, ip, - has_keys ? ",\nbut keys of different type are already " - "known for this host." : ".", - type, fp); + "(yes/no)? ", host, ip, type, fp); xfree(fp); if (!confirm(msg)) goto fail; @@ -747,9 +771,6 @@ * accept the authentication. */ break; - case HOST_FOUND: - fatal("internal error"); - break; } if (options.check_host_ip && host_status != HOST_CHANGED && @@ -763,7 +784,7 @@ len = strlen(msg); snprintf(msg + len, sizeof(msg) - len, "\nMatching host key in %s:%d", - host_file, host_line); + host_file, host_line); } if (options.strict_host_key_checking == 1) { log(msg); @@ -860,59 +881,4 @@ packet_put_string(padded, size); memset(padded, 0, size); xfree(padded); -} - -static int -show_key_from_file(const char *file, const char *host, int keytype) -{ - Key *found; - char *fp; - int line, ret; - - found = key_new(keytype); - if ((ret = lookup_key_in_hostfile_by_type(file, host, - keytype, found, &line))) { - fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); - log("WARNING: %s key found for host %s\n" - "in %s:%d\n" - "%s key fingerprint %s.", - key_type(found), host, file, line, - key_type(found), fp); - xfree(fp); - } - key_free(found); - return (ret); -} - -/* print all known host keys for a given host, but skip keys of given type */ -static int -show_other_keys(const char *host, Key *key) -{ - int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, -1}; - int i, found = 0; - - for (i = 0; type[i] != -1; i++) { - if (type[i] == key->type) - continue; - if (type[i] != KEY_RSA1 && - show_key_from_file(options.user_hostfile2, host, type[i])) { - found = 1; - continue; - } - if (type[i] != KEY_RSA1 && - show_key_from_file(options.system_hostfile2, host, type[i])) { - found = 1; - continue; - } - if (show_key_from_file(options.user_hostfile, host, type[i])) { - found = 1; - continue; - } - if (show_key_from_file(options.system_hostfile, host, type[i])) { - found = 1; - continue; - } - debug2("no key of type %d for host %s", type[i], host); - } - return (found); }