diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 124 |
1 files changed, 120 insertions, 4 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index fcaed6b01..44c89e691 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -160,9 +160,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
160 | struct kex *kex; | 160 | struct kex *kex; |
161 | int r; | 161 | int r; |
162 | 162 | ||
163 | #ifdef GSSAPI | ||
164 | char *orig = NULL, *gss = NULL; | ||
165 | char *gss_host = NULL; | ||
166 | #endif | ||
167 | |||
163 | xxx_host = host; | 168 | xxx_host = host; |
164 | xxx_hostaddr = hostaddr; | 169 | xxx_hostaddr = hostaddr; |
165 | 170 | ||
171 | #ifdef GSSAPI | ||
172 | if (options.gss_keyex) { | ||
173 | /* Add the GSSAPI mechanisms currently supported on this | ||
174 | * client to the key exchange algorithm proposal */ | ||
175 | orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
176 | |||
177 | if (options.gss_trust_dns) | ||
178 | gss_host = (char *)get_canonical_hostname(1); | ||
179 | else | ||
180 | gss_host = host; | ||
181 | |||
182 | gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity); | ||
183 | if (gss) { | ||
184 | debug("Offering GSSAPI proposal: %s", gss); | ||
185 | xasprintf(&myproposal[PROPOSAL_KEX_ALGS], | ||
186 | "%s,%s", gss, orig); | ||
187 | } | ||
188 | } | ||
189 | #endif | ||
190 | |||
166 | if (options.ciphers == (char *)-1) { | 191 | if (options.ciphers == (char *)-1) { |
167 | logit("No valid ciphers for protocol version 2 given, using defaults."); | 192 | logit("No valid ciphers for protocol version 2 given, using defaults."); |
168 | options.ciphers = NULL; | 193 | options.ciphers = NULL; |
@@ -200,6 +225,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
200 | myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( | 225 | myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( |
201 | myproposal[PROPOSAL_KEX_ALGS]); | 226 | myproposal[PROPOSAL_KEX_ALGS]); |
202 | 227 | ||
228 | #ifdef GSSAPI | ||
229 | /* If we've got GSSAPI algorithms, then we also support the | ||
230 | * 'null' hostkey, as a last resort */ | ||
231 | if (options.gss_keyex && gss) { | ||
232 | orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; | ||
233 | xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], | ||
234 | "%s,null", orig); | ||
235 | free(gss); | ||
236 | } | ||
237 | #endif | ||
238 | |||
203 | if (options.rekey_limit || options.rekey_interval) | 239 | if (options.rekey_limit || options.rekey_interval) |
204 | packet_set_rekey_limits((u_int32_t)options.rekey_limit, | 240 | packet_set_rekey_limits((u_int32_t)options.rekey_limit, |
205 | (time_t)options.rekey_interval); | 241 | (time_t)options.rekey_interval); |
@@ -218,10 +254,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
218 | # endif | 254 | # endif |
219 | #endif | 255 | #endif |
220 | kex->kex[KEX_C25519_SHA256] = kexc25519_client; | 256 | kex->kex[KEX_C25519_SHA256] = kexc25519_client; |
257 | #ifdef GSSAPI | ||
258 | if (options.gss_keyex) { | ||
259 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; | ||
260 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; | ||
261 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; | ||
262 | } | ||
263 | #endif | ||
221 | kex->client_version_string=client_version_string; | 264 | kex->client_version_string=client_version_string; |
222 | kex->server_version_string=server_version_string; | 265 | kex->server_version_string=server_version_string; |
223 | kex->verify_host_key=&verify_host_key_callback; | 266 | kex->verify_host_key=&verify_host_key_callback; |
224 | 267 | ||
268 | #ifdef GSSAPI | ||
269 | if (options.gss_keyex) { | ||
270 | kex->gss_deleg_creds = options.gss_deleg_creds; | ||
271 | kex->gss_trust_dns = options.gss_trust_dns; | ||
272 | kex->gss_client = options.gss_client_identity; | ||
273 | if (options.gss_server_identity) { | ||
274 | kex->gss_host = options.gss_server_identity; | ||
275 | } else { | ||
276 | kex->gss_host = gss_host; | ||
277 | } | ||
278 | } | ||
279 | #endif | ||
280 | |||
225 | dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); | 281 | dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); |
226 | 282 | ||
227 | if (options.use_roaming && !kex->roaming) { | 283 | if (options.use_roaming && !kex->roaming) { |
@@ -313,6 +369,7 @@ int input_gssapi_token(int type, u_int32_t, void *); | |||
313 | int input_gssapi_hash(int type, u_int32_t, void *); | 369 | int input_gssapi_hash(int type, u_int32_t, void *); |
314 | int input_gssapi_error(int, u_int32_t, void *); | 370 | int input_gssapi_error(int, u_int32_t, void *); |
315 | int input_gssapi_errtok(int, u_int32_t, void *); | 371 | int input_gssapi_errtok(int, u_int32_t, void *); |
372 | int userauth_gsskeyex(Authctxt *authctxt); | ||
316 | #endif | 373 | #endif |
317 | 374 | ||
318 | void userauth(Authctxt *, char *); | 375 | void userauth(Authctxt *, char *); |
@@ -328,6 +385,11 @@ static char *authmethods_get(void); | |||
328 | 385 | ||
329 | Authmethod authmethods[] = { | 386 | Authmethod authmethods[] = { |
330 | #ifdef GSSAPI | 387 | #ifdef GSSAPI |
388 | {"gssapi-keyex", | ||
389 | userauth_gsskeyex, | ||
390 | NULL, | ||
391 | &options.gss_authentication, | ||
392 | NULL}, | ||
331 | {"gssapi-with-mic", | 393 | {"gssapi-with-mic", |
332 | userauth_gssapi, | 394 | userauth_gssapi, |
333 | NULL, | 395 | NULL, |
@@ -634,19 +696,31 @@ userauth_gssapi(Authctxt *authctxt) | |||
634 | static u_int mech = 0; | 696 | static u_int mech = 0; |
635 | OM_uint32 min; | 697 | OM_uint32 min; |
636 | int ok = 0; | 698 | int ok = 0; |
699 | const char *gss_host; | ||
700 | |||
701 | if (options.gss_server_identity) | ||
702 | gss_host = options.gss_server_identity; | ||
703 | else if (options.gss_trust_dns) | ||
704 | gss_host = get_canonical_hostname(1); | ||
705 | else | ||
706 | gss_host = authctxt->host; | ||
637 | 707 | ||
638 | /* Try one GSSAPI method at a time, rather than sending them all at | 708 | /* Try one GSSAPI method at a time, rather than sending them all at |
639 | * once. */ | 709 | * once. */ |
640 | 710 | ||
641 | if (gss_supported == NULL) | 711 | if (gss_supported == NULL) |
642 | gss_indicate_mechs(&min, &gss_supported); | 712 | if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { |
713 | gss_supported = NULL; | ||
714 | return 0; | ||
715 | } | ||
643 | 716 | ||
644 | /* Check to see if the mechanism is usable before we offer it */ | 717 | /* Check to see if the mechanism is usable before we offer it */ |
645 | while (mech < gss_supported->count && !ok) { | 718 | while (mech < gss_supported->count && !ok) { |
646 | /* My DER encoding requires length<128 */ | 719 | /* My DER encoding requires length<128 */ |
647 | if (gss_supported->elements[mech].length < 128 && | 720 | if (gss_supported->elements[mech].length < 128 && |
648 | ssh_gssapi_check_mechanism(&gssctxt, | 721 | ssh_gssapi_check_mechanism(&gssctxt, |
649 | &gss_supported->elements[mech], authctxt->host)) { | 722 | &gss_supported->elements[mech], gss_host, |
723 | options.gss_client_identity)) { | ||
650 | ok = 1; /* Mechanism works */ | 724 | ok = 1; /* Mechanism works */ |
651 | } else { | 725 | } else { |
652 | mech++; | 726 | mech++; |
@@ -743,8 +817,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
743 | { | 817 | { |
744 | Authctxt *authctxt = ctxt; | 818 | Authctxt *authctxt = ctxt; |
745 | Gssctxt *gssctxt; | 819 | Gssctxt *gssctxt; |
746 | int oidlen; | 820 | u_int oidlen; |
747 | char *oidv; | 821 | u_char *oidv; |
748 | 822 | ||
749 | if (authctxt == NULL) | 823 | if (authctxt == NULL) |
750 | fatal("input_gssapi_response: no authentication context"); | 824 | fatal("input_gssapi_response: no authentication context"); |
@@ -857,6 +931,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) | |||
857 | free(lang); | 931 | free(lang); |
858 | return 0; | 932 | return 0; |
859 | } | 933 | } |
934 | |||
935 | int | ||
936 | userauth_gsskeyex(Authctxt *authctxt) | ||
937 | { | ||
938 | Buffer b; | ||
939 | gss_buffer_desc gssbuf; | ||
940 | gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; | ||
941 | OM_uint32 ms; | ||
942 | |||
943 | static int attempt = 0; | ||
944 | if (attempt++ >= 1) | ||
945 | return (0); | ||
946 | |||
947 | if (gss_kex_context == NULL) { | ||
948 | debug("No valid Key exchange context"); | ||
949 | return (0); | ||
950 | } | ||
951 | |||
952 | ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, | ||
953 | "gssapi-keyex"); | ||
954 | |||
955 | gssbuf.value = buffer_ptr(&b); | ||
956 | gssbuf.length = buffer_len(&b); | ||
957 | |||
958 | if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { | ||
959 | buffer_free(&b); | ||
960 | return (0); | ||
961 | } | ||
962 | |||
963 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
964 | packet_put_cstring(authctxt->server_user); | ||
965 | packet_put_cstring(authctxt->service); | ||
966 | packet_put_cstring(authctxt->method->name); | ||
967 | packet_put_string(mic.value, mic.length); | ||
968 | packet_send(); | ||
969 | |||
970 | buffer_free(&b); | ||
971 | gss_release_buffer(&ms, &mic); | ||
972 | |||
973 | return (1); | ||
974 | } | ||
975 | |||
860 | #endif /* GSSAPI */ | 976 | #endif /* GSSAPI */ |
861 | 977 | ||
862 | int | 978 | int |