]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/openssh/sshconnect.c
Merge commit 'd84e570b54961e8874bbd8de25635eb96be0977e'
[FreeBSD/FreeBSD.git] / crypto / openssh / sshconnect.c
1 /* $OpenBSD: sshconnect.c,v 1.361 2023/01/13 02:44:02 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 = NULL;
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          * Don't ever try to write an invalid name to a known hosts file.
965          * Note: do this before get_hostfile_hostname_ipaddr() to catch
966          * '[' or ']' in the name before they are added.
967          */
968         if (strcspn(hostname, "@?*#[]|'\'\"\\") != strlen(hostname)) {
969                 debug_f("invalid hostname \"%s\"; will not record: %s",
970                     hostname, fail_reason);
971                 readonly = RDONLY;
972         }
973
974         /*
975          * Prepare the hostname and address strings used for hostkey lookup.
976          * In some cases, these will have a port number appended.
977          */
978         get_hostfile_hostname_ipaddr(hostname, hostaddr,
979             clobber_port ? 0 : port, &host, &ip);
980
981         /*
982          * Turn off check_host_ip if the connection is to localhost, via proxy
983          * command or if we don't have a hostname to compare with
984          */
985         if (options.check_host_ip && (local ||
986             strcmp(hostname, ip) == 0 || options.proxy_command != NULL))
987                 options.check_host_ip = 0;
988
989         host_hostkeys = init_hostkeys();
990         for (i = 0; i < num_user_hostfiles; i++)
991                 load_hostkeys(host_hostkeys, host, user_hostfiles[i], 0);
992         for (i = 0; i < num_system_hostfiles; i++)
993                 load_hostkeys(host_hostkeys, host, system_hostfiles[i], 0);
994         if (hostfile_command != NULL && !clobber_port) {
995                 load_hostkeys_command(host_hostkeys, hostfile_command,
996                     "HOSTNAME", cinfo, host_key, host);
997         }
998
999         ip_hostkeys = NULL;
1000         if (!want_cert && options.check_host_ip) {
1001                 ip_hostkeys = init_hostkeys();
1002                 for (i = 0; i < num_user_hostfiles; i++)
1003                         load_hostkeys(ip_hostkeys, ip, user_hostfiles[i], 0);
1004                 for (i = 0; i < num_system_hostfiles; i++)
1005                         load_hostkeys(ip_hostkeys, ip, system_hostfiles[i], 0);
1006                 if (hostfile_command != NULL && !clobber_port) {
1007                         load_hostkeys_command(ip_hostkeys, hostfile_command,
1008                             "ADDRESS", cinfo, host_key, ip);
1009                 }
1010         }
1011
1012  retry:
1013         /* Reload these as they may have changed on cert->key downgrade */
1014         want_cert = sshkey_is_cert(host_key);
1015         type = sshkey_type(host_key);
1016
1017         /*
1018          * Check if the host key is present in the user's list of known
1019          * hosts or in the systemwide list.
1020          */
1021         host_status = check_key_in_hostkeys(host_hostkeys, host_key,
1022             &host_found);
1023
1024         /*
1025          * If there are no hostfiles, or if the hostkey was found via
1026          * KnownHostsCommand, then don't try to touch the disk.
1027          */
1028         if (!readonly && (num_user_hostfiles == 0 ||
1029             (host_found != NULL && host_found->note != 0)))
1030                 readonly = RDONLY;
1031
1032         /*
1033          * Also perform check for the ip address, skip the check if we are
1034          * localhost, looking for a certificate, or the hostname was an ip
1035          * address to begin with.
1036          */
1037         if (!want_cert && ip_hostkeys != NULL) {
1038                 ip_status = check_key_in_hostkeys(ip_hostkeys, host_key,
1039                     &ip_found);
1040                 if (host_status == HOST_CHANGED &&
1041                     (ip_status != HOST_CHANGED ||
1042                     (ip_found != NULL &&
1043                     !sshkey_equal(ip_found->key, host_found->key))))
1044                         host_ip_differ = 1;
1045         } else
1046                 ip_status = host_status;
1047
1048         switch (host_status) {
1049         case HOST_OK:
1050                 /* The host is known and the key matches. */
1051                 debug("Host '%.200s' is known and matches the %s host %s.",
1052                     host, type, want_cert ? "certificate" : "key");
1053                 debug("Found %s in %s:%lu", want_cert ? "CA key" : "key",
1054                     host_found->file, host_found->line);
1055                 if (want_cert) {
1056                         if (sshkey_cert_check_host(host_key,
1057                             options.host_key_alias == NULL ?
1058                             hostname : options.host_key_alias, 0,
1059                             options.ca_sign_algorithms, &fail_reason) != 0) {
1060                                 error("%s", fail_reason);
1061                                 goto fail;
1062                         }
1063                         /*
1064                          * Do not attempt hostkey update if a certificate was
1065                          * successfully matched.
1066                          */
1067                         if (options.update_hostkeys != 0) {
1068                                 options.update_hostkeys = 0;
1069                                 debug3_f("certificate host key in use; "
1070                                     "disabling UpdateHostkeys");
1071                         }
1072                 }
1073                 /* Turn off UpdateHostkeys if key was in system known_hosts */
1074                 if (options.update_hostkeys != 0 &&
1075                     (path_in_hostfiles(host_found->file,
1076                     system_hostfiles, num_system_hostfiles) ||
1077                     (ip_status == HOST_OK && ip_found != NULL &&
1078                     path_in_hostfiles(ip_found->file,
1079                     system_hostfiles, num_system_hostfiles)))) {
1080                         options.update_hostkeys = 0;
1081                         debug3_f("host key found in GlobalKnownHostsFile; "
1082                             "disabling UpdateHostkeys");
1083                 }
1084                 if (options.update_hostkeys != 0 && host_found->note) {
1085                         options.update_hostkeys = 0;
1086                         debug3_f("host key found via KnownHostsCommand; "
1087                             "disabling UpdateHostkeys");
1088                 }
1089                 if (options.check_host_ip && ip_status == HOST_NEW) {
1090                         if (readonly || want_cert)
1091                                 logit("%s host key for IP address "
1092                                     "'%.128s' not in list of known hosts.",
1093                                     type, ip);
1094                         else if (!add_host_to_hostfile(user_hostfiles[0], ip,
1095                             host_key, options.hash_known_hosts))
1096                                 logit("Failed to add the %s host key for IP "
1097                                     "address '%.128s' to the list of known "
1098                                     "hosts (%.500s).", type, ip,
1099                                     user_hostfiles[0]);
1100                         else
1101                                 logit("Warning: Permanently added the %s host "
1102                                     "key for IP address '%.128s' to the list "
1103                                     "of known hosts.", type, ip);
1104                 } else if (options.visual_host_key) {
1105                         fp = sshkey_fingerprint(host_key,
1106                             options.fingerprint_hash, SSH_FP_DEFAULT);
1107                         ra = sshkey_fingerprint(host_key,
1108                             options.fingerprint_hash, SSH_FP_RANDOMART);
1109                         if (fp == NULL || ra == NULL)
1110                                 fatal_f("sshkey_fingerprint failed");
1111                         logit("Host key fingerprint is %s\n%s", fp, ra);
1112                         free(ra);
1113                         free(fp);
1114                 }
1115                 hostkey_trusted = 1;
1116                 break;
1117         case HOST_NEW:
1118                 if (options.host_key_alias == NULL && port != 0 &&
1119                     port != SSH_DEFAULT_PORT && !clobber_port) {
1120                         debug("checking without port identifier");
1121                         if (check_host_key(hostname, cinfo, hostaddr, 0,
1122                             host_key, ROQUIET, 1,
1123                             user_hostfiles, num_user_hostfiles,
1124                             system_hostfiles, num_system_hostfiles,
1125                             hostfile_command) == 0) {
1126                                 debug("found matching key w/out port");
1127                                 break;
1128                         }
1129                 }
1130                 if (readonly || want_cert)
1131                         goto fail;
1132                 /* The host is new. */
1133                 if (options.strict_host_key_checking ==
1134                     SSH_STRICT_HOSTKEY_YES) {
1135                         /*
1136                          * User has requested strict host key checking.  We
1137                          * will not add the host key automatically.  The only
1138                          * alternative left is to abort.
1139                          */
1140                         error("No %s host key is known for %.200s and you "
1141                             "have requested strict checking.", type, host);
1142                         goto fail;
1143                 } else if (options.strict_host_key_checking ==
1144                     SSH_STRICT_HOSTKEY_ASK) {
1145                         char *msg1 = NULL, *msg2 = NULL;
1146
1147                         xasprintf(&msg1, "The authenticity of host "
1148                             "'%.200s (%s)' can't be established", host, ip);
1149
1150                         if (show_other_keys(host_hostkeys, host_key)) {
1151                                 xextendf(&msg1, "\n", "but keys of different "
1152                                     "type are already known for this host.");
1153                         } else
1154                                 xextendf(&msg1, "", ".");
1155
1156                         fp = sshkey_fingerprint(host_key,
1157                             options.fingerprint_hash, SSH_FP_DEFAULT);
1158                         ra = sshkey_fingerprint(host_key,
1159                             options.fingerprint_hash, SSH_FP_RANDOMART);
1160                         if (fp == NULL || ra == NULL)
1161                                 fatal_f("sshkey_fingerprint failed");
1162                         xextendf(&msg1, "\n", "%s key fingerprint is %s.",
1163                             type, fp);
1164                         if (options.visual_host_key)
1165                                 xextendf(&msg1, "\n", "%s", ra);
1166                         if (options.verify_host_key_dns) {
1167                                 xextendf(&msg1, "\n",
1168                                     "%s host key fingerprint found in DNS.",
1169                                     matching_host_key_dns ?
1170                                     "Matching" : "No matching");
1171                         }
1172                         /* msg2 informs for other names matching this key */
1173                         if ((msg2 = other_hostkeys_message(host, ip, host_key,
1174                             user_hostfiles, num_user_hostfiles,
1175                             system_hostfiles, num_system_hostfiles)) != NULL)
1176                                 xextendf(&msg1, "\n", "%s", msg2);
1177
1178                         xextendf(&msg1, "\n",
1179                             "Are you sure you want to continue connecting "
1180                             "(yes/no/[fingerprint])? ");
1181
1182                         confirmed = confirm(msg1, fp);
1183                         free(ra);
1184                         free(fp);
1185                         free(msg1);
1186                         free(msg2);
1187                         if (!confirmed)
1188                                 goto fail;
1189                         hostkey_trusted = 1; /* user explicitly confirmed */
1190                 }
1191                 /*
1192                  * If in "new" or "off" strict mode, add the key automatically
1193                  * to the local known_hosts file.
1194                  */
1195                 if (options.check_host_ip && ip_status == HOST_NEW) {
1196                         snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
1197                         hostp = hostline;
1198                         if (options.hash_known_hosts) {
1199                                 /* Add hash of host and IP separately */
1200                                 r = add_host_to_hostfile(user_hostfiles[0],
1201                                     host, host_key, options.hash_known_hosts) &&
1202                                     add_host_to_hostfile(user_hostfiles[0], ip,
1203                                     host_key, options.hash_known_hosts);
1204                         } else {
1205                                 /* Add unhashed "host,ip" */
1206                                 r = add_host_to_hostfile(user_hostfiles[0],
1207                                     hostline, host_key,
1208                                     options.hash_known_hosts);
1209                         }
1210                 } else {
1211                         r = add_host_to_hostfile(user_hostfiles[0], host,
1212                             host_key, options.hash_known_hosts);
1213                         hostp = host;
1214                 }
1215
1216                 if (!r)
1217                         logit("Failed to add the host to the list of known "
1218                             "hosts (%.500s).", user_hostfiles[0]);
1219                 else
1220                         logit("Warning: Permanently added '%.200s' (%s) to the "
1221                             "list of known hosts.", hostp, type);
1222                 break;
1223         case HOST_REVOKED:
1224                 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1225                 error("@       WARNING: REVOKED HOST KEY DETECTED!               @");
1226                 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1227                 error("The %s host key for %s is marked as revoked.", type, host);
1228                 error("This could mean that a stolen key is being used to");
1229                 error("impersonate this host.");
1230
1231                 /*
1232                  * If strict host key checking is in use, the user will have
1233                  * to edit the key manually and we can only abort.
1234                  */
1235                 if (options.strict_host_key_checking !=
1236                     SSH_STRICT_HOSTKEY_OFF) {
1237                         error("%s host key for %.200s was revoked and you have "
1238                             "requested strict checking.", type, host);
1239                         goto fail;
1240                 }
1241                 goto continue_unsafe;
1242
1243         case HOST_CHANGED:
1244                 if (want_cert) {
1245                         /*
1246                          * This is only a debug() since it is valid to have
1247                          * CAs with wildcard DNS matches that don't match
1248                          * all hosts that one might visit.
1249                          */
1250                         debug("Host certificate authority does not "
1251                             "match %s in %s:%lu", CA_MARKER,
1252                             host_found->file, host_found->line);
1253                         goto fail;
1254                 }
1255                 if (readonly == ROQUIET)
1256                         goto fail;
1257                 if (options.check_host_ip && host_ip_differ) {
1258                         char *key_msg;
1259                         if (ip_status == HOST_NEW)
1260                                 key_msg = "is unknown";
1261                         else if (ip_status == HOST_OK)
1262                                 key_msg = "is unchanged";
1263                         else
1264                                 key_msg = "has a different value";
1265                         error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1266                         error("@       WARNING: POSSIBLE DNS SPOOFING DETECTED!          @");
1267                         error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1268                         error("The %s host key for %s has changed,", type, host);
1269                         error("and the key for the corresponding IP address %s", ip);
1270                         error("%s. This could either mean that", key_msg);
1271                         error("DNS SPOOFING is happening or the IP address for the host");
1272                         error("and its host key have changed at the same time.");
1273                         if (ip_status != HOST_NEW)
1274                                 error("Offending key for IP in %s:%lu",
1275                                     ip_found->file, ip_found->line);
1276                 }
1277                 /* The host key has changed. */
1278                 warn_changed_key(host_key);
1279                 if (num_user_hostfiles > 0 || num_system_hostfiles > 0) {
1280                         error("Add correct host key in %.100s to get rid "
1281                             "of this message.", num_user_hostfiles > 0 ?
1282                             user_hostfiles[0] : system_hostfiles[0]);
1283                 }
1284                 error("Offending %s key in %s:%lu",
1285                     sshkey_type(host_found->key),
1286                     host_found->file, host_found->line);
1287
1288                 /*
1289                  * If strict host key checking is in use, the user will have
1290                  * to edit the key manually and we can only abort.
1291                  */
1292                 if (options.strict_host_key_checking !=
1293                     SSH_STRICT_HOSTKEY_OFF) {
1294                         error("Host key for %.200s has changed and you have "
1295                             "requested strict checking.", host);
1296                         goto fail;
1297                 }
1298
1299  continue_unsafe:
1300                 /*
1301                  * If strict host key checking has not been requested, allow
1302                  * the connection but without MITM-able authentication or
1303                  * forwarding.
1304                  */
1305                 if (options.password_authentication) {
1306                         error("Password authentication is disabled to avoid "
1307                             "man-in-the-middle attacks.");
1308                         options.password_authentication = 0;
1309                         cancelled_forwarding = 1;
1310                 }
1311                 if (options.kbd_interactive_authentication) {
1312                         error("Keyboard-interactive authentication is disabled"
1313                             " to avoid man-in-the-middle attacks.");
1314                         options.kbd_interactive_authentication = 0;
1315                         cancelled_forwarding = 1;
1316                 }
1317                 if (options.forward_agent) {
1318                         error("Agent forwarding is disabled to avoid "
1319                             "man-in-the-middle attacks.");
1320                         options.forward_agent = 0;
1321                         cancelled_forwarding = 1;
1322                 }
1323                 if (options.forward_x11) {
1324                         error("X11 forwarding is disabled to avoid "
1325                             "man-in-the-middle attacks.");
1326                         options.forward_x11 = 0;
1327                         cancelled_forwarding = 1;
1328                 }
1329                 if (options.num_local_forwards > 0 ||
1330                     options.num_remote_forwards > 0) {
1331                         error("Port forwarding is disabled to avoid "
1332                             "man-in-the-middle attacks.");
1333                         options.num_local_forwards =
1334                             options.num_remote_forwards = 0;
1335                         cancelled_forwarding = 1;
1336                 }
1337                 if (options.tun_open != SSH_TUNMODE_NO) {
1338                         error("Tunnel forwarding is disabled to avoid "
1339                             "man-in-the-middle attacks.");
1340                         options.tun_open = SSH_TUNMODE_NO;
1341                         cancelled_forwarding = 1;
1342                 }
1343                 if (options.update_hostkeys != 0) {
1344                         error("UpdateHostkeys is disabled because the host "
1345                             "key is not trusted.");
1346                         options.update_hostkeys = 0;
1347                 }
1348                 if (options.exit_on_forward_failure && cancelled_forwarding)
1349                         fatal("Error: forwarding disabled due to host key "
1350                             "check failure");
1351
1352                 /*
1353                  * XXX Should permit the user to change to use the new id.
1354                  * This could be done by converting the host key to an
1355                  * identifying sentence, tell that the host identifies itself
1356                  * by that sentence, and ask the user if they wish to
1357                  * accept the authentication.
1358                  */
1359                 break;
1360         case HOST_FOUND:
1361                 fatal("internal error");
1362                 break;
1363         }
1364
1365         if (options.check_host_ip && host_status != HOST_CHANGED &&
1366             ip_status == HOST_CHANGED) {
1367                 snprintf(msg, sizeof(msg),
1368                     "Warning: the %s host key for '%.200s' "
1369                     "differs from the key for the IP address '%.128s'"
1370                     "\nOffending key for IP in %s:%lu",
1371                     type, host, ip, ip_found->file, ip_found->line);
1372                 if (host_status == HOST_OK) {
1373                         len = strlen(msg);
1374                         snprintf(msg + len, sizeof(msg) - len,
1375                             "\nMatching host key in %s:%lu",
1376                             host_found->file, host_found->line);
1377                 }
1378                 if (options.strict_host_key_checking ==
1379                     SSH_STRICT_HOSTKEY_ASK) {
1380                         strlcat(msg, "\nAre you sure you want "
1381                             "to continue connecting (yes/no)? ", sizeof(msg));
1382                         if (!confirm(msg, NULL))
1383                                 goto fail;
1384                 } else if (options.strict_host_key_checking !=
1385                     SSH_STRICT_HOSTKEY_OFF) {
1386                         logit("%s", msg);
1387                         error("Exiting, you have requested strict checking.");
1388                         goto fail;
1389                 } else {
1390                         logit("%s", msg);
1391                 }
1392         }
1393
1394         if (!hostkey_trusted && options.update_hostkeys) {
1395                 debug_f("hostkey not known or explicitly trusted: "
1396                     "disabling UpdateHostkeys");
1397                 options.update_hostkeys = 0;
1398         }
1399
1400         free(ip);
1401         free(host);
1402         if (host_hostkeys != NULL)
1403                 free_hostkeys(host_hostkeys);
1404         if (ip_hostkeys != NULL)
1405                 free_hostkeys(ip_hostkeys);
1406         return 0;
1407
1408 fail:
1409         if (want_cert && host_status != HOST_REVOKED) {
1410                 /*
1411                  * No matching certificate. Downgrade cert to raw key and
1412                  * search normally.
1413                  */
1414                 debug("No matching CA found. Retry with plain key");
1415                 if ((r = sshkey_from_private(host_key, &raw_key)) != 0)
1416                         fatal_fr(r, "decode key");
1417                 if ((r = sshkey_drop_cert(raw_key)) != 0)
1418                         fatal_r(r, "Couldn't drop certificate");
1419                 host_key = raw_key;
1420                 goto retry;
1421         }
1422         sshkey_free(raw_key);
1423         free(ip);
1424         free(host);
1425         if (host_hostkeys != NULL)
1426                 free_hostkeys(host_hostkeys);
1427         if (ip_hostkeys != NULL)
1428                 free_hostkeys(ip_hostkeys);
1429         return -1;
1430 }
1431
1432 /* returns 0 if key verifies or -1 if key does NOT verify */
1433 int
1434 verify_host_key(char *host, struct sockaddr *hostaddr, struct sshkey *host_key,
1435     const struct ssh_conn_info *cinfo)
1436 {
1437         u_int i;
1438         int r = -1, flags = 0;
1439         char valid[64], *fp = NULL, *cafp = NULL;
1440         struct sshkey *plain = NULL;
1441
1442         if ((fp = sshkey_fingerprint(host_key,
1443             options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
1444                 error_fr(r, "fingerprint host key");
1445                 r = -1;
1446                 goto out;
1447         }
1448
1449         if (sshkey_is_cert(host_key)) {
1450                 if ((cafp = sshkey_fingerprint(host_key->cert->signature_key,
1451                     options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
1452                         error_fr(r, "fingerprint CA key");
1453                         r = -1;
1454                         goto out;
1455                 }
1456                 sshkey_format_cert_validity(host_key->cert,
1457                     valid, sizeof(valid));
1458                 debug("Server host certificate: %s %s, serial %llu "
1459                     "ID \"%s\" CA %s %s valid %s",
1460                     sshkey_ssh_name(host_key), fp,
1461                     (unsigned long long)host_key->cert->serial,
1462                     host_key->cert->key_id,
1463                     sshkey_ssh_name(host_key->cert->signature_key), cafp,
1464                     valid);
1465                 for (i = 0; i < host_key->cert->nprincipals; i++) {
1466                         debug2("Server host certificate hostname: %s",
1467                             host_key->cert->principals[i]);
1468                 }
1469         } else {
1470                 debug("Server host key: %s %s", sshkey_ssh_name(host_key), fp);
1471         }
1472
1473         if (sshkey_equal(previous_host_key, host_key)) {
1474                 debug2_f("server host key %s %s matches cached key",
1475                     sshkey_type(host_key), fp);
1476                 r = 0;
1477                 goto out;
1478         }
1479
1480         /* Check in RevokedHostKeys file if specified */
1481         if (options.revoked_host_keys != NULL) {
1482                 r = sshkey_check_revoked(host_key, options.revoked_host_keys);
1483                 switch (r) {
1484                 case 0:
1485                         break; /* not revoked */
1486                 case SSH_ERR_KEY_REVOKED:
1487                         error("Host key %s %s revoked by file %s",
1488                             sshkey_type(host_key), fp,
1489                             options.revoked_host_keys);
1490                         r = -1;
1491                         goto out;
1492                 default:
1493                         error_r(r, "Error checking host key %s %s in "
1494                             "revoked keys file %s", sshkey_type(host_key),
1495                             fp, options.revoked_host_keys);
1496                         r = -1;
1497                         goto out;
1498                 }
1499         }
1500
1501         if (options.verify_host_key_dns) {
1502                 /*
1503                  * XXX certs are not yet supported for DNS, so downgrade
1504                  * them and try the plain key.
1505                  */
1506                 if ((r = sshkey_from_private(host_key, &plain)) != 0)
1507                         goto out;
1508                 if (sshkey_is_cert(plain))
1509                         sshkey_drop_cert(plain);
1510                 if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) {
1511                         if (flags & DNS_VERIFY_FOUND) {
1512                                 if (options.verify_host_key_dns == 1 &&
1513                                     flags & DNS_VERIFY_MATCH &&
1514                                     flags & DNS_VERIFY_SECURE) {
1515                                         r = 0;
1516                                         goto out;
1517                                 }
1518                                 if (flags & DNS_VERIFY_MATCH) {
1519                                         matching_host_key_dns = 1;
1520                                 } else {
1521                                         warn_changed_key(plain);
1522                                         error("Update the SSHFP RR in DNS "
1523                                             "with the new host key to get rid "
1524                                             "of this message.");
1525                                 }
1526                         }
1527                 }
1528         }
1529         r = check_host_key(host, cinfo, hostaddr, options.port, host_key,
1530             RDRW, 0, options.user_hostfiles, options.num_user_hostfiles,
1531             options.system_hostfiles, options.num_system_hostfiles,
1532             options.known_hosts_command);
1533
1534 out:
1535         sshkey_free(plain);
1536         free(fp);
1537         free(cafp);
1538         if (r == 0 && host_key != NULL) {
1539                 sshkey_free(previous_host_key);
1540                 r = sshkey_from_private(host_key, &previous_host_key);
1541         }
1542
1543         return r;
1544 }
1545
1546 /*
1547  * Starts a dialog with the server, and authenticates the current user on the
1548  * server.  This does not need any extra privileges.  The basic connection
1549  * to the server must already have been established before this is called.
1550  * If login fails, this function prints an error and never returns.
1551  * This function does not require super-user privileges.
1552  */
1553 void
1554 ssh_login(struct ssh *ssh, Sensitive *sensitive, const char *orighost,
1555     struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms,
1556     const struct ssh_conn_info *cinfo)
1557 {
1558         char *host;
1559         char *server_user, *local_user;
1560         int r;
1561
1562         local_user = xstrdup(pw->pw_name);
1563         server_user = options.user ? options.user : local_user;
1564
1565         /* Convert the user-supplied hostname into all lowercase. */
1566         host = xstrdup(orighost);
1567         lowercase(host);
1568
1569         /* Exchange protocol version identification strings with the server. */
1570         if ((r = kex_exchange_identification(ssh, timeout_ms, NULL)) != 0)
1571                 sshpkt_fatal(ssh, r, "banner exchange");
1572
1573         /* Put the connection into non-blocking mode. */
1574         ssh_packet_set_nonblocking(ssh);
1575
1576         /* key exchange */
1577         /* authenticate user */
1578         debug("Authenticating to %s:%d as '%s'", host, port, server_user);
1579         ssh_kex2(ssh, host, hostaddr, port, cinfo);
1580         ssh_userauth2(ssh, local_user, server_user, host, sensitive);
1581         free(local_user);
1582         free(host);
1583 }
1584
1585 /* print all known host keys for a given host, but skip keys of given type */
1586 static int
1587 show_other_keys(struct hostkeys *hostkeys, struct sshkey *key)
1588 {
1589         int type[] = {
1590                 KEY_RSA,
1591                 KEY_DSA,
1592                 KEY_ECDSA,
1593                 KEY_ED25519,
1594                 KEY_XMSS,
1595                 -1
1596         };
1597         int i, ret = 0;
1598         char *fp, *ra;
1599         const struct hostkey_entry *found;
1600
1601         for (i = 0; type[i] != -1; i++) {
1602                 if (type[i] == key->type)
1603                         continue;
1604                 if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i],
1605                     -1, &found))
1606                         continue;
1607                 fp = sshkey_fingerprint(found->key,
1608                     options.fingerprint_hash, SSH_FP_DEFAULT);
1609                 ra = sshkey_fingerprint(found->key,
1610                     options.fingerprint_hash, SSH_FP_RANDOMART);
1611                 if (fp == NULL || ra == NULL)
1612                         fatal_f("sshkey_fingerprint fail");
1613                 logit("WARNING: %s key found for host %s\n"
1614                     "in %s:%lu\n"
1615                     "%s key fingerprint %s.",
1616                     sshkey_type(found->key),
1617                     found->host, found->file, found->line,
1618                     sshkey_type(found->key), fp);
1619                 if (options.visual_host_key)
1620                         logit("%s", ra);
1621                 free(ra);
1622                 free(fp);
1623                 ret = 1;
1624         }
1625         return ret;
1626 }
1627
1628 static void
1629 warn_changed_key(struct sshkey *host_key)
1630 {
1631         char *fp;
1632
1633         fp = sshkey_fingerprint(host_key, options.fingerprint_hash,
1634             SSH_FP_DEFAULT);
1635         if (fp == NULL)
1636                 fatal_f("sshkey_fingerprint fail");
1637
1638         error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1639         error("@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @");
1640         error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1641         error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
1642         error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
1643         error("It is also possible that a host key has just been changed.");
1644         error("The fingerprint for the %s key sent by the remote host is\n%s.",
1645             sshkey_type(host_key), fp);
1646         error("Please contact your system administrator.");
1647
1648         free(fp);
1649 }
1650
1651 /*
1652  * Execute a local command
1653  */
1654 int
1655 ssh_local_cmd(const char *args)
1656 {
1657         char *shell;
1658         pid_t pid;
1659         int status;
1660         void (*osighand)(int);
1661
1662         if (!options.permit_local_command ||
1663             args == NULL || !*args)
1664                 return (1);
1665
1666         if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
1667                 shell = _PATH_BSHELL;
1668
1669         osighand = ssh_signal(SIGCHLD, SIG_DFL);
1670         pid = fork();
1671         if (pid == 0) {
1672                 ssh_signal(SIGPIPE, SIG_DFL);
1673                 debug3("Executing %s -c \"%s\"", shell, args);
1674                 execl(shell, shell, "-c", args, (char *)NULL);
1675                 error("Couldn't execute %s -c \"%s\": %s",
1676                     shell, args, strerror(errno));
1677                 _exit(1);
1678         } else if (pid == -1)
1679                 fatal("fork failed: %.100s", strerror(errno));
1680         while (waitpid(pid, &status, 0) == -1)
1681                 if (errno != EINTR)
1682                         fatal("Couldn't wait for child: %s", strerror(errno));
1683         ssh_signal(SIGCHLD, osighand);
1684
1685         if (!WIFEXITED(status))
1686                 return (1);
1687
1688         return (WEXITSTATUS(status));
1689 }
1690
1691 void
1692 maybe_add_key_to_agent(const char *authfile, struct sshkey *private,
1693     const char *comment, const char *passphrase)
1694 {
1695         int auth_sock = -1, r;
1696         const char *skprovider = NULL;
1697
1698         if (options.add_keys_to_agent == 0)
1699                 return;
1700
1701         if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) {
1702                 debug3("no authentication agent, not adding key");
1703                 return;
1704         }
1705
1706         if (options.add_keys_to_agent == 2 &&
1707             !ask_permission("Add key %s (%s) to agent?", authfile, comment)) {
1708                 debug3("user denied adding this key");
1709                 close(auth_sock);
1710                 return;
1711         }
1712         if (sshkey_is_sk(private))
1713                 skprovider = options.sk_provider;
1714         if ((r = ssh_add_identity_constrained(auth_sock, private,
1715             comment == NULL ? authfile : comment,
1716             options.add_keys_to_agent_lifespan,
1717             (options.add_keys_to_agent == 3), 0, skprovider, NULL, 0)) == 0)
1718                 debug("identity added to agent: %s", authfile);
1719         else
1720                 debug("could not add identity to agent: %s (%d)", authfile, r);
1721         close(auth_sock);
1722 }