]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/openssh/sshconnect.c
ssh-keygen: fix double free in error path
[FreeBSD/FreeBSD.git] / crypto / openssh / sshconnect.c
1 /* $OpenBSD: sshconnect.c,v 1.356 2021/12/19 22:10:24 djm Exp $ */
2 /*
3  * Author: Tatu Ylonen <ylo@cs.hut.fi>
4  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5  *                    All rights reserved
6  * Code to connect to a remote host, and to perform the client side of the
7  * login (authentication) dialog.
8  *
9  * As far as I am concerned, the code I have written for this software
10  * can be used freely for any purpose.  Any derived versions of this
11  * software must be clearly marked as such, and if the derived work is
12  * incompatible with the protocol description in the RFC file, it must be
13  * called by a name other than "ssh" or "Secure Shell".
14  */
15
16 #include "includes.h"
17
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include <sys/stat.h>
21 #include <sys/socket.h>
22 #ifdef HAVE_SYS_TIME_H
23 # include <sys/time.h>
24 #endif
25
26 #include <net/if.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <limits.h>
34 #include <netdb.h>
35 #ifdef HAVE_PATHS_H
36 #include <paths.h>
37 #endif
38 #include <pwd.h>
39 #ifdef HAVE_POLL_H
40 #include <poll.h>
41 #endif
42 #include <signal.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <stdarg.h>
46 #include <string.h>
47 #include <unistd.h>
48 #ifdef HAVE_IFADDRS_H
49 # include <ifaddrs.h>
50 #endif
51
52 #include "xmalloc.h"
53 #include "hostfile.h"
54 #include "ssh.h"
55 #include "sshbuf.h"
56 #include "packet.h"
57 #include "compat.h"
58 #include "sshkey.h"
59 #include "sshconnect.h"
60 #include "log.h"
61 #include "misc.h"
62 #include "readconf.h"
63 #include "atomicio.h"
64 #include "dns.h"
65 #include "monitor_fdpass.h"
66 #include "ssh2.h"
67 #include "version.h"
68 #include "authfile.h"
69 #include "ssherr.h"
70 #include "authfd.h"
71 #include "kex.h"
72
73 struct sshkey *previous_host_key = NULL;
74
75 static int matching_host_key_dns = 0;
76
77 static pid_t proxy_command_pid = 0;
78
79 /* import */
80 extern int debug_flag;
81 extern Options options;
82 extern char *__progname;
83
84 static int show_other_keys(struct hostkeys *, struct sshkey *);
85 static void warn_changed_key(struct sshkey *);
86
87 /* Expand a proxy command */
88 static char *
89 expand_proxy_command(const char *proxy_command, const char *user,
90     const char *host, const char *host_arg, int port)
91 {
92         char *tmp, *ret, strport[NI_MAXSERV];
93         const char *keyalias = options.host_key_alias ?
94             options.host_key_alias : host_arg;
95
96         snprintf(strport, sizeof strport, "%d", port);
97         xasprintf(&tmp, "exec %s", proxy_command);
98         ret = percent_expand(tmp,
99             "h", host,
100             "k", keyalias,
101             "n", host_arg,
102             "p", strport,
103             "r", options.user,
104             (char *)NULL);
105         free(tmp);
106         return ret;
107 }
108
109 /*
110  * Connect to the given ssh server using a proxy command that passes a
111  * a connected fd back to us.
112  */
113 static int
114 ssh_proxy_fdpass_connect(struct ssh *ssh, const char *host,
115     const char *host_arg, u_short port, const char *proxy_command)
116 {
117         char *command_string;
118         int sp[2], sock;
119         pid_t pid;
120         char *shell;
121
122         if ((shell = getenv("SHELL")) == NULL)
123                 shell = _PATH_BSHELL;
124
125         if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == -1)
126                 fatal("Could not create socketpair to communicate with "
127                     "proxy dialer: %.100s", strerror(errno));
128
129         command_string = expand_proxy_command(proxy_command, options.user,
130             host, host_arg, port);
131         debug("Executing proxy dialer command: %.500s", command_string);
132
133         /* Fork and execute the proxy command. */
134         if ((pid = fork()) == 0) {
135                 char *argv[10];
136
137                 close(sp[1]);
138                 /* Redirect stdin and stdout. */
139                 if (sp[0] != 0) {
140                         if (dup2(sp[0], 0) == -1)
141                                 perror("dup2 stdin");
142                 }
143                 if (sp[0] != 1) {
144                         if (dup2(sp[0], 1) == -1)
145                                 perror("dup2 stdout");
146                 }
147                 if (sp[0] >= 2)
148                         close(sp[0]);
149
150                 /*
151                  * Stderr is left for non-ControlPersist connections is so
152                  * error messages may be printed on the user's terminal.
153                  */
154                 if (!debug_flag && options.control_path != NULL &&
155                     options.control_persist && stdfd_devnull(0, 0, 1) == -1)
156                         error_f("stdfd_devnull failed");
157
158                 argv[0] = shell;
159                 argv[1] = "-c";
160                 argv[2] = command_string;
161                 argv[3] = NULL;
162
163                 /*
164                  * Execute the proxy command.
165                  * Note that we gave up any extra privileges above.
166                  */
167                 execv(argv[0], argv);
168                 perror(argv[0]);
169                 exit(1);
170         }
171         /* Parent. */
172         if (pid == -1)
173                 fatal("fork failed: %.100s", strerror(errno));
174         close(sp[0]);
175         free(command_string);
176
177         if ((sock = mm_receive_fd(sp[1])) == -1)
178                 fatal("proxy dialer did not pass back a connection");
179         close(sp[1]);
180
181         while (waitpid(pid, NULL, 0) == -1)
182                 if (errno != EINTR)
183                         fatal("Couldn't wait for child: %s", strerror(errno));
184
185         /* Set the connection file descriptors. */
186         if (ssh_packet_set_connection(ssh, sock, sock) == NULL)
187                 return -1; /* ssh_packet_set_connection logs error */
188
189         return 0;
190 }
191
192 /*
193  * Connect to the given ssh server using a proxy command.
194  */
195 static int
196 ssh_proxy_connect(struct ssh *ssh, const char *host, const char *host_arg,
197     u_short port, const char *proxy_command)
198 {
199         char *command_string;
200         int pin[2], pout[2];
201         pid_t pid;
202         char *shell;
203
204         if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
205                 shell = _PATH_BSHELL;
206
207         /* Create pipes for communicating with the proxy. */
208         if (pipe(pin) == -1 || pipe(pout) == -1)
209                 fatal("Could not create pipes to communicate with the proxy: %.100s",
210                     strerror(errno));
211
212         command_string = expand_proxy_command(proxy_command, options.user,
213             host, host_arg, port);
214         debug("Executing proxy command: %.500s", command_string);
215
216         /* Fork and execute the proxy command. */
217         if ((pid = fork()) == 0) {
218                 char *argv[10];
219
220                 /* Redirect stdin and stdout. */
221                 close(pin[1]);
222                 if (pin[0] != 0) {
223                         if (dup2(pin[0], 0) == -1)
224                                 perror("dup2 stdin");
225                         close(pin[0]);
226                 }
227                 close(pout[0]);
228                 if (dup2(pout[1], 1) == -1)
229                         perror("dup2 stdout");
230                 /* Cannot be 1 because pin allocated two descriptors. */
231                 close(pout[1]);
232
233                 /*
234                  * Stderr is left for non-ControlPersist connections is so
235                  * error messages may be printed on the user's terminal.
236                  */
237                 if (!debug_flag && options.control_path != NULL &&
238                     options.control_persist && stdfd_devnull(0, 0, 1) == -1)
239                         error_f("stdfd_devnull failed");
240
241                 argv[0] = shell;
242                 argv[1] = "-c";
243                 argv[2] = command_string;
244                 argv[3] = NULL;
245
246                 /*
247                  * Execute the proxy command.  Note that we gave up any
248                  * extra privileges above.
249                  */
250                 ssh_signal(SIGPIPE, SIG_DFL);
251                 execv(argv[0], argv);
252                 perror(argv[0]);
253                 exit(1);
254         }
255         /* Parent. */
256         if (pid == -1)
257                 fatal("fork failed: %.100s", strerror(errno));
258         else
259                 proxy_command_pid = pid; /* save pid to clean up later */
260
261         /* Close child side of the descriptors. */
262         close(pin[0]);
263         close(pout[1]);
264
265         /* Free the command name. */
266         free(command_string);
267
268         /* Set the connection file descriptors. */
269         if (ssh_packet_set_connection(ssh, pout[0], pin[1]) == NULL)
270                 return -1; /* ssh_packet_set_connection logs error */
271
272         return 0;
273 }
274
275 void
276 ssh_kill_proxy_command(void)
277 {
278         /*
279          * Send SIGHUP to proxy command if used. We don't wait() in
280          * case it hangs and instead rely on init to reap the child
281          */
282         if (proxy_command_pid > 1)
283                 kill(proxy_command_pid, SIGHUP);
284 }
285
286 #ifdef HAVE_IFADDRS_H
287 /*
288  * Search a interface address list (returned from getifaddrs(3)) for an
289  * address that matches the desired address family on the specified interface.
290  * Returns 0 and fills in *resultp and *rlenp on success. Returns -1 on failure.
291  */
292 static int
293 check_ifaddrs(const char *ifname, int af, const struct ifaddrs *ifaddrs,
294     struct sockaddr_storage *resultp, socklen_t *rlenp)
295 {
296         struct sockaddr_in6 *sa6;
297         struct sockaddr_in *sa;
298         struct in6_addr *v6addr;
299         const struct ifaddrs *ifa;
300         int allow_local;
301
302         /*
303          * Prefer addresses that are not loopback or linklocal, but use them
304          * if nothing else matches.
305          */
306         for (allow_local = 0; allow_local < 2; allow_local++) {
307                 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
308                         if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL ||
309                             (ifa->ifa_flags & IFF_UP) == 0 ||
310                             ifa->ifa_addr->sa_family != af ||
311                             strcmp(ifa->ifa_name, options.bind_interface) != 0)
312                                 continue;
313                         switch (ifa->ifa_addr->sa_family) {
314                         case AF_INET:
315                                 sa = (struct sockaddr_in *)ifa->ifa_addr;
316                                 if (!allow_local && sa->sin_addr.s_addr ==
317                                     htonl(INADDR_LOOPBACK))
318                                         continue;
319                                 if (*rlenp < sizeof(struct sockaddr_in)) {
320                                         error_f("v4 addr doesn't fit");
321                                         return -1;
322                                 }
323                                 *rlenp = sizeof(struct sockaddr_in);
324                                 memcpy(resultp, sa, *rlenp);
325                                 return 0;
326                         case AF_INET6:
327                                 sa6 = (struct sockaddr_in6 *)ifa->ifa_addr;
328                                 v6addr = &sa6->sin6_addr;
329                                 if (!allow_local &&
330                                     (IN6_IS_ADDR_LINKLOCAL(v6addr) ||
331                                     IN6_IS_ADDR_LOOPBACK(v6addr)))
332                                         continue;
333                                 if (*rlenp < sizeof(struct sockaddr_in6)) {
334                                         error_f("v6 addr doesn't fit");
335                                         return -1;
336                                 }
337                                 *rlenp = sizeof(struct sockaddr_in6);
338                                 memcpy(resultp, sa6, *rlenp);
339                                 return 0;
340                         }
341                 }
342         }
343         return -1;
344 }
345 #endif
346
347 /*
348  * Creates a socket for use as the ssh connection.
349  */
350 static int
351 ssh_create_socket(struct addrinfo *ai)
352 {
353         int sock, r;
354         struct sockaddr_storage bindaddr;
355         socklen_t bindaddrlen = 0;
356         struct addrinfo hints, *res = NULL;
357 #ifdef HAVE_IFADDRS_H
358         struct ifaddrs *ifaddrs = NULL;
359 #endif
360         char ntop[NI_MAXHOST];
361
362         sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
363         if (sock == -1) {
364                 error("socket: %s", strerror(errno));
365                 return -1;
366         }
367         fcntl(sock, F_SETFD, FD_CLOEXEC);
368
369         /* Use interactive QOS (if specified) until authentication completed */
370         if (options.ip_qos_interactive != INT_MAX)
371                 set_sock_tos(sock, options.ip_qos_interactive);
372
373         /* Bind the socket to an alternative local IP address */
374         if (options.bind_address == NULL && options.bind_interface == NULL)
375                 return sock;
376
377         if (options.bind_address != NULL) {
378                 memset(&hints, 0, sizeof(hints));
379                 hints.ai_family = ai->ai_family;
380                 hints.ai_socktype = ai->ai_socktype;
381                 hints.ai_protocol = ai->ai_protocol;
382                 hints.ai_flags = AI_PASSIVE;
383                 if ((r = getaddrinfo(options.bind_address, NULL,
384                     &hints, &res)) != 0) {
385                         error("getaddrinfo: %s: %s", options.bind_address,
386                             ssh_gai_strerror(r));
387                         goto fail;
388                 }
389                 if (res == NULL) {
390                         error("getaddrinfo: no addrs");
391                         goto fail;
392                 }
393                 memcpy(&bindaddr, res->ai_addr, res->ai_addrlen);
394                 bindaddrlen = res->ai_addrlen;
395         } else if (options.bind_interface != NULL) {
396 #ifdef HAVE_IFADDRS_H
397                 if ((r = getifaddrs(&ifaddrs)) != 0) {
398                         error("getifaddrs: %s: %s", options.bind_interface,
399                             strerror(errno));
400                         goto fail;
401                 }
402                 bindaddrlen = sizeof(bindaddr);
403                 if (check_ifaddrs(options.bind_interface, ai->ai_family,
404                     ifaddrs, &bindaddr, &bindaddrlen) != 0) {
405                         logit("getifaddrs: %s: no suitable addresses",
406                             options.bind_interface);
407                         goto fail;
408                 }
409 #else
410                 error("BindInterface not supported on this platform.");
411 #endif
412         }
413         if ((r = getnameinfo((struct sockaddr *)&bindaddr, bindaddrlen,
414             ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST)) != 0) {
415                 error_f("getnameinfo failed: %s", ssh_gai_strerror(r));
416                 goto fail;
417         }
418         if (bind(sock, (struct sockaddr *)&bindaddr, bindaddrlen) != 0) {
419                 error("bind %s: %s", ntop, strerror(errno));
420                 goto fail;
421         }
422         debug_f("bound to %s", ntop);
423         /* success */
424         goto out;
425 fail:
426         close(sock);
427         sock = -1;
428  out:
429         if (res != NULL)
430                 freeaddrinfo(res);
431 #ifdef HAVE_IFADDRS_H
432         if (ifaddrs != NULL)
433                 freeifaddrs(ifaddrs);
434 #endif
435         return sock;
436 }
437
438 /*
439  * Opens a TCP/IP connection to the remote server on the given host.
440  * The address of the remote host will be returned in hostaddr.
441  * If port is 0, the default port will be used.
442  * Connection_attempts specifies the maximum number of tries (one per
443  * second).  If proxy_command is non-NULL, it specifies the command (with %h
444  * and %p substituted for host and port, respectively) to use to contact
445  * the daemon.
446  */
447 static int
448 ssh_connect_direct(struct ssh *ssh, const char *host, struct addrinfo *aitop,
449     struct sockaddr_storage *hostaddr, u_short port, int connection_attempts,
450     int *timeout_ms, int want_keepalive)
451 {
452         int on = 1, saved_timeout_ms = *timeout_ms;
453         int oerrno, sock = -1, attempt;
454         char ntop[NI_MAXHOST], strport[NI_MAXSERV];
455         struct addrinfo *ai;
456
457         debug3_f("entering");
458         memset(ntop, 0, sizeof(ntop));
459         memset(strport, 0, sizeof(strport));
460
461         for (attempt = 0; attempt < connection_attempts; attempt++) {
462                 if (attempt > 0) {
463                         /* Sleep a moment before retrying. */
464                         sleep(1);
465                         debug("Trying again...");
466                 }
467                 /*
468                  * Loop through addresses for this host, and try each one in
469                  * sequence until the connection succeeds.
470                  */
471                 for (ai = aitop; ai; ai = ai->ai_next) {
472                         if (ai->ai_family != AF_INET &&
473                             ai->ai_family != AF_INET6) {
474                                 errno = EAFNOSUPPORT;
475                                 continue;
476                         }
477                         if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
478                             ntop, sizeof(ntop), strport, sizeof(strport),
479                             NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
480                                 oerrno = errno;
481                                 error_f("getnameinfo failed");
482                                 errno = oerrno;
483                                 continue;
484                         }
485                         debug("Connecting to %.200s [%.100s] port %s.",
486                                 host, ntop, strport);
487
488                         /* Create a socket for connecting. */
489                         sock = ssh_create_socket(ai);
490                         if (sock < 0) {
491                                 /* Any error is already output */
492                                 errno = 0;
493                                 continue;
494                         }
495
496                         *timeout_ms = saved_timeout_ms;
497                         if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen,
498                             timeout_ms) >= 0) {
499                                 /* Successful connection. */
500                                 memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
501                                 break;
502                         } else {
503                                 oerrno = errno;
504                                 debug("connect to address %s port %s: %s",
505                                     ntop, strport, strerror(errno));
506                                 close(sock);
507                                 sock = -1;
508                                 errno = oerrno;
509                         }
510                 }
511                 if (sock != -1)
512                         break;  /* Successful connection. */
513         }
514
515         /* Return failure if we didn't get a successful connection. */
516         if (sock == -1) {
517                 error("ssh: connect to host %s port %s: %s",
518                     host, strport, errno == 0 ? "failure" : strerror(errno));
519                 return -1;
520         }
521
522         debug("Connection established.");
523
524         /* Set SO_KEEPALIVE if requested. */
525         if (want_keepalive &&
526             setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
527             sizeof(on)) == -1)
528                 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
529
530         /* Set the connection. */
531         if (ssh_packet_set_connection(ssh, sock, sock) == NULL)
532                 return -1; /* ssh_packet_set_connection logs error */
533
534         return 0;
535 }
536
537 int
538 ssh_connect(struct ssh *ssh, const char *host, const char *host_arg,
539     struct addrinfo *addrs, struct sockaddr_storage *hostaddr, u_short port,
540     int connection_attempts, int *timeout_ms, int want_keepalive)
541 {
542         int in, out;
543
544         if (options.proxy_command == NULL) {
545                 return ssh_connect_direct(ssh, host, addrs, hostaddr, port,
546                     connection_attempts, timeout_ms, want_keepalive);
547         } else if (strcmp(options.proxy_command, "-") == 0) {
548                 if ((in = dup(STDIN_FILENO)) == -1 ||
549                     (out = dup(STDOUT_FILENO)) == -1) {
550                         if (in >= 0)
551                                 close(in);
552                         error_f("dup() in/out failed");
553                         return -1; /* ssh_packet_set_connection logs error */
554                 }
555                 if ((ssh_packet_set_connection(ssh, in, out)) == NULL)
556                         return -1; /* ssh_packet_set_connection logs error */
557                 return 0;
558         } else if (options.proxy_use_fdpass) {
559                 return ssh_proxy_fdpass_connect(ssh, host, host_arg, port,
560                     options.proxy_command);
561         }
562         return ssh_proxy_connect(ssh, host, host_arg, port,
563             options.proxy_command);
564 }
565
566 /* defaults to 'no' */
567 static int
568 confirm(const char *prompt, const char *fingerprint)
569 {
570         const char *msg, *again = "Please type 'yes' or 'no': ";
571         const char *again_fp = "Please type 'yes', 'no' or the fingerprint: ";
572         char *p, *cp;
573         int ret = -1;
574
575         if (options.batch_mode)
576                 return 0;
577         for (msg = prompt;;msg = fingerprint ? again_fp : again) {
578                 cp = p = read_passphrase(msg, RP_ECHO);
579                 if (p == NULL)
580                         return 0;
581                 p += strspn(p, " \t"); /* skip leading whitespace */
582                 p[strcspn(p, " \t\n")] = '\0'; /* remove trailing whitespace */
583                 if (p[0] == '\0' || strcasecmp(p, "no") == 0)
584                         ret = 0;
585                 else if (strcasecmp(p, "yes") == 0 || (fingerprint != NULL &&
586                     strcmp(p, fingerprint) == 0))
587                         ret = 1;
588                 free(cp);
589                 if (ret != -1)
590                         return ret;
591         }
592 }
593
594 static int
595 sockaddr_is_local(struct sockaddr *hostaddr)
596 {
597         switch (hostaddr->sa_family) {
598         case AF_INET:
599                 return (ntohl(((struct sockaddr_in *)hostaddr)->
600                     sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
601         case AF_INET6:
602                 return IN6_IS_ADDR_LOOPBACK(
603                     &(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
604         default:
605                 return 0;
606         }
607 }
608
609 /*
610  * Prepare the hostname and ip address strings that are used to lookup
611  * host keys in known_hosts files. These may have a port number appended.
612  */
613 void
614 get_hostfile_hostname_ipaddr(char *hostname, struct sockaddr *hostaddr,
615     u_short port, char **hostfile_hostname, char **hostfile_ipaddr)
616 {
617         char ntop[NI_MAXHOST];
618         socklen_t addrlen;
619
620         switch (hostaddr == NULL ? -1 : hostaddr->sa_family) {
621         case -1:
622                 addrlen = 0;
623                 break;
624         case AF_INET:
625                 addrlen = sizeof(struct sockaddr_in);
626                 break;
627         case AF_INET6:
628                 addrlen = sizeof(struct sockaddr_in6);
629                 break;
630         default:
631                 addrlen = sizeof(struct sockaddr);
632                 break;
633         }
634
635         /*
636          * We don't have the remote ip-address for connections
637          * using a proxy command
638          */
639         if (hostfile_ipaddr != NULL) {
640                 if (options.proxy_command == NULL) {
641                         if (getnameinfo(hostaddr, addrlen,
642                             ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0)
643                         fatal_f("getnameinfo failed");
644                         *hostfile_ipaddr = put_host_port(ntop, port);
645                 } else {
646                         *hostfile_ipaddr = xstrdup("<no hostip for proxy "
647                             "command>");
648                 }
649         }
650
651         /*
652          * Allow the user to record the key under a different name or
653          * differentiate a non-standard port.  This is useful for ssh
654          * tunneling over forwarded connections or if you run multiple
655          * sshd's on different ports on the same machine.
656          */
657         if (hostfile_hostname != NULL) {
658                 if (options.host_key_alias != NULL) {
659                         *hostfile_hostname = xstrdup(options.host_key_alias);
660                         debug("using hostkeyalias: %s", *hostfile_hostname);
661                 } else {
662                         *hostfile_hostname = put_host_port(hostname, port);
663                 }
664         }
665 }
666
667 /* returns non-zero if path appears in hostfiles, or 0 if not. */
668 static int
669 path_in_hostfiles(const char *path, char **hostfiles, u_int num_hostfiles)
670 {
671         u_int i;
672
673         for (i = 0; i < num_hostfiles; i++) {
674                 if (strcmp(path, hostfiles[i]) == 0)
675                         return 1;
676         }
677         return 0;
678 }
679
680 struct find_by_key_ctx {
681         const char *host, *ip;
682         const struct sshkey *key;
683         char **names;
684         u_int nnames;
685 };
686
687 /* Try to replace home directory prefix (per $HOME) with a ~/ sequence */
688 static char *
689 try_tilde_unexpand(const char *path)
690 {
691         char *home, *ret = NULL;
692         size_t l;
693
694         if (*path != '/')
695                 return xstrdup(path);
696         if ((home = getenv("HOME")) == NULL || (l = strlen(home)) == 0)
697                 return xstrdup(path);
698         if (strncmp(path, home, l) != 0)
699                 return xstrdup(path);
700         /*
701          * ensure we have matched on a path boundary: either the $HOME that
702          * we just compared ends with a '/' or the next character of the path
703          * must be a '/'.
704          */
705         if (home[l - 1] != '/' && path[l] != '/')
706                 return xstrdup(path);
707         if (path[l] == '/')
708                 l++;
709         xasprintf(&ret, "~/%s", path + l);
710         return ret;
711 }
712
713 static int
714 hostkeys_find_by_key_cb(struct hostkey_foreach_line *l, void *_ctx)
715 {
716         struct find_by_key_ctx *ctx = (struct find_by_key_ctx *)_ctx;
717         char *path;
718
719         /* we are looking for keys with names that *do not* match */
720         if ((l->match & HKF_MATCH_HOST) != 0)
721                 return 0;
722         /* not interested in marker lines */
723         if (l->marker != MRK_NONE)
724                 return 0;
725         /* we are only interested in exact key matches */
726         if (l->key == NULL || !sshkey_equal(ctx->key, l->key))
727                 return 0;
728         path = try_tilde_unexpand(l->path);
729         debug_f("found matching key in %s:%lu", path, l->linenum);
730         ctx->names = xrecallocarray(ctx->names,
731             ctx->nnames, ctx->nnames + 1, sizeof(*ctx->names));
732         xasprintf(&ctx->names[ctx->nnames], "%s:%lu: %s", path, l->linenum,
733             strncmp(l->hosts, HASH_MAGIC, strlen(HASH_MAGIC)) == 0 ?
734             "[hashed name]" : l->hosts);
735         ctx->nnames++;
736         free(path);
737         return 0;
738 }
739
740 static int
741 hostkeys_find_by_key_hostfile(const char *file, const char *which,
742     struct find_by_key_ctx *ctx)
743 {
744         int r;
745
746         debug3_f("trying %s hostfile \"%s\"", which, file);
747         if ((r = hostkeys_foreach(file, hostkeys_find_by_key_cb, ctx,
748             ctx->host, ctx->ip, HKF_WANT_PARSE_KEY, 0)) != 0) {
749                 if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) {
750                         debug_f("hostkeys file %s does not exist", file);
751                         return 0;
752                 }
753                 error_fr(r, "hostkeys_foreach failed for %s", file);
754                 return r;
755         }
756         return 0;
757 }
758
759 /*
760  * Find 'key' in known hosts file(s) that do not match host/ip.
761  * Used to display also-known-as information for previously-unseen hostkeys.
762  */
763 static void
764 hostkeys_find_by_key(const char *host, const char *ip, const struct sshkey *key,
765     char **user_hostfiles, u_int num_user_hostfiles,
766     char **system_hostfiles, u_int num_system_hostfiles,
767     char ***names, u_int *nnames)
768 {
769         struct find_by_key_ctx ctx = {0, 0, 0, 0, 0};
770         u_int i;
771
772         *names = NULL;
773         *nnames = 0;
774
775         if (key == NULL || sshkey_is_cert(key))
776                 return;
777
778         ctx.host = host;
779         ctx.ip = ip;
780         ctx.key = key;
781
782         for (i = 0; i < num_user_hostfiles; i++) {
783                 if (hostkeys_find_by_key_hostfile(user_hostfiles[i],
784                     "user", &ctx) != 0)
785                         goto fail;
786         }
787         for (i = 0; i < num_system_hostfiles; i++) {
788                 if (hostkeys_find_by_key_hostfile(system_hostfiles[i],
789                     "system", &ctx) != 0)
790                         goto fail;
791         }
792         /* success */
793         *names = ctx.names;
794         *nnames = ctx.nnames;
795         ctx.names = NULL;
796         ctx.nnames = 0;
797         return;
798  fail:
799         for (i = 0; i < ctx.nnames; i++)
800                 free(ctx.names[i]);
801         free(ctx.names);
802 }
803
804 #define MAX_OTHER_NAMES 8 /* Maximum number of names to list */
805 static char *
806 other_hostkeys_message(const char *host, const char *ip,
807     const struct sshkey *key,
808     char **user_hostfiles, u_int num_user_hostfiles,
809     char **system_hostfiles, u_int num_system_hostfiles)
810 {
811         char *ret = NULL, **othernames = NULL;
812         u_int i, n, num_othernames = 0;
813
814         hostkeys_find_by_key(host, ip, key,
815             user_hostfiles, num_user_hostfiles,
816             system_hostfiles, num_system_hostfiles,
817             &othernames, &num_othernames);
818         if (num_othernames == 0)
819                 return xstrdup("This key is not known by any other names");
820
821         xasprintf(&ret, "This host key is known by the following other "
822             "names/addresses:");
823
824         n = num_othernames;
825         if (n > MAX_OTHER_NAMES)
826                 n = MAX_OTHER_NAMES;
827         for (i = 0; i < n; i++) {
828                 xextendf(&ret, "\n", "    %s", othernames[i]);
829         }
830         if (n < num_othernames) {
831                 xextendf(&ret, "\n", "    (%d additional names omitted)",
832                     num_othernames - n);
833         }
834         for (i = 0; i < num_othernames; i++)
835                 free(othernames[i]);
836         free(othernames);
837         return ret;
838 }
839
840 void
841 load_hostkeys_command(struct hostkeys *hostkeys, const char *command_template,
842     const char *invocation, const struct ssh_conn_info *cinfo,
843     const struct sshkey *host_key, const char *hostfile_hostname)
844 {
845         int r, i, ac = 0;
846         char *key_fp = NULL, *keytext = NULL, *tmp;
847         char *command = NULL, *tag = NULL, **av = NULL;
848         FILE *f = NULL;
849         pid_t pid;
850         void (*osigchld)(int);
851
852         xasprintf(&tag, "KnownHostsCommand-%s", invocation);
853
854         if (host_key != NULL) {
855                 if ((key_fp = sshkey_fingerprint(host_key,
856                     options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
857                         fatal_f("sshkey_fingerprint failed");
858                 if ((r = sshkey_to_base64(host_key, &keytext)) != 0)
859                         fatal_fr(r, "sshkey_to_base64 failed");
860         }
861         /*
862          * NB. all returns later this function should go via "out" to
863          * ensure the original SIGCHLD handler is restored properly.
864          */
865         osigchld = ssh_signal(SIGCHLD, SIG_DFL);
866
867         /* Turn the command into an argument vector */
868         if (argv_split(command_template, &ac, &av, 0) != 0) {
869                 error("%s \"%s\" contains invalid quotes", tag,
870                     command_template);
871                 goto out;
872         }
873         if (ac == 0) {
874                 error("%s \"%s\" yielded no arguments", tag,
875                     command_template);
876                 goto out;
877         }
878         for (i = 1; i < ac; i++) {
879                 tmp = percent_dollar_expand(av[i],
880                     DEFAULT_CLIENT_PERCENT_EXPAND_ARGS(cinfo),
881                     "H", hostfile_hostname,
882                     "I", invocation,
883                     "t", host_key == NULL ? "NONE" : sshkey_ssh_name(host_key),
884                     "f", key_fp == NULL ? "NONE" : key_fp,
885                     "K", keytext == NULL ? "NONE" : keytext,
886                     (char *)NULL);
887                 if (tmp == NULL)
888                         fatal_f("percent_expand failed");
889                 free(av[i]);
890                 av[i] = tmp;
891         }
892         /* Prepare a printable command for logs, etc. */
893         command = argv_assemble(ac, av);
894
895         if ((pid = subprocess(tag, command, ac, av, &f,
896             SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_UNSAFE_PATH|
897             SSH_SUBPROCESS_PRESERVE_ENV, NULL, NULL, NULL)) == 0)
898                 goto out;
899
900         load_hostkeys_file(hostkeys, hostfile_hostname, tag, f, 1);
901
902         if (exited_cleanly(pid, tag, command, 0) != 0)
903                 fatal("KnownHostsCommand failed");
904
905  out:
906         if (f != NULL)
907                 fclose(f);
908         ssh_signal(SIGCHLD, osigchld);
909         for (i = 0; i < ac; i++)
910                 free(av[i]);
911         free(av);
912         free(tag);
913         free(command);
914         free(key_fp);
915         free(keytext);
916 }
917
918 /*
919  * check whether the supplied host key is valid, return -1 if the key
920  * is not valid. user_hostfile[0] will not be updated if 'readonly' is true.
921  */
922 #define RDRW    0
923 #define RDONLY  1
924 #define ROQUIET 2
925 static int
926 check_host_key(char *hostname, const struct ssh_conn_info *cinfo,
927     struct sockaddr *hostaddr, u_short port,
928     struct sshkey *host_key, int readonly, int clobber_port,
929     char **user_hostfiles, u_int num_user_hostfiles,
930     char **system_hostfiles, u_int num_system_hostfiles,
931     const char *hostfile_command)
932 {
933         HostStatus host_status = -1, ip_status = -1;
934         struct sshkey *raw_key = NULL;
935         char *ip = NULL, *host = NULL;
936         char hostline[1000], *hostp, *fp, *ra;
937         char msg[1024];
938         const char *type, *fail_reason;
939         const struct hostkey_entry *host_found = NULL, *ip_found = NULL;
940         int len, cancelled_forwarding = 0, confirmed;
941         int local = sockaddr_is_local(hostaddr);
942         int r, want_cert = sshkey_is_cert(host_key), host_ip_differ = 0;
943         int hostkey_trusted = 0; /* Known or explicitly accepted by user */
944         struct hostkeys *host_hostkeys, *ip_hostkeys;
945         u_int i;
946
947         /*
948          * Force accepting of the host key for loopback/localhost. The
949          * problem is that if the home directory is NFS-mounted to multiple
950          * machines, localhost will refer to a different machine in each of
951          * them, and the user will get bogus HOST_CHANGED warnings.  This
952          * essentially disables host authentication for localhost; however,
953          * this is probably not a real problem.
954          */
955         if (options.no_host_authentication_for_localhost == 1 && local &&
956             options.host_key_alias == NULL) {
957                 debug("Forcing accepting of host key for "
958                     "loopback/localhost.");
959                 options.update_hostkeys = 0;
960                 return 0;
961         }
962
963         /*
964          * Prepare the hostname and address strings used for hostkey lookup.
965          * In some cases, these will have a port number appended.
966          */
967         get_hostfile_hostname_ipaddr(hostname, hostaddr,
968             clobber_port ? 0 : port, &host, &ip);
969
970         /*
971          * Turn off check_host_ip if the connection is to localhost, via proxy
972          * command or if we don't have a hostname to compare with
973          */
974         if (options.check_host_ip && (local ||
975             strcmp(hostname, ip) == 0 || options.proxy_command != NULL))
976                 options.check_host_ip = 0;
977
978         host_hostkeys = init_hostkeys();
979         for (i = 0; i < num_user_hostfiles; i++)
980                 load_hostkeys(host_hostkeys, host, user_hostfiles[i], 0);
981         for (i = 0; i < num_system_hostfiles; i++)
982                 load_hostkeys(host_hostkeys, host, system_hostfiles[i], 0);
983         if (hostfile_command != NULL && !clobber_port) {
984                 load_hostkeys_command(host_hostkeys, hostfile_command,
985                     "HOSTNAME", cinfo, host_key, host);
986         }
987
988         ip_hostkeys = NULL;
989         if (!want_cert && options.check_host_ip) {
990                 ip_hostkeys = init_hostkeys();
991                 for (i = 0; i < num_user_hostfiles; i++)
992                         load_hostkeys(ip_hostkeys, ip, user_hostfiles[i], 0);
993                 for (i = 0; i < num_system_hostfiles; i++)
994                         load_hostkeys(ip_hostkeys, ip, system_hostfiles[i], 0);
995                 if (hostfile_command != NULL && !clobber_port) {
996                         load_hostkeys_command(ip_hostkeys, hostfile_command,
997                             "ADDRESS", cinfo, host_key, ip);
998                 }
999         }
1000
1001  retry:
1002         /* Reload these as they may have changed on cert->key downgrade */
1003         want_cert = sshkey_is_cert(host_key);
1004         type = sshkey_type(host_key);
1005
1006         /*
1007          * Check if the host key is present in the user's list of known
1008          * hosts or in the systemwide list.
1009          */
1010         host_status = check_key_in_hostkeys(host_hostkeys, host_key,
1011             &host_found);
1012
1013         /*
1014          * If there are no hostfiles, or if the hostkey was found via
1015          * KnownHostsCommand, then don't try to touch the disk.
1016          */
1017         if (!readonly && (num_user_hostfiles == 0 ||
1018             (host_found != NULL && host_found->note != 0)))
1019                 readonly = RDONLY;
1020
1021         /*
1022          * Also perform check for the ip address, skip the check if we are
1023          * localhost, looking for a certificate, or the hostname was an ip
1024          * address to begin with.
1025          */
1026         if (!want_cert && ip_hostkeys != NULL) {
1027                 ip_status = check_key_in_hostkeys(ip_hostkeys, host_key,
1028                     &ip_found);
1029                 if (host_status == HOST_CHANGED &&
1030                     (ip_status != HOST_CHANGED ||
1031                     (ip_found != NULL &&
1032                     !sshkey_equal(ip_found->key, host_found->key))))
1033                         host_ip_differ = 1;
1034         } else
1035                 ip_status = host_status;
1036
1037         switch (host_status) {
1038         case HOST_OK:
1039                 /* The host is known and the key matches. */
1040                 debug("Host '%.200s' is known and matches the %s host %s.",
1041                     host, type, want_cert ? "certificate" : "key");
1042                 debug("Found %s in %s:%lu", want_cert ? "CA key" : "key",
1043                     host_found->file, host_found->line);
1044                 if (want_cert) {
1045                         if (sshkey_cert_check_host(host_key,
1046                             options.host_key_alias == NULL ?
1047                             hostname : options.host_key_alias, 0,
1048                             options.ca_sign_algorithms, &fail_reason) != 0) {
1049                                 error("%s", fail_reason);
1050                                 goto fail;
1051                         }
1052                         /*
1053                          * Do not attempt hostkey update if a certificate was
1054                          * successfully matched.
1055                          */
1056                         if (options.update_hostkeys != 0) {
1057                                 options.update_hostkeys = 0;
1058                                 debug3_f("certificate host key in use; "
1059                                     "disabling UpdateHostkeys");
1060                         }
1061                 }
1062                 /* Turn off UpdateHostkeys if key was in system known_hosts */
1063                 if (options.update_hostkeys != 0 &&
1064                     (path_in_hostfiles(host_found->file,
1065                     system_hostfiles, num_system_hostfiles) ||
1066                     (ip_status == HOST_OK && ip_found != NULL &&
1067                     path_in_hostfiles(ip_found->file,
1068                     system_hostfiles, num_system_hostfiles)))) {
1069                         options.update_hostkeys = 0;
1070                         debug3_f("host key found in GlobalKnownHostsFile; "
1071                             "disabling UpdateHostkeys");
1072                 }
1073                 if (options.update_hostkeys != 0 && host_found->note) {
1074                         options.update_hostkeys = 0;
1075                         debug3_f("host key found via KnownHostsCommand; "
1076                             "disabling UpdateHostkeys");
1077                 }
1078                 if (options.check_host_ip && ip_status == HOST_NEW) {
1079                         if (readonly || want_cert)
1080                                 logit("%s host key for IP address "
1081                                     "'%.128s' not in list of known hosts.",
1082                                     type, ip);
1083                         else if (!add_host_to_hostfile(user_hostfiles[0], ip,
1084                             host_key, options.hash_known_hosts))
1085                                 logit("Failed to add the %s host key for IP "
1086                                     "address '%.128s' to the list of known "
1087                                     "hosts (%.500s).", type, ip,
1088                                     user_hostfiles[0]);
1089                         else
1090                                 logit("Warning: Permanently added the %s host "
1091                                     "key for IP address '%.128s' to the list "
1092                                     "of known hosts.", type, ip);
1093                 } else if (options.visual_host_key) {
1094                         fp = sshkey_fingerprint(host_key,
1095                             options.fingerprint_hash, SSH_FP_DEFAULT);
1096                         ra = sshkey_fingerprint(host_key,
1097                             options.fingerprint_hash, SSH_FP_RANDOMART);
1098                         if (fp == NULL || ra == NULL)
1099                                 fatal_f("sshkey_fingerprint failed");
1100                         logit("Host key fingerprint is %s\n%s", fp, ra);
1101                         free(ra);
1102                         free(fp);
1103                 }
1104                 hostkey_trusted = 1;
1105                 break;
1106         case HOST_NEW:
1107                 if (options.host_key_alias == NULL && port != 0 &&
1108                     port != SSH_DEFAULT_PORT && !clobber_port) {
1109                         debug("checking without port identifier");
1110                         if (check_host_key(hostname, cinfo, hostaddr, 0,
1111                             host_key, ROQUIET, 1,
1112                             user_hostfiles, num_user_hostfiles,
1113                             system_hostfiles, num_system_hostfiles,
1114                             hostfile_command) == 0) {
1115                                 debug("found matching key w/out port");
1116                                 break;
1117                         }
1118                 }
1119                 if (readonly || want_cert)
1120                         goto fail;
1121                 /* The host is new. */
1122                 if (options.strict_host_key_checking ==
1123                     SSH_STRICT_HOSTKEY_YES) {
1124                         /*
1125                          * User has requested strict host key checking.  We
1126                          * will not add the host key automatically.  The only
1127                          * alternative left is to abort.
1128                          */
1129                         error("No %s host key is known for %.200s and you "
1130                             "have requested strict checking.", type, host);
1131                         goto fail;
1132                 } else if (options.strict_host_key_checking ==
1133                     SSH_STRICT_HOSTKEY_ASK) {
1134                         char *msg1 = NULL, *msg2 = NULL;
1135
1136                         xasprintf(&msg1, "The authenticity of host "
1137                             "'%.200s (%s)' can't be established", host, ip);
1138
1139                         if (show_other_keys(host_hostkeys, host_key)) {
1140                                 xextendf(&msg1, "\n", "but keys of different "
1141                                     "type are already known for this host.");
1142                         } else
1143                                 xextendf(&msg1, "", ".");
1144
1145                         fp = sshkey_fingerprint(host_key,
1146                             options.fingerprint_hash, SSH_FP_DEFAULT);
1147                         ra = sshkey_fingerprint(host_key,
1148                             options.fingerprint_hash, SSH_FP_RANDOMART);
1149                         if (fp == NULL || ra == NULL)
1150                                 fatal_f("sshkey_fingerprint failed");
1151                         xextendf(&msg1, "\n", "%s key fingerprint is %s.",
1152                             type, fp);
1153                         if (options.visual_host_key)
1154                                 xextendf(&msg1, "\n", "%s", ra);
1155                         if (options.verify_host_key_dns) {
1156                                 xextendf(&msg1, "\n",
1157                                     "%s host key fingerprint found in DNS.",
1158                                     matching_host_key_dns ?
1159                                     "Matching" : "No matching");
1160                         }
1161                         /* msg2 informs for other names matching this key */
1162                         if ((msg2 = other_hostkeys_message(host, ip, host_key,
1163                             user_hostfiles, num_user_hostfiles,
1164                             system_hostfiles, num_system_hostfiles)) != NULL)
1165                                 xextendf(&msg1, "\n", "%s", msg2);
1166
1167                         xextendf(&msg1, "\n",
1168                             "Are you sure you want to continue connecting "
1169                             "(yes/no/[fingerprint])? ");
1170
1171                         confirmed = confirm(msg1, fp);
1172                         free(ra);
1173                         free(fp);
1174                         free(msg1);
1175                         free(msg2);
1176                         if (!confirmed)
1177                                 goto fail;
1178                         hostkey_trusted = 1; /* user explicitly confirmed */
1179                 }
1180                 /*
1181                  * If in "new" or "off" strict mode, add the key automatically
1182                  * to the local known_hosts file.
1183                  */
1184                 if (options.check_host_ip && ip_status == HOST_NEW) {
1185                         snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
1186                         hostp = hostline;
1187                         if (options.hash_known_hosts) {
1188                                 /* Add hash of host and IP separately */
1189                                 r = add_host_to_hostfile(user_hostfiles[0],
1190                                     host, host_key, options.hash_known_hosts) &&
1191                                     add_host_to_hostfile(user_hostfiles[0], ip,
1192                                     host_key, options.hash_known_hosts);
1193                         } else {
1194                                 /* Add unhashed "host,ip" */
1195                                 r = add_host_to_hostfile(user_hostfiles[0],
1196                                     hostline, host_key,
1197                                     options.hash_known_hosts);
1198                         }
1199                 } else {
1200                         r = add_host_to_hostfile(user_hostfiles[0], host,
1201                             host_key, options.hash_known_hosts);
1202                         hostp = host;
1203                 }
1204
1205                 if (!r)
1206                         logit("Failed to add the host to the list of known "
1207                             "hosts (%.500s).", user_hostfiles[0]);
1208                 else
1209                         logit("Warning: Permanently added '%.200s' (%s) to the "
1210                             "list of known hosts.", hostp, type);
1211                 break;
1212         case HOST_REVOKED:
1213                 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1214                 error("@       WARNING: REVOKED HOST KEY DETECTED!               @");
1215                 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1216                 error("The %s host key for %s is marked as revoked.", type, host);
1217                 error("This could mean that a stolen key is being used to");
1218                 error("impersonate this host.");
1219
1220                 /*
1221                  * If strict host key checking is in use, the user will have
1222                  * to edit the key manually and we can only abort.
1223                  */
1224                 if (options.strict_host_key_checking !=
1225                     SSH_STRICT_HOSTKEY_OFF) {
1226                         error("%s host key for %.200s was revoked and you have "
1227                             "requested strict checking.", type, host);
1228                         goto fail;
1229                 }
1230                 goto continue_unsafe;
1231
1232         case HOST_CHANGED:
1233                 if (want_cert) {
1234                         /*
1235                          * This is only a debug() since it is valid to have
1236                          * CAs with wildcard DNS matches that don't match
1237                          * all hosts that one might visit.
1238                          */
1239                         debug("Host certificate authority does not "
1240                             "match %s in %s:%lu", CA_MARKER,
1241                             host_found->file, host_found->line);
1242                         goto fail;
1243                 }
1244                 if (readonly == ROQUIET)
1245                         goto fail;
1246                 if (options.check_host_ip && host_ip_differ) {
1247                         char *key_msg;
1248                         if (ip_status == HOST_NEW)
1249                                 key_msg = "is unknown";
1250                         else if (ip_status == HOST_OK)
1251                                 key_msg = "is unchanged";
1252                         else
1253                                 key_msg = "has a different value";
1254                         error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1255                         error("@       WARNING: POSSIBLE DNS SPOOFING DETECTED!          @");
1256                         error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1257                         error("The %s host key for %s has changed,", type, host);
1258                         error("and the key for the corresponding IP address %s", ip);
1259                         error("%s. This could either mean that", key_msg);
1260                         error("DNS SPOOFING is happening or the IP address for the host");
1261                         error("and its host key have changed at the same time.");
1262                         if (ip_status != HOST_NEW)
1263                                 error("Offending key for IP in %s:%lu",
1264                                     ip_found->file, ip_found->line);
1265                 }
1266                 /* The host key has changed. */
1267                 warn_changed_key(host_key);
1268                 error("Add correct host key in %.100s to get rid of this message.",
1269                     user_hostfiles[0]);
1270                 error("Offending %s key in %s:%lu",
1271                     sshkey_type(host_found->key),
1272                     host_found->file, host_found->line);
1273
1274                 /*
1275                  * If strict host key checking is in use, the user will have
1276                  * to edit the key manually and we can only abort.
1277                  */
1278                 if (options.strict_host_key_checking !=
1279                     SSH_STRICT_HOSTKEY_OFF) {
1280                         error("Host key for %.200s has changed and you have "
1281                             "requested strict checking.", host);
1282                         goto fail;
1283                 }
1284
1285  continue_unsafe:
1286                 /*
1287                  * If strict host key checking has not been requested, allow
1288                  * the connection but without MITM-able authentication or
1289                  * forwarding.
1290                  */
1291                 if (options.password_authentication) {
1292                         error("Password authentication is disabled to avoid "
1293                             "man-in-the-middle attacks.");
1294                         options.password_authentication = 0;
1295                         cancelled_forwarding = 1;
1296                 }
1297                 if (options.kbd_interactive_authentication) {
1298                         error("Keyboard-interactive authentication is disabled"
1299                             " to avoid man-in-the-middle attacks.");
1300                         options.kbd_interactive_authentication = 0;
1301                         cancelled_forwarding = 1;
1302                 }
1303                 if (options.forward_agent) {
1304                         error("Agent forwarding is disabled to avoid "
1305                             "man-in-the-middle attacks.");
1306                         options.forward_agent = 0;
1307                         cancelled_forwarding = 1;
1308                 }
1309                 if (options.forward_x11) {
1310                         error("X11 forwarding is disabled to avoid "
1311                             "man-in-the-middle attacks.");
1312                         options.forward_x11 = 0;
1313                         cancelled_forwarding = 1;
1314                 }
1315                 if (options.num_local_forwards > 0 ||
1316                     options.num_remote_forwards > 0) {
1317                         error("Port forwarding is disabled to avoid "
1318                             "man-in-the-middle attacks.");
1319                         options.num_local_forwards =
1320                             options.num_remote_forwards = 0;
1321                         cancelled_forwarding = 1;
1322                 }
1323                 if (options.tun_open != SSH_TUNMODE_NO) {
1324                         error("Tunnel forwarding is disabled to avoid "
1325                             "man-in-the-middle attacks.");
1326                         options.tun_open = SSH_TUNMODE_NO;
1327                         cancelled_forwarding = 1;
1328                 }
1329                 if (options.update_hostkeys != 0) {
1330                         error("UpdateHostkeys is disabled because the host "
1331                             "key is not trusted.");
1332                         options.update_hostkeys = 0;
1333                 }
1334                 if (options.exit_on_forward_failure && cancelled_forwarding)
1335                         fatal("Error: forwarding disabled due to host key "
1336                             "check failure");
1337                 
1338                 /*
1339                  * XXX Should permit the user to change to use the new id.
1340                  * This could be done by converting the host key to an
1341                  * identifying sentence, tell that the host identifies itself
1342                  * by that sentence, and ask the user if they wish to
1343                  * accept the authentication.
1344                  */
1345                 break;
1346         case HOST_FOUND:
1347                 fatal("internal error");
1348                 break;
1349         }
1350
1351         if (options.check_host_ip && host_status != HOST_CHANGED &&
1352             ip_status == HOST_CHANGED) {
1353                 snprintf(msg, sizeof(msg),
1354                     "Warning: the %s host key for '%.200s' "
1355                     "differs from the key for the IP address '%.128s'"
1356                     "\nOffending key for IP in %s:%lu",
1357                     type, host, ip, ip_found->file, ip_found->line);
1358                 if (host_status == HOST_OK) {
1359                         len = strlen(msg);
1360                         snprintf(msg + len, sizeof(msg) - len,
1361                             "\nMatching host key in %s:%lu",
1362                             host_found->file, host_found->line);
1363                 }
1364                 if (options.strict_host_key_checking ==
1365                     SSH_STRICT_HOSTKEY_ASK) {
1366                         strlcat(msg, "\nAre you sure you want "
1367                             "to continue connecting (yes/no)? ", sizeof(msg));
1368                         if (!confirm(msg, NULL))
1369                                 goto fail;
1370                 } else if (options.strict_host_key_checking !=
1371                     SSH_STRICT_HOSTKEY_OFF) {
1372                         logit("%s", msg);
1373                         error("Exiting, you have requested strict checking.");
1374                         goto fail;
1375                 } else {
1376                         logit("%s", msg);
1377                 }
1378         }
1379
1380         if (!hostkey_trusted && options.update_hostkeys) {
1381                 debug_f("hostkey not known or explicitly trusted: "
1382                     "disabling UpdateHostkeys");
1383                 options.update_hostkeys = 0;
1384         }
1385
1386         free(ip);
1387         free(host);
1388         if (host_hostkeys != NULL)
1389                 free_hostkeys(host_hostkeys);
1390         if (ip_hostkeys != NULL)
1391                 free_hostkeys(ip_hostkeys);
1392         return 0;
1393
1394 fail:
1395         if (want_cert && host_status != HOST_REVOKED) {
1396                 /*
1397                  * No matching certificate. Downgrade cert to raw key and
1398                  * search normally.
1399                  */
1400                 debug("No matching CA found. Retry with plain key");
1401                 if ((r = sshkey_from_private(host_key, &raw_key)) != 0)
1402                         fatal_fr(r, "decode key");
1403                 if ((r = sshkey_drop_cert(raw_key)) != 0)
1404                         fatal_r(r, "Couldn't drop certificate");
1405                 host_key = raw_key;
1406                 goto retry;
1407         }
1408         sshkey_free(raw_key);
1409         free(ip);
1410         free(host);
1411         if (host_hostkeys != NULL)
1412                 free_hostkeys(host_hostkeys);
1413         if (ip_hostkeys != NULL)
1414                 free_hostkeys(ip_hostkeys);
1415         return -1;
1416 }
1417
1418 /* returns 0 if key verifies or -1 if key does NOT verify */
1419 int
1420 verify_host_key(char *host, struct sockaddr *hostaddr, struct sshkey *host_key,
1421     const struct ssh_conn_info *cinfo)
1422 {
1423         u_int i;
1424         int r = -1, flags = 0;
1425         char valid[64], *fp = NULL, *cafp = NULL;
1426         struct sshkey *plain = NULL;
1427
1428         if ((fp = sshkey_fingerprint(host_key,
1429             options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
1430                 error_fr(r, "fingerprint host key");
1431                 r = -1;
1432                 goto out;
1433         }
1434
1435         if (sshkey_is_cert(host_key)) {
1436                 if ((cafp = sshkey_fingerprint(host_key->cert->signature_key,
1437                     options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
1438                         error_fr(r, "fingerprint CA key");
1439                         r = -1;
1440                         goto out;
1441                 }
1442                 sshkey_format_cert_validity(host_key->cert,
1443                     valid, sizeof(valid));
1444                 debug("Server host certificate: %s %s, serial %llu "
1445                     "ID \"%s\" CA %s %s valid %s",
1446                     sshkey_ssh_name(host_key), fp,
1447                     (unsigned long long)host_key->cert->serial,
1448                     host_key->cert->key_id,
1449                     sshkey_ssh_name(host_key->cert->signature_key), cafp,
1450                     valid);
1451                 for (i = 0; i < host_key->cert->nprincipals; i++) {
1452                         debug2("Server host certificate hostname: %s",
1453                             host_key->cert->principals[i]);
1454                 }
1455         } else {
1456                 debug("Server host key: %s %s", sshkey_ssh_name(host_key), fp);
1457         }
1458
1459         if (sshkey_equal(previous_host_key, host_key)) {
1460                 debug2_f("server host key %s %s matches cached key",
1461                     sshkey_type(host_key), fp);
1462                 r = 0;
1463                 goto out;
1464         }
1465
1466         /* Check in RevokedHostKeys file if specified */
1467         if (options.revoked_host_keys != NULL) {
1468                 r = sshkey_check_revoked(host_key, options.revoked_host_keys);
1469                 switch (r) {
1470                 case 0:
1471                         break; /* not revoked */
1472                 case SSH_ERR_KEY_REVOKED:
1473                         error("Host key %s %s revoked by file %s",
1474                             sshkey_type(host_key), fp,
1475                             options.revoked_host_keys);
1476                         r = -1;
1477                         goto out;
1478                 default:
1479                         error_r(r, "Error checking host key %s %s in "
1480                             "revoked keys file %s", sshkey_type(host_key),
1481                             fp, options.revoked_host_keys);
1482                         r = -1;
1483                         goto out;
1484                 }
1485         }
1486
1487         if (options.verify_host_key_dns) {
1488                 /*
1489                  * XXX certs are not yet supported for DNS, so downgrade
1490                  * them and try the plain key.
1491                  */
1492                 if ((r = sshkey_from_private(host_key, &plain)) != 0)
1493                         goto out;
1494                 if (sshkey_is_cert(plain))
1495                         sshkey_drop_cert(plain);
1496                 if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) {
1497                         if (flags & DNS_VERIFY_FOUND) {
1498                                 if (options.verify_host_key_dns == 1 &&
1499                                     flags & DNS_VERIFY_MATCH &&
1500                                     flags & DNS_VERIFY_SECURE) {
1501                                         r = 0;
1502                                         goto out;
1503                                 }
1504                                 if (flags & DNS_VERIFY_MATCH) {
1505                                         matching_host_key_dns = 1;
1506                                 } else {
1507                                         warn_changed_key(plain);
1508                                         error("Update the SSHFP RR in DNS "
1509                                             "with the new host key to get rid "
1510                                             "of this message.");
1511                                 }
1512                         }
1513                 }
1514         }
1515         r = check_host_key(host, cinfo, hostaddr, options.port, host_key,
1516             RDRW, 0, options.user_hostfiles, options.num_user_hostfiles,
1517             options.system_hostfiles, options.num_system_hostfiles,
1518             options.known_hosts_command);
1519
1520 out:
1521         sshkey_free(plain);
1522         free(fp);
1523         free(cafp);
1524         if (r == 0 && host_key != NULL) {
1525                 sshkey_free(previous_host_key);
1526                 r = sshkey_from_private(host_key, &previous_host_key);
1527         }
1528
1529         return r;
1530 }
1531
1532 /*
1533  * Starts a dialog with the server, and authenticates the current user on the
1534  * server.  This does not need any extra privileges.  The basic connection
1535  * to the server must already have been established before this is called.
1536  * If login fails, this function prints an error and never returns.
1537  * This function does not require super-user privileges.
1538  */
1539 void
1540 ssh_login(struct ssh *ssh, Sensitive *sensitive, const char *orighost,
1541     struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms,
1542     const struct ssh_conn_info *cinfo)
1543 {
1544         char *host;
1545         char *server_user, *local_user;
1546         int r;
1547
1548         local_user = xstrdup(pw->pw_name);
1549         server_user = options.user ? options.user : local_user;
1550
1551         /* Convert the user-supplied hostname into all lowercase. */
1552         host = xstrdup(orighost);
1553         lowercase(host);
1554
1555         /* Exchange protocol version identification strings with the server. */
1556         if ((r = kex_exchange_identification(ssh, timeout_ms, NULL)) != 0)
1557                 sshpkt_fatal(ssh, r, "banner exchange");
1558
1559         /* Put the connection into non-blocking mode. */
1560         ssh_packet_set_nonblocking(ssh);
1561
1562         /* key exchange */
1563         /* authenticate user */
1564         debug("Authenticating to %s:%d as '%s'", host, port, server_user);
1565         ssh_kex2(ssh, host, hostaddr, port, cinfo);
1566         ssh_userauth2(ssh, local_user, server_user, host, sensitive);
1567         free(local_user);
1568         free(host);
1569 }
1570
1571 /* print all known host keys for a given host, but skip keys of given type */
1572 static int
1573 show_other_keys(struct hostkeys *hostkeys, struct sshkey *key)
1574 {
1575         int type[] = {
1576                 KEY_RSA,
1577                 KEY_DSA,
1578                 KEY_ECDSA,
1579                 KEY_ED25519,
1580                 KEY_XMSS,
1581                 -1
1582         };
1583         int i, ret = 0;
1584         char *fp, *ra;
1585         const struct hostkey_entry *found;
1586
1587         for (i = 0; type[i] != -1; i++) {
1588                 if (type[i] == key->type)
1589                         continue;
1590                 if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i],
1591                     -1, &found))
1592                         continue;
1593                 fp = sshkey_fingerprint(found->key,
1594                     options.fingerprint_hash, SSH_FP_DEFAULT);
1595                 ra = sshkey_fingerprint(found->key,
1596                     options.fingerprint_hash, SSH_FP_RANDOMART);
1597                 if (fp == NULL || ra == NULL)
1598                         fatal_f("sshkey_fingerprint fail");
1599                 logit("WARNING: %s key found for host %s\n"
1600                     "in %s:%lu\n"
1601                     "%s key fingerprint %s.",
1602                     sshkey_type(found->key),
1603                     found->host, found->file, found->line,
1604                     sshkey_type(found->key), fp);
1605                 if (options.visual_host_key)
1606                         logit("%s", ra);
1607                 free(ra);
1608                 free(fp);
1609                 ret = 1;
1610         }
1611         return ret;
1612 }
1613
1614 static void
1615 warn_changed_key(struct sshkey *host_key)
1616 {
1617         char *fp;
1618
1619         fp = sshkey_fingerprint(host_key, options.fingerprint_hash,
1620             SSH_FP_DEFAULT);
1621         if (fp == NULL)
1622                 fatal_f("sshkey_fingerprint fail");
1623
1624         error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1625         error("@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @");
1626         error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1627         error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
1628         error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
1629         error("It is also possible that a host key has just been changed.");
1630         error("The fingerprint for the %s key sent by the remote host is\n%s.",
1631             sshkey_type(host_key), fp);
1632         error("Please contact your system administrator.");
1633
1634         free(fp);
1635 }
1636
1637 /*
1638  * Execute a local command
1639  */
1640 int
1641 ssh_local_cmd(const char *args)
1642 {
1643         char *shell;
1644         pid_t pid;
1645         int status;
1646         void (*osighand)(int);
1647
1648         if (!options.permit_local_command ||
1649             args == NULL || !*args)
1650                 return (1);
1651
1652         if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
1653                 shell = _PATH_BSHELL;
1654
1655         osighand = ssh_signal(SIGCHLD, SIG_DFL);
1656         pid = fork();
1657         if (pid == 0) {
1658                 ssh_signal(SIGPIPE, SIG_DFL);
1659                 debug3("Executing %s -c \"%s\"", shell, args);
1660                 execl(shell, shell, "-c", args, (char *)NULL);
1661                 error("Couldn't execute %s -c \"%s\": %s",
1662                     shell, args, strerror(errno));
1663                 _exit(1);
1664         } else if (pid == -1)
1665                 fatal("fork failed: %.100s", strerror(errno));
1666         while (waitpid(pid, &status, 0) == -1)
1667                 if (errno != EINTR)
1668                         fatal("Couldn't wait for child: %s", strerror(errno));
1669         ssh_signal(SIGCHLD, osighand);
1670
1671         if (!WIFEXITED(status))
1672                 return (1);
1673
1674         return (WEXITSTATUS(status));
1675 }
1676
1677 void
1678 maybe_add_key_to_agent(const char *authfile, struct sshkey *private,
1679     const char *comment, const char *passphrase)
1680 {
1681         int auth_sock = -1, r;
1682         const char *skprovider = NULL;
1683
1684         if (options.add_keys_to_agent == 0)
1685                 return;
1686
1687         if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) {
1688                 debug3("no authentication agent, not adding key");
1689                 return;
1690         }
1691
1692         if (options.add_keys_to_agent == 2 &&
1693             !ask_permission("Add key %s (%s) to agent?", authfile, comment)) {
1694                 debug3("user denied adding this key");
1695                 close(auth_sock);
1696                 return;
1697         }
1698         if (sshkey_is_sk(private))
1699                 skprovider = options.sk_provider;
1700         if ((r = ssh_add_identity_constrained(auth_sock, private,
1701             comment == NULL ? authfile : comment,
1702             options.add_keys_to_agent_lifespan,
1703             (options.add_keys_to_agent == 3), 0, skprovider, NULL, 0)) == 0)
1704                 debug("identity added to agent: %s", authfile);
1705         else
1706                 debug("could not add identity to agent: %s (%d)", authfile, r);
1707         close(auth_sock);
1708 }