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