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