* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, 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.74 2000/05/17 16:57:02 markus Exp $");
+RCSID("$OpenBSD: sshconnect.c,v 1.89 2001/01/04 22:41:03 markus Exp $");
#include <openssl/bn.h>
#include <openssl/dsa.h>
char *server_version_string = NULL;
extern Options options;
-#ifdef HAVE___PROGNAME
extern char *__progname;
-#else /* HAVE___PROGNAME */
-static const char *__progname = "ssh";
-#endif /* HAVE___PROGNAME */
/*
* Connect to the given ssh server using a proxy command.
/* 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. */
int gaierr;
struct linger linger;
- 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) {
/* Create a socket for connecting. */
sock = ssh_create_socket(original_real_uid,
- !anonymous && geteuid() == 0 && port < IPPORT_RESERVED,
+#ifdef HAVE_CYGWIN
+ !anonymous,
+#else
+ !anonymous && geteuid() == 0,
+#endif
ai->ai_family);
if (sock < 0)
continue;
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);
/*
}
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;
/* 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));
FILE *f;
int retval = -1;
- if (isatty(0))
+ if (isatty(STDIN_FILENO))
f = stdin;
else
f = fopen("/dev/tty", "rw");
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)
int local = 0, host_ip_differ = 0;
int salen;
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
salen = sizeof(struct sockaddr_storage);
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, salen, ntop, sizeof(ntop),
NULL, 0, NI_NUMERICHOST) != 0)
fatal("check_host_key: getnameinfo failed");
ip = xstrdup(ntop);
+ } else {
+ ip = xstrdup("<no hostip for proxy command>");
+ }
+ /*
+ * 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);
}
/*
* 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;
/* 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 '%.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);
}
break;
case HOST_NEW:
} 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
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("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
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
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
*/
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 '%.30s'",
+ 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("Continue?", -1))
+ fatal("Aborted by user!\n");
+ }
+ }
+
+ xfree(ip);
}
/*
/* 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;