diff options
-rw-r--r-- | ChangeLog.gssapi | 69 | ||||
-rw-r--r-- | Makefile.in | 4 | ||||
-rw-r--r-- | auth-krb5.c | 17 | ||||
-rw-r--r-- | auth.h | 1 | ||||
-rw-r--r-- | auth2-gss.c | 41 | ||||
-rw-r--r-- | auth2.c | 7 | ||||
-rw-r--r-- | configure.ac | 26 | ||||
-rw-r--r-- | gss-genr.c | 170 | ||||
-rw-r--r-- | gss-serv-krb5.c | 14 | ||||
-rw-r--r-- | gss-serv.c | 38 | ||||
-rw-r--r-- | kex.c | 18 | ||||
-rw-r--r-- | kex.h | 13 | ||||
-rw-r--r-- | kexgssc.c | 319 | ||||
-rw-r--r-- | kexgsss.c | 271 | ||||
-rw-r--r-- | key.c | 2 | ||||
-rw-r--r-- | key.h | 1 | ||||
-rw-r--r-- | monitor.c | 59 | ||||
-rw-r--r-- | monitor.h | 1 | ||||
-rw-r--r-- | monitor_wrap.c | 23 | ||||
-rw-r--r-- | monitor_wrap.h | 1 | ||||
-rw-r--r-- | readconf.c | 20 | ||||
-rw-r--r-- | readconf.h | 2 | ||||
-rw-r--r-- | servconf.c | 22 | ||||
-rw-r--r-- | servconf.h | 2 | ||||
-rw-r--r-- | ssh-gss.h | 19 | ||||
-rw-r--r-- | ssh_config | 2 | ||||
-rw-r--r-- | ssh_config.5 | 17 | ||||
-rw-r--r-- | sshconnect2.c | 105 | ||||
-rw-r--r-- | sshd.c | 108 | ||||
-rw-r--r-- | sshd_config | 2 | ||||
-rw-r--r-- | sshd_config.5 | 23 |
31 files changed, 1391 insertions, 26 deletions
diff --git a/ChangeLog.gssapi b/ChangeLog.gssapi new file mode 100644 index 000000000..010612c4c --- /dev/null +++ b/ChangeLog.gssapi | |||
@@ -0,0 +1,69 @@ | |||
1 | 20070317 | ||
2 | - [ gss-serv-krb5.c ] | ||
3 | Remove C99ism, where new_ccname was being declared in the middle of a | ||
4 | function | ||
5 | |||
6 | 20061220 | ||
7 | - [ servconf.c ] | ||
8 | Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and | ||
9 | documented, behaviour. Reported by Dan Watson. | ||
10 | |||
11 | 20060910 | ||
12 | - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c | ||
13 | ssh-gss.h ] | ||
14 | add support for gss-group14-sha1 key exchange mechanisms | ||
15 | - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ] | ||
16 | Add GSSAPIStrictAcceptorCheck option to allow the disabling of | ||
17 | acceptor principal checking on multi-homed machines. | ||
18 | <Bugzilla #928> | ||
19 | - [ sshd_config ssh_config ] | ||
20 | Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample | ||
21 | configuration files | ||
22 | - [ kexgss.c kegsss.c sshconnect2.c sshd.c ] | ||
23 | Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf() | ||
24 | Limit length of error messages displayed by client | ||
25 | |||
26 | 20060909 | ||
27 | - [ gss-genr.c gss-serv.c ] | ||
28 | move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server | ||
29 | only, where they belong | ||
30 | <Bugzilla #1225> | ||
31 | |||
32 | 20060829 | ||
33 | - [ gss-serv-krb5.c ] | ||
34 | Fix CCAPI credentials cache name when creating KRB5CCNAME environment | ||
35 | variable | ||
36 | |||
37 | 20060828 | ||
38 | - [ gss-genr.c ] | ||
39 | Avoid Heimdal context freeing problem | ||
40 | <Fixed upstream 20060829> | ||
41 | |||
42 | 20060818 | ||
43 | - [ gss-genr.c ssh-gss.h sshconnect2.c ] | ||
44 | Make sure that SPENGO is disabled | ||
45 | <Bugzilla #1218 - Fixed upstream 20060818> | ||
46 | |||
47 | 20060421 | ||
48 | - [ gssgenr.c, sshconnect2.c ] | ||
49 | a few type changes (signed versus unsigned, int versus size_t) to | ||
50 | fix compiler errors/warnings | ||
51 | (from jbasney AT ncsa.uiuc.edu) | ||
52 | - [ kexgssc.c, sshconnect2.c ] | ||
53 | fix uninitialized variable warnings | ||
54 | (from jbasney AT ncsa.uiuc.edu) | ||
55 | - [ gssgenr.c ] | ||
56 | pass oid to gss_display_status (helpful when using GSSAPI mechglue) | ||
57 | (from jbasney AT ncsa.uiuc.edu) | ||
58 | <Bugzilla #1220 > | ||
59 | - [ gss-serv-krb5.c ] | ||
60 | #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H | ||
61 | (from jbasney AT ncsa.uiuc.edu) | ||
62 | <Fixed upstream 20060304> | ||
63 | - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c | ||
64 | add client-side GssapiKeyExchange option | ||
65 | (from jbasney AT ncsa.uiuc.edu) | ||
66 | - [ sshconnect2.c ] | ||
67 | add support for GssapiTrustDns option for gssapi-with-mic | ||
68 | (from jbasney AT ncsa.uiuc.edu) | ||
69 | <gssapi-with-mic support is Bugzilla #1008> | ||
diff --git a/Makefile.in b/Makefile.in index 2486edc95..1e77a67b5 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -71,7 +71,7 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \ | |||
71 | atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ | 71 | atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ |
72 | monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \ | 72 | monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \ |
73 | kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \ | 73 | kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \ |
74 | entropy.o scard-opensc.o gss-genr.o umac.o | 74 | entropy.o scard-opensc.o gss-genr.o umac.o kexgssc.o |
75 | 75 | ||
76 | SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ | 76 | SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ |
77 | sshconnect.o sshconnect1.o sshconnect2.o | 77 | sshconnect.o sshconnect1.o sshconnect2.o |
@@ -84,7 +84,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ | |||
84 | auth2-none.o auth2-passwd.o auth2-pubkey.o \ | 84 | auth2-none.o auth2-passwd.o auth2-pubkey.o \ |
85 | monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \ | 85 | monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \ |
86 | auth-krb5.o \ | 86 | auth-krb5.o \ |
87 | auth2-gss.o gss-serv.o gss-serv-krb5.o \ | 87 | auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\ |
88 | loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ | 88 | loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ |
89 | audit.o audit-bsm.o platform.o | 89 | audit.o audit-bsm.o platform.o |
90 | 90 | ||
diff --git a/auth-krb5.c b/auth-krb5.c index 868288126..38164fda8 100644 --- a/auth-krb5.c +++ b/auth-krb5.c | |||
@@ -166,8 +166,13 @@ auth_krb5_password(Authctxt *authctxt, const char *password) | |||
166 | 166 | ||
167 | len = strlen(authctxt->krb5_ticket_file) + 6; | 167 | len = strlen(authctxt->krb5_ticket_file) + 6; |
168 | authctxt->krb5_ccname = xmalloc(len); | 168 | authctxt->krb5_ccname = xmalloc(len); |
169 | #ifdef USE_CCAPI | ||
170 | snprintf(authctxt->krb5_ccname, len, "API:%s", | ||
171 | authctxt->krb5_ticket_file); | ||
172 | #else | ||
169 | snprintf(authctxt->krb5_ccname, len, "FILE:%s", | 173 | snprintf(authctxt->krb5_ccname, len, "FILE:%s", |
170 | authctxt->krb5_ticket_file); | 174 | authctxt->krb5_ticket_file); |
175 | #endif | ||
171 | 176 | ||
172 | #ifdef USE_PAM | 177 | #ifdef USE_PAM |
173 | if (options.use_pam) | 178 | if (options.use_pam) |
@@ -219,15 +224,22 @@ krb5_cleanup_proc(Authctxt *authctxt) | |||
219 | #ifndef HEIMDAL | 224 | #ifndef HEIMDAL |
220 | krb5_error_code | 225 | krb5_error_code |
221 | ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { | 226 | ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { |
222 | int tmpfd, ret; | 227 | int ret; |
223 | char ccname[40]; | 228 | char ccname[40]; |
224 | mode_t old_umask; | 229 | mode_t old_umask; |
230 | #ifdef USE_CCAPI | ||
231 | char cctemplate[] = "API:krb5cc_%d"; | ||
232 | #else | ||
233 | char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX"; | ||
234 | int tmpfd; | ||
235 | #endif | ||
225 | 236 | ||
226 | ret = snprintf(ccname, sizeof(ccname), | 237 | ret = snprintf(ccname, sizeof(ccname), |
227 | "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); | 238 | cctemplate, geteuid()); |
228 | if (ret < 0 || (size_t)ret >= sizeof(ccname)) | 239 | if (ret < 0 || (size_t)ret >= sizeof(ccname)) |
229 | return ENOMEM; | 240 | return ENOMEM; |
230 | 241 | ||
242 | #ifndef USE_CCAPI | ||
231 | old_umask = umask(0177); | 243 | old_umask = umask(0177); |
232 | tmpfd = mkstemp(ccname + strlen("FILE:")); | 244 | tmpfd = mkstemp(ccname + strlen("FILE:")); |
233 | umask(old_umask); | 245 | umask(old_umask); |
@@ -242,6 +254,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { | |||
242 | return errno; | 254 | return errno; |
243 | } | 255 | } |
244 | close(tmpfd); | 256 | close(tmpfd); |
257 | #endif | ||
245 | 258 | ||
246 | return (krb5_cc_resolve(ctx, ccname, ccache)); | 259 | return (krb5_cc_resolve(ctx, ccname, ccache)); |
247 | } | 260 | } |
@@ -53,6 +53,7 @@ struct Authctxt { | |||
53 | int valid; /* user exists and is allowed to login */ | 53 | int valid; /* user exists and is allowed to login */ |
54 | int attempt; | 54 | int attempt; |
55 | int failures; | 55 | int failures; |
56 | int server_caused_failure; | ||
56 | int force_pwchange; | 57 | int force_pwchange; |
57 | char *user; /* username sent by the client */ | 58 | char *user; /* username sent by the client */ |
58 | char *service; | 59 | char *service; |
diff --git a/auth2-gss.c b/auth2-gss.c index c77c841a3..50bdc6452 100644 --- a/auth2-gss.c +++ b/auth2-gss.c | |||
@@ -52,6 +52,39 @@ static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt); | |||
52 | static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); | 52 | static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); |
53 | static void input_gssapi_errtok(int, u_int32_t, void *); | 53 | static void input_gssapi_errtok(int, u_int32_t, void *); |
54 | 54 | ||
55 | /* | ||
56 | * The 'gssapi_keyex' userauth mechanism. | ||
57 | */ | ||
58 | static int | ||
59 | userauth_gsskeyex(Authctxt *authctxt) | ||
60 | { | ||
61 | int authenticated = 0; | ||
62 | Buffer b; | ||
63 | gss_buffer_desc mic, gssbuf; | ||
64 | u_int len; | ||
65 | |||
66 | mic.value = packet_get_string(&len); | ||
67 | mic.length = len; | ||
68 | |||
69 | packet_check_eom(); | ||
70 | |||
71 | ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service, | ||
72 | "gssapi-keyex"); | ||
73 | |||
74 | gssbuf.value = buffer_ptr(&b); | ||
75 | gssbuf.length = buffer_len(&b); | ||
76 | |||
77 | /* gss_kex_context is NULL with privsep, so we can't check it here */ | ||
78 | if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, | ||
79 | &gssbuf, &mic)))) | ||
80 | authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); | ||
81 | |||
82 | buffer_free(&b); | ||
83 | xfree(mic.value); | ||
84 | |||
85 | return (authenticated); | ||
86 | } | ||
87 | |||
55 | /* | 88 | /* |
56 | * We only support those mechanisms that we know about (ie ones that we know | 89 | * We only support those mechanisms that we know about (ie ones that we know |
57 | * how to check local user kuserok and the like) | 90 | * how to check local user kuserok and the like) |
@@ -102,6 +135,7 @@ userauth_gssapi(Authctxt *authctxt) | |||
102 | 135 | ||
103 | if (!present) { | 136 | if (!present) { |
104 | xfree(doid); | 137 | xfree(doid); |
138 | authctxt->server_caused_failure = 1; | ||
105 | return (0); | 139 | return (0); |
106 | } | 140 | } |
107 | 141 | ||
@@ -109,6 +143,7 @@ userauth_gssapi(Authctxt *authctxt) | |||
109 | if (ctxt != NULL) | 143 | if (ctxt != NULL) |
110 | ssh_gssapi_delete_ctx(&ctxt); | 144 | ssh_gssapi_delete_ctx(&ctxt); |
111 | xfree(doid); | 145 | xfree(doid); |
146 | authctxt->server_caused_failure = 1; | ||
112 | return (0); | 147 | return (0); |
113 | } | 148 | } |
114 | 149 | ||
@@ -292,6 +327,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) | |||
292 | userauth_finish(authctxt, authenticated, "gssapi-with-mic"); | 327 | userauth_finish(authctxt, authenticated, "gssapi-with-mic"); |
293 | } | 328 | } |
294 | 329 | ||
330 | Authmethod method_gsskeyex = { | ||
331 | "gssapi-keyex", | ||
332 | userauth_gsskeyex, | ||
333 | &options.gss_authentication | ||
334 | }; | ||
335 | |||
295 | Authmethod method_gssapi = { | 336 | Authmethod method_gssapi = { |
296 | "gssapi-with-mic", | 337 | "gssapi-with-mic", |
297 | userauth_gssapi, | 338 | userauth_gssapi, |
@@ -64,6 +64,7 @@ extern Authmethod method_passwd; | |||
64 | extern Authmethod method_kbdint; | 64 | extern Authmethod method_kbdint; |
65 | extern Authmethod method_hostbased; | 65 | extern Authmethod method_hostbased; |
66 | #ifdef GSSAPI | 66 | #ifdef GSSAPI |
67 | extern Authmethod method_gsskeyex; | ||
67 | extern Authmethod method_gssapi; | 68 | extern Authmethod method_gssapi; |
68 | #endif | 69 | #endif |
69 | 70 | ||
@@ -71,6 +72,7 @@ Authmethod *authmethods[] = { | |||
71 | &method_none, | 72 | &method_none, |
72 | &method_pubkey, | 73 | &method_pubkey, |
73 | #ifdef GSSAPI | 74 | #ifdef GSSAPI |
75 | &method_gsskeyex, | ||
74 | &method_gssapi, | 76 | &method_gssapi, |
75 | #endif | 77 | #endif |
76 | &method_passwd, | 78 | &method_passwd, |
@@ -195,6 +197,7 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) | |||
195 | #endif | 197 | #endif |
196 | 198 | ||
197 | authctxt->postponed = 0; | 199 | authctxt->postponed = 0; |
200 | authctxt->server_caused_failure = 0; | ||
198 | 201 | ||
199 | /* try to authenticate user */ | 202 | /* try to authenticate user */ |
200 | m = authmethod_lookup(method); | 203 | m = authmethod_lookup(method); |
@@ -265,7 +268,9 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method) | |||
265 | /* now we can break out */ | 268 | /* now we can break out */ |
266 | authctxt->success = 1; | 269 | authctxt->success = 1; |
267 | } else { | 270 | } else { |
268 | if (authctxt->failures++ > options.max_authtries) { | 271 | /* Dont count server configuration issues against the client */ |
272 | if (!authctxt->server_caused_failure && | ||
273 | authctxt->failures++ > options.max_authtries) { | ||
269 | #ifdef SSH_AUDIT_EVENTS | 274 | #ifdef SSH_AUDIT_EVENTS |
270 | PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); | 275 | PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); |
271 | #endif | 276 | #endif |
diff --git a/configure.ac b/configure.ac index f1052b079..a9eb8e76d 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -412,7 +412,31 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) | |||
412 | [Use tunnel device compatibility to OpenBSD]) | 412 | [Use tunnel device compatibility to OpenBSD]) |
413 | AC_DEFINE(SSH_TUN_PREPEND_AF, 1, | 413 | AC_DEFINE(SSH_TUN_PREPEND_AF, 1, |
414 | [Prepend the address family to IP tunnel traffic]) | 414 | [Prepend the address family to IP tunnel traffic]) |
415 | ;; | 415 | AC_MSG_CHECKING(if we have the Security Authorization Session API) |
416 | AC_TRY_COMPILE([#include <Security/AuthSession.h>], | ||
417 | [SessionCreate(0, 0);], | ||
418 | [ac_cv_use_security_session_api="yes" | ||
419 | AC_DEFINE(USE_SECURITY_SESSION_API, 1, | ||
420 | [platform has the Security Authorization Session API]) | ||
421 | LIBS="$LIBS -framework Security" | ||
422 | AC_MSG_RESULT(yes)], | ||
423 | [ac_cv_use_security_session_api="no" | ||
424 | AC_MSG_RESULT(no)]) | ||
425 | AC_MSG_CHECKING(if we have an in-memory credentials cache) | ||
426 | AC_TRY_COMPILE( | ||
427 | [#include <Kerberos/Kerberos.h>], | ||
428 | [cc_context_t c; | ||
429 | (void) cc_initialize (&c, 0, NULL, NULL);], | ||
430 | [AC_DEFINE(USE_CCAPI, 1, | ||
431 | [platform uses an in-memory credentials cache]) | ||
432 | LIBS="$LIBS -framework Security" | ||
433 | AC_MSG_RESULT(yes) | ||
434 | if test "x$ac_cv_use_security_session_api" = "xno"; then | ||
435 | AC_MSG_ERROR(*** Need a security framework to use the credentials cache API ***) | ||
436 | fi], | ||
437 | [AC_MSG_RESULT(no)] | ||
438 | ) | ||
439 | ;; | ||
416 | *-*-dragonfly*) | 440 | *-*-dragonfly*) |
417 | SSHDLIBS="$SSHDLIBS -lcrypt" | 441 | SSHDLIBS="$SSHDLIBS -lcrypt" |
418 | ;; | 442 | ;; |
diff --git a/gss-genr.c b/gss-genr.c index e9190575d..822a08212 100644 --- a/gss-genr.c +++ b/gss-genr.c | |||
@@ -39,12 +39,160 @@ | |||
39 | #include "buffer.h" | 39 | #include "buffer.h" |
40 | #include "log.h" | 40 | #include "log.h" |
41 | #include "ssh2.h" | 41 | #include "ssh2.h" |
42 | #include "cipher.h" | ||
43 | #include "key.h" | ||
44 | #include "kex.h" | ||
45 | #include <openssl/evp.h> | ||
42 | 46 | ||
43 | #include "ssh-gss.h" | 47 | #include "ssh-gss.h" |
44 | 48 | ||
45 | extern u_char *session_id2; | 49 | extern u_char *session_id2; |
46 | extern u_int session_id2_len; | 50 | extern u_int session_id2_len; |
47 | 51 | ||
52 | typedef struct { | ||
53 | char *encoded; | ||
54 | gss_OID oid; | ||
55 | } ssh_gss_kex_mapping; | ||
56 | |||
57 | /* | ||
58 | * XXX - It would be nice to find a more elegant way of handling the | ||
59 | * XXX passing of the key exchange context to the userauth routines | ||
60 | */ | ||
61 | |||
62 | Gssctxt *gss_kex_context = NULL; | ||
63 | |||
64 | static ssh_gss_kex_mapping *gss_enc2oid = NULL; | ||
65 | |||
66 | int | ||
67 | ssh_gssapi_oid_table_ok() { | ||
68 | return (gss_enc2oid != NULL); | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * Return a list of the gss-group1-sha1 mechanisms supported by this program | ||
73 | * | ||
74 | * We test mechanisms to ensure that we can use them, to avoid starting | ||
75 | * a key exchange with a bad mechanism | ||
76 | */ | ||
77 | |||
78 | char * | ||
79 | ssh_gssapi_client_mechanisms(const char *host) { | ||
80 | gss_OID_set gss_supported; | ||
81 | OM_uint32 min_status; | ||
82 | |||
83 | gss_indicate_mechs(&min_status, &gss_supported); | ||
84 | |||
85 | return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, | ||
86 | host)); | ||
87 | } | ||
88 | |||
89 | char * | ||
90 | ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, | ||
91 | const char *data) { | ||
92 | Buffer buf; | ||
93 | size_t i; | ||
94 | int oidpos, enclen; | ||
95 | char *mechs, *encoded; | ||
96 | u_char digest[EVP_MAX_MD_SIZE]; | ||
97 | char deroid[2]; | ||
98 | const EVP_MD *evp_md = EVP_md5(); | ||
99 | EVP_MD_CTX md; | ||
100 | |||
101 | if (gss_enc2oid != NULL) { | ||
102 | for (i = 0; gss_enc2oid[i].encoded != NULL; i++) | ||
103 | xfree(gss_enc2oid[i].encoded); | ||
104 | xfree(gss_enc2oid); | ||
105 | } | ||
106 | |||
107 | gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) * | ||
108 | (gss_supported->count + 1)); | ||
109 | |||
110 | buffer_init(&buf); | ||
111 | |||
112 | oidpos = 0; | ||
113 | for (i = 0; i < gss_supported->count; i++) { | ||
114 | if (gss_supported->elements[i].length < 128 && | ||
115 | (*check)(NULL, &(gss_supported->elements[i]), data)) { | ||
116 | |||
117 | deroid[0] = SSH_GSS_OIDTYPE; | ||
118 | deroid[1] = gss_supported->elements[i].length; | ||
119 | |||
120 | EVP_DigestInit(&md, evp_md); | ||
121 | EVP_DigestUpdate(&md, deroid, 2); | ||
122 | EVP_DigestUpdate(&md, | ||
123 | gss_supported->elements[i].elements, | ||
124 | gss_supported->elements[i].length); | ||
125 | EVP_DigestFinal(&md, digest, NULL); | ||
126 | |||
127 | encoded = xmalloc(EVP_MD_size(evp_md) * 2); | ||
128 | enclen = __b64_ntop(digest, EVP_MD_size(evp_md), | ||
129 | encoded, EVP_MD_size(evp_md) * 2); | ||
130 | |||
131 | if (oidpos != 0) | ||
132 | buffer_put_char(&buf, ','); | ||
133 | |||
134 | buffer_append(&buf, KEX_GSS_GEX_SHA1_ID, | ||
135 | sizeof(KEX_GSS_GEX_SHA1_ID) - 1); | ||
136 | buffer_append(&buf, encoded, enclen); | ||
137 | buffer_put_char(&buf, ','); | ||
138 | buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, | ||
139 | sizeof(KEX_GSS_GRP1_SHA1_ID) - 1); | ||
140 | buffer_append(&buf, encoded, enclen); | ||
141 | buffer_put_char(&buf, ','); | ||
142 | buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID, | ||
143 | sizeof(KEX_GSS_GRP14_SHA1_ID) - 1); | ||
144 | buffer_append(&buf, encoded, enclen); | ||
145 | |||
146 | gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); | ||
147 | gss_enc2oid[oidpos].encoded = encoded; | ||
148 | oidpos++; | ||
149 | } | ||
150 | } | ||
151 | gss_enc2oid[oidpos].oid = NULL; | ||
152 | gss_enc2oid[oidpos].encoded = NULL; | ||
153 | |||
154 | buffer_put_char(&buf, '\0'); | ||
155 | |||
156 | mechs = xmalloc(buffer_len(&buf)); | ||
157 | buffer_get(&buf, mechs, buffer_len(&buf)); | ||
158 | buffer_free(&buf); | ||
159 | |||
160 | if (strlen(mechs) == 0) { | ||
161 | xfree(mechs); | ||
162 | mechs = NULL; | ||
163 | } | ||
164 | |||
165 | return (mechs); | ||
166 | } | ||
167 | |||
168 | gss_OID | ||
169 | ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) { | ||
170 | int i = 0; | ||
171 | |||
172 | switch (kex_type) { | ||
173 | case KEX_GSS_GRP1_SHA1: | ||
174 | name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1; | ||
175 | break; | ||
176 | case KEX_GSS_GRP14_SHA1: | ||
177 | name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1; | ||
178 | break; | ||
179 | case KEX_GSS_GEX_SHA1: | ||
180 | name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1; | ||
181 | break; | ||
182 | default: | ||
183 | return GSS_C_NO_OID; | ||
184 | } | ||
185 | |||
186 | while (gss_enc2oid[i].encoded != NULL && | ||
187 | strcmp(name, gss_enc2oid[i].encoded) != 0) | ||
188 | i++; | ||
189 | |||
190 | if (gss_enc2oid[i].oid != NULL && ctx != NULL) | ||
191 | ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid); | ||
192 | |||
193 | return gss_enc2oid[i].oid; | ||
194 | } | ||
195 | |||
48 | /* Check that the OID in a data stream matches that in the context */ | 196 | /* Check that the OID in a data stream matches that in the context */ |
49 | int | 197 | int |
50 | ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) | 198 | ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) |
@@ -229,6 +377,9 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) | |||
229 | OM_uint32 | 377 | OM_uint32 |
230 | ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) | 378 | ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) |
231 | { | 379 | { |
380 | if (ctx == NULL) | ||
381 | return -1; | ||
382 | |||
232 | if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, | 383 | if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, |
233 | GSS_C_QOP_DEFAULT, buffer, hash))) | 384 | GSS_C_QOP_DEFAULT, buffer, hash))) |
234 | ssh_gssapi_error(ctx); | 385 | ssh_gssapi_error(ctx); |
@@ -236,6 +387,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) | |||
236 | return (ctx->major); | 387 | return (ctx->major); |
237 | } | 388 | } |
238 | 389 | ||
390 | /* Priviledged when used by server */ | ||
391 | OM_uint32 | ||
392 | ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) | ||
393 | { | ||
394 | if (ctx == NULL) | ||
395 | return -1; | ||
396 | |||
397 | ctx->major = gss_verify_mic(&ctx->minor, ctx->context, | ||
398 | gssbuf, gssmic, NULL); | ||
399 | |||
400 | return (ctx->major); | ||
401 | } | ||
402 | |||
239 | void | 403 | void |
240 | ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, | 404 | ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, |
241 | const char *context) | 405 | const char *context) |
@@ -254,6 +418,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) | |||
254 | gss_buffer_desc token = GSS_C_EMPTY_BUFFER; | 418 | gss_buffer_desc token = GSS_C_EMPTY_BUFFER; |
255 | OM_uint32 major, minor; | 419 | OM_uint32 major, minor; |
256 | gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; | 420 | gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; |
421 | Gssctxt *intctx = NULL; | ||
422 | |||
423 | if (ctx == NULL) | ||
424 | ctx = &intctx; | ||
257 | 425 | ||
258 | /* RFC 4462 says we MUST NOT do SPNEGO */ | 426 | /* RFC 4462 says we MUST NOT do SPNEGO */ |
259 | if (oid->length == spnego_oid.length && | 427 | if (oid->length == spnego_oid.length && |
@@ -272,7 +440,7 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) | |||
272 | GSS_C_NO_BUFFER); | 440 | GSS_C_NO_BUFFER); |
273 | } | 441 | } |
274 | 442 | ||
275 | if (GSS_ERROR(major)) | 443 | if (GSS_ERROR(major) || intctx != NULL) |
276 | ssh_gssapi_delete_ctx(ctx); | 444 | ssh_gssapi_delete_ctx(ctx); |
277 | 445 | ||
278 | return (!GSS_ERROR(major)); | 446 | return (!GSS_ERROR(major)); |
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c index 5a625acb8..b400081f6 100644 --- a/gss-serv-krb5.c +++ b/gss-serv-krb5.c | |||
@@ -120,6 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) | |||
120 | krb5_principal princ; | 120 | krb5_principal princ; |
121 | OM_uint32 maj_status, min_status; | 121 | OM_uint32 maj_status, min_status; |
122 | int len; | 122 | int len; |
123 | const char *new_ccname; | ||
123 | 124 | ||
124 | if (client->creds == NULL) { | 125 | if (client->creds == NULL) { |
125 | debug("No credentials stored"); | 126 | debug("No credentials stored"); |
@@ -168,11 +169,16 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) | |||
168 | return; | 169 | return; |
169 | } | 170 | } |
170 | 171 | ||
171 | client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); | 172 | new_ccname = krb5_cc_get_name(krb_context, ccache); |
173 | |||
172 | client->store.envvar = "KRB5CCNAME"; | 174 | client->store.envvar = "KRB5CCNAME"; |
173 | len = strlen(client->store.filename) + 6; | 175 | #ifdef USE_CCAPI |
174 | client->store.envval = xmalloc(len); | 176 | xasprintf(&client->store.envval, "API:%s", new_ccname); |
175 | snprintf(client->store.envval, len, "FILE:%s", client->store.filename); | 177 | client->store.filename = NULL; |
178 | #else | ||
179 | xasprintf(&client->store.envval, "FILE:%s", new_ccname); | ||
180 | client->store.filename = xstrdup(new_ccname); | ||
181 | #endif | ||
176 | 182 | ||
177 | #ifdef USE_PAM | 183 | #ifdef USE_PAM |
178 | if (options.use_pam) | 184 | if (options.use_pam) |
diff --git a/gss-serv.c b/gss-serv.c index bc498fd47..e157ec515 100644 --- a/gss-serv.c +++ b/gss-serv.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* $OpenBSD: gss-serv.c,v 1.21 2007/06/12 08:20:00 djm Exp $ */ | 1 | /* $OpenBSD: gss-serv.c,v 1.21 2007/06/12 08:20:00 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. | 4 | * Copyright (c) 2001-2006 Simon Wilkinson. All rights reserved. |
5 | * | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without | 6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions | 7 | * modification, are permitted provided that the following conditions |
@@ -44,8 +44,12 @@ | |||
44 | #include "channels.h" | 44 | #include "channels.h" |
45 | #include "session.h" | 45 | #include "session.h" |
46 | #include "misc.h" | 46 | #include "misc.h" |
47 | #include "servconf.h" | ||
47 | 48 | ||
48 | #include "ssh-gss.h" | 49 | #include "ssh-gss.h" |
50 | #include "monitor_wrap.h" | ||
51 | |||
52 | extern ServerOptions options; | ||
49 | 53 | ||
50 | static ssh_gssapi_client gssapi_client = | 54 | static ssh_gssapi_client gssapi_client = |
51 | { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, | 55 | { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, |
@@ -113,6 +117,28 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) | |||
113 | } | 117 | } |
114 | 118 | ||
115 | /* Unprivileged */ | 119 | /* Unprivileged */ |
120 | char * | ||
121 | ssh_gssapi_server_mechanisms() { | ||
122 | gss_OID_set supported; | ||
123 | |||
124 | ssh_gssapi_supported_oids(&supported); | ||
125 | return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech, | ||
126 | NULL)); | ||
127 | } | ||
128 | |||
129 | /* Unprivileged */ | ||
130 | int | ||
131 | ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data) { | ||
132 | Gssctxt *ctx = NULL; | ||
133 | int res; | ||
134 | |||
135 | res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid))); | ||
136 | ssh_gssapi_delete_ctx(&ctx); | ||
137 | |||
138 | return (res); | ||
139 | } | ||
140 | |||
141 | /* Unprivileged */ | ||
116 | void | 142 | void |
117 | ssh_gssapi_supported_oids(gss_OID_set *oidset) | 143 | ssh_gssapi_supported_oids(gss_OID_set *oidset) |
118 | { | 144 | { |
@@ -351,14 +377,4 @@ ssh_gssapi_userok(char *user) | |||
351 | return (0); | 377 | return (0); |
352 | } | 378 | } |
353 | 379 | ||
354 | /* Privileged */ | ||
355 | OM_uint32 | ||
356 | ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) | ||
357 | { | ||
358 | ctx->major = gss_verify_mic(&ctx->minor, ctx->context, | ||
359 | gssbuf, gssmic, NULL); | ||
360 | |||
361 | return (ctx->major); | ||
362 | } | ||
363 | |||
364 | #endif | 380 | #endif |
@@ -49,6 +49,10 @@ | |||
49 | #include "dispatch.h" | 49 | #include "dispatch.h" |
50 | #include "monitor.h" | 50 | #include "monitor.h" |
51 | 51 | ||
52 | #ifdef GSSAPI | ||
53 | #include "ssh-gss.h" | ||
54 | #endif | ||
55 | |||
52 | #define KEX_COOKIE_LEN 16 | 56 | #define KEX_COOKIE_LEN 16 |
53 | 57 | ||
54 | #if OPENSSL_VERSION_NUMBER >= 0x00907000L | 58 | #if OPENSSL_VERSION_NUMBER >= 0x00907000L |
@@ -327,6 +331,20 @@ choose_kex(Kex *k, char *client, char *server) | |||
327 | k->kex_type = KEX_DH_GEX_SHA256; | 331 | k->kex_type = KEX_DH_GEX_SHA256; |
328 | k->evp_md = evp_ssh_sha256(); | 332 | k->evp_md = evp_ssh_sha256(); |
329 | #endif | 333 | #endif |
334 | #ifdef GSSAPI | ||
335 | } else if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID, | ||
336 | sizeof(KEX_GSS_GEX_SHA1_ID) - 1) == 0) { | ||
337 | k->kex_type = KEX_GSS_GEX_SHA1; | ||
338 | k->evp_md = EVP_sha1(); | ||
339 | } else if (strncmp(k->name, KEX_GSS_GRP1_SHA1_ID, | ||
340 | sizeof(KEX_GSS_GRP1_SHA1_ID) - 1) == 0) { | ||
341 | k->kex_type = KEX_GSS_GRP1_SHA1; | ||
342 | k->evp_md = EVP_sha1(); | ||
343 | } else if (strncmp(k->name, KEX_GSS_GRP14_SHA1_ID, | ||
344 | sizeof(KEX_GSS_GRP14_SHA1_ID) - 1) == 0) { | ||
345 | k->kex_type = KEX_GSS_GRP14_SHA1; | ||
346 | k->evp_md = EVP_sha1(); | ||
347 | #endif | ||
330 | } else | 348 | } else |
331 | fatal("bad kex alg %s", k->name); | 349 | fatal("bad kex alg %s", k->name); |
332 | } | 350 | } |
@@ -64,6 +64,9 @@ enum kex_exchange { | |||
64 | KEX_DH_GRP14_SHA1, | 64 | KEX_DH_GRP14_SHA1, |
65 | KEX_DH_GEX_SHA1, | 65 | KEX_DH_GEX_SHA1, |
66 | KEX_DH_GEX_SHA256, | 66 | KEX_DH_GEX_SHA256, |
67 | KEX_GSS_GRP1_SHA1, | ||
68 | KEX_GSS_GRP14_SHA1, | ||
69 | KEX_GSS_GEX_SHA1, | ||
67 | KEX_MAX | 70 | KEX_MAX |
68 | }; | 71 | }; |
69 | 72 | ||
@@ -119,6 +122,11 @@ struct Kex { | |||
119 | sig_atomic_t done; | 122 | sig_atomic_t done; |
120 | int flags; | 123 | int flags; |
121 | const EVP_MD *evp_md; | 124 | const EVP_MD *evp_md; |
125 | #ifdef GSSAPI | ||
126 | int gss_deleg_creds; | ||
127 | int gss_trust_dns; | ||
128 | char *gss_host; | ||
129 | #endif | ||
122 | char *client_version_string; | 130 | char *client_version_string; |
123 | char *server_version_string; | 131 | char *server_version_string; |
124 | int (*verify_host_key)(Key *); | 132 | int (*verify_host_key)(Key *); |
@@ -141,6 +149,11 @@ void kexdh_server(Kex *); | |||
141 | void kexgex_client(Kex *); | 149 | void kexgex_client(Kex *); |
142 | void kexgex_server(Kex *); | 150 | void kexgex_server(Kex *); |
143 | 151 | ||
152 | #ifdef GSSAPI | ||
153 | void kexgss_client(Kex *); | ||
154 | void kexgss_server(Kex *); | ||
155 | #endif | ||
156 | |||
144 | void | 157 | void |
145 | kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, | 158 | kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, |
146 | BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); | 159 | BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); |
diff --git a/kexgssc.c b/kexgssc.c new file mode 100644 index 000000000..7c4a56f45 --- /dev/null +++ b/kexgssc.c | |||
@@ -0,0 +1,319 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2001-2006 Simon Wilkinson. All rights reserved. | ||
3 | * | ||
4 | * Redistribution and use in source and binary forms, with or without | ||
5 | * modification, are permitted provided that the following conditions | ||
6 | * are met: | ||
7 | * 1. Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * 2. Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * | ||
13 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR | ||
14 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
15 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
16 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
17 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
18 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
19 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
20 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
23 | */ | ||
24 | |||
25 | #include "includes.h" | ||
26 | |||
27 | #ifdef GSSAPI | ||
28 | |||
29 | #include "includes.h" | ||
30 | |||
31 | #include <openssl/crypto.h> | ||
32 | #include <openssl/bn.h> | ||
33 | |||
34 | #include <string.h> | ||
35 | |||
36 | #include "xmalloc.h" | ||
37 | #include "buffer.h" | ||
38 | #include "ssh2.h" | ||
39 | #include "key.h" | ||
40 | #include "cipher.h" | ||
41 | #include "kex.h" | ||
42 | #include "log.h" | ||
43 | #include "packet.h" | ||
44 | #include "dh.h" | ||
45 | |||
46 | #include "ssh-gss.h" | ||
47 | |||
48 | void | ||
49 | kexgss_client(Kex *kex) { | ||
50 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
51 | gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr; | ||
52 | Gssctxt *ctxt; | ||
53 | OM_uint32 maj_status, min_status, ret_flags; | ||
54 | u_int klen, kout, slen = 0, hashlen, strlen; | ||
55 | DH *dh; | ||
56 | BIGNUM *dh_server_pub = NULL; | ||
57 | BIGNUM *shared_secret = NULL; | ||
58 | BIGNUM *p = NULL; | ||
59 | BIGNUM *g = NULL; | ||
60 | u_char *kbuf, *hash; | ||
61 | u_char *serverhostkey = NULL; | ||
62 | char *msg; | ||
63 | char *lang; | ||
64 | int type = 0; | ||
65 | int first = 1; | ||
66 | int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX; | ||
67 | |||
68 | /* Initialise our GSSAPI world */ | ||
69 | ssh_gssapi_build_ctx(&ctxt); | ||
70 | if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) | ||
71 | == GSS_C_NO_OID) | ||
72 | fatal("Couldn't identify host exchange"); | ||
73 | |||
74 | if (ssh_gssapi_import_name(ctxt, kex->gss_host)) | ||
75 | fatal("Couldn't import hostname"); | ||
76 | |||
77 | switch (kex->kex_type) { | ||
78 | case KEX_GSS_GRP1_SHA1: | ||
79 | dh = dh_new_group1(); | ||
80 | break; | ||
81 | case KEX_GSS_GRP14_SHA1: | ||
82 | dh = dh_new_group14(); | ||
83 | break; | ||
84 | case KEX_GSS_GEX_SHA1: | ||
85 | debug("Doing group exchange\n"); | ||
86 | nbits = dh_estimate(kex->we_need * 8); | ||
87 | packet_start(SSH2_MSG_KEXGSS_GROUPREQ); | ||
88 | packet_put_int(min); | ||
89 | packet_put_int(nbits); | ||
90 | packet_put_int(max); | ||
91 | |||
92 | packet_send(); | ||
93 | |||
94 | packet_read_expect(SSH2_MSG_KEXGSS_GROUP); | ||
95 | |||
96 | if ((p = BN_new()) == NULL) | ||
97 | fatal("BN_new() failed"); | ||
98 | packet_get_bignum2(p); | ||
99 | if ((g = BN_new()) == NULL) | ||
100 | fatal("BN_new() failed"); | ||
101 | packet_get_bignum2(g); | ||
102 | packet_check_eom(); | ||
103 | |||
104 | if (BN_num_bits(p) < min || BN_num_bits(p) > max) | ||
105 | fatal("GSSGRP_GEX group out of range: %d !< %d !< %d", | ||
106 | min, BN_num_bits(p), max); | ||
107 | |||
108 | dh = dh_new_group(g, p); | ||
109 | break; | ||
110 | default: | ||
111 | fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); | ||
112 | } | ||
113 | |||
114 | /* Step 1 - e is dh->pub_key */ | ||
115 | dh_gen_key(dh, kex->we_need * 8); | ||
116 | |||
117 | /* This is f, we initialise it now to make life easier */ | ||
118 | dh_server_pub = BN_new(); | ||
119 | if (dh_server_pub == NULL) | ||
120 | fatal("dh_server_pub == NULL"); | ||
121 | |||
122 | token_ptr = GSS_C_NO_BUFFER; | ||
123 | |||
124 | do { | ||
125 | debug("Calling gss_init_sec_context"); | ||
126 | |||
127 | maj_status = ssh_gssapi_init_ctx(ctxt, | ||
128 | kex->gss_deleg_creds, token_ptr, &send_tok, | ||
129 | &ret_flags); | ||
130 | |||
131 | if (GSS_ERROR(maj_status)) { | ||
132 | if (send_tok.length != 0) { | ||
133 | packet_start(SSH2_MSG_KEXGSS_CONTINUE); | ||
134 | packet_put_string(send_tok.value, | ||
135 | send_tok.length); | ||
136 | } | ||
137 | fatal("gss_init_context failed"); | ||
138 | } | ||
139 | |||
140 | /* If we've got an old receive buffer get rid of it */ | ||
141 | if (token_ptr != GSS_C_NO_BUFFER) | ||
142 | xfree(recv_tok.value); | ||
143 | |||
144 | if (maj_status == GSS_S_COMPLETE) { | ||
145 | /* If mutual state flag is not true, kex fails */ | ||
146 | if (!(ret_flags & GSS_C_MUTUAL_FLAG)) | ||
147 | fatal("Mutual authentication failed"); | ||
148 | |||
149 | /* If integ avail flag is not true kex fails */ | ||
150 | if (!(ret_flags & GSS_C_INTEG_FLAG)) | ||
151 | fatal("Integrity check failed"); | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * If we have data to send, then the last message that we | ||
156 | * received cannot have been a 'complete'. | ||
157 | */ | ||
158 | if (send_tok.length != 0) { | ||
159 | if (first) { | ||
160 | packet_start(SSH2_MSG_KEXGSS_INIT); | ||
161 | packet_put_string(send_tok.value, | ||
162 | send_tok.length); | ||
163 | packet_put_bignum2(dh->pub_key); | ||
164 | first = 0; | ||
165 | } else { | ||
166 | packet_start(SSH2_MSG_KEXGSS_CONTINUE); | ||
167 | packet_put_string(send_tok.value, | ||
168 | send_tok.length); | ||
169 | } | ||
170 | packet_send(); | ||
171 | gss_release_buffer(&min_status, &send_tok); | ||
172 | |||
173 | /* If we've sent them data, they should reply */ | ||
174 | do { | ||
175 | type = packet_read(); | ||
176 | if (type == SSH2_MSG_KEXGSS_HOSTKEY) { | ||
177 | debug("Received KEXGSS_HOSTKEY"); | ||
178 | if (serverhostkey) | ||
179 | fatal("Server host key received more than once"); | ||
180 | serverhostkey = | ||
181 | packet_get_string(&slen); | ||
182 | } | ||
183 | } while (type == SSH2_MSG_KEXGSS_HOSTKEY); | ||
184 | |||
185 | switch (type) { | ||
186 | case SSH2_MSG_KEXGSS_CONTINUE: | ||
187 | debug("Received GSSAPI_CONTINUE"); | ||
188 | if (maj_status == GSS_S_COMPLETE) | ||
189 | fatal("GSSAPI Continue received from server when complete"); | ||
190 | recv_tok.value = packet_get_string(&strlen); | ||
191 | recv_tok.length = strlen; | ||
192 | break; | ||
193 | case SSH2_MSG_KEXGSS_COMPLETE: | ||
194 | debug("Received GSSAPI_COMPLETE"); | ||
195 | packet_get_bignum2(dh_server_pub); | ||
196 | msg_tok.value = packet_get_string(&strlen); | ||
197 | msg_tok.length = strlen; | ||
198 | |||
199 | /* Is there a token included? */ | ||
200 | if (packet_get_char()) { | ||
201 | recv_tok.value= | ||
202 | packet_get_string(&strlen); | ||
203 | recv_tok.length = strlen; | ||
204 | /* If we're already complete - protocol error */ | ||
205 | if (maj_status == GSS_S_COMPLETE) | ||
206 | packet_disconnect("Protocol error: received token when complete"); | ||
207 | } else { | ||
208 | /* No token included */ | ||
209 | if (maj_status != GSS_S_COMPLETE) | ||
210 | packet_disconnect("Protocol error: did not receive final token"); | ||
211 | } | ||
212 | break; | ||
213 | case SSH2_MSG_KEXGSS_ERROR: | ||
214 | debug("Received Error"); | ||
215 | maj_status = packet_get_int(); | ||
216 | min_status = packet_get_int(); | ||
217 | msg = packet_get_string(NULL); | ||
218 | lang = packet_get_string(NULL); | ||
219 | fatal("GSSAPI Error: \n%.400s",msg); | ||
220 | default: | ||
221 | packet_disconnect("Protocol error: didn't expect packet type %d", | ||
222 | type); | ||
223 | } | ||
224 | token_ptr = &recv_tok; | ||
225 | } else { | ||
226 | /* No data, and not complete */ | ||
227 | if (maj_status != GSS_S_COMPLETE) | ||
228 | fatal("Not complete, and no token output"); | ||
229 | } | ||
230 | } while (maj_status & GSS_S_CONTINUE_NEEDED); | ||
231 | |||
232 | /* | ||
233 | * We _must_ have received a COMPLETE message in reply from the | ||
234 | * server, which will have set dh_server_pub and msg_tok | ||
235 | */ | ||
236 | |||
237 | if (type != SSH2_MSG_KEXGSS_COMPLETE) | ||
238 | fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); | ||
239 | |||
240 | /* Check f in range [1, p-1] */ | ||
241 | if (!dh_pub_is_valid(dh, dh_server_pub)) | ||
242 | packet_disconnect("bad server public DH value"); | ||
243 | |||
244 | /* compute K=f^x mod p */ | ||
245 | klen = DH_size(dh); | ||
246 | kbuf = xmalloc(klen); | ||
247 | kout = DH_compute_key(kbuf, dh_server_pub, dh); | ||
248 | |||
249 | shared_secret = BN_new(); | ||
250 | BN_bin2bn(kbuf,kout, shared_secret); | ||
251 | memset(kbuf, 0, klen); | ||
252 | xfree(kbuf); | ||
253 | |||
254 | switch (kex->kex_type) { | ||
255 | case KEX_GSS_GRP1_SHA1: | ||
256 | case KEX_GSS_GRP14_SHA1: | ||
257 | kex_dh_hash( kex->client_version_string, | ||
258 | kex->server_version_string, | ||
259 | buffer_ptr(&kex->my), buffer_len(&kex->my), | ||
260 | buffer_ptr(&kex->peer), buffer_len(&kex->peer), | ||
261 | serverhostkey, slen, /* server host key */ | ||
262 | dh->pub_key, /* e */ | ||
263 | dh_server_pub, /* f */ | ||
264 | shared_secret, /* K */ | ||
265 | &hash, &hashlen | ||
266 | ); | ||
267 | break; | ||
268 | case KEX_GSS_GEX_SHA1: | ||
269 | kexgex_hash( | ||
270 | kex->evp_md, | ||
271 | kex->client_version_string, | ||
272 | kex->server_version_string, | ||
273 | buffer_ptr(&kex->my), buffer_len(&kex->my), | ||
274 | buffer_ptr(&kex->peer), buffer_len(&kex->peer), | ||
275 | serverhostkey, slen, | ||
276 | min, nbits, max, | ||
277 | dh->p, dh->g, | ||
278 | dh->pub_key, | ||
279 | dh_server_pub, | ||
280 | shared_secret, | ||
281 | &hash, &hashlen | ||
282 | ); | ||
283 | break; | ||
284 | default: | ||
285 | fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); | ||
286 | } | ||
287 | |||
288 | gssbuf.value = hash; | ||
289 | gssbuf.length = hashlen; | ||
290 | |||
291 | /* Verify that the hash matches the MIC we just got. */ | ||
292 | if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) | ||
293 | packet_disconnect("Hash's MIC didn't verify"); | ||
294 | |||
295 | xfree(msg_tok.value); | ||
296 | |||
297 | DH_free(dh); | ||
298 | if (serverhostkey) | ||
299 | xfree(serverhostkey); | ||
300 | BN_clear_free(dh_server_pub); | ||
301 | |||
302 | /* save session id */ | ||
303 | if (kex->session_id == NULL) { | ||
304 | kex->session_id_len = hashlen; | ||
305 | kex->session_id = xmalloc(kex->session_id_len); | ||
306 | memcpy(kex->session_id, hash, kex->session_id_len); | ||
307 | } | ||
308 | |||
309 | if (gss_kex_context == NULL) | ||
310 | gss_kex_context = ctxt; | ||
311 | else | ||
312 | ssh_gssapi_delete_ctx(&ctxt); | ||
313 | |||
314 | kex_derive_keys(kex, hash, hashlen, shared_secret); | ||
315 | BN_clear_free(shared_secret); | ||
316 | kex_finish(kex); | ||
317 | } | ||
318 | |||
319 | #endif /* GSSAPI */ | ||
diff --git a/kexgsss.c b/kexgsss.c new file mode 100644 index 000000000..3ca23bbb2 --- /dev/null +++ b/kexgsss.c | |||
@@ -0,0 +1,271 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2001-2006 Simon Wilkinson. All rights reserved. | ||
3 | * | ||
4 | * Redistribution and use in source and binary forms, with or without | ||
5 | * modification, are permitted provided that the following conditions | ||
6 | * are met: | ||
7 | * 1. Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * 2. Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * | ||
13 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR | ||
14 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
15 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
16 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
17 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
18 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
19 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
20 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
23 | */ | ||
24 | |||
25 | #include "includes.h" | ||
26 | |||
27 | #ifdef GSSAPI | ||
28 | |||
29 | #include <string.h> | ||
30 | |||
31 | #include <openssl/crypto.h> | ||
32 | #include <openssl/bn.h> | ||
33 | |||
34 | #include "xmalloc.h" | ||
35 | #include "buffer.h" | ||
36 | #include "ssh2.h" | ||
37 | #include "key.h" | ||
38 | #include "cipher.h" | ||
39 | #include "kex.h" | ||
40 | #include "log.h" | ||
41 | #include "packet.h" | ||
42 | #include "dh.h" | ||
43 | #include "ssh-gss.h" | ||
44 | #include "monitor_wrap.h" | ||
45 | |||
46 | void | ||
47 | kexgss_server(Kex *kex) | ||
48 | { | ||
49 | OM_uint32 maj_status, min_status; | ||
50 | |||
51 | /* | ||
52 | * Some GSSAPI implementations use the input value of ret_flags (an | ||
53 | * output variable) as a means of triggering mechanism specific | ||
54 | * features. Initializing it to zero avoids inadvertently | ||
55 | * activating this non-standard behaviour. | ||
56 | */ | ||
57 | |||
58 | OM_uint32 ret_flags = 0; | ||
59 | gss_buffer_desc gssbuf, recv_tok, msg_tok; | ||
60 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
61 | Gssctxt *ctxt = NULL; | ||
62 | u_int slen, klen, kout, hashlen; | ||
63 | u_char *kbuf, *hash; | ||
64 | DH *dh; | ||
65 | int min = -1, max = -1, nbits = -1; | ||
66 | BIGNUM *shared_secret = NULL; | ||
67 | BIGNUM *dh_client_pub = NULL; | ||
68 | int type = 0; | ||
69 | gss_OID oid; | ||
70 | |||
71 | /* Initialise GSSAPI */ | ||
72 | |||
73 | /* If we're rekeying, privsep means that some of the private structures | ||
74 | * in the GSSAPI code are no longer available. This kludges them back | ||
75 | * into life | ||
76 | */ | ||
77 | if (!ssh_gssapi_oid_table_ok()) | ||
78 | ssh_gssapi_server_mechanisms(); | ||
79 | |||
80 | debug2("%s: Identifying %s", __func__, kex->name); | ||
81 | oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); | ||
82 | if (oid == GSS_C_NO_OID) | ||
83 | fatal("Unknown gssapi mechanism"); | ||
84 | |||
85 | debug2("%s: Acquiring credentials", __func__); | ||
86 | |||
87 | if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) | ||
88 | fatal("Unable to acquire credentials for the server"); | ||
89 | |||
90 | switch (kex->kex_type) { | ||
91 | case KEX_GSS_GRP1_SHA1: | ||
92 | dh = dh_new_group1(); | ||
93 | break; | ||
94 | case KEX_GSS_GRP14_SHA1: | ||
95 | dh = dh_new_group14(); | ||
96 | break; | ||
97 | case KEX_GSS_GEX_SHA1: | ||
98 | debug("Doing group exchange"); | ||
99 | packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ); | ||
100 | min = packet_get_int(); | ||
101 | nbits = packet_get_int(); | ||
102 | max = packet_get_int(); | ||
103 | min = MAX(DH_GRP_MIN, min); | ||
104 | max = MIN(DH_GRP_MAX, max); | ||
105 | packet_check_eom(); | ||
106 | if (max < min || nbits < min || max < nbits) | ||
107 | fatal("GSS_GEX, bad parameters: %d !< %d !< %d", | ||
108 | min, nbits, max); | ||
109 | dh = PRIVSEP(choose_dh(min, nbits, max)); | ||
110 | if (dh == NULL) | ||
111 | packet_disconnect("Protocol error: no matching group found"); | ||
112 | |||
113 | packet_start(SSH2_MSG_KEXGSS_GROUP); | ||
114 | packet_put_bignum2(dh->p); | ||
115 | packet_put_bignum2(dh->g); | ||
116 | packet_send(); | ||
117 | |||
118 | packet_write_wait(); | ||
119 | break; | ||
120 | default: | ||
121 | fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); | ||
122 | } | ||
123 | |||
124 | dh_gen_key(dh, kex->we_need * 8); | ||
125 | |||
126 | do { | ||
127 | debug("Wait SSH2_MSG_GSSAPI_INIT"); | ||
128 | type = packet_read(); | ||
129 | switch(type) { | ||
130 | case SSH2_MSG_KEXGSS_INIT: | ||
131 | if (dh_client_pub != NULL) | ||
132 | fatal("Received KEXGSS_INIT after initialising"); | ||
133 | recv_tok.value = packet_get_string(&slen); | ||
134 | recv_tok.length = slen; | ||
135 | |||
136 | if ((dh_client_pub = BN_new()) == NULL) | ||
137 | fatal("dh_client_pub == NULL"); | ||
138 | |||
139 | packet_get_bignum2(dh_client_pub); | ||
140 | |||
141 | /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ | ||
142 | break; | ||
143 | case SSH2_MSG_KEXGSS_CONTINUE: | ||
144 | recv_tok.value = packet_get_string(&slen); | ||
145 | recv_tok.length = slen; | ||
146 | break; | ||
147 | default: | ||
148 | packet_disconnect( | ||
149 | "Protocol error: didn't expect packet type %d", | ||
150 | type); | ||
151 | } | ||
152 | |||
153 | maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, | ||
154 | &send_tok, &ret_flags)); | ||
155 | |||
156 | xfree(recv_tok.value); | ||
157 | |||
158 | if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) | ||
159 | fatal("Zero length token output when incomplete"); | ||
160 | |||
161 | if (dh_client_pub == NULL) | ||
162 | fatal("No client public key"); | ||
163 | |||
164 | if (maj_status & GSS_S_CONTINUE_NEEDED) { | ||
165 | debug("Sending GSSAPI_CONTINUE"); | ||
166 | packet_start(SSH2_MSG_KEXGSS_CONTINUE); | ||
167 | packet_put_string(send_tok.value, send_tok.length); | ||
168 | packet_send(); | ||
169 | gss_release_buffer(&min_status, &send_tok); | ||
170 | } | ||
171 | } while (maj_status & GSS_S_CONTINUE_NEEDED); | ||
172 | |||
173 | if (GSS_ERROR(maj_status)) { | ||
174 | if (send_tok.length > 0) { | ||
175 | packet_start(SSH2_MSG_KEXGSS_CONTINUE); | ||
176 | packet_put_string(send_tok.value, send_tok.length); | ||
177 | packet_send(); | ||
178 | } | ||
179 | fatal("accept_ctx died"); | ||
180 | } | ||
181 | |||
182 | if (!(ret_flags & GSS_C_MUTUAL_FLAG)) | ||
183 | fatal("Mutual Authentication flag wasn't set"); | ||
184 | |||
185 | if (!(ret_flags & GSS_C_INTEG_FLAG)) | ||
186 | fatal("Integrity flag wasn't set"); | ||
187 | |||
188 | if (!dh_pub_is_valid(dh, dh_client_pub)) | ||
189 | packet_disconnect("bad client public DH value"); | ||
190 | |||
191 | klen = DH_size(dh); | ||
192 | kbuf = xmalloc(klen); | ||
193 | kout = DH_compute_key(kbuf, dh_client_pub, dh); | ||
194 | |||
195 | shared_secret = BN_new(); | ||
196 | BN_bin2bn(kbuf, kout, shared_secret); | ||
197 | memset(kbuf, 0, klen); | ||
198 | xfree(kbuf); | ||
199 | |||
200 | switch (kex->kex_type) { | ||
201 | case KEX_GSS_GRP1_SHA1: | ||
202 | case KEX_GSS_GRP14_SHA1: | ||
203 | kex_dh_hash( | ||
204 | kex->client_version_string, kex->server_version_string, | ||
205 | buffer_ptr(&kex->peer), buffer_len(&kex->peer), | ||
206 | buffer_ptr(&kex->my), buffer_len(&kex->my), | ||
207 | NULL, 0, /* Change this if we start sending host keys */ | ||
208 | dh_client_pub, dh->pub_key, shared_secret, | ||
209 | &hash, &hashlen | ||
210 | ); | ||
211 | break; | ||
212 | case KEX_GSS_GEX_SHA1: | ||
213 | kexgex_hash( | ||
214 | kex->evp_md, | ||
215 | kex->client_version_string, kex->server_version_string, | ||
216 | buffer_ptr(&kex->peer), buffer_len(&kex->peer), | ||
217 | buffer_ptr(&kex->my), buffer_len(&kex->my), | ||
218 | NULL, 0, | ||
219 | min, nbits, max, | ||
220 | dh->p, dh->g, | ||
221 | dh_client_pub, | ||
222 | dh->pub_key, | ||
223 | shared_secret, | ||
224 | &hash, &hashlen | ||
225 | ); | ||
226 | break; | ||
227 | default: | ||
228 | fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); | ||
229 | } | ||
230 | |||
231 | BN_free(dh_client_pub); | ||
232 | |||
233 | if (kex->session_id == NULL) { | ||
234 | kex->session_id_len = hashlen; | ||
235 | kex->session_id = xmalloc(kex->session_id_len); | ||
236 | memcpy(kex->session_id, hash, kex->session_id_len); | ||
237 | } | ||
238 | |||
239 | gssbuf.value = hash; | ||
240 | gssbuf.length = hashlen; | ||
241 | |||
242 | if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) | ||
243 | fatal("Couldn't get MIC"); | ||
244 | |||
245 | packet_start(SSH2_MSG_KEXGSS_COMPLETE); | ||
246 | packet_put_bignum2(dh->pub_key); | ||
247 | packet_put_string(msg_tok.value,msg_tok.length); | ||
248 | |||
249 | if (send_tok.length != 0) { | ||
250 | packet_put_char(1); /* true */ | ||
251 | packet_put_string(send_tok.value, send_tok.length); | ||
252 | } else { | ||
253 | packet_put_char(0); /* false */ | ||
254 | } | ||
255 | packet_send(); | ||
256 | |||
257 | gss_release_buffer(&min_status, &send_tok); | ||
258 | gss_release_buffer(&min_status, &msg_tok); | ||
259 | |||
260 | if (gss_kex_context == NULL) | ||
261 | gss_kex_context = ctxt; | ||
262 | else | ||
263 | ssh_gssapi_delete_ctx(&ctxt); | ||
264 | |||
265 | DH_free(dh); | ||
266 | |||
267 | kex_derive_keys(kex, hash, hashlen, shared_secret); | ||
268 | BN_clear_free(shared_secret); | ||
269 | kex_finish(kex); | ||
270 | } | ||
271 | #endif /* GSSAPI */ | ||
@@ -648,6 +648,8 @@ key_type_from_name(char *name) | |||
648 | return KEY_RSA; | 648 | return KEY_RSA; |
649 | } else if (strcmp(name, "ssh-dss") == 0) { | 649 | } else if (strcmp(name, "ssh-dss") == 0) { |
650 | return KEY_DSA; | 650 | return KEY_DSA; |
651 | } else if (strcmp(name, "null") == 0) { | ||
652 | return KEY_NULL; | ||
651 | } | 653 | } |
652 | debug2("key_type_from_name: unknown key type '%s'", name); | 654 | debug2("key_type_from_name: unknown key type '%s'", name); |
653 | return KEY_UNSPEC; | 655 | return KEY_UNSPEC; |
@@ -34,6 +34,7 @@ enum types { | |||
34 | KEY_RSA1, | 34 | KEY_RSA1, |
35 | KEY_RSA, | 35 | KEY_RSA, |
36 | KEY_DSA, | 36 | KEY_DSA, |
37 | KEY_NULL, | ||
37 | KEY_UNSPEC | 38 | KEY_UNSPEC |
38 | }; | 39 | }; |
39 | enum fp_type { | 40 | enum fp_type { |
@@ -163,6 +163,7 @@ int mm_answer_gss_setup_ctx(int, Buffer *); | |||
163 | int mm_answer_gss_accept_ctx(int, Buffer *); | 163 | int mm_answer_gss_accept_ctx(int, Buffer *); |
164 | int mm_answer_gss_userok(int, Buffer *); | 164 | int mm_answer_gss_userok(int, Buffer *); |
165 | int mm_answer_gss_checkmic(int, Buffer *); | 165 | int mm_answer_gss_checkmic(int, Buffer *); |
166 | int mm_answer_gss_sign(int, Buffer *); | ||
166 | #endif | 167 | #endif |
167 | 168 | ||
168 | #ifdef SSH_AUDIT_EVENTS | 169 | #ifdef SSH_AUDIT_EVENTS |
@@ -232,11 +233,17 @@ struct mon_table mon_dispatch_proto20[] = { | |||
232 | {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, | 233 | {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, |
233 | {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, | 234 | {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, |
234 | {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, | 235 | {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, |
236 | {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign}, | ||
235 | #endif | 237 | #endif |
236 | {0, 0, NULL} | 238 | {0, 0, NULL} |
237 | }; | 239 | }; |
238 | 240 | ||
239 | struct mon_table mon_dispatch_postauth20[] = { | 241 | struct mon_table mon_dispatch_postauth20[] = { |
242 | #ifdef GSSAPI | ||
243 | {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx}, | ||
244 | {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, | ||
245 | {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, | ||
246 | #endif | ||
240 | {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, | 247 | {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, |
241 | {MONITOR_REQ_SIGN, 0, mm_answer_sign}, | 248 | {MONITOR_REQ_SIGN, 0, mm_answer_sign}, |
242 | {MONITOR_REQ_PTY, 0, mm_answer_pty}, | 249 | {MONITOR_REQ_PTY, 0, mm_answer_pty}, |
@@ -341,6 +348,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) | |||
341 | /* Permit requests for moduli and signatures */ | 348 | /* Permit requests for moduli and signatures */ |
342 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); | 349 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); |
343 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); | 350 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); |
351 | #ifdef GSSAPI | ||
352 | /* and for the GSSAPI key exchange */ | ||
353 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); | ||
354 | #endif | ||
344 | } else { | 355 | } else { |
345 | mon_dispatch = mon_dispatch_proto15; | 356 | mon_dispatch = mon_dispatch_proto15; |
346 | 357 | ||
@@ -418,6 +429,10 @@ monitor_child_postauth(struct monitor *pmonitor) | |||
418 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); | 429 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); |
419 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); | 430 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); |
420 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); | 431 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); |
432 | #ifdef GSSAPI | ||
433 | /* and for the GSSAPI key exchange */ | ||
434 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); | ||
435 | #endif | ||
421 | } else { | 436 | } else { |
422 | mon_dispatch = mon_dispatch_postauth15; | 437 | mon_dispatch = mon_dispatch_postauth15; |
423 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); | 438 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); |
@@ -1664,6 +1679,11 @@ mm_get_kex(Buffer *m) | |||
1664 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; | 1679 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; |
1665 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; | 1680 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; |
1666 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; | 1681 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; |
1682 | #ifdef GSSAPI | ||
1683 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; | ||
1684 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; | ||
1685 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; | ||
1686 | #endif | ||
1667 | kex->server = 1; | 1687 | kex->server = 1; |
1668 | kex->hostkey_type = buffer_get_int(m); | 1688 | kex->hostkey_type = buffer_get_int(m); |
1669 | kex->kex_type = buffer_get_int(m); | 1689 | kex->kex_type = buffer_get_int(m); |
@@ -1905,6 +1925,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m) | |||
1905 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); | 1925 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); |
1906 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); | 1926 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); |
1907 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); | 1927 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); |
1928 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1); | ||
1908 | } | 1929 | } |
1909 | return (0); | 1930 | return (0); |
1910 | } | 1931 | } |
@@ -1955,4 +1976,42 @@ mm_answer_gss_userok(int sock, Buffer *m) | |||
1955 | /* Monitor loop will terminate if authenticated */ | 1976 | /* Monitor loop will terminate if authenticated */ |
1956 | return (authenticated); | 1977 | return (authenticated); |
1957 | } | 1978 | } |
1979 | |||
1980 | int | ||
1981 | mm_answer_gss_sign(int socket, Buffer *m) | ||
1982 | { | ||
1983 | gss_buffer_desc data; | ||
1984 | gss_buffer_desc hash = GSS_C_EMPTY_BUFFER; | ||
1985 | OM_uint32 major, minor; | ||
1986 | u_int len; | ||
1987 | |||
1988 | data.value = buffer_get_string(m, &len); | ||
1989 | data.length = len; | ||
1990 | if (data.length != 20) | ||
1991 | fatal("%s: data length incorrect: %d", __func__, data.length); | ||
1992 | |||
1993 | /* Save the session ID on the first time around */ | ||
1994 | if (session_id2_len == 0) { | ||
1995 | session_id2_len = data.length; | ||
1996 | session_id2 = xmalloc(session_id2_len); | ||
1997 | memcpy(session_id2, data.value, session_id2_len); | ||
1998 | } | ||
1999 | major = ssh_gssapi_sign(gsscontext, &data, &hash); | ||
2000 | |||
2001 | xfree(data.value); | ||
2002 | |||
2003 | buffer_clear(m); | ||
2004 | buffer_put_int(m, major); | ||
2005 | buffer_put_string(m, hash.value, hash.length); | ||
2006 | |||
2007 | mm_request_send(socket, MONITOR_ANS_GSSSIGN, m); | ||
2008 | |||
2009 | gss_release_buffer(&minor, &hash); | ||
2010 | |||
2011 | /* Turn on getpwnam permissions */ | ||
2012 | monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); | ||
2013 | |||
2014 | return (0); | ||
2015 | } | ||
2016 | |||
1958 | #endif /* GSSAPI */ | 2017 | #endif /* GSSAPI */ |
@@ -53,6 +53,7 @@ enum monitor_reqtype { | |||
53 | MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP, | 53 | MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP, |
54 | MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK, | 54 | MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK, |
55 | MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC, | 55 | MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC, |
56 | MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN, | ||
56 | MONITOR_REQ_PAM_START, | 57 | MONITOR_REQ_PAM_START, |
57 | MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, | 58 | MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, |
58 | MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, | 59 | MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, |
diff --git a/monitor_wrap.c b/monitor_wrap.c index edf2814e5..eff912562 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c | |||
@@ -1236,4 +1236,27 @@ mm_ssh_gssapi_userok(char *user) | |||
1236 | debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); | 1236 | debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); |
1237 | return (authenticated); | 1237 | return (authenticated); |
1238 | } | 1238 | } |
1239 | |||
1240 | OM_uint32 | ||
1241 | mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) | ||
1242 | { | ||
1243 | Buffer m; | ||
1244 | OM_uint32 major; | ||
1245 | u_int len; | ||
1246 | |||
1247 | buffer_init(&m); | ||
1248 | buffer_put_string(&m, data->value, data->length); | ||
1249 | |||
1250 | mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m); | ||
1251 | mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m); | ||
1252 | |||
1253 | major = buffer_get_int(&m); | ||
1254 | hash->value = buffer_get_string(&m, &len); | ||
1255 | hash->length = len; | ||
1256 | |||
1257 | buffer_free(&m); | ||
1258 | |||
1259 | return(major); | ||
1260 | } | ||
1261 | |||
1239 | #endif /* GSSAPI */ | 1262 | #endif /* GSSAPI */ |
diff --git a/monitor_wrap.h b/monitor_wrap.h index 329189c2a..2a7bf7c87 100644 --- a/monitor_wrap.h +++ b/monitor_wrap.h | |||
@@ -59,6 +59,7 @@ OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, | |||
59 | gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); | 59 | gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); |
60 | int mm_ssh_gssapi_userok(char *user); | 60 | int mm_ssh_gssapi_userok(char *user); |
61 | OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); | 61 | OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); |
62 | OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); | ||
62 | #endif | 63 | #endif |
63 | 64 | ||
64 | #ifdef USE_PAM | 65 | #ifdef USE_PAM |
diff --git a/readconf.c b/readconf.c index d57d4551d..3f82345f6 100644 --- a/readconf.c +++ b/readconf.c | |||
@@ -127,6 +127,8 @@ typedef enum { | |||
127 | oClearAllForwardings, oNoHostAuthenticationForLocalhost, | 127 | oClearAllForwardings, oNoHostAuthenticationForLocalhost, |
128 | oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, | 128 | oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, |
129 | oAddressFamily, oGssAuthentication, oGssDelegateCreds, | 129 | oAddressFamily, oGssAuthentication, oGssDelegateCreds, |
130 | oGssKeyEx, | ||
131 | oGssTrustDns, | ||
130 | oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, | 132 | oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, |
131 | oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, | 133 | oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, |
132 | oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, | 134 | oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, |
@@ -163,10 +165,14 @@ static struct { | |||
163 | { "afstokenpassing", oUnsupported }, | 165 | { "afstokenpassing", oUnsupported }, |
164 | #if defined(GSSAPI) | 166 | #if defined(GSSAPI) |
165 | { "gssapiauthentication", oGssAuthentication }, | 167 | { "gssapiauthentication", oGssAuthentication }, |
168 | { "gssapikeyexchange", oGssKeyEx }, | ||
166 | { "gssapidelegatecredentials", oGssDelegateCreds }, | 169 | { "gssapidelegatecredentials", oGssDelegateCreds }, |
170 | { "gssapitrustdns", oGssTrustDns }, | ||
167 | #else | 171 | #else |
168 | { "gssapiauthentication", oUnsupported }, | 172 | { "gssapiauthentication", oUnsupported }, |
173 | { "gssapikeyexchange", oUnsupported }, | ||
169 | { "gssapidelegatecredentials", oUnsupported }, | 174 | { "gssapidelegatecredentials", oUnsupported }, |
175 | { "gssapitrustdns", oUnsupported }, | ||
170 | #endif | 176 | #endif |
171 | { "fallbacktorsh", oDeprecated }, | 177 | { "fallbacktorsh", oDeprecated }, |
172 | { "usersh", oDeprecated }, | 178 | { "usersh", oDeprecated }, |
@@ -441,10 +447,18 @@ parse_flag: | |||
441 | intptr = &options->gss_authentication; | 447 | intptr = &options->gss_authentication; |
442 | goto parse_flag; | 448 | goto parse_flag; |
443 | 449 | ||
450 | case oGssKeyEx: | ||
451 | intptr = &options->gss_keyex; | ||
452 | goto parse_flag; | ||
453 | |||
444 | case oGssDelegateCreds: | 454 | case oGssDelegateCreds: |
445 | intptr = &options->gss_deleg_creds; | 455 | intptr = &options->gss_deleg_creds; |
446 | goto parse_flag; | 456 | goto parse_flag; |
447 | 457 | ||
458 | case oGssTrustDns: | ||
459 | intptr = &options->gss_trust_dns; | ||
460 | goto parse_flag; | ||
461 | |||
448 | case oBatchMode: | 462 | case oBatchMode: |
449 | intptr = &options->batch_mode; | 463 | intptr = &options->batch_mode; |
450 | goto parse_flag; | 464 | goto parse_flag; |
@@ -1010,7 +1024,9 @@ initialize_options(Options * options) | |||
1010 | options->pubkey_authentication = -1; | 1024 | options->pubkey_authentication = -1; |
1011 | options->challenge_response_authentication = -1; | 1025 | options->challenge_response_authentication = -1; |
1012 | options->gss_authentication = -1; | 1026 | options->gss_authentication = -1; |
1027 | options->gss_keyex = -1; | ||
1013 | options->gss_deleg_creds = -1; | 1028 | options->gss_deleg_creds = -1; |
1029 | options->gss_trust_dns = -1; | ||
1014 | options->password_authentication = -1; | 1030 | options->password_authentication = -1; |
1015 | options->kbd_interactive_authentication = -1; | 1031 | options->kbd_interactive_authentication = -1; |
1016 | options->kbd_interactive_devices = NULL; | 1032 | options->kbd_interactive_devices = NULL; |
@@ -1099,8 +1115,12 @@ fill_default_options(Options * options) | |||
1099 | options->challenge_response_authentication = 1; | 1115 | options->challenge_response_authentication = 1; |
1100 | if (options->gss_authentication == -1) | 1116 | if (options->gss_authentication == -1) |
1101 | options->gss_authentication = 0; | 1117 | options->gss_authentication = 0; |
1118 | if (options->gss_keyex == -1) | ||
1119 | options->gss_keyex = 0; | ||
1102 | if (options->gss_deleg_creds == -1) | 1120 | if (options->gss_deleg_creds == -1) |
1103 | options->gss_deleg_creds = 0; | 1121 | options->gss_deleg_creds = 0; |
1122 | if (options->gss_trust_dns == -1) | ||
1123 | options->gss_trust_dns = 0; | ||
1104 | if (options->password_authentication == -1) | 1124 | if (options->password_authentication == -1) |
1105 | options->password_authentication = 1; | 1125 | options->password_authentication = 1; |
1106 | if (options->kbd_interactive_authentication == -1) | 1126 | if (options->kbd_interactive_authentication == -1) |
diff --git a/readconf.h b/readconf.h index d484f258e..a3d302420 100644 --- a/readconf.h +++ b/readconf.h | |||
@@ -44,7 +44,9 @@ typedef struct { | |||
44 | int challenge_response_authentication; | 44 | int challenge_response_authentication; |
45 | /* Try S/Key or TIS, authentication. */ | 45 | /* Try S/Key or TIS, authentication. */ |
46 | int gss_authentication; /* Try GSS authentication */ | 46 | int gss_authentication; /* Try GSS authentication */ |
47 | int gss_keyex; /* Try GSS key exchange */ | ||
47 | int gss_deleg_creds; /* Delegate GSS credentials */ | 48 | int gss_deleg_creds; /* Delegate GSS credentials */ |
49 | int gss_trust_dns; /* Trust DNS for GSS canonicalization */ | ||
48 | int password_authentication; /* Try password | 50 | int password_authentication; /* Try password |
49 | * authentication. */ | 51 | * authentication. */ |
50 | int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ | 52 | int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ |
diff --git a/servconf.c b/servconf.c index 1a7545171..f56cc1803 100644 --- a/servconf.c +++ b/servconf.c | |||
@@ -90,7 +90,9 @@ initialize_server_options(ServerOptions *options) | |||
90 | options->kerberos_ticket_cleanup = -1; | 90 | options->kerberos_ticket_cleanup = -1; |
91 | options->kerberos_get_afs_token = -1; | 91 | options->kerberos_get_afs_token = -1; |
92 | options->gss_authentication=-1; | 92 | options->gss_authentication=-1; |
93 | options->gss_keyex = -1; | ||
93 | options->gss_cleanup_creds = -1; | 94 | options->gss_cleanup_creds = -1; |
95 | options->gss_strict_acceptor = -1; | ||
94 | options->password_authentication = -1; | 96 | options->password_authentication = -1; |
95 | options->kbd_interactive_authentication = -1; | 97 | options->kbd_interactive_authentication = -1; |
96 | options->challenge_response_authentication = -1; | 98 | options->challenge_response_authentication = -1; |
@@ -204,8 +206,12 @@ fill_default_server_options(ServerOptions *options) | |||
204 | options->kerberos_get_afs_token = 0; | 206 | options->kerberos_get_afs_token = 0; |
205 | if (options->gss_authentication == -1) | 207 | if (options->gss_authentication == -1) |
206 | options->gss_authentication = 0; | 208 | options->gss_authentication = 0; |
209 | if (options->gss_keyex == -1) | ||
210 | options->gss_keyex = 0; | ||
207 | if (options->gss_cleanup_creds == -1) | 211 | if (options->gss_cleanup_creds == -1) |
208 | options->gss_cleanup_creds = 1; | 212 | options->gss_cleanup_creds = 1; |
213 | if (options->gss_strict_acceptor == -1) | ||
214 | options->gss_strict_acceptor = 1; | ||
209 | if (options->password_authentication == -1) | 215 | if (options->password_authentication == -1) |
210 | options->password_authentication = 1; | 216 | options->password_authentication = 1; |
211 | if (options->kbd_interactive_authentication == -1) | 217 | if (options->kbd_interactive_authentication == -1) |
@@ -290,7 +296,9 @@ typedef enum { | |||
290 | sBanner, sUseDNS, sHostbasedAuthentication, | 296 | sBanner, sUseDNS, sHostbasedAuthentication, |
291 | sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, | 297 | sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, |
292 | sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, | 298 | sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, |
293 | sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, | 299 | sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, |
300 | sGssKeyEx, | ||
301 | sAcceptEnv, sPermitTunnel, | ||
294 | sMatch, sPermitOpen, sForceCommand, | 302 | sMatch, sPermitOpen, sForceCommand, |
295 | sUsePrivilegeSeparation, | 303 | sUsePrivilegeSeparation, |
296 | sDeprecated, sUnsupported | 304 | sDeprecated, sUnsupported |
@@ -351,9 +359,13 @@ static struct { | |||
351 | #ifdef GSSAPI | 359 | #ifdef GSSAPI |
352 | { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, | 360 | { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, |
353 | { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, | 361 | { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, |
362 | { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, | ||
363 | { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, | ||
354 | #else | 364 | #else |
355 | { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, | 365 | { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, |
356 | { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, | 366 | { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, |
367 | { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, | ||
368 | { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, | ||
357 | #endif | 369 | #endif |
358 | { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, | 370 | { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, |
359 | { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, | 371 | { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, |
@@ -871,10 +883,18 @@ parse_flag: | |||
871 | intptr = &options->gss_authentication; | 883 | intptr = &options->gss_authentication; |
872 | goto parse_flag; | 884 | goto parse_flag; |
873 | 885 | ||
886 | case sGssKeyEx: | ||
887 | intptr = &options->gss_keyex; | ||
888 | goto parse_flag; | ||
889 | |||
874 | case sGssCleanupCreds: | 890 | case sGssCleanupCreds: |
875 | intptr = &options->gss_cleanup_creds; | 891 | intptr = &options->gss_cleanup_creds; |
876 | goto parse_flag; | 892 | goto parse_flag; |
877 | 893 | ||
894 | case sGssStrictAcceptor: | ||
895 | intptr = &options->gss_strict_acceptor; | ||
896 | goto parse_flag; | ||
897 | |||
878 | case sPasswordAuthentication: | 898 | case sPasswordAuthentication: |
879 | intptr = &options->password_authentication; | 899 | intptr = &options->password_authentication; |
880 | goto parse_flag; | 900 | goto parse_flag; |
diff --git a/servconf.h b/servconf.h index 8a5b950ea..257de1c8b 100644 --- a/servconf.h +++ b/servconf.h | |||
@@ -87,7 +87,9 @@ typedef struct { | |||
87 | int kerberos_get_afs_token; /* If true, try to get AFS token if | 87 | int kerberos_get_afs_token; /* If true, try to get AFS token if |
88 | * authenticated with Kerberos. */ | 88 | * authenticated with Kerberos. */ |
89 | int gss_authentication; /* If true, permit GSSAPI authentication */ | 89 | int gss_authentication; /* If true, permit GSSAPI authentication */ |
90 | int gss_keyex; /* If true, permit GSSAPI key exchange */ | ||
90 | int gss_cleanup_creds; /* If true, destroy cred cache on logout */ | 91 | int gss_cleanup_creds; /* If true, destroy cred cache on logout */ |
92 | int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ | ||
91 | int password_authentication; /* If true, permit password | 93 | int password_authentication; /* If true, permit password |
92 | * authentication. */ | 94 | * authentication. */ |
93 | int kbd_interactive_authentication; /* If true, permit */ | 95 | int kbd_interactive_authentication; /* If true, permit */ |
@@ -60,6 +60,17 @@ | |||
60 | 60 | ||
61 | #define SSH_GSS_OIDTYPE 0x06 | 61 | #define SSH_GSS_OIDTYPE 0x06 |
62 | 62 | ||
63 | #define SSH2_MSG_KEXGSS_INIT 30 | ||
64 | #define SSH2_MSG_KEXGSS_CONTINUE 31 | ||
65 | #define SSH2_MSG_KEXGSS_COMPLETE 32 | ||
66 | #define SSH2_MSG_KEXGSS_HOSTKEY 33 | ||
67 | #define SSH2_MSG_KEXGSS_ERROR 34 | ||
68 | #define SSH2_MSG_KEXGSS_GROUPREQ 40 | ||
69 | #define SSH2_MSG_KEXGSS_GROUP 41 | ||
70 | #define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-" | ||
71 | #define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-" | ||
72 | #define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-" | ||
73 | |||
63 | typedef struct { | 74 | typedef struct { |
64 | char *filename; | 75 | char *filename; |
65 | char *envvar; | 76 | char *envvar; |
@@ -97,6 +108,7 @@ typedef struct { | |||
97 | } Gssctxt; | 108 | } Gssctxt; |
98 | 109 | ||
99 | extern ssh_gssapi_mech *supported_mechs[]; | 110 | extern ssh_gssapi_mech *supported_mechs[]; |
111 | extern Gssctxt *gss_kex_context; | ||
100 | 112 | ||
101 | int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); | 113 | int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); |
102 | void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); | 114 | void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); |
@@ -119,6 +131,11 @@ void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); | |||
119 | int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); | 131 | int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); |
120 | 132 | ||
121 | /* In the server */ | 133 | /* In the server */ |
134 | typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *); | ||
135 | char *ssh_gssapi_client_mechanisms(const char *host); | ||
136 | char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *); | ||
137 | gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int); | ||
138 | int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *); | ||
122 | OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); | 139 | OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); |
123 | int ssh_gssapi_userok(char *name); | 140 | int ssh_gssapi_userok(char *name); |
124 | OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); | 141 | OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); |
@@ -126,6 +143,8 @@ void ssh_gssapi_do_child(char ***, u_int *); | |||
126 | void ssh_gssapi_cleanup_creds(void); | 143 | void ssh_gssapi_cleanup_creds(void); |
127 | void ssh_gssapi_storecreds(void); | 144 | void ssh_gssapi_storecreds(void); |
128 | 145 | ||
146 | char *ssh_gssapi_server_mechanisms(void); | ||
147 | int ssh_gssapi_oid_table_ok(); | ||
129 | #endif /* GSSAPI */ | 148 | #endif /* GSSAPI */ |
130 | 149 | ||
131 | #endif /* _SSH_GSS_H */ | 150 | #endif /* _SSH_GSS_H */ |
diff --git a/ssh_config b/ssh_config index 8cb0698a8..5e3cd7426 100644 --- a/ssh_config +++ b/ssh_config | |||
@@ -26,6 +26,8 @@ | |||
26 | # HostbasedAuthentication no | 26 | # HostbasedAuthentication no |
27 | # GSSAPIAuthentication no | 27 | # GSSAPIAuthentication no |
28 | # GSSAPIDelegateCredentials no | 28 | # GSSAPIDelegateCredentials no |
29 | # GSSAPIKeyExchange no | ||
30 | # GSSAPITrustDNS no | ||
29 | # BatchMode no | 31 | # BatchMode no |
30 | # CheckHostIP yes | 32 | # CheckHostIP yes |
31 | # AddressFamily any | 33 | # AddressFamily any |
diff --git a/ssh_config.5 b/ssh_config.5 index 95af3976a..53596e63a 100644 --- a/ssh_config.5 +++ b/ssh_config.5 | |||
@@ -477,11 +477,28 @@ Specifies whether user authentication based on GSSAPI is allowed. | |||
477 | The default is | 477 | The default is |
478 | .Dq no . | 478 | .Dq no . |
479 | Note that this option applies to protocol version 2 only. | 479 | Note that this option applies to protocol version 2 only. |
480 | .It Cm GSSAPIKeyExchange | ||
481 | Specifies whether key exchange based on GSSAPI may be used. When using | ||
482 | GSSAPI key exchange the server need not have a host key. | ||
483 | The default is | ||
484 | .Dq no . | ||
485 | Note that this option applies to protocol version 2 only. | ||
480 | .It Cm GSSAPIDelegateCredentials | 486 | .It Cm GSSAPIDelegateCredentials |
481 | Forward (delegate) credentials to the server. | 487 | Forward (delegate) credentials to the server. |
482 | The default is | 488 | The default is |
483 | .Dq no . | 489 | .Dq no . |
484 | Note that this option applies to protocol version 2 only. | 490 | Note that this option applies to protocol version 2 only. |
491 | .It Cm GSSAPITrustDns | ||
492 | Set to | ||
493 | .Dq yes | ||
494 | to indicate that the DNS is trusted to securely canonicalize | ||
495 | the name of the host being connected to. If | ||
496 | .Dq no , | ||
497 | the hostname entered on the | ||
498 | command line will be passed untouched to the GSSAPI library. | ||
499 | The default is | ||
500 | .Dq no . | ||
501 | This option only applies to protocol version 2 connections using GSSAPI. | ||
485 | .It Cm HashKnownHosts | 502 | .It Cm HashKnownHosts |
486 | Indicates that | 503 | Indicates that |
487 | .Xr ssh 1 | 504 | .Xr ssh 1 |
diff --git a/sshconnect2.c b/sshconnect2.c index 208df078c..a28b06502 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -99,9 +99,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
99 | { | 99 | { |
100 | Kex *kex; | 100 | Kex *kex; |
101 | 101 | ||
102 | #ifdef GSSAPI | ||
103 | char *orig = NULL, *gss = NULL; | ||
104 | char *gss_host = NULL; | ||
105 | #endif | ||
106 | |||
102 | xxx_host = host; | 107 | xxx_host = host; |
103 | xxx_hostaddr = hostaddr; | 108 | xxx_hostaddr = hostaddr; |
104 | 109 | ||
110 | #ifdef GSSAPI | ||
111 | if (options.gss_keyex) { | ||
112 | /* Add the GSSAPI mechanisms currently supported on this | ||
113 | * client to the key exchange algorithm proposal */ | ||
114 | orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
115 | |||
116 | if (options.gss_trust_dns) | ||
117 | gss_host = (char *)get_canonical_hostname(1); | ||
118 | else | ||
119 | gss_host = host; | ||
120 | |||
121 | gss = ssh_gssapi_client_mechanisms(gss_host); | ||
122 | if (gss) { | ||
123 | debug("Offering GSSAPI proposal: %s", gss); | ||
124 | xasprintf(&myproposal[PROPOSAL_KEX_ALGS], | ||
125 | "%s,%s", gss, orig); | ||
126 | } | ||
127 | } | ||
128 | #endif | ||
129 | |||
105 | if (options.ciphers == (char *)-1) { | 130 | if (options.ciphers == (char *)-1) { |
106 | logit("No valid ciphers for protocol version 2 given, using defaults."); | 131 | logit("No valid ciphers for protocol version 2 given, using defaults."); |
107 | options.ciphers = NULL; | 132 | options.ciphers = NULL; |
@@ -129,6 +154,16 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
129 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = | 154 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = |
130 | options.hostkeyalgorithms; | 155 | options.hostkeyalgorithms; |
131 | 156 | ||
157 | #ifdef GSSAPI | ||
158 | /* If we've got GSSAPI algorithms, then we also support the | ||
159 | * 'null' hostkey, as a last resort */ | ||
160 | if (options.gss_keyex && gss) { | ||
161 | orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; | ||
162 | xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], | ||
163 | "%s,null", orig); | ||
164 | } | ||
165 | #endif | ||
166 | |||
132 | if (options.rekey_limit) | 167 | if (options.rekey_limit) |
133 | packet_set_rekey_limit(options.rekey_limit); | 168 | packet_set_rekey_limit(options.rekey_limit); |
134 | 169 | ||
@@ -138,10 +173,21 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
138 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; | 173 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; |
139 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; | 174 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; |
140 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; | 175 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; |
176 | #ifdef GSSAPI | ||
177 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; | ||
178 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; | ||
179 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; | ||
180 | #endif | ||
141 | kex->client_version_string=client_version_string; | 181 | kex->client_version_string=client_version_string; |
142 | kex->server_version_string=server_version_string; | 182 | kex->server_version_string=server_version_string; |
143 | kex->verify_host_key=&verify_host_key_callback; | 183 | kex->verify_host_key=&verify_host_key_callback; |
144 | 184 | ||
185 | #ifdef GSSAPI | ||
186 | kex->gss_deleg_creds = options.gss_deleg_creds; | ||
187 | kex->gss_trust_dns = options.gss_trust_dns; | ||
188 | kex->gss_host = gss_host; | ||
189 | #endif | ||
190 | |||
145 | xxx_kex = kex; | 191 | xxx_kex = kex; |
146 | 192 | ||
147 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); | 193 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); |
@@ -224,6 +270,7 @@ void input_gssapi_token(int type, u_int32_t, void *); | |||
224 | void input_gssapi_hash(int type, u_int32_t, void *); | 270 | void input_gssapi_hash(int type, u_int32_t, void *); |
225 | void input_gssapi_error(int, u_int32_t, void *); | 271 | void input_gssapi_error(int, u_int32_t, void *); |
226 | void input_gssapi_errtok(int, u_int32_t, void *); | 272 | void input_gssapi_errtok(int, u_int32_t, void *); |
273 | int userauth_gsskeyex(Authctxt *authctxt); | ||
227 | #endif | 274 | #endif |
228 | 275 | ||
229 | void userauth(Authctxt *, char *); | 276 | void userauth(Authctxt *, char *); |
@@ -239,6 +286,10 @@ static char *authmethods_get(void); | |||
239 | 286 | ||
240 | Authmethod authmethods[] = { | 287 | Authmethod authmethods[] = { |
241 | #ifdef GSSAPI | 288 | #ifdef GSSAPI |
289 | {"gssapi-keyex", | ||
290 | userauth_gsskeyex, | ||
291 | &options.gss_authentication, | ||
292 | NULL}, | ||
242 | {"gssapi-with-mic", | 293 | {"gssapi-with-mic", |
243 | userauth_gssapi, | 294 | userauth_gssapi, |
244 | &options.gss_authentication, | 295 | &options.gss_authentication, |
@@ -501,6 +552,12 @@ userauth_gssapi(Authctxt *authctxt) | |||
501 | static u_int mech = 0; | 552 | static u_int mech = 0; |
502 | OM_uint32 min; | 553 | OM_uint32 min; |
503 | int ok = 0; | 554 | int ok = 0; |
555 | char *gss_host = NULL; | ||
556 | |||
557 | if (options.gss_trust_dns) | ||
558 | gss_host = (char *)get_canonical_hostname(1); | ||
559 | else | ||
560 | gss_host = (char *)authctxt->host; | ||
504 | 561 | ||
505 | /* Try one GSSAPI method at a time, rather than sending them all at | 562 | /* Try one GSSAPI method at a time, rather than sending them all at |
506 | * once. */ | 563 | * once. */ |
@@ -513,7 +570,7 @@ userauth_gssapi(Authctxt *authctxt) | |||
513 | /* My DER encoding requires length<128 */ | 570 | /* My DER encoding requires length<128 */ |
514 | if (gss_supported->elements[mech].length < 128 && | 571 | if (gss_supported->elements[mech].length < 128 && |
515 | ssh_gssapi_check_mechanism(&gssctxt, | 572 | ssh_gssapi_check_mechanism(&gssctxt, |
516 | &gss_supported->elements[mech], authctxt->host)) { | 573 | &gss_supported->elements[mech], gss_host)) { |
517 | ok = 1; /* Mechanism works */ | 574 | ok = 1; /* Mechanism works */ |
518 | } else { | 575 | } else { |
519 | mech++; | 576 | mech++; |
@@ -609,8 +666,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
609 | { | 666 | { |
610 | Authctxt *authctxt = ctxt; | 667 | Authctxt *authctxt = ctxt; |
611 | Gssctxt *gssctxt; | 668 | Gssctxt *gssctxt; |
612 | int oidlen; | 669 | u_int oidlen; |
613 | char *oidv; | 670 | u_char *oidv; |
614 | 671 | ||
615 | if (authctxt == NULL) | 672 | if (authctxt == NULL) |
616 | fatal("input_gssapi_response: no authentication context"); | 673 | fatal("input_gssapi_response: no authentication context"); |
@@ -717,6 +774,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) | |||
717 | xfree(msg); | 774 | xfree(msg); |
718 | xfree(lang); | 775 | xfree(lang); |
719 | } | 776 | } |
777 | |||
778 | int | ||
779 | userauth_gsskeyex(Authctxt *authctxt) | ||
780 | { | ||
781 | Buffer b; | ||
782 | gss_buffer_desc gssbuf; | ||
783 | gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; | ||
784 | OM_uint32 ms; | ||
785 | |||
786 | static int attempt = 0; | ||
787 | if (attempt++ >= 1) | ||
788 | return (0); | ||
789 | |||
790 | if (gss_kex_context == NULL) { | ||
791 | debug("No valid Key exchange context"); | ||
792 | return (0); | ||
793 | } | ||
794 | |||
795 | ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, | ||
796 | "gssapi-keyex"); | ||
797 | |||
798 | gssbuf.value = buffer_ptr(&b); | ||
799 | gssbuf.length = buffer_len(&b); | ||
800 | |||
801 | if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { | ||
802 | buffer_free(&b); | ||
803 | return (0); | ||
804 | } | ||
805 | |||
806 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
807 | packet_put_cstring(authctxt->server_user); | ||
808 | packet_put_cstring(authctxt->service); | ||
809 | packet_put_cstring(authctxt->method->name); | ||
810 | packet_put_string(mic.value, mic.length); | ||
811 | packet_send(); | ||
812 | |||
813 | buffer_free(&b); | ||
814 | gss_release_buffer(&ms, &mic); | ||
815 | |||
816 | return (1); | ||
817 | } | ||
818 | |||
720 | #endif /* GSSAPI */ | 819 | #endif /* GSSAPI */ |
721 | 820 | ||
722 | int | 821 | int |
@@ -117,6 +117,10 @@ | |||
117 | #include "monitor_fdpass.h" | 117 | #include "monitor_fdpass.h" |
118 | #include "version.h" | 118 | #include "version.h" |
119 | 119 | ||
120 | #ifdef USE_SECURITY_SESSION_API | ||
121 | #include <Security/AuthSession.h> | ||
122 | #endif | ||
123 | |||
120 | #ifdef LIBWRAP | 124 | #ifdef LIBWRAP |
121 | #include <tcpd.h> | 125 | #include <tcpd.h> |
122 | #include <syslog.h> | 126 | #include <syslog.h> |
@@ -1481,10 +1485,13 @@ main(int ac, char **av) | |||
1481 | logit("Disabling protocol version 1. Could not load host key"); | 1485 | logit("Disabling protocol version 1. Could not load host key"); |
1482 | options.protocol &= ~SSH_PROTO_1; | 1486 | options.protocol &= ~SSH_PROTO_1; |
1483 | } | 1487 | } |
1488 | #ifndef GSSAPI | ||
1489 | /* The GSSAPI key exchange can run without a host key */ | ||
1484 | if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { | 1490 | if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { |
1485 | logit("Disabling protocol version 2. Could not load host key"); | 1491 | logit("Disabling protocol version 2. Could not load host key"); |
1486 | options.protocol &= ~SSH_PROTO_2; | 1492 | options.protocol &= ~SSH_PROTO_2; |
1487 | } | 1493 | } |
1494 | #endif | ||
1488 | if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { | 1495 | if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { |
1489 | logit("sshd: no hostkeys available -- exiting."); | 1496 | logit("sshd: no hostkeys available -- exiting."); |
1490 | exit(1); | 1497 | exit(1); |
@@ -1759,6 +1766,60 @@ main(int ac, char **av) | |||
1759 | /* Log the connection. */ | 1766 | /* Log the connection. */ |
1760 | verbose("Connection from %.500s port %d", remote_ip, remote_port); | 1767 | verbose("Connection from %.500s port %d", remote_ip, remote_port); |
1761 | 1768 | ||
1769 | #ifdef USE_SECURITY_SESSION_API | ||
1770 | /* | ||
1771 | * Create a new security session for use by the new user login if | ||
1772 | * the current session is the root session or we are not launched | ||
1773 | * by inetd (eg: debugging mode or server mode). We do not | ||
1774 | * necessarily need to create a session if we are launched from | ||
1775 | * inetd because Panther xinetd will create a session for us. | ||
1776 | * | ||
1777 | * The only case where this logic will fail is if there is an | ||
1778 | * inetd running in a non-root session which is not creating | ||
1779 | * new sessions for us. Then all the users will end up in the | ||
1780 | * same session (bad). | ||
1781 | * | ||
1782 | * When the client exits, the session will be destroyed for us | ||
1783 | * automatically. | ||
1784 | * | ||
1785 | * We must create the session before any credentials are stored | ||
1786 | * (including AFS pags, which happens a few lines below). | ||
1787 | */ | ||
1788 | { | ||
1789 | OSStatus err = 0; | ||
1790 | SecuritySessionId sid = 0; | ||
1791 | SessionAttributeBits sattrs = 0; | ||
1792 | |||
1793 | err = SessionGetInfo(callerSecuritySession, &sid, &sattrs); | ||
1794 | if (err) | ||
1795 | error("SessionGetInfo() failed with error %.8X", | ||
1796 | (unsigned) err); | ||
1797 | else | ||
1798 | debug("Current Session ID is %.8X / Session Attributes are %.8X", | ||
1799 | (unsigned) sid, (unsigned) sattrs); | ||
1800 | |||
1801 | if (inetd_flag && !(sattrs & sessionIsRoot)) | ||
1802 | debug("Running in inetd mode in a non-root session... " | ||
1803 | "assuming inetd created the session for us."); | ||
1804 | else { | ||
1805 | debug("Creating new security session..."); | ||
1806 | err = SessionCreate(0, sessionHasTTY | sessionIsRemote); | ||
1807 | if (err) | ||
1808 | error("SessionCreate() failed with error %.8X", | ||
1809 | (unsigned) err); | ||
1810 | |||
1811 | err = SessionGetInfo(callerSecuritySession, &sid, | ||
1812 | &sattrs); | ||
1813 | if (err) | ||
1814 | error("SessionGetInfo() failed with error %.8X", | ||
1815 | (unsigned) err); | ||
1816 | else | ||
1817 | debug("New Session ID is %.8X / Session Attributes are %.8X", | ||
1818 | (unsigned) sid, (unsigned) sattrs); | ||
1819 | } | ||
1820 | } | ||
1821 | #endif | ||
1822 | |||
1762 | /* | 1823 | /* |
1763 | * We don't want to listen forever unless the other side | 1824 | * We don't want to listen forever unless the other side |
1764 | * successfully authenticates itself. So we set up an alarm which is | 1825 | * successfully authenticates itself. So we set up an alarm which is |
@@ -2117,12 +2178,59 @@ do_ssh2_kex(void) | |||
2117 | 2178 | ||
2118 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); | 2179 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); |
2119 | 2180 | ||
2181 | #ifdef GSSAPI | ||
2182 | { | ||
2183 | char *orig; | ||
2184 | char *gss = NULL; | ||
2185 | char *newstr = NULL; | ||
2186 | orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
2187 | |||
2188 | /* | ||
2189 | * If we don't have a host key, then there's no point advertising | ||
2190 | * the other key exchange algorithms | ||
2191 | */ | ||
2192 | |||
2193 | if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) | ||
2194 | orig = NULL; | ||
2195 | |||
2196 | if (options.gss_keyex) | ||
2197 | gss = ssh_gssapi_server_mechanisms(); | ||
2198 | else | ||
2199 | gss = NULL; | ||
2200 | |||
2201 | if (gss && orig) | ||
2202 | xasprintf(&newstr, "%s,%s", gss, orig); | ||
2203 | else if (gss) | ||
2204 | newstr = gss; | ||
2205 | else if (orig) | ||
2206 | newstr = orig; | ||
2207 | |||
2208 | /* | ||
2209 | * If we've got GSSAPI mechanisms, then we've got the 'null' host | ||
2210 | * key alg, but we can't tell people about it unless its the only | ||
2211 | * host key algorithm we support | ||
2212 | */ | ||
2213 | if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) | ||
2214 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null"; | ||
2215 | |||
2216 | if (newstr) | ||
2217 | myproposal[PROPOSAL_KEX_ALGS] = newstr; | ||
2218 | else | ||
2219 | fatal("No supported key exchange algorithms"); | ||
2220 | } | ||
2221 | #endif | ||
2222 | |||
2120 | /* start key exchange */ | 2223 | /* start key exchange */ |
2121 | kex = kex_setup(myproposal); | 2224 | kex = kex_setup(myproposal); |
2122 | kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; | 2225 | kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; |
2123 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; | 2226 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; |
2124 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; | 2227 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; |
2125 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; | 2228 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; |
2229 | #ifdef GSSAPI | ||
2230 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; | ||
2231 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; | ||
2232 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; | ||
2233 | #endif | ||
2126 | kex->server = 1; | 2234 | kex->server = 1; |
2127 | kex->client_version_string=client_version_string; | 2235 | kex->client_version_string=client_version_string; |
2128 | kex->server_version_string=server_version_string; | 2236 | kex->server_version_string=server_version_string; |
diff --git a/sshd_config b/sshd_config index 3393cec50..aa1e4abdf 100644 --- a/sshd_config +++ b/sshd_config | |||
@@ -72,6 +72,8 @@ Protocol 2 | |||
72 | # GSSAPI options | 72 | # GSSAPI options |
73 | #GSSAPIAuthentication no | 73 | #GSSAPIAuthentication no |
74 | #GSSAPICleanupCredentials yes | 74 | #GSSAPICleanupCredentials yes |
75 | #GSSAPIStrictAcceptorCheck yes | ||
76 | #GSSAPIKeyExchange no | ||
75 | 77 | ||
76 | # Set this to 'yes' to enable PAM authentication, account processing, | 78 | # Set this to 'yes' to enable PAM authentication, account processing, |
77 | # and session processing. If this is enabled, PAM authentication will | 79 | # and session processing. If this is enabled, PAM authentication will |
diff --git a/sshd_config.5 b/sshd_config.5 index 7882f8bcf..5e1c7943c 100644 --- a/sshd_config.5 +++ b/sshd_config.5 | |||
@@ -318,12 +318,35 @@ Specifies whether user authentication based on GSSAPI is allowed. | |||
318 | The default is | 318 | The default is |
319 | .Dq no . | 319 | .Dq no . |
320 | Note that this option applies to protocol version 2 only. | 320 | Note that this option applies to protocol version 2 only. |
321 | .It Cm GSSAPIKeyExchange | ||
322 | Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange | ||
323 | doesn't rely on ssh keys to verify host identity. | ||
324 | The default is | ||
325 | .Dq no . | ||
326 | Note that this option applies to protocol version 2 only. | ||
321 | .It Cm GSSAPICleanupCredentials | 327 | .It Cm GSSAPICleanupCredentials |
322 | Specifies whether to automatically destroy the user's credentials cache | 328 | Specifies whether to automatically destroy the user's credentials cache |
323 | on logout. | 329 | on logout. |
324 | The default is | 330 | The default is |
325 | .Dq yes . | 331 | .Dq yes . |
326 | Note that this option applies to protocol version 2 only. | 332 | Note that this option applies to protocol version 2 only. |
333 | .It Cm GSSAPIStrictAcceptorCheck | ||
334 | Determines whether to be strict about the identity of the GSSAPI acceptor | ||
335 | a client authenticates against. If | ||
336 | .Dq yes | ||
337 | then the client must authenticate against the | ||
338 | .Pa host | ||
339 | service on the current hostname. If | ||
340 | .Dq no | ||
341 | then the client may authenticate against any service key stored in the | ||
342 | machine's default store. This facility is provided to assist with operation | ||
343 | on multi homed machines. | ||
344 | The default is | ||
345 | .Dq yes . | ||
346 | Note that this option applies only to protocol version 2 GSSAPI connections, | ||
347 | and setting it to | ||
348 | .Dq no | ||
349 | may only work with recent Kerberos GSSAPI libraries. | ||
327 | .It Cm HostbasedAuthentication | 350 | .It Cm HostbasedAuthentication |
328 | Specifies whether rhosts or /etc/hosts.equiv authentication together | 351 | Specifies whether rhosts or /etc/hosts.equiv authentication together |
329 | with successful public key client host authentication is allowed | 352 | with successful public key client host authentication is allowed |