diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 120 |
1 files changed, 116 insertions, 4 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index 775103185..32e9b0df2 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -160,6 +160,11 @@ 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 | ||
@@ -193,6 +198,33 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
193 | order_hostkeyalgs(host, hostaddr, port)); | 198 | order_hostkeyalgs(host, hostaddr, port)); |
194 | } | 199 | } |
195 | 200 | ||
201 | #ifdef GSSAPI | ||
202 | if (options.gss_keyex) { | ||
203 | /* Add the GSSAPI mechanisms currently supported on this | ||
204 | * client to the key exchange algorithm proposal */ | ||
205 | orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
206 | |||
207 | if (options.gss_trust_dns) | ||
208 | gss_host = (char *)get_canonical_hostname(1); | ||
209 | else | ||
210 | gss_host = host; | ||
211 | |||
212 | gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity); | ||
213 | if (gss) { | ||
214 | debug("Offering GSSAPI proposal: %s", gss); | ||
215 | xasprintf(&myproposal[PROPOSAL_KEX_ALGS], | ||
216 | "%s,%s", gss, orig); | ||
217 | |||
218 | /* If we've got GSSAPI algorithms, then we also | ||
219 | * support the 'null' hostkey, as a last resort */ | ||
220 | orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; | ||
221 | xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], | ||
222 | "%s,null", orig); | ||
223 | free(gss); | ||
224 | } | ||
225 | } | ||
226 | #endif | ||
227 | |||
196 | if (options.rekey_limit || options.rekey_interval) | 228 | if (options.rekey_limit || options.rekey_interval) |
197 | packet_set_rekey_limits((u_int32_t)options.rekey_limit, | 229 | packet_set_rekey_limits((u_int32_t)options.rekey_limit, |
198 | (time_t)options.rekey_interval); | 230 | (time_t)options.rekey_interval); |
@@ -211,10 +243,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
211 | # endif | 243 | # endif |
212 | #endif | 244 | #endif |
213 | kex->kex[KEX_C25519_SHA256] = kexc25519_client; | 245 | kex->kex[KEX_C25519_SHA256] = kexc25519_client; |
246 | #ifdef GSSAPI | ||
247 | if (options.gss_keyex) { | ||
248 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; | ||
249 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; | ||
250 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; | ||
251 | } | ||
252 | #endif | ||
214 | kex->client_version_string=client_version_string; | 253 | kex->client_version_string=client_version_string; |
215 | kex->server_version_string=server_version_string; | 254 | kex->server_version_string=server_version_string; |
216 | kex->verify_host_key=&verify_host_key_callback; | 255 | kex->verify_host_key=&verify_host_key_callback; |
217 | 256 | ||
257 | #ifdef GSSAPI | ||
258 | if (options.gss_keyex) { | ||
259 | kex->gss_deleg_creds = options.gss_deleg_creds; | ||
260 | kex->gss_trust_dns = options.gss_trust_dns; | ||
261 | kex->gss_client = options.gss_client_identity; | ||
262 | if (options.gss_server_identity) { | ||
263 | kex->gss_host = options.gss_server_identity; | ||
264 | } else { | ||
265 | kex->gss_host = gss_host; | ||
266 | } | ||
267 | } | ||
268 | #endif | ||
269 | |||
218 | dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); | 270 | dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); |
219 | 271 | ||
220 | if (options.use_roaming && !kex->roaming) { | 272 | if (options.use_roaming && !kex->roaming) { |
@@ -306,6 +358,7 @@ int input_gssapi_token(int type, u_int32_t, void *); | |||
306 | int input_gssapi_hash(int type, u_int32_t, void *); | 358 | int input_gssapi_hash(int type, u_int32_t, void *); |
307 | int input_gssapi_error(int, u_int32_t, void *); | 359 | int input_gssapi_error(int, u_int32_t, void *); |
308 | int input_gssapi_errtok(int, u_int32_t, void *); | 360 | int input_gssapi_errtok(int, u_int32_t, void *); |
361 | int userauth_gsskeyex(Authctxt *authctxt); | ||
309 | #endif | 362 | #endif |
310 | 363 | ||
311 | void userauth(Authctxt *, char *); | 364 | void userauth(Authctxt *, char *); |
@@ -321,6 +374,11 @@ static char *authmethods_get(void); | |||
321 | 374 | ||
322 | Authmethod authmethods[] = { | 375 | Authmethod authmethods[] = { |
323 | #ifdef GSSAPI | 376 | #ifdef GSSAPI |
377 | {"gssapi-keyex", | ||
378 | userauth_gsskeyex, | ||
379 | NULL, | ||
380 | &options.gss_authentication, | ||
381 | NULL}, | ||
324 | {"gssapi-with-mic", | 382 | {"gssapi-with-mic", |
325 | userauth_gssapi, | 383 | userauth_gssapi, |
326 | NULL, | 384 | NULL, |
@@ -627,19 +685,31 @@ userauth_gssapi(Authctxt *authctxt) | |||
627 | static u_int mech = 0; | 685 | static u_int mech = 0; |
628 | OM_uint32 min; | 686 | OM_uint32 min; |
629 | int ok = 0; | 687 | int ok = 0; |
688 | const char *gss_host; | ||
689 | |||
690 | if (options.gss_server_identity) | ||
691 | gss_host = options.gss_server_identity; | ||
692 | else if (options.gss_trust_dns) | ||
693 | gss_host = get_canonical_hostname(1); | ||
694 | else | ||
695 | gss_host = authctxt->host; | ||
630 | 696 | ||
631 | /* Try one GSSAPI method at a time, rather than sending them all at | 697 | /* Try one GSSAPI method at a time, rather than sending them all at |
632 | * once. */ | 698 | * once. */ |
633 | 699 | ||
634 | if (gss_supported == NULL) | 700 | if (gss_supported == NULL) |
635 | gss_indicate_mechs(&min, &gss_supported); | 701 | if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { |
702 | gss_supported = NULL; | ||
703 | return 0; | ||
704 | } | ||
636 | 705 | ||
637 | /* Check to see if the mechanism is usable before we offer it */ | 706 | /* Check to see if the mechanism is usable before we offer it */ |
638 | while (mech < gss_supported->count && !ok) { | 707 | while (mech < gss_supported->count && !ok) { |
639 | /* My DER encoding requires length<128 */ | 708 | /* My DER encoding requires length<128 */ |
640 | if (gss_supported->elements[mech].length < 128 && | 709 | if (gss_supported->elements[mech].length < 128 && |
641 | ssh_gssapi_check_mechanism(&gssctxt, | 710 | ssh_gssapi_check_mechanism(&gssctxt, |
642 | &gss_supported->elements[mech], authctxt->host)) { | 711 | &gss_supported->elements[mech], gss_host, |
712 | options.gss_client_identity)) { | ||
643 | ok = 1; /* Mechanism works */ | 713 | ok = 1; /* Mechanism works */ |
644 | } else { | 714 | } else { |
645 | mech++; | 715 | mech++; |
@@ -736,8 +806,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
736 | { | 806 | { |
737 | Authctxt *authctxt = ctxt; | 807 | Authctxt *authctxt = ctxt; |
738 | Gssctxt *gssctxt; | 808 | Gssctxt *gssctxt; |
739 | int oidlen; | 809 | u_int oidlen; |
740 | char *oidv; | 810 | u_char *oidv; |
741 | 811 | ||
742 | if (authctxt == NULL) | 812 | if (authctxt == NULL) |
743 | fatal("input_gssapi_response: no authentication context"); | 813 | fatal("input_gssapi_response: no authentication context"); |
@@ -850,6 +920,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) | |||
850 | free(lang); | 920 | free(lang); |
851 | return 0; | 921 | return 0; |
852 | } | 922 | } |
923 | |||
924 | int | ||
925 | userauth_gsskeyex(Authctxt *authctxt) | ||
926 | { | ||
927 | Buffer b; | ||
928 | gss_buffer_desc gssbuf; | ||
929 | gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; | ||
930 | OM_uint32 ms; | ||
931 | |||
932 | static int attempt = 0; | ||
933 | if (attempt++ >= 1) | ||
934 | return (0); | ||
935 | |||
936 | if (gss_kex_context == NULL) { | ||
937 | debug("No valid Key exchange context"); | ||
938 | return (0); | ||
939 | } | ||
940 | |||
941 | ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, | ||
942 | "gssapi-keyex"); | ||
943 | |||
944 | gssbuf.value = buffer_ptr(&b); | ||
945 | gssbuf.length = buffer_len(&b); | ||
946 | |||
947 | if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { | ||
948 | buffer_free(&b); | ||
949 | return (0); | ||
950 | } | ||
951 | |||
952 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
953 | packet_put_cstring(authctxt->server_user); | ||
954 | packet_put_cstring(authctxt->service); | ||
955 | packet_put_cstring(authctxt->method->name); | ||
956 | packet_put_string(mic.value, mic.length); | ||
957 | packet_send(); | ||
958 | |||
959 | buffer_free(&b); | ||
960 | gss_release_buffer(&ms, &mic); | ||
961 | |||
962 | return (1); | ||
963 | } | ||
964 | |||
853 | #endif /* GSSAPI */ | 965 | #endif /* GSSAPI */ |
854 | 966 | ||
855 | int | 967 | int |