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 68f7f4fdd..7b478f16d 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -159,9 +159,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
159 | char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; | 159 | char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; |
160 | Kex *kex; | 160 | Kex *kex; |
161 | 161 | ||
162 | #ifdef GSSAPI | ||
163 | char *orig = NULL, *gss = NULL; | ||
164 | char *gss_host = NULL; | ||
165 | #endif | ||
166 | |||
162 | xxx_host = host; | 167 | xxx_host = host; |
163 | xxx_hostaddr = hostaddr; | 168 | xxx_hostaddr = hostaddr; |
164 | 169 | ||
170 | #ifdef GSSAPI | ||
171 | if (options.gss_keyex) { | ||
172 | /* Add the GSSAPI mechanisms currently supported on this | ||
173 | * client to the key exchange algorithm proposal */ | ||
174 | orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
175 | |||
176 | if (options.gss_trust_dns) | ||
177 | gss_host = (char *)get_canonical_hostname(1); | ||
178 | else | ||
179 | gss_host = host; | ||
180 | |||
181 | gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity); | ||
182 | if (gss) { | ||
183 | debug("Offering GSSAPI proposal: %s", gss); | ||
184 | xasprintf(&myproposal[PROPOSAL_KEX_ALGS], | ||
185 | "%s,%s", gss, orig); | ||
186 | } | ||
187 | } | ||
188 | #endif | ||
189 | |||
165 | if (options.ciphers == (char *)-1) { | 190 | if (options.ciphers == (char *)-1) { |
166 | logit("No valid ciphers for protocol version 2 given, using defaults."); | 191 | logit("No valid ciphers for protocol version 2 given, using defaults."); |
167 | options.ciphers = NULL; | 192 | options.ciphers = NULL; |
@@ -199,6 +224,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
199 | myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( | 224 | myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( |
200 | myproposal[PROPOSAL_KEX_ALGS]); | 225 | myproposal[PROPOSAL_KEX_ALGS]); |
201 | 226 | ||
227 | #ifdef GSSAPI | ||
228 | /* If we've got GSSAPI algorithms, then we also support the | ||
229 | * 'null' hostkey, as a last resort */ | ||
230 | if (options.gss_keyex && gss) { | ||
231 | orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; | ||
232 | xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], | ||
233 | "%s,null", orig); | ||
234 | free(gss); | ||
235 | } | ||
236 | #endif | ||
237 | |||
202 | if (options.rekey_limit || options.rekey_interval) | 238 | if (options.rekey_limit || options.rekey_interval) |
203 | packet_set_rekey_limits((u_int32_t)options.rekey_limit, | 239 | packet_set_rekey_limits((u_int32_t)options.rekey_limit, |
204 | (time_t)options.rekey_interval); | 240 | (time_t)options.rekey_interval); |
@@ -213,10 +249,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
213 | kex->kex[KEX_ECDH_SHA2] = kexecdh_client; | 249 | kex->kex[KEX_ECDH_SHA2] = kexecdh_client; |
214 | #endif | 250 | #endif |
215 | kex->kex[KEX_C25519_SHA256] = kexc25519_client; | 251 | kex->kex[KEX_C25519_SHA256] = kexc25519_client; |
252 | #ifdef GSSAPI | ||
253 | if (options.gss_keyex) { | ||
254 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; | ||
255 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; | ||
256 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; | ||
257 | } | ||
258 | #endif | ||
216 | kex->client_version_string=client_version_string; | 259 | kex->client_version_string=client_version_string; |
217 | kex->server_version_string=server_version_string; | 260 | kex->server_version_string=server_version_string; |
218 | kex->verify_host_key=&verify_host_key_callback; | 261 | kex->verify_host_key=&verify_host_key_callback; |
219 | 262 | ||
263 | #ifdef GSSAPI | ||
264 | if (options.gss_keyex) { | ||
265 | kex->gss_deleg_creds = options.gss_deleg_creds; | ||
266 | kex->gss_trust_dns = options.gss_trust_dns; | ||
267 | kex->gss_client = options.gss_client_identity; | ||
268 | if (options.gss_server_identity) { | ||
269 | kex->gss_host = options.gss_server_identity; | ||
270 | } else { | ||
271 | kex->gss_host = gss_host; | ||
272 | } | ||
273 | } | ||
274 | #endif | ||
275 | |||
220 | xxx_kex = kex; | 276 | xxx_kex = kex; |
221 | 277 | ||
222 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); | 278 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); |
@@ -306,6 +362,7 @@ void input_gssapi_token(int type, u_int32_t, void *); | |||
306 | void input_gssapi_hash(int type, u_int32_t, void *); | 362 | void input_gssapi_hash(int type, u_int32_t, void *); |
307 | void input_gssapi_error(int, u_int32_t, void *); | 363 | void input_gssapi_error(int, u_int32_t, void *); |
308 | void input_gssapi_errtok(int, u_int32_t, void *); | 364 | void input_gssapi_errtok(int, u_int32_t, void *); |
365 | int userauth_gsskeyex(Authctxt *authctxt); | ||
309 | #endif | 366 | #endif |
310 | 367 | ||
311 | void userauth(Authctxt *, char *); | 368 | void userauth(Authctxt *, char *); |
@@ -321,6 +378,11 @@ static char *authmethods_get(void); | |||
321 | 378 | ||
322 | Authmethod authmethods[] = { | 379 | Authmethod authmethods[] = { |
323 | #ifdef GSSAPI | 380 | #ifdef GSSAPI |
381 | {"gssapi-keyex", | ||
382 | userauth_gsskeyex, | ||
383 | NULL, | ||
384 | &options.gss_authentication, | ||
385 | NULL}, | ||
324 | {"gssapi-with-mic", | 386 | {"gssapi-with-mic", |
325 | userauth_gssapi, | 387 | userauth_gssapi, |
326 | NULL, | 388 | NULL, |
@@ -617,19 +679,31 @@ userauth_gssapi(Authctxt *authctxt) | |||
617 | static u_int mech = 0; | 679 | static u_int mech = 0; |
618 | OM_uint32 min; | 680 | OM_uint32 min; |
619 | int ok = 0; | 681 | int ok = 0; |
682 | const char *gss_host; | ||
683 | |||
684 | if (options.gss_server_identity) | ||
685 | gss_host = options.gss_server_identity; | ||
686 | else if (options.gss_trust_dns) | ||
687 | gss_host = get_canonical_hostname(1); | ||
688 | else | ||
689 | gss_host = authctxt->host; | ||
620 | 690 | ||
621 | /* Try one GSSAPI method at a time, rather than sending them all at | 691 | /* Try one GSSAPI method at a time, rather than sending them all at |
622 | * once. */ | 692 | * once. */ |
623 | 693 | ||
624 | if (gss_supported == NULL) | 694 | if (gss_supported == NULL) |
625 | gss_indicate_mechs(&min, &gss_supported); | 695 | if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { |
696 | gss_supported = NULL; | ||
697 | return 0; | ||
698 | } | ||
626 | 699 | ||
627 | /* Check to see if the mechanism is usable before we offer it */ | 700 | /* Check to see if the mechanism is usable before we offer it */ |
628 | while (mech < gss_supported->count && !ok) { | 701 | while (mech < gss_supported->count && !ok) { |
629 | /* My DER encoding requires length<128 */ | 702 | /* My DER encoding requires length<128 */ |
630 | if (gss_supported->elements[mech].length < 128 && | 703 | if (gss_supported->elements[mech].length < 128 && |
631 | ssh_gssapi_check_mechanism(&gssctxt, | 704 | ssh_gssapi_check_mechanism(&gssctxt, |
632 | &gss_supported->elements[mech], authctxt->host)) { | 705 | &gss_supported->elements[mech], gss_host, |
706 | options.gss_client_identity)) { | ||
633 | ok = 1; /* Mechanism works */ | 707 | ok = 1; /* Mechanism works */ |
634 | } else { | 708 | } else { |
635 | mech++; | 709 | mech++; |
@@ -726,8 +800,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
726 | { | 800 | { |
727 | Authctxt *authctxt = ctxt; | 801 | Authctxt *authctxt = ctxt; |
728 | Gssctxt *gssctxt; | 802 | Gssctxt *gssctxt; |
729 | int oidlen; | 803 | u_int oidlen; |
730 | char *oidv; | 804 | u_char *oidv; |
731 | 805 | ||
732 | if (authctxt == NULL) | 806 | if (authctxt == NULL) |
733 | fatal("input_gssapi_response: no authentication context"); | 807 | fatal("input_gssapi_response: no authentication context"); |
@@ -836,6 +910,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) | |||
836 | free(msg); | 910 | free(msg); |
837 | free(lang); | 911 | free(lang); |
838 | } | 912 | } |
913 | |||
914 | int | ||
915 | userauth_gsskeyex(Authctxt *authctxt) | ||
916 | { | ||
917 | Buffer b; | ||
918 | gss_buffer_desc gssbuf; | ||
919 | gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; | ||
920 | OM_uint32 ms; | ||
921 | |||
922 | static int attempt = 0; | ||
923 | if (attempt++ >= 1) | ||
924 | return (0); | ||
925 | |||
926 | if (gss_kex_context == NULL) { | ||
927 | debug("No valid Key exchange context"); | ||
928 | return (0); | ||
929 | } | ||
930 | |||
931 | ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, | ||
932 | "gssapi-keyex"); | ||
933 | |||
934 | gssbuf.value = buffer_ptr(&b); | ||
935 | gssbuf.length = buffer_len(&b); | ||
936 | |||
937 | if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { | ||
938 | buffer_free(&b); | ||
939 | return (0); | ||
940 | } | ||
941 | |||
942 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
943 | packet_put_cstring(authctxt->server_user); | ||
944 | packet_put_cstring(authctxt->service); | ||
945 | packet_put_cstring(authctxt->method->name); | ||
946 | packet_put_string(mic.value, mic.length); | ||
947 | packet_send(); | ||
948 | |||
949 | buffer_free(&b); | ||
950 | gss_release_buffer(&ms, &mic); | ||
951 | |||
952 | return (1); | ||
953 | } | ||
954 | |||
839 | #endif /* GSSAPI */ | 955 | #endif /* GSSAPI */ |
840 | 956 | ||
841 | int | 957 | int |