=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/sshconnect.c,v retrieving revision 1.72 retrieving revision 1.72.2.4 diff -u -r1.72 -r1.72.2.4 --- src/usr.bin/ssh/sshconnect.c 2000/05/04 09:50:22 1.72 +++ src/usr.bin/ssh/sshconnect.c 2001/03/12 15:44:17 1.72.2.4 @@ -2,29 +2,35 @@ * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved - * Created: Sat Mar 18 22:15:47 1995 ylo * Code to connect to a remote host, and to perform the client side of the * login (authentication) dialog. + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". */ #include "includes.h" -RCSID("$OpenBSD: sshconnect.c,v 1.72 2000/05/04 09:50:22 markus Exp $"); +RCSID("$OpenBSD: sshconnect.c,v 1.72.2.4 2001/03/12 15:44:17 jason Exp $"); #include -#include -#include +#include "ssh.h" #include "xmalloc.h" #include "rsa.h" -#include "ssh.h" #include "buffer.h" #include "packet.h" #include "uidswap.h" #include "compat.h" -#include "readconf.h" #include "key.h" #include "sshconnect.h" #include "hostfile.h" +#include "log.h" +#include "readconf.h" +#include "atomicio.h" +#include "misc.h" char *client_version_string = NULL; char *server_version_string = NULL; @@ -32,6 +38,9 @@ extern Options options; extern char *__progname; +/* AF_UNSPEC or AF_INET or AF_INET6 */ +extern int IPv4or6; + /* * Connect to the given ssh server using a proxy command. */ @@ -104,15 +113,15 @@ /* Stderr is left as it is so that error messages get printed on the user's terminal. */ - argv[0] = "/bin/sh"; + argv[0] = _PATH_BSHELL; argv[1] = "-c"; argv[2] = command_string; argv[3] = NULL; /* Execute the proxy command. Note that we gave up any extra privileges above. */ - execv("/bin/sh", argv); - perror("/bin/sh"); + execv(argv[0], argv); + perror(argv[0]); exit(1); } /* Parent. */ @@ -182,15 +191,16 @@ int anonymous, uid_t original_real_uid, const char *proxy_command) { + int gaierr; + int on = 1; int sock = -1, attempt; - struct servent *sp; - struct addrinfo hints, *ai, *aitop; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; - int gaierr; + struct addrinfo hints, *ai, *aitop; struct linger linger; + struct servent *sp; - debug("ssh_connect: getuid %d geteuid %d anon %d", - (int) getuid(), (int) geteuid(), anonymous); + 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) { @@ -239,7 +249,7 @@ /* Create a socket for connecting. */ sock = ssh_create_socket(original_real_uid, - !anonymous && geteuid() == 0 && port < IPPORT_RESERVED, + !anonymous && geteuid() == 0, ai->ai_family); if (sock < 0) continue; @@ -251,7 +261,7 @@ temporarily_use_uid(original_real_uid); if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) { /* Successful connection. */ - memcpy(hostaddr, ai->ai_addr, sizeof(*hostaddr)); + memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); restore_uid(); break; } else { @@ -289,59 +299,56 @@ /* 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)); + 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, + sizeof(on)) < 0) + error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); + /* Set the connection. */ packet_set_connection(sock, sock); return 1; } -char * -chop(char *s) -{ - char *t = s; - while (*t) { - if(*t == '\n' || *t == '\r') { - *t = '\0'; - return s; - } - t++; - } - return s; - -} - /* * Waits for the server identification string, and sends our own * identification string. */ void -ssh_exchange_identification() +ssh_exchange_identification(void) { char buf[256], remote_version[256]; /* must be same size! */ int remote_major, remote_minor, i, mismatch; int connection_in = packet_get_connection_in(); int connection_out = packet_get_connection_out(); + int minor1 = PROTOCOL_MINOR_1; /* Read other side\'s version identification. */ - for (i = 0; i < sizeof(buf) - 1; i++) { - int len = read(connection_in, &buf[i], 1); - if (len < 0) - fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); - if (len != 1) - fatal("ssh_exchange_identification: Connection closed by remote host"); - if (buf[i] == '\r') { - buf[i] = '\n'; - buf[i + 1] = 0; - continue; /**XXX wait for \n */ + for (;;) { + for (i = 0; i < sizeof(buf) - 1; i++) { + int len = atomicio(read, connection_in, &buf[i], 1); + if (len < 0) + fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); + if (len != 1) + fatal("ssh_exchange_identification: Connection closed by remote host"); + if (buf[i] == '\r') { + buf[i] = '\n'; + buf[i + 1] = 0; + continue; /**XXX wait for \n */ + } + if (buf[i] == '\n') { + buf[i + 1] = 0; + break; + } } - if (buf[i] == '\n') { - buf[i + 1] = 0; + buf[sizeof(buf) - 1] = 0; + if (strncmp(buf, "SSH-", 4) == 0) break; - } + debug("ssh_exchange_identification: %s", buf); } - buf[sizeof(buf) - 1] = 0; server_version_string = xstrdup(buf); /* @@ -371,9 +378,10 @@ } if (remote_minor < 3) { fatal("Remote machine has too old SSH software version."); - } else if (remote_minor == 3) { + } else if (remote_minor == 3 || remote_minor == 4) { /* We speak 1.3, too. */ enable_compat13(); + minor1 = 3; if (options.forward_agent) { log("Agent forwarding disabled for protocol 1.3"); options.forward_agent = 0; @@ -399,7 +407,7 @@ /* Send our own protocol version identification. */ snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, - compat20 ? PROTOCOL_MINOR_2 : PROTOCOL_MINOR_1, + compat20 ? PROTOCOL_MINOR_2 : minor1, SSH_VERSION); if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf)) fatal("write: %.100s", strerror(errno)); @@ -409,6 +417,7 @@ debug("Local version string %.100s", client_version_string); } +/* defaults to 'no' */ int read_yes_or_no(const char *prompt, int defval) { @@ -416,10 +425,13 @@ FILE *f; int retval = -1; - if (isatty(0)) + if (options.batch_mode) + return 0; + + if (isatty(STDIN_FILENO)) f = stdin; else - f = fopen("/dev/tty", "rw"); + f = fopen(_PATH_TTY, "rw"); if (f == NULL) return 0; @@ -441,8 +453,10 @@ retval = defval; if (strcmp(buf, "yes") == 0) retval = 1; - if (strcmp(buf, "no") == 0) + else if (strcmp(buf, "no") == 0) retval = 0; + else + fprintf(stderr, "Please type 'yes' or 'no'.\n"); if (retval != -1) { if (f != stdin) @@ -468,6 +482,8 @@ HostStatus ip_status; int local = 0, host_ip_differ = 0; char ntop[NI_MAXHOST]; + int host_line, ip_line; + const char *host_file = NULL, *ip_file = NULL; /* * Force accepting of the host key for loopback/localhost. The @@ -489,26 +505,43 @@ local = 0; break; } - if (local) { - debug("Forcing accepting of host key for loopback/localhost."); + if (local && options.host_key_alias == NULL) { + debug("Forcing accepting of host key for " + "loopback/localhost."); return; } /* - * Turn off check_host_ip for proxy connects, since - * we don't have the remote ip-address + * We don't have the remote ip-address for connections + * using a proxy command */ - if (options.proxy_command != NULL && options.check_host_ip) - options.check_host_ip = 0; - - if (options.check_host_ip) { + if (options.proxy_command == NULL) { if (getnameinfo(hostaddr, hostaddr->sa_len, ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0) fatal("check_host_key: getnameinfo failed"); ip = xstrdup(ntop); + } else { + ip = xstrdup(""); } + /* + * 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)) + 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. + */ + if (options.host_key_alias != NULL) { + host = options.host_key_alias; + debug("using hostkeyalias: %s", host); + } + + /* * Store the host key from the known host file in here so that we can * compare it with the key for the IP address. */ @@ -518,19 +551,25 @@ * Check if the host key is present in the user\'s list of known * hosts or in the systemwide list. */ - host_status = check_host_in_hostfile(user_hostfile, host, host_key, file_key); - if (host_status == HOST_NEW) - host_status = check_host_in_hostfile(system_hostfile, host, host_key, file_key); + host_file = user_hostfile; + host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line); + if (host_status == HOST_NEW) { + host_file = system_hostfile; + host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line); + } /* * Also perform check for the ip address, skip the check if we are * localhost or the hostname was an ip address to begin with */ - if (options.check_host_ip && !local && strcmp(host, ip)) { + if (options.check_host_ip) { Key *ip_key = key_new(host_key->type); - ip_status = check_host_in_hostfile(user_hostfile, ip, host_key, ip_key); - if (ip_status == HOST_NEW) - ip_status = check_host_in_hostfile(system_hostfile, ip, host_key, ip_key); + ip_file = user_hostfile; + ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line); + if (ip_status == HOST_NEW) { + ip_file = system_hostfile; + ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line); + } if (host_status == HOST_CHANGED && (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key))) host_ip_differ = 1; @@ -546,17 +585,14 @@ /* The host is known and the key matches. */ debug("Host '%.200s' is known and matches the %s host key.", host, type); - if (options.check_host_ip) { - if (ip_status == HOST_NEW) { - if (!add_host_to_hostfile(user_hostfile, ip, host_key)) - log("Failed to add the %s host key for IP address '%.30s' to the list of known hosts (%.30s).", - type, ip, user_hostfile); - else - log("Warning: Permanently added the %s host key for IP address '%.30s' to the list of known hosts.", - type, ip); - } else if (ip_status != HOST_OK) - log("Warning: the %s host key for '%.200s' differs from the key for the IP address '%.30s'", - type, host, ip); + debug("Found key in %s:%d", host_file, host_line); + if (options.check_host_ip && ip_status == HOST_NEW) { + if (!add_host_to_hostfile(user_hostfile, ip, host_key)) + log("Failed to add the %s host key for IP address '%.128s' to the list of known hosts (%.30s).", + type, ip, user_hostfile); + else + log("Warning: Permanently added the %s host key for IP address '%.128s' to the list of known hosts.", + type, ip); } break; case HOST_NEW: @@ -568,16 +604,15 @@ } else if (options.strict_host_key_checking == 2) { /* The default */ char prompt[1024]; - char *fp = key_fingerprint(host_key); snprintf(prompt, sizeof(prompt), - "The authenticity of host '%.200s' can't be established.\n" + "The authenticity of host '%.200s (%s)' can't be established.\n" "%s key fingerprint is %s.\n" "Are you sure you want to continue connecting (yes/no)? ", - host, type, fp); + host, ip, type, key_fingerprint(host_key)); if (!read_yes_or_no(prompt, -1)) fatal("Aborted by user!\n"); } - if (options.check_host_ip && ip_status == HOST_NEW && strcmp(host, ip)) { + if (options.check_host_ip && ip_status == HOST_NEW) { snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); hostp = hostline; } else @@ -607,7 +642,9 @@ error("and the key for the according IP address %s", ip); error("%s. This could either mean that", msg); error("DNS SPOOFING is happening or the IP address for the host"); - error("and its host key have changed at the same time"); + error("and its host key have changed at the same time."); + if (ip_status != HOST_NEW) + error("Offending key for IP in %s:%d", ip_file, ip_line); } /* The host key has changed. */ error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); @@ -616,9 +653,12 @@ error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); error("It is also possible that the %s host key has just been changed.", type); + error("The fingerprint for the %s key sent by the remote host is\n%s.", + type, key_fingerprint(host_key)); error("Please contact your system administrator."); error("Add correct host key in %.100s to get rid of this message.", - user_hostfile); + user_hostfile); + error("Offending key in %s:%d", host_file, host_line); /* * If strict host key checking is in use, the user will have @@ -640,6 +680,14 @@ error("Agent forwarding is disabled to avoid trojan horses."); options.forward_agent = 0; } + if (options.forward_x11) { + error("X11 forwarding is disabled to avoid trojan horses."); + options.forward_x11 = 0; + } + if (options.num_local_forwards > 0 || options.num_remote_forwards > 0) { + error("Port forwarding is disabled to avoid trojan horses."); + options.num_local_forwards = options.num_remote_forwards = 0; + } /* * XXX Should permit the user to change to use the new id. * This could be done by converting the host key to an @@ -649,8 +697,25 @@ */ break; } - if (options.check_host_ip) - xfree(ip); + + if (options.check_host_ip && host_status != HOST_CHANGED && + ip_status == HOST_CHANGED) { + log("Warning: the %s host key for '%.200s' " + "differs from the key for the IP address '%.128s'", + type, host, ip); + if (host_status == HOST_OK) + log("Matching host key in %s:%d", host_file, host_line); + log("Offending key for IP in %s:%d", ip_file, ip_line); + if (options.strict_host_key_checking == 1) { + fatal("Exiting, you have requested strict checking."); + } else if (options.strict_host_key_checking == 2) { + if (!read_yes_or_no("Are you sure you want " \ + "to continue connecting (yes/no)? ", -1)) + fatal("Aborted by user!\n"); + } + } + + xfree(ip); } /* @@ -671,7 +736,7 @@ /* Get local user name. Use it as server user if no user name was given. */ pw = getpwuid(original_real_uid); if (!pw) - fatal("User id %d not found from user database.", original_real_uid); + fatal("User id %u not found from user database.", original_real_uid); local_user = xstrdup(pw->pw_name); server_user = options.user ? options.user : local_user; @@ -696,4 +761,19 @@ ssh_kex(host, hostaddr); ssh_userauth(local_user, server_user, host, host_key_valid, own_host_key); } +} + +void +ssh_put_password(char *password) +{ + int size; + char *padded; + + size = roundup(strlen(password) + 1, 32); + padded = xmalloc(size); + memset(padded, 0, size); + strlcpy(padded, password, size); + packet_put_string(padded, size); + memset(padded, 0, size); + xfree(padded); }