diff options
-rw-r--r-- | auth-krb5.c | 17 | ||||
-rw-r--r-- | auth.h | 1 | ||||
-rw-r--r-- | auth2-gss.c | 4 | ||||
-rw-r--r-- | auth2.c | 5 | ||||
-rw-r--r-- | config.h.in | 9 | ||||
-rwxr-xr-x | configure | 117 | ||||
-rw-r--r-- | configure.ac | 24 | ||||
-rw-r--r-- | debian/changelog | 3 | ||||
-rw-r--r-- | gss-genr.c | 47 | ||||
-rw-r--r-- | gss-serv.c | 15 | ||||
-rw-r--r-- | kex.c | 8 | ||||
-rw-r--r-- | kex.h | 5 | ||||
-rw-r--r-- | kexgssc.c | 159 | ||||
-rw-r--r-- | kexgsss.c | 110 | ||||
-rw-r--r-- | monitor.c | 8 | ||||
-rw-r--r-- | monitor_wrap.c | 4 | ||||
-rw-r--r-- | readconf.c | 10 | ||||
-rw-r--r-- | readconf.h | 1 | ||||
-rw-r--r-- | servconf.c | 12 | ||||
-rw-r--r-- | servconf.h | 1 | ||||
-rw-r--r-- | ssh-gss.h | 13 | ||||
-rw-r--r-- | ssh_config.5 | 10 | ||||
-rw-r--r-- | sshconnect2.c | 31 | ||||
-rw-r--r-- | sshd.c | 65 | ||||
-rw-r--r-- | sshd_config.5 | 6 |
25 files changed, 554 insertions, 131 deletions
diff --git a/auth-krb5.c b/auth-krb5.c index 64d613543..bc37675a2 100644 --- a/auth-krb5.c +++ b/auth-krb5.c | |||
@@ -156,8 +156,13 @@ auth_krb5_password(Authctxt *authctxt, const char *password) | |||
156 | 156 | ||
157 | len = strlen(authctxt->krb5_ticket_file) + 6; | 157 | len = strlen(authctxt->krb5_ticket_file) + 6; |
158 | authctxt->krb5_ccname = xmalloc(len); | 158 | authctxt->krb5_ccname = xmalloc(len); |
159 | #ifdef USE_CCAPI | ||
160 | snprintf(authctxt->krb5_ccname, len, "API:%s", | ||
161 | authctxt->krb5_ticket_file); | ||
162 | #else | ||
159 | snprintf(authctxt->krb5_ccname, len, "FILE:%s", | 163 | snprintf(authctxt->krb5_ccname, len, "FILE:%s", |
160 | authctxt->krb5_ticket_file); | 164 | authctxt->krb5_ticket_file); |
165 | #endif | ||
161 | 166 | ||
162 | #ifdef USE_PAM | 167 | #ifdef USE_PAM |
163 | if (options.use_pam) | 168 | if (options.use_pam) |
@@ -209,15 +214,22 @@ krb5_cleanup_proc(Authctxt *authctxt) | |||
209 | #ifndef HEIMDAL | 214 | #ifndef HEIMDAL |
210 | krb5_error_code | 215 | krb5_error_code |
211 | ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { | 216 | ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { |
212 | int tmpfd, ret; | 217 | int ret; |
213 | char ccname[40]; | 218 | char ccname[40]; |
214 | mode_t old_umask; | 219 | mode_t old_umask; |
220 | #ifdef USE_CCAPI | ||
221 | char cctemplate[] = "API:krb5cc_%d"; | ||
222 | #else | ||
223 | char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX"; | ||
224 | int tmpfd; | ||
225 | #endif | ||
215 | 226 | ||
216 | ret = snprintf(ccname, sizeof(ccname), | 227 | ret = snprintf(ccname, sizeof(ccname), |
217 | "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); | 228 | cctemplate, geteuid()); |
218 | if (ret < 0 || (size_t)ret >= sizeof(ccname)) | 229 | if (ret < 0 || (size_t)ret >= sizeof(ccname)) |
219 | return ENOMEM; | 230 | return ENOMEM; |
220 | 231 | ||
232 | #ifndef USE_CCAPI | ||
221 | old_umask = umask(0177); | 233 | old_umask = umask(0177); |
222 | tmpfd = mkstemp(ccname + strlen("FILE:")); | 234 | tmpfd = mkstemp(ccname + strlen("FILE:")); |
223 | umask(old_umask); | 235 | umask(old_umask); |
@@ -232,6 +244,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { | |||
232 | return errno; | 244 | return errno; |
233 | } | 245 | } |
234 | close(tmpfd); | 246 | close(tmpfd); |
247 | #endif | ||
235 | 248 | ||
236 | return (krb5_cc_resolve(ctx, ccname, ccache)); | 249 | return (krb5_cc_resolve(ctx, ccname, ccache)); |
237 | } | 250 | } |
@@ -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 a6a9c05cd..539654ee0 100644 --- a/auth2-gss.c +++ b/auth2-gss.c | |||
@@ -129,11 +129,13 @@ userauth_gssapi(Authctxt *authctxt) | |||
129 | 129 | ||
130 | if (!present) { | 130 | if (!present) { |
131 | xfree(doid); | 131 | xfree(doid); |
132 | authctxt->server_caused_failure = 1; | ||
132 | return (0); | 133 | return (0); |
133 | } | 134 | } |
134 | 135 | ||
135 | if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) { | 136 | if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) { |
136 | xfree(doid); | 137 | xfree(doid); |
138 | authctxt->server_caused_failure = 1; | ||
137 | return (0); | 139 | return (0); |
138 | } | 140 | } |
139 | 141 | ||
@@ -318,7 +320,7 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) | |||
318 | } | 320 | } |
319 | 321 | ||
320 | Authmethod method_gsskeyex = { | 322 | Authmethod method_gsskeyex = { |
321 | "gssapi-keyx", | 323 | "gssapi-keyex", |
322 | userauth_gsskeyex, | 324 | userauth_gsskeyex, |
323 | &options.gss_authentication | 325 | &options.gss_authentication |
324 | }; | 326 | }; |
@@ -196,6 +196,7 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) | |||
196 | #endif | 196 | #endif |
197 | 197 | ||
198 | authctxt->postponed = 0; | 198 | authctxt->postponed = 0; |
199 | authctxt->server_caused_failure = 0; | ||
199 | 200 | ||
200 | /* try to authenticate user */ | 201 | /* try to authenticate user */ |
201 | m = authmethod_lookup(method); | 202 | m = authmethod_lookup(method); |
@@ -266,7 +267,9 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method) | |||
266 | /* now we can break out */ | 267 | /* now we can break out */ |
267 | authctxt->success = 1; | 268 | authctxt->success = 1; |
268 | } else { | 269 | } else { |
269 | if (authctxt->failures++ > options.max_authtries) { | 270 | /* Dont count server configuration issues against the client */ |
271 | if (!authctxt->server_caused_failure && | ||
272 | authctxt->failures++ > options.max_authtries) { | ||
270 | #ifdef SSH_AUDIT_EVENTS | 273 | #ifdef SSH_AUDIT_EVENTS |
271 | PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); | 274 | PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); |
272 | #endif | 275 | #endif |
diff --git a/config.h.in b/config.h.in index 05e17adc8..e841f33c9 100644 --- a/config.h.in +++ b/config.h.in | |||
@@ -1216,6 +1216,9 @@ | |||
1216 | /* Use btmp to log bad logins */ | 1216 | /* Use btmp to log bad logins */ |
1217 | #undef USE_BTMP | 1217 | #undef USE_BTMP |
1218 | 1218 | ||
1219 | /* platform uses an in-memory credentials cache */ | ||
1220 | #undef USE_CCAPI | ||
1221 | |||
1219 | /* Use libedit for sftp */ | 1222 | /* Use libedit for sftp */ |
1220 | #undef USE_LIBEDIT | 1223 | #undef USE_LIBEDIT |
1221 | 1224 | ||
@@ -1231,6 +1234,9 @@ | |||
1231 | /* Define if you want smartcard support using sectok */ | 1234 | /* Define if you want smartcard support using sectok */ |
1232 | #undef USE_SECTOK | 1235 | #undef USE_SECTOK |
1233 | 1236 | ||
1237 | /* platform has the Security Authorization Session API */ | ||
1238 | #undef USE_SECURITY_SESSION_API | ||
1239 | |||
1234 | /* Define if you shouldn't strip 'tty' from your ttyname in [uw]tmp */ | 1240 | /* Define if you shouldn't strip 'tty' from your ttyname in [uw]tmp */ |
1235 | #undef WITH_ABBREV_NO_TTY | 1241 | #undef WITH_ABBREV_NO_TTY |
1236 | 1242 | ||
@@ -1250,6 +1256,9 @@ | |||
1250 | /* Define if you want IRIX project management */ | 1256 | /* Define if you want IRIX project management */ |
1251 | #undef WITH_IRIX_PROJECT | 1257 | #undef WITH_IRIX_PROJECT |
1252 | 1258 | ||
1259 | /* Define if you want SELinux support. */ | ||
1260 | #undef WITH_SELINUX | ||
1261 | |||
1253 | /* Define to 1 if your processor stores words with the most significant byte | 1262 | /* Define to 1 if your processor stores words with the most significant byte |
1254 | first (like Motorola and SPARC, unlike Intel and VAX). */ | 1263 | first (like Motorola and SPARC, unlike Intel and VAX). */ |
1255 | #undef WORDS_BIGENDIAN | 1264 | #undef WORDS_BIGENDIAN |
@@ -5257,6 +5257,123 @@ cat >>confdefs.h <<_ACEOF | |||
5257 | #define BIND_8_COMPAT 1 | 5257 | #define BIND_8_COMPAT 1 |
5258 | _ACEOF | 5258 | _ACEOF |
5259 | 5259 | ||
5260 | echo "$as_me:$LINENO: checking if we have the Security Authorization Session API" >&5 | ||
5261 | echo $ECHO_N "checking if we have the Security Authorization Session API... $ECHO_C" >&6 | ||
5262 | cat >conftest.$ac_ext <<_ACEOF | ||
5263 | /* confdefs.h. */ | ||
5264 | _ACEOF | ||
5265 | cat confdefs.h >>conftest.$ac_ext | ||
5266 | cat >>conftest.$ac_ext <<_ACEOF | ||
5267 | /* end confdefs.h. */ | ||
5268 | #include <Security/AuthSession.h> | ||
5269 | int | ||
5270 | main () | ||
5271 | { | ||
5272 | SessionCreate(0, 0); | ||
5273 | ; | ||
5274 | return 0; | ||
5275 | } | ||
5276 | _ACEOF | ||
5277 | rm -f conftest.$ac_objext | ||
5278 | if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 | ||
5279 | (eval $ac_compile) 2>conftest.er1 | ||
5280 | ac_status=$? | ||
5281 | grep -v '^ *+' conftest.er1 >conftest.err | ||
5282 | rm -f conftest.er1 | ||
5283 | cat conftest.err >&5 | ||
5284 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | ||
5285 | (exit $ac_status); } && | ||
5286 | { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' | ||
5287 | { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 | ||
5288 | (eval $ac_try) 2>&5 | ||
5289 | ac_status=$? | ||
5290 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | ||
5291 | (exit $ac_status); }; } && | ||
5292 | { ac_try='test -s conftest.$ac_objext' | ||
5293 | { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 | ||
5294 | (eval $ac_try) 2>&5 | ||
5295 | ac_status=$? | ||
5296 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | ||
5297 | (exit $ac_status); }; }; then | ||
5298 | ac_cv_use_security_session_api="yes" | ||
5299 | |||
5300 | cat >>confdefs.h <<\_ACEOF | ||
5301 | #define USE_SECURITY_SESSION_API 1 | ||
5302 | _ACEOF | ||
5303 | |||
5304 | LIBS="$LIBS -framework Security" | ||
5305 | echo "$as_me:$LINENO: result: yes" >&5 | ||
5306 | echo "${ECHO_T}yes" >&6 | ||
5307 | else | ||
5308 | echo "$as_me: failed program was:" >&5 | ||
5309 | sed 's/^/| /' conftest.$ac_ext >&5 | ||
5310 | |||
5311 | ac_cv_use_security_session_api="no" | ||
5312 | echo "$as_me:$LINENO: result: no" >&5 | ||
5313 | echo "${ECHO_T}no" >&6 | ||
5314 | fi | ||
5315 | rm -f conftest.err conftest.$ac_objext conftest.$ac_ext | ||
5316 | echo "$as_me:$LINENO: checking if we have an in-memory credentials cache" >&5 | ||
5317 | echo $ECHO_N "checking if we have an in-memory credentials cache... $ECHO_C" >&6 | ||
5318 | cat >conftest.$ac_ext <<_ACEOF | ||
5319 | /* confdefs.h. */ | ||
5320 | _ACEOF | ||
5321 | cat confdefs.h >>conftest.$ac_ext | ||
5322 | cat >>conftest.$ac_ext <<_ACEOF | ||
5323 | /* end confdefs.h. */ | ||
5324 | #include <Kerberos/Kerberos.h> | ||
5325 | int | ||
5326 | main () | ||
5327 | { | ||
5328 | cc_context_t c; | ||
5329 | (void) cc_initialize (&c, 0, NULL, NULL); | ||
5330 | ; | ||
5331 | return 0; | ||
5332 | } | ||
5333 | _ACEOF | ||
5334 | rm -f conftest.$ac_objext | ||
5335 | if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 | ||
5336 | (eval $ac_compile) 2>conftest.er1 | ||
5337 | ac_status=$? | ||
5338 | grep -v '^ *+' conftest.er1 >conftest.err | ||
5339 | rm -f conftest.er1 | ||
5340 | cat conftest.err >&5 | ||
5341 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | ||
5342 | (exit $ac_status); } && | ||
5343 | { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' | ||
5344 | { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 | ||
5345 | (eval $ac_try) 2>&5 | ||
5346 | ac_status=$? | ||
5347 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | ||
5348 | (exit $ac_status); }; } && | ||
5349 | { ac_try='test -s conftest.$ac_objext' | ||
5350 | { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 | ||
5351 | (eval $ac_try) 2>&5 | ||
5352 | ac_status=$? | ||
5353 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | ||
5354 | (exit $ac_status); }; }; then | ||
5355 | |||
5356 | cat >>confdefs.h <<\_ACEOF | ||
5357 | #define USE_CCAPI 1 | ||
5358 | _ACEOF | ||
5359 | |||
5360 | LIBS="$LIBS -framework Security" | ||
5361 | echo "$as_me:$LINENO: result: yes" >&5 | ||
5362 | echo "${ECHO_T}yes" >&6 | ||
5363 | if test "x$ac_cv_use_security_session_api" = "xno"; then | ||
5364 | { { echo "$as_me:$LINENO: error: *** Need a security framework to use the credentials cache API ***" >&5 | ||
5365 | echo "$as_me: error: *** Need a security framework to use the credentials cache API ***" >&2;} | ||
5366 | { (exit 1); exit 1; }; } | ||
5367 | fi | ||
5368 | else | ||
5369 | echo "$as_me: failed program was:" >&5 | ||
5370 | sed 's/^/| /' conftest.$ac_ext >&5 | ||
5371 | |||
5372 | echo "$as_me:$LINENO: result: no" >&5 | ||
5373 | echo "${ECHO_T}no" >&6 | ||
5374 | |||
5375 | fi | ||
5376 | rm -f conftest.err conftest.$ac_objext conftest.$ac_ext | ||
5260 | ;; | 5377 | ;; |
5261 | *-*-hpux*) | 5378 | *-*-hpux*) |
5262 | # first we define all of the options common to all HP-UX releases | 5379 | # first we define all of the options common to all HP-UX releases |
diff --git a/configure.ac b/configure.ac index 9ff199451..7b723799e 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -231,6 +231,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) | |||
231 | AC_DEFINE(BROKEN_SETREGID) | 231 | AC_DEFINE(BROKEN_SETREGID) |
232 | AC_DEFINE_UNQUOTED(BIND_8_COMPAT, 1, | 232 | AC_DEFINE_UNQUOTED(BIND_8_COMPAT, 1, |
233 | [Define if your resolver libs need this for getrrsetbyname]) | 233 | [Define if your resolver libs need this for getrrsetbyname]) |
234 | AC_MSG_CHECKING(if we have the Security Authorization Session API) | ||
235 | AC_TRY_COMPILE([#include <Security/AuthSession.h>], | ||
236 | [SessionCreate(0, 0);], | ||
237 | [ac_cv_use_security_session_api="yes" | ||
238 | AC_DEFINE(USE_SECURITY_SESSION_API, 1, | ||
239 | [platform has the Security Authorization Session API]) | ||
240 | LIBS="$LIBS -framework Security" | ||
241 | AC_MSG_RESULT(yes)], | ||
242 | [ac_cv_use_security_session_api="no" | ||
243 | AC_MSG_RESULT(no)]) | ||
244 | AC_MSG_CHECKING(if we have an in-memory credentials cache) | ||
245 | AC_TRY_COMPILE( | ||
246 | [#include <Kerberos/Kerberos.h>], | ||
247 | [cc_context_t c; | ||
248 | (void) cc_initialize (&c, 0, NULL, NULL);], | ||
249 | [AC_DEFINE(USE_CCAPI, 1, | ||
250 | [platform uses an in-memory credentials cache]) | ||
251 | LIBS="$LIBS -framework Security" | ||
252 | AC_MSG_RESULT(yes) | ||
253 | if test "x$ac_cv_use_security_session_api" = "xno"; then | ||
254 | AC_MSG_ERROR(*** Need a security framework to use the credentials cache API ***) | ||
255 | fi], | ||
256 | [AC_MSG_RESULT(no)] | ||
257 | ) | ||
234 | ;; | 258 | ;; |
235 | *-*-hpux*) | 259 | *-*-hpux*) |
236 | # first we define all of the options common to all HP-UX releases | 260 | # first we define all of the options common to all HP-UX releases |
diff --git a/debian/changelog b/debian/changelog index 98e6ed73a..2c4dc3b01 100644 --- a/debian/changelog +++ b/debian/changelog | |||
@@ -40,6 +40,9 @@ openssh (1:4.3p2-1) UNRELEASED; urgency=low | |||
40 | - Many manual page improvements. | 40 | - Many manual page improvements. |
41 | - Lots of cleanups, including fixes to memory leaks on error paths and | 41 | - Lots of cleanups, including fixes to memory leaks on error paths and |
42 | possible crashes. | 42 | possible crashes. |
43 | * Update to current GSSAPI patch from | ||
44 | http://www.sxw.org.uk/computing/patches/openssh-4.3p2-gsskex-20060223.patch | ||
45 | (closes: #352042). | ||
43 | * Rename KeepAlive to TCPKeepAlive in default sshd_config | 46 | * Rename KeepAlive to TCPKeepAlive in default sshd_config |
44 | (closes: #349896). | 47 | (closes: #349896). |
45 | * debconf template translations: | 48 | * debconf template translations: |
diff --git a/gss-genr.c b/gss-genr.c index 2a905f5e9..dfaa708ea 100644 --- a/gss-genr.c +++ b/gss-genr.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* $OpenBSD: gss-genr.c,v 1.6 2005/10/13 22:24:31 stevesk Exp $ */ | 1 | /* $OpenBSD: gss-genr.c,v 1.6 2005/10/13 22:24:31 stevesk Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. | 4 | * Copyright (c) 2001-2005 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 |
@@ -53,6 +53,11 @@ Gssctxt *gss_kex_context = NULL; | |||
53 | 53 | ||
54 | static ssh_gss_kex_mapping *gss_enc2oid = NULL; | 54 | static ssh_gss_kex_mapping *gss_enc2oid = NULL; |
55 | 55 | ||
56 | int | ||
57 | ssh_gssapi_oid_table_ok() { | ||
58 | return (gss_enc2oid != NULL); | ||
59 | } | ||
60 | |||
56 | /* | 61 | /* |
57 | * Return a list of the gss-group1-sha1 mechanisms supported by this program | 62 | * Return a list of the gss-group1-sha1 mechanisms supported by this program |
58 | * | 63 | * |
@@ -62,7 +67,7 @@ static ssh_gss_kex_mapping *gss_enc2oid = NULL; | |||
62 | 67 | ||
63 | 68 | ||
64 | char * | 69 | char * |
65 | ssh_gssapi_client_mechanisms(char *host) { | 70 | ssh_gssapi_client_mechanisms(const char *host) { |
66 | gss_OID_set gss_supported; | 71 | gss_OID_set gss_supported; |
67 | OM_uint32 min_status; | 72 | OM_uint32 min_status; |
68 | 73 | ||
@@ -83,8 +88,6 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, | |||
83 | const EVP_MD *evp_md = EVP_md5(); | 88 | const EVP_MD *evp_md = EVP_md5(); |
84 | EVP_MD_CTX md; | 89 | EVP_MD_CTX md; |
85 | 90 | ||
86 | evp_md = EVP_md5(); | ||
87 | |||
88 | if (gss_enc2oid != NULL) { | 91 | if (gss_enc2oid != NULL) { |
89 | for (i=0;gss_enc2oid[i].encoded!=NULL;i++) | 92 | for (i=0;gss_enc2oid[i].encoded!=NULL;i++) |
90 | xfree(gss_enc2oid[i].encoded); | 93 | xfree(gss_enc2oid[i].encoded); |
@@ -97,12 +100,13 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, | |||
97 | buffer_init(&buf); | 100 | buffer_init(&buf); |
98 | 101 | ||
99 | oidpos = 0; | 102 | oidpos = 0; |
100 | for (i=0;i<gss_supported->count;i++) { | 103 | for (i = 0;i < gss_supported->count;i++) { |
101 | if (gss_supported->elements[i].length<128 && | 104 | if (gss_supported->elements[i].length < 128 && |
102 | (*check)(&(gss_supported->elements[i]), data)) { | 105 | (*check)(&(gss_supported->elements[i]), data)) { |
103 | 106 | ||
104 | deroid[0] = SSH_GSS_OIDTYPE; | 107 | deroid[0] = SSH_GSS_OIDTYPE; |
105 | deroid[1] = gss_supported->elements[i].length; | 108 | deroid[1] = gss_supported->elements[i].length; |
109 | |||
106 | EVP_DigestInit(&md, evp_md); | 110 | EVP_DigestInit(&md, evp_md); |
107 | EVP_DigestUpdate(&md, deroid, 2); | 111 | EVP_DigestUpdate(&md, deroid, 2); |
108 | EVP_DigestUpdate(&md, | 112 | EVP_DigestUpdate(&md, |
@@ -115,10 +119,14 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, | |||
115 | encoded, EVP_MD_size(evp_md)*2); | 119 | encoded, EVP_MD_size(evp_md)*2); |
116 | 120 | ||
117 | if (oidpos != 0) | 121 | if (oidpos != 0) |
118 | buffer_put_char(&buf,','); | 122 | buffer_put_char(&buf, ','); |
119 | 123 | ||
120 | buffer_append(&buf, KEX_GSS_SHA1, | 124 | buffer_append(&buf, KEX_GSS_GEX_SHA1_ID, |
121 | sizeof(KEX_GSS_SHA1)-1); | 125 | sizeof(KEX_GSS_GEX_SHA1_ID)-1); |
126 | buffer_append(&buf, encoded, enclen); | ||
127 | buffer_put_char(&buf,','); | ||
128 | buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, | ||
129 | sizeof(KEX_GSS_GRP1_SHA1_ID)-1); | ||
122 | buffer_append(&buf, encoded, enclen); | 130 | buffer_append(&buf, encoded, enclen); |
123 | 131 | ||
124 | gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); | 132 | gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); |
@@ -129,7 +137,7 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, | |||
129 | gss_enc2oid[oidpos].oid = NULL; | 137 | gss_enc2oid[oidpos].oid = NULL; |
130 | gss_enc2oid[oidpos].encoded = NULL; | 138 | gss_enc2oid[oidpos].encoded = NULL; |
131 | 139 | ||
132 | buffer_put_char(&buf,'\0'); | 140 | buffer_put_char(&buf, '\0'); |
133 | 141 | ||
134 | mechs = xmalloc(buffer_len(&buf)); | 142 | mechs = xmalloc(buffer_len(&buf)); |
135 | buffer_get(&buf, mechs, buffer_len(&buf)); | 143 | buffer_get(&buf, mechs, buffer_len(&buf)); |
@@ -144,21 +152,28 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, | |||
144 | } | 152 | } |
145 | 153 | ||
146 | gss_OID | 154 | gss_OID |
147 | ssh_gssapi_id_kex(Gssctxt *ctx, char *name) { | 155 | ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int *gex) { |
148 | int i = 0; | 156 | int i = 0; |
149 | 157 | ||
150 | if (strncmp(name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) != 0) | 158 | if (strncmp(name, KEX_GSS_GRP1_SHA1_ID, |
159 | sizeof(KEX_GSS_GRP1_SHA1_ID)-1) == 0) { | ||
160 | name+=sizeof(KEX_GSS_GRP1_SHA1_ID)-1; | ||
161 | *gex = 0; | ||
162 | } else if (strncmp(name, KEX_GSS_GEX_SHA1_ID, | ||
163 | sizeof(KEX_GSS_GEX_SHA1_ID)-1) == 0) { | ||
164 | name+=sizeof(KEX_GSS_GEX_SHA1_ID)-1; | ||
165 | *gex = 1; | ||
166 | } else { | ||
151 | return NULL; | 167 | return NULL; |
152 | 168 | } | |
153 | name+=sizeof(KEX_GSS_SHA1)-1; /* Skip ID string */ | ||
154 | 169 | ||
155 | while (gss_enc2oid[i].encoded != NULL && | 170 | while (gss_enc2oid[i].encoded != NULL && |
156 | strcmp(name,gss_enc2oid[i].encoded)!=0) { | 171 | strcmp(name, gss_enc2oid[i].encoded) != 0) { |
157 | i++; | 172 | i++; |
158 | } | 173 | } |
159 | 174 | ||
160 | if (gss_enc2oid[i].oid != NULL && ctx != NULL) | 175 | if (gss_enc2oid[i].oid != NULL && ctx != NULL) |
161 | ssh_gssapi_set_oid(ctx,gss_enc2oid[i].oid); | 176 | ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid); |
162 | 177 | ||
163 | return gss_enc2oid[i].oid; | 178 | return gss_enc2oid[i].oid; |
164 | } | 179 | } |
diff --git a/gss-serv.c b/gss-serv.c index 9682fc3c3..190f56fc0 100644 --- a/gss-serv.c +++ b/gss-serv.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "servconf.h" | 36 | #include "servconf.h" |
37 | #include "xmalloc.h" | 37 | #include "xmalloc.h" |
38 | #include "getput.h" | 38 | #include "getput.h" |
39 | #include "monitor_wrap.h" | ||
39 | 40 | ||
40 | #include "ssh-gss.h" | 41 | #include "ssh-gss.h" |
41 | 42 | ||
@@ -70,9 +71,9 @@ ssh_gssapi_server_mechanisms() { | |||
70 | /* Unprivileged */ | 71 | /* Unprivileged */ |
71 | int | 72 | int |
72 | ssh_gssapi_server_check_mech(gss_OID oid, void *data) { | 73 | ssh_gssapi_server_check_mech(gss_OID oid, void *data) { |
73 | Gssctxt * ctx = NULL; | 74 | Gssctxt * ctx = NULL; |
74 | int res; | 75 | int res; |
75 | 76 | ||
76 | res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid))); | 77 | res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid))); |
77 | ssh_gssapi_delete_ctx(&ctx); | 78 | ssh_gssapi_delete_ctx(&ctx); |
78 | 79 | ||
@@ -315,14 +316,4 @@ ssh_gssapi_userok(char *user) | |||
315 | return (0); | 316 | return (0); |
316 | } | 317 | } |
317 | 318 | ||
318 | /* Privileged */ | ||
319 | OM_uint32 | ||
320 | ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) | ||
321 | { | ||
322 | ctx->major = gss_verify_mic(&ctx->minor, ctx->context, | ||
323 | gssbuf, gssmic, NULL); | ||
324 | |||
325 | return (ctx->major); | ||
326 | } | ||
327 | |||
328 | #endif | 319 | #endif |
@@ -306,8 +306,12 @@ choose_kex(Kex *k, char *client, char *server) | |||
306 | k->kex_type = KEX_DH_GEX_SHA1; | 306 | k->kex_type = KEX_DH_GEX_SHA1; |
307 | k->evp_md = EVP_sha1(); | 307 | k->evp_md = EVP_sha1(); |
308 | #ifdef GSSAPI | 308 | #ifdef GSSAPI |
309 | } else if (strncmp(k->name, KEX_GSS_SHA1, | 309 | } else if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID, |
310 | sizeof(KEX_GSS_SHA1)-1) == 0) { | 310 | sizeof(KEX_GSS_GEX_SHA1_ID)-1) == 0) { |
311 | k->kex_type = KEX_GSS_GEX_SHA1; | ||
312 | k->evp_md = EVP_sha1(); | ||
313 | } else if (strncmp(k->name, KEX_GSS_GRP1_SHA1_ID, | ||
314 | sizeof(KEX_GSS_GRP1_SHA1_ID)-1) == 0) { | ||
311 | k->kex_type = KEX_GSS_GRP1_SHA1; | 315 | k->kex_type = KEX_GSS_GRP1_SHA1; |
312 | k->evp_md = EVP_sha1(); | 316 | k->evp_md = EVP_sha1(); |
313 | #endif | 317 | #endif |
@@ -64,6 +64,7 @@ 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_GSS_GRP1_SHA1, | 66 | KEX_GSS_GRP1_SHA1, |
67 | KEX_GSS_GEX_SHA1, | ||
67 | KEX_MAX | 68 | KEX_MAX |
68 | }; | 69 | }; |
69 | 70 | ||
@@ -117,7 +118,9 @@ struct Kex { | |||
117 | int flags; | 118 | int flags; |
118 | const EVP_MD *evp_md; | 119 | const EVP_MD *evp_md; |
119 | #ifdef GSSAPI | 120 | #ifdef GSSAPI |
120 | int gss_deleg_creds; | 121 | int gss_deleg_creds; |
122 | int gss_trust_dns; | ||
123 | char *gss_host; | ||
121 | #endif | 124 | #endif |
122 | char *client_version_string; | 125 | char *client_version_string; |
123 | char *server_version_string; | 126 | char *server_version_string; |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2001-2004 Simon Wilkinson. All rights reserved. | 2 | * Copyright (c) 2001-2005 Simon Wilkinson. All rights reserved. |
3 | * | 3 | * |
4 | * Redistribution and use in source and binary forms, with or without | 4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions | 5 | * modification, are permitted provided that the following conditions |
@@ -42,34 +42,65 @@ | |||
42 | 42 | ||
43 | void | 43 | void |
44 | kexgss_client(Kex *kex) { | 44 | kexgss_client(Kex *kex) { |
45 | gss_buffer_desc gssbuf, send_tok, recv_tok, msg_tok, *token_ptr; | 45 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; |
46 | gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr; | ||
46 | Gssctxt *ctxt; | 47 | Gssctxt *ctxt; |
47 | OM_uint32 maj_status, min_status, ret_flags; | 48 | OM_uint32 maj_status, min_status, ret_flags; |
48 | unsigned int klen, kout; | 49 | u_int klen, kout, slen = 0, hashlen, strlen; |
49 | DH *dh; | 50 | DH *dh; |
50 | BIGNUM *dh_server_pub = 0; | 51 | BIGNUM *dh_server_pub = NULL; |
51 | BIGNUM *shared_secret = 0; | 52 | BIGNUM *shared_secret = NULL; |
52 | unsigned char *kbuf; | 53 | BIGNUM *p = NULL; |
53 | unsigned char *hash; | 54 | BIGNUM *g = NULL; |
54 | unsigned char *serverhostkey; | 55 | u_char *kbuf, *hash; |
56 | u_char *serverhostkey = NULL; | ||
55 | char *msg; | 57 | char *msg; |
56 | char *lang; | 58 | char *lang; |
57 | int type = 0; | 59 | int type = 0; |
58 | int first = 1; | 60 | int first = 1; |
59 | int slen = 0; | 61 | int gex = 0; |
60 | u_int strlen; | 62 | int nbits, min, max; |
61 | 63 | ||
64 | /* Initialise our GSSAPI world */ | ||
62 | ssh_gssapi_build_ctx(&ctxt); | 65 | ssh_gssapi_build_ctx(&ctxt); |
63 | if (ssh_gssapi_id_kex(ctxt,kex->name) == NULL) | 66 | if (ssh_gssapi_id_kex(ctxt, kex->name, &gex) == NULL) |
64 | fatal("Couldn't identify host exchange"); | 67 | fatal("Couldn't identify host exchange"); |
65 | 68 | ||
66 | if (ssh_gssapi_import_name(ctxt,get_canonical_hostname(1))) | 69 | if (ssh_gssapi_import_name(ctxt, kex->gss_host)) |
67 | fatal("Couldn't import hostname "); | 70 | fatal("Couldn't import hostname"); |
71 | |||
72 | if (gex) { | ||
73 | debug("Doing group exchange\n"); | ||
74 | nbits = dh_estimate(kex->we_need * 8); | ||
75 | min = DH_GRP_MIN; | ||
76 | max = DH_GRP_MAX; | ||
77 | packet_start(SSH2_MSG_KEXGSS_GROUPREQ); | ||
78 | packet_put_int(min); | ||
79 | packet_put_int(nbits); | ||
80 | packet_put_int(max); | ||
81 | |||
82 | packet_send(); | ||
83 | |||
84 | packet_read_expect(SSH2_MSG_KEXGSS_GROUP); | ||
85 | |||
86 | if ((p = BN_new()) == NULL) | ||
87 | fatal("BN_new() failed"); | ||
88 | packet_get_bignum2(p); | ||
89 | if ((g = BN_new()) == NULL) | ||
90 | fatal("BN_new() failed"); | ||
91 | packet_get_bignum2(g); | ||
92 | packet_check_eom(); | ||
93 | |||
94 | if (BN_num_bits(p) < min || BN_num_bits(p) > max) | ||
95 | fatal("GSSGRP_GEX group out of range: %d !< %d !< %d", | ||
96 | min, BN_num_bits(p), max); | ||
97 | |||
98 | dh = dh_new_group(g, p); | ||
99 | } else { | ||
100 | dh = dh_new_group1(); | ||
101 | } | ||
68 | 102 | ||
69 | /* This code should match that in ssh_dh1_client */ | ||
70 | |||
71 | /* Step 1 - e is dh->pub_key */ | 103 | /* Step 1 - e is dh->pub_key */ |
72 | dh = dh_new_group1(); | ||
73 | dh_gen_key(dh, kex->we_need * 8); | 104 | dh_gen_key(dh, kex->we_need * 8); |
74 | 105 | ||
75 | /* This is f, we initialise it now to make life easier */ | 106 | /* This is f, we initialise it now to make life easier */ |
@@ -97,7 +128,7 @@ kexgss_client(Kex *kex) { | |||
97 | 128 | ||
98 | /* If we've got an old receive buffer get rid of it */ | 129 | /* If we've got an old receive buffer get rid of it */ |
99 | if (token_ptr != GSS_C_NO_BUFFER) | 130 | if (token_ptr != GSS_C_NO_BUFFER) |
100 | (void) gss_release_buffer(&min_status, &recv_tok); | 131 | xfree(recv_tok.value); |
101 | 132 | ||
102 | if (maj_status == GSS_S_COMPLETE) { | 133 | if (maj_status == GSS_S_COMPLETE) { |
103 | /* If mutual state flag is not true, kex fails */ | 134 | /* If mutual state flag is not true, kex fails */ |
@@ -126,15 +157,21 @@ kexgss_client(Kex *kex) { | |||
126 | send_tok.length); | 157 | send_tok.length); |
127 | } | 158 | } |
128 | packet_send(); | 159 | packet_send(); |
160 | gss_release_buffer(&min_status, &send_tok); | ||
129 | 161 | ||
130 | /* If we've sent them data, they should reply */ | 162 | /* If we've sent them data, they should reply */ |
131 | 163 | do { | |
132 | type = packet_read(); | 164 | type = packet_read(); |
165 | if (type == SSH2_MSG_KEXGSS_HOSTKEY) { | ||
166 | debug("Received KEXGSS_HOSTKEY"); | ||
167 | if (serverhostkey) | ||
168 | fatal("Server host key received more than once"); | ||
169 | serverhostkey = | ||
170 | packet_get_string(&slen); | ||
171 | } | ||
172 | } while (type == SSH2_MSG_KEXGSS_HOSTKEY); | ||
173 | |||
133 | switch (type) { | 174 | switch (type) { |
134 | case SSH2_MSG_KEXGSS_HOSTKEY: | ||
135 | debug("Received KEXGSS_HOSTKEY"); | ||
136 | serverhostkey = packet_get_string(&slen); | ||
137 | break; | ||
138 | case SSH2_MSG_KEXGSS_CONTINUE: | 175 | case SSH2_MSG_KEXGSS_CONTINUE: |
139 | debug("Received GSSAPI_CONTINUE"); | 176 | debug("Received GSSAPI_CONTINUE"); |
140 | if (maj_status == GSS_S_COMPLETE) | 177 | if (maj_status == GSS_S_COMPLETE) |
@@ -144,8 +181,8 @@ kexgss_client(Kex *kex) { | |||
144 | break; | 181 | break; |
145 | case SSH2_MSG_KEXGSS_COMPLETE: | 182 | case SSH2_MSG_KEXGSS_COMPLETE: |
146 | debug("Received GSSAPI_COMPLETE"); | 183 | debug("Received GSSAPI_COMPLETE"); |
147 | packet_get_bignum2(dh_server_pub); | 184 | packet_get_bignum2(dh_server_pub); |
148 | msg_tok.value = packet_get_string(&strlen); | 185 | msg_tok.value = packet_get_string(&strlen); |
149 | msg_tok.length = strlen; | 186 | msg_tok.length = strlen; |
150 | 187 | ||
151 | /* Is there a token included? */ | 188 | /* Is there a token included? */ |
@@ -156,10 +193,10 @@ kexgss_client(Kex *kex) { | |||
156 | /* If we're already complete - protocol error */ | 193 | /* If we're already complete - protocol error */ |
157 | if (maj_status == GSS_S_COMPLETE) | 194 | if (maj_status == GSS_S_COMPLETE) |
158 | packet_disconnect("Protocol error: received token when complete"); | 195 | packet_disconnect("Protocol error: received token when complete"); |
159 | } else { | 196 | } else { |
160 | /* No token included */ | 197 | /* No token included */ |
161 | if (maj_status != GSS_S_COMPLETE) | 198 | if (maj_status != GSS_S_COMPLETE) |
162 | packet_disconnect("Protocol error: did not receive final token"); | 199 | packet_disconnect("Protocol error: did not receive final token"); |
163 | } | 200 | } |
164 | break; | 201 | break; |
165 | case SSH2_MSG_KEXGSS_ERROR: | 202 | case SSH2_MSG_KEXGSS_ERROR: |
@@ -168,7 +205,7 @@ kexgss_client(Kex *kex) { | |||
168 | min_status = packet_get_int(); | 205 | min_status = packet_get_int(); |
169 | msg = packet_get_string(NULL); | 206 | msg = packet_get_string(NULL); |
170 | lang = packet_get_string(NULL); | 207 | lang = packet_get_string(NULL); |
171 | fprintf(stderr,"GSSAPI Error: \n%s",msg); | 208 | fatal("GSSAPI Error: \n%s",msg); |
172 | default: | 209 | default: |
173 | packet_disconnect("Protocol error: didn't expect packet type %d", | 210 | packet_disconnect("Protocol error: didn't expect packet type %d", |
174 | type); | 211 | type); |
@@ -181,12 +218,12 @@ kexgss_client(Kex *kex) { | |||
181 | } | 218 | } |
182 | } while (maj_status & GSS_S_CONTINUE_NEEDED); | 219 | } while (maj_status & GSS_S_CONTINUE_NEEDED); |
183 | 220 | ||
184 | /* | 221 | /* |
185 | * We _must_ have received a COMPLETE message in reply from the | 222 | * We _must_ have received a COMPLETE message in reply from the |
186 | * server, which will have set dh_server_pub and msg_tok | 223 | * server, which will have set dh_server_pub and msg_tok |
187 | */ | 224 | */ |
188 | 225 | ||
189 | if (type!=SSH2_MSG_KEXGSS_COMPLETE) | 226 | if (type != SSH2_MSG_KEXGSS_COMPLETE) |
190 | fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); | 227 | fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); |
191 | 228 | ||
192 | /* Check f in range [1, p-1] */ | 229 | /* Check f in range [1, p-1] */ |
@@ -203,28 +240,52 @@ kexgss_client(Kex *kex) { | |||
203 | memset(kbuf, 0, klen); | 240 | memset(kbuf, 0, klen); |
204 | xfree(kbuf); | 241 | xfree(kbuf); |
205 | 242 | ||
206 | /* The GSS hash is identical to the DH one */ | 243 | if (gex) { |
207 | hash = kex_dh_hash( kex->client_version_string, | 244 | kexgex_hash( |
208 | kex->server_version_string, | 245 | kex->evp_md, |
209 | buffer_ptr(&kex->my), buffer_len(&kex->my), | 246 | kex->client_version_string, |
210 | buffer_ptr(&kex->peer), buffer_len(&kex->peer), | 247 | kex->server_version_string, |
211 | serverhostkey, slen, /* server host key */ | 248 | buffer_ptr(&kex->my), buffer_len(&kex->my), |
212 | dh->pub_key, /* e */ | 249 | buffer_ptr(&kex->peer), buffer_len(&kex->peer), |
213 | dh_server_pub, /* f */ | 250 | serverhostkey, slen, |
214 | shared_secret /* K */ | 251 | min, nbits, max, |
215 | ); | 252 | dh->p, dh->g, |
216 | 253 | dh->pub_key, | |
254 | dh_server_pub, | ||
255 | shared_secret, | ||
256 | &hash, &hashlen | ||
257 | ); | ||
258 | } else { | ||
259 | /* The GSS hash is identical to the DH one */ | ||
260 | kex_dh_hash( kex->client_version_string, | ||
261 | kex->server_version_string, | ||
262 | buffer_ptr(&kex->my), buffer_len(&kex->my), | ||
263 | buffer_ptr(&kex->peer), buffer_len(&kex->peer), | ||
264 | serverhostkey, slen, /* server host key */ | ||
265 | dh->pub_key, /* e */ | ||
266 | dh_server_pub, /* f */ | ||
267 | shared_secret, /* K */ | ||
268 | &hash, &hashlen | ||
269 | ); | ||
270 | } | ||
271 | |||
217 | gssbuf.value = hash; | 272 | gssbuf.value = hash; |
218 | gssbuf.length = 20; | 273 | gssbuf.length = hashlen; |
219 | 274 | ||
220 | /* Verify that the hash matches the MIC we just got. */ | 275 | /* Verify that the hash matches the MIC we just got. */ |
221 | if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) | 276 | if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) |
222 | packet_disconnect("Hash's MIC didn't verify"); | 277 | packet_disconnect("Hash's MIC didn't verify"); |
223 | 278 | ||
279 | xfree(msg_tok.value); | ||
280 | |||
224 | DH_free(dh); | 281 | DH_free(dh); |
282 | if (serverhostkey) | ||
283 | xfree(serverhostkey); | ||
284 | BN_clear_free(dh_server_pub); | ||
285 | |||
225 | /* save session id */ | 286 | /* save session id */ |
226 | if (kex->session_id == NULL) { | 287 | if (kex->session_id == NULL) { |
227 | kex->session_id_len = 20; | 288 | kex->session_id_len = hashlen; |
228 | kex->session_id = xmalloc(kex->session_id_len); | 289 | kex->session_id = xmalloc(kex->session_id_len); |
229 | memcpy(kex->session_id, hash, kex->session_id_len); | 290 | memcpy(kex->session_id, hash, kex->session_id_len); |
230 | } | 291 | } |
@@ -234,7 +295,7 @@ kexgss_client(Kex *kex) { | |||
234 | else | 295 | else |
235 | ssh_gssapi_delete_ctx(&ctxt); | 296 | ssh_gssapi_delete_ctx(&ctxt); |
236 | 297 | ||
237 | kex_derive_keys(kex, hash, shared_secret); | 298 | kex_derive_keys(kex, hash, hashlen, shared_secret); |
238 | BN_clear_free(shared_secret); | 299 | BN_clear_free(shared_secret); |
239 | kex_finish(kex); | 300 | kex_finish(kex); |
240 | } | 301 | } |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2001-2004 Simon Wilkinson. All rights reserved. | 2 | * Copyright (c) 2001-2005 Simon Wilkinson. All rights reserved. |
3 | * | 3 | * |
4 | * Redistribution and use in source and binary forms, with or without | 4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions | 5 | * modification, are permitted provided that the following conditions |
@@ -53,21 +53,30 @@ kexgss_server(Kex *kex) | |||
53 | */ | 53 | */ |
54 | 54 | ||
55 | OM_uint32 ret_flags = 0; | 55 | OM_uint32 ret_flags = 0; |
56 | gss_buffer_desc gssbuf, send_tok, recv_tok, msg_tok; | 56 | gss_buffer_desc gssbuf, recv_tok, msg_tok; |
57 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
57 | Gssctxt *ctxt = NULL; | 58 | Gssctxt *ctxt = NULL; |
58 | unsigned int klen, kout; | 59 | u_int slen, klen, kout, hashlen; |
59 | unsigned char *kbuf, *hash; | 60 | u_char *kbuf, *hash; |
60 | DH *dh; | 61 | DH *dh; |
62 | int min = -1, max = -1, nbits = -1; | ||
61 | BIGNUM *shared_secret = NULL; | 63 | BIGNUM *shared_secret = NULL; |
62 | BIGNUM *dh_client_pub = NULL; | 64 | BIGNUM *dh_client_pub = NULL; |
63 | int type =0; | 65 | int type = 0; |
64 | u_int slen; | 66 | int gex; |
65 | gss_OID oid; | 67 | gss_OID oid; |
66 | 68 | ||
67 | /* Initialise GSSAPI */ | 69 | /* Initialise GSSAPI */ |
68 | 70 | ||
71 | /* If we're rekeying, privsep means that some of the private structures | ||
72 | * in the GSSAPI code are no longer available. This kludges them back | ||
73 | * into life | ||
74 | */ | ||
75 | if (!ssh_gssapi_oid_table_ok()) | ||
76 | ssh_gssapi_server_mechanisms(); | ||
77 | |||
69 | debug2("%s: Identifying %s", __func__, kex->name); | 78 | debug2("%s: Identifying %s", __func__, kex->name); |
70 | oid = ssh_gssapi_id_kex(NULL, kex->name); | 79 | oid = ssh_gssapi_id_kex(NULL, kex->name, &gex); |
71 | if (oid == NULL) | 80 | if (oid == NULL) |
72 | fatal("Unknown gssapi mechanism"); | 81 | fatal("Unknown gssapi mechanism"); |
73 | 82 | ||
@@ -76,6 +85,34 @@ kexgss_server(Kex *kex) | |||
76 | if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) | 85 | if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) |
77 | fatal("Unable to acquire credentials for the server"); | 86 | fatal("Unable to acquire credentials for the server"); |
78 | 87 | ||
88 | if (gex) { | ||
89 | debug("Doing group exchange"); | ||
90 | packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ); | ||
91 | min = packet_get_int(); | ||
92 | nbits = packet_get_int(); | ||
93 | max = packet_get_int(); | ||
94 | min = MAX(DH_GRP_MIN, min); | ||
95 | max = MIN(DH_GRP_MAX, max); | ||
96 | packet_check_eom(); | ||
97 | if (max < min || nbits < min || max < nbits) | ||
98 | fatal("GSS_GEX, bad parameters: %d !< %d !< %d", | ||
99 | min, nbits, max); | ||
100 | dh = PRIVSEP(choose_dh(min, nbits, max)); | ||
101 | if (dh == NULL) | ||
102 | packet_disconnect("Protocol error: no matching group found"); | ||
103 | |||
104 | packet_start(SSH2_MSG_KEXGSS_GROUP); | ||
105 | packet_put_bignum2(dh->p); | ||
106 | packet_put_bignum2(dh->g); | ||
107 | packet_send(); | ||
108 | |||
109 | packet_write_wait(); | ||
110 | |||
111 | } else { | ||
112 | dh = dh_new_group1(); | ||
113 | } | ||
114 | dh_gen_key(dh, kex->we_need * 8); | ||
115 | |||
79 | do { | 116 | do { |
80 | debug("Wait SSH2_MSG_GSSAPI_INIT"); | 117 | debug("Wait SSH2_MSG_GSSAPI_INIT"); |
81 | type = packet_read(); | 118 | type = packet_read(); |
@@ -86,10 +123,9 @@ kexgss_server(Kex *kex) | |||
86 | recv_tok.value = packet_get_string(&slen); | 123 | recv_tok.value = packet_get_string(&slen); |
87 | recv_tok.length = slen; | 124 | recv_tok.length = slen; |
88 | 125 | ||
89 | dh_client_pub = BN_new(); | 126 | if ((dh_client_pub = BN_new()) == NULL) |
90 | |||
91 | if (dh_client_pub == NULL) | ||
92 | fatal("dh_client_pub == NULL"); | 127 | fatal("dh_client_pub == NULL"); |
128 | |||
93 | packet_get_bignum2(dh_client_pub); | 129 | packet_get_bignum2(dh_client_pub); |
94 | 130 | ||
95 | /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ | 131 | /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ |
@@ -107,8 +143,8 @@ kexgss_server(Kex *kex) | |||
107 | maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, | 143 | maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, |
108 | &send_tok, &ret_flags)); | 144 | &send_tok, &ret_flags)); |
109 | 145 | ||
110 | gss_release_buffer(&min_status, &recv_tok); | 146 | xfree(recv_tok.value); |
111 | 147 | ||
112 | if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) | 148 | if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) |
113 | fatal("Zero length token output when incomplete"); | 149 | fatal("Zero length token output when incomplete"); |
114 | 150 | ||
@@ -125,7 +161,7 @@ kexgss_server(Kex *kex) | |||
125 | } while (maj_status & GSS_S_CONTINUE_NEEDED); | 161 | } while (maj_status & GSS_S_CONTINUE_NEEDED); |
126 | 162 | ||
127 | if (GSS_ERROR(maj_status)) { | 163 | if (GSS_ERROR(maj_status)) { |
128 | if (send_tok.length>0) { | 164 | if (send_tok.length > 0) { |
129 | packet_start(SSH2_MSG_KEXGSS_CONTINUE); | 165 | packet_start(SSH2_MSG_KEXGSS_CONTINUE); |
130 | packet_put_string(send_tok.value, send_tok.length); | 166 | packet_put_string(send_tok.value, send_tok.length); |
131 | packet_send(); | 167 | packet_send(); |
@@ -139,9 +175,6 @@ kexgss_server(Kex *kex) | |||
139 | if (!(ret_flags & GSS_C_INTEG_FLAG)) | 175 | if (!(ret_flags & GSS_C_INTEG_FLAG)) |
140 | fatal("Integrity flag wasn't set"); | 176 | fatal("Integrity flag wasn't set"); |
141 | 177 | ||
142 | dh = dh_new_group1(); | ||
143 | dh_gen_key(dh, kex->we_need * 8); | ||
144 | |||
145 | if (!dh_pub_is_valid(dh, dh_client_pub)) | 178 | if (!dh_pub_is_valid(dh, dh_client_pub)) |
146 | packet_disconnect("bad client public DH value"); | 179 | packet_disconnect("bad client public DH value"); |
147 | 180 | ||
@@ -154,24 +187,42 @@ kexgss_server(Kex *kex) | |||
154 | memset(kbuf, 0, klen); | 187 | memset(kbuf, 0, klen); |
155 | xfree(kbuf); | 188 | xfree(kbuf); |
156 | 189 | ||
157 | /* The GSSAPI hash is identical to the Diffie Helman one */ | 190 | if (gex) { |
158 | hash = kex_dh_hash( | 191 | kexgex_hash( |
159 | kex->client_version_string, kex->server_version_string, | 192 | kex->evp_md, |
160 | buffer_ptr(&kex->peer), buffer_len(&kex->peer), | 193 | kex->client_version_string, kex->server_version_string, |
161 | buffer_ptr(&kex->my), buffer_len(&kex->my), | 194 | buffer_ptr(&kex->peer), buffer_len(&kex->peer), |
162 | NULL, 0, /* Change this if we start sending host keys */ | 195 | buffer_ptr(&kex->my), buffer_len(&kex->my), |
163 | dh_client_pub, dh->pub_key, shared_secret | 196 | NULL, 0, |
164 | ); | 197 | min, nbits, max, |
198 | dh->p, dh->g, | ||
199 | dh_client_pub, | ||
200 | dh->pub_key, | ||
201 | shared_secret, | ||
202 | &hash, &hashlen | ||
203 | ); | ||
204 | } | ||
205 | else { | ||
206 | /* The GSSAPI hash is identical to the Diffie Helman one */ | ||
207 | kex_dh_hash( | ||
208 | kex->client_version_string, kex->server_version_string, | ||
209 | buffer_ptr(&kex->peer), buffer_len(&kex->peer), | ||
210 | buffer_ptr(&kex->my), buffer_len(&kex->my), | ||
211 | NULL, 0, /* Change this if we start sending host keys */ | ||
212 | dh_client_pub, dh->pub_key, shared_secret, | ||
213 | &hash, &hashlen | ||
214 | ); | ||
215 | } | ||
165 | BN_free(dh_client_pub); | 216 | BN_free(dh_client_pub); |
166 | 217 | ||
167 | if (kex->session_id == NULL) { | 218 | if (kex->session_id == NULL) { |
168 | kex->session_id_len = 20; | 219 | kex->session_id_len = hashlen; |
169 | kex->session_id = xmalloc(kex->session_id_len); | 220 | kex->session_id = xmalloc(kex->session_id_len); |
170 | memcpy(kex->session_id, hash, kex->session_id_len); | 221 | memcpy(kex->session_id, hash, kex->session_id_len); |
171 | } | 222 | } |
172 | 223 | ||
173 | gssbuf.value = hash; | 224 | gssbuf.value = hash; |
174 | gssbuf.length = 20; /* Hashlen appears to always be 20 */ | 225 | gssbuf.length = hashlen; |
175 | 226 | ||
176 | if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) | 227 | if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) |
177 | fatal("Couldn't get MIC"); | 228 | fatal("Couldn't get MIC"); |
@@ -180,7 +231,7 @@ kexgss_server(Kex *kex) | |||
180 | packet_put_bignum2(dh->pub_key); | 231 | packet_put_bignum2(dh->pub_key); |
181 | packet_put_string((char *)msg_tok.value,msg_tok.length); | 232 | packet_put_string((char *)msg_tok.value,msg_tok.length); |
182 | 233 | ||
183 | if (send_tok.length!=0) { | 234 | if (send_tok.length != 0) { |
184 | packet_put_char(1); /* true */ | 235 | packet_put_char(1); /* true */ |
185 | packet_put_string((char *)send_tok.value, send_tok.length); | 236 | packet_put_string((char *)send_tok.value, send_tok.length); |
186 | } else { | 237 | } else { |
@@ -188,7 +239,8 @@ kexgss_server(Kex *kex) | |||
188 | } | 239 | } |
189 | packet_send(); | 240 | packet_send(); |
190 | 241 | ||
191 | gss_release_buffer(&min_status, &send_tok); | 242 | gss_release_buffer(&min_status, &send_tok); |
243 | gss_release_buffer(&min_status, &msg_tok); | ||
192 | 244 | ||
193 | if (gss_kex_context == NULL) | 245 | if (gss_kex_context == NULL) |
194 | gss_kex_context = ctxt; | 246 | gss_kex_context = ctxt; |
@@ -197,7 +249,7 @@ kexgss_server(Kex *kex) | |||
197 | 249 | ||
198 | DH_free(dh); | 250 | DH_free(dh); |
199 | 251 | ||
200 | kex_derive_keys(kex, hash, shared_secret); | 252 | kex_derive_keys(kex, hash, hashlen, shared_secret); |
201 | BN_clear_free(shared_secret); | 253 | BN_clear_free(shared_secret); |
202 | kex_finish(kex); | 254 | kex_finish(kex); |
203 | } | 255 | } |
@@ -1644,6 +1644,7 @@ mm_get_kex(Buffer *m) | |||
1644 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; | 1644 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; |
1645 | #ifdef GSSAPI | 1645 | #ifdef GSSAPI |
1646 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; | 1646 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; |
1647 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; | ||
1647 | #endif | 1648 | #endif |
1648 | kex->server = 1; | 1649 | kex->server = 1; |
1649 | kex->hostkey_type = buffer_get_int(m); | 1650 | kex->hostkey_type = buffer_get_int(m); |
@@ -1942,10 +1943,13 @@ mm_answer_gss_userok(int sock, Buffer *m) | |||
1942 | int | 1943 | int |
1943 | mm_answer_gss_sign(int socket, Buffer *m) | 1944 | mm_answer_gss_sign(int socket, Buffer *m) |
1944 | { | 1945 | { |
1945 | gss_buffer_desc data, hash; | 1946 | gss_buffer_desc data; |
1947 | gss_buffer_desc hash = GSS_C_EMPTY_BUFFER; | ||
1946 | OM_uint32 major, minor; | 1948 | OM_uint32 major, minor; |
1949 | u_int len; | ||
1947 | 1950 | ||
1948 | data.value = buffer_get_string(m, &data.length); | 1951 | data.value = buffer_get_string(m, &len); |
1952 | data.length = len; | ||
1949 | if (data.length != 20) | 1953 | if (data.length != 20) |
1950 | fatal("%s: data length incorrect: %d", __func__, data.length); | 1954 | fatal("%s: data length incorrect: %d", __func__, data.length); |
1951 | 1955 | ||
diff --git a/monitor_wrap.c b/monitor_wrap.c index 23b0cbd59..6749d3f93 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c | |||
@@ -1222,6 +1222,7 @@ mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) | |||
1222 | { | 1222 | { |
1223 | Buffer m; | 1223 | Buffer m; |
1224 | OM_uint32 major; | 1224 | OM_uint32 major; |
1225 | u_int len; | ||
1225 | 1226 | ||
1226 | buffer_init(&m); | 1227 | buffer_init(&m); |
1227 | buffer_put_string(&m, data->value, data->length); | 1228 | buffer_put_string(&m, data->value, data->length); |
@@ -1230,7 +1231,8 @@ mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) | |||
1230 | mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m); | 1231 | mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m); |
1231 | 1232 | ||
1232 | major = buffer_get_int(&m); | 1233 | major = buffer_get_int(&m); |
1233 | hash->value = buffer_get_string(&m, &hash->length); | 1234 | hash->value = buffer_get_string(&m, &len); |
1235 | hash->length = len; | ||
1234 | 1236 | ||
1235 | buffer_free(&m); | 1237 | buffer_free(&m); |
1236 | 1238 | ||
diff --git a/readconf.c b/readconf.c index 7933c5289..b3e14b9d2 100644 --- a/readconf.c +++ b/readconf.c | |||
@@ -109,6 +109,7 @@ typedef enum { | |||
109 | oClearAllForwardings, oNoHostAuthenticationForLocalhost, | 109 | oClearAllForwardings, oNoHostAuthenticationForLocalhost, |
110 | oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, | 110 | oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, |
111 | oAddressFamily, oGssAuthentication, oGssDelegateCreds, | 111 | oAddressFamily, oGssAuthentication, oGssDelegateCreds, |
112 | oGssTrustDns, | ||
112 | oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, | 113 | oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, |
113 | oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, | 114 | oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, |
114 | oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, | 115 | oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, |
@@ -146,9 +147,11 @@ static struct { | |||
146 | #if defined(GSSAPI) | 147 | #if defined(GSSAPI) |
147 | { "gssapiauthentication", oGssAuthentication }, | 148 | { "gssapiauthentication", oGssAuthentication }, |
148 | { "gssapidelegatecredentials", oGssDelegateCreds }, | 149 | { "gssapidelegatecredentials", oGssDelegateCreds }, |
150 | { "gssapitrustdns", oGssTrustDns }, | ||
149 | #else | 151 | #else |
150 | { "gssapiauthentication", oUnsupported }, | 152 | { "gssapiauthentication", oUnsupported }, |
151 | { "gssapidelegatecredentials", oUnsupported }, | 153 | { "gssapidelegatecredentials", oUnsupported }, |
154 | { "gssapitrustdns", oUnsupported }, | ||
152 | #endif | 155 | #endif |
153 | { "fallbacktorsh", oDeprecated }, | 156 | { "fallbacktorsh", oDeprecated }, |
154 | { "usersh", oDeprecated }, | 157 | { "usersh", oDeprecated }, |
@@ -423,6 +426,10 @@ parse_flag: | |||
423 | intptr = &options->gss_deleg_creds; | 426 | intptr = &options->gss_deleg_creds; |
424 | goto parse_flag; | 427 | goto parse_flag; |
425 | 428 | ||
429 | case oGssTrustDns: | ||
430 | intptr = &options->gss_trust_dns; | ||
431 | goto parse_flag; | ||
432 | |||
426 | case oBatchMode: | 433 | case oBatchMode: |
427 | intptr = &options->batch_mode; | 434 | intptr = &options->batch_mode; |
428 | goto parse_flag; | 435 | goto parse_flag; |
@@ -998,6 +1005,7 @@ initialize_options(Options * options) | |||
998 | options->challenge_response_authentication = -1; | 1005 | options->challenge_response_authentication = -1; |
999 | options->gss_authentication = -1; | 1006 | options->gss_authentication = -1; |
1000 | options->gss_deleg_creds = -1; | 1007 | options->gss_deleg_creds = -1; |
1008 | options->gss_trust_dns = -1; | ||
1001 | options->password_authentication = -1; | 1009 | options->password_authentication = -1; |
1002 | options->kbd_interactive_authentication = -1; | 1010 | options->kbd_interactive_authentication = -1; |
1003 | options->kbd_interactive_devices = NULL; | 1011 | options->kbd_interactive_devices = NULL; |
@@ -1087,6 +1095,8 @@ fill_default_options(Options * options) | |||
1087 | options->gss_authentication = 0; | 1095 | options->gss_authentication = 0; |
1088 | if (options->gss_deleg_creds == -1) | 1096 | if (options->gss_deleg_creds == -1) |
1089 | options->gss_deleg_creds = 0; | 1097 | options->gss_deleg_creds = 0; |
1098 | if (options->gss_trust_dns == -1) | ||
1099 | options->gss_trust_dns = 0; | ||
1090 | if (options->password_authentication == -1) | 1100 | if (options->password_authentication == -1) |
1091 | options->password_authentication = 1; | 1101 | options->password_authentication = 1; |
1092 | if (options->kbd_interactive_authentication == -1) | 1102 | if (options->kbd_interactive_authentication == -1) |
diff --git a/readconf.h b/readconf.h index 630895ee4..4639a74a4 100644 --- a/readconf.h +++ b/readconf.h | |||
@@ -46,6 +46,7 @@ typedef struct { | |||
46 | /* Try S/Key or TIS, authentication. */ | 46 | /* Try S/Key or TIS, authentication. */ |
47 | int gss_authentication; /* Try GSS authentication */ | 47 | int gss_authentication; /* Try GSS authentication */ |
48 | 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 */ | ||
49 | int password_authentication; /* Try password | 50 | int password_authentication; /* Try password |
50 | * authentication. */ | 51 | * authentication. */ |
51 | 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 81953bb80..219a0300f 100644 --- a/servconf.c +++ b/servconf.c | |||
@@ -72,6 +72,7 @@ initialize_server_options(ServerOptions *options) | |||
72 | options->kerberos_ticket_cleanup = -1; | 72 | options->kerberos_ticket_cleanup = -1; |
73 | options->kerberos_get_afs_token = -1; | 73 | options->kerberos_get_afs_token = -1; |
74 | options->gss_authentication=-1; | 74 | options->gss_authentication=-1; |
75 | options->gss_keyex = -1; | ||
75 | options->gss_cleanup_creds = -1; | 76 | options->gss_cleanup_creds = -1; |
76 | options->password_authentication = -1; | 77 | options->password_authentication = -1; |
77 | options->kbd_interactive_authentication = -1; | 78 | options->kbd_interactive_authentication = -1; |
@@ -187,6 +188,8 @@ fill_default_server_options(ServerOptions *options) | |||
187 | options->kerberos_get_afs_token = 0; | 188 | options->kerberos_get_afs_token = 0; |
188 | if (options->gss_authentication == -1) | 189 | if (options->gss_authentication == -1) |
189 | options->gss_authentication = 0; | 190 | options->gss_authentication = 0; |
191 | if (options->gss_keyex == -1) | ||
192 | options->gss_keyex = 0; | ||
190 | if (options->gss_cleanup_creds == -1) | 193 | if (options->gss_cleanup_creds == -1) |
191 | options->gss_cleanup_creds = 1; | 194 | options->gss_cleanup_creds = 1; |
192 | if (options->password_authentication == -1) | 195 | if (options->password_authentication == -1) |
@@ -273,7 +276,8 @@ typedef enum { | |||
273 | sBanner, sUseDNS, sHostbasedAuthentication, | 276 | sBanner, sUseDNS, sHostbasedAuthentication, |
274 | sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, | 277 | sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, |
275 | sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, | 278 | sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, |
276 | sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, | 279 | sGssAuthentication, sGssKeyEx, sGssCleanupCreds, |
280 | sAcceptEnv, sPermitTunnel, | ||
277 | sUsePrivilegeSeparation, | 281 | sUsePrivilegeSeparation, |
278 | sDeprecated, sUnsupported | 282 | sDeprecated, sUnsupported |
279 | } ServerOpCodes; | 283 | } ServerOpCodes; |
@@ -327,9 +331,11 @@ static struct { | |||
327 | { "afstokenpassing", sUnsupported }, | 331 | { "afstokenpassing", sUnsupported }, |
328 | #ifdef GSSAPI | 332 | #ifdef GSSAPI |
329 | { "gssapiauthentication", sGssAuthentication }, | 333 | { "gssapiauthentication", sGssAuthentication }, |
334 | { "gssapikeyexchange", sGssKeyEx }, | ||
330 | { "gssapicleanupcredentials", sGssCleanupCreds }, | 335 | { "gssapicleanupcredentials", sGssCleanupCreds }, |
331 | #else | 336 | #else |
332 | { "gssapiauthentication", sUnsupported }, | 337 | { "gssapiauthentication", sUnsupported }, |
338 | { "gssapikeyexchange", sUnsupported }, | ||
333 | { "gssapicleanupcredentials", sUnsupported }, | 339 | { "gssapicleanupcredentials", sUnsupported }, |
334 | #endif | 340 | #endif |
335 | { "passwordauthentication", sPasswordAuthentication }, | 341 | { "passwordauthentication", sPasswordAuthentication }, |
@@ -673,6 +679,10 @@ parse_flag: | |||
673 | intptr = &options->gss_authentication; | 679 | intptr = &options->gss_authentication; |
674 | goto parse_flag; | 680 | goto parse_flag; |
675 | 681 | ||
682 | case sGssKeyEx: | ||
683 | intptr = &options->gss_keyex; | ||
684 | goto parse_flag; | ||
685 | |||
676 | case sGssCleanupCreds: | 686 | case sGssCleanupCreds: |
677 | intptr = &options->gss_cleanup_creds; | 687 | intptr = &options->gss_cleanup_creds; |
678 | goto parse_flag; | 688 | goto parse_flag; |
diff --git a/servconf.h b/servconf.h index ab82c8f57..0ef05bcd9 100644 --- a/servconf.h +++ b/servconf.h | |||
@@ -88,6 +88,7 @@ typedef struct { | |||
88 | int kerberos_get_afs_token; /* If true, try to get AFS token if | 88 | int kerberos_get_afs_token; /* If true, try to get AFS token if |
89 | * authenticated with Kerberos. */ | 89 | * authenticated with Kerberos. */ |
90 | int gss_authentication; /* If true, permit GSSAPI authentication */ | 90 | int gss_authentication; /* If true, permit GSSAPI authentication */ |
91 | int gss_keyex; /* If true, permit GSSAPI key exchange */ | ||
91 | int gss_cleanup_creds; /* If true, destroy cred cache on logout */ | 92 | int gss_cleanup_creds; /* If true, destroy cred cache on logout */ |
92 | int password_authentication; /* If true, permit password | 93 | int password_authentication; /* If true, permit password |
93 | * authentication. */ | 94 | * authentication. */ |
@@ -67,7 +67,10 @@ | |||
67 | #define SSH2_MSG_KEXGSS_COMPLETE 32 | 67 | #define SSH2_MSG_KEXGSS_COMPLETE 32 |
68 | #define SSH2_MSG_KEXGSS_HOSTKEY 33 | 68 | #define SSH2_MSG_KEXGSS_HOSTKEY 33 |
69 | #define SSH2_MSG_KEXGSS_ERROR 34 | 69 | #define SSH2_MSG_KEXGSS_ERROR 34 |
70 | #define KEX_GSS_SHA1 "gss-group1-sha1-" | 70 | #define SSH2_MSG_KEXGSS_GROUPREQ 40 |
71 | #define SSH2_MSG_KEXGSS_GROUP 41 | ||
72 | #define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-" | ||
73 | #define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-" | ||
71 | 74 | ||
72 | typedef struct { | 75 | typedef struct { |
73 | char *filename; | 76 | char *filename; |
@@ -130,19 +133,19 @@ OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); | |||
130 | void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); | 133 | void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); |
131 | 134 | ||
132 | typedef int ssh_gssapi_check_fn(gss_OID, void *); | 135 | typedef int ssh_gssapi_check_fn(gss_OID, void *); |
133 | char *ssh_gssapi_client_mechanisms(char *host); | 136 | char *ssh_gssapi_client_mechanisms(const char *host); |
134 | char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, void *); | 137 | char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, void *); |
135 | int ssh_gssapi_check_mechanism(gss_OID, void *); | 138 | int ssh_gssapi_check_mechanism(gss_OID, void *); |
136 | gss_OID ssh_gssapi_id_kex(Gssctxt *, char *); | 139 | gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int *); |
137 | 140 | ||
138 | char *ssh_gssapi_server_mechanisms(void); | ||
139 | int ssh_gssapi_server_check_mech(gss_OID, void *); | 141 | int ssh_gssapi_server_check_mech(gss_OID, void *); |
140 | int ssh_gssapi_userok(char *name); | 142 | int ssh_gssapi_userok(char *name); |
141 | OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); | 143 | OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); |
142 | void ssh_gssapi_do_child(char ***, u_int *); | 144 | void ssh_gssapi_do_child(char ***, u_int *); |
143 | void ssh_gssapi_cleanup_creds(void); | 145 | void ssh_gssapi_cleanup_creds(void); |
144 | void ssh_gssapi_storecreds(void); | 146 | void ssh_gssapi_storecreds(void); |
145 | 147 | char * ssh_gssapi_server_mechanisms(void); | |
148 | int ssh_gssapi_oid_table_ok(); | ||
146 | #endif /* GSSAPI */ | 149 | #endif /* GSSAPI */ |
147 | 150 | ||
148 | #endif /* _SSH_GSS_H */ | 151 | #endif /* _SSH_GSS_H */ |
diff --git a/ssh_config.5 b/ssh_config.5 index 889def626..979f9282f 100644 --- a/ssh_config.5 +++ b/ssh_config.5 | |||
@@ -479,6 +479,16 @@ Forward (delegate) credentials to the server. | |||
479 | The default is | 479 | The default is |
480 | .Dq no . | 480 | .Dq no . |
481 | Note that this option applies to protocol version 2 only. | 481 | Note that this option applies to protocol version 2 only. |
482 | .It Cm GSSAPITrustDns | ||
483 | Set to | ||
484 | .Dq yes to indicate that the DNS is trusted to securely canonicalize | ||
485 | the name of the host being connected to. If | ||
486 | .Dq no, the hostname entered on the | ||
487 | command line will be passed untouched to the GSSAPI library. | ||
488 | The default is | ||
489 | .Dq no . | ||
490 | This option only applies to protocol version 2 connections using GSSAPI | ||
491 | key exchange. | ||
482 | .It Cm HashKnownHosts | 492 | .It Cm HashKnownHosts |
483 | Indicates that | 493 | Indicates that |
484 | .Nm ssh | 494 | .Nm ssh |
diff --git a/sshconnect2.c b/sshconnect2.c index 7ee71763a..3fb5df233 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -87,6 +87,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
87 | #ifdef GSSAPI | 87 | #ifdef GSSAPI |
88 | char *orig, *gss = NULL; | 88 | char *orig, *gss = NULL; |
89 | int len; | 89 | int len; |
90 | char *gss_host; | ||
90 | #endif | 91 | #endif |
91 | 92 | ||
92 | xxx_host = host; | 93 | xxx_host = host; |
@@ -94,10 +95,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
94 | 95 | ||
95 | #ifdef GSSAPI | 96 | #ifdef GSSAPI |
96 | if (options.gss_authentication) { | 97 | if (options.gss_authentication) { |
98 | /* Add the GSSAPI mechanisms currently supported on this | ||
99 | * client to the key exchange algorithm proposal */ | ||
97 | orig = myproposal[PROPOSAL_KEX_ALGS]; | 100 | orig = myproposal[PROPOSAL_KEX_ALGS]; |
98 | gss = ssh_gssapi_client_mechanisms(get_canonical_hostname(1)); | 101 | if (options.gss_trust_dns) |
99 | debug("Offering GSSAPI proposal: %s",gss); | 102 | gss_host = (char *)get_canonical_hostname(1); |
103 | else | ||
104 | gss_host = host; | ||
105 | |||
106 | gss = ssh_gssapi_client_mechanisms(gss_host); | ||
100 | if (gss) { | 107 | if (gss) { |
108 | debug("Offering GSSAPI proposal: %s", gss); | ||
101 | len = strlen(orig) + strlen(gss) + 2; | 109 | len = strlen(orig) + strlen(gss) + 2; |
102 | myproposal[PROPOSAL_KEX_ALGS] = xmalloc(len); | 110 | myproposal[PROPOSAL_KEX_ALGS] = xmalloc(len); |
103 | snprintf(myproposal[PROPOSAL_KEX_ALGS], len, "%s,%s", | 111 | snprintf(myproposal[PROPOSAL_KEX_ALGS], len, "%s,%s", |
@@ -134,6 +142,8 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
134 | options.hostkeyalgorithms; | 142 | options.hostkeyalgorithms; |
135 | 143 | ||
136 | #ifdef GSSAPI | 144 | #ifdef GSSAPI |
145 | /* If we've got GSSAPI algorithms, then we also support the | ||
146 | * 'null' hostkey, as a last resort */ | ||
137 | if (gss) { | 147 | if (gss) { |
138 | orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; | 148 | orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; |
139 | len = strlen(orig) + sizeof(",null"); | 149 | len = strlen(orig) + sizeof(",null"); |
@@ -152,8 +162,10 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
152 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; | 162 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; |
153 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; | 163 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; |
154 | #ifdef GSSAPI | 164 | #ifdef GSSAPI |
155 | if (options.gss_authentication) | 165 | if (options.gss_authentication) { |
156 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; | 166 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; |
167 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; | ||
168 | } | ||
157 | #endif | 169 | #endif |
158 | kex->client_version_string=client_version_string; | 170 | kex->client_version_string=client_version_string; |
159 | kex->server_version_string=server_version_string; | 171 | kex->server_version_string=server_version_string; |
@@ -161,6 +173,8 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
161 | 173 | ||
162 | #ifdef GSSAPI | 174 | #ifdef GSSAPI |
163 | kex->gss_deleg_creds = options.gss_deleg_creds; | 175 | kex->gss_deleg_creds = options.gss_deleg_creds; |
176 | kex->gss_trust_dns = options.gss_trust_dns; | ||
177 | kex->gss_host = gss_host; | ||
164 | #endif | 178 | #endif |
165 | 179 | ||
166 | xxx_kex = kex; | 180 | xxx_kex = kex; |
@@ -245,7 +259,7 @@ void input_gssapi_token(int type, u_int32_t, void *); | |||
245 | void input_gssapi_hash(int type, u_int32_t, void *); | 259 | void input_gssapi_hash(int type, u_int32_t, void *); |
246 | void input_gssapi_error(int, u_int32_t, void *); | 260 | void input_gssapi_error(int, u_int32_t, void *); |
247 | void input_gssapi_errtok(int, u_int32_t, void *); | 261 | void input_gssapi_errtok(int, u_int32_t, void *); |
248 | int userauth_gsskeyx(Authctxt *authctxt); | 262 | int userauth_gsskeyex(Authctxt *authctxt); |
249 | #endif | 263 | #endif |
250 | 264 | ||
251 | void userauth(Authctxt *, char *); | 265 | void userauth(Authctxt *, char *); |
@@ -261,8 +275,8 @@ static char *authmethods_get(void); | |||
261 | 275 | ||
262 | Authmethod authmethods[] = { | 276 | Authmethod authmethods[] = { |
263 | #ifdef GSSAPI | 277 | #ifdef GSSAPI |
264 | {"gssapi-keyx", | 278 | {"gssapi-keyex", |
265 | userauth_gsskeyx, | 279 | userauth_gsskeyex, |
266 | &options.gss_authentication, | 280 | &options.gss_authentication, |
267 | NULL}, | 281 | NULL}, |
268 | {"gssapi-with-mic", | 282 | {"gssapi-with-mic", |
@@ -775,10 +789,11 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) | |||
775 | } | 789 | } |
776 | 790 | ||
777 | int | 791 | int |
778 | userauth_gsskeyx(Authctxt *authctxt) | 792 | userauth_gsskeyex(Authctxt *authctxt) |
779 | { | 793 | { |
780 | Buffer b; | 794 | Buffer b; |
781 | gss_buffer_desc gssbuf, mic; | 795 | gss_buffer_desc gssbuf; |
796 | gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; | ||
782 | OM_uint32 ms; | 797 | OM_uint32 ms; |
783 | 798 | ||
784 | static int attempt = 0; | 799 | static int attempt = 0; |
@@ -86,6 +86,10 @@ RCSID("$OpenBSD: sshd.c,v 1.318 2005/12/24 02:27:41 djm Exp $"); | |||
86 | #include "monitor_wrap.h" | 86 | #include "monitor_wrap.h" |
87 | #include "monitor_fdpass.h" | 87 | #include "monitor_fdpass.h" |
88 | 88 | ||
89 | #ifdef USE_SECURITY_SESSION_API | ||
90 | #include <Security/AuthSession.h> | ||
91 | #endif | ||
92 | |||
89 | #ifdef LIBWRAP | 93 | #ifdef LIBWRAP |
90 | #include <tcpd.h> | 94 | #include <tcpd.h> |
91 | #include <syslog.h> | 95 | #include <syslog.h> |
@@ -1129,6 +1133,7 @@ main(int ac, char **av) | |||
1129 | options.protocol &= ~SSH_PROTO_1; | 1133 | options.protocol &= ~SSH_PROTO_1; |
1130 | } | 1134 | } |
1131 | #ifndef GSSAPI | 1135 | #ifndef GSSAPI |
1136 | /* The GSSAPI key exchange can run without a host key */ | ||
1132 | if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { | 1137 | if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { |
1133 | logit("Disabling protocol version 2. Could not load host key"); | 1138 | logit("Disabling protocol version 2. Could not load host key"); |
1134 | options.protocol &= ~SSH_PROTO_2; | 1139 | options.protocol &= ~SSH_PROTO_2; |
@@ -1681,6 +1686,60 @@ main(int ac, char **av) | |||
1681 | /* Log the connection. */ | 1686 | /* Log the connection. */ |
1682 | verbose("Connection from %.500s port %d", remote_ip, remote_port); | 1687 | verbose("Connection from %.500s port %d", remote_ip, remote_port); |
1683 | 1688 | ||
1689 | #ifdef USE_SECURITY_SESSION_API | ||
1690 | /* | ||
1691 | * Create a new security session for use by the new user login if | ||
1692 | * the current session is the root session or we are not launched | ||
1693 | * by inetd (eg: debugging mode or server mode). We do not | ||
1694 | * necessarily need to create a session if we are launched from | ||
1695 | * inetd because Panther xinetd will create a session for us. | ||
1696 | * | ||
1697 | * The only case where this logic will fail is if there is an | ||
1698 | * inetd running in a non-root session which is not creating | ||
1699 | * new sessions for us. Then all the users will end up in the | ||
1700 | * same session (bad). | ||
1701 | * | ||
1702 | * When the client exits, the session will be destroyed for us | ||
1703 | * automatically. | ||
1704 | * | ||
1705 | * We must create the session before any credentials are stored | ||
1706 | * (including AFS pags, which happens a few lines below). | ||
1707 | */ | ||
1708 | { | ||
1709 | OSStatus err = 0; | ||
1710 | SecuritySessionId sid = 0; | ||
1711 | SessionAttributeBits sattrs = 0; | ||
1712 | |||
1713 | err = SessionGetInfo(callerSecuritySession, &sid, &sattrs); | ||
1714 | if (err) | ||
1715 | error("SessionGetInfo() failed with error %.8X", | ||
1716 | (unsigned) err); | ||
1717 | else | ||
1718 | debug("Current Session ID is %.8X / Session Attributes are %.8X", | ||
1719 | (unsigned) sid, (unsigned) sattrs); | ||
1720 | |||
1721 | if (inetd_flag && !(sattrs & sessionIsRoot)) | ||
1722 | debug("Running in inetd mode in a non-root session... " | ||
1723 | "assuming inetd created the session for us."); | ||
1724 | else { | ||
1725 | debug("Creating new security session..."); | ||
1726 | err = SessionCreate(0, sessionHasTTY | sessionIsRemote); | ||
1727 | if (err) | ||
1728 | error("SessionCreate() failed with error %.8X", | ||
1729 | (unsigned) err); | ||
1730 | |||
1731 | err = SessionGetInfo(callerSecuritySession, &sid, | ||
1732 | &sattrs); | ||
1733 | if (err) | ||
1734 | error("SessionGetInfo() failed with error %.8X", | ||
1735 | (unsigned) err); | ||
1736 | else | ||
1737 | debug("New Session ID is %.8X / Session Attributes are %.8X", | ||
1738 | (unsigned) sid, (unsigned) sattrs); | ||
1739 | } | ||
1740 | } | ||
1741 | #endif | ||
1742 | |||
1684 | /* | 1743 | /* |
1685 | * We don't want to listen forever unless the other side | 1744 | * We don't want to listen forever unless the other side |
1686 | * successfully authenticates itself. So we set up an alarm which is | 1745 | * successfully authenticates itself. So we set up an alarm which is |
@@ -2051,7 +2110,10 @@ do_ssh2_kex(void) | |||
2051 | if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) | 2110 | if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) |
2052 | orig = NULL; | 2111 | orig = NULL; |
2053 | 2112 | ||
2054 | gss = ssh_gssapi_server_mechanisms(); | 2113 | if (options.gss_keyex) |
2114 | gss = ssh_gssapi_server_mechanisms(); | ||
2115 | else | ||
2116 | gss = NULL; | ||
2055 | 2117 | ||
2056 | if (gss && orig) { | 2118 | if (gss && orig) { |
2057 | int len = strlen(orig) + strlen(gss) + 2; | 2119 | int len = strlen(orig) + strlen(gss) + 2; |
@@ -2084,6 +2146,7 @@ do_ssh2_kex(void) | |||
2084 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; | 2146 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; |
2085 | #ifdef GSSAPI | 2147 | #ifdef GSSAPI |
2086 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; | 2148 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; |
2149 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; | ||
2087 | #endif | 2150 | #endif |
2088 | kex->server = 1; | 2151 | kex->server = 1; |
2089 | kex->client_version_string=client_version_string; | 2152 | kex->client_version_string=client_version_string; |
diff --git a/sshd_config.5 b/sshd_config.5 index 71a293ffb..841cb29d3 100644 --- a/sshd_config.5 +++ b/sshd_config.5 | |||
@@ -277,6 +277,12 @@ Specifies whether user authentication based on GSSAPI is allowed. | |||
277 | The default is | 277 | The default is |
278 | .Dq no . | 278 | .Dq no . |
279 | Note that this option applies to protocol version 2 only. | 279 | Note that this option applies to protocol version 2 only. |
280 | .It Cm GSSAPIKeyExchange | ||
281 | Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange | ||
282 | doesn't rely on ssh keys to verify host identity. | ||
283 | The default is | ||
284 | .Dq no . | ||
285 | Note that this option applies to protocol version 2 only. | ||
280 | .It Cm GSSAPICleanupCredentials | 286 | .It Cm GSSAPICleanupCredentials |
281 | Specifies whether to automatically destroy the user's credentials cache | 287 | Specifies whether to automatically destroy the user's credentials cache |
282 | on logout. | 288 | on logout. |