diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 146 |
1 files changed, 136 insertions, 10 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index dd971a9f9..63e9369b1 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -98,9 +98,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
98 | { | 98 | { |
99 | Kex *kex; | 99 | Kex *kex; |
100 | 100 | ||
101 | #ifdef GSSAPI | ||
102 | char *orig = NULL, *gss = NULL; | ||
103 | char *gss_host = NULL; | ||
104 | #endif | ||
105 | |||
101 | xxx_host = host; | 106 | xxx_host = host; |
102 | xxx_hostaddr = hostaddr; | 107 | xxx_hostaddr = hostaddr; |
103 | 108 | ||
109 | #ifdef GSSAPI | ||
110 | if (options.gss_keyex) { | ||
111 | /* Add the GSSAPI mechanisms currently supported on this | ||
112 | * client to the key exchange algorithm proposal */ | ||
113 | orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
114 | |||
115 | if (options.gss_trust_dns) | ||
116 | gss_host = (char *)get_canonical_hostname(1); | ||
117 | else | ||
118 | gss_host = host; | ||
119 | |||
120 | gss = ssh_gssapi_client_mechanisms(gss_host); | ||
121 | if (gss) { | ||
122 | debug("Offering GSSAPI proposal: %s", gss); | ||
123 | xasprintf(&myproposal[PROPOSAL_KEX_ALGS], | ||
124 | "%s,%s", gss, orig); | ||
125 | } | ||
126 | } | ||
127 | #endif | ||
128 | |||
104 | if (options.ciphers == (char *)-1) { | 129 | if (options.ciphers == (char *)-1) { |
105 | logit("No valid ciphers for protocol version 2 given, using defaults."); | 130 | logit("No valid ciphers for protocol version 2 given, using defaults."); |
106 | options.ciphers = NULL; | 131 | options.ciphers = NULL; |
@@ -128,6 +153,16 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
128 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = | 153 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = |
129 | options.hostkeyalgorithms; | 154 | options.hostkeyalgorithms; |
130 | 155 | ||
156 | #ifdef GSSAPI | ||
157 | /* If we've got GSSAPI algorithms, then we also support the | ||
158 | * 'null' hostkey, as a last resort */ | ||
159 | if (options.gss_keyex && gss) { | ||
160 | orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; | ||
161 | xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], | ||
162 | "%s,null", orig); | ||
163 | } | ||
164 | #endif | ||
165 | |||
131 | if (options.rekey_limit) | 166 | if (options.rekey_limit) |
132 | packet_set_rekey_limit(options.rekey_limit); | 167 | packet_set_rekey_limit(options.rekey_limit); |
133 | 168 | ||
@@ -137,10 +172,23 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
137 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; | 172 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; |
138 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; | 173 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; |
139 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; | 174 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; |
175 | #ifdef GSSAPI | ||
176 | if (options.gss_keyex) { | ||
177 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; | ||
178 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; | ||
179 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; | ||
180 | } | ||
181 | #endif | ||
140 | kex->client_version_string=client_version_string; | 182 | kex->client_version_string=client_version_string; |
141 | kex->server_version_string=server_version_string; | 183 | kex->server_version_string=server_version_string; |
142 | kex->verify_host_key=&verify_host_key_callback; | 184 | kex->verify_host_key=&verify_host_key_callback; |
143 | 185 | ||
186 | #ifdef GSSAPI | ||
187 | kex->gss_deleg_creds = options.gss_deleg_creds; | ||
188 | kex->gss_trust_dns = options.gss_trust_dns; | ||
189 | kex->gss_host = gss_host; | ||
190 | #endif | ||
191 | |||
144 | xxx_kex = kex; | 192 | xxx_kex = kex; |
145 | 193 | ||
146 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); | 194 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); |
@@ -223,6 +271,7 @@ void input_gssapi_token(int type, u_int32_t, void *); | |||
223 | void input_gssapi_hash(int type, u_int32_t, void *); | 271 | void input_gssapi_hash(int type, u_int32_t, void *); |
224 | void input_gssapi_error(int, u_int32_t, void *); | 272 | void input_gssapi_error(int, u_int32_t, void *); |
225 | void input_gssapi_errtok(int, u_int32_t, void *); | 273 | void input_gssapi_errtok(int, u_int32_t, void *); |
274 | int userauth_gsskeyex(Authctxt *authctxt); | ||
226 | #endif | 275 | #endif |
227 | 276 | ||
228 | void userauth(Authctxt *, char *); | 277 | void userauth(Authctxt *, char *); |
@@ -238,10 +287,18 @@ static char *authmethods_get(void); | |||
238 | 287 | ||
239 | Authmethod authmethods[] = { | 288 | Authmethod authmethods[] = { |
240 | #ifdef GSSAPI | 289 | #ifdef GSSAPI |
290 | {"gssapi-keyex", | ||
291 | userauth_gsskeyex, | ||
292 | &options.gss_authentication, | ||
293 | NULL}, | ||
241 | {"gssapi-with-mic", | 294 | {"gssapi-with-mic", |
242 | userauth_gssapi, | 295 | userauth_gssapi, |
243 | &options.gss_authentication, | 296 | &options.gss_authentication, |
244 | NULL}, | 297 | NULL}, |
298 | {"gssapi", | ||
299 | userauth_gssapi, | ||
300 | &options.gss_authentication, | ||
301 | NULL}, | ||
245 | #endif | 302 | #endif |
246 | {"hostbased", | 303 | {"hostbased", |
247 | userauth_hostbased, | 304 | userauth_hostbased, |
@@ -500,6 +557,13 @@ userauth_gssapi(Authctxt *authctxt) | |||
500 | static u_int mech = 0; | 557 | static u_int mech = 0; |
501 | OM_uint32 min; | 558 | OM_uint32 min; |
502 | int ok = 0; | 559 | int ok = 0; |
560 | char *gss_host = NULL; | ||
561 | int old_gssapi_method; | ||
562 | |||
563 | if (options.gss_trust_dns) | ||
564 | gss_host = (char *)get_canonical_hostname(1); | ||
565 | else | ||
566 | gss_host = (char *)authctxt->host; | ||
503 | 567 | ||
504 | /* Try one GSSAPI method at a time, rather than sending them all at | 568 | /* Try one GSSAPI method at a time, rather than sending them all at |
505 | * once. */ | 569 | * once. */ |
@@ -512,7 +576,7 @@ userauth_gssapi(Authctxt *authctxt) | |||
512 | /* My DER encoding requires length<128 */ | 576 | /* My DER encoding requires length<128 */ |
513 | if (gss_supported->elements[mech].length < 128 && | 577 | if (gss_supported->elements[mech].length < 128 && |
514 | ssh_gssapi_check_mechanism(&gssctxt, | 578 | ssh_gssapi_check_mechanism(&gssctxt, |
515 | &gss_supported->elements[mech], authctxt->host)) { | 579 | &gss_supported->elements[mech], gss_host)) { |
516 | ok = 1; /* Mechanism works */ | 580 | ok = 1; /* Mechanism works */ |
517 | } else { | 581 | } else { |
518 | mech++; | 582 | mech++; |
@@ -529,13 +593,25 @@ userauth_gssapi(Authctxt *authctxt) | |||
529 | packet_put_cstring(authctxt->service); | 593 | packet_put_cstring(authctxt->service); |
530 | packet_put_cstring(authctxt->method->name); | 594 | packet_put_cstring(authctxt->method->name); |
531 | 595 | ||
532 | packet_put_int(1); | 596 | old_gssapi_method = !strcmp(authctxt->method->name, "gssapi"); |
597 | |||
598 | /* Versions of Debian ssh-krb5 prior to 3.8.1p1-1 don't expect | ||
599 | * tagged OIDs. As such we include both tagged and untagged oids | ||
600 | * for the old gssapi method. | ||
601 | * We only include tagged oids for the new gssapi-with-mic method. | ||
602 | */ | ||
603 | packet_put_int(old_gssapi_method ? 2 : 1); | ||
533 | 604 | ||
534 | packet_put_int((gss_supported->elements[mech].length) + 2); | 605 | packet_put_int((gss_supported->elements[mech].length) + 2); |
535 | packet_put_char(SSH_GSS_OIDTYPE); | 606 | packet_put_char(SSH_GSS_OIDTYPE); |
536 | packet_put_char(gss_supported->elements[mech].length); | 607 | packet_put_char(gss_supported->elements[mech].length); |
537 | packet_put_raw(gss_supported->elements[mech].elements, | 608 | packet_put_raw(gss_supported->elements[mech].elements, |
538 | gss_supported->elements[mech].length); | 609 | gss_supported->elements[mech].length); |
610 | if (old_gssapi_method) { | ||
611 | packet_put_int(gss_supported->elements[mech].length); | ||
612 | packet_put_raw(gss_supported->elements[mech].elements, | ||
613 | gss_supported->elements[mech].length); | ||
614 | } | ||
539 | 615 | ||
540 | packet_send(); | 616 | packet_send(); |
541 | 617 | ||
@@ -575,8 +651,10 @@ process_gssapi_token(void *ctxt, gss_buffer_t recv_tok) | |||
575 | } | 651 | } |
576 | 652 | ||
577 | if (status == GSS_S_COMPLETE) { | 653 | if (status == GSS_S_COMPLETE) { |
654 | int old_gssapi_method = !strcmp(authctxt->method->name, | ||
655 | "gssapi"); | ||
578 | /* send either complete or MIC, depending on mechanism */ | 656 | /* send either complete or MIC, depending on mechanism */ |
579 | if (!(flags & GSS_C_INTEG_FLAG)) { | 657 | if (old_gssapi_method || !(flags & GSS_C_INTEG_FLAG)) { |
580 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); | 658 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); |
581 | packet_send(); | 659 | packet_send(); |
582 | } else { | 660 | } else { |
@@ -608,8 +686,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
608 | { | 686 | { |
609 | Authctxt *authctxt = ctxt; | 687 | Authctxt *authctxt = ctxt; |
610 | Gssctxt *gssctxt; | 688 | Gssctxt *gssctxt; |
611 | int oidlen; | 689 | u_int oidlen; |
612 | char *oidv; | 690 | u_char *oidv, *oidv_free; |
613 | 691 | ||
614 | if (authctxt == NULL) | 692 | if (authctxt == NULL) |
615 | fatal("input_gssapi_response: no authentication context"); | 693 | fatal("input_gssapi_response: no authentication context"); |
@@ -617,22 +695,28 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
617 | 695 | ||
618 | /* Setup our OID */ | 696 | /* Setup our OID */ |
619 | oidv = packet_get_string(&oidlen); | 697 | oidv = packet_get_string(&oidlen); |
698 | oidv_free = oidv; | ||
620 | 699 | ||
621 | if (oidlen <= 2 || | 700 | if (oidlen <= 2 || |
622 | oidv[0] != SSH_GSS_OIDTYPE || | 701 | oidv[0] != SSH_GSS_OIDTYPE || |
623 | oidv[1] != oidlen - 2) { | 702 | oidv[1] != oidlen - 2) { |
624 | xfree(oidv); | ||
625 | debug("Badly encoded mechanism OID received"); | 703 | debug("Badly encoded mechanism OID received"); |
626 | userauth(authctxt, NULL); | 704 | if (oidlen < 2) { |
627 | return; | 705 | xfree(oidv_free); |
706 | userauth(authctxt, NULL); | ||
707 | return; | ||
708 | } | ||
709 | } else { | ||
710 | oidlen -= 2; | ||
711 | oidv += 2; | ||
628 | } | 712 | } |
629 | 713 | ||
630 | if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2)) | 714 | if (!ssh_gssapi_check_oid(gssctxt, oidv, oidlen)) |
631 | fatal("Server returned different OID than expected"); | 715 | fatal("Server returned different OID than expected"); |
632 | 716 | ||
633 | packet_check_eom(); | 717 | packet_check_eom(); |
634 | 718 | ||
635 | xfree(oidv); | 719 | xfree(oidv_free); |
636 | 720 | ||
637 | if (GSS_ERROR(process_gssapi_token(ctxt, GSS_C_NO_BUFFER))) { | 721 | if (GSS_ERROR(process_gssapi_token(ctxt, GSS_C_NO_BUFFER))) { |
638 | /* Start again with next method on list */ | 722 | /* Start again with next method on list */ |
@@ -716,6 +800,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) | |||
716 | xfree(msg); | 800 | xfree(msg); |
717 | xfree(lang); | 801 | xfree(lang); |
718 | } | 802 | } |
803 | |||
804 | int | ||
805 | userauth_gsskeyex(Authctxt *authctxt) | ||
806 | { | ||
807 | Buffer b; | ||
808 | gss_buffer_desc gssbuf; | ||
809 | gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; | ||
810 | OM_uint32 ms; | ||
811 | |||
812 | static int attempt = 0; | ||
813 | if (attempt++ >= 1) | ||
814 | return (0); | ||
815 | |||
816 | if (gss_kex_context == NULL) { | ||
817 | debug("No valid Key exchange context"); | ||
818 | return (0); | ||
819 | } | ||
820 | |||
821 | ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, | ||
822 | "gssapi-keyex"); | ||
823 | |||
824 | gssbuf.value = buffer_ptr(&b); | ||
825 | gssbuf.length = buffer_len(&b); | ||
826 | |||
827 | if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { | ||
828 | buffer_free(&b); | ||
829 | return (0); | ||
830 | } | ||
831 | |||
832 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
833 | packet_put_cstring(authctxt->server_user); | ||
834 | packet_put_cstring(authctxt->service); | ||
835 | packet_put_cstring(authctxt->method->name); | ||
836 | packet_put_string(mic.value, mic.length); | ||
837 | packet_send(); | ||
838 | |||
839 | buffer_free(&b); | ||
840 | gss_release_buffer(&ms, &mic); | ||
841 | |||
842 | return (1); | ||
843 | } | ||
844 | |||
719 | #endif /* GSSAPI */ | 845 | #endif /* GSSAPI */ |
720 | 846 | ||
721 | int | 847 | int |