diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 131 |
1 files changed, 127 insertions, 4 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index 103a2b36a..c35a0bd50 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -162,6 +162,11 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
162 | struct kex *kex; | 162 | struct kex *kex; |
163 | int r; | 163 | int r; |
164 | 164 | ||
165 | #ifdef GSSAPI | ||
166 | char *orig = NULL, *gss = NULL; | ||
167 | char *gss_host = NULL; | ||
168 | #endif | ||
169 | |||
165 | xxx_host = host; | 170 | xxx_host = host; |
166 | xxx_hostaddr = hostaddr; | 171 | xxx_hostaddr = hostaddr; |
167 | 172 | ||
@@ -192,6 +197,35 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
192 | order_hostkeyalgs(host, hostaddr, port)); | 197 | order_hostkeyalgs(host, hostaddr, port)); |
193 | } | 198 | } |
194 | 199 | ||
200 | #ifdef GSSAPI | ||
201 | if (options.gss_keyex) { | ||
202 | /* Add the GSSAPI mechanisms currently supported on this | ||
203 | * client to the key exchange algorithm proposal */ | ||
204 | orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
205 | |||
206 | if (options.gss_server_identity) | ||
207 | gss_host = xstrdup(options.gss_server_identity); | ||
208 | else if (options.gss_trust_dns) | ||
209 | gss_host = remote_hostname(active_state); | ||
210 | else | ||
211 | gss_host = xstrdup(host); | ||
212 | |||
213 | gss = ssh_gssapi_client_mechanisms(gss_host, | ||
214 | options.gss_client_identity); | ||
215 | if (gss) { | ||
216 | debug("Offering GSSAPI proposal: %s", gss); | ||
217 | xasprintf(&myproposal[PROPOSAL_KEX_ALGS], | ||
218 | "%s,%s", gss, orig); | ||
219 | |||
220 | /* If we've got GSSAPI algorithms, then we also | ||
221 | * support the 'null' hostkey, as a last resort */ | ||
222 | orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; | ||
223 | xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], | ||
224 | "%s,null", orig); | ||
225 | } | ||
226 | } | ||
227 | #endif | ||
228 | |||
195 | if (options.rekey_limit || options.rekey_interval) | 229 | if (options.rekey_limit || options.rekey_interval) |
196 | packet_set_rekey_limits((u_int32_t)options.rekey_limit, | 230 | packet_set_rekey_limits((u_int32_t)options.rekey_limit, |
197 | (time_t)options.rekey_interval); | 231 | (time_t)options.rekey_interval); |
@@ -213,15 +247,41 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
213 | # endif | 247 | # endif |
214 | #endif | 248 | #endif |
215 | kex->kex[KEX_C25519_SHA256] = kexc25519_client; | 249 | kex->kex[KEX_C25519_SHA256] = kexc25519_client; |
250 | #ifdef GSSAPI | ||
251 | if (options.gss_keyex) { | ||
252 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; | ||
253 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; | ||
254 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; | ||
255 | } | ||
256 | #endif | ||
216 | kex->client_version_string=client_version_string; | 257 | kex->client_version_string=client_version_string; |
217 | kex->server_version_string=server_version_string; | 258 | kex->server_version_string=server_version_string; |
218 | kex->verify_host_key=&verify_host_key_callback; | 259 | kex->verify_host_key=&verify_host_key_callback; |
219 | 260 | ||
261 | #ifdef GSSAPI | ||
262 | if (options.gss_keyex) { | ||
263 | kex->gss_deleg_creds = options.gss_deleg_creds; | ||
264 | kex->gss_trust_dns = options.gss_trust_dns; | ||
265 | kex->gss_client = options.gss_client_identity; | ||
266 | kex->gss_host = gss_host; | ||
267 | } | ||
268 | #endif | ||
269 | |||
220 | dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); | 270 | dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); |
221 | 271 | ||
222 | /* remove ext-info from the KEX proposals for rekeying */ | 272 | /* remove ext-info from the KEX proposals for rekeying */ |
223 | myproposal[PROPOSAL_KEX_ALGS] = | 273 | myproposal[PROPOSAL_KEX_ALGS] = |
224 | compat_kex_proposal(options.kex_algorithms); | 274 | compat_kex_proposal(options.kex_algorithms); |
275 | #ifdef GSSAPI | ||
276 | /* repair myproposal after it was crumpled by the */ | ||
277 | /* ext-info removal above */ | ||
278 | if (gss) { | ||
279 | orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
280 | xasprintf(&myproposal[PROPOSAL_KEX_ALGS], | ||
281 | "%s,%s", gss, orig); | ||
282 | free(gss); | ||
283 | } | ||
284 | #endif | ||
225 | if ((r = kex_prop2buf(kex->my, myproposal)) != 0) | 285 | if ((r = kex_prop2buf(kex->my, myproposal)) != 0) |
226 | fatal("kex_prop2buf: %s", ssh_err(r)); | 286 | fatal("kex_prop2buf: %s", ssh_err(r)); |
227 | 287 | ||
@@ -311,6 +371,7 @@ int input_gssapi_token(int type, u_int32_t, void *); | |||
311 | int input_gssapi_hash(int type, u_int32_t, void *); | 371 | int input_gssapi_hash(int type, u_int32_t, void *); |
312 | int input_gssapi_error(int, u_int32_t, void *); | 372 | int input_gssapi_error(int, u_int32_t, void *); |
313 | int input_gssapi_errtok(int, u_int32_t, void *); | 373 | int input_gssapi_errtok(int, u_int32_t, void *); |
374 | int userauth_gsskeyex(Authctxt *authctxt); | ||
314 | #endif | 375 | #endif |
315 | 376 | ||
316 | void userauth(Authctxt *, char *); | 377 | void userauth(Authctxt *, char *); |
@@ -327,6 +388,11 @@ static char *authmethods_get(void); | |||
327 | 388 | ||
328 | Authmethod authmethods[] = { | 389 | Authmethod authmethods[] = { |
329 | #ifdef GSSAPI | 390 | #ifdef GSSAPI |
391 | {"gssapi-keyex", | ||
392 | userauth_gsskeyex, | ||
393 | NULL, | ||
394 | &options.gss_authentication, | ||
395 | NULL}, | ||
330 | {"gssapi-with-mic", | 396 | {"gssapi-with-mic", |
331 | userauth_gssapi, | 397 | userauth_gssapi, |
332 | NULL, | 398 | NULL, |
@@ -652,25 +718,40 @@ userauth_gssapi(Authctxt *authctxt) | |||
652 | static u_int mech = 0; | 718 | static u_int mech = 0; |
653 | OM_uint32 min; | 719 | OM_uint32 min; |
654 | int ok = 0; | 720 | int ok = 0; |
721 | char *gss_host; | ||
722 | |||
723 | if (options.gss_server_identity) | ||
724 | gss_host = xstrdup(options.gss_server_identity); | ||
725 | else if (options.gss_trust_dns) | ||
726 | gss_host = remote_hostname(active_state); | ||
727 | else | ||
728 | gss_host = xstrdup(authctxt->host); | ||
655 | 729 | ||
656 | /* Try one GSSAPI method at a time, rather than sending them all at | 730 | /* Try one GSSAPI method at a time, rather than sending them all at |
657 | * once. */ | 731 | * once. */ |
658 | 732 | ||
659 | if (gss_supported == NULL) | 733 | if (gss_supported == NULL) |
660 | gss_indicate_mechs(&min, &gss_supported); | 734 | if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { |
735 | gss_supported = NULL; | ||
736 | free(gss_host); | ||
737 | return 0; | ||
738 | } | ||
661 | 739 | ||
662 | /* Check to see if the mechanism is usable before we offer it */ | 740 | /* Check to see if the mechanism is usable before we offer it */ |
663 | while (mech < gss_supported->count && !ok) { | 741 | while (mech < gss_supported->count && !ok) { |
664 | /* My DER encoding requires length<128 */ | 742 | /* My DER encoding requires length<128 */ |
665 | if (gss_supported->elements[mech].length < 128 && | 743 | if (gss_supported->elements[mech].length < 128 && |
666 | ssh_gssapi_check_mechanism(&gssctxt, | 744 | ssh_gssapi_check_mechanism(&gssctxt, |
667 | &gss_supported->elements[mech], authctxt->host)) { | 745 | &gss_supported->elements[mech], gss_host, |
746 | options.gss_client_identity)) { | ||
668 | ok = 1; /* Mechanism works */ | 747 | ok = 1; /* Mechanism works */ |
669 | } else { | 748 | } else { |
670 | mech++; | 749 | mech++; |
671 | } | 750 | } |
672 | } | 751 | } |
673 | 752 | ||
753 | free(gss_host); | ||
754 | |||
674 | if (!ok) | 755 | if (!ok) |
675 | return 0; | 756 | return 0; |
676 | 757 | ||
@@ -761,8 +842,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
761 | { | 842 | { |
762 | Authctxt *authctxt = ctxt; | 843 | Authctxt *authctxt = ctxt; |
763 | Gssctxt *gssctxt; | 844 | Gssctxt *gssctxt; |
764 | int oidlen; | 845 | u_int oidlen; |
765 | char *oidv; | 846 | u_char *oidv; |
766 | 847 | ||
767 | if (authctxt == NULL) | 848 | if (authctxt == NULL) |
768 | fatal("input_gssapi_response: no authentication context"); | 849 | fatal("input_gssapi_response: no authentication context"); |
@@ -875,6 +956,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) | |||
875 | free(lang); | 956 | free(lang); |
876 | return 0; | 957 | return 0; |
877 | } | 958 | } |
959 | |||
960 | int | ||
961 | userauth_gsskeyex(Authctxt *authctxt) | ||
962 | { | ||
963 | Buffer b; | ||
964 | gss_buffer_desc gssbuf; | ||
965 | gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; | ||
966 | OM_uint32 ms; | ||
967 | |||
968 | static int attempt = 0; | ||
969 | if (attempt++ >= 1) | ||
970 | return (0); | ||
971 | |||
972 | if (gss_kex_context == NULL) { | ||
973 | debug("No valid Key exchange context"); | ||
974 | return (0); | ||
975 | } | ||
976 | |||
977 | ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, | ||
978 | "gssapi-keyex"); | ||
979 | |||
980 | gssbuf.value = buffer_ptr(&b); | ||
981 | gssbuf.length = buffer_len(&b); | ||
982 | |||
983 | if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { | ||
984 | buffer_free(&b); | ||
985 | return (0); | ||
986 | } | ||
987 | |||
988 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
989 | packet_put_cstring(authctxt->server_user); | ||
990 | packet_put_cstring(authctxt->service); | ||
991 | packet_put_cstring(authctxt->method->name); | ||
992 | packet_put_string(mic.value, mic.length); | ||
993 | packet_send(); | ||
994 | |||
995 | buffer_free(&b); | ||
996 | gss_release_buffer(&ms, &mic); | ||
997 | |||
998 | return (1); | ||
999 | } | ||
1000 | |||
878 | #endif /* GSSAPI */ | 1001 | #endif /* GSSAPI */ |
879 | 1002 | ||
880 | int | 1003 | int |