diff options
Diffstat (limited to 'sshconnect.c')
-rw-r--r-- | sshconnect.c | 339 |
1 files changed, 138 insertions, 201 deletions
diff --git a/sshconnect.c b/sshconnect.c index d9ed5910b..3280b310d 100644 --- a/sshconnect.c +++ b/sshconnect.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect.c,v 1.273 2017/03/10 03:22:40 dtucker Exp $ */ | 1 | /* $OpenBSD: sshconnect.c,v 1.287 2017/09/14 04:32:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -34,6 +34,9 @@ | |||
34 | #include <paths.h> | 34 | #include <paths.h> |
35 | #endif | 35 | #endif |
36 | #include <pwd.h> | 36 | #include <pwd.h> |
37 | #ifdef HAVE_POLL_H | ||
38 | #include <poll.h> | ||
39 | #endif | ||
37 | #include <signal.h> | 40 | #include <signal.h> |
38 | #include <stdarg.h> | 41 | #include <stdarg.h> |
39 | #include <stdio.h> | 42 | #include <stdio.h> |
@@ -45,7 +48,6 @@ | |||
45 | #include "key.h" | 48 | #include "key.h" |
46 | #include "hostfile.h" | 49 | #include "hostfile.h" |
47 | #include "ssh.h" | 50 | #include "ssh.h" |
48 | #include "rsa.h" | ||
49 | #include "buffer.h" | 51 | #include "buffer.h" |
50 | #include "packet.h" | 52 | #include "packet.h" |
51 | #include "uidswap.h" | 53 | #include "uidswap.h" |
@@ -67,7 +69,7 @@ | |||
67 | 69 | ||
68 | char *client_version_string = NULL; | 70 | char *client_version_string = NULL; |
69 | char *server_version_string = NULL; | 71 | char *server_version_string = NULL; |
70 | Key *previous_host_key = NULL; | 72 | struct sshkey *previous_host_key = NULL; |
71 | 73 | ||
72 | static int matching_host_key_dns = 0; | 74 | static int matching_host_key_dns = 0; |
73 | 75 | ||
@@ -79,8 +81,8 @@ extern char *__progname; | |||
79 | extern uid_t original_real_uid; | 81 | extern uid_t original_real_uid; |
80 | extern uid_t original_effective_uid; | 82 | extern uid_t original_effective_uid; |
81 | 83 | ||
82 | static int show_other_keys(struct hostkeys *, Key *); | 84 | static int show_other_keys(struct hostkeys *, struct sshkey *); |
83 | static void warn_changed_key(Key *); | 85 | static void warn_changed_key(struct sshkey *); |
84 | 86 | ||
85 | /* Expand a proxy command */ | 87 | /* Expand a proxy command */ |
86 | static char * | 88 | static char * |
@@ -102,7 +104,7 @@ expand_proxy_command(const char *proxy_command, const char *user, | |||
102 | * a connected fd back to us. | 104 | * a connected fd back to us. |
103 | */ | 105 | */ |
104 | static int | 106 | static int |
105 | ssh_proxy_fdpass_connect(const char *host, u_short port, | 107 | ssh_proxy_fdpass_connect(struct ssh *ssh, const char *host, u_short port, |
106 | const char *proxy_command) | 108 | const char *proxy_command) |
107 | { | 109 | { |
108 | char *command_string; | 110 | char *command_string; |
@@ -173,7 +175,8 @@ ssh_proxy_fdpass_connect(const char *host, u_short port, | |||
173 | fatal("Couldn't wait for child: %s", strerror(errno)); | 175 | fatal("Couldn't wait for child: %s", strerror(errno)); |
174 | 176 | ||
175 | /* Set the connection file descriptors. */ | 177 | /* Set the connection file descriptors. */ |
176 | packet_set_connection(sock, sock); | 178 | if (ssh_packet_set_connection(ssh, sock, sock) == NULL) |
179 | return -1; /* ssh_packet_set_connection logs error */ | ||
177 | 180 | ||
178 | return 0; | 181 | return 0; |
179 | } | 182 | } |
@@ -182,7 +185,8 @@ ssh_proxy_fdpass_connect(const char *host, u_short port, | |||
182 | * Connect to the given ssh server using a proxy command. | 185 | * Connect to the given ssh server using a proxy command. |
183 | */ | 186 | */ |
184 | static int | 187 | static int |
185 | ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) | 188 | ssh_proxy_connect(struct ssh *ssh, const char *host, u_short port, |
189 | const char *proxy_command) | ||
186 | { | 190 | { |
187 | char *command_string; | 191 | char *command_string; |
188 | int pin[2], pout[2]; | 192 | int pin[2], pout[2]; |
@@ -249,9 +253,9 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) | |||
249 | free(command_string); | 253 | free(command_string); |
250 | 254 | ||
251 | /* Set the connection file descriptors. */ | 255 | /* Set the connection file descriptors. */ |
252 | packet_set_connection(pout[0], pin[1]); | 256 | if (ssh_packet_set_connection(ssh, pout[0], pin[1]) == NULL) |
257 | return -1; /* ssh_packet_set_connection logs error */ | ||
253 | 258 | ||
254 | /* Indicate OK return */ | ||
255 | return 0; | 259 | return 0; |
256 | } | 260 | } |
257 | 261 | ||
@@ -328,87 +332,71 @@ ssh_create_socket(int privileged, struct addrinfo *ai) | |||
328 | return sock; | 332 | return sock; |
329 | } | 333 | } |
330 | 334 | ||
335 | /* | ||
336 | * Wait up to *timeoutp milliseconds for fd to be readable. Updates | ||
337 | * *timeoutp with time remaining. | ||
338 | * Returns 0 if fd ready or -1 on timeout or error (see errno). | ||
339 | */ | ||
331 | static int | 340 | static int |
332 | timeout_connect(int sockfd, const struct sockaddr *serv_addr, | 341 | waitrfd(int fd, int *timeoutp) |
333 | socklen_t addrlen, int *timeoutp) | ||
334 | { | 342 | { |
335 | fd_set *fdset; | 343 | struct pollfd pfd; |
336 | struct timeval tv, t_start; | 344 | struct timeval t_start; |
337 | socklen_t optlen; | 345 | int oerrno, r; |
338 | int optval, rc, result = -1; | ||
339 | 346 | ||
340 | gettimeofday(&t_start, NULL); | 347 | gettimeofday(&t_start, NULL); |
341 | 348 | pfd.fd = fd; | |
342 | if (*timeoutp <= 0) { | 349 | pfd.events = POLLIN; |
343 | result = connect(sockfd, serv_addr, addrlen); | 350 | for (; *timeoutp >= 0;) { |
344 | goto done; | 351 | r = poll(&pfd, 1, *timeoutp); |
345 | } | 352 | oerrno = errno; |
346 | 353 | ms_subtract_diff(&t_start, timeoutp); | |
347 | set_nonblock(sockfd); | 354 | errno = oerrno; |
348 | rc = connect(sockfd, serv_addr, addrlen); | 355 | if (r > 0) |
349 | if (rc == 0) { | 356 | return 0; |
350 | unset_nonblock(sockfd); | 357 | else if (r == -1 && errno != EAGAIN) |
351 | result = 0; | 358 | return -1; |
352 | goto done; | 359 | else if (r == 0) |
353 | } | 360 | break; |
354 | if (errno != EINPROGRESS) { | ||
355 | result = -1; | ||
356 | goto done; | ||
357 | } | 361 | } |
362 | /* timeout */ | ||
363 | errno = ETIMEDOUT; | ||
364 | return -1; | ||
365 | } | ||
358 | 366 | ||
359 | fdset = xcalloc(howmany(sockfd + 1, NFDBITS), | 367 | static int |
360 | sizeof(fd_mask)); | 368 | timeout_connect(int sockfd, const struct sockaddr *serv_addr, |
361 | FD_SET(sockfd, fdset); | 369 | socklen_t addrlen, int *timeoutp) |
362 | ms_to_timeval(&tv, *timeoutp); | 370 | { |
371 | int optval = 0; | ||
372 | socklen_t optlen = sizeof(optval); | ||
363 | 373 | ||
364 | for (;;) { | 374 | /* No timeout: just do a blocking connect() */ |
365 | rc = select(sockfd + 1, NULL, fdset, NULL, &tv); | 375 | if (*timeoutp <= 0) |
366 | if (rc != -1 || errno != EINTR) | 376 | return connect(sockfd, serv_addr, addrlen); |
367 | break; | ||
368 | } | ||
369 | 377 | ||
370 | switch (rc) { | 378 | set_nonblock(sockfd); |
371 | case 0: | 379 | if (connect(sockfd, serv_addr, addrlen) == 0) { |
372 | /* Timed out */ | 380 | /* Succeeded already? */ |
373 | errno = ETIMEDOUT; | ||
374 | break; | ||
375 | case -1: | ||
376 | /* Select error */ | ||
377 | debug("select: %s", strerror(errno)); | ||
378 | break; | ||
379 | case 1: | ||
380 | /* Completed or failed */ | ||
381 | optval = 0; | ||
382 | optlen = sizeof(optval); | ||
383 | if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, | ||
384 | &optlen) == -1) { | ||
385 | debug("getsockopt: %s", strerror(errno)); | ||
386 | break; | ||
387 | } | ||
388 | if (optval != 0) { | ||
389 | errno = optval; | ||
390 | break; | ||
391 | } | ||
392 | result = 0; | ||
393 | unset_nonblock(sockfd); | 381 | unset_nonblock(sockfd); |
394 | break; | 382 | return 0; |
395 | default: | 383 | } else if (errno != EINPROGRESS) |
396 | /* Should not occur */ | 384 | return -1; |
397 | fatal("Bogus return (%d) from select()", rc); | ||
398 | } | ||
399 | 385 | ||
400 | free(fdset); | 386 | if (waitrfd(sockfd, timeoutp) == -1) |
387 | return -1; | ||
401 | 388 | ||
402 | done: | 389 | /* Completed or failed */ |
403 | if (result == 0 && *timeoutp > 0) { | 390 | if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1) { |
404 | ms_subtract_diff(&t_start, timeoutp); | 391 | debug("getsockopt: %s", strerror(errno)); |
405 | if (*timeoutp <= 0) { | 392 | return -1; |
406 | errno = ETIMEDOUT; | ||
407 | result = -1; | ||
408 | } | ||
409 | } | 393 | } |
410 | 394 | if (optval != 0) { | |
411 | return (result); | 395 | errno = optval; |
396 | return -1; | ||
397 | } | ||
398 | unset_nonblock(sockfd); | ||
399 | return 0; | ||
412 | } | 400 | } |
413 | 401 | ||
414 | /* | 402 | /* |
@@ -423,7 +411,7 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr, | |||
423 | * the daemon. | 411 | * the daemon. |
424 | */ | 412 | */ |
425 | static int | 413 | static int |
426 | ssh_connect_direct(const char *host, struct addrinfo *aitop, | 414 | ssh_connect_direct(struct ssh *ssh, const char *host, struct addrinfo *aitop, |
427 | struct sockaddr_storage *hostaddr, u_short port, int family, | 415 | struct sockaddr_storage *hostaddr, u_short port, int family, |
428 | int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv) | 416 | int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv) |
429 | { | 417 | { |
@@ -497,40 +485,39 @@ ssh_connect_direct(const char *host, struct addrinfo *aitop, | |||
497 | error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); | 485 | error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); |
498 | 486 | ||
499 | /* Set the connection. */ | 487 | /* Set the connection. */ |
500 | packet_set_connection(sock, sock); | 488 | if (ssh_packet_set_connection(ssh, sock, sock) == NULL) |
489 | return -1; /* ssh_packet_set_connection logs error */ | ||
501 | 490 | ||
502 | return 0; | 491 | return 0; |
503 | } | 492 | } |
504 | 493 | ||
505 | int | 494 | int |
506 | ssh_connect(const char *host, struct addrinfo *addrs, | 495 | ssh_connect(struct ssh *ssh, const char *host, struct addrinfo *addrs, |
507 | struct sockaddr_storage *hostaddr, u_short port, int family, | 496 | struct sockaddr_storage *hostaddr, u_short port, int family, |
508 | int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv) | 497 | int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv) |
509 | { | 498 | { |
510 | if (options.proxy_command == NULL) { | 499 | if (options.proxy_command == NULL) { |
511 | return ssh_connect_direct(host, addrs, hostaddr, port, family, | 500 | return ssh_connect_direct(ssh, host, addrs, hostaddr, port, |
512 | connection_attempts, timeout_ms, want_keepalive, needpriv); | 501 | family, connection_attempts, timeout_ms, want_keepalive, |
502 | needpriv); | ||
513 | } else if (strcmp(options.proxy_command, "-") == 0) { | 503 | } else if (strcmp(options.proxy_command, "-") == 0) { |
514 | packet_set_connection(STDIN_FILENO, STDOUT_FILENO); | 504 | if ((ssh_packet_set_connection(ssh, |
515 | return 0; /* Always succeeds */ | 505 | STDIN_FILENO, STDOUT_FILENO)) == NULL) |
506 | return -1; /* ssh_packet_set_connection logs error */ | ||
507 | return 0; | ||
516 | } else if (options.proxy_use_fdpass) { | 508 | } else if (options.proxy_use_fdpass) { |
517 | return ssh_proxy_fdpass_connect(host, port, | 509 | return ssh_proxy_fdpass_connect(ssh, host, port, |
518 | options.proxy_command); | 510 | options.proxy_command); |
519 | } | 511 | } |
520 | return ssh_proxy_connect(host, port, options.proxy_command); | 512 | return ssh_proxy_connect(ssh, host, port, options.proxy_command); |
521 | } | 513 | } |
522 | 514 | ||
523 | static void | 515 | static void |
524 | send_client_banner(int connection_out, int minor1) | 516 | send_client_banner(int connection_out, int minor1) |
525 | { | 517 | { |
526 | /* Send our own protocol version identification. */ | 518 | /* Send our own protocol version identification. */ |
527 | if (compat20) { | 519 | xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n", |
528 | xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n", | 520 | PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_RELEASE); |
529 | PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_RELEASE); | ||
530 | } else { | ||
531 | xasprintf(&client_version_string, "SSH-%d.%d-%.100s\n", | ||
532 | PROTOCOL_MAJOR_1, minor1, SSH_RELEASE); | ||
533 | } | ||
534 | if (atomicio(vwrite, connection_out, client_version_string, | 521 | if (atomicio(vwrite, connection_out, client_version_string, |
535 | strlen(client_version_string)) != strlen(client_version_string)) | 522 | strlen(client_version_string)) != strlen(client_version_string)) |
536 | fatal("write: %.100s", strerror(errno)); | 523 | fatal("write: %.100s", strerror(errno)); |
@@ -549,50 +536,27 @@ ssh_exchange_identification(int timeout_ms) | |||
549 | int remote_major, remote_minor, mismatch; | 536 | int remote_major, remote_minor, mismatch; |
550 | int connection_in = packet_get_connection_in(); | 537 | int connection_in = packet_get_connection_in(); |
551 | int connection_out = packet_get_connection_out(); | 538 | int connection_out = packet_get_connection_out(); |
552 | int minor1 = PROTOCOL_MINOR_1, client_banner_sent = 0; | ||
553 | u_int i, n; | 539 | u_int i, n; |
554 | size_t len; | 540 | size_t len; |
555 | int fdsetsz, remaining, rc; | 541 | int rc; |
556 | struct timeval t_start, t_remaining; | ||
557 | fd_set *fdset; | ||
558 | |||
559 | fdsetsz = howmany(connection_in + 1, NFDBITS) * sizeof(fd_mask); | ||
560 | fdset = xcalloc(1, fdsetsz); | ||
561 | 542 | ||
562 | /* | 543 | send_client_banner(connection_out, 0); |
563 | * If we are SSH2-only then we can send the banner immediately and | ||
564 | * save a round-trip. | ||
565 | */ | ||
566 | if (options.protocol == SSH_PROTO_2) { | ||
567 | enable_compat20(); | ||
568 | send_client_banner(connection_out, 0); | ||
569 | client_banner_sent = 1; | ||
570 | } | ||
571 | 544 | ||
572 | /* Read other side's version identification. */ | 545 | /* Read other side's version identification. */ |
573 | remaining = timeout_ms; | ||
574 | for (n = 0;;) { | 546 | for (n = 0;;) { |
575 | for (i = 0; i < sizeof(buf) - 1; i++) { | 547 | for (i = 0; i < sizeof(buf) - 1; i++) { |
576 | if (timeout_ms > 0) { | 548 | if (timeout_ms > 0) { |
577 | gettimeofday(&t_start, NULL); | 549 | rc = waitrfd(connection_in, &timeout_ms); |
578 | ms_to_timeval(&t_remaining, remaining); | 550 | if (rc == -1 && errno == ETIMEDOUT) { |
579 | FD_SET(connection_in, fdset); | ||
580 | rc = select(connection_in + 1, fdset, NULL, | ||
581 | fdset, &t_remaining); | ||
582 | ms_subtract_diff(&t_start, &remaining); | ||
583 | if (rc == 0 || remaining <= 0) | ||
584 | fatal("Connection timed out during " | 551 | fatal("Connection timed out during " |
585 | "banner exchange"); | 552 | "banner exchange"); |
586 | if (rc == -1) { | 553 | } else if (rc == -1) { |
587 | if (errno == EINTR) | 554 | fatal("%s: %s", |
588 | continue; | 555 | __func__, strerror(errno)); |
589 | fatal("ssh_exchange_identification: " | ||
590 | "select: %s", strerror(errno)); | ||
591 | } | 556 | } |
592 | } | 557 | } |
593 | 558 | ||
594 | len = atomicio(read, connection_in, &buf[i], 1); | 559 | len = atomicio(read, connection_in, &buf[i], 1); |
595 | |||
596 | if (len != 1 && errno == EPIPE) | 560 | if (len != 1 && errno == EPIPE) |
597 | fatal("ssh_exchange_identification: " | 561 | fatal("ssh_exchange_identification: " |
598 | "Connection closed by remote host"); | 562 | "Connection closed by remote host"); |
@@ -618,7 +582,6 @@ ssh_exchange_identification(int timeout_ms) | |||
618 | debug("ssh_exchange_identification: %s", buf); | 582 | debug("ssh_exchange_identification: %s", buf); |
619 | } | 583 | } |
620 | server_version_string = xstrdup(buf); | 584 | server_version_string = xstrdup(buf); |
621 | free(fdset); | ||
622 | 585 | ||
623 | /* | 586 | /* |
624 | * Check that the versions match. In future this might accept | 587 | * Check that the versions match. In future this might accept |
@@ -634,51 +597,25 @@ ssh_exchange_identification(int timeout_ms) | |||
634 | mismatch = 0; | 597 | mismatch = 0; |
635 | 598 | ||
636 | switch (remote_major) { | 599 | switch (remote_major) { |
600 | case 2: | ||
601 | break; | ||
637 | case 1: | 602 | case 1: |
638 | if (remote_minor == 99 && | 603 | if (remote_minor != 99) |
639 | (options.protocol & SSH_PROTO_2) && | ||
640 | !(options.protocol & SSH_PROTO_1_PREFERRED)) { | ||
641 | enable_compat20(); | ||
642 | break; | ||
643 | } | ||
644 | if (!(options.protocol & SSH_PROTO_1)) { | ||
645 | mismatch = 1; | 604 | mismatch = 1; |
646 | break; | ||
647 | } | ||
648 | if (remote_minor < 3) { | ||
649 | fatal("Remote machine has too old SSH software version."); | ||
650 | } else if (remote_minor == 3 || remote_minor == 4) { | ||
651 | /* We speak 1.3, too. */ | ||
652 | enable_compat13(); | ||
653 | minor1 = 3; | ||
654 | if (options.forward_agent) { | ||
655 | logit("Agent forwarding disabled for protocol 1.3"); | ||
656 | options.forward_agent = 0; | ||
657 | } | ||
658 | } | ||
659 | break; | 605 | break; |
660 | case 2: | ||
661 | if (options.protocol & SSH_PROTO_2) { | ||
662 | enable_compat20(); | ||
663 | break; | ||
664 | } | ||
665 | /* FALLTHROUGH */ | ||
666 | default: | 606 | default: |
667 | mismatch = 1; | 607 | mismatch = 1; |
668 | break; | 608 | break; |
669 | } | 609 | } |
670 | if (mismatch) | 610 | if (mismatch) |
671 | fatal("Protocol major versions differ: %d vs. %d", | 611 | fatal("Protocol major versions differ: %d vs. %d", |
672 | (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, | 612 | PROTOCOL_MAJOR_2, remote_major); |
673 | remote_major); | ||
674 | if ((datafellows & SSH_BUG_DERIVEKEY) != 0) | 613 | if ((datafellows & SSH_BUG_DERIVEKEY) != 0) |
675 | fatal("Server version \"%.100s\" uses unsafe key agreement; " | 614 | fatal("Server version \"%.100s\" uses unsafe key agreement; " |
676 | "refusing connection", remote_version); | 615 | "refusing connection", remote_version); |
677 | if ((datafellows & SSH_BUG_RSASIGMD5) != 0) | 616 | if ((datafellows & SSH_BUG_RSASIGMD5) != 0) |
678 | logit("Server version \"%.100s\" uses unsafe RSA signature " | 617 | logit("Server version \"%.100s\" uses unsafe RSA signature " |
679 | "scheme; disabling use of RSA keys", remote_version); | 618 | "scheme; disabling use of RSA keys", remote_version); |
680 | if (!client_banner_sent) | ||
681 | send_client_banner(connection_out, minor1); | ||
682 | chop(server_version_string); | 619 | chop(server_version_string); |
683 | } | 620 | } |
684 | 621 | ||
@@ -707,7 +644,7 @@ confirm(const char *prompt) | |||
707 | } | 644 | } |
708 | 645 | ||
709 | static int | 646 | static int |
710 | check_host_cert(const char *host, const Key *host_key) | 647 | check_host_cert(const char *host, const struct sshkey *host_key) |
711 | { | 648 | { |
712 | const char *reason; | 649 | const char *reason; |
713 | 650 | ||
@@ -805,13 +742,13 @@ get_hostfile_hostname_ipaddr(char *hostname, struct sockaddr *hostaddr, | |||
805 | #define ROQUIET 2 | 742 | #define ROQUIET 2 |
806 | static int | 743 | static int |
807 | check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | 744 | check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, |
808 | Key *host_key, int readonly, | 745 | struct sshkey *host_key, int readonly, |
809 | char **user_hostfiles, u_int num_user_hostfiles, | 746 | char **user_hostfiles, u_int num_user_hostfiles, |
810 | char **system_hostfiles, u_int num_system_hostfiles) | 747 | char **system_hostfiles, u_int num_system_hostfiles) |
811 | { | 748 | { |
812 | HostStatus host_status; | 749 | HostStatus host_status; |
813 | HostStatus ip_status; | 750 | HostStatus ip_status; |
814 | Key *raw_key = NULL; | 751 | struct sshkey *raw_key = NULL; |
815 | char *ip = NULL, *host = NULL; | 752 | char *ip = NULL, *host = NULL; |
816 | char hostline[1000], *hostp, *fp, *ra; | 753 | char hostline[1000], *hostp, *fp, *ra; |
817 | char msg[1024]; | 754 | char msg[1024]; |
@@ -819,7 +756,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
819 | const struct hostkey_entry *host_found, *ip_found; | 756 | const struct hostkey_entry *host_found, *ip_found; |
820 | int len, cancelled_forwarding = 0; | 757 | int len, cancelled_forwarding = 0; |
821 | int local = sockaddr_is_local(hostaddr); | 758 | int local = sockaddr_is_local(hostaddr); |
822 | int r, want_cert = key_is_cert(host_key), host_ip_differ = 0; | 759 | int r, want_cert = sshkey_is_cert(host_key), host_ip_differ = 0; |
823 | int hostkey_trusted = 0; /* Known or explicitly accepted by user */ | 760 | int hostkey_trusted = 0; /* Known or explicitly accepted by user */ |
824 | struct hostkeys *host_hostkeys, *ip_hostkeys; | 761 | struct hostkeys *host_hostkeys, *ip_hostkeys; |
825 | u_int i; | 762 | u_int i; |
@@ -870,8 +807,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
870 | 807 | ||
871 | retry: | 808 | retry: |
872 | /* Reload these as they may have changed on cert->key downgrade */ | 809 | /* Reload these as they may have changed on cert->key downgrade */ |
873 | want_cert = key_is_cert(host_key); | 810 | want_cert = sshkey_is_cert(host_key); |
874 | type = key_type(host_key); | 811 | type = sshkey_type(host_key); |
875 | 812 | ||
876 | /* | 813 | /* |
877 | * Check if the host key is present in the user's list of known | 814 | * Check if the host key is present in the user's list of known |
@@ -891,7 +828,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
891 | if (host_status == HOST_CHANGED && | 828 | if (host_status == HOST_CHANGED && |
892 | (ip_status != HOST_CHANGED || | 829 | (ip_status != HOST_CHANGED || |
893 | (ip_found != NULL && | 830 | (ip_found != NULL && |
894 | !key_equal(ip_found->key, host_found->key)))) | 831 | !sshkey_equal(ip_found->key, host_found->key)))) |
895 | host_ip_differ = 1; | 832 | host_ip_differ = 1; |
896 | } else | 833 | } else |
897 | ip_status = host_status; | 834 | ip_status = host_status; |
@@ -903,7 +840,9 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
903 | host, type, want_cert ? "certificate" : "key"); | 840 | host, type, want_cert ? "certificate" : "key"); |
904 | debug("Found %s in %s:%lu", want_cert ? "CA key" : "key", | 841 | debug("Found %s in %s:%lu", want_cert ? "CA key" : "key", |
905 | host_found->file, host_found->line); | 842 | host_found->file, host_found->line); |
906 | if (want_cert && !check_host_cert(hostname, host_key)) | 843 | if (want_cert && |
844 | !check_host_cert(options.host_key_alias == NULL ? | ||
845 | hostname : options.host_key_alias, host_key)) | ||
907 | goto fail; | 846 | goto fail; |
908 | if (options.check_host_ip && ip_status == HOST_NEW) { | 847 | if (options.check_host_ip && ip_status == HOST_NEW) { |
909 | if (readonly || want_cert) | 848 | if (readonly || want_cert) |
@@ -947,7 +886,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
947 | if (readonly || want_cert) | 886 | if (readonly || want_cert) |
948 | goto fail; | 887 | goto fail; |
949 | /* The host is new. */ | 888 | /* The host is new. */ |
950 | if (options.strict_host_key_checking == 1) { | 889 | if (options.strict_host_key_checking == |
890 | SSH_STRICT_HOSTKEY_YES) { | ||
951 | /* | 891 | /* |
952 | * User has requested strict host key checking. We | 892 | * User has requested strict host key checking. We |
953 | * will not add the host key automatically. The only | 893 | * will not add the host key automatically. The only |
@@ -956,7 +896,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
956 | error("No %s host key is known for %.200s and you " | 896 | error("No %s host key is known for %.200s and you " |
957 | "have requested strict checking.", type, host); | 897 | "have requested strict checking.", type, host); |
958 | goto fail; | 898 | goto fail; |
959 | } else if (options.strict_host_key_checking == 2) { | 899 | } else if (options.strict_host_key_checking == |
900 | SSH_STRICT_HOSTKEY_ASK) { | ||
960 | char msg1[1024], msg2[1024]; | 901 | char msg1[1024], msg2[1024]; |
961 | 902 | ||
962 | if (show_other_keys(host_hostkeys, host_key)) | 903 | if (show_other_keys(host_hostkeys, host_key)) |
@@ -1000,8 +941,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
1000 | hostkey_trusted = 1; /* user explicitly confirmed */ | 941 | hostkey_trusted = 1; /* user explicitly confirmed */ |
1001 | } | 942 | } |
1002 | /* | 943 | /* |
1003 | * If not in strict mode, add the key automatically to the | 944 | * If in "new" or "off" strict mode, add the key automatically |
1004 | * local known_hosts file. | 945 | * to the local known_hosts file. |
1005 | */ | 946 | */ |
1006 | if (options.check_host_ip && ip_status == HOST_NEW) { | 947 | if (options.check_host_ip && ip_status == HOST_NEW) { |
1007 | snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); | 948 | snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); |
@@ -1043,7 +984,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
1043 | * If strict host key checking is in use, the user will have | 984 | * If strict host key checking is in use, the user will have |
1044 | * to edit the key manually and we can only abort. | 985 | * to edit the key manually and we can only abort. |
1045 | */ | 986 | */ |
1046 | if (options.strict_host_key_checking) { | 987 | if (options.strict_host_key_checking != |
988 | SSH_STRICT_HOSTKEY_OFF) { | ||
1047 | error("%s host key for %.200s was revoked and you have " | 989 | error("%s host key for %.200s was revoked and you have " |
1048 | "requested strict checking.", type, host); | 990 | "requested strict checking.", type, host); |
1049 | goto fail; | 991 | goto fail; |
@@ -1092,7 +1034,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
1092 | warn_changed_key(host_key); | 1034 | warn_changed_key(host_key); |
1093 | error("Add correct host key in %.100s to get rid of this message.", | 1035 | error("Add correct host key in %.100s to get rid of this message.", |
1094 | user_hostfiles[0]); | 1036 | user_hostfiles[0]); |
1095 | error("Offending %s key in %s:%lu", key_type(host_found->key), | 1037 | error("Offending %s key in %s:%lu", |
1038 | sshkey_type(host_found->key), | ||
1096 | host_found->file, host_found->line); | 1039 | host_found->file, host_found->line); |
1097 | error(" remove with:"); | 1040 | error(" remove with:"); |
1098 | error(" ssh-keygen -f \"%s\" -R \"%s\"", | 1041 | error(" ssh-keygen -f \"%s\" -R \"%s\"", |
@@ -1102,7 +1045,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
1102 | * If strict host key checking is in use, the user will have | 1045 | * If strict host key checking is in use, the user will have |
1103 | * to edit the key manually and we can only abort. | 1046 | * to edit the key manually and we can only abort. |
1104 | */ | 1047 | */ |
1105 | if (options.strict_host_key_checking) { | 1048 | if (options.strict_host_key_checking != |
1049 | SSH_STRICT_HOSTKEY_OFF) { | ||
1106 | error("%s host key for %.200s has changed and you have " | 1050 | error("%s host key for %.200s has changed and you have " |
1107 | "requested strict checking.", type, host); | 1051 | "requested strict checking.", type, host); |
1108 | goto fail; | 1052 | goto fail; |
@@ -1189,15 +1133,17 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
1189 | "\nMatching host key in %s:%lu", | 1133 | "\nMatching host key in %s:%lu", |
1190 | host_found->file, host_found->line); | 1134 | host_found->file, host_found->line); |
1191 | } | 1135 | } |
1192 | if (options.strict_host_key_checking == 1) { | 1136 | if (options.strict_host_key_checking == |
1193 | logit("%s", msg); | 1137 | SSH_STRICT_HOSTKEY_ASK) { |
1194 | error("Exiting, you have requested strict checking."); | ||
1195 | goto fail; | ||
1196 | } else if (options.strict_host_key_checking == 2) { | ||
1197 | strlcat(msg, "\nAre you sure you want " | 1138 | strlcat(msg, "\nAre you sure you want " |
1198 | "to continue connecting (yes/no)? ", sizeof(msg)); | 1139 | "to continue connecting (yes/no)? ", sizeof(msg)); |
1199 | if (!confirm(msg)) | 1140 | if (!confirm(msg)) |
1200 | goto fail; | 1141 | goto fail; |
1142 | } else if (options.strict_host_key_checking != | ||
1143 | SSH_STRICT_HOSTKEY_OFF) { | ||
1144 | logit("%s", msg); | ||
1145 | error("Exiting, you have requested strict checking."); | ||
1146 | goto fail; | ||
1201 | } else { | 1147 | } else { |
1202 | logit("%s", msg); | 1148 | logit("%s", msg); |
1203 | } | 1149 | } |
@@ -1224,14 +1170,16 @@ fail: | |||
1224 | * search normally. | 1170 | * search normally. |
1225 | */ | 1171 | */ |
1226 | debug("No matching CA found. Retry with plain key"); | 1172 | debug("No matching CA found. Retry with plain key"); |
1227 | raw_key = key_from_private(host_key); | 1173 | if ((r = sshkey_from_private(host_key, &raw_key)) != 0) |
1228 | if (key_drop_cert(raw_key) != 0) | 1174 | fatal("%s: sshkey_from_private: %s", |
1229 | fatal("Couldn't drop certificate"); | 1175 | __func__, ssh_err(r)); |
1176 | if ((r = sshkey_drop_cert(raw_key)) != 0) | ||
1177 | fatal("Couldn't drop certificate: %s", ssh_err(r)); | ||
1230 | host_key = raw_key; | 1178 | host_key = raw_key; |
1231 | goto retry; | 1179 | goto retry; |
1232 | } | 1180 | } |
1233 | if (raw_key != NULL) | 1181 | if (raw_key != NULL) |
1234 | key_free(raw_key); | 1182 | sshkey_free(raw_key); |
1235 | free(ip); | 1183 | free(ip); |
1236 | free(host); | 1184 | free(host); |
1237 | if (host_hostkeys != NULL) | 1185 | if (host_hostkeys != NULL) |
@@ -1243,7 +1191,7 @@ fail: | |||
1243 | 1191 | ||
1244 | /* returns 0 if key verifies or -1 if key does NOT verify */ | 1192 | /* returns 0 if key verifies or -1 if key does NOT verify */ |
1245 | int | 1193 | int |
1246 | verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | 1194 | verify_host_key(char *host, struct sockaddr *hostaddr, struct sshkey *host_key) |
1247 | { | 1195 | { |
1248 | u_int i; | 1196 | u_int i; |
1249 | int r = -1, flags = 0; | 1197 | int r = -1, flags = 0; |
@@ -1279,8 +1227,7 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | |||
1279 | host_key->cert->principals[i]); | 1227 | host_key->cert->principals[i]); |
1280 | } | 1228 | } |
1281 | } else { | 1229 | } else { |
1282 | debug("Server host key: %s %s", compat20 ? | 1230 | debug("Server host key: %s %s", sshkey_ssh_name(host_key), fp); |
1283 | sshkey_ssh_name(host_key) : sshkey_type(host_key), fp); | ||
1284 | } | 1231 | } |
1285 | 1232 | ||
1286 | if (sshkey_equal(previous_host_key, host_key)) { | 1233 | if (sshkey_equal(previous_host_key, host_key)) { |
@@ -1348,8 +1295,8 @@ out: | |||
1348 | free(fp); | 1295 | free(fp); |
1349 | free(cafp); | 1296 | free(cafp); |
1350 | if (r == 0 && host_key != NULL) { | 1297 | if (r == 0 && host_key != NULL) { |
1351 | key_free(previous_host_key); | 1298 | sshkey_free(previous_host_key); |
1352 | previous_host_key = key_from_private(host_key); | 1299 | r = sshkey_from_private(host_key, &previous_host_key); |
1353 | } | 1300 | } |
1354 | 1301 | ||
1355 | return r; | 1302 | return r; |
@@ -1385,17 +1332,8 @@ ssh_login(Sensitive *sensitive, const char *orighost, | |||
1385 | /* key exchange */ | 1332 | /* key exchange */ |
1386 | /* authenticate user */ | 1333 | /* authenticate user */ |
1387 | debug("Authenticating to %s:%d as '%s'", host, port, server_user); | 1334 | debug("Authenticating to %s:%d as '%s'", host, port, server_user); |
1388 | if (compat20) { | 1335 | ssh_kex2(host, hostaddr, port); |
1389 | ssh_kex2(host, hostaddr, port); | 1336 | ssh_userauth2(local_user, server_user, host, sensitive); |
1390 | ssh_userauth2(local_user, server_user, host, sensitive); | ||
1391 | } else { | ||
1392 | #ifdef WITH_SSH1 | ||
1393 | ssh_kex(host, hostaddr); | ||
1394 | ssh_userauth1(local_user, server_user, host, sensitive); | ||
1395 | #else | ||
1396 | fatal("ssh1 is not supported"); | ||
1397 | #endif | ||
1398 | } | ||
1399 | free(local_user); | 1337 | free(local_user); |
1400 | } | 1338 | } |
1401 | 1339 | ||
@@ -1419,10 +1357,9 @@ ssh_put_password(char *password) | |||
1419 | 1357 | ||
1420 | /* print all known host keys for a given host, but skip keys of given type */ | 1358 | /* print all known host keys for a given host, but skip keys of given type */ |
1421 | static int | 1359 | static int |
1422 | show_other_keys(struct hostkeys *hostkeys, Key *key) | 1360 | show_other_keys(struct hostkeys *hostkeys, struct sshkey *key) |
1423 | { | 1361 | { |
1424 | int type[] = { | 1362 | int type[] = { |
1425 | KEY_RSA1, | ||
1426 | KEY_RSA, | 1363 | KEY_RSA, |
1427 | KEY_DSA, | 1364 | KEY_DSA, |
1428 | KEY_ECDSA, | 1365 | KEY_ECDSA, |
@@ -1460,7 +1397,7 @@ show_other_keys(struct hostkeys *hostkeys, Key *key) | |||
1460 | } | 1397 | } |
1461 | 1398 | ||
1462 | static void | 1399 | static void |
1463 | warn_changed_key(Key *host_key) | 1400 | warn_changed_key(struct sshkey *host_key) |
1464 | { | 1401 | { |
1465 | char *fp; | 1402 | char *fp; |
1466 | 1403 | ||
@@ -1523,7 +1460,7 @@ ssh_local_cmd(const char *args) | |||
1523 | } | 1460 | } |
1524 | 1461 | ||
1525 | void | 1462 | void |
1526 | maybe_add_key_to_agent(char *authfile, Key *private, char *comment, | 1463 | maybe_add_key_to_agent(char *authfile, struct sshkey *private, char *comment, |
1527 | char *passphrase) | 1464 | char *passphrase) |
1528 | { | 1465 | { |
1529 | int auth_sock = -1, r; | 1466 | int auth_sock = -1, r; |