diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 118 |
1 files changed, 114 insertions, 4 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index 2a5943e7e..5bf11c085 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -106,9 +106,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
106 | { | 106 | { |
107 | Kex *kex; | 107 | Kex *kex; |
108 | 108 | ||
109 | #ifdef GSSAPI | ||
110 | char *orig = NULL, *gss = NULL; | ||
111 | char *gss_host = NULL; | ||
112 | #endif | ||
113 | |||
109 | xxx_host = host; | 114 | xxx_host = host; |
110 | xxx_hostaddr = hostaddr; | 115 | xxx_hostaddr = hostaddr; |
111 | 116 | ||
117 | #ifdef GSSAPI | ||
118 | if (options.gss_keyex) { | ||
119 | /* Add the GSSAPI mechanisms currently supported on this | ||
120 | * client to the key exchange algorithm proposal */ | ||
121 | orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
122 | |||
123 | if (options.gss_trust_dns) | ||
124 | gss_host = (char *)get_canonical_hostname(1); | ||
125 | else | ||
126 | gss_host = host; | ||
127 | |||
128 | gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity); | ||
129 | if (gss) { | ||
130 | debug("Offering GSSAPI proposal: %s", gss); | ||
131 | xasprintf(&myproposal[PROPOSAL_KEX_ALGS], | ||
132 | "%s,%s", gss, orig); | ||
133 | } | ||
134 | } | ||
135 | #endif | ||
136 | |||
112 | if (options.ciphers == (char *)-1) { | 137 | if (options.ciphers == (char *)-1) { |
113 | logit("No valid ciphers for protocol version 2 given, using defaults."); | 138 | logit("No valid ciphers for protocol version 2 given, using defaults."); |
114 | options.ciphers = NULL; | 139 | options.ciphers = NULL; |
@@ -136,6 +161,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
136 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = | 161 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = |
137 | options.hostkeyalgorithms; | 162 | options.hostkeyalgorithms; |
138 | 163 | ||
164 | #ifdef GSSAPI | ||
165 | /* If we've got GSSAPI algorithms, then we also support the | ||
166 | * 'null' hostkey, as a last resort */ | ||
167 | if (options.gss_keyex && gss) { | ||
168 | orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; | ||
169 | xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], | ||
170 | "%s,null", orig); | ||
171 | xfree(gss); | ||
172 | } | ||
173 | #endif | ||
174 | |||
139 | if (options.rekey_limit) | 175 | if (options.rekey_limit) |
140 | packet_set_rekey_limit((u_int32_t)options.rekey_limit); | 176 | packet_set_rekey_limit((u_int32_t)options.rekey_limit); |
141 | 177 | ||
@@ -145,10 +181,26 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
145 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; | 181 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; |
146 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; | 182 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; |
147 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; | 183 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; |
184 | #ifdef GSSAPI | ||
185 | if (options.gss_keyex) { | ||
186 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; | ||
187 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; | ||
188 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; | ||
189 | } | ||
190 | #endif | ||
148 | kex->client_version_string=client_version_string; | 191 | kex->client_version_string=client_version_string; |
149 | kex->server_version_string=server_version_string; | 192 | kex->server_version_string=server_version_string; |
150 | kex->verify_host_key=&verify_host_key_callback; | 193 | kex->verify_host_key=&verify_host_key_callback; |
151 | 194 | ||
195 | #ifdef GSSAPI | ||
196 | if (options.gss_keyex) { | ||
197 | kex->gss_deleg_creds = options.gss_deleg_creds; | ||
198 | kex->gss_trust_dns = options.gss_trust_dns; | ||
199 | kex->gss_client = options.gss_client_identity; | ||
200 | kex->gss_host = gss_host; | ||
201 | } | ||
202 | #endif | ||
203 | |||
152 | xxx_kex = kex; | 204 | xxx_kex = kex; |
153 | 205 | ||
154 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); | 206 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); |
@@ -243,6 +295,7 @@ void input_gssapi_token(int type, u_int32_t, void *); | |||
243 | void input_gssapi_hash(int type, u_int32_t, void *); | 295 | void input_gssapi_hash(int type, u_int32_t, void *); |
244 | void input_gssapi_error(int, u_int32_t, void *); | 296 | void input_gssapi_error(int, u_int32_t, void *); |
245 | void input_gssapi_errtok(int, u_int32_t, void *); | 297 | void input_gssapi_errtok(int, u_int32_t, void *); |
298 | int userauth_gsskeyex(Authctxt *authctxt); | ||
246 | #endif | 299 | #endif |
247 | 300 | ||
248 | void userauth(Authctxt *, char *); | 301 | void userauth(Authctxt *, char *); |
@@ -258,6 +311,11 @@ static char *authmethods_get(void); | |||
258 | 311 | ||
259 | Authmethod authmethods[] = { | 312 | Authmethod authmethods[] = { |
260 | #ifdef GSSAPI | 313 | #ifdef GSSAPI |
314 | {"gssapi-keyex", | ||
315 | userauth_gsskeyex, | ||
316 | NULL, | ||
317 | &options.gss_authentication, | ||
318 | NULL}, | ||
261 | {"gssapi-with-mic", | 319 | {"gssapi-with-mic", |
262 | userauth_gssapi, | 320 | userauth_gssapi, |
263 | NULL, | 321 | NULL, |
@@ -564,19 +622,29 @@ userauth_gssapi(Authctxt *authctxt) | |||
564 | static u_int mech = 0; | 622 | static u_int mech = 0; |
565 | OM_uint32 min; | 623 | OM_uint32 min; |
566 | int ok = 0; | 624 | int ok = 0; |
625 | const char *gss_host; | ||
626 | |||
627 | if (options.gss_trust_dns) | ||
628 | gss_host = get_canonical_hostname(1); | ||
629 | else | ||
630 | gss_host = authctxt->host; | ||
567 | 631 | ||
568 | /* Try one GSSAPI method at a time, rather than sending them all at | 632 | /* Try one GSSAPI method at a time, rather than sending them all at |
569 | * once. */ | 633 | * once. */ |
570 | 634 | ||
571 | if (gss_supported == NULL) | 635 | if (gss_supported == NULL) |
572 | gss_indicate_mechs(&min, &gss_supported); | 636 | if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { |
637 | gss_supported = NULL; | ||
638 | return 0; | ||
639 | } | ||
573 | 640 | ||
574 | /* Check to see if the mechanism is usable before we offer it */ | 641 | /* Check to see if the mechanism is usable before we offer it */ |
575 | while (mech < gss_supported->count && !ok) { | 642 | while (mech < gss_supported->count && !ok) { |
576 | /* My DER encoding requires length<128 */ | 643 | /* My DER encoding requires length<128 */ |
577 | if (gss_supported->elements[mech].length < 128 && | 644 | if (gss_supported->elements[mech].length < 128 && |
578 | ssh_gssapi_check_mechanism(&gssctxt, | 645 | ssh_gssapi_check_mechanism(&gssctxt, |
579 | &gss_supported->elements[mech], authctxt->host)) { | 646 | &gss_supported->elements[mech], gss_host, |
647 | options.gss_client_identity)) { | ||
580 | ok = 1; /* Mechanism works */ | 648 | ok = 1; /* Mechanism works */ |
581 | } else { | 649 | } else { |
582 | mech++; | 650 | mech++; |
@@ -673,8 +741,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
673 | { | 741 | { |
674 | Authctxt *authctxt = ctxt; | 742 | Authctxt *authctxt = ctxt; |
675 | Gssctxt *gssctxt; | 743 | Gssctxt *gssctxt; |
676 | int oidlen; | 744 | u_int oidlen; |
677 | char *oidv; | 745 | u_char *oidv; |
678 | 746 | ||
679 | if (authctxt == NULL) | 747 | if (authctxt == NULL) |
680 | fatal("input_gssapi_response: no authentication context"); | 748 | fatal("input_gssapi_response: no authentication context"); |
@@ -784,6 +852,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) | |||
784 | xfree(msg); | 852 | xfree(msg); |
785 | xfree(lang); | 853 | xfree(lang); |
786 | } | 854 | } |
855 | |||
856 | int | ||
857 | userauth_gsskeyex(Authctxt *authctxt) | ||
858 | { | ||
859 | Buffer b; | ||
860 | gss_buffer_desc gssbuf; | ||
861 | gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; | ||
862 | OM_uint32 ms; | ||
863 | |||
864 | static int attempt = 0; | ||
865 | if (attempt++ >= 1) | ||
866 | return (0); | ||
867 | |||
868 | if (gss_kex_context == NULL) { | ||
869 | debug("No valid Key exchange context"); | ||
870 | return (0); | ||
871 | } | ||
872 | |||
873 | ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, | ||
874 | "gssapi-keyex"); | ||
875 | |||
876 | gssbuf.value = buffer_ptr(&b); | ||
877 | gssbuf.length = buffer_len(&b); | ||
878 | |||
879 | if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { | ||
880 | buffer_free(&b); | ||
881 | return (0); | ||
882 | } | ||
883 | |||
884 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
885 | packet_put_cstring(authctxt->server_user); | ||
886 | packet_put_cstring(authctxt->service); | ||
887 | packet_put_cstring(authctxt->method->name); | ||
888 | packet_put_string(mic.value, mic.length); | ||
889 | packet_send(); | ||
890 | |||
891 | buffer_free(&b); | ||
892 | gss_release_buffer(&ms, &mic); | ||
893 | |||
894 | return (1); | ||
895 | } | ||
896 | |||
787 | #endif /* GSSAPI */ | 897 | #endif /* GSSAPI */ |
788 | 898 | ||
789 | int | 899 | int |