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 f79c96beb..b452eae24 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -161,6 +161,11 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
161 | struct kex *kex; | 161 | struct kex *kex; |
162 | int r; | 162 | int r; |
163 | 163 | ||
164 | #ifdef GSSAPI | ||
165 | char *orig = NULL, *gss = NULL; | ||
166 | char *gss_host = NULL; | ||
167 | #endif | ||
168 | |||
164 | xxx_host = host; | 169 | xxx_host = host; |
165 | xxx_hostaddr = hostaddr; | 170 | xxx_hostaddr = hostaddr; |
166 | 171 | ||
@@ -195,6 +200,33 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
195 | order_hostkeyalgs(host, hostaddr, port)); | 200 | order_hostkeyalgs(host, hostaddr, port)); |
196 | } | 201 | } |
197 | 202 | ||
203 | #ifdef GSSAPI | ||
204 | if (options.gss_keyex) { | ||
205 | /* Add the GSSAPI mechanisms currently supported on this | ||
206 | * client to the key exchange algorithm proposal */ | ||
207 | orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
208 | |||
209 | if (options.gss_trust_dns) | ||
210 | gss_host = (char *)get_canonical_hostname(1); | ||
211 | else | ||
212 | gss_host = host; | ||
213 | |||
214 | gss = ssh_gssapi_client_mechanisms(gss_host, 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 | free(gss); | ||
226 | } | ||
227 | } | ||
228 | #endif | ||
229 | |||
198 | if (options.rekey_limit || options.rekey_interval) | 230 | if (options.rekey_limit || options.rekey_interval) |
199 | packet_set_rekey_limits((u_int32_t)options.rekey_limit, | 231 | packet_set_rekey_limits((u_int32_t)options.rekey_limit, |
200 | (time_t)options.rekey_interval); | 232 | (time_t)options.rekey_interval); |
@@ -213,10 +245,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
213 | # endif | 245 | # endif |
214 | #endif | 246 | #endif |
215 | kex->kex[KEX_C25519_SHA256] = kexc25519_client; | 247 | kex->kex[KEX_C25519_SHA256] = kexc25519_client; |
248 | #ifdef GSSAPI | ||
249 | if (options.gss_keyex) { | ||
250 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; | ||
251 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; | ||
252 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; | ||
253 | } | ||
254 | #endif | ||
216 | kex->client_version_string=client_version_string; | 255 | kex->client_version_string=client_version_string; |
217 | kex->server_version_string=server_version_string; | 256 | kex->server_version_string=server_version_string; |
218 | kex->verify_host_key=&verify_host_key_callback; | 257 | kex->verify_host_key=&verify_host_key_callback; |
219 | 258 | ||
259 | #ifdef GSSAPI | ||
260 | if (options.gss_keyex) { | ||
261 | kex->gss_deleg_creds = options.gss_deleg_creds; | ||
262 | kex->gss_trust_dns = options.gss_trust_dns; | ||
263 | kex->gss_client = options.gss_client_identity; | ||
264 | if (options.gss_server_identity) { | ||
265 | kex->gss_host = options.gss_server_identity; | ||
266 | } else { | ||
267 | kex->gss_host = gss_host; | ||
268 | } | ||
269 | } | ||
270 | #endif | ||
271 | |||
220 | dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); | 272 | dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); |
221 | 273 | ||
222 | /* remove ext-info from the KEX proposals for rekeying */ | 274 | /* remove ext-info from the KEX proposals for rekeying */ |
@@ -311,6 +363,7 @@ int input_gssapi_token(int type, u_int32_t, void *); | |||
311 | int input_gssapi_hash(int type, u_int32_t, void *); | 363 | int input_gssapi_hash(int type, u_int32_t, void *); |
312 | int input_gssapi_error(int, u_int32_t, void *); | 364 | int input_gssapi_error(int, u_int32_t, void *); |
313 | int input_gssapi_errtok(int, u_int32_t, void *); | 365 | int input_gssapi_errtok(int, u_int32_t, void *); |
366 | int userauth_gsskeyex(Authctxt *authctxt); | ||
314 | #endif | 367 | #endif |
315 | 368 | ||
316 | void userauth(Authctxt *, char *); | 369 | void userauth(Authctxt *, char *); |
@@ -326,6 +379,11 @@ static char *authmethods_get(void); | |||
326 | 379 | ||
327 | Authmethod authmethods[] = { | 380 | Authmethod authmethods[] = { |
328 | #ifdef GSSAPI | 381 | #ifdef GSSAPI |
382 | {"gssapi-keyex", | ||
383 | userauth_gsskeyex, | ||
384 | NULL, | ||
385 | &options.gss_authentication, | ||
386 | NULL}, | ||
329 | {"gssapi-with-mic", | 387 | {"gssapi-with-mic", |
330 | userauth_gssapi, | 388 | userauth_gssapi, |
331 | NULL, | 389 | NULL, |
@@ -656,19 +714,31 @@ userauth_gssapi(Authctxt *authctxt) | |||
656 | static u_int mech = 0; | 714 | static u_int mech = 0; |
657 | OM_uint32 min; | 715 | OM_uint32 min; |
658 | int ok = 0; | 716 | int ok = 0; |
717 | const char *gss_host; | ||
718 | |||
719 | if (options.gss_server_identity) | ||
720 | gss_host = options.gss_server_identity; | ||
721 | else if (options.gss_trust_dns) | ||
722 | gss_host = get_canonical_hostname(1); | ||
723 | else | ||
724 | gss_host = authctxt->host; | ||
659 | 725 | ||
660 | /* Try one GSSAPI method at a time, rather than sending them all at | 726 | /* Try one GSSAPI method at a time, rather than sending them all at |
661 | * once. */ | 727 | * once. */ |
662 | 728 | ||
663 | if (gss_supported == NULL) | 729 | if (gss_supported == NULL) |
664 | gss_indicate_mechs(&min, &gss_supported); | 730 | if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { |
731 | gss_supported = NULL; | ||
732 | return 0; | ||
733 | } | ||
665 | 734 | ||
666 | /* Check to see if the mechanism is usable before we offer it */ | 735 | /* Check to see if the mechanism is usable before we offer it */ |
667 | while (mech < gss_supported->count && !ok) { | 736 | while (mech < gss_supported->count && !ok) { |
668 | /* My DER encoding requires length<128 */ | 737 | /* My DER encoding requires length<128 */ |
669 | if (gss_supported->elements[mech].length < 128 && | 738 | if (gss_supported->elements[mech].length < 128 && |
670 | ssh_gssapi_check_mechanism(&gssctxt, | 739 | ssh_gssapi_check_mechanism(&gssctxt, |
671 | &gss_supported->elements[mech], authctxt->host)) { | 740 | &gss_supported->elements[mech], gss_host, |
741 | options.gss_client_identity)) { | ||
672 | ok = 1; /* Mechanism works */ | 742 | ok = 1; /* Mechanism works */ |
673 | } else { | 743 | } else { |
674 | mech++; | 744 | mech++; |
@@ -765,8 +835,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
765 | { | 835 | { |
766 | Authctxt *authctxt = ctxt; | 836 | Authctxt *authctxt = ctxt; |
767 | Gssctxt *gssctxt; | 837 | Gssctxt *gssctxt; |
768 | int oidlen; | 838 | u_int oidlen; |
769 | char *oidv; | 839 | u_char *oidv; |
770 | 840 | ||
771 | if (authctxt == NULL) | 841 | if (authctxt == NULL) |
772 | fatal("input_gssapi_response: no authentication context"); | 842 | fatal("input_gssapi_response: no authentication context"); |
@@ -879,6 +949,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) | |||
879 | free(lang); | 949 | free(lang); |
880 | return 0; | 950 | return 0; |
881 | } | 951 | } |
952 | |||
953 | int | ||
954 | userauth_gsskeyex(Authctxt *authctxt) | ||
955 | { | ||
956 | Buffer b; | ||
957 | gss_buffer_desc gssbuf; | ||
958 | gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; | ||
959 | OM_uint32 ms; | ||
960 | |||
961 | static int attempt = 0; | ||
962 | if (attempt++ >= 1) | ||
963 | return (0); | ||
964 | |||
965 | if (gss_kex_context == NULL) { | ||
966 | debug("No valid Key exchange context"); | ||
967 | return (0); | ||
968 | } | ||
969 | |||
970 | ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, | ||
971 | "gssapi-keyex"); | ||
972 | |||
973 | gssbuf.value = buffer_ptr(&b); | ||
974 | gssbuf.length = buffer_len(&b); | ||
975 | |||
976 | if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { | ||
977 | buffer_free(&b); | ||
978 | return (0); | ||
979 | } | ||
980 | |||
981 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
982 | packet_put_cstring(authctxt->server_user); | ||
983 | packet_put_cstring(authctxt->service); | ||
984 | packet_put_cstring(authctxt->method->name); | ||
985 | packet_put_string(mic.value, mic.length); | ||
986 | packet_send(); | ||
987 | |||
988 | buffer_free(&b); | ||
989 | gss_release_buffer(&ms, &mic); | ||
990 | |||
991 | return (1); | ||
992 | } | ||
993 | |||
882 | #endif /* GSSAPI */ | 994 | #endif /* GSSAPI */ |
883 | 995 | ||
884 | int | 996 | int |