xref: /onnv-gate/usr/src/cmd/ssh/ssh/sshconnect.c (revision 9976:a945dec9643d)
1 /*
2  * Author: Tatu Ylonen <ylo@cs.hut.fi>
3  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4  *                    All rights reserved
5  * Code to connect to a remote host, and to perform the client side of the
6  * login (authentication) dialog.
7  *
8  * As far as I am concerned, the code I have written for this software
9  * can be used freely for any purpose.  Any derived versions of this
10  * software must be clearly marked as such, and if the derived work is
11  * incompatible with the protocol description in the RFC file, it must be
12  * called by a name other than "ssh" or "Secure Shell".
13  */
14 /*
15  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
16  * Use is subject to license terms.
17  */
18 
19 #include "includes.h"
20 RCSID("$OpenBSD: sshconnect.c,v 1.135 2002/09/19 01:58:18 djm Exp $");
21 
22 #include <openssl/bn.h>
23 
24 #include "ssh.h"
25 #include "xmalloc.h"
26 #include "rsa.h"
27 #include "buffer.h"
28 #include "packet.h"
29 #include "uidswap.h"
30 #include "compat.h"
31 #include "key.h"
32 #include "sshconnect.h"
33 #include "hostfile.h"
34 #include "log.h"
35 #include "readconf.h"
36 #include "atomicio.h"
37 #include "misc.h"
38 #include "readpass.h"
39 #include <langinfo.h>
40 #include "engine.h"
41 
42 char *client_version_string = NULL;
43 char *server_version_string = NULL;
44 
45 /* import */
46 extern Options options;
47 extern char *__progname;
48 extern uid_t original_real_uid;
49 extern uid_t original_effective_uid;
50 extern pid_t proxy_command_pid;
51 extern ENGINE *e;
52 
53 #ifndef INET6_ADDRSTRLEN		/* for non IPv6 machines */
54 #define INET6_ADDRSTRLEN 46
55 #endif
56 
57 static int show_other_keys(const char *, Key *);
58 
59 /*
60  * Connect to the given ssh server using a proxy command.
61  */
62 static int
ssh_proxy_connect(const char * host,u_short port,const char * proxy_command)63 ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
64 {
65 	Buffer command;
66 	const char *cp;
67 	char *command_string;
68 	int pin[2], pout[2];
69 	pid_t pid;
70 	char strport[NI_MAXSERV];
71 
72 	/* Convert the port number into a string. */
73 	snprintf(strport, sizeof strport, "%hu", port);
74 
75 	/*
76 	 * Build the final command string in the buffer by making the
77 	 * appropriate substitutions to the given proxy command.
78 	 *
79 	 * Use "exec" to avoid "sh -c" processes on some platforms
80 	 * (e.g. Solaris)
81 	 */
82 	buffer_init(&command);
83 
84 #define EXECLEN (sizeof ("exec") - 1)
85 	for (cp = proxy_command; *cp && isspace(*cp) ; cp++)
86 		;
87 	if (strncmp(cp, "exec", EXECLEN) != 0 ||
88 	    (strlen(cp) >= EXECLEN && !isspace(*(cp + EXECLEN))))
89 		buffer_append(&command, "exec ", EXECLEN + 1);
90 #undef EXECLEN
91 
92 	for (cp = proxy_command; *cp; cp++) {
93 		if (cp[0] == '%' && cp[1] == '%') {
94 			buffer_append(&command, "%", 1);
95 			cp++;
96 			continue;
97 		}
98 		if (cp[0] == '%' && cp[1] == 'h') {
99 			buffer_append(&command, host, strlen(host));
100 			cp++;
101 			continue;
102 		}
103 		if (cp[0] == '%' && cp[1] == 'p') {
104 			buffer_append(&command, strport, strlen(strport));
105 			cp++;
106 			continue;
107 		}
108 		buffer_append(&command, cp, 1);
109 	}
110 	buffer_append(&command, "\0", 1);
111 
112 	/* Get the final command string. */
113 	command_string = buffer_ptr(&command);
114 
115 	/* Create pipes for communicating with the proxy. */
116 	if (pipe(pin) < 0 || pipe(pout) < 0)
117 		fatal("Could not create pipes to communicate with the proxy: %.100s",
118 		    strerror(errno));
119 
120 	debug("Executing proxy command: %.500s", command_string);
121 
122 	/* Fork and execute the proxy command. */
123 	if ((pid = fork()) == 0) {
124 		char *argv[10];
125 
126 		/* Child.  Permanently give up superuser privileges. */
127 		seteuid(original_real_uid);
128 		setuid(original_real_uid);
129 
130 		/* Redirect stdin and stdout. */
131 		close(pin[1]);
132 		if (pin[0] != 0) {
133 			if (dup2(pin[0], 0) < 0)
134 				perror("dup2 stdin");
135 			close(pin[0]);
136 		}
137 		close(pout[0]);
138 		if (dup2(pout[1], 1) < 0)
139 			perror("dup2 stdout");
140 		/* Cannot be 1 because pin allocated two descriptors. */
141 		close(pout[1]);
142 
143 		/* Stderr is left as it is so that error messages get
144 		   printed on the user's terminal. */
145 		argv[0] = _PATH_BSHELL;
146 		argv[1] = "-c";
147 		argv[2] = command_string;
148 		argv[3] = NULL;
149 
150 		/* Execute the proxy command.  Note that we gave up any
151 		   extra privileges above. */
152 		execv(argv[0], argv);
153 		perror(argv[0]);
154 		exit(1);
155 	}
156 	/* Parent. */
157 	if (pid < 0)
158 		fatal("fork failed: %.100s", strerror(errno));
159 	else
160 		proxy_command_pid = pid; /* save pid to clean up later */
161 
162 	/* Close child side of the descriptors. */
163 	close(pin[0]);
164 	close(pout[1]);
165 
166 	/* Free the command name. */
167 	buffer_free(&command);
168 
169 	/* Set the connection file descriptors. */
170 	packet_set_connection(pout[0], pin[1]);
171 
172 	/* Indicate OK return */
173 	return 0;
174 }
175 
176 /*
177  * Creates a (possibly privileged) socket for use as the ssh connection.
178  */
179 static int
ssh_create_socket(int privileged,int family)180 ssh_create_socket(int privileged, int family)
181 {
182 	int sock, gaierr;
183 	struct addrinfo hints, *res;
184 
185 	/*
186 	 * If we are running as root and want to connect to a privileged
187 	 * port, bind our own socket to a privileged port.
188 	 */
189 	if (privileged) {
190 		int p = IPPORT_RESERVED - 1;
191 		PRIV_START;
192 		sock = rresvport_af(&p, family);
193 		PRIV_END;
194 		if (sock < 0)
195 			error("rresvport: af=%d %.100s", family, strerror(errno));
196 		else
197 			debug("Allocated local port %d.", p);
198 		return sock;
199 	}
200 	sock = socket(family, SOCK_STREAM, 0);
201 	if (sock < 0)
202 		error("socket: %.100s", strerror(errno));
203 
204 	/* Bind the socket to an alternative local IP address */
205 	if (options.bind_address == NULL)
206 		return sock;
207 
208 	memset(&hints, 0, sizeof(hints));
209 	hints.ai_family = family;
210 	hints.ai_socktype = SOCK_STREAM;
211 	hints.ai_flags = AI_PASSIVE;
212 	gaierr = getaddrinfo(options.bind_address, "0", &hints, &res);
213 	if (gaierr) {
214 		error("getaddrinfo: %s: %s", options.bind_address,
215 		    gai_strerror(gaierr));
216 		close(sock);
217 		return -1;
218 	}
219 	if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
220 		error("bind: %s: %s", options.bind_address, strerror(errno));
221 		close(sock);
222 		freeaddrinfo(res);
223 		return -1;
224 	}
225 	freeaddrinfo(res);
226 	return sock;
227 }
228 
229 /*
230  * Connect with timeout. Implements ConnectTimeout option.
231  */
232 static int
timeout_connect(int sockfd,const struct sockaddr * serv_addr,socklen_t addrlen,int timeout)233 timeout_connect(int sockfd, const struct sockaddr *serv_addr,
234     socklen_t addrlen, int timeout)
235 {
236 	fd_set *fdset;
237 	struct timeval tv;
238 	socklen_t optlen;
239 	int optval, rc, result = -1;
240 
241 	if (timeout <= 0)
242 		return (connect(sockfd, serv_addr, addrlen));
243 
244 	set_nonblock(sockfd);
245 	rc = connect(sockfd, serv_addr, addrlen);
246 	if (rc == 0) {
247 		unset_nonblock(sockfd);
248 		return (0);
249 	}
250 	if (errno != EINPROGRESS)
251 		return (-1);
252 
253 	fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS),
254 	    sizeof(fd_mask));
255 	FD_SET(sockfd, fdset);
256 	tv.tv_sec = timeout;
257 	tv.tv_usec = 0;
258 
259 	for (;;) {
260 		rc = select(sockfd + 1, NULL, fdset, NULL, &tv);
261 		if (rc != -1 || errno != EINTR)
262 			break;
263 	}
264 
265 	switch (rc) {
266 	case 0:
267 		/* Timed out */
268 		errno = ETIMEDOUT;
269 		break;
270 	case -1:
271 		/* Select error */
272 		debug("select: %s", strerror(errno));
273 		break;
274 	case 1:
275 		/* Completed or failed */
276 		optval = 0;
277 		optlen = sizeof(optval);
278 		if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval,
279 		    &optlen) == -1) {
280 			debug("getsockopt: %s", strerror(errno));
281 			break;
282 		}
283 		if (optval != 0) {
284 			errno = optval;
285 			break;
286 		}
287 		result = 0;
288 		unset_nonblock(sockfd);
289 		break;
290 	default:
291 		/* Should not occur */
292 		fatal("Bogus return (%d) from select()", rc);
293 	}
294 
295 	xfree(fdset);
296 	return (result);
297 }
298 
299 /*
300  * Opens a TCP/IP connection to the remote server on the given host.
301  * The address of the remote host will be returned in hostaddr.
302  * If port is 0, the default port will be used.  If needpriv is true,
303  * a privileged port will be allocated to make the connection.
304  * This requires super-user privileges if needpriv is true.
305  * Connection_attempts specifies the maximum number of tries (one per
306  * second).  If proxy_command is non-NULL, it specifies the command (with %h
307  * and %p substituted for host and port, respectively) to use to contact
308  * the daemon.
309  * Return values:
310  *    0 for OK
311  *    ECONNREFUSED if we got a "Connection Refused" by the peer on any address
312  *    ECONNABORTED if we failed without a "Connection refused"
313  * Suitable error messages for the connection failure will already have been
314  * printed.
315  */
316 int
ssh_connect(const char * host,struct sockaddr_storage * hostaddr,ushort_t port,int family,int connection_attempts,int needpriv,const char * proxy_command)317 ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
318     ushort_t port, int family, int connection_attempts,
319     int needpriv, const char *proxy_command)
320 {
321 	int gaierr;
322 	int on = 1;
323 	int sock = -1, attempt;
324 	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
325 	struct addrinfo hints, *ai, *aitop;
326 	struct servent *sp;
327 	/*
328 	 * Did we get only other errors than "Connection refused" (which
329 	 * should block fallback to rsh and similar), or did we get at least
330 	 * one "Connection refused"?
331 	 */
332 	int full_failure = 1;
333 
334 	debug("ssh_connect: needpriv %d", needpriv);
335 
336 	/* Get default port if port has not been set. */
337 	if (port == 0) {
338 		sp = getservbyname(SSH_SERVICE_NAME, "tcp");
339 		if (sp)
340 			port = ntohs(sp->s_port);
341 		else
342 			port = SSH_DEFAULT_PORT;
343 	}
344 	/* If a proxy command is given, connect using it. */
345 	if (proxy_command != NULL)
346 		return ssh_proxy_connect(host, port, proxy_command);
347 
348 	/* No proxy command. */
349 
350 	memset(&hints, 0, sizeof(hints));
351 	hints.ai_family = family;
352 	hints.ai_socktype = SOCK_STREAM;
353 	snprintf(strport, sizeof strport, "%u", port);
354 	if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
355 		fatal("%s: %.100s: %s", __progname, host,
356 		    gai_strerror(gaierr));
357 
358 	/*
359 	 * Try to connect several times.  On some machines, the first time
360 	 * will sometimes fail.  In general socket code appears to behave
361 	 * quite magically on many machines.
362 		 */
363 	for (attempt = 0; ;) {
364 		if (attempt > 0)
365 			debug("Trying again...");
366 
367 		/* Loop through addresses for this host, and try each one in
368 		   sequence until the connection succeeds. */
369 		for (ai = aitop; ai; ai = ai->ai_next) {
370 			if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
371 				continue;
372 			if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
373 			    ntop, sizeof(ntop), strport, sizeof(strport),
374 			    NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
375 				error("ssh_connect: getnameinfo failed");
376 				continue;
377 			}
378 			debug("Connecting to %.200s [%.100s] port %s.",
379 				host, ntop, strport);
380 
381 			/* Create a socket for connecting. */
382 			sock = ssh_create_socket(needpriv, ai->ai_family);
383 			if (sock < 0)
384 				/* Any error is already output */
385 				continue;
386 
387 			if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen,
388 			    options.connection_timeout) >= 0) {
389 				/* Successful connection. */
390 				memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
391 				break;
392 			} else {
393 				if (errno == ECONNREFUSED)
394 					full_failure = 0;
395 				debug("connect to address %s port %s: %s",
396 				    ntop, strport, strerror(errno));
397 				/*
398 				 * Close the failed socket; there appear to
399 				 * be some problems when reusing a socket for
400 				 * which connect() has already returned an
401 				 * error.
402 				 */
403 				close(sock);
404 			}
405 		}
406 		if (ai)
407 			break;	/* Successful connection. */
408 
409 		attempt++;
410 		if (attempt >= connection_attempts)
411 			break;
412 		/* Sleep a moment before retrying. */
413 		sleep(1);
414 	}
415 
416 	freeaddrinfo(aitop);
417 
418 	/* Return failure if we didn't get a successful connection. */
419 	if (attempt >= connection_attempts) {
420 		log("ssh: connect to host %s port %s: %s",
421 		    host, strport, strerror(errno));
422 		return full_failure ? ECONNABORTED : ECONNREFUSED;
423 	}
424 
425 	debug("Connection established.");
426 
427 	/* Set keepalives if requested. */
428 	if (options.keepalives &&
429 	    setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
430 	    sizeof(on)) < 0)
431 		debug2("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
432 
433 	/* Set the connection. */
434 	packet_set_connection(sock, sock);
435 
436 	return 0;
437 }
438 
439 /*
440  * Waits for the server identification string, and sends our own
441  * identification string.
442  */
443 static void
ssh_exchange_identification(void)444 ssh_exchange_identification(void)
445 {
446 	char buf[256], remote_version[256];	/* must be same size! */
447 	int remote_major, remote_minor, i, mismatch;
448 	int connection_in = packet_get_connection_in();
449 	int connection_out = packet_get_connection_out();
450 	int minor1 = PROTOCOL_MINOR_1;
451 
452 	/* Read other side\'s version identification. */
453 	for (;;) {
454 		for (i = 0; i < sizeof(buf) - 1; i++) {
455 			int len = atomicio(read, connection_in, &buf[i], 1);
456 			if (len < 0)
457 				fatal("ssh_exchange_identification: read: %.100s", strerror(errno));
458 			if (len != 1)
459 				fatal("ssh_exchange_identification: Connection closed by remote host");
460 			if (buf[i] == '\r') {
461 				buf[i] = '\n';
462 				buf[i + 1] = 0;
463 				continue;		/**XXX wait for \n */
464 			}
465 			if (buf[i] == '\n') {
466 				buf[i + 1] = 0;
467 				break;
468 			}
469 		}
470 		buf[sizeof(buf) - 1] = 0;
471 		if (strncmp(buf, "SSH-", 4) == 0)
472 			break;
473 		debug("ssh_exchange_identification: %s", buf);
474 	}
475 	server_version_string = xstrdup(buf);
476 
477 	/*
478 	 * Check that the versions match.  In future this might accept
479 	 * several versions and set appropriate flags to handle them.
480 	 */
481 	if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n",
482 	    &remote_major, &remote_minor, remote_version) != 3)
483 		fatal("Bad remote protocol version identification: '%.100s'", buf);
484 	debug("Remote protocol version %d.%d, remote software version %.100s",
485 	    remote_major, remote_minor, remote_version);
486 
487 	compat_datafellows(remote_version);
488 	mismatch = 0;
489 
490 	switch (remote_major) {
491 	case 1:
492 		if (remote_minor == 99 &&
493 		    (options.protocol & SSH_PROTO_2) &&
494 		    !(options.protocol & SSH_PROTO_1_PREFERRED)) {
495 			enable_compat20();
496 			break;
497 		}
498 		if (!(options.protocol & SSH_PROTO_1)) {
499 			mismatch = 1;
500 			break;
501 		}
502 		if (remote_minor < 3) {
503 			fatal("Remote machine has too old SSH software version.");
504 		} else if (remote_minor == 3 || remote_minor == 4) {
505 			/* We speak 1.3, too. */
506 			enable_compat13();
507 			minor1 = 3;
508 			if (options.forward_agent) {
509 				log("Agent forwarding disabled for protocol 1.3");
510 				options.forward_agent = 0;
511 			}
512 		}
513 		break;
514 	case 2:
515 		if (options.protocol & SSH_PROTO_2) {
516 			enable_compat20();
517 			break;
518 		}
519 		/* FALLTHROUGH */
520 	default:
521 		mismatch = 1;
522 		break;
523 	}
524 	if (mismatch)
525 		fatal("Protocol major versions differ: %d vs. %d",
526 		    (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
527 		    remote_major);
528 	/* Send our own protocol version identification. */
529 	snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
530 	    compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
531 	    compat20 ? PROTOCOL_MINOR_2 : minor1,
532 	    SSH_VERSION);
533 	if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf))
534 		fatal("write: %.100s", strerror(errno));
535 	client_version_string = xstrdup(buf);
536 	chop(client_version_string);
537 	chop(server_version_string);
538 	debug("Local version string %.100s", client_version_string);
539 }
540 
541 /* defaults to 'no' */
542 static int
confirm(const char * prompt)543 confirm(const char *prompt)
544 {
545 	const char *msg;
546 	char *p, *again = NULL;
547 	int n, ret = -1;
548 
549 	if (options.batch_mode)
550 		return 0;
551 	n = snprintf(NULL, 0, gettext("Please type '%s' or '%s': "),
552 		nl_langinfo(YESSTR), nl_langinfo(NOSTR));
553 	again = xmalloc(n + 1);
554 	(void) snprintf(again, n + 1, gettext("Please type '%s' or '%s': "),
555 		    nl_langinfo(YESSTR), nl_langinfo(NOSTR));
556 
557 	for (msg = prompt;;msg = again) {
558 		p = read_passphrase(msg, RP_ECHO);
559 		if (p == NULL ||
560 		    (p[0] == '\0') || (p[0] == '\n') ||
561 		    strcasecmp(p, nl_langinfo(NOSTR)) == 0)
562 			ret = 0;
563 		if (p && strcasecmp(p, nl_langinfo(YESSTR)) == 0)
564 			ret = 1;
565 		if (p)
566 			xfree(p);
567 		if (ret != -1)
568 			return ret;
569 	}
570 }
571 
572 /*
573  * check whether the supplied host key is valid, return -1 if the key
574  * is not valid. the user_hostfile will not be updated if 'readonly' is true.
575  */
576 static int
check_host_key(char * host,struct sockaddr * hostaddr,Key * host_key,int validated,int readonly,const char * user_hostfile,const char * system_hostfile)577 check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, int
578 	validated, int readonly, const char *user_hostfile, const char
579 	*system_hostfile)
580 {
581 	Key *file_key;
582 	char *type = key_type(host_key);
583 	char *ip = NULL;
584 	char hostline[1000], *hostp, *fp;
585 	HostStatus host_status;
586 	HostStatus ip_status;
587 	int r, local = 0, host_ip_differ = 0;
588 	int salen;
589 	char ntop[NI_MAXHOST];
590 	char msg[1024];
591 	int len, host_line, ip_line, has_keys;
592 	const char *host_file = NULL, *ip_file = NULL;
593 
594 	/*
595 	 * Force accepting of the host key for loopback/localhost. The
596 	 * problem is that if the home directory is NFS-mounted to multiple
597 	 * machines, localhost will refer to a different machine in each of
598 	 * them, and the user will get bogus HOST_CHANGED warnings.  This
599 	 * essentially disables host authentication for localhost; however,
600 	 * this is probably not a real problem.
601 	 */
602 	/**  hostaddr == 0! */
603 	switch (hostaddr->sa_family) {
604 	case AF_INET:
605 		/* LINTED */
606 		local = (ntohl(((struct sockaddr_in *)hostaddr)->
607 		   sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
608 		salen = sizeof(struct sockaddr_in);
609 		break;
610 	case AF_INET6:
611 		/* LINTED */
612 		local = IN6_IS_ADDR_LOOPBACK(
613 		    &(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
614 		salen = sizeof(struct sockaddr_in6);
615 		break;
616 	default:
617 		local = 0;
618 		salen = sizeof(struct sockaddr_storage);
619 		break;
620 	}
621 	if (options.no_host_authentication_for_localhost == 1 && local &&
622 	    options.host_key_alias == NULL) {
623 		debug("Forcing accepting of host key for "
624 		    "loopback/localhost.");
625 		return 0;
626 	}
627 
628 	/*
629 	 * We don't have the remote ip-address for connections
630 	 * using a proxy command
631 	 */
632 	if (options.proxy_command == NULL) {
633 		if (getnameinfo(hostaddr, salen, ntop, sizeof(ntop),
634 		    NULL, 0, NI_NUMERICHOST) != 0)
635 			fatal("check_host_key: getnameinfo failed");
636 		ip = xstrdup(ntop);
637 	} else {
638 		ip = xstrdup("<no hostip for proxy command>");
639 	}
640 	/*
641 	 * Turn off check_host_ip if the connection is to localhost, via proxy
642 	 * command or if we don't have a hostname to compare with
643 	 */
644 	if (options.check_host_ip &&
645 	    (local || strcmp(host, ip) == 0 || options.proxy_command != NULL))
646 		options.check_host_ip = 0;
647 
648 	/*
649 	 * Allow the user to record the key under a different name. This is
650 	 * useful for ssh tunneling over forwarded connections or if you run
651 	 * multiple sshd's on different ports on the same machine.
652 	 */
653 	if (options.host_key_alias != NULL) {
654 		host = options.host_key_alias;
655 		debug("using hostkeyalias: %s", host);
656 	}
657 
658 	/*
659 	 * Store the host key from the known host file in here so that we can
660 	 * compare it with the key for the IP address.
661 	 */
662 	file_key = key_new(host_key->type);
663 
664 	/*
665 	 * Check if the host key is present in the user's list of known
666 	 * hosts or in the systemwide list.
667 	 */
668 	host_file = user_hostfile;
669 	host_status = check_host_in_hostfile(host_file, host, host_key,
670 	    file_key, &host_line);
671 	if (host_status == HOST_NEW) {
672 		host_file = system_hostfile;
673 		host_status = check_host_in_hostfile(host_file, host, host_key,
674 		    file_key, &host_line);
675 	}
676 	/*
677 	 * Also perform check for the ip address, skip the check if we are
678 	 * localhost or the hostname was an ip address to begin with
679 	 */
680 	if (options.check_host_ip) {
681 		Key *ip_key = key_new(host_key->type);
682 
683 		ip_file = user_hostfile;
684 		ip_status = check_host_in_hostfile(ip_file, ip, host_key,
685 		    ip_key, &ip_line);
686 		if (ip_status == HOST_NEW) {
687 			ip_file = system_hostfile;
688 			ip_status = check_host_in_hostfile(ip_file, ip,
689 			    host_key, ip_key, &ip_line);
690 		}
691 		if (host_status == HOST_CHANGED &&
692 		    (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))
693 			host_ip_differ = 1;
694 
695 		key_free(ip_key);
696 	} else
697 		ip_status = host_status;
698 
699 	key_free(file_key);
700 
701 	switch (host_status) {
702 	case HOST_OK:
703 		/* The host is known and the key matches. */
704 		if (validated)
705 			debug("Host '%.200s' is known and matches the %s host key.",
706 			    host, type);
707 		else
708 			debug("Host '%.200s' is known and matches the %s host "
709 				"key.", host, type);
710 		debug("Found key in %s:%d", host_file, host_line);
711 		if (options.check_host_ip && ip_status == HOST_NEW) {
712 			if (readonly)
713 				log("%s host key for IP address "
714 				    "'%.128s' not in list of known hosts.",
715 				    type, ip);
716 			else if (!add_host_to_hostfile(user_hostfile, ip,
717 			    host_key, options.hash_known_hosts))
718 				log("Failed to add the %s host key for IP "
719 				    "address '%.128s' to the list of known "
720 				    "hosts (%.30s).", type, ip, user_hostfile);
721 			else
722 				log("Warning: Permanently added the %s host "
723 				    "key for IP address '%.128s' to the list "
724 				    "of known hosts.", type, ip);
725 		}
726 		break;
727 	case HOST_NEW:
728 		if (readonly)
729 			goto fail;
730 		/* The host is new. */
731 		if (!validated && options.strict_host_key_checking == 1) {
732 			/*
733 			 * User has requested strict host key checking.  We
734 			 * will not add the host key automatically.  The only
735 			 * alternative left is to abort.
736 			 */
737 			error("No %s host key is known for %.200s and you "
738 			    "have requested strict checking.", type, host);
739 			goto fail;
740 		} else if (!validated &&
741 			    options.strict_host_key_checking == 2) {
742 			has_keys = show_other_keys(host, host_key);
743 			/* The default */
744 			fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
745 			snprintf(msg, sizeof(msg),
746 			    gettext("The authenticity of host '%.200s (%s)' "
747 			    "can't be established%s\n%s key fingerprint "
748 			    "is %s.\n"
749 			    "Are you sure you want to continue connecting "
750 			    "(%s/%s)? "),
751 			     host, ip,
752 			     has_keys ? gettext(",\nbut keys of different type "
753 				    "are already known for this host.") : ".",
754 			     type, fp, nl_langinfo(YESSTR), nl_langinfo(NOSTR));
755 			xfree(fp);
756 			if (!confirm(msg))
757 				goto fail;
758 		}
759 		/*
760 		 * If not in strict mode, add the key automatically to the
761 		 * local known_hosts file.
762 		 */
763 		if (options.check_host_ip && ip_status == HOST_NEW) {
764 			snprintf(hostline, sizeof(hostline), "%s,%s",
765 			    host, ip);
766 			hostp = hostline;
767 			if (options.hash_known_hosts) {
768 				/* Add hash of host and IP separately */
769 				r = add_host_to_hostfile(user_hostfile, host,
770 				    host_key, options.hash_known_hosts) &&
771 				    add_host_to_hostfile(user_hostfile, ip,
772 				    host_key, options.hash_known_hosts);
773 			} else {
774 				/* Add unhashed "host,ip" */
775 				r = add_host_to_hostfile(user_hostfile,
776 				    hostline, host_key,
777 				    options.hash_known_hosts);
778 			}
779 		} else {
780 			r = add_host_to_hostfile(user_hostfile, host, host_key,
781 			    options.hash_known_hosts);
782 			hostp = host;
783 		}
784 
785 		if (!r)
786 			log("Failed to add the host to the list of known "
787 			    "hosts (%.500s).", user_hostfile);
788 		else
789 			log("Warning: Permanently added '%.200s' (%s) to the "
790 			    "list of known hosts.", hostp, type);
791 		break;
792 	case HOST_CHANGED:
793 		if (validated) {
794 			log("Warning: The host key for host %s has changed; "
795 				"please update your known hosts file(s) "
796 				"(%s:%d)", host, host_file, host_line);
797 			if (options.check_host_ip && host_ip_differ) {
798 				log("Warning: The host key for host %s has "
799 					"changed; please update your known "
800 					"hosts file(s) (%s:%d)", ip, host_file,
801 					host_line);
802 
803 			}
804 			break;
805 		}
806 		if (options.check_host_ip && host_ip_differ) {
807 			char *msg;
808 			if (ip_status == HOST_NEW)
809 				msg = "is unknown";
810 			else if (ip_status == HOST_OK)
811 				msg = "is unchanged";
812 			else
813 				msg = "has a different value";
814 			error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"
815 			      "@       WARNING: POSSIBLE DNS SPOOFING DETECTED!          @\n"
816 			      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"
817 			      "The %s host key for %s has changed,\n"
818 			      "and the key for the according IP address %s\n"
819 			      "%s. This could either mean that\n"
820 			      "DNS SPOOFING is happening or the IP address for the host\n"
821 			      "and its host key have changed at the same time.\n",
822 			      type, host, ip, msg);
823 			if (ip_status != HOST_NEW)
824 				error("Offending key for IP in %s:%d", ip_file, ip_line);
825 		}
826 		/* The host key has changed. */
827 		fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
828 		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"
829 		      "@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @\n"
830 		      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"
831 		      "IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!\n"
832 		      "Someone could be eavesdropping on you right now (man-in-the-middle attack)!\n"
833 		      "It is also possible that the %s host key has just been changed.\n"
834 		      "The fingerprint for the %s key sent by the remote host is\n%s.\n"
835 		      "Please contact your system administrator.\n"
836 		      "Add correct host key in %.100s to get rid of this message.\n"
837 		      "Offending key in %s:%d\n",
838 		      type, type, fp, user_hostfile, host_file, host_line);
839 		xfree(fp);
840 
841 		/*
842 		 * If strict host key checking is in use, the user will have
843 		 * to edit the key manually and we can only abort.
844 		 */
845 		if (options.strict_host_key_checking) {
846 			error("%s host key for %.200s has changed and you have "
847 			    "requested strict checking.", type, host);
848 			goto fail;
849 		}
850 
851 		/*
852 		 * If strict host key checking has not been requested, allow
853 		 * the connection but without password authentication or
854 		 * agent forwarding.
855 		 */
856 		if (options.password_authentication) {
857 			error("Password authentication is disabled to avoid "
858 			    "man-in-the-middle attacks.");
859 			options.password_authentication = 0;
860 		}
861 		if (options.forward_agent) {
862 			error("Agent forwarding is disabled to avoid "
863 			    "man-in-the-middle attacks.");
864 			options.forward_agent = 0;
865 		}
866 		if (options.forward_x11) {
867 			error("X11 forwarding is disabled to avoid "
868 			    "man-in-the-middle attacks.");
869 			options.forward_x11 = 0;
870 		}
871 		if (options.num_local_forwards > 0 ||
872 		    options.num_remote_forwards > 0) {
873 			error("Port forwarding is disabled to avoid "
874 			    "man-in-the-middle attacks.");
875 			options.num_local_forwards =
876 			    options.num_remote_forwards = 0;
877 		}
878 		/*
879 		 * XXX Should permit the user to change to use the new id.
880 		 * This could be done by converting the host key to an
881 		 * identifying sentence, tell that the host identifies itself
882 		 * by that sentence, and ask the user if he/she whishes to
883 		 * accept the authentication.
884 		 */
885 		break;
886 	case HOST_FOUND:
887 		fatal("internal error");
888 		break;
889 	}
890 
891 	if (options.check_host_ip && host_status != HOST_CHANGED &&
892 	    ip_status == HOST_CHANGED) {
893 		snprintf(msg, sizeof(msg),
894 		    gettext("Warning: the %s host key for '%.200s' "
895 			    "differs from the key for the IP address '%.128s'"
896 			    "\nOffending key for IP in %s:%d"),
897 		    type, host, ip, ip_file, ip_line);
898 		if (host_status == HOST_OK) {
899 			len = strlen(msg);
900 			snprintf(msg + len, sizeof(msg) - len,
901 			    "\nMatching host key in %s:%d",
902 			    host_file, host_line);
903 		}
904 		if (!validated && options.strict_host_key_checking == 1) {
905 			log(msg);
906 			error("Exiting, you have requested strict checking.");
907 			goto fail;
908 		} else if (!validated &&
909 			    options.strict_host_key_checking == 2) {
910 			snprintf(msg + strlen(msg), sizeof(msg) - strlen(msg),
911 				gettext("\nAre you sure you want to continue "
912 					"connecting (%s/%s)"),
913 				nl_langinfo(YESSTR), nl_langinfo(NOSTR));
914 			if (!confirm(msg))
915 				goto fail;
916 		} else {
917 			log(msg);
918 		}
919 	}
920 
921 	xfree(ip);
922 	return 0;
923 
924 fail:
925 	xfree(ip);
926 	return -1;
927 }
928 
929 int
verify_host_key(char * host,struct sockaddr * hostaddr,Key * host_key)930 verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
931 {
932 	struct stat st;
933 
934 	/* return ok if the key can be found in an old keyfile */
935 	if (stat(options.system_hostfile2, &st) == 0 ||
936 	    stat(options.user_hostfile2, &st) == 0) {
937 		if (check_host_key(host, hostaddr, host_key, 0, /*readonly*/ 1,
938 		    options.user_hostfile2, options.system_hostfile2) == 0)
939 			return 0;
940 	}
941 	return check_host_key(host, hostaddr, host_key, 0, /*readonly*/ 0,
942 	    options.user_hostfile, options.system_hostfile);
943 }
944 
945 int
accept_host_key(char * host,struct sockaddr * hostaddr,Key * host_key)946 accept_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
947 {
948 	struct stat st;
949 
950 	/* return ok if the key can be found in an old keyfile */
951 	if (stat(options.system_hostfile2, &st) == 0 ||
952 	    stat(options.user_hostfile2, &st) == 0) {
953 		if (check_host_key(host, hostaddr, host_key, 1, /*readonly*/ 1,
954 		    options.user_hostfile2, options.system_hostfile2) == 0)
955 			return 0;
956 	}
957 	return check_host_key(host, hostaddr, host_key, 1, /*readonly*/ 0,
958 	    options.user_hostfile, options.system_hostfile);
959 }
960 /*
961  * Starts a dialog with the server, and authenticates the current user on the
962  * server.  This does not need any extra privileges.  The basic connection
963  * to the server must already have been established before this is called.
964  * If login fails, this function prints an error and never returns.
965  * This function does not require super-user privileges.
966  */
967 void
ssh_login(Sensitive * sensitive,const char * orighost,struct sockaddr * hostaddr,char * pw_name)968 ssh_login(Sensitive *sensitive, const char *orighost,
969     struct sockaddr *hostaddr, char *pw_name)
970 {
971 	char *host, *cp;
972 	char *server_user, *local_user;
973 
974 	local_user = xstrdup(pw_name);
975 	server_user = options.user ? options.user : local_user;
976 
977 	/* Convert the user-supplied hostname into all lowercase. */
978 	host = xstrdup(orighost);
979 	for (cp = host; *cp; cp++)
980 		if (isupper(*cp))
981 			*cp = tolower(*cp);
982 
983 	/* Exchange protocol version identification strings with the server. */
984 	ssh_exchange_identification();
985 
986 	/*
987 	 * See comment at definition of will_daemonize for information why we
988 	 * don't support the PKCS#11 engine with protocol 1.
989 	 */
990 	if (compat20 == 1 && options.use_openssl_engine == 1) {
991 		/*
992 		 * If this fails then 'e' will be NULL which means we do not use
993 		 * the engine, as if UseOpenSSLEngine was set to "no". This is
994 		 * important in case we go to the background after the
995 		 * authentication.
996 		 */
997 		e = pkcs11_engine_load(options.use_openssl_engine);
998 	}
999 
1000 	/* Put the connection into non-blocking mode. */
1001 	packet_set_nonblocking();
1002 
1003 	/* key exchange */
1004 	/* authenticate user */
1005 	if (compat20) {
1006 		/*
1007 		 * Note that the host pointer is saved in ssh_kex2() for later
1008 		 * use during the key re-exchanges so we must not xfree() it.
1009 		 */
1010 		ssh_kex2(host, hostaddr);
1011 		ssh_userauth2(local_user, server_user, host, sensitive);
1012 	} else {
1013 		ssh_kex(host, hostaddr);
1014 		ssh_userauth1(local_user, server_user, host, sensitive);
1015 	}
1016 
1017 	xfree(local_user);
1018 }
1019 
1020 void
ssh_put_password(char * password)1021 ssh_put_password(char *password)
1022 {
1023 	int size;
1024 	char *padded;
1025 
1026 	if (datafellows & SSH_BUG_PASSWORDPAD) {
1027 		packet_put_cstring(password);
1028 		return;
1029 	}
1030 	size = roundup(strlen(password) + 1, 32);
1031 	padded = xmalloc(size);
1032 	memset(padded, 0, size);
1033 	strlcpy(padded, password, size);
1034 	packet_put_string(padded, size);
1035 	memset(padded, 0, size);
1036 	xfree(padded);
1037 }
1038 
1039 static int
show_key_from_file(const char * file,const char * host,int keytype)1040 show_key_from_file(const char *file, const char *host, int keytype)
1041 {
1042 	Key *found;
1043 	char *fp;
1044 	int line, ret;
1045 
1046 	found = key_new(keytype);
1047 	if ((ret = lookup_key_in_hostfile_by_type(file, host,
1048 	    keytype, found, &line))) {
1049 		fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
1050 		log("WARNING: %s key found for host %s\n"
1051 		    "in %s:%d\n"
1052 		    "%s key fingerprint %s.",
1053 		    key_type(found), host, file, line,
1054 		    key_type(found), fp);
1055 		xfree(fp);
1056 	}
1057 	key_free(found);
1058 	return (ret);
1059 }
1060 
1061 /* print all known host keys for a given host, but skip keys of given type */
1062 static int
show_other_keys(const char * host,Key * key)1063 show_other_keys(const char *host, Key *key)
1064 {
1065 	int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, -1};
1066 	int i, found = 0;
1067 
1068 	for (i = 0; type[i] != -1; i++) {
1069 		if (type[i] == key->type)
1070 			continue;
1071 		if (type[i] != KEY_RSA1 &&
1072 		    show_key_from_file(options.user_hostfile2, host, type[i])) {
1073 			found = 1;
1074 			continue;
1075 		}
1076 		if (type[i] != KEY_RSA1 &&
1077 		    show_key_from_file(options.system_hostfile2, host, type[i])) {
1078 			found = 1;
1079 			continue;
1080 		}
1081 		if (show_key_from_file(options.user_hostfile, host, type[i])) {
1082 			found = 1;
1083 			continue;
1084 		}
1085 		if (show_key_from_file(options.system_hostfile, host, type[i])) {
1086 			found = 1;
1087 			continue;
1088 		}
1089 		debug2("no key of type %d for host %s", type[i], host);
1090 	}
1091 	return (found);
1092 }
1093