diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | compat.c | 7 | ||||
-rw-r--r-- | compat.h | 3 | ||||
-rw-r--r-- | readconf.h | 6 | ||||
-rw-r--r-- | ssh.c | 46 | ||||
-rw-r--r-- | sshconnect1.c | 5 | ||||
-rw-r--r-- | sshconnect2.c | 272 |
7 files changed, 269 insertions, 77 deletions
@@ -6,6 +6,11 @@ | |||
6 | - stevesk@cvs.openbsd.org 2001/03/08 20:44:48 | 6 | - stevesk@cvs.openbsd.org 2001/03/08 20:44:48 |
7 | [sftp.1] | 7 | [sftp.1] |
8 | spelling, cleanup; ok deraadt@ | 8 | spelling, cleanup; ok deraadt@ |
9 | - markus@cvs.openbsd.org 2001/03/08 21:42:33 | ||
10 | [compat.c compat.h readconf.h ssh.c sshconnect1.c sshconnect2.c] | ||
11 | implement client side of SSH2_MSG_USERAUTH_PK_OK (test public key -> | ||
12 | no need to do enter passphrase or do expensive sign operations if the | ||
13 | server does not accept key). | ||
9 | 14 | ||
10 | 20010308 | 15 | 20010308 |
11 | - OpenBSD CVS Sync | 16 | - OpenBSD CVS Sync |
@@ -4452,4 +4457,4 @@ | |||
4452 | - Wrote replacements for strlcpy and mkdtemp | 4457 | - Wrote replacements for strlcpy and mkdtemp |
4453 | - Released 1.0pre1 | 4458 | - Released 1.0pre1 |
4454 | 4459 | ||
4455 | $Id: ChangeLog,v 1.929 2001/03/09 00:09:02 mouring Exp $ | 4460 | $Id: ChangeLog,v 1.930 2001/03/09 00:12:22 mouring Exp $ |
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: compat.c,v 1.36 2001/02/27 11:00:11 markus Exp $"); | 26 | RCSID("$OpenBSD: compat.c,v 1.37 2001/03/08 21:42:31 markus Exp $"); |
27 | 27 | ||
28 | #ifdef HAVE_LIBPCRE | 28 | #ifdef HAVE_LIBPCRE |
29 | # include <pcreposix.h> | 29 | # include <pcreposix.h> |
@@ -78,11 +78,12 @@ compat_datafellows(const char *version) | |||
78 | SSH_OLD_SESSIONID|SSH_BUG_DEBUG }, | 78 | SSH_OLD_SESSIONID|SSH_BUG_DEBUG }, |
79 | { "^2\\.0\\.1[3-9]", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| | 79 | { "^2\\.0\\.1[3-9]", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| |
80 | SSH_OLD_SESSIONID|SSH_BUG_DEBUG| | 80 | SSH_OLD_SESSIONID|SSH_BUG_DEBUG| |
81 | SSH_BUG_PKSERVICE|SSH_BUG_X11FWD }, | 81 | SSH_BUG_PKSERVICE|SSH_BUG_X11FWD| |
82 | SSH_BUG_PKOK }, | ||
82 | { "^2\\.0\\.", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| | 83 | { "^2\\.0\\.", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| |
83 | SSH_OLD_SESSIONID|SSH_BUG_DEBUG| | 84 | SSH_OLD_SESSIONID|SSH_BUG_DEBUG| |
84 | SSH_BUG_PKSERVICE|SSH_BUG_X11FWD| | 85 | SSH_BUG_PKSERVICE|SSH_BUG_X11FWD| |
85 | SSH_BUG_PKAUTH }, | 86 | SSH_BUG_PKAUTH|SSH_BUG_PKOK }, |
86 | { "^2\\.[23]\\.0", SSH_BUG_HMAC}, | 87 | { "^2\\.[23]\\.0", SSH_BUG_HMAC}, |
87 | { "^2\\.[2-9]\\.", 0 }, | 88 | { "^2\\.[2-9]\\.", 0 }, |
88 | { "^2\\.4$", SSH_OLD_SESSIONID}, /* Van Dyke */ | 89 | { "^2\\.4$", SSH_OLD_SESSIONID}, /* Van Dyke */ |
@@ -21,7 +21,7 @@ | |||
21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
23 | */ | 23 | */ |
24 | /* RCSID("$OpenBSD: compat.h,v 1.15 2001/02/19 09:53:31 markus Exp $"); */ | 24 | /* RCSID("$OpenBSD: compat.h,v 1.16 2001/03/08 21:42:32 markus Exp $"); */ |
25 | 25 | ||
26 | #ifndef COMPAT_H | 26 | #ifndef COMPAT_H |
27 | #define COMPAT_H | 27 | #define COMPAT_H |
@@ -40,6 +40,7 @@ | |||
40 | #define SSH_BUG_DEBUG 0x0040 | 40 | #define SSH_BUG_DEBUG 0x0040 |
41 | #define SSH_BUG_BANNER 0x0080 | 41 | #define SSH_BUG_BANNER 0x0080 |
42 | #define SSH_BUG_IGNOREMSG 0x0100 | 42 | #define SSH_BUG_IGNOREMSG 0x0100 |
43 | #define SSH_BUG_PKOK 0x0200 | ||
43 | 44 | ||
44 | void enable_compat13(void); | 45 | void enable_compat13(void); |
45 | void enable_compat20(void); | 46 | void enable_compat20(void); |
diff --git a/readconf.h b/readconf.h index 575b2646d..97615620e 100644 --- a/readconf.h +++ b/readconf.h | |||
@@ -11,11 +11,13 @@ | |||
11 | * called by a name other than "ssh" or "Secure Shell". | 11 | * called by a name other than "ssh" or "Secure Shell". |
12 | */ | 12 | */ |
13 | 13 | ||
14 | /* RCSID("$OpenBSD: readconf.h,v 1.26 2001/02/11 12:59:25 markus Exp $"); */ | 14 | /* RCSID("$OpenBSD: readconf.h,v 1.27 2001/03/08 21:42:32 markus Exp $"); */ |
15 | 15 | ||
16 | #ifndef READCONF_H | 16 | #ifndef READCONF_H |
17 | #define READCONF_H | 17 | #define READCONF_H |
18 | 18 | ||
19 | #include "key.h" | ||
20 | |||
19 | /* Data structure for representing a forwarding request. */ | 21 | /* Data structure for representing a forwarding request. */ |
20 | 22 | ||
21 | typedef struct { | 23 | typedef struct { |
@@ -83,7 +85,7 @@ typedef struct { | |||
83 | 85 | ||
84 | int num_identity_files; /* Number of files for RSA/DSA identities. */ | 86 | int num_identity_files; /* Number of files for RSA/DSA identities. */ |
85 | char *identity_files[SSH_MAX_IDENTITY_FILES]; | 87 | char *identity_files[SSH_MAX_IDENTITY_FILES]; |
86 | int identity_files_type[SSH_MAX_IDENTITY_FILES]; | 88 | Key *identity_keys[SSH_MAX_IDENTITY_FILES]; |
87 | 89 | ||
88 | /* Local TCP/IP forward requests. */ | 90 | /* Local TCP/IP forward requests. */ |
89 | int num_local_forwards; | 91 | int num_local_forwards; |
@@ -39,7 +39,7 @@ | |||
39 | */ | 39 | */ |
40 | 40 | ||
41 | #include "includes.h" | 41 | #include "includes.h" |
42 | RCSID("$OpenBSD: ssh.c,v 1.103 2001/03/04 17:42:28 millert Exp $"); | 42 | RCSID("$OpenBSD: ssh.c,v 1.104 2001/03/08 21:42:32 markus Exp $"); |
43 | 43 | ||
44 | #include <openssl/evp.h> | 44 | #include <openssl/evp.h> |
45 | #include <openssl/err.h> | 45 | #include <openssl/err.h> |
@@ -233,7 +233,7 @@ rsh_connect(char *host, char *user, Buffer * command) | |||
233 | 233 | ||
234 | int ssh_session(void); | 234 | int ssh_session(void); |
235 | int ssh_session2(void); | 235 | int ssh_session2(void); |
236 | int guess_identity_file_type(const char *filename); | 236 | void load_public_identity_files(void); |
237 | 237 | ||
238 | /* | 238 | /* |
239 | * Main program for the ssh client. | 239 | * Main program for the ssh client. |
@@ -678,15 +678,11 @@ main(int ac, char **av) | |||
678 | } | 678 | } |
679 | exit(1); | 679 | exit(1); |
680 | } | 680 | } |
681 | /* Expand ~ in options.identity_files, known host file names. */ | 681 | /* load options.identity_files */ |
682 | /* XXX mem-leaks */ | 682 | load_public_identity_files(); |
683 | for (i = 0; i < options.num_identity_files; i++) { | 683 | |
684 | options.identity_files[i] = | 684 | /* Expand ~ in known host file names. */ |
685 | tilde_expand_filename(options.identity_files[i], original_real_uid); | 685 | /* XXX mem-leaks: */ |
686 | options.identity_files_type[i] = guess_identity_file_type(options.identity_files[i]); | ||
687 | debug("identity file %s type %d", options.identity_files[i], | ||
688 | options.identity_files_type[i]); | ||
689 | } | ||
690 | options.system_hostfile = | 686 | options.system_hostfile = |
691 | tilde_expand_filename(options.system_hostfile, original_real_uid); | 687 | tilde_expand_filename(options.system_hostfile, original_real_uid); |
692 | options.user_hostfile = | 688 | options.user_hostfile = |
@@ -1095,3 +1091,31 @@ guess_identity_file_type(const char *filename) | |||
1095 | key_free(public); | 1091 | key_free(public); |
1096 | return type; | 1092 | return type; |
1097 | } | 1093 | } |
1094 | |||
1095 | void | ||
1096 | load_public_identity_files(void) | ||
1097 | { | ||
1098 | char *filename; | ||
1099 | Key *public; | ||
1100 | int i; | ||
1101 | |||
1102 | for (i = 0; i < options.num_identity_files; i++) { | ||
1103 | filename = tilde_expand_filename(options.identity_files[i], | ||
1104 | original_real_uid); | ||
1105 | public = key_new(KEY_RSA1); | ||
1106 | if (!load_public_key(filename, public, NULL)) { | ||
1107 | key_free(public); | ||
1108 | public = key_new(KEY_UNSPEC); | ||
1109 | if (!try_load_public_key(filename, public, NULL)) { | ||
1110 | debug("unknown identity file %s", filename); | ||
1111 | key_free(public); | ||
1112 | public = NULL; | ||
1113 | } | ||
1114 | } | ||
1115 | debug("identity file %s type %d", filename, | ||
1116 | public ? public->type : -1); | ||
1117 | xfree(options.identity_files[i]); | ||
1118 | options.identity_files[i] = filename; | ||
1119 | options.identity_keys[i] = public; | ||
1120 | } | ||
1121 | } | ||
diff --git a/sshconnect1.c b/sshconnect1.c index c5ff7213a..3d45ac5a2 100644 --- a/sshconnect1.c +++ b/sshconnect1.c | |||
@@ -13,7 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include "includes.h" | 15 | #include "includes.h" |
16 | RCSID("$OpenBSD: sshconnect1.c,v 1.27 2001/02/15 23:19:59 markus Exp $"); | 16 | RCSID("$OpenBSD: sshconnect1.c,v 1.28 2001/03/08 21:42:33 markus Exp $"); |
17 | 17 | ||
18 | #include <openssl/bn.h> | 18 | #include <openssl/bn.h> |
19 | #include <openssl/evp.h> | 19 | #include <openssl/evp.h> |
@@ -1017,7 +1017,8 @@ ssh_userauth( | |||
1017 | 1017 | ||
1018 | /* Try RSA authentication for each identity. */ | 1018 | /* Try RSA authentication for each identity. */ |
1019 | for (i = 0; i < options.num_identity_files; i++) | 1019 | for (i = 0; i < options.num_identity_files; i++) |
1020 | if (options.identity_files_type[i] == KEY_RSA1 && | 1020 | if (options.identity_keys[i] != NULL && |
1021 | options.identity_keys[i]->type == KEY_RSA1 && | ||
1021 | try_rsa_authentication(options.identity_files[i])) | 1022 | try_rsa_authentication(options.identity_files[i])) |
1022 | return; | 1023 | return; |
1023 | } | 1024 | } |
diff --git a/sshconnect2.c b/sshconnect2.c index 0baecf0a5..81e1aef93 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: sshconnect2.c,v 1.50 2001/03/05 17:17:21 markus Exp $"); | 26 | RCSID("$OpenBSD: sshconnect2.c,v 1.51 2001/03/08 21:42:33 markus Exp $"); |
27 | 27 | ||
28 | #include <openssl/bn.h> | 28 | #include <openssl/bn.h> |
29 | #include <openssl/md5.h> | 29 | #include <openssl/md5.h> |
@@ -467,6 +467,10 @@ struct Authctxt { | |||
467 | AuthenticationConnection *agent; | 467 | AuthenticationConnection *agent; |
468 | Authmethod *method; | 468 | Authmethod *method; |
469 | int success; | 469 | int success; |
470 | char *authlist; | ||
471 | Key *last_key; | ||
472 | sign_cb_fn *last_key_sign; | ||
473 | int last_key_hint; | ||
470 | }; | 474 | }; |
471 | struct Authmethod { | 475 | struct Authmethod { |
472 | char *name; /* string to compare against server's list */ | 476 | char *name; /* string to compare against server's list */ |
@@ -480,12 +484,20 @@ void input_userauth_failure(int type, int plen, void *ctxt); | |||
480 | void input_userauth_banner(int type, int plen, void *ctxt); | 484 | void input_userauth_banner(int type, int plen, void *ctxt); |
481 | void input_userauth_error(int type, int plen, void *ctxt); | 485 | void input_userauth_error(int type, int plen, void *ctxt); |
482 | void input_userauth_info_req(int type, int plen, void *ctxt); | 486 | void input_userauth_info_req(int type, int plen, void *ctxt); |
487 | void input_userauth_pk_ok(int type, int plen, void *ctxt); | ||
483 | 488 | ||
484 | int userauth_none(Authctxt *authctxt); | 489 | int userauth_none(Authctxt *authctxt); |
485 | int userauth_pubkey(Authctxt *authctxt); | 490 | int userauth_pubkey(Authctxt *authctxt); |
486 | int userauth_passwd(Authctxt *authctxt); | 491 | int userauth_passwd(Authctxt *authctxt); |
487 | int userauth_kbdint(Authctxt *authctxt); | 492 | int userauth_kbdint(Authctxt *authctxt); |
488 | 493 | ||
494 | void userauth(Authctxt *authctxt, char *authlist); | ||
495 | |||
496 | int | ||
497 | sign_and_send_pubkey(Authctxt *authctxt, Key *k, | ||
498 | sign_cb_fn *sign_callback); | ||
499 | void clear_auth_state(Authctxt *authctxt); | ||
500 | |||
489 | void authmethod_clear(void); | 501 | void authmethod_clear(void); |
490 | Authmethod *authmethod_get(char *authlist); | 502 | Authmethod *authmethod_get(char *authlist); |
491 | Authmethod *authmethod_lookup(const char *name); | 503 | Authmethod *authmethod_lookup(const char *name); |
@@ -546,6 +558,7 @@ ssh_userauth2(const char *server_user, char *host) | |||
546 | authctxt.service = "ssh-connection"; /* service name */ | 558 | authctxt.service = "ssh-connection"; /* service name */ |
547 | authctxt.success = 0; | 559 | authctxt.success = 0; |
548 | authctxt.method = authmethod_lookup("none"); | 560 | authctxt.method = authmethod_lookup("none"); |
561 | authctxt.authlist = NULL; | ||
549 | if (authctxt.method == NULL) | 562 | if (authctxt.method == NULL) |
550 | fatal("ssh_userauth2: internal error: cannot send userauth none request"); | 563 | fatal("ssh_userauth2: internal error: cannot send userauth none request"); |
551 | authmethod_clear(); | 564 | authmethod_clear(); |
@@ -565,6 +578,30 @@ ssh_userauth2(const char *server_user, char *host) | |||
565 | debug("ssh-userauth2 successful: method %s", authctxt.method->name); | 578 | debug("ssh-userauth2 successful: method %s", authctxt.method->name); |
566 | } | 579 | } |
567 | void | 580 | void |
581 | userauth(Authctxt *authctxt, char *authlist) | ||
582 | { | ||
583 | if (authlist == NULL) { | ||
584 | authlist = authctxt->authlist; | ||
585 | } else { | ||
586 | if (authctxt->authlist) | ||
587 | xfree(authctxt->authlist); | ||
588 | authctxt->authlist = authlist; | ||
589 | } | ||
590 | for (;;) { | ||
591 | Authmethod *method = authmethod_get(authlist); | ||
592 | if (method == NULL) | ||
593 | fatal("Permission denied (%s).", authlist); | ||
594 | authctxt->method = method; | ||
595 | if (method->userauth(authctxt) != 0) { | ||
596 | debug2("we sent a %s packet, wait for reply", method->name); | ||
597 | break; | ||
598 | } else { | ||
599 | debug2("we did not send a packet, disable method"); | ||
600 | method->enabled = NULL; | ||
601 | } | ||
602 | } | ||
603 | } | ||
604 | void | ||
568 | input_userauth_error(int type, int plen, void *ctxt) | 605 | input_userauth_error(int type, int plen, void *ctxt) |
569 | { | 606 | { |
570 | fatal("input_userauth_error: bad message during authentication: " | 607 | fatal("input_userauth_error: bad message during authentication: " |
@@ -587,12 +624,14 @@ input_userauth_success(int type, int plen, void *ctxt) | |||
587 | Authctxt *authctxt = ctxt; | 624 | Authctxt *authctxt = ctxt; |
588 | if (authctxt == NULL) | 625 | if (authctxt == NULL) |
589 | fatal("input_userauth_success: no authentication context"); | 626 | fatal("input_userauth_success: no authentication context"); |
627 | if (authctxt->authlist) | ||
628 | xfree(authctxt->authlist); | ||
629 | clear_auth_state(authctxt); | ||
590 | authctxt->success = 1; /* break out */ | 630 | authctxt->success = 1; /* break out */ |
591 | } | 631 | } |
592 | void | 632 | void |
593 | input_userauth_failure(int type, int plen, void *ctxt) | 633 | input_userauth_failure(int type, int plen, void *ctxt) |
594 | { | 634 | { |
595 | Authmethod *method = NULL; | ||
596 | Authctxt *authctxt = ctxt; | 635 | Authctxt *authctxt = ctxt; |
597 | char *authlist = NULL; | 636 | char *authlist = NULL; |
598 | int partial; | 637 | int partial; |
@@ -608,20 +647,74 @@ input_userauth_failure(int type, int plen, void *ctxt) | |||
608 | log("Authenticated with partial success."); | 647 | log("Authenticated with partial success."); |
609 | debug("authentications that can continue: %s", authlist); | 648 | debug("authentications that can continue: %s", authlist); |
610 | 649 | ||
611 | for (;;) { | 650 | clear_auth_state(authctxt); |
612 | method = authmethod_get(authlist); | 651 | userauth(authctxt, authlist); |
613 | if (method == NULL) | 652 | } |
614 | fatal("Permission denied (%s).", authlist); | 653 | void |
615 | authctxt->method = method; | 654 | input_userauth_pk_ok(int type, int plen, void *ctxt) |
616 | if (method->userauth(authctxt) != 0) { | 655 | { |
617 | debug2("we sent a %s packet, wait for reply", method->name); | 656 | Authctxt *authctxt = ctxt; |
657 | Key *key = NULL; | ||
658 | Buffer b; | ||
659 | int alen, blen, pktype, sent = 0; | ||
660 | char *pkalg, *pkblob; | ||
661 | |||
662 | if (authctxt == NULL) | ||
663 | fatal("input_userauth_pk_ok: no authentication context"); | ||
664 | if (datafellows & SSH_BUG_PKOK) { | ||
665 | /* this is similar to SSH_BUG_PKAUTH */ | ||
666 | debug2("input_userauth_pk_ok: SSH_BUG_PKOK"); | ||
667 | pkblob = packet_get_string(&blen); | ||
668 | buffer_init(&b); | ||
669 | buffer_append(&b, pkblob, blen); | ||
670 | pkalg = buffer_get_string(&b, &alen); | ||
671 | buffer_free(&b); | ||
672 | } else { | ||
673 | pkalg = packet_get_string(&alen); | ||
674 | pkblob = packet_get_string(&blen); | ||
675 | } | ||
676 | packet_done(); | ||
677 | |||
678 | debug("input_userauth_pk_ok: pkalg %s blen %d lastkey %p hint %d", | ||
679 | pkalg, blen, authctxt->last_key, authctxt->last_key_hint); | ||
680 | |||
681 | do { | ||
682 | if (authctxt->last_key == NULL || | ||
683 | authctxt->last_key_sign == NULL) { | ||
684 | debug("no last key or no sign cb"); | ||
618 | break; | 685 | break; |
619 | } else { | ||
620 | debug2("we did not send a packet, disable method"); | ||
621 | method->enabled = NULL; | ||
622 | } | 686 | } |
623 | } | 687 | debug2("last_key %s", key_fingerprint(authctxt->last_key)); |
624 | xfree(authlist); | 688 | if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) { |
689 | debug("unknown pkalg %s", pkalg); | ||
690 | break; | ||
691 | } | ||
692 | if ((key = key_from_blob(pkblob, blen)) == NULL) { | ||
693 | debug("no key from blob. pkalg %s", pkalg); | ||
694 | break; | ||
695 | } | ||
696 | debug2("input_userauth_pk_ok: fp %s", key_fingerprint(key)); | ||
697 | if (!key_equal(key, authctxt->last_key)) { | ||
698 | debug("key != last_key"); | ||
699 | break; | ||
700 | } | ||
701 | sent = sign_and_send_pubkey(authctxt, key, | ||
702 | authctxt->last_key_sign); | ||
703 | } while(0); | ||
704 | |||
705 | if (key != NULL) | ||
706 | key_free(key); | ||
707 | xfree(pkalg); | ||
708 | xfree(pkblob); | ||
709 | |||
710 | /* unregister */ | ||
711 | clear_auth_state(authctxt); | ||
712 | dispatch_set(SSH2_MSG_USERAUTH_PK_OK, NULL); | ||
713 | |||
714 | /* try another method if we did not send a packet*/ | ||
715 | if (sent == 0) | ||
716 | userauth(authctxt, NULL); | ||
717 | |||
625 | } | 718 | } |
626 | 719 | ||
627 | int | 720 | int |
@@ -633,7 +726,6 @@ userauth_none(Authctxt *authctxt) | |||
633 | packet_put_cstring(authctxt->service); | 726 | packet_put_cstring(authctxt->service); |
634 | packet_put_cstring(authctxt->method->name); | 727 | packet_put_cstring(authctxt->method->name); |
635 | packet_send(); | 728 | packet_send(); |
636 | packet_write_wait(); | ||
637 | return 1; | 729 | return 1; |
638 | } | 730 | } |
639 | 731 | ||
@@ -663,10 +755,22 @@ userauth_passwd(Authctxt *authctxt) | |||
663 | xfree(password); | 755 | xfree(password); |
664 | packet_inject_ignore(64); | 756 | packet_inject_ignore(64); |
665 | packet_send(); | 757 | packet_send(); |
666 | packet_write_wait(); | ||
667 | return 1; | 758 | return 1; |
668 | } | 759 | } |
669 | 760 | ||
761 | void | ||
762 | clear_auth_state(Authctxt *authctxt) | ||
763 | { | ||
764 | /* XXX clear authentication state */ | ||
765 | if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) { | ||
766 | debug3("clear_auth_state: key_free %p", authctxt->last_key); | ||
767 | key_free(authctxt->last_key); | ||
768 | } | ||
769 | authctxt->last_key = NULL; | ||
770 | authctxt->last_key_hint = -2; | ||
771 | authctxt->last_key_sign = NULL; | ||
772 | } | ||
773 | |||
670 | int | 774 | int |
671 | sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) | 775 | sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) |
672 | { | 776 | { |
@@ -678,6 +782,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) | |||
678 | int have_sig = 1; | 782 | int have_sig = 1; |
679 | 783 | ||
680 | debug3("sign_and_send_pubkey"); | 784 | debug3("sign_and_send_pubkey"); |
785 | |||
681 | if (key_to_blob(k, &blob, &bloblen) == 0) { | 786 | if (key_to_blob(k, &blob, &bloblen) == 0) { |
682 | /* we cannot handle this key */ | 787 | /* we cannot handle this key */ |
683 | debug3("sign_and_send_pubkey: cannot handle key"); | 788 | debug3("sign_and_send_pubkey: cannot handle key"); |
@@ -708,7 +813,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) | |||
708 | buffer_put_string(&b, blob, bloblen); | 813 | buffer_put_string(&b, blob, bloblen); |
709 | 814 | ||
710 | /* generate signature */ | 815 | /* generate signature */ |
711 | ret = (*sign_callback)(authctxt, k, &signature, &slen, buffer_ptr(&b), buffer_len(&b)); | 816 | ret = (*sign_callback)(authctxt, k, &signature, &slen, |
817 | buffer_ptr(&b), buffer_len(&b)); | ||
712 | if (ret == -1) { | 818 | if (ret == -1) { |
713 | xfree(blob); | 819 | xfree(blob); |
714 | buffer_free(&b); | 820 | buffer_free(&b); |
@@ -720,6 +826,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) | |||
720 | if (datafellows & SSH_BUG_PKSERVICE) { | 826 | if (datafellows & SSH_BUG_PKSERVICE) { |
721 | buffer_clear(&b); | 827 | buffer_clear(&b); |
722 | buffer_append(&b, session_id2, session_id2_len); | 828 | buffer_append(&b, session_id2, session_id2_len); |
829 | skip = session_id2_len; | ||
723 | buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); | 830 | buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); |
724 | buffer_put_cstring(&b, authctxt->server_user); | 831 | buffer_put_cstring(&b, authctxt->server_user); |
725 | buffer_put_cstring(&b, authctxt->service); | 832 | buffer_put_cstring(&b, authctxt->service); |
@@ -730,6 +837,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) | |||
730 | buffer_put_string(&b, blob, bloblen); | 837 | buffer_put_string(&b, blob, bloblen); |
731 | } | 838 | } |
732 | xfree(blob); | 839 | xfree(blob); |
840 | |||
733 | /* append signature */ | 841 | /* append signature */ |
734 | buffer_put_string(&b, signature, slen); | 842 | buffer_put_string(&b, signature, slen); |
735 | xfree(signature); | 843 | xfree(signature); |
@@ -743,76 +851,113 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) | |||
743 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | 851 | packet_start(SSH2_MSG_USERAUTH_REQUEST); |
744 | packet_put_raw(buffer_ptr(&b), buffer_len(&b)); | 852 | packet_put_raw(buffer_ptr(&b), buffer_len(&b)); |
745 | buffer_free(&b); | 853 | buffer_free(&b); |
746 | |||
747 | /* send */ | ||
748 | packet_send(); | 854 | packet_send(); |
749 | packet_write_wait(); | ||
750 | 855 | ||
751 | return 1; | 856 | return 1; |
752 | } | 857 | } |
753 | 858 | ||
754 | /* sign callback */ | ||
755 | int key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp, | ||
756 | u_char *data, int datalen) | ||
757 | { | ||
758 | return key_sign(key, sigp, lenp, data, datalen); | ||
759 | } | ||
760 | |||
761 | int | 859 | int |
762 | userauth_pubkey_identity(Authctxt *authctxt, char *filename) | 860 | send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback, |
861 | int hint) | ||
763 | { | 862 | { |
764 | Key *k; | 863 | u_char *blob; |
765 | int i, ret, try_next, success = 0; | 864 | int bloblen, have_sig = 0; |
766 | struct stat st; | ||
767 | char *passphrase; | ||
768 | char prompt[300]; | ||
769 | 865 | ||
770 | if (stat(filename, &st) != 0) { | 866 | debug3("send_pubkey_test"); |
771 | debug("key does not exist: %s", filename); | 867 | |
868 | if (key_to_blob(k, &blob, &bloblen) == 0) { | ||
869 | /* we cannot handle this key */ | ||
870 | debug3("send_pubkey_test: cannot handle key"); | ||
772 | return 0; | 871 | return 0; |
773 | } | 872 | } |
774 | debug("try pubkey: %s", filename); | 873 | /* register callback for USERAUTH_PK_OK message */ |
874 | authctxt->last_key_sign = sign_callback; | ||
875 | authctxt->last_key_hint = hint; | ||
876 | authctxt->last_key = k; | ||
877 | dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok); | ||
775 | 878 | ||
776 | k = key_new(KEY_UNSPEC); | 879 | packet_start(SSH2_MSG_USERAUTH_REQUEST); |
777 | if (!load_private_key(filename, "", k, NULL)) { | 880 | packet_put_cstring(authctxt->server_user); |
881 | packet_put_cstring(authctxt->service); | ||
882 | packet_put_cstring(authctxt->method->name); | ||
883 | packet_put_char(have_sig); | ||
884 | if (!(datafellows & SSH_BUG_PKAUTH)) | ||
885 | packet_put_cstring(key_ssh_name(k)); | ||
886 | packet_put_string(blob, bloblen); | ||
887 | xfree(blob); | ||
888 | packet_send(); | ||
889 | return 1; | ||
890 | } | ||
891 | |||
892 | Key * | ||
893 | load_identity_file(char *filename) | ||
894 | { | ||
895 | Key *private; | ||
896 | char prompt[300], *passphrase; | ||
897 | int success = 0, quit, i; | ||
898 | |||
899 | private = key_new(KEY_UNSPEC); | ||
900 | if (!load_private_key(filename, "", private, NULL)) { | ||
778 | if (options.batch_mode) { | 901 | if (options.batch_mode) { |
779 | key_free(k); | 902 | key_free(private); |
780 | return 0; | 903 | return NULL; |
781 | } | 904 | } |
782 | snprintf(prompt, sizeof prompt, | 905 | snprintf(prompt, sizeof prompt, |
783 | "Enter passphrase for key '%.100s': ", filename); | 906 | "Enter passphrase for key '%.100s': ", filename); |
784 | for (i = 0; i < options.number_of_password_prompts; i++) { | 907 | for (i = 0; i < options.number_of_password_prompts; i++) { |
785 | passphrase = read_passphrase(prompt, 0); | 908 | passphrase = read_passphrase(prompt, 0); |
786 | if (strcmp(passphrase, "") != 0) { | 909 | if (strcmp(passphrase, "") != 0) { |
787 | success = load_private_key(filename, passphrase, k, NULL); | 910 | success = load_private_key(filename, |
788 | try_next = 0; | 911 | passphrase, private, NULL); |
912 | quit = 0; | ||
789 | } else { | 913 | } else { |
790 | debug2("no passphrase given, try next key"); | 914 | debug2("no passphrase given, try next key"); |
791 | try_next = 1; | 915 | quit = 1; |
792 | } | 916 | } |
793 | memset(passphrase, 0, strlen(passphrase)); | 917 | memset(passphrase, 0, strlen(passphrase)); |
794 | xfree(passphrase); | 918 | xfree(passphrase); |
795 | if (success || try_next) | 919 | if (success || quit) |
796 | break; | 920 | break; |
797 | debug2("bad passphrase given, try again..."); | 921 | debug2("bad passphrase given, try again..."); |
798 | } | 922 | } |
799 | if (!success) { | 923 | if (!success) { |
800 | key_free(k); | 924 | key_free(private); |
801 | return 0; | 925 | return NULL; |
802 | } | 926 | } |
803 | } | 927 | } |
804 | ret = sign_and_send_pubkey(authctxt, k, key_sign_cb); | 928 | return private; |
805 | key_free(k); | 929 | } |
930 | |||
931 | int | ||
932 | identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp, | ||
933 | u_char *data, int datalen) | ||
934 | { | ||
935 | Key *private; | ||
936 | int idx, ret; | ||
937 | |||
938 | idx = authctxt->last_key_hint; | ||
939 | if (idx < 0) | ||
940 | return -1; | ||
941 | private = load_identity_file(options.identity_files[idx]); | ||
942 | if (private == NULL) | ||
943 | return -1; | ||
944 | ret = key_sign(private, sigp, lenp, data, datalen); | ||
945 | key_free(private); | ||
806 | return ret; | 946 | return ret; |
807 | } | 947 | } |
808 | 948 | ||
809 | /* sign callback */ | ||
810 | int agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp, | 949 | int agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp, |
811 | u_char *data, int datalen) | 950 | u_char *data, int datalen) |
812 | { | 951 | { |
813 | return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen); | 952 | return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen); |
814 | } | 953 | } |
815 | 954 | ||
955 | int key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp, | ||
956 | u_char *data, int datalen) | ||
957 | { | ||
958 | return key_sign(key, sigp, lenp, data, datalen); | ||
959 | } | ||
960 | |||
816 | int | 961 | int |
817 | userauth_pubkey_agent(Authctxt *authctxt) | 962 | userauth_pubkey_agent(Authctxt *authctxt) |
818 | { | 963 | { |
@@ -830,10 +975,11 @@ userauth_pubkey_agent(Authctxt *authctxt) | |||
830 | if (k == NULL) { | 975 | if (k == NULL) { |
831 | debug2("userauth_pubkey_agent: no more keys"); | 976 | debug2("userauth_pubkey_agent: no more keys"); |
832 | } else { | 977 | } else { |
833 | debug("userauth_pubkey_agent: trying agent key %s", comment); | 978 | debug("userauth_pubkey_agent: testing agent key %s", comment); |
834 | xfree(comment); | 979 | xfree(comment); |
835 | ret = sign_and_send_pubkey(authctxt, k, agent_sign_cb); | 980 | ret = send_pubkey_test(authctxt, k, agent_sign_cb, -1); |
836 | key_free(k); | 981 | if (ret == 0) |
982 | key_free(k); | ||
837 | } | 983 | } |
838 | if (ret == 0) | 984 | if (ret == 0) |
839 | debug2("userauth_pubkey_agent: no message sent"); | 985 | debug2("userauth_pubkey_agent: no message sent"); |
@@ -845,6 +991,8 @@ userauth_pubkey(Authctxt *authctxt) | |||
845 | { | 991 | { |
846 | static int idx = 0; | 992 | static int idx = 0; |
847 | int sent = 0; | 993 | int sent = 0; |
994 | Key *key; | ||
995 | char *filename; | ||
848 | 996 | ||
849 | if (authctxt->agent != NULL) { | 997 | if (authctxt->agent != NULL) { |
850 | do { | 998 | do { |
@@ -852,9 +1000,21 @@ userauth_pubkey(Authctxt *authctxt) | |||
852 | } while(!sent && authctxt->agent->howmany > 0); | 1000 | } while(!sent && authctxt->agent->howmany > 0); |
853 | } | 1001 | } |
854 | while (!sent && idx < options.num_identity_files) { | 1002 | while (!sent && idx < options.num_identity_files) { |
855 | if (options.identity_files_type[idx] != KEY_RSA1) | 1003 | key = options.identity_keys[idx]; |
856 | sent = userauth_pubkey_identity(authctxt, | 1004 | filename = options.identity_files[idx]; |
857 | options.identity_files[idx]); | 1005 | if (key == NULL) { |
1006 | debug("try privkey: %s", filename); | ||
1007 | key = load_identity_file(filename); | ||
1008 | if (key != NULL) { | ||
1009 | sent = sign_and_send_pubkey(authctxt, key, | ||
1010 | key_sign_cb); | ||
1011 | key_free(key); | ||
1012 | } | ||
1013 | } else if (key->type != KEY_RSA1) { | ||
1014 | debug("try pubkey: %s", filename); | ||
1015 | sent = send_pubkey_test(authctxt, key, | ||
1016 | identity_sign_cb, idx); | ||
1017 | } | ||
858 | idx++; | 1018 | idx++; |
859 | } | 1019 | } |
860 | return sent; | 1020 | return sent; |
@@ -880,7 +1040,6 @@ userauth_kbdint(Authctxt *authctxt) | |||
880 | packet_put_cstring(options.kbd_interactive_devices ? | 1040 | packet_put_cstring(options.kbd_interactive_devices ? |
881 | options.kbd_interactive_devices : ""); | 1041 | options.kbd_interactive_devices : ""); |
882 | packet_send(); | 1042 | packet_send(); |
883 | packet_write_wait(); | ||
884 | 1043 | ||
885 | dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req); | 1044 | dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req); |
886 | return 1; | 1045 | return 1; |
@@ -938,7 +1097,6 @@ input_userauth_info_req(int type, int plen, void *ctxt) | |||
938 | 1097 | ||
939 | packet_inject_ignore(64); | 1098 | packet_inject_ignore(64); |
940 | packet_send(); | 1099 | packet_send(); |
941 | packet_write_wait(); | ||
942 | } | 1100 | } |
943 | 1101 | ||
944 | /* find auth method */ | 1102 | /* find auth method */ |