diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 148 |
1 files changed, 137 insertions, 11 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index 389bec9e4..18cbbd9f9 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -102,9 +102,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
102 | { | 102 | { |
103 | Kex *kex; | 103 | Kex *kex; |
104 | 104 | ||
105 | #ifdef GSSAPI | ||
106 | char *orig = NULL, *gss = NULL; | ||
107 | char *gss_host = NULL; | ||
108 | #endif | ||
109 | |||
105 | xxx_host = host; | 110 | xxx_host = host; |
106 | xxx_hostaddr = hostaddr; | 111 | xxx_hostaddr = hostaddr; |
107 | 112 | ||
113 | #ifdef GSSAPI | ||
114 | if (options.gss_keyex) { | ||
115 | /* Add the GSSAPI mechanisms currently supported on this | ||
116 | * client to the key exchange algorithm proposal */ | ||
117 | orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
118 | |||
119 | if (options.gss_trust_dns) | ||
120 | gss_host = (char *)get_canonical_hostname(1); | ||
121 | else | ||
122 | gss_host = host; | ||
123 | |||
124 | gss = ssh_gssapi_client_mechanisms(gss_host); | ||
125 | if (gss) { | ||
126 | debug("Offering GSSAPI proposal: %s", gss); | ||
127 | xasprintf(&myproposal[PROPOSAL_KEX_ALGS], | ||
128 | "%s,%s", gss, orig); | ||
129 | } | ||
130 | } | ||
131 | #endif | ||
132 | |||
108 | if (options.ciphers == (char *)-1) { | 133 | if (options.ciphers == (char *)-1) { |
109 | logit("No valid ciphers for protocol version 2 given, using defaults."); | 134 | logit("No valid ciphers for protocol version 2 given, using defaults."); |
110 | options.ciphers = NULL; | 135 | options.ciphers = NULL; |
@@ -132,6 +157,16 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
132 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = | 157 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = |
133 | options.hostkeyalgorithms; | 158 | options.hostkeyalgorithms; |
134 | 159 | ||
160 | #ifdef GSSAPI | ||
161 | /* If we've got GSSAPI algorithms, then we also support the | ||
162 | * 'null' hostkey, as a last resort */ | ||
163 | if (options.gss_keyex && gss) { | ||
164 | orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; | ||
165 | xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], | ||
166 | "%s,null", orig); | ||
167 | } | ||
168 | #endif | ||
169 | |||
135 | if (options.rekey_limit) | 170 | if (options.rekey_limit) |
136 | packet_set_rekey_limit((u_int32_t)options.rekey_limit); | 171 | packet_set_rekey_limit((u_int32_t)options.rekey_limit); |
137 | 172 | ||
@@ -141,10 +176,21 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
141 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; | 176 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; |
142 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; | 177 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; |
143 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; | 178 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; |
179 | #ifdef GSSAPI | ||
180 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; | ||
181 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; | ||
182 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; | ||
183 | #endif | ||
144 | kex->client_version_string=client_version_string; | 184 | kex->client_version_string=client_version_string; |
145 | kex->server_version_string=server_version_string; | 185 | kex->server_version_string=server_version_string; |
146 | kex->verify_host_key=&verify_host_key_callback; | 186 | kex->verify_host_key=&verify_host_key_callback; |
147 | 187 | ||
188 | #ifdef GSSAPI | ||
189 | kex->gss_deleg_creds = options.gss_deleg_creds; | ||
190 | kex->gss_trust_dns = options.gss_trust_dns; | ||
191 | kex->gss_host = gss_host; | ||
192 | #endif | ||
193 | |||
148 | xxx_kex = kex; | 194 | xxx_kex = kex; |
149 | 195 | ||
150 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); | 196 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); |
@@ -227,6 +273,7 @@ void input_gssapi_token(int type, u_int32_t, void *); | |||
227 | void input_gssapi_hash(int type, u_int32_t, void *); | 273 | void input_gssapi_hash(int type, u_int32_t, void *); |
228 | void input_gssapi_error(int, u_int32_t, void *); | 274 | void input_gssapi_error(int, u_int32_t, void *); |
229 | void input_gssapi_errtok(int, u_int32_t, void *); | 275 | void input_gssapi_errtok(int, u_int32_t, void *); |
276 | int userauth_gsskeyex(Authctxt *authctxt); | ||
230 | #endif | 277 | #endif |
231 | 278 | ||
232 | void userauth(Authctxt *, char *); | 279 | void userauth(Authctxt *, char *); |
@@ -242,10 +289,18 @@ static char *authmethods_get(void); | |||
242 | 289 | ||
243 | Authmethod authmethods[] = { | 290 | Authmethod authmethods[] = { |
244 | #ifdef GSSAPI | 291 | #ifdef GSSAPI |
292 | {"gssapi-keyex", | ||
293 | userauth_gsskeyex, | ||
294 | &options.gss_authentication, | ||
295 | NULL}, | ||
245 | {"gssapi-with-mic", | 296 | {"gssapi-with-mic", |
246 | userauth_gssapi, | 297 | userauth_gssapi, |
247 | &options.gss_authentication, | 298 | &options.gss_authentication, |
248 | NULL}, | 299 | NULL}, |
300 | {"gssapi", | ||
301 | userauth_gssapi, | ||
302 | &options.gss_authentication, | ||
303 | NULL}, | ||
249 | #endif | 304 | #endif |
250 | {"hostbased", | 305 | {"hostbased", |
251 | userauth_hostbased, | 306 | userauth_hostbased, |
@@ -511,6 +566,13 @@ userauth_gssapi(Authctxt *authctxt) | |||
511 | static u_int mech = 0; | 566 | static u_int mech = 0; |
512 | OM_uint32 min; | 567 | OM_uint32 min; |
513 | int ok = 0; | 568 | int ok = 0; |
569 | char *gss_host = NULL; | ||
570 | int old_gssapi_method; | ||
571 | |||
572 | if (options.gss_trust_dns) | ||
573 | gss_host = (char *)get_canonical_hostname(1); | ||
574 | else | ||
575 | gss_host = (char *)authctxt->host; | ||
514 | 576 | ||
515 | /* Try one GSSAPI method at a time, rather than sending them all at | 577 | /* Try one GSSAPI method at a time, rather than sending them all at |
516 | * once. */ | 578 | * once. */ |
@@ -523,7 +585,7 @@ userauth_gssapi(Authctxt *authctxt) | |||
523 | /* My DER encoding requires length<128 */ | 585 | /* My DER encoding requires length<128 */ |
524 | if (gss_supported->elements[mech].length < 128 && | 586 | if (gss_supported->elements[mech].length < 128 && |
525 | ssh_gssapi_check_mechanism(&gssctxt, | 587 | ssh_gssapi_check_mechanism(&gssctxt, |
526 | &gss_supported->elements[mech], authctxt->host)) { | 588 | &gss_supported->elements[mech], gss_host)) { |
527 | ok = 1; /* Mechanism works */ | 589 | ok = 1; /* Mechanism works */ |
528 | } else { | 590 | } else { |
529 | mech++; | 591 | mech++; |
@@ -540,13 +602,25 @@ userauth_gssapi(Authctxt *authctxt) | |||
540 | packet_put_cstring(authctxt->service); | 602 | packet_put_cstring(authctxt->service); |
541 | packet_put_cstring(authctxt->method->name); | 603 | packet_put_cstring(authctxt->method->name); |
542 | 604 | ||
543 | packet_put_int(1); | 605 | old_gssapi_method = !strcmp(authctxt->method->name, "gssapi"); |
606 | |||
607 | /* Versions of Debian ssh-krb5 prior to 3.8.1p1-1 don't expect | ||
608 | * tagged OIDs. As such we include both tagged and untagged oids | ||
609 | * for the old gssapi method. | ||
610 | * We only include tagged oids for the new gssapi-with-mic method. | ||
611 | */ | ||
612 | packet_put_int(old_gssapi_method ? 2 : 1); | ||
544 | 613 | ||
545 | packet_put_int((gss_supported->elements[mech].length) + 2); | 614 | packet_put_int((gss_supported->elements[mech].length) + 2); |
546 | packet_put_char(SSH_GSS_OIDTYPE); | 615 | packet_put_char(SSH_GSS_OIDTYPE); |
547 | packet_put_char(gss_supported->elements[mech].length); | 616 | packet_put_char(gss_supported->elements[mech].length); |
548 | packet_put_raw(gss_supported->elements[mech].elements, | 617 | packet_put_raw(gss_supported->elements[mech].elements, |
549 | gss_supported->elements[mech].length); | 618 | gss_supported->elements[mech].length); |
619 | if (old_gssapi_method) { | ||
620 | packet_put_int(gss_supported->elements[mech].length); | ||
621 | packet_put_raw(gss_supported->elements[mech].elements, | ||
622 | gss_supported->elements[mech].length); | ||
623 | } | ||
550 | 624 | ||
551 | packet_send(); | 625 | packet_send(); |
552 | 626 | ||
@@ -586,8 +660,10 @@ process_gssapi_token(void *ctxt, gss_buffer_t recv_tok) | |||
586 | } | 660 | } |
587 | 661 | ||
588 | if (status == GSS_S_COMPLETE) { | 662 | if (status == GSS_S_COMPLETE) { |
663 | int old_gssapi_method = !strcmp(authctxt->method->name, | ||
664 | "gssapi"); | ||
589 | /* send either complete or MIC, depending on mechanism */ | 665 | /* send either complete or MIC, depending on mechanism */ |
590 | if (!(flags & GSS_C_INTEG_FLAG)) { | 666 | if (old_gssapi_method || !(flags & GSS_C_INTEG_FLAG)) { |
591 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); | 667 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); |
592 | packet_send(); | 668 | packet_send(); |
593 | } else { | 669 | } else { |
@@ -619,8 +695,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
619 | { | 695 | { |
620 | Authctxt *authctxt = ctxt; | 696 | Authctxt *authctxt = ctxt; |
621 | Gssctxt *gssctxt; | 697 | Gssctxt *gssctxt; |
622 | int oidlen; | 698 | u_int oidlen; |
623 | char *oidv; | 699 | u_char *oidv, *oidv_free; |
624 | 700 | ||
625 | if (authctxt == NULL) | 701 | if (authctxt == NULL) |
626 | fatal("input_gssapi_response: no authentication context"); | 702 | fatal("input_gssapi_response: no authentication context"); |
@@ -628,22 +704,28 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
628 | 704 | ||
629 | /* Setup our OID */ | 705 | /* Setup our OID */ |
630 | oidv = packet_get_string(&oidlen); | 706 | oidv = packet_get_string(&oidlen); |
707 | oidv_free = oidv; | ||
631 | 708 | ||
632 | if (oidlen <= 2 || | 709 | if (oidlen <= 2 || |
633 | oidv[0] != SSH_GSS_OIDTYPE || | 710 | oidv[0] != SSH_GSS_OIDTYPE || |
634 | oidv[1] != oidlen - 2) { | 711 | oidv[1] != oidlen - 2) { |
635 | xfree(oidv); | ||
636 | debug("Badly encoded mechanism OID received"); | 712 | debug("Badly encoded mechanism OID received"); |
637 | userauth(authctxt, NULL); | 713 | if (oidlen < 2) { |
638 | return; | 714 | xfree(oidv_free); |
715 | userauth(authctxt, NULL); | ||
716 | return; | ||
717 | } | ||
718 | } else { | ||
719 | oidlen -= 2; | ||
720 | oidv += 2; | ||
639 | } | 721 | } |
640 | 722 | ||
641 | if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2)) | 723 | if (!ssh_gssapi_check_oid(gssctxt, oidv, oidlen)) |
642 | fatal("Server returned different OID than expected"); | 724 | fatal("Server returned different OID than expected"); |
643 | 725 | ||
644 | packet_check_eom(); | 726 | packet_check_eom(); |
645 | 727 | ||
646 | xfree(oidv); | 728 | xfree(oidv_free); |
647 | 729 | ||
648 | if (GSS_ERROR(process_gssapi_token(ctxt, GSS_C_NO_BUFFER))) { | 730 | if (GSS_ERROR(process_gssapi_token(ctxt, GSS_C_NO_BUFFER))) { |
649 | /* Start again with next method on list */ | 731 | /* Start again with next method on list */ |
@@ -727,6 +809,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) | |||
727 | xfree(msg); | 809 | xfree(msg); |
728 | xfree(lang); | 810 | xfree(lang); |
729 | } | 811 | } |
812 | |||
813 | int | ||
814 | userauth_gsskeyex(Authctxt *authctxt) | ||
815 | { | ||
816 | Buffer b; | ||
817 | gss_buffer_desc gssbuf; | ||
818 | gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; | ||
819 | OM_uint32 ms; | ||
820 | |||
821 | static int attempt = 0; | ||
822 | if (attempt++ >= 1) | ||
823 | return (0); | ||
824 | |||
825 | if (gss_kex_context == NULL) { | ||
826 | debug("No valid Key exchange context"); | ||
827 | return (0); | ||
828 | } | ||
829 | |||
830 | ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, | ||
831 | "gssapi-keyex"); | ||
832 | |||
833 | gssbuf.value = buffer_ptr(&b); | ||
834 | gssbuf.length = buffer_len(&b); | ||
835 | |||
836 | if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { | ||
837 | buffer_free(&b); | ||
838 | return (0); | ||
839 | } | ||
840 | |||
841 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
842 | packet_put_cstring(authctxt->server_user); | ||
843 | packet_put_cstring(authctxt->service); | ||
844 | packet_put_cstring(authctxt->method->name); | ||
845 | packet_put_string(mic.value, mic.length); | ||
846 | packet_send(); | ||
847 | |||
848 | buffer_free(&b); | ||
849 | gss_release_buffer(&ms, &mic); | ||
850 | |||
851 | return (1); | ||
852 | } | ||
853 | |||
730 | #endif /* GSSAPI */ | 854 | #endif /* GSSAPI */ |
731 | 855 | ||
732 | int | 856 | int |
@@ -1042,6 +1166,8 @@ pubkey_prepare(Authctxt *authctxt) | |||
1042 | 1166 | ||
1043 | /* list of keys stored in the filesystem */ | 1167 | /* list of keys stored in the filesystem */ |
1044 | for (i = 0; i < options.num_identity_files; i++) { | 1168 | for (i = 0; i < options.num_identity_files; i++) { |
1169 | if (options.identity_files[i] == NULL) | ||
1170 | continue; | ||
1045 | key = options.identity_keys[i]; | 1171 | key = options.identity_keys[i]; |
1046 | if (key && key->type == KEY_RSA1) | 1172 | if (key && key->type == KEY_RSA1) |
1047 | continue; | 1173 | continue; |
@@ -1132,7 +1258,7 @@ userauth_pubkey(Authctxt *authctxt) | |||
1132 | if (id->key && id->key->type != KEY_RSA1) { | 1258 | if (id->key && id->key->type != KEY_RSA1) { |
1133 | debug("Offering public key: %s", id->filename); | 1259 | debug("Offering public key: %s", id->filename); |
1134 | sent = send_pubkey_test(authctxt, id); | 1260 | sent = send_pubkey_test(authctxt, id); |
1135 | } else if (id->key == NULL) { | 1261 | } else if (id->key == NULL && id->filename) { |
1136 | debug("Trying private key: %s", id->filename); | 1262 | debug("Trying private key: %s", id->filename); |
1137 | id->key = load_identity_file(id->filename); | 1263 | id->key = load_identity_file(id->filename); |
1138 | if (id->key != NULL) { | 1264 | if (id->key != NULL) { |