diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 117 |
1 files changed, 113 insertions, 4 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index a762eec3b..a96153903 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -104,9 +104,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
104 | { | 104 | { |
105 | Kex *kex; | 105 | Kex *kex; |
106 | 106 | ||
107 | #ifdef GSSAPI | ||
108 | char *orig = NULL, *gss = NULL; | ||
109 | char *gss_host = NULL; | ||
110 | #endif | ||
111 | |||
107 | xxx_host = host; | 112 | xxx_host = host; |
108 | xxx_hostaddr = hostaddr; | 113 | xxx_hostaddr = hostaddr; |
109 | 114 | ||
115 | #ifdef GSSAPI | ||
116 | if (options.gss_keyex) { | ||
117 | /* Add the GSSAPI mechanisms currently supported on this | ||
118 | * client to the key exchange algorithm proposal */ | ||
119 | orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
120 | |||
121 | if (options.gss_trust_dns) | ||
122 | gss_host = (char *)get_canonical_hostname(1); | ||
123 | else | ||
124 | gss_host = host; | ||
125 | |||
126 | gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity); | ||
127 | if (gss) { | ||
128 | debug("Offering GSSAPI proposal: %s", gss); | ||
129 | xasprintf(&myproposal[PROPOSAL_KEX_ALGS], | ||
130 | "%s,%s", gss, orig); | ||
131 | } | ||
132 | } | ||
133 | #endif | ||
134 | |||
110 | if (options.ciphers == (char *)-1) { | 135 | if (options.ciphers == (char *)-1) { |
111 | logit("No valid ciphers for protocol version 2 given, using defaults."); | 136 | logit("No valid ciphers for protocol version 2 given, using defaults."); |
112 | options.ciphers = NULL; | 137 | options.ciphers = NULL; |
@@ -134,6 +159,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
134 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = | 159 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = |
135 | options.hostkeyalgorithms; | 160 | options.hostkeyalgorithms; |
136 | 161 | ||
162 | #ifdef GSSAPI | ||
163 | /* If we've got GSSAPI algorithms, then we also support the | ||
164 | * 'null' hostkey, as a last resort */ | ||
165 | if (options.gss_keyex && gss) { | ||
166 | orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; | ||
167 | xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], | ||
168 | "%s,null", orig); | ||
169 | xfree(gss); | ||
170 | } | ||
171 | #endif | ||
172 | |||
137 | if (options.rekey_limit) | 173 | if (options.rekey_limit) |
138 | packet_set_rekey_limit((u_int32_t)options.rekey_limit); | 174 | packet_set_rekey_limit((u_int32_t)options.rekey_limit); |
139 | 175 | ||
@@ -143,10 +179,26 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
143 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; | 179 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; |
144 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; | 180 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; |
145 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; | 181 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; |
182 | #ifdef GSSAPI | ||
183 | if (options.gss_keyex) { | ||
184 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; | ||
185 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; | ||
186 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; | ||
187 | } | ||
188 | #endif | ||
146 | kex->client_version_string=client_version_string; | 189 | kex->client_version_string=client_version_string; |
147 | kex->server_version_string=server_version_string; | 190 | kex->server_version_string=server_version_string; |
148 | kex->verify_host_key=&verify_host_key_callback; | 191 | kex->verify_host_key=&verify_host_key_callback; |
149 | 192 | ||
193 | #ifdef GSSAPI | ||
194 | if (options.gss_keyex) { | ||
195 | kex->gss_deleg_creds = options.gss_deleg_creds; | ||
196 | kex->gss_trust_dns = options.gss_trust_dns; | ||
197 | kex->gss_client = options.gss_client_identity; | ||
198 | kex->gss_host = gss_host; | ||
199 | } | ||
200 | #endif | ||
201 | |||
150 | xxx_kex = kex; | 202 | xxx_kex = kex; |
151 | 203 | ||
152 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); | 204 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); |
@@ -235,6 +287,7 @@ void input_gssapi_token(int type, u_int32_t, void *); | |||
235 | void input_gssapi_hash(int type, u_int32_t, void *); | 287 | void input_gssapi_hash(int type, u_int32_t, void *); |
236 | void input_gssapi_error(int, u_int32_t, void *); | 288 | void input_gssapi_error(int, u_int32_t, void *); |
237 | void input_gssapi_errtok(int, u_int32_t, void *); | 289 | void input_gssapi_errtok(int, u_int32_t, void *); |
290 | int userauth_gsskeyex(Authctxt *authctxt); | ||
238 | #endif | 291 | #endif |
239 | 292 | ||
240 | void userauth(Authctxt *, char *); | 293 | void userauth(Authctxt *, char *); |
@@ -250,6 +303,10 @@ static char *authmethods_get(void); | |||
250 | 303 | ||
251 | Authmethod authmethods[] = { | 304 | Authmethod authmethods[] = { |
252 | #ifdef GSSAPI | 305 | #ifdef GSSAPI |
306 | {"gssapi-keyex", | ||
307 | userauth_gsskeyex, | ||
308 | &options.gss_authentication, | ||
309 | NULL}, | ||
253 | {"gssapi-with-mic", | 310 | {"gssapi-with-mic", |
254 | userauth_gssapi, | 311 | userauth_gssapi, |
255 | NULL, | 312 | NULL, |
@@ -541,19 +598,29 @@ userauth_gssapi(Authctxt *authctxt) | |||
541 | static u_int mech = 0; | 598 | static u_int mech = 0; |
542 | OM_uint32 min; | 599 | OM_uint32 min; |
543 | int ok = 0; | 600 | int ok = 0; |
601 | const char *gss_host; | ||
602 | |||
603 | if (options.gss_trust_dns) | ||
604 | gss_host = get_canonical_hostname(1); | ||
605 | else | ||
606 | gss_host = authctxt->host; | ||
544 | 607 | ||
545 | /* Try one GSSAPI method at a time, rather than sending them all at | 608 | /* Try one GSSAPI method at a time, rather than sending them all at |
546 | * once. */ | 609 | * once. */ |
547 | 610 | ||
548 | if (gss_supported == NULL) | 611 | if (gss_supported == NULL) |
549 | gss_indicate_mechs(&min, &gss_supported); | 612 | if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { |
613 | gss_supported = NULL; | ||
614 | return 0; | ||
615 | } | ||
550 | 616 | ||
551 | /* Check to see if the mechanism is usable before we offer it */ | 617 | /* Check to see if the mechanism is usable before we offer it */ |
552 | while (mech < gss_supported->count && !ok) { | 618 | while (mech < gss_supported->count && !ok) { |
553 | /* My DER encoding requires length<128 */ | 619 | /* My DER encoding requires length<128 */ |
554 | if (gss_supported->elements[mech].length < 128 && | 620 | if (gss_supported->elements[mech].length < 128 && |
555 | ssh_gssapi_check_mechanism(&gssctxt, | 621 | ssh_gssapi_check_mechanism(&gssctxt, |
556 | &gss_supported->elements[mech], authctxt->host)) { | 622 | &gss_supported->elements[mech], gss_host, |
623 | options.gss_client_identity)) { | ||
557 | ok = 1; /* Mechanism works */ | 624 | ok = 1; /* Mechanism works */ |
558 | } else { | 625 | } else { |
559 | mech++; | 626 | mech++; |
@@ -650,8 +717,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
650 | { | 717 | { |
651 | Authctxt *authctxt = ctxt; | 718 | Authctxt *authctxt = ctxt; |
652 | Gssctxt *gssctxt; | 719 | Gssctxt *gssctxt; |
653 | int oidlen; | 720 | u_int oidlen; |
654 | char *oidv; | 721 | u_char *oidv; |
655 | 722 | ||
656 | if (authctxt == NULL) | 723 | if (authctxt == NULL) |
657 | fatal("input_gssapi_response: no authentication context"); | 724 | fatal("input_gssapi_response: no authentication context"); |
@@ -761,6 +828,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) | |||
761 | xfree(msg); | 828 | xfree(msg); |
762 | xfree(lang); | 829 | xfree(lang); |
763 | } | 830 | } |
831 | |||
832 | int | ||
833 | userauth_gsskeyex(Authctxt *authctxt) | ||
834 | { | ||
835 | Buffer b; | ||
836 | gss_buffer_desc gssbuf; | ||
837 | gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; | ||
838 | OM_uint32 ms; | ||
839 | |||
840 | static int attempt = 0; | ||
841 | if (attempt++ >= 1) | ||
842 | return (0); | ||
843 | |||
844 | if (gss_kex_context == NULL) { | ||
845 | debug("No valid Key exchange context"); | ||
846 | return (0); | ||
847 | } | ||
848 | |||
849 | ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, | ||
850 | "gssapi-keyex"); | ||
851 | |||
852 | gssbuf.value = buffer_ptr(&b); | ||
853 | gssbuf.length = buffer_len(&b); | ||
854 | |||
855 | if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { | ||
856 | buffer_free(&b); | ||
857 | return (0); | ||
858 | } | ||
859 | |||
860 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
861 | packet_put_cstring(authctxt->server_user); | ||
862 | packet_put_cstring(authctxt->service); | ||
863 | packet_put_cstring(authctxt->method->name); | ||
864 | packet_put_string(mic.value, mic.length); | ||
865 | packet_send(); | ||
866 | |||
867 | buffer_free(&b); | ||
868 | gss_release_buffer(&ms, &mic); | ||
869 | |||
870 | return (1); | ||
871 | } | ||
872 | |||
764 | #endif /* GSSAPI */ | 873 | #endif /* GSSAPI */ |
765 | 874 | ||
766 | int | 875 | int |