sshconnect.c revision 147005
155992Swpaul/*
255992Swpaul * Author: Tatu Ylonen <ylo@cs.hut.fi>
355992Swpaul * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
455992Swpaul *                    All rights reserved
555992Swpaul * Code to connect to a remote host, and to perform the client side of the
655992Swpaul * login (authentication) dialog.
755992Swpaul *
855992Swpaul * As far as I am concerned, the code I have written for this software
955992Swpaul * can be used freely for any purpose.  Any derived versions of this
1055992Swpaul * software must be clearly marked as such, and if the derived work is
1155992Swpaul * incompatible with the protocol description in the RFC file, it must be
1255992Swpaul * called by a name other than "ssh" or "Secure Shell".
1355992Swpaul */
1455992Swpaul
1555992Swpaul#include "includes.h"
1655992SwpaulRCSID("$OpenBSD: sshconnect.c,v 1.162 2005/03/10 22:01:06 deraadt Exp $");
1755992Swpaul
1855992Swpaul#include <openssl/bn.h>
1955992Swpaul
2055992Swpaul#include "ssh.h"
2155992Swpaul#include "xmalloc.h"
2255992Swpaul#include "rsa.h"
2355992Swpaul#include "buffer.h"
2455992Swpaul#include "packet.h"
2555992Swpaul#include "uidswap.h"
2655992Swpaul#include "compat.h"
2755992Swpaul#include "key.h"
2855992Swpaul#include "sshconnect.h"
2955992Swpaul#include "hostfile.h"
3055992Swpaul#include "log.h"
3155992Swpaul#include "readconf.h"
3255992Swpaul#include "atomicio.h"
3355992Swpaul#include "misc.h"
3455992Swpaul
3555992Swpaul#include "dns.h"
3655992Swpaul
3755992Swpaulchar *client_version_string = NULL;
3855992Swpaulchar *server_version_string = NULL;
3955992Swpaul
4055992Swpaulint matching_host_key_dns = 0;
4155992Swpaul
4255992Swpaul/* import */
4355992Swpaulextern Options options;
4455992Swpaulextern char *__progname;
4555992Swpaulextern uid_t original_real_uid;
4655992Swpaulextern uid_t original_effective_uid;
4755992Swpaulextern pid_t proxy_command_pid;
4855992Swpaul
4955992Swpaul#ifndef INET6_ADDRSTRLEN		/* for non IPv6 machines */
5055992Swpaul#define INET6_ADDRSTRLEN 46
5155992Swpaul#endif
5255992Swpaul
5355992Swpaulstatic int show_other_keys(const char *, Key *);
5455992Swpaulstatic void warn_changed_key(Key *);
5555992Swpaul
5655992Swpaul/*
5755992Swpaul * Connect to the given ssh server using a proxy command.
5855992Swpaul */
5955992Swpaulstatic int
6055992Swpaulssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
6155992Swpaul{
6255992Swpaul	Buffer command;
6355992Swpaul	const char *cp;
6455992Swpaul	char *command_string;
6555992Swpaul	int pin[2], pout[2];
6655992Swpaul	pid_t pid;
6755992Swpaul	char strport[NI_MAXSERV];
6855992Swpaul
6955992Swpaul	/* Convert the port number into a string. */
7055992Swpaul	snprintf(strport, sizeof strport, "%hu", port);
7155992Swpaul
7284811Sjhb	/*
7367365Sjhb	 * Build the final command string in the buffer by making the
7455992Swpaul	 * appropriate substitutions to the given proxy command.
7555992Swpaul	 *
7655992Swpaul	 * Use "exec" to avoid "sh -c" processes on some platforms
7755992Swpaul	 * (e.g. Solaris)
7855992Swpaul	 */
7955992Swpaul	buffer_init(&command);
8077217Sphk	buffer_append(&command, "exec ", 5);
8155992Swpaul
8255992Swpaul	for (cp = proxy_command; *cp; cp++) {
8355992Swpaul		if (cp[0] == '%' && cp[1] == '%') {
8455992Swpaul			buffer_append(&command, "%", 1);
8555992Swpaul			cp++;
8655992Swpaul			continue;
8755992Swpaul		}
8855992Swpaul		if (cp[0] == '%' && cp[1] == 'h') {
8955992Swpaul			buffer_append(&command, host, strlen(host));
9055992Swpaul			cp++;
9155992Swpaul			continue;
9255992Swpaul		}
9355992Swpaul		if (cp[0] == '%' && cp[1] == 'p') {
9455992Swpaul			buffer_append(&command, strport, strlen(strport));
9555992Swpaul			cp++;
9655992Swpaul			continue;
9755992Swpaul		}
9855992Swpaul		buffer_append(&command, cp, 1);
9955992Swpaul	}
10081221Sbrooks	buffer_append(&command, "\0", 1);
10155992Swpaul
10255992Swpaul	/* Get the final command string. */
10355992Swpaul	command_string = buffer_ptr(&command);
104108401Sambrisko
10555992Swpaul	/* Create pipes for communicating with the proxy. */
10655992Swpaul	if (pipe(pin) < 0 || pipe(pout) < 0)
10755992Swpaul		fatal("Could not create pipes to communicate with the proxy: %.100s",
10855992Swpaul		    strerror(errno));
10981221Sbrooks
11055992Swpaul	debug("Executing proxy command: %.500s", command_string);
11155992Swpaul
11255992Swpaul	/* Fork and execute the proxy command. */
11355992Swpaul	if ((pid = fork()) == 0) {
11455992Swpaul		char *argv[10];
11555992Swpaul
11692739Salfred		/* Child.  Permanently give up superuser privileges. */
11792739Salfred		seteuid(original_real_uid);
11892739Salfred		setuid(original_real_uid);
11955992Swpaul
12083270Sbrooks		/* Redirect stdin and stdout. */
12183270Sbrooks		close(pin[1]);
12255992Swpaul		if (pin[0] != 0) {
12355992Swpaul			if (dup2(pin[0], 0) < 0)
12455992Swpaul				perror("dup2 stdin");
12555992Swpaul			close(pin[0]);
12655992Swpaul		}
12783270Sbrooks		close(pout[0]);
12855992Swpaul		if (dup2(pout[1], 1) < 0)
12956051Swpaul			perror("dup2 stdout");
13055992Swpaul		/* Cannot be 1 because pin allocated two descriptors. */
13155992Swpaul		close(pout[1]);
13255992Swpaul
13355992Swpaul		/* Stderr is left as it is so that error messages get
13455992Swpaul		   printed on the user's terminal. */
13555992Swpaul		argv[0] = _PATH_BSHELL;
136108401Sambrisko		argv[1] = "-c";
137108401Sambrisko		argv[2] = command_string;
138108401Sambrisko		argv[3] = NULL;
139108401Sambrisko
140108401Sambrisko		/* Execute the proxy command.  Note that we gave up any
141108401Sambrisko		   extra privileges above. */
14255992Swpaul		execv(argv[0], argv);
14355992Swpaul		perror(argv[0]);
14455992Swpaul		exit(1);
14583270Sbrooks	}
14683270Sbrooks	/* Parent. */
14755992Swpaul	if (pid < 0)
14855992Swpaul		fatal("fork failed: %.100s", strerror(errno));
14955992Swpaul	else
15055992Swpaul		proxy_command_pid = pid; /* save pid to clean up later */
15155992Swpaul
15255992Swpaul	/* Close child side of the descriptors. */
15355992Swpaul	close(pin[0]);
15455992Swpaul	close(pout[1]);
15555992Swpaul
15655992Swpaul	/* Free the command name. */
15783270Sbrooks	buffer_free(&command);
158108401Sambrisko
159108401Sambrisko	/* Set the connection file descriptors. */
160108401Sambrisko	packet_set_connection(pout[0], pin[1]);
161108401Sambrisko
162108401Sambrisko	/* Indicate OK return */
163108401Sambrisko	return 0;
164108401Sambrisko}
165108401Sambrisko
166108401Sambrisko/*
167108401Sambrisko * Creates a (possibly privileged) socket for use as the ssh connection.
168108401Sambrisko */
169108401Sambriskostatic int
17055992Swpaulssh_create_socket(int privileged, struct addrinfo *ai)
171108401Sambrisko{
172108401Sambrisko	int sock, gaierr;
173108401Sambrisko	struct addrinfo hints, *res;
174108401Sambrisko
175108401Sambrisko	/*
176108401Sambrisko	 * If we are running as root and want to connect to a privileged
17755992Swpaul	 * port, bind our own socket to a privileged port.
17855992Swpaul	 */
17955992Swpaul	if (privileged) {
18055992Swpaul		int p = IPPORT_RESERVED - 1;
18155992Swpaul		PRIV_START;
18255992Swpaul		sock = rresvport_af(&p, ai->ai_family);
18355992Swpaul		PRIV_END;
18455992Swpaul		if (sock < 0)
18555992Swpaul			error("rresvport: af=%d %.100s", ai->ai_family,
18655992Swpaul			    strerror(errno));
18755992Swpaul		else
188108401Sambrisko			debug("Allocated local port %d.", p);
189108401Sambrisko		return sock;
190108401Sambrisko	}
191108401Sambrisko	sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
192108401Sambrisko	if (sock < 0)
193108401Sambrisko		error("socket: %.100s", strerror(errno));
194108401Sambrisko
195108401Sambrisko	/* Bind the socket to an alternative local IP address */
196108401Sambrisko	if (options.bind_address == NULL)
197108401Sambrisko		return sock;
198108401Sambrisko
199108401Sambrisko	memset(&hints, 0, sizeof(hints));
200108401Sambrisko	hints.ai_family = ai->ai_family;
201108401Sambrisko	hints.ai_socktype = ai->ai_socktype;
202108401Sambrisko	hints.ai_protocol = ai->ai_protocol;
203108401Sambrisko	hints.ai_flags = AI_PASSIVE;
204108401Sambrisko	gaierr = getaddrinfo(options.bind_address, "0", &hints, &res);
205108401Sambrisko	if (gaierr) {
206108401Sambrisko		error("getaddrinfo: %s: %s", options.bind_address,
207108401Sambrisko		    gai_strerror(gaierr));
208108401Sambrisko		close(sock);
209108401Sambrisko		return -1;
210108401Sambrisko	}
211108401Sambrisko	if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
212108401Sambrisko		error("bind: %s: %s", options.bind_address, strerror(errno));
213108401Sambrisko		close(sock);
214108401Sambrisko		freeaddrinfo(res);
215108401Sambrisko		return -1;
216108401Sambrisko	}
217108401Sambrisko	freeaddrinfo(res);
218108401Sambrisko	return sock;
219108401Sambrisko}
220108401Sambrisko
221108401Sambriskostatic int
222108401Sambriskotimeout_connect(int sockfd, const struct sockaddr *serv_addr,
223108401Sambrisko    socklen_t addrlen, int timeout)
224108401Sambrisko{
225108401Sambrisko	fd_set *fdset;
226108401Sambrisko	struct timeval tv;
227108401Sambrisko	socklen_t optlen;
22855992Swpaul	int fdsetsz, optval, rc, result = -1;
22955992Swpaul
23055992Swpaul	if (timeout <= 0)
23155992Swpaul		return (connect(sockfd, serv_addr, addrlen));
23255992Swpaul
23383270Sbrooks	set_nonblock(sockfd);
23455992Swpaul	rc = connect(sockfd, serv_addr, addrlen);
23555992Swpaul	if (rc == 0) {
23655992Swpaul		unset_nonblock(sockfd);
23755992Swpaul		return (0);
23855992Swpaul	}
23955992Swpaul	if (errno != EINPROGRESS)
24067096Swpaul		return (-1);
24155992Swpaul
24255992Swpaul	fdsetsz = howmany(sockfd + 1, NFDBITS) * sizeof(fd_mask);
24355992Swpaul	fdset = (fd_set *)xmalloc(fdsetsz);
244108401Sambrisko
245108401Sambrisko	memset(fdset, 0, fdsetsz);
24655992Swpaul	FD_SET(sockfd, fdset);
24755992Swpaul	tv.tv_sec = timeout;
24855992Swpaul	tv.tv_usec = 0;
24983270Sbrooks
25055992Swpaul	for (;;) {
25155992Swpaul		rc = select(sockfd + 1, NULL, fdset, NULL, &tv);
25255992Swpaul		if (rc != -1 || errno != EINTR)
25355992Swpaul			break;
25455992Swpaul	}
25555992Swpaul
25677217Sphk	switch (rc) {
257106937Ssam	case 0:
25855992Swpaul		/* Timed out */
25955992Swpaul		errno = ETIMEDOUT;
26055992Swpaul		break;
26155992Swpaul	case -1:
26255992Swpaul		/* Select error */
26355992Swpaul		debug("select: %s", strerror(errno));
26455992Swpaul		break;
26555992Swpaul	case 1:
26655992Swpaul		/* Completed or failed */
26755992Swpaul		optval = 0;
26855992Swpaul		optlen = sizeof(optval);
26955992Swpaul		if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval,
27055992Swpaul		    &optlen) == -1) {
27155992Swpaul			debug("getsockopt: %s", strerror(errno));
27255992Swpaul			break;
27355992Swpaul		}
27455992Swpaul		if (optval != 0) {
27555992Swpaul			errno = optval;
27655992Swpaul			break;
27755992Swpaul		}
27855992Swpaul		result = 0;
27955992Swpaul		unset_nonblock(sockfd);
28055992Swpaul		break;
28155992Swpaul	default:
282		/* Should not occur */
283		fatal("Bogus return (%d) from select()", rc);
284	}
285
286	xfree(fdset);
287	return (result);
288}
289
290/*
291 * Opens a TCP/IP connection to the remote server on the given host.
292 * The address of the remote host will be returned in hostaddr.
293 * If port is 0, the default port will be used.  If needpriv is true,
294 * a privileged port will be allocated to make the connection.
295 * This requires super-user privileges if needpriv is true.
296 * Connection_attempts specifies the maximum number of tries (one per
297 * second).  If proxy_command is non-NULL, it specifies the command (with %h
298 * and %p substituted for host and port, respectively) to use to contact
299 * the daemon.
300 */
301int
302ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
303    u_short port, int family, int connection_attempts,
304    int needpriv, const char *proxy_command)
305{
306	int gaierr;
307	int on = 1;
308	int sock = -1, attempt;
309	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
310	struct addrinfo hints, *ai, *aitop;
311	struct servent *sp;
312
313	debug2("ssh_connect: needpriv %d", needpriv);
314
315	/* Get default port if port has not been set. */
316	if (port == 0) {
317		sp = getservbyname(SSH_SERVICE_NAME, "tcp");
318		if (sp)
319			port = ntohs(sp->s_port);
320		else
321			port = SSH_DEFAULT_PORT;
322	}
323	/* If a proxy command is given, connect using it. */
324	if (proxy_command != NULL)
325		return ssh_proxy_connect(host, port, proxy_command);
326
327	/* No proxy command. */
328
329	memset(&hints, 0, sizeof(hints));
330	hints.ai_family = family;
331	hints.ai_socktype = SOCK_STREAM;
332	snprintf(strport, sizeof strport, "%u", port);
333	if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
334		fatal("%s: %.100s: %s", __progname, host,
335		    gai_strerror(gaierr));
336
337	/*
338	 * Try to connect several times.  On some machines, the first time
339	 * will sometimes fail.  In general socket code appears to behave
340	 * quite magically on many machines.
341		 */
342	for (attempt = 0; ;) {
343		if (attempt > 0)
344			debug("Trying again...");
345
346		/* Loop through addresses for this host, and try each one in
347		   sequence until the connection succeeds. */
348		for (ai = aitop; ai; ai = ai->ai_next) {
349			if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
350				continue;
351			if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
352			    ntop, sizeof(ntop), strport, sizeof(strport),
353			    NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
354				error("ssh_connect: getnameinfo failed");
355				continue;
356			}
357			debug("Connecting to %.200s [%.100s] port %s.",
358				host, ntop, strport);
359
360			/* Create a socket for connecting. */
361			sock = ssh_create_socket(needpriv, ai);
362			if (sock < 0)
363				/* Any error is already output */
364				continue;
365
366			if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen,
367			    options.connection_timeout) >= 0) {
368				/* Successful connection. */
369				memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
370				break;
371			} else {
372				debug("connect to address %s port %s: %s",
373				    ntop, strport, strerror(errno));
374				/*
375				 * Close the failed socket; there appear to
376				 * be some problems when reusing a socket for
377				 * which connect() has already returned an
378				 * error.
379				 */
380				close(sock);
381			}
382		}
383		if (ai)
384			break;	/* Successful connection. */
385
386		attempt++;
387		if (attempt >= connection_attempts)
388			break;
389		/* Sleep a moment before retrying. */
390		sleep(1);
391	}
392
393	freeaddrinfo(aitop);
394
395	/* Return failure if we didn't get a successful connection. */
396	if (attempt >= connection_attempts) {
397		error("ssh: connect to host %s port %s: %s",
398		    host, strport, strerror(errno));
399		return (-1);
400	}
401
402	debug("Connection established.");
403
404	/* Set SO_KEEPALIVE if requested. */
405	if (options.tcp_keep_alive &&
406	    setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
407	    sizeof(on)) < 0)
408		error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
409
410	/* Set the connection. */
411	packet_set_connection(sock, sock);
412
413	return 0;
414}
415
416/*
417 * Waits for the server identification string, and sends our own
418 * identification string.
419 */
420static void
421ssh_exchange_identification(void)
422{
423	char buf[256], remote_version[256];	/* must be same size! */
424	int remote_major, remote_minor, i, mismatch;
425	int connection_in = packet_get_connection_in();
426	int connection_out = packet_get_connection_out();
427	int minor1 = PROTOCOL_MINOR_1;
428
429	/* Read other side\'s version identification. */
430	for (;;) {
431		for (i = 0; i < sizeof(buf) - 1; i++) {
432			int len = atomicio(read, connection_in, &buf[i], 1);
433			if (len < 0)
434				fatal("ssh_exchange_identification: read: %.100s", strerror(errno));
435			if (len != 1)
436				fatal("ssh_exchange_identification: Connection closed by remote host");
437			if (buf[i] == '\r') {
438				buf[i] = '\n';
439				buf[i + 1] = 0;
440				continue;		/**XXX wait for \n */
441			}
442			if (buf[i] == '\n') {
443				buf[i + 1] = 0;
444				break;
445			}
446		}
447		buf[sizeof(buf) - 1] = 0;
448		if (strncmp(buf, "SSH-", 4) == 0)
449			break;
450		debug("ssh_exchange_identification: %s", buf);
451	}
452	server_version_string = xstrdup(buf);
453
454	/*
455	 * Check that the versions match.  In future this might accept
456	 * several versions and set appropriate flags to handle them.
457	 */
458	if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n",
459	    &remote_major, &remote_minor, remote_version) != 3)
460		fatal("Bad remote protocol version identification: '%.100s'", buf);
461	debug("Remote protocol version %d.%d, remote software version %.100s",
462	    remote_major, remote_minor, remote_version);
463
464	compat_datafellows(remote_version);
465	mismatch = 0;
466
467	switch (remote_major) {
468	case 1:
469		if (remote_minor == 99 &&
470		    (options.protocol & SSH_PROTO_2) &&
471		    !(options.protocol & SSH_PROTO_1_PREFERRED)) {
472			enable_compat20();
473			break;
474		}
475		if (!(options.protocol & SSH_PROTO_1)) {
476			mismatch = 1;
477			break;
478		}
479		if (remote_minor < 3) {
480			fatal("Remote machine has too old SSH software version.");
481		} else if (remote_minor == 3 || remote_minor == 4) {
482			/* We speak 1.3, too. */
483			enable_compat13();
484			minor1 = 3;
485			if (options.forward_agent) {
486				logit("Agent forwarding disabled for protocol 1.3");
487				options.forward_agent = 0;
488			}
489		}
490		break;
491	case 2:
492		if (options.protocol & SSH_PROTO_2) {
493			enable_compat20();
494			break;
495		}
496		/* FALLTHROUGH */
497	default:
498		mismatch = 1;
499		break;
500	}
501	if (mismatch)
502		fatal("Protocol major versions differ: %d vs. %d",
503		    (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
504		    remote_major);
505	/* Send our own protocol version identification. */
506	snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
507	    compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
508	    compat20 ? PROTOCOL_MINOR_2 : minor1,
509	    SSH_VERSION);
510	if (atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf))
511		fatal("write: %.100s", strerror(errno));
512	client_version_string = xstrdup(buf);
513	chop(client_version_string);
514	chop(server_version_string);
515	debug("Local version string %.100s", client_version_string);
516}
517
518/* defaults to 'no' */
519static int
520confirm(const char *prompt)
521{
522	const char *msg, *again = "Please type 'yes' or 'no': ";
523	char *p;
524	int ret = -1;
525
526	if (options.batch_mode)
527		return 0;
528	for (msg = prompt;;msg = again) {
529		p = read_passphrase(msg, RP_ECHO);
530		if (p == NULL ||
531		    (p[0] == '\0') || (p[0] == '\n') ||
532		    strncasecmp(p, "no", 2) == 0)
533			ret = 0;
534		if (p && strncasecmp(p, "yes", 3) == 0)
535			ret = 1;
536		if (p)
537			xfree(p);
538		if (ret != -1)
539			return ret;
540	}
541}
542
543/*
544 * check whether the supplied host key is valid, return -1 if the key
545 * is not valid. the user_hostfile will not be updated if 'readonly' is true.
546 */
547static int
548check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
549    int readonly, const char *user_hostfile, const char *system_hostfile)
550{
551	Key *file_key;
552	const char *type = key_type(host_key);
553	char *ip = NULL;
554	char hostline[1000], *hostp, *fp;
555	HostStatus host_status;
556	HostStatus ip_status;
557	int r, local = 0, host_ip_differ = 0;
558	int salen;
559	char ntop[NI_MAXHOST];
560	char msg[1024];
561	int len, host_line, ip_line;
562	const char *host_file = NULL, *ip_file = NULL;
563
564	/*
565	 * Force accepting of the host key for loopback/localhost. The
566	 * problem is that if the home directory is NFS-mounted to multiple
567	 * machines, localhost will refer to a different machine in each of
568	 * them, and the user will get bogus HOST_CHANGED warnings.  This
569	 * essentially disables host authentication for localhost; however,
570	 * this is probably not a real problem.
571	 */
572	/**  hostaddr == 0! */
573	switch (hostaddr->sa_family) {
574	case AF_INET:
575		local = (ntohl(((struct sockaddr_in *)hostaddr)->
576		   sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
577		salen = sizeof(struct sockaddr_in);
578		break;
579	case AF_INET6:
580		local = IN6_IS_ADDR_LOOPBACK(
581		    &(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
582		salen = sizeof(struct sockaddr_in6);
583		break;
584	default:
585		local = 0;
586		salen = sizeof(struct sockaddr_storage);
587		break;
588	}
589	if (options.no_host_authentication_for_localhost == 1 && local &&
590	    options.host_key_alias == NULL) {
591		debug("Forcing accepting of host key for "
592		    "loopback/localhost.");
593		return 0;
594	}
595
596	/*
597	 * We don't have the remote ip-address for connections
598	 * using a proxy command
599	 */
600	if (options.proxy_command == NULL) {
601		if (getnameinfo(hostaddr, salen, ntop, sizeof(ntop),
602		    NULL, 0, NI_NUMERICHOST) != 0)
603			fatal("check_host_key: getnameinfo failed");
604		ip = xstrdup(ntop);
605	} else {
606		ip = xstrdup("<no hostip for proxy command>");
607	}
608	/*
609	 * Turn off check_host_ip if the connection is to localhost, via proxy
610	 * command or if we don't have a hostname to compare with
611	 */
612	if (options.check_host_ip &&
613	    (local || strcmp(host, ip) == 0 || options.proxy_command != NULL))
614		options.check_host_ip = 0;
615
616	/*
617	 * Allow the user to record the key under a different name. This is
618	 * useful for ssh tunneling over forwarded connections or if you run
619	 * multiple sshd's on different ports on the same machine.
620	 */
621	if (options.host_key_alias != NULL) {
622		host = options.host_key_alias;
623		debug("using hostkeyalias: %s", host);
624	}
625
626	/*
627	 * Store the host key from the known host file in here so that we can
628	 * compare it with the key for the IP address.
629	 */
630	file_key = key_new(host_key->type);
631
632	/*
633	 * Check if the host key is present in the user\'s list of known
634	 * hosts or in the systemwide list.
635	 */
636	host_file = user_hostfile;
637	host_status = check_host_in_hostfile(host_file, host, host_key,
638	    file_key, &host_line);
639	if (host_status == HOST_NEW) {
640		host_file = system_hostfile;
641		host_status = check_host_in_hostfile(host_file, host, host_key,
642		    file_key, &host_line);
643	}
644	/*
645	 * Also perform check for the ip address, skip the check if we are
646	 * localhost or the hostname was an ip address to begin with
647	 */
648	if (options.check_host_ip) {
649		Key *ip_key = key_new(host_key->type);
650
651		ip_file = user_hostfile;
652		ip_status = check_host_in_hostfile(ip_file, ip, host_key,
653		    ip_key, &ip_line);
654		if (ip_status == HOST_NEW) {
655			ip_file = system_hostfile;
656			ip_status = check_host_in_hostfile(ip_file, ip,
657			    host_key, ip_key, &ip_line);
658		}
659		if (host_status == HOST_CHANGED &&
660		    (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))
661			host_ip_differ = 1;
662
663		key_free(ip_key);
664	} else
665		ip_status = host_status;
666
667	key_free(file_key);
668
669	switch (host_status) {
670	case HOST_OK:
671		/* The host is known and the key matches. */
672		debug("Host '%.200s' is known and matches the %s host key.",
673		    host, type);
674		debug("Found key in %s:%d", host_file, host_line);
675		if (options.check_host_ip && ip_status == HOST_NEW) {
676			if (readonly)
677				logit("%s host key for IP address "
678				    "'%.128s' not in list of known hosts.",
679				    type, ip);
680			else if (!add_host_to_hostfile(user_hostfile, ip,
681			    host_key, options.hash_known_hosts))
682				logit("Failed to add the %s host key for IP "
683				    "address '%.128s' to the list of known "
684				    "hosts (%.30s).", type, ip, user_hostfile);
685			else
686				logit("Warning: Permanently added the %s host "
687				    "key for IP address '%.128s' to the list "
688				    "of known hosts.", type, ip);
689		}
690		break;
691	case HOST_NEW:
692		if (readonly)
693			goto fail;
694		/* The host is new. */
695		if (options.strict_host_key_checking == 1) {
696			/*
697			 * User has requested strict host key checking.  We
698			 * will not add the host key automatically.  The only
699			 * alternative left is to abort.
700			 */
701			error("No %s host key is known for %.200s and you "
702			    "have requested strict checking.", type, host);
703			goto fail;
704		} else if (options.strict_host_key_checking == 2) {
705			char msg1[1024], msg2[1024];
706
707			if (show_other_keys(host, host_key))
708				snprintf(msg1, sizeof(msg1),
709				   "\nbut keys of different type are already"
710				   " known for this host.");
711			else
712				snprintf(msg1, sizeof(msg1), ".");
713			/* The default */
714			fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
715			msg2[0] = '\0';
716			if (options.verify_host_key_dns) {
717				if (matching_host_key_dns)
718					snprintf(msg2, sizeof(msg2),
719					    "Matching host key fingerprint"
720					    " found in DNS.\n");
721				else
722					snprintf(msg2, sizeof(msg2),
723					    "No matching host key fingerprint"
724					    " found in DNS.\n");
725			}
726			snprintf(msg, sizeof(msg),
727			    "The authenticity of host '%.200s (%s)' can't be "
728			    "established%s\n"
729			    "%s key fingerprint is %s.\n%s"
730			    "Are you sure you want to continue connecting "
731			    "(yes/no)? ",
732			    host, ip, msg1, type, fp, msg2);
733			xfree(fp);
734			if (!confirm(msg))
735				goto fail;
736		}
737		/*
738		 * If not in strict mode, add the key automatically to the
739		 * local known_hosts file.
740		 */
741		if (options.check_host_ip && ip_status == HOST_NEW) {
742			snprintf(hostline, sizeof(hostline), "%s,%s",
743			    host, ip);
744			hostp = hostline;
745			if (options.hash_known_hosts) {
746				/* Add hash of host and IP separately */
747				r = add_host_to_hostfile(user_hostfile, host,
748				    host_key, options.hash_known_hosts) &&
749				    add_host_to_hostfile(user_hostfile, ip,
750				    host_key, options.hash_known_hosts);
751			} else {
752				/* Add unhashed "host,ip" */
753				r = add_host_to_hostfile(user_hostfile,
754				    hostline, host_key,
755				    options.hash_known_hosts);
756			}
757		} else {
758			r = add_host_to_hostfile(user_hostfile, host, host_key,
759			    options.hash_known_hosts);
760			hostp = host;
761		}
762
763		if (!r)
764			logit("Failed to add the host to the list of known "
765			    "hosts (%.500s).", user_hostfile);
766		else
767			logit("Warning: Permanently added '%.200s' (%s) to the "
768			    "list of known hosts.", hostp, type);
769		break;
770	case HOST_CHANGED:
771		if (options.check_host_ip && host_ip_differ) {
772			char *key_msg;
773			if (ip_status == HOST_NEW)
774				key_msg = "is unknown";
775			else if (ip_status == HOST_OK)
776				key_msg = "is unchanged";
777			else
778				key_msg = "has a different value";
779			error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
780			error("@       WARNING: POSSIBLE DNS SPOOFING DETECTED!          @");
781			error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
782			error("The %s host key for %s has changed,", type, host);
783			error("and the key for the according IP address %s", ip);
784			error("%s. This could either mean that", key_msg);
785			error("DNS SPOOFING is happening or the IP address for the host");
786			error("and its host key have changed at the same time.");
787			if (ip_status != HOST_NEW)
788				error("Offending key for IP in %s:%d", ip_file, ip_line);
789		}
790		/* The host key has changed. */
791		warn_changed_key(host_key);
792		error("Add correct host key in %.100s to get rid of this message.",
793		    user_hostfile);
794		error("Offending key in %s:%d", host_file, host_line);
795
796		/*
797		 * If strict host key checking is in use, the user will have
798		 * to edit the key manually and we can only abort.
799		 */
800		if (options.strict_host_key_checking) {
801			error("%s host key for %.200s has changed and you have "
802			    "requested strict checking.", type, host);
803			goto fail;
804		}
805
806		/*
807		 * If strict host key checking has not been requested, allow
808		 * the connection but without MITM-able authentication or
809		 * agent forwarding.
810		 */
811		if (options.password_authentication) {
812			error("Password authentication is disabled to avoid "
813			    "man-in-the-middle attacks.");
814			options.password_authentication = 0;
815		}
816		if (options.kbd_interactive_authentication) {
817			error("Keyboard-interactive authentication is disabled"
818			    " to avoid man-in-the-middle attacks.");
819			options.kbd_interactive_authentication = 0;
820			options.challenge_response_authentication = 0;
821		}
822		if (options.challenge_response_authentication) {
823			error("Challenge/response authentication is disabled"
824			    " to avoid man-in-the-middle attacks.");
825			options.challenge_response_authentication = 0;
826		}
827		if (options.forward_agent) {
828			error("Agent forwarding is disabled to avoid "
829			    "man-in-the-middle attacks.");
830			options.forward_agent = 0;
831		}
832		if (options.forward_x11) {
833			error("X11 forwarding is disabled to avoid "
834			    "man-in-the-middle attacks.");
835			options.forward_x11 = 0;
836		}
837		if (options.num_local_forwards > 0 ||
838		    options.num_remote_forwards > 0) {
839			error("Port forwarding is disabled to avoid "
840			    "man-in-the-middle attacks.");
841			options.num_local_forwards =
842			    options.num_remote_forwards = 0;
843		}
844		/*
845		 * XXX Should permit the user to change to use the new id.
846		 * This could be done by converting the host key to an
847		 * identifying sentence, tell that the host identifies itself
848		 * by that sentence, and ask the user if he/she whishes to
849		 * accept the authentication.
850		 */
851		break;
852	case HOST_FOUND:
853		fatal("internal error");
854		break;
855	}
856
857	if (options.check_host_ip && host_status != HOST_CHANGED &&
858	    ip_status == HOST_CHANGED) {
859		snprintf(msg, sizeof(msg),
860		    "Warning: the %s host key for '%.200s' "
861		    "differs from the key for the IP address '%.128s'"
862		    "\nOffending key for IP in %s:%d",
863		    type, host, ip, ip_file, ip_line);
864		if (host_status == HOST_OK) {
865			len = strlen(msg);
866			snprintf(msg + len, sizeof(msg) - len,
867			    "\nMatching host key in %s:%d",
868			    host_file, host_line);
869		}
870		if (options.strict_host_key_checking == 1) {
871			logit("%s", msg);
872			error("Exiting, you have requested strict checking.");
873			goto fail;
874		} else if (options.strict_host_key_checking == 2) {
875			strlcat(msg, "\nAre you sure you want "
876			    "to continue connecting (yes/no)? ", sizeof(msg));
877			if (!confirm(msg))
878				goto fail;
879		} else {
880			logit("%s", msg);
881		}
882	}
883
884	xfree(ip);
885	return 0;
886
887fail:
888	xfree(ip);
889	return -1;
890}
891
892/* returns 0 if key verifies or -1 if key does NOT verify */
893int
894verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
895{
896	struct stat st;
897	int flags = 0;
898
899	if (options.verify_host_key_dns &&
900	    verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) {
901
902		if (flags & DNS_VERIFY_FOUND) {
903
904			if (options.verify_host_key_dns == 1 &&
905			    flags & DNS_VERIFY_MATCH &&
906			    flags & DNS_VERIFY_SECURE)
907				return 0;
908
909			if (flags & DNS_VERIFY_MATCH) {
910				matching_host_key_dns = 1;
911			} else {
912				warn_changed_key(host_key);
913				error("Update the SSHFP RR in DNS with the new "
914				    "host key to get rid of this message.");
915			}
916		}
917	}
918
919	/* return ok if the key can be found in an old keyfile */
920	if (stat(options.system_hostfile2, &st) == 0 ||
921	    stat(options.user_hostfile2, &st) == 0) {
922		if (check_host_key(host, hostaddr, host_key, /*readonly*/ 1,
923		    options.user_hostfile2, options.system_hostfile2) == 0)
924			return 0;
925	}
926	return check_host_key(host, hostaddr, host_key, /*readonly*/ 0,
927	    options.user_hostfile, options.system_hostfile);
928}
929
930/*
931 * Starts a dialog with the server, and authenticates the current user on the
932 * server.  This does not need any extra privileges.  The basic connection
933 * to the server must already have been established before this is called.
934 * If login fails, this function prints an error and never returns.
935 * This function does not require super-user privileges.
936 */
937void
938ssh_login(Sensitive *sensitive, const char *orighost,
939    struct sockaddr *hostaddr, struct passwd *pw)
940{
941	char *host, *cp;
942	char *server_user, *local_user;
943
944	local_user = xstrdup(pw->pw_name);
945	server_user = options.user ? options.user : local_user;
946
947	/* Convert the user-supplied hostname into all lowercase. */
948	host = xstrdup(orighost);
949	for (cp = host; *cp; cp++)
950		if (isupper(*cp))
951			*cp = tolower(*cp);
952
953	/* Exchange protocol version identification strings with the server. */
954	ssh_exchange_identification();
955
956	/* Put the connection into non-blocking mode. */
957	packet_set_nonblocking();
958
959	/* key exchange */
960	/* authenticate user */
961	if (compat20) {
962		ssh_kex2(host, hostaddr);
963		ssh_userauth2(local_user, server_user, host, sensitive);
964	} else {
965		ssh_kex(host, hostaddr);
966		ssh_userauth1(local_user, server_user, host, sensitive);
967	}
968}
969
970void
971ssh_put_password(char *password)
972{
973	int size;
974	char *padded;
975
976	if (datafellows & SSH_BUG_PASSWORDPAD) {
977		packet_put_cstring(password);
978		return;
979	}
980	size = roundup(strlen(password) + 1, 32);
981	padded = xmalloc(size);
982	memset(padded, 0, size);
983	strlcpy(padded, password, size);
984	packet_put_string(padded, size);
985	memset(padded, 0, size);
986	xfree(padded);
987}
988
989static int
990show_key_from_file(const char *file, const char *host, int keytype)
991{
992	Key *found;
993	char *fp;
994	int line, ret;
995
996	found = key_new(keytype);
997	if ((ret = lookup_key_in_hostfile_by_type(file, host,
998	    keytype, found, &line))) {
999		fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
1000		logit("WARNING: %s key found for host %s\n"
1001		    "in %s:%d\n"
1002		    "%s key fingerprint %s.",
1003		    key_type(found), host, file, line,
1004		    key_type(found), fp);
1005		xfree(fp);
1006	}
1007	key_free(found);
1008	return (ret);
1009}
1010
1011/* print all known host keys for a given host, but skip keys of given type */
1012static int
1013show_other_keys(const char *host, Key *key)
1014{
1015	int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, -1};
1016	int i, found = 0;
1017
1018	for (i = 0; type[i] != -1; i++) {
1019		if (type[i] == key->type)
1020			continue;
1021		if (type[i] != KEY_RSA1 &&
1022		    show_key_from_file(options.user_hostfile2, host, type[i])) {
1023			found = 1;
1024			continue;
1025		}
1026		if (type[i] != KEY_RSA1 &&
1027		    show_key_from_file(options.system_hostfile2, host, type[i])) {
1028			found = 1;
1029			continue;
1030		}
1031		if (show_key_from_file(options.user_hostfile, host, type[i])) {
1032			found = 1;
1033			continue;
1034		}
1035		if (show_key_from_file(options.system_hostfile, host, type[i])) {
1036			found = 1;
1037			continue;
1038		}
1039		debug2("no key of type %d for host %s", type[i], host);
1040	}
1041	return (found);
1042}
1043
1044static void
1045warn_changed_key(Key *host_key)
1046{
1047	char *fp;
1048	const char *type = key_type(host_key);
1049
1050	fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
1051
1052	error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1053	error("@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @");
1054	error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1055	error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
1056	error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
1057	error("It is also possible that the %s host key has just been changed.", type);
1058	error("The fingerprint for the %s key sent by the remote host is\n%s.",
1059	    type, fp);
1060	error("Please contact your system administrator.");
1061
1062	xfree(fp);
1063}
1064