2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * Code to connect to a remote host, and to perform the client side of the
6 * login (authentication) dialog.
8 * As far as I am concerned, the code I have written for this software
9 * can be used freely for any purpose. Any derived versions of this
10 * software must be clearly marked as such, and if the derived work is
11 * incompatible with the protocol description in the RFC file, it must be
12 * called by a name other than "ssh" or "Secure Shell".
16 RCSID("$OpenBSD: sshconnect.c,v 1.168 2005/07/17 07:17:55 djm Exp $");
18 #include <openssl/bn.h>
28 #include "sshconnect.h"
37 char *client_version_string
= NULL
;
38 char *server_version_string
= NULL
;
40 int matching_host_key_dns
= 0;
43 extern Options options
;
44 extern char *__progname
;
45 extern uid_t original_real_uid
;
46 extern uid_t original_effective_uid
;
47 extern pid_t proxy_command_pid
;
49 #ifndef INET6_ADDRSTRLEN /* for non IPv6 machines */
50 #define INET6_ADDRSTRLEN 46
53 static int show_other_keys(const char *, Key
*);
54 static void warn_changed_key(Key
*);
57 * Connect to the given ssh server using a proxy command.
60 ssh_proxy_connect(const char *host
, u_short port
, const char *proxy_command
)
62 char *command_string
, *tmp
;
65 char strport
[NI_MAXSERV
];
68 /* Convert the port number into a string. */
69 snprintf(strport
, sizeof strport
, "%hu", port
);
72 * Build the final command string in the buffer by making the
73 * appropriate substitutions to the given proxy command.
75 * Use "exec" to avoid "sh -c" processes on some platforms
78 len
= strlen(proxy_command
) + 6;
80 strlcpy(tmp
, "exec ", len
);
81 strlcat(tmp
, proxy_command
, len
);
82 command_string
= percent_expand(tmp
, "h", host
,
83 "p", strport
, (char *)NULL
);
86 /* Create pipes for communicating with the proxy. */
87 if (pipe(pin
) < 0 || pipe(pout
) < 0)
88 fatal("Could not create pipes to communicate with the proxy: %.100s",
91 debug("Executing proxy command: %.500s", command_string
);
93 /* Fork and execute the proxy command. */
94 if ((pid
= fork()) == 0) {
97 /* Child. Permanently give up superuser privileges. */
98 seteuid(original_real_uid
);
99 setuid(original_real_uid
);
101 /* Redirect stdin and stdout. */
104 if (dup2(pin
[0], 0) < 0)
105 perror("dup2 stdin");
109 if (dup2(pout
[1], 1) < 0)
110 perror("dup2 stdout");
111 /* Cannot be 1 because pin allocated two descriptors. */
114 /* Stderr is left as it is so that error messages get
115 printed on the user's terminal. */
116 argv
[0] = _PATH_BSHELL
;
118 argv
[2] = command_string
;
121 /* Execute the proxy command. Note that we gave up any
122 extra privileges above. */
123 execv(argv
[0], argv
);
129 fatal("fork failed: %.100s", strerror(errno
));
131 proxy_command_pid
= pid
; /* save pid to clean up later */
133 /* Close child side of the descriptors. */
137 /* Free the command name. */
138 xfree(command_string
);
140 /* Set the connection file descriptors. */
141 packet_set_connection(pout
[0], pin
[1]);
143 /* Indicate OK return */
148 * Creates a (possibly privileged) socket for use as the ssh connection.
151 ssh_create_socket(int privileged
, struct addrinfo
*ai
)
154 struct addrinfo hints
, *res
;
157 * If we are running as root and want to connect to a privileged
158 * port, bind our own socket to a privileged port.
161 int p
= IPPORT_RESERVED
- 1;
163 sock
= rresvport_af(&p
, ai
->ai_family
);
166 error("rresvport: af=%d %.100s", ai
->ai_family
,
169 debug("Allocated local port %d.", p
);
172 sock
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
174 error("socket: %.100s", strerror(errno
));
176 /* Bind the socket to an alternative local IP address */
177 if (options
.bind_address
== NULL
)
180 memset(&hints
, 0, sizeof(hints
));
181 hints
.ai_family
= ai
->ai_family
;
182 hints
.ai_socktype
= ai
->ai_socktype
;
183 hints
.ai_protocol
= ai
->ai_protocol
;
184 hints
.ai_flags
= AI_PASSIVE
;
185 gaierr
= getaddrinfo(options
.bind_address
, "0", &hints
, &res
);
187 error("getaddrinfo: %s: %s", options
.bind_address
,
188 gai_strerror(gaierr
));
192 if (bind(sock
, res
->ai_addr
, res
->ai_addrlen
) < 0) {
193 error("bind: %s: %s", options
.bind_address
, strerror(errno
));
203 timeout_connect(int sockfd
, const struct sockaddr
*serv_addr
,
204 socklen_t addrlen
, int timeout
)
209 int fdsetsz
, optval
, rc
, result
= -1;
212 return (connect(sockfd
, serv_addr
, addrlen
));
214 set_nonblock(sockfd
);
215 rc
= connect(sockfd
, serv_addr
, addrlen
);
217 unset_nonblock(sockfd
);
220 if (errno
!= EINPROGRESS
)
223 fdsetsz
= howmany(sockfd
+ 1, NFDBITS
) * sizeof(fd_mask
);
224 fdset
= (fd_set
*)xmalloc(fdsetsz
);
226 memset(fdset
, 0, fdsetsz
);
227 FD_SET(sockfd
, fdset
);
232 rc
= select(sockfd
+ 1, NULL
, fdset
, NULL
, &tv
);
233 if (rc
!= -1 || errno
!= EINTR
)
244 debug("select: %s", strerror(errno
));
247 /* Completed or failed */
249 optlen
= sizeof(optval
);
250 if (getsockopt(sockfd
, SOL_SOCKET
, SO_ERROR
, &optval
,
252 debug("getsockopt: %s", strerror(errno
));
260 unset_nonblock(sockfd
);
263 /* Should not occur */
264 fatal("Bogus return (%d) from select()", rc
);
272 * Opens a TCP/IP connection to the remote server on the given host.
273 * The address of the remote host will be returned in hostaddr.
274 * If port is 0, the default port will be used. If needpriv is true,
275 * a privileged port will be allocated to make the connection.
276 * This requires super-user privileges if needpriv is true.
277 * Connection_attempts specifies the maximum number of tries (one per
278 * second). If proxy_command is non-NULL, it specifies the command (with %h
279 * and %p substituted for host and port, respectively) to use to contact
283 ssh_connect(const char *host
, struct sockaddr_storage
* hostaddr
,
284 u_short port
, int family
, int connection_attempts
,
285 int needpriv
, const char *proxy_command
)
289 int sock
= -1, attempt
;
290 char ntop
[NI_MAXHOST
], strport
[NI_MAXSERV
];
291 struct addrinfo hints
, *ai
, *aitop
;
293 debug2("ssh_connect: needpriv %d", needpriv
);
295 /* If a proxy command is given, connect using it. */
296 if (proxy_command
!= NULL
)
297 return ssh_proxy_connect(host
, port
, proxy_command
);
299 /* No proxy command. */
301 memset(&hints
, 0, sizeof(hints
));
302 hints
.ai_family
= family
;
303 hints
.ai_socktype
= SOCK_STREAM
;
304 snprintf(strport
, sizeof strport
, "%u", port
);
305 if ((gaierr
= getaddrinfo(host
, strport
, &hints
, &aitop
)) != 0)
306 fatal("%s: %.100s: %s", __progname
, host
,
307 gai_strerror(gaierr
));
310 * Try to connect several times. On some machines, the first time
311 * will sometimes fail. In general socket code appears to behave
312 * quite magically on many machines.
314 for (attempt
= 0; ;) {
316 debug("Trying again...");
318 /* Loop through addresses for this host, and try each one in
319 sequence until the connection succeeds. */
320 for (ai
= aitop
; ai
; ai
= ai
->ai_next
) {
321 if (ai
->ai_family
!= AF_INET
&& ai
->ai_family
!= AF_INET6
)
323 if (getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
324 ntop
, sizeof(ntop
), strport
, sizeof(strport
),
325 NI_NUMERICHOST
|NI_NUMERICSERV
) != 0) {
326 error("ssh_connect: getnameinfo failed");
329 debug("Connecting to %.200s [%.100s] port %s.",
330 host
, ntop
, strport
);
332 /* Create a socket for connecting. */
333 sock
= ssh_create_socket(needpriv
, ai
);
335 /* Any error is already output */
338 if (timeout_connect(sock
, ai
->ai_addr
, ai
->ai_addrlen
,
339 options
.connection_timeout
) >= 0) {
340 /* Successful connection. */
341 memcpy(hostaddr
, ai
->ai_addr
, ai
->ai_addrlen
);
344 debug("connect to address %s port %s: %s",
345 ntop
, strport
, strerror(errno
));
347 * Close the failed socket; there appear to
348 * be some problems when reusing a socket for
349 * which connect() has already returned an
356 break; /* Successful connection. */
359 if (attempt
>= connection_attempts
)
361 /* Sleep a moment before retrying. */
367 /* Return failure if we didn't get a successful connection. */
368 if (attempt
>= connection_attempts
) {
369 error("ssh: connect to host %s port %s: %s",
370 host
, strport
, strerror(errno
));
374 debug("Connection established.");
376 /* Set SO_KEEPALIVE if requested. */
377 if (options
.tcp_keep_alive
&&
378 setsockopt(sock
, SOL_SOCKET
, SO_KEEPALIVE
, (void *)&on
,
380 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno
));
382 /* Set the connection. */
383 packet_set_connection(sock
, sock
);
389 * Waits for the server identification string, and sends our own
390 * identification string.
393 ssh_exchange_identification(void)
395 char buf
[256], remote_version
[256]; /* must be same size! */
396 int remote_major
, remote_minor
, mismatch
;
397 int connection_in
= packet_get_connection_in();
398 int connection_out
= packet_get_connection_out();
399 int minor1
= PROTOCOL_MINOR_1
;
402 /* Read other side's version identification. */
404 for (i
= 0; i
< sizeof(buf
) - 1; i
++) {
405 size_t len
= atomicio(read
, connection_in
, &buf
[i
], 1);
407 if (len
!= 1 && errno
== EPIPE
)
408 fatal("ssh_exchange_identification: Connection closed by remote host");
410 fatal("ssh_exchange_identification: read: %.100s", strerror(errno
));
411 if (buf
[i
] == '\r') {
414 continue; /**XXX wait for \n */
416 if (buf
[i
] == '\n') {
421 buf
[sizeof(buf
) - 1] = 0;
422 if (strncmp(buf
, "SSH-", 4) == 0)
424 debug("ssh_exchange_identification: %s", buf
);
426 server_version_string
= xstrdup(buf
);
429 * Check that the versions match. In future this might accept
430 * several versions and set appropriate flags to handle them.
432 if (sscanf(server_version_string
, "SSH-%d.%d-%[^\n]\n",
433 &remote_major
, &remote_minor
, remote_version
) != 3)
434 fatal("Bad remote protocol version identification: '%.100s'", buf
);
435 debug("Remote protocol version %d.%d, remote software version %.100s",
436 remote_major
, remote_minor
, remote_version
);
438 compat_datafellows(remote_version
);
441 switch (remote_major
) {
443 if (remote_minor
== 99 &&
444 (options
.protocol
& SSH_PROTO_2
) &&
445 !(options
.protocol
& SSH_PROTO_1_PREFERRED
)) {
449 if (!(options
.protocol
& SSH_PROTO_1
)) {
453 if (remote_minor
< 3) {
454 fatal("Remote machine has too old SSH software version.");
455 } else if (remote_minor
== 3 || remote_minor
== 4) {
456 /* We speak 1.3, too. */
459 if (options
.forward_agent
) {
460 logit("Agent forwarding disabled for protocol 1.3");
461 options
.forward_agent
= 0;
466 if (options
.protocol
& SSH_PROTO_2
) {
476 fatal("Protocol major versions differ: %d vs. %d",
477 (options
.protocol
& SSH_PROTO_2
) ? PROTOCOL_MAJOR_2
: PROTOCOL_MAJOR_1
,
479 /* Send our own protocol version identification. */
480 snprintf(buf
, sizeof buf
, "SSH-%d.%d-%.100s\n",
481 compat20
? PROTOCOL_MAJOR_2
: PROTOCOL_MAJOR_1
,
482 compat20
? PROTOCOL_MINOR_2
: minor1
,
484 if (atomicio(vwrite
, connection_out
, buf
, strlen(buf
)) != strlen(buf
))
485 fatal("write: %.100s", strerror(errno
));
486 client_version_string
= xstrdup(buf
);
487 chop(client_version_string
);
488 chop(server_version_string
);
489 debug("Local version string %.100s", client_version_string
);
492 /* defaults to 'no' */
494 confirm(const char *prompt
)
496 const char *msg
, *again
= "Please type 'yes' or 'no': ";
500 if (options
.batch_mode
)
502 for (msg
= prompt
;;msg
= again
) {
503 p
= read_passphrase(msg
, RP_ECHO
);
505 (p
[0] == '\0') || (p
[0] == '\n') ||
506 strncasecmp(p
, "no", 2) == 0)
508 if (p
&& strncasecmp(p
, "yes", 3) == 0)
518 * check whether the supplied host key is valid, return -1 if the key
519 * is not valid. the user_hostfile will not be updated if 'readonly' is true.
522 check_host_key(char *host
, struct sockaddr
*hostaddr
, Key
*host_key
,
523 int readonly
, const char *user_hostfile
, const char *system_hostfile
)
526 const char *type
= key_type(host_key
);
528 char hostline
[1000], *hostp
, *fp
;
529 HostStatus host_status
;
530 HostStatus ip_status
;
531 int r
, local
= 0, host_ip_differ
= 0;
533 char ntop
[NI_MAXHOST
];
535 int len
, host_line
, ip_line
;
536 const char *host_file
= NULL
, *ip_file
= NULL
;
539 * Force accepting of the host key for loopback/localhost. The
540 * problem is that if the home directory is NFS-mounted to multiple
541 * machines, localhost will refer to a different machine in each of
542 * them, and the user will get bogus HOST_CHANGED warnings. This
543 * essentially disables host authentication for localhost; however,
544 * this is probably not a real problem.
546 /** hostaddr == 0! */
547 switch (hostaddr
->sa_family
) {
549 local
= (ntohl(((struct sockaddr_in
*)hostaddr
)->
550 sin_addr
.s_addr
) >> 24) == IN_LOOPBACKNET
;
551 salen
= sizeof(struct sockaddr_in
);
554 local
= IN6_IS_ADDR_LOOPBACK(
555 &(((struct sockaddr_in6
*)hostaddr
)->sin6_addr
));
556 salen
= sizeof(struct sockaddr_in6
);
560 salen
= sizeof(struct sockaddr_storage
);
563 if (options
.no_host_authentication_for_localhost
== 1 && local
&&
564 options
.host_key_alias
== NULL
) {
565 debug("Forcing accepting of host key for "
566 "loopback/localhost.");
571 * We don't have the remote ip-address for connections
572 * using a proxy command
574 if (options
.proxy_command
== NULL
) {
575 if (getnameinfo(hostaddr
, salen
, ntop
, sizeof(ntop
),
576 NULL
, 0, NI_NUMERICHOST
) != 0)
577 fatal("check_host_key: getnameinfo failed");
580 ip
= xstrdup("<no hostip for proxy command>");
583 * Turn off check_host_ip if the connection is to localhost, via proxy
584 * command or if we don't have a hostname to compare with
586 if (options
.check_host_ip
&&
587 (local
|| strcmp(host
, ip
) == 0 || options
.proxy_command
!= NULL
))
588 options
.check_host_ip
= 0;
591 * Allow the user to record the key under a different name. This is
592 * useful for ssh tunneling over forwarded connections or if you run
593 * multiple sshd's on different ports on the same machine.
595 if (options
.host_key_alias
!= NULL
) {
596 host
= options
.host_key_alias
;
597 debug("using hostkeyalias: %s", host
);
601 * Store the host key from the known host file in here so that we can
602 * compare it with the key for the IP address.
604 file_key
= key_new(host_key
->type
);
607 * Check if the host key is present in the user\'s list of known
608 * hosts or in the systemwide list.
610 host_file
= user_hostfile
;
611 host_status
= check_host_in_hostfile(host_file
, host
, host_key
,
612 file_key
, &host_line
);
613 if (host_status
== HOST_NEW
) {
614 host_file
= system_hostfile
;
615 host_status
= check_host_in_hostfile(host_file
, host
, host_key
,
616 file_key
, &host_line
);
619 * Also perform check for the ip address, skip the check if we are
620 * localhost or the hostname was an ip address to begin with
622 if (options
.check_host_ip
) {
623 Key
*ip_key
= key_new(host_key
->type
);
625 ip_file
= user_hostfile
;
626 ip_status
= check_host_in_hostfile(ip_file
, ip
, host_key
,
628 if (ip_status
== HOST_NEW
) {
629 ip_file
= system_hostfile
;
630 ip_status
= check_host_in_hostfile(ip_file
, ip
,
631 host_key
, ip_key
, &ip_line
);
633 if (host_status
== HOST_CHANGED
&&
634 (ip_status
!= HOST_CHANGED
|| !key_equal(ip_key
, file_key
)))
639 ip_status
= host_status
;
643 switch (host_status
) {
645 /* The host is known and the key matches. */
646 debug("Host '%.200s' is known and matches the %s host key.",
648 debug("Found key in %s:%d", host_file
, host_line
);
649 if (options
.check_host_ip
&& ip_status
== HOST_NEW
) {
651 logit("%s host key for IP address "
652 "'%.128s' not in list of known hosts.",
654 else if (!add_host_to_hostfile(user_hostfile
, ip
,
655 host_key
, options
.hash_known_hosts
))
656 logit("Failed to add the %s host key for IP "
657 "address '%.128s' to the list of known "
658 "hosts (%.30s).", type
, ip
, user_hostfile
);
660 logit("Warning: Permanently added the %s host "
661 "key for IP address '%.128s' to the list "
662 "of known hosts.", type
, ip
);
668 /* The host is new. */
669 if (options
.strict_host_key_checking
== 1) {
671 * User has requested strict host key checking. We
672 * will not add the host key automatically. The only
673 * alternative left is to abort.
675 error("No %s host key is known for %.200s and you "
676 "have requested strict checking.", type
, host
);
678 } else if (options
.strict_host_key_checking
== 2) {
679 char msg1
[1024], msg2
[1024];
681 if (show_other_keys(host
, host_key
))
682 snprintf(msg1
, sizeof(msg1
),
683 "\nbut keys of different type are already"
684 " known for this host.");
686 snprintf(msg1
, sizeof(msg1
), ".");
688 fp
= key_fingerprint(host_key
, SSH_FP_MD5
, SSH_FP_HEX
);
690 if (options
.verify_host_key_dns
) {
691 if (matching_host_key_dns
)
692 snprintf(msg2
, sizeof(msg2
),
693 "Matching host key fingerprint"
696 snprintf(msg2
, sizeof(msg2
),
697 "No matching host key fingerprint"
700 snprintf(msg
, sizeof(msg
),
701 "The authenticity of host '%.200s (%s)' can't be "
703 "%s key fingerprint is %s.\n%s"
704 "Are you sure you want to continue connecting "
706 host
, ip
, msg1
, type
, fp
, msg2
);
712 * If not in strict mode, add the key automatically to the
713 * local known_hosts file.
715 if (options
.check_host_ip
&& ip_status
== HOST_NEW
) {
716 snprintf(hostline
, sizeof(hostline
), "%s,%s",
719 if (options
.hash_known_hosts
) {
720 /* Add hash of host and IP separately */
721 r
= add_host_to_hostfile(user_hostfile
, host
,
722 host_key
, options
.hash_known_hosts
) &&
723 add_host_to_hostfile(user_hostfile
, ip
,
724 host_key
, options
.hash_known_hosts
);
726 /* Add unhashed "host,ip" */
727 r
= add_host_to_hostfile(user_hostfile
,
729 options
.hash_known_hosts
);
732 r
= add_host_to_hostfile(user_hostfile
, host
, host_key
,
733 options
.hash_known_hosts
);
738 logit("Failed to add the host to the list of known "
739 "hosts (%.500s).", user_hostfile
);
741 logit("Warning: Permanently added '%.200s' (%s) to the "
742 "list of known hosts.", hostp
, type
);
745 if (options
.check_host_ip
&& host_ip_differ
) {
747 if (ip_status
== HOST_NEW
)
748 key_msg
= "is unknown";
749 else if (ip_status
== HOST_OK
)
750 key_msg
= "is unchanged";
752 key_msg
= "has a different value";
753 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
754 error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @");
755 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
756 error("The %s host key for %s has changed,", type
, host
);
757 error("and the key for the according IP address %s", ip
);
758 error("%s. This could either mean that", key_msg
);
759 error("DNS SPOOFING is happening or the IP address for the host");
760 error("and its host key have changed at the same time.");
761 if (ip_status
!= HOST_NEW
)
762 error("Offending key for IP in %s:%d", ip_file
, ip_line
);
764 /* The host key has changed. */
765 warn_changed_key(host_key
);
766 error("Add correct host key in %.100s to get rid of this message.",
768 error("Offending key in %s:%d", host_file
, host_line
);
771 * If strict host key checking is in use, the user will have
772 * to edit the key manually and we can only abort.
774 if (options
.strict_host_key_checking
) {
775 error("%s host key for %.200s has changed and you have "
776 "requested strict checking.", type
, host
);
781 * If strict host key checking has not been requested, allow
782 * the connection but without MITM-able authentication or
785 if (options
.password_authentication
) {
786 error("Password authentication is disabled to avoid "
787 "man-in-the-middle attacks.");
788 options
.password_authentication
= 0;
790 if (options
.kbd_interactive_authentication
) {
791 error("Keyboard-interactive authentication is disabled"
792 " to avoid man-in-the-middle attacks.");
793 options
.kbd_interactive_authentication
= 0;
794 options
.challenge_response_authentication
= 0;
796 if (options
.challenge_response_authentication
) {
797 error("Challenge/response authentication is disabled"
798 " to avoid man-in-the-middle attacks.");
799 options
.challenge_response_authentication
= 0;
801 if (options
.forward_agent
) {
802 error("Agent forwarding is disabled to avoid "
803 "man-in-the-middle attacks.");
804 options
.forward_agent
= 0;
806 if (options
.forward_x11
) {
807 error("X11 forwarding is disabled to avoid "
808 "man-in-the-middle attacks.");
809 options
.forward_x11
= 0;
811 if (options
.num_local_forwards
> 0 ||
812 options
.num_remote_forwards
> 0) {
813 error("Port forwarding is disabled to avoid "
814 "man-in-the-middle attacks.");
815 options
.num_local_forwards
=
816 options
.num_remote_forwards
= 0;
819 * XXX Should permit the user to change to use the new id.
820 * This could be done by converting the host key to an
821 * identifying sentence, tell that the host identifies itself
822 * by that sentence, and ask the user if he/she whishes to
823 * accept the authentication.
827 fatal("internal error");
831 if (options
.check_host_ip
&& host_status
!= HOST_CHANGED
&&
832 ip_status
== HOST_CHANGED
) {
833 snprintf(msg
, sizeof(msg
),
834 "Warning: the %s host key for '%.200s' "
835 "differs from the key for the IP address '%.128s'"
836 "\nOffending key for IP in %s:%d",
837 type
, host
, ip
, ip_file
, ip_line
);
838 if (host_status
== HOST_OK
) {
840 snprintf(msg
+ len
, sizeof(msg
) - len
,
841 "\nMatching host key in %s:%d",
842 host_file
, host_line
);
844 if (options
.strict_host_key_checking
== 1) {
846 error("Exiting, you have requested strict checking.");
848 } else if (options
.strict_host_key_checking
== 2) {
849 strlcat(msg
, "\nAre you sure you want "
850 "to continue connecting (yes/no)? ", sizeof(msg
));
866 /* returns 0 if key verifies or -1 if key does NOT verify */
868 verify_host_key(char *host
, struct sockaddr
*hostaddr
, Key
*host_key
)
873 if (options
.verify_host_key_dns
&&
874 verify_host_key_dns(host
, hostaddr
, host_key
, &flags
) == 0) {
876 if (flags
& DNS_VERIFY_FOUND
) {
878 if (options
.verify_host_key_dns
== 1 &&
879 flags
& DNS_VERIFY_MATCH
&&
880 flags
& DNS_VERIFY_SECURE
)
883 if (flags
& DNS_VERIFY_MATCH
) {
884 matching_host_key_dns
= 1;
886 warn_changed_key(host_key
);
887 error("Update the SSHFP RR in DNS with the new "
888 "host key to get rid of this message.");
893 /* return ok if the key can be found in an old keyfile */
894 if (stat(options
.system_hostfile2
, &st
) == 0 ||
895 stat(options
.user_hostfile2
, &st
) == 0) {
896 if (check_host_key(host
, hostaddr
, host_key
, /*readonly*/ 1,
897 options
.user_hostfile2
, options
.system_hostfile2
) == 0)
900 return check_host_key(host
, hostaddr
, host_key
, /*readonly*/ 0,
901 options
.user_hostfile
, options
.system_hostfile
);
905 * Starts a dialog with the server, and authenticates the current user on the
906 * server. This does not need any extra privileges. The basic connection
907 * to the server must already have been established before this is called.
908 * If login fails, this function prints an error and never returns.
909 * This function does not require super-user privileges.
912 ssh_login(Sensitive
*sensitive
, const char *orighost
,
913 struct sockaddr
*hostaddr
, struct passwd
*pw
)
916 char *server_user
, *local_user
;
918 local_user
= xstrdup(pw
->pw_name
);
919 server_user
= options
.user
? options
.user
: local_user
;
921 /* Convert the user-supplied hostname into all lowercase. */
922 host
= xstrdup(orighost
);
923 for (cp
= host
; *cp
; cp
++)
927 /* Exchange protocol version identification strings with the server. */
928 ssh_exchange_identification();
930 /* Put the connection into non-blocking mode. */
931 packet_set_nonblocking();
934 /* authenticate user */
936 ssh_kex2(host
, hostaddr
);
937 ssh_userauth2(local_user
, server_user
, host
, sensitive
);
939 ssh_kex(host
, hostaddr
);
940 ssh_userauth1(local_user
, server_user
, host
, sensitive
);
945 ssh_put_password(char *password
)
950 if (datafellows
& SSH_BUG_PASSWORDPAD
) {
951 packet_put_cstring(password
);
954 size
= roundup(strlen(password
) + 1, 32);
955 padded
= xmalloc(size
);
956 memset(padded
, 0, size
);
957 strlcpy(padded
, password
, size
);
958 packet_put_string(padded
, size
);
959 memset(padded
, 0, size
);
964 show_key_from_file(const char *file
, const char *host
, int keytype
)
970 found
= key_new(keytype
);
971 if ((ret
= lookup_key_in_hostfile_by_type(file
, host
,
972 keytype
, found
, &line
))) {
973 fp
= key_fingerprint(found
, SSH_FP_MD5
, SSH_FP_HEX
);
974 logit("WARNING: %s key found for host %s\n"
976 "%s key fingerprint %s.",
977 key_type(found
), host
, file
, line
,
978 key_type(found
), fp
);
985 /* print all known host keys for a given host, but skip keys of given type */
987 show_other_keys(const char *host
, Key
*key
)
989 int type
[] = { KEY_RSA1
, KEY_RSA
, KEY_DSA
, -1};
992 for (i
= 0; type
[i
] != -1; i
++) {
993 if (type
[i
] == key
->type
)
995 if (type
[i
] != KEY_RSA1
&&
996 show_key_from_file(options
.user_hostfile2
, host
, type
[i
])) {
1000 if (type
[i
] != KEY_RSA1
&&
1001 show_key_from_file(options
.system_hostfile2
, host
, type
[i
])) {
1005 if (show_key_from_file(options
.user_hostfile
, host
, type
[i
])) {
1009 if (show_key_from_file(options
.system_hostfile
, host
, type
[i
])) {
1013 debug2("no key of type %d for host %s", type
[i
], host
);
1019 warn_changed_key(Key
*host_key
)
1022 const char *type
= key_type(host_key
);
1024 fp
= key_fingerprint(host_key
, SSH_FP_MD5
, SSH_FP_HEX
);
1026 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1027 error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @");
1028 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1029 error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
1030 error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
1031 error("It is also possible that the %s host key has just been changed.", type
);
1032 error("The fingerprint for the %s key sent by the remote host is\n%s.",
1034 error("Please contact your system administrator.");