1 /* $OpenBSD: sshconnect.c,v 1.358 2022/08/26 08:16:27 djm Exp $ */
3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6 * Code to connect to a remote host, and to perform the client side of the
7 * login (authentication) dialog.
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".
18 #include <sys/types.h>
21 #include <sys/socket.h>
22 #ifdef HAVE_SYS_TIME_H
23 # include <sys/time.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
59 #include "sshconnect.h"
65 #include "monitor_fdpass.h"
73 struct sshkey
*previous_host_key
= NULL
;
75 static int matching_host_key_dns
= 0;
77 static pid_t proxy_command_pid
= 0;
80 extern int debug_flag
;
81 extern Options options
;
82 extern char *__progname
;
84 static int show_other_keys(struct hostkeys
*, struct sshkey
*);
85 static void warn_changed_key(struct sshkey
*);
87 /* Expand a proxy command */
89 expand_proxy_command(const char *proxy_command
, const char *user
,
90 const char *host
, const char *host_arg
, int port
)
92 char *tmp
, *ret
, strport
[NI_MAXSERV
];
93 const char *keyalias
= options
.host_key_alias
?
94 options
.host_key_alias
: host_arg
;
96 snprintf(strport
, sizeof strport
, "%d", port
);
97 xasprintf(&tmp
, "exec %s", proxy_command
);
98 ret
= percent_expand(tmp
,
110 * Connect to the given ssh server using a proxy command that passes a
111 * a connected fd back to us.
114 ssh_proxy_fdpass_connect(struct ssh
*ssh
, const char *host
,
115 const char *host_arg
, u_short port
, const char *proxy_command
)
117 char *command_string
;
122 if ((shell
= getenv("SHELL")) == NULL
)
123 shell
= _PATH_BSHELL
;
125 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, sp
) == -1)
126 fatal("Could not create socketpair to communicate with "
127 "proxy dialer: %.100s", strerror(errno
));
129 command_string
= expand_proxy_command(proxy_command
, options
.user
,
130 host
, host_arg
, port
);
131 debug("Executing proxy dialer command: %.500s", command_string
);
133 /* Fork and execute the proxy command. */
134 if ((pid
= fork()) == 0) {
138 /* Redirect stdin and stdout. */
140 if (dup2(sp
[0], 0) == -1)
141 perror("dup2 stdin");
144 if (dup2(sp
[0], 1) == -1)
145 perror("dup2 stdout");
151 * Stderr is left for non-ControlPersist connections is so
152 * error messages may be printed on the user's terminal.
154 if (!debug_flag
&& options
.control_path
!= NULL
&&
155 options
.control_persist
&& stdfd_devnull(0, 0, 1) == -1)
156 error_f("stdfd_devnull failed");
160 argv
[2] = command_string
;
164 * Execute the proxy command.
165 * Note that we gave up any extra privileges above.
167 execv(argv
[0], argv
);
173 fatal("fork failed: %.100s", strerror(errno
));
175 free(command_string
);
177 if ((sock
= mm_receive_fd(sp
[1])) == -1)
178 fatal("proxy dialer did not pass back a connection");
181 while (waitpid(pid
, NULL
, 0) == -1)
183 fatal("Couldn't wait for child: %s", strerror(errno
));
185 /* Set the connection file descriptors. */
186 if (ssh_packet_set_connection(ssh
, sock
, sock
) == NULL
)
187 return -1; /* ssh_packet_set_connection logs error */
193 * Connect to the given ssh server using a proxy command.
196 ssh_proxy_connect(struct ssh
*ssh
, const char *host
, const char *host_arg
,
197 u_short port
, const char *proxy_command
)
199 char *command_string
;
204 if ((shell
= getenv("SHELL")) == NULL
|| *shell
== '\0')
205 shell
= _PATH_BSHELL
;
207 /* Create pipes for communicating with the proxy. */
208 if (pipe(pin
) == -1 || pipe(pout
) == -1)
209 fatal("Could not create pipes to communicate with the proxy: %.100s",
212 command_string
= expand_proxy_command(proxy_command
, options
.user
,
213 host
, host_arg
, port
);
214 debug("Executing proxy command: %.500s", command_string
);
216 /* Fork and execute the proxy command. */
217 if ((pid
= fork()) == 0) {
220 /* Redirect stdin and stdout. */
223 if (dup2(pin
[0], 0) == -1)
224 perror("dup2 stdin");
228 if (dup2(pout
[1], 1) == -1)
229 perror("dup2 stdout");
230 /* Cannot be 1 because pin allocated two descriptors. */
234 * Stderr is left for non-ControlPersist connections is so
235 * error messages may be printed on the user's terminal.
237 if (!debug_flag
&& options
.control_path
!= NULL
&&
238 options
.control_persist
&& stdfd_devnull(0, 0, 1) == -1)
239 error_f("stdfd_devnull failed");
243 argv
[2] = command_string
;
247 * Execute the proxy command. Note that we gave up any
248 * extra privileges above.
250 ssh_signal(SIGPIPE
, SIG_DFL
);
251 execv(argv
[0], argv
);
257 fatal("fork failed: %.100s", strerror(errno
));
259 proxy_command_pid
= pid
; /* save pid to clean up later */
261 /* Close child side of the descriptors. */
265 /* Free the command name. */
266 free(command_string
);
268 /* Set the connection file descriptors. */
269 if (ssh_packet_set_connection(ssh
, pout
[0], pin
[1]) == NULL
)
270 return -1; /* ssh_packet_set_connection logs error */
276 ssh_kill_proxy_command(void)
279 * Send SIGHUP to proxy command if used. We don't wait() in
280 * case it hangs and instead rely on init to reap the child
282 if (proxy_command_pid
> 1)
283 kill(proxy_command_pid
, SIGHUP
);
286 #ifdef HAVE_IFADDRS_H
288 * Search a interface address list (returned from getifaddrs(3)) for an
289 * address that matches the desired address family on the specified interface.
290 * Returns 0 and fills in *resultp and *rlenp on success. Returns -1 on failure.
293 check_ifaddrs(const char *ifname
, int af
, const struct ifaddrs
*ifaddrs
,
294 struct sockaddr_storage
*resultp
, socklen_t
*rlenp
)
296 struct sockaddr_in6
*sa6
;
297 struct sockaddr_in
*sa
;
298 struct in6_addr
*v6addr
;
299 const struct ifaddrs
*ifa
;
303 * Prefer addresses that are not loopback or linklocal, but use them
304 * if nothing else matches.
306 for (allow_local
= 0; allow_local
< 2; allow_local
++) {
307 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
308 if (ifa
->ifa_addr
== NULL
|| ifa
->ifa_name
== NULL
||
309 (ifa
->ifa_flags
& IFF_UP
) == 0 ||
310 ifa
->ifa_addr
->sa_family
!= af
||
311 strcmp(ifa
->ifa_name
, options
.bind_interface
) != 0)
313 switch (ifa
->ifa_addr
->sa_family
) {
315 sa
= (struct sockaddr_in
*)ifa
->ifa_addr
;
316 if (!allow_local
&& sa
->sin_addr
.s_addr
==
317 htonl(INADDR_LOOPBACK
))
319 if (*rlenp
< sizeof(struct sockaddr_in
)) {
320 error_f("v4 addr doesn't fit");
323 *rlenp
= sizeof(struct sockaddr_in
);
324 memcpy(resultp
, sa
, *rlenp
);
327 sa6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
328 v6addr
= &sa6
->sin6_addr
;
330 (IN6_IS_ADDR_LINKLOCAL(v6addr
) ||
331 IN6_IS_ADDR_LOOPBACK(v6addr
)))
333 if (*rlenp
< sizeof(struct sockaddr_in6
)) {
334 error_f("v6 addr doesn't fit");
337 *rlenp
= sizeof(struct sockaddr_in6
);
338 memcpy(resultp
, sa6
, *rlenp
);
348 * Creates a socket for use as the ssh connection.
351 ssh_create_socket(struct addrinfo
*ai
)
354 struct sockaddr_storage bindaddr
;
355 socklen_t bindaddrlen
= 0;
356 struct addrinfo hints
, *res
= NULL
;
357 #ifdef HAVE_IFADDRS_H
358 struct ifaddrs
*ifaddrs
= NULL
;
360 char ntop
[NI_MAXHOST
];
362 sock
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
364 error("socket: %s", strerror(errno
));
367 fcntl(sock
, F_SETFD
, FD_CLOEXEC
);
369 /* Use interactive QOS (if specified) until authentication completed */
370 if (options
.ip_qos_interactive
!= INT_MAX
)
371 set_sock_tos(sock
, options
.ip_qos_interactive
);
373 /* Bind the socket to an alternative local IP address */
374 if (options
.bind_address
== NULL
&& options
.bind_interface
== NULL
)
377 if (options
.bind_address
!= NULL
) {
378 memset(&hints
, 0, sizeof(hints
));
379 hints
.ai_family
= ai
->ai_family
;
380 hints
.ai_socktype
= ai
->ai_socktype
;
381 hints
.ai_protocol
= ai
->ai_protocol
;
382 hints
.ai_flags
= AI_PASSIVE
;
383 if ((r
= getaddrinfo(options
.bind_address
, NULL
,
384 &hints
, &res
)) != 0) {
385 error("getaddrinfo: %s: %s", options
.bind_address
,
386 ssh_gai_strerror(r
));
390 error("getaddrinfo: no addrs");
393 memcpy(&bindaddr
, res
->ai_addr
, res
->ai_addrlen
);
394 bindaddrlen
= res
->ai_addrlen
;
395 } else if (options
.bind_interface
!= NULL
) {
396 #ifdef HAVE_IFADDRS_H
397 if ((r
= getifaddrs(&ifaddrs
)) != 0) {
398 error("getifaddrs: %s: %s", options
.bind_interface
,
402 bindaddrlen
= sizeof(bindaddr
);
403 if (check_ifaddrs(options
.bind_interface
, ai
->ai_family
,
404 ifaddrs
, &bindaddr
, &bindaddrlen
) != 0) {
405 logit("getifaddrs: %s: no suitable addresses",
406 options
.bind_interface
);
410 error("BindInterface not supported on this platform.");
413 if ((r
= getnameinfo((struct sockaddr
*)&bindaddr
, bindaddrlen
,
414 ntop
, sizeof(ntop
), NULL
, 0, NI_NUMERICHOST
)) != 0) {
415 error_f("getnameinfo failed: %s", ssh_gai_strerror(r
));
418 if (bind(sock
, (struct sockaddr
*)&bindaddr
, bindaddrlen
) != 0) {
419 error("bind %s: %s", ntop
, strerror(errno
));
422 debug_f("bound to %s", ntop
);
431 #ifdef HAVE_IFADDRS_H
433 freeifaddrs(ifaddrs
);
439 * Opens a TCP/IP connection to the remote server on the given host.
440 * The address of the remote host will be returned in hostaddr.
441 * If port is 0, the default port will be used.
442 * Connection_attempts specifies the maximum number of tries (one per
443 * second). If proxy_command is non-NULL, it specifies the command (with %h
444 * and %p substituted for host and port, respectively) to use to contact
448 ssh_connect_direct(struct ssh
*ssh
, const char *host
, struct addrinfo
*aitop
,
449 struct sockaddr_storage
*hostaddr
, u_short port
, int connection_attempts
,
450 int *timeout_ms
, int want_keepalive
)
452 int on
= 1, saved_timeout_ms
= *timeout_ms
;
453 int oerrno
, sock
= -1, attempt
;
454 char ntop
[NI_MAXHOST
], strport
[NI_MAXSERV
];
457 debug3_f("entering");
458 memset(ntop
, 0, sizeof(ntop
));
459 memset(strport
, 0, sizeof(strport
));
461 for (attempt
= 0; attempt
< connection_attempts
; attempt
++) {
463 /* Sleep a moment before retrying. */
465 debug("Trying again...");
468 * Loop through addresses for this host, and try each one in
469 * sequence until the connection succeeds.
471 for (ai
= aitop
; ai
; ai
= ai
->ai_next
) {
472 if (ai
->ai_family
!= AF_INET
&&
473 ai
->ai_family
!= AF_INET6
) {
474 errno
= EAFNOSUPPORT
;
477 if (getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
478 ntop
, sizeof(ntop
), strport
, sizeof(strport
),
479 NI_NUMERICHOST
|NI_NUMERICSERV
) != 0) {
481 error_f("getnameinfo failed");
485 debug("Connecting to %.200s [%.100s] port %s.",
486 host
, ntop
, strport
);
488 /* Create a socket for connecting. */
489 sock
= ssh_create_socket(ai
);
491 /* Any error is already output */
496 *timeout_ms
= saved_timeout_ms
;
497 if (timeout_connect(sock
, ai
->ai_addr
, ai
->ai_addrlen
,
499 /* Successful connection. */
500 memcpy(hostaddr
, ai
->ai_addr
, ai
->ai_addrlen
);
504 debug("connect to address %s port %s: %s",
505 ntop
, strport
, strerror(errno
));
512 break; /* Successful connection. */
515 /* Return failure if we didn't get a successful connection. */
517 error("ssh: connect to host %s port %s: %s",
518 host
, strport
, errno
== 0 ? "failure" : strerror(errno
));
522 debug("Connection established.");
524 /* Set SO_KEEPALIVE if requested. */
525 if (want_keepalive
&&
526 setsockopt(sock
, SOL_SOCKET
, SO_KEEPALIVE
, (void *)&on
,
528 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno
));
530 /* Set the connection. */
531 if (ssh_packet_set_connection(ssh
, sock
, sock
) == NULL
)
532 return -1; /* ssh_packet_set_connection logs error */
538 ssh_connect(struct ssh
*ssh
, const char *host
, const char *host_arg
,
539 struct addrinfo
*addrs
, struct sockaddr_storage
*hostaddr
, u_short port
,
540 int connection_attempts
, int *timeout_ms
, int want_keepalive
)
544 if (options
.proxy_command
== NULL
) {
545 return ssh_connect_direct(ssh
, host
, addrs
, hostaddr
, port
,
546 connection_attempts
, timeout_ms
, want_keepalive
);
547 } else if (strcmp(options
.proxy_command
, "-") == 0) {
548 if ((in
= dup(STDIN_FILENO
)) == -1 ||
549 (out
= dup(STDOUT_FILENO
)) == -1) {
552 error_f("dup() in/out failed");
553 return -1; /* ssh_packet_set_connection logs error */
555 if ((ssh_packet_set_connection(ssh
, in
, out
)) == NULL
)
556 return -1; /* ssh_packet_set_connection logs error */
558 } else if (options
.proxy_use_fdpass
) {
559 return ssh_proxy_fdpass_connect(ssh
, host
, host_arg
, port
,
560 options
.proxy_command
);
562 return ssh_proxy_connect(ssh
, host
, host_arg
, port
,
563 options
.proxy_command
);
566 /* defaults to 'no' */
568 confirm(const char *prompt
, const char *fingerprint
)
570 const char *msg
, *again
= "Please type 'yes' or 'no': ";
571 const char *again_fp
= "Please type 'yes', 'no' or the fingerprint: ";
575 if (options
.batch_mode
)
577 for (msg
= prompt
;;msg
= fingerprint
? again_fp
: again
) {
578 cp
= p
= read_passphrase(msg
, RP_ECHO
);
581 p
+= strspn(p
, " \t"); /* skip leading whitespace */
582 p
[strcspn(p
, " \t\n")] = '\0'; /* remove trailing whitespace */
583 if (p
[0] == '\0' || strcasecmp(p
, "no") == 0)
585 else if (strcasecmp(p
, "yes") == 0 || (fingerprint
!= NULL
&&
586 strcmp(p
, fingerprint
) == 0))
595 sockaddr_is_local(struct sockaddr
*hostaddr
)
597 switch (hostaddr
->sa_family
) {
599 return (ntohl(((struct sockaddr_in
*)hostaddr
)->
600 sin_addr
.s_addr
) >> 24) == IN_LOOPBACKNET
;
602 return IN6_IS_ADDR_LOOPBACK(
603 &(((struct sockaddr_in6
*)hostaddr
)->sin6_addr
));
610 * Prepare the hostname and ip address strings that are used to lookup
611 * host keys in known_hosts files. These may have a port number appended.
614 get_hostfile_hostname_ipaddr(char *hostname
, struct sockaddr
*hostaddr
,
615 u_short port
, char **hostfile_hostname
, char **hostfile_ipaddr
)
617 char ntop
[NI_MAXHOST
];
620 switch (hostaddr
== NULL
? -1 : hostaddr
->sa_family
) {
625 addrlen
= sizeof(struct sockaddr_in
);
628 addrlen
= sizeof(struct sockaddr_in6
);
631 addrlen
= sizeof(struct sockaddr
);
636 * We don't have the remote ip-address for connections
637 * using a proxy command
639 if (hostfile_ipaddr
!= NULL
) {
640 if (options
.proxy_command
== NULL
) {
641 if (getnameinfo(hostaddr
, addrlen
,
642 ntop
, sizeof(ntop
), NULL
, 0, NI_NUMERICHOST
) != 0)
643 fatal_f("getnameinfo failed");
644 *hostfile_ipaddr
= put_host_port(ntop
, port
);
646 *hostfile_ipaddr
= xstrdup("<no hostip for proxy "
652 * Allow the user to record the key under a different name or
653 * differentiate a non-standard port. This is useful for ssh
654 * tunneling over forwarded connections or if you run multiple
655 * sshd's on different ports on the same machine.
657 if (hostfile_hostname
!= NULL
) {
658 if (options
.host_key_alias
!= NULL
) {
659 *hostfile_hostname
= xstrdup(options
.host_key_alias
);
660 debug("using hostkeyalias: %s", *hostfile_hostname
);
662 *hostfile_hostname
= put_host_port(hostname
, port
);
667 /* returns non-zero if path appears in hostfiles, or 0 if not. */
669 path_in_hostfiles(const char *path
, char **hostfiles
, u_int num_hostfiles
)
673 for (i
= 0; i
< num_hostfiles
; i
++) {
674 if (strcmp(path
, hostfiles
[i
]) == 0)
680 struct find_by_key_ctx
{
681 const char *host
, *ip
;
682 const struct sshkey
*key
;
687 /* Try to replace home directory prefix (per $HOME) with a ~/ sequence */
689 try_tilde_unexpand(const char *path
)
691 char *home
, *ret
= NULL
;
695 return xstrdup(path
);
696 if ((home
= getenv("HOME")) == NULL
|| (l
= strlen(home
)) == 0)
697 return xstrdup(path
);
698 if (strncmp(path
, home
, l
) != 0)
699 return xstrdup(path
);
701 * ensure we have matched on a path boundary: either the $HOME that
702 * we just compared ends with a '/' or the next character of the path
705 if (home
[l
- 1] != '/' && path
[l
] != '/')
706 return xstrdup(path
);
709 xasprintf(&ret
, "~/%s", path
+ l
);
714 hostkeys_find_by_key_cb(struct hostkey_foreach_line
*l
, void *_ctx
)
716 struct find_by_key_ctx
*ctx
= (struct find_by_key_ctx
*)_ctx
;
719 /* we are looking for keys with names that *do not* match */
720 if ((l
->match
& HKF_MATCH_HOST
) != 0)
722 /* not interested in marker lines */
723 if (l
->marker
!= MRK_NONE
)
725 /* we are only interested in exact key matches */
726 if (l
->key
== NULL
|| !sshkey_equal(ctx
->key
, l
->key
))
728 path
= try_tilde_unexpand(l
->path
);
729 debug_f("found matching key in %s:%lu", path
, l
->linenum
);
730 ctx
->names
= xrecallocarray(ctx
->names
,
731 ctx
->nnames
, ctx
->nnames
+ 1, sizeof(*ctx
->names
));
732 xasprintf(&ctx
->names
[ctx
->nnames
], "%s:%lu: %s", path
, l
->linenum
,
733 strncmp(l
->hosts
, HASH_MAGIC
, strlen(HASH_MAGIC
)) == 0 ?
734 "[hashed name]" : l
->hosts
);
741 hostkeys_find_by_key_hostfile(const char *file
, const char *which
,
742 struct find_by_key_ctx
*ctx
)
746 debug3_f("trying %s hostfile \"%s\"", which
, file
);
747 if ((r
= hostkeys_foreach(file
, hostkeys_find_by_key_cb
, ctx
,
748 ctx
->host
, ctx
->ip
, HKF_WANT_PARSE_KEY
, 0)) != 0) {
749 if (r
== SSH_ERR_SYSTEM_ERROR
&& errno
== ENOENT
) {
750 debug_f("hostkeys file %s does not exist", file
);
753 error_fr(r
, "hostkeys_foreach failed for %s", file
);
760 * Find 'key' in known hosts file(s) that do not match host/ip.
761 * Used to display also-known-as information for previously-unseen hostkeys.
764 hostkeys_find_by_key(const char *host
, const char *ip
, const struct sshkey
*key
,
765 char **user_hostfiles
, u_int num_user_hostfiles
,
766 char **system_hostfiles
, u_int num_system_hostfiles
,
767 char ***names
, u_int
*nnames
)
769 struct find_by_key_ctx ctx
= {0, 0, 0, 0, 0};
775 if (key
== NULL
|| sshkey_is_cert(key
))
782 for (i
= 0; i
< num_user_hostfiles
; i
++) {
783 if (hostkeys_find_by_key_hostfile(user_hostfiles
[i
],
787 for (i
= 0; i
< num_system_hostfiles
; i
++) {
788 if (hostkeys_find_by_key_hostfile(system_hostfiles
[i
],
789 "system", &ctx
) != 0)
794 *nnames
= ctx
.nnames
;
799 for (i
= 0; i
< ctx
.nnames
; i
++)
804 #define MAX_OTHER_NAMES 8 /* Maximum number of names to list */
806 other_hostkeys_message(const char *host
, const char *ip
,
807 const struct sshkey
*key
,
808 char **user_hostfiles
, u_int num_user_hostfiles
,
809 char **system_hostfiles
, u_int num_system_hostfiles
)
811 char *ret
= NULL
, **othernames
= NULL
;
812 u_int i
, n
, num_othernames
= 0;
814 hostkeys_find_by_key(host
, ip
, key
,
815 user_hostfiles
, num_user_hostfiles
,
816 system_hostfiles
, num_system_hostfiles
,
817 &othernames
, &num_othernames
);
818 if (num_othernames
== 0)
819 return xstrdup("This key is not known by any other names.");
821 xasprintf(&ret
, "This host key is known by the following other "
825 if (n
> MAX_OTHER_NAMES
)
827 for (i
= 0; i
< n
; i
++) {
828 xextendf(&ret
, "\n", " %s", othernames
[i
]);
830 if (n
< num_othernames
) {
831 xextendf(&ret
, "\n", " (%d additional names omitted)",
834 for (i
= 0; i
< num_othernames
; i
++)
841 load_hostkeys_command(struct hostkeys
*hostkeys
, const char *command_template
,
842 const char *invocation
, const struct ssh_conn_info
*cinfo
,
843 const struct sshkey
*host_key
, const char *hostfile_hostname
)
846 char *key_fp
= NULL
, *keytext
= NULL
, *tmp
;
847 char *command
= NULL
, *tag
= NULL
, **av
= NULL
;
850 void (*osigchld
)(int);
852 xasprintf(&tag
, "KnownHostsCommand-%s", invocation
);
854 if (host_key
!= NULL
) {
855 if ((key_fp
= sshkey_fingerprint(host_key
,
856 options
.fingerprint_hash
, SSH_FP_DEFAULT
)) == NULL
)
857 fatal_f("sshkey_fingerprint failed");
858 if ((r
= sshkey_to_base64(host_key
, &keytext
)) != 0)
859 fatal_fr(r
, "sshkey_to_base64 failed");
862 * NB. all returns later this function should go via "out" to
863 * ensure the original SIGCHLD handler is restored properly.
865 osigchld
= ssh_signal(SIGCHLD
, SIG_DFL
);
867 /* Turn the command into an argument vector */
868 if (argv_split(command_template
, &ac
, &av
, 0) != 0) {
869 error("%s \"%s\" contains invalid quotes", tag
,
874 error("%s \"%s\" yielded no arguments", tag
,
878 for (i
= 1; i
< ac
; i
++) {
879 tmp
= percent_dollar_expand(av
[i
],
880 DEFAULT_CLIENT_PERCENT_EXPAND_ARGS(cinfo
),
881 "H", hostfile_hostname
,
883 "t", host_key
== NULL
? "NONE" : sshkey_ssh_name(host_key
),
884 "f", key_fp
== NULL
? "NONE" : key_fp
,
885 "K", keytext
== NULL
? "NONE" : keytext
,
888 fatal_f("percent_expand failed");
892 /* Prepare a printable command for logs, etc. */
893 command
= argv_assemble(ac
, av
);
895 if ((pid
= subprocess(tag
, command
, ac
, av
, &f
,
896 SSH_SUBPROCESS_STDOUT_CAPTURE
|SSH_SUBPROCESS_UNSAFE_PATH
|
897 SSH_SUBPROCESS_PRESERVE_ENV
, NULL
, NULL
, NULL
)) == 0)
900 load_hostkeys_file(hostkeys
, hostfile_hostname
, tag
, f
, 1);
902 if (exited_cleanly(pid
, tag
, command
, 0) != 0)
903 fatal("KnownHostsCommand failed");
908 ssh_signal(SIGCHLD
, osigchld
);
909 for (i
= 0; i
< ac
; i
++)
919 * check whether the supplied host key is valid, return -1 if the key
920 * is not valid. user_hostfile[0] will not be updated if 'readonly' is true.
926 check_host_key(char *hostname
, const struct ssh_conn_info
*cinfo
,
927 struct sockaddr
*hostaddr
, u_short port
,
928 struct sshkey
*host_key
, int readonly
, int clobber_port
,
929 char **user_hostfiles
, u_int num_user_hostfiles
,
930 char **system_hostfiles
, u_int num_system_hostfiles
,
931 const char *hostfile_command
)
933 HostStatus host_status
= -1, ip_status
= -1;
934 struct sshkey
*raw_key
= NULL
;
935 char *ip
= NULL
, *host
= NULL
;
936 char hostline
[1000], *hostp
, *fp
, *ra
;
938 const char *type
, *fail_reason
;
939 const struct hostkey_entry
*host_found
= NULL
, *ip_found
= NULL
;
940 int len
, cancelled_forwarding
= 0, confirmed
;
941 int local
= sockaddr_is_local(hostaddr
);
942 int r
, want_cert
= sshkey_is_cert(host_key
), host_ip_differ
= 0;
943 int hostkey_trusted
= 0; /* Known or explicitly accepted by user */
944 struct hostkeys
*host_hostkeys
, *ip_hostkeys
;
948 * Force accepting of the host key for loopback/localhost. The
949 * problem is that if the home directory is NFS-mounted to multiple
950 * machines, localhost will refer to a different machine in each of
951 * them, and the user will get bogus HOST_CHANGED warnings. This
952 * essentially disables host authentication for localhost; however,
953 * this is probably not a real problem.
955 if (options
.no_host_authentication_for_localhost
== 1 && local
&&
956 options
.host_key_alias
== NULL
) {
957 debug("Forcing accepting of host key for "
958 "loopback/localhost.");
959 options
.update_hostkeys
= 0;
964 * Prepare the hostname and address strings used for hostkey lookup.
965 * In some cases, these will have a port number appended.
967 get_hostfile_hostname_ipaddr(hostname
, hostaddr
,
968 clobber_port
? 0 : port
, &host
, &ip
);
971 * Turn off check_host_ip if the connection is to localhost, via proxy
972 * command or if we don't have a hostname to compare with
974 if (options
.check_host_ip
&& (local
||
975 strcmp(hostname
, ip
) == 0 || options
.proxy_command
!= NULL
))
976 options
.check_host_ip
= 0;
978 host_hostkeys
= init_hostkeys();
979 for (i
= 0; i
< num_user_hostfiles
; i
++)
980 load_hostkeys(host_hostkeys
, host
, user_hostfiles
[i
], 0);
981 for (i
= 0; i
< num_system_hostfiles
; i
++)
982 load_hostkeys(host_hostkeys
, host
, system_hostfiles
[i
], 0);
983 if (hostfile_command
!= NULL
&& !clobber_port
) {
984 load_hostkeys_command(host_hostkeys
, hostfile_command
,
985 "HOSTNAME", cinfo
, host_key
, host
);
989 if (!want_cert
&& options
.check_host_ip
) {
990 ip_hostkeys
= init_hostkeys();
991 for (i
= 0; i
< num_user_hostfiles
; i
++)
992 load_hostkeys(ip_hostkeys
, ip
, user_hostfiles
[i
], 0);
993 for (i
= 0; i
< num_system_hostfiles
; i
++)
994 load_hostkeys(ip_hostkeys
, ip
, system_hostfiles
[i
], 0);
995 if (hostfile_command
!= NULL
&& !clobber_port
) {
996 load_hostkeys_command(ip_hostkeys
, hostfile_command
,
997 "ADDRESS", cinfo
, host_key
, ip
);
1002 /* Reload these as they may have changed on cert->key downgrade */
1003 want_cert
= sshkey_is_cert(host_key
);
1004 type
= sshkey_type(host_key
);
1007 * Check if the host key is present in the user's list of known
1008 * hosts or in the systemwide list.
1010 host_status
= check_key_in_hostkeys(host_hostkeys
, host_key
,
1014 * If there are no hostfiles, or if the hostkey was found via
1015 * KnownHostsCommand, then don't try to touch the disk.
1017 if (!readonly
&& (num_user_hostfiles
== 0 ||
1018 (host_found
!= NULL
&& host_found
->note
!= 0)))
1022 * Also perform check for the ip address, skip the check if we are
1023 * localhost, looking for a certificate, or the hostname was an ip
1024 * address to begin with.
1026 if (!want_cert
&& ip_hostkeys
!= NULL
) {
1027 ip_status
= check_key_in_hostkeys(ip_hostkeys
, host_key
,
1029 if (host_status
== HOST_CHANGED
&&
1030 (ip_status
!= HOST_CHANGED
||
1031 (ip_found
!= NULL
&&
1032 !sshkey_equal(ip_found
->key
, host_found
->key
))))
1035 ip_status
= host_status
;
1037 switch (host_status
) {
1039 /* The host is known and the key matches. */
1040 debug("Host '%.200s' is known and matches the %s host %s.",
1041 host
, type
, want_cert
? "certificate" : "key");
1042 debug("Found %s in %s:%lu", want_cert
? "CA key" : "key",
1043 host_found
->file
, host_found
->line
);
1045 if (sshkey_cert_check_host(host_key
,
1046 options
.host_key_alias
== NULL
?
1047 hostname
: options
.host_key_alias
, 0,
1048 options
.ca_sign_algorithms
, &fail_reason
) != 0) {
1049 error("%s", fail_reason
);
1053 * Do not attempt hostkey update if a certificate was
1054 * successfully matched.
1056 if (options
.update_hostkeys
!= 0) {
1057 options
.update_hostkeys
= 0;
1058 debug3_f("certificate host key in use; "
1059 "disabling UpdateHostkeys");
1062 /* Turn off UpdateHostkeys if key was in system known_hosts */
1063 if (options
.update_hostkeys
!= 0 &&
1064 (path_in_hostfiles(host_found
->file
,
1065 system_hostfiles
, num_system_hostfiles
) ||
1066 (ip_status
== HOST_OK
&& ip_found
!= NULL
&&
1067 path_in_hostfiles(ip_found
->file
,
1068 system_hostfiles
, num_system_hostfiles
)))) {
1069 options
.update_hostkeys
= 0;
1070 debug3_f("host key found in GlobalKnownHostsFile; "
1071 "disabling UpdateHostkeys");
1073 if (options
.update_hostkeys
!= 0 && host_found
->note
) {
1074 options
.update_hostkeys
= 0;
1075 debug3_f("host key found via KnownHostsCommand; "
1076 "disabling UpdateHostkeys");
1078 if (options
.check_host_ip
&& ip_status
== HOST_NEW
) {
1079 if (readonly
|| want_cert
)
1080 logit("%s host key for IP address "
1081 "'%.128s' not in list of known hosts.",
1083 else if (!add_host_to_hostfile(user_hostfiles
[0], ip
,
1084 host_key
, options
.hash_known_hosts
))
1085 logit("Failed to add the %s host key for IP "
1086 "address '%.128s' to the list of known "
1087 "hosts (%.500s).", type
, ip
,
1090 logit("Warning: Permanently added the %s host "
1091 "key for IP address '%.128s' to the list "
1092 "of known hosts.", type
, ip
);
1093 } else if (options
.visual_host_key
) {
1094 fp
= sshkey_fingerprint(host_key
,
1095 options
.fingerprint_hash
, SSH_FP_DEFAULT
);
1096 ra
= sshkey_fingerprint(host_key
,
1097 options
.fingerprint_hash
, SSH_FP_RANDOMART
);
1098 if (fp
== NULL
|| ra
== NULL
)
1099 fatal_f("sshkey_fingerprint failed");
1100 logit("Host key fingerprint is %s\n%s", fp
, ra
);
1104 hostkey_trusted
= 1;
1107 if (options
.host_key_alias
== NULL
&& port
!= 0 &&
1108 port
!= SSH_DEFAULT_PORT
&& !clobber_port
) {
1109 debug("checking without port identifier");
1110 if (check_host_key(hostname
, cinfo
, hostaddr
, 0,
1111 host_key
, ROQUIET
, 1,
1112 user_hostfiles
, num_user_hostfiles
,
1113 system_hostfiles
, num_system_hostfiles
,
1114 hostfile_command
) == 0) {
1115 debug("found matching key w/out port");
1119 if (readonly
|| want_cert
)
1121 /* The host is new. */
1122 if (options
.strict_host_key_checking
==
1123 SSH_STRICT_HOSTKEY_YES
) {
1125 * User has requested strict host key checking. We
1126 * will not add the host key automatically. The only
1127 * alternative left is to abort.
1129 error("No %s host key is known for %.200s and you "
1130 "have requested strict checking.", type
, host
);
1132 } else if (options
.strict_host_key_checking
==
1133 SSH_STRICT_HOSTKEY_ASK
) {
1134 char *msg1
= NULL
, *msg2
= NULL
;
1136 xasprintf(&msg1
, "The authenticity of host "
1137 "'%.200s (%s)' can't be established", host
, ip
);
1139 if (show_other_keys(host_hostkeys
, host_key
)) {
1140 xextendf(&msg1
, "\n", "but keys of different "
1141 "type are already known for this host.");
1143 xextendf(&msg1
, "", ".");
1145 fp
= sshkey_fingerprint(host_key
,
1146 options
.fingerprint_hash
, SSH_FP_DEFAULT
);
1147 ra
= sshkey_fingerprint(host_key
,
1148 options
.fingerprint_hash
, SSH_FP_RANDOMART
);
1149 if (fp
== NULL
|| ra
== NULL
)
1150 fatal_f("sshkey_fingerprint failed");
1151 xextendf(&msg1
, "\n", "%s key fingerprint is %s.",
1153 if (options
.visual_host_key
)
1154 xextendf(&msg1
, "\n", "%s", ra
);
1155 if (options
.verify_host_key_dns
) {
1156 xextendf(&msg1
, "\n",
1157 "%s host key fingerprint found in DNS.",
1158 matching_host_key_dns
?
1159 "Matching" : "No matching");
1161 /* msg2 informs for other names matching this key */
1162 if ((msg2
= other_hostkeys_message(host
, ip
, host_key
,
1163 user_hostfiles
, num_user_hostfiles
,
1164 system_hostfiles
, num_system_hostfiles
)) != NULL
)
1165 xextendf(&msg1
, "\n", "%s", msg2
);
1167 xextendf(&msg1
, "\n",
1168 "Are you sure you want to continue connecting "
1169 "(yes/no/[fingerprint])? ");
1171 confirmed
= confirm(msg1
, fp
);
1178 hostkey_trusted
= 1; /* user explicitly confirmed */
1181 * If in "new" or "off" strict mode, add the key automatically
1182 * to the local known_hosts file.
1184 if (options
.check_host_ip
&& ip_status
== HOST_NEW
) {
1185 snprintf(hostline
, sizeof(hostline
), "%s,%s", host
, ip
);
1187 if (options
.hash_known_hosts
) {
1188 /* Add hash of host and IP separately */
1189 r
= add_host_to_hostfile(user_hostfiles
[0],
1190 host
, host_key
, options
.hash_known_hosts
) &&
1191 add_host_to_hostfile(user_hostfiles
[0], ip
,
1192 host_key
, options
.hash_known_hosts
);
1194 /* Add unhashed "host,ip" */
1195 r
= add_host_to_hostfile(user_hostfiles
[0],
1197 options
.hash_known_hosts
);
1200 r
= add_host_to_hostfile(user_hostfiles
[0], host
,
1201 host_key
, options
.hash_known_hosts
);
1206 logit("Failed to add the host to the list of known "
1207 "hosts (%.500s).", user_hostfiles
[0]);
1209 logit("Warning: Permanently added '%.200s' (%s) to the "
1210 "list of known hosts.", hostp
, type
);
1213 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1214 error("@ WARNING: REVOKED HOST KEY DETECTED! @");
1215 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1216 error("The %s host key for %s is marked as revoked.", type
, host
);
1217 error("This could mean that a stolen key is being used to");
1218 error("impersonate this host.");
1221 * If strict host key checking is in use, the user will have
1222 * to edit the key manually and we can only abort.
1224 if (options
.strict_host_key_checking
!=
1225 SSH_STRICT_HOSTKEY_OFF
) {
1226 error("%s host key for %.200s was revoked and you have "
1227 "requested strict checking.", type
, host
);
1230 goto continue_unsafe
;
1235 * This is only a debug() since it is valid to have
1236 * CAs with wildcard DNS matches that don't match
1237 * all hosts that one might visit.
1239 debug("Host certificate authority does not "
1240 "match %s in %s:%lu", CA_MARKER
,
1241 host_found
->file
, host_found
->line
);
1244 if (readonly
== ROQUIET
)
1246 if (options
.check_host_ip
&& host_ip_differ
) {
1248 if (ip_status
== HOST_NEW
)
1249 key_msg
= "is unknown";
1250 else if (ip_status
== HOST_OK
)
1251 key_msg
= "is unchanged";
1253 key_msg
= "has a different value";
1254 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1255 error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @");
1256 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1257 error("The %s host key for %s has changed,", type
, host
);
1258 error("and the key for the corresponding IP address %s", ip
);
1259 error("%s. This could either mean that", key_msg
);
1260 error("DNS SPOOFING is happening or the IP address for the host");
1261 error("and its host key have changed at the same time.");
1262 if (ip_status
!= HOST_NEW
)
1263 error("Offending key for IP in %s:%lu",
1264 ip_found
->file
, ip_found
->line
);
1266 /* The host key has changed. */
1267 warn_changed_key(host_key
);
1268 error("Add correct host key in %.100s to get rid of this message.",
1270 error("Offending %s key in %s:%lu",
1271 sshkey_type(host_found
->key
),
1272 host_found
->file
, host_found
->line
);
1275 * If strict host key checking is in use, the user will have
1276 * to edit the key manually and we can only abort.
1278 if (options
.strict_host_key_checking
!=
1279 SSH_STRICT_HOSTKEY_OFF
) {
1280 error("Host key for %.200s has changed and you have "
1281 "requested strict checking.", host
);
1287 * If strict host key checking has not been requested, allow
1288 * the connection but without MITM-able authentication or
1291 if (options
.password_authentication
) {
1292 error("Password authentication is disabled to avoid "
1293 "man-in-the-middle attacks.");
1294 options
.password_authentication
= 0;
1295 cancelled_forwarding
= 1;
1297 if (options
.kbd_interactive_authentication
) {
1298 error("Keyboard-interactive authentication is disabled"
1299 " to avoid man-in-the-middle attacks.");
1300 options
.kbd_interactive_authentication
= 0;
1301 cancelled_forwarding
= 1;
1303 if (options
.forward_agent
) {
1304 error("Agent forwarding is disabled to avoid "
1305 "man-in-the-middle attacks.");
1306 options
.forward_agent
= 0;
1307 cancelled_forwarding
= 1;
1309 if (options
.forward_x11
) {
1310 error("X11 forwarding is disabled to avoid "
1311 "man-in-the-middle attacks.");
1312 options
.forward_x11
= 0;
1313 cancelled_forwarding
= 1;
1315 if (options
.num_local_forwards
> 0 ||
1316 options
.num_remote_forwards
> 0) {
1317 error("Port forwarding is disabled to avoid "
1318 "man-in-the-middle attacks.");
1319 options
.num_local_forwards
=
1320 options
.num_remote_forwards
= 0;
1321 cancelled_forwarding
= 1;
1323 if (options
.tun_open
!= SSH_TUNMODE_NO
) {
1324 error("Tunnel forwarding is disabled to avoid "
1325 "man-in-the-middle attacks.");
1326 options
.tun_open
= SSH_TUNMODE_NO
;
1327 cancelled_forwarding
= 1;
1329 if (options
.update_hostkeys
!= 0) {
1330 error("UpdateHostkeys is disabled because the host "
1331 "key is not trusted.");
1332 options
.update_hostkeys
= 0;
1334 if (options
.exit_on_forward_failure
&& cancelled_forwarding
)
1335 fatal("Error: forwarding disabled due to host key "
1339 * XXX Should permit the user to change to use the new id.
1340 * This could be done by converting the host key to an
1341 * identifying sentence, tell that the host identifies itself
1342 * by that sentence, and ask the user if they wish to
1343 * accept the authentication.
1347 fatal("internal error");
1351 if (options
.check_host_ip
&& host_status
!= HOST_CHANGED
&&
1352 ip_status
== HOST_CHANGED
) {
1353 snprintf(msg
, sizeof(msg
),
1354 "Warning: the %s host key for '%.200s' "
1355 "differs from the key for the IP address '%.128s'"
1356 "\nOffending key for IP in %s:%lu",
1357 type
, host
, ip
, ip_found
->file
, ip_found
->line
);
1358 if (host_status
== HOST_OK
) {
1360 snprintf(msg
+ len
, sizeof(msg
) - len
,
1361 "\nMatching host key in %s:%lu",
1362 host_found
->file
, host_found
->line
);
1364 if (options
.strict_host_key_checking
==
1365 SSH_STRICT_HOSTKEY_ASK
) {
1366 strlcat(msg
, "\nAre you sure you want "
1367 "to continue connecting (yes/no)? ", sizeof(msg
));
1368 if (!confirm(msg
, NULL
))
1370 } else if (options
.strict_host_key_checking
!=
1371 SSH_STRICT_HOSTKEY_OFF
) {
1373 error("Exiting, you have requested strict checking.");
1380 if (!hostkey_trusted
&& options
.update_hostkeys
) {
1381 debug_f("hostkey not known or explicitly trusted: "
1382 "disabling UpdateHostkeys");
1383 options
.update_hostkeys
= 0;
1388 if (host_hostkeys
!= NULL
)
1389 free_hostkeys(host_hostkeys
);
1390 if (ip_hostkeys
!= NULL
)
1391 free_hostkeys(ip_hostkeys
);
1395 if (want_cert
&& host_status
!= HOST_REVOKED
) {
1397 * No matching certificate. Downgrade cert to raw key and
1400 debug("No matching CA found. Retry with plain key");
1401 if ((r
= sshkey_from_private(host_key
, &raw_key
)) != 0)
1402 fatal_fr(r
, "decode key");
1403 if ((r
= sshkey_drop_cert(raw_key
)) != 0)
1404 fatal_r(r
, "Couldn't drop certificate");
1408 sshkey_free(raw_key
);
1411 if (host_hostkeys
!= NULL
)
1412 free_hostkeys(host_hostkeys
);
1413 if (ip_hostkeys
!= NULL
)
1414 free_hostkeys(ip_hostkeys
);
1418 /* returns 0 if key verifies or -1 if key does NOT verify */
1420 verify_host_key(char *host
, struct sockaddr
*hostaddr
, struct sshkey
*host_key
,
1421 const struct ssh_conn_info
*cinfo
)
1424 int r
= -1, flags
= 0;
1425 char valid
[64], *fp
= NULL
, *cafp
= NULL
;
1426 struct sshkey
*plain
= NULL
;
1428 if ((fp
= sshkey_fingerprint(host_key
,
1429 options
.fingerprint_hash
, SSH_FP_DEFAULT
)) == NULL
) {
1430 error_fr(r
, "fingerprint host key");
1435 if (sshkey_is_cert(host_key
)) {
1436 if ((cafp
= sshkey_fingerprint(host_key
->cert
->signature_key
,
1437 options
.fingerprint_hash
, SSH_FP_DEFAULT
)) == NULL
) {
1438 error_fr(r
, "fingerprint CA key");
1442 sshkey_format_cert_validity(host_key
->cert
,
1443 valid
, sizeof(valid
));
1444 debug("Server host certificate: %s %s, serial %llu "
1445 "ID \"%s\" CA %s %s valid %s",
1446 sshkey_ssh_name(host_key
), fp
,
1447 (unsigned long long)host_key
->cert
->serial
,
1448 host_key
->cert
->key_id
,
1449 sshkey_ssh_name(host_key
->cert
->signature_key
), cafp
,
1451 for (i
= 0; i
< host_key
->cert
->nprincipals
; i
++) {
1452 debug2("Server host certificate hostname: %s",
1453 host_key
->cert
->principals
[i
]);
1456 debug("Server host key: %s %s", sshkey_ssh_name(host_key
), fp
);
1459 if (sshkey_equal(previous_host_key
, host_key
)) {
1460 debug2_f("server host key %s %s matches cached key",
1461 sshkey_type(host_key
), fp
);
1466 /* Check in RevokedHostKeys file if specified */
1467 if (options
.revoked_host_keys
!= NULL
) {
1468 r
= sshkey_check_revoked(host_key
, options
.revoked_host_keys
);
1471 break; /* not revoked */
1472 case SSH_ERR_KEY_REVOKED
:
1473 error("Host key %s %s revoked by file %s",
1474 sshkey_type(host_key
), fp
,
1475 options
.revoked_host_keys
);
1479 error_r(r
, "Error checking host key %s %s in "
1480 "revoked keys file %s", sshkey_type(host_key
),
1481 fp
, options
.revoked_host_keys
);
1487 if (options
.verify_host_key_dns
) {
1489 * XXX certs are not yet supported for DNS, so downgrade
1490 * them and try the plain key.
1492 if ((r
= sshkey_from_private(host_key
, &plain
)) != 0)
1494 if (sshkey_is_cert(plain
))
1495 sshkey_drop_cert(plain
);
1496 if (verify_host_key_dns(host
, hostaddr
, plain
, &flags
) == 0) {
1497 if (flags
& DNS_VERIFY_FOUND
) {
1498 if (options
.verify_host_key_dns
== 1 &&
1499 flags
& DNS_VERIFY_MATCH
&&
1500 flags
& DNS_VERIFY_SECURE
) {
1504 if (flags
& DNS_VERIFY_MATCH
) {
1505 matching_host_key_dns
= 1;
1507 warn_changed_key(plain
);
1508 error("Update the SSHFP RR in DNS "
1509 "with the new host key to get rid "
1510 "of this message.");
1515 r
= check_host_key(host
, cinfo
, hostaddr
, options
.port
, host_key
,
1516 RDRW
, 0, options
.user_hostfiles
, options
.num_user_hostfiles
,
1517 options
.system_hostfiles
, options
.num_system_hostfiles
,
1518 options
.known_hosts_command
);
1524 if (r
== 0 && host_key
!= NULL
) {
1525 sshkey_free(previous_host_key
);
1526 r
= sshkey_from_private(host_key
, &previous_host_key
);
1533 * Starts a dialog with the server, and authenticates the current user on the
1534 * server. This does not need any extra privileges. The basic connection
1535 * to the server must already have been established before this is called.
1536 * If login fails, this function prints an error and never returns.
1537 * This function does not require super-user privileges.
1540 ssh_login(struct ssh
*ssh
, Sensitive
*sensitive
, const char *orighost
,
1541 struct sockaddr
*hostaddr
, u_short port
, struct passwd
*pw
, int timeout_ms
,
1542 const struct ssh_conn_info
*cinfo
)
1545 char *server_user
, *local_user
;
1548 local_user
= xstrdup(pw
->pw_name
);
1549 server_user
= options
.user
? options
.user
: local_user
;
1551 /* Convert the user-supplied hostname into all lowercase. */
1552 host
= xstrdup(orighost
);
1555 /* Exchange protocol version identification strings with the server. */
1556 if ((r
= kex_exchange_identification(ssh
, timeout_ms
, NULL
)) != 0)
1557 sshpkt_fatal(ssh
, r
, "banner exchange");
1559 /* Put the connection into non-blocking mode. */
1560 ssh_packet_set_nonblocking(ssh
);
1563 /* authenticate user */
1564 debug("Authenticating to %s:%d as '%s'", host
, port
, server_user
);
1565 ssh_kex2(ssh
, host
, hostaddr
, port
, cinfo
);
1566 ssh_userauth2(ssh
, local_user
, server_user
, host
, sensitive
);
1571 /* print all known host keys for a given host, but skip keys of given type */
1573 show_other_keys(struct hostkeys
*hostkeys
, struct sshkey
*key
)
1585 const struct hostkey_entry
*found
;
1587 for (i
= 0; type
[i
] != -1; i
++) {
1588 if (type
[i
] == key
->type
)
1590 if (!lookup_key_in_hostkeys_by_type(hostkeys
, type
[i
],
1593 fp
= sshkey_fingerprint(found
->key
,
1594 options
.fingerprint_hash
, SSH_FP_DEFAULT
);
1595 ra
= sshkey_fingerprint(found
->key
,
1596 options
.fingerprint_hash
, SSH_FP_RANDOMART
);
1597 if (fp
== NULL
|| ra
== NULL
)
1598 fatal_f("sshkey_fingerprint fail");
1599 logit("WARNING: %s key found for host %s\n"
1601 "%s key fingerprint %s.",
1602 sshkey_type(found
->key
),
1603 found
->host
, found
->file
, found
->line
,
1604 sshkey_type(found
->key
), fp
);
1605 if (options
.visual_host_key
)
1615 warn_changed_key(struct sshkey
*host_key
)
1619 fp
= sshkey_fingerprint(host_key
, options
.fingerprint_hash
,
1622 fatal_f("sshkey_fingerprint fail");
1624 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1625 error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @");
1626 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1627 error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
1628 error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
1629 error("It is also possible that a host key has just been changed.");
1630 error("The fingerprint for the %s key sent by the remote host is\n%s.",
1631 sshkey_type(host_key
), fp
);
1632 error("Please contact your system administrator.");
1638 * Execute a local command
1641 ssh_local_cmd(const char *args
)
1646 void (*osighand
)(int);
1648 if (!options
.permit_local_command
||
1649 args
== NULL
|| !*args
)
1652 if ((shell
= getenv("SHELL")) == NULL
|| *shell
== '\0')
1653 shell
= _PATH_BSHELL
;
1655 osighand
= ssh_signal(SIGCHLD
, SIG_DFL
);
1658 ssh_signal(SIGPIPE
, SIG_DFL
);
1659 debug3("Executing %s -c \"%s\"", shell
, args
);
1660 execl(shell
, shell
, "-c", args
, (char *)NULL
);
1661 error("Couldn't execute %s -c \"%s\": %s",
1662 shell
, args
, strerror(errno
));
1664 } else if (pid
== -1)
1665 fatal("fork failed: %.100s", strerror(errno
));
1666 while (waitpid(pid
, &status
, 0) == -1)
1668 fatal("Couldn't wait for child: %s", strerror(errno
));
1669 ssh_signal(SIGCHLD
, osighand
);
1671 if (!WIFEXITED(status
))
1674 return (WEXITSTATUS(status
));
1678 maybe_add_key_to_agent(const char *authfile
, struct sshkey
*private,
1679 const char *comment
, const char *passphrase
)
1681 int auth_sock
= -1, r
;
1682 const char *skprovider
= NULL
;
1684 if (options
.add_keys_to_agent
== 0)
1687 if ((r
= ssh_get_authentication_socket(&auth_sock
)) != 0) {
1688 debug3("no authentication agent, not adding key");
1692 if (options
.add_keys_to_agent
== 2 &&
1693 !ask_permission("Add key %s (%s) to agent?", authfile
, comment
)) {
1694 debug3("user denied adding this key");
1698 if (sshkey_is_sk(private))
1699 skprovider
= options
.sk_provider
;
1700 if ((r
= ssh_add_identity_constrained(auth_sock
, private,
1701 comment
== NULL
? authfile
: comment
,
1702 options
.add_keys_to_agent_lifespan
,
1703 (options
.add_keys_to_agent
== 3), 0, skprovider
, NULL
, 0)) == 0)
1704 debug("identity added to agent: %s", authfile
);
1706 debug("could not add identity to agent: %s (%d)", authfile
, r
);