summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--auth-krb5.c17
-rw-r--r--auth.h1
-rw-r--r--auth2-gss.c4
-rw-r--r--auth2.c5
-rw-r--r--config.h.in9
-rwxr-xr-xconfigure117
-rw-r--r--configure.ac24
-rw-r--r--debian/changelog3
-rw-r--r--gss-genr.c47
-rw-r--r--gss-serv.c15
-rw-r--r--kex.c8
-rw-r--r--kex.h5
-rw-r--r--kexgssc.c159
-rw-r--r--kexgsss.c110
-rw-r--r--monitor.c8
-rw-r--r--monitor_wrap.c4
-rw-r--r--readconf.c10
-rw-r--r--readconf.h1
-rw-r--r--servconf.c12
-rw-r--r--servconf.h1
-rw-r--r--ssh-gss.h13
-rw-r--r--ssh_config.510
-rw-r--r--sshconnect2.c31
-rw-r--r--sshd.c65
-rw-r--r--sshd_config.56
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
210krb5_error_code 215krb5_error_code
211ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { 216ssh_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}
diff --git a/auth.h b/auth.h
index f3a31c446..267e7b022 100644
--- a/auth.h
+++ b/auth.h
@@ -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
320Authmethod method_gsskeyex = { 322Authmethod method_gsskeyex = {
321 "gssapi-keyx", 323 "gssapi-keyex",
322 userauth_gsskeyex, 324 userauth_gsskeyex,
323 &options.gss_authentication 325 &options.gss_authentication
324}; 326};
diff --git a/auth2.c b/auth2.c
index f12440815..a67449db5 100644
--- a/auth2.c
+++ b/auth2.c
@@ -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
diff --git a/configure b/configure
index 552acba68..271904359 100755
--- a/configure
+++ b/configure
@@ -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
5261echo $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
5265cat confdefs.h >>conftest.$ac_ext
5266cat >>conftest.$ac_ext <<_ACEOF
5267/* end confdefs.h. */
5268#include <Security/AuthSession.h>
5269int
5270main ()
5271{
5272SessionCreate(0, 0);
5273 ;
5274 return 0;
5275}
5276_ACEOF
5277rm -f conftest.$ac_objext
5278if { (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
5300cat >>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
5306echo "${ECHO_T}yes" >&6
5307else
5308 echo "$as_me: failed program was:" >&5
5309sed 's/^/| /' conftest.$ac_ext >&5
5310
5311ac_cv_use_security_session_api="no"
5312 echo "$as_me:$LINENO: result: no" >&5
5313echo "${ECHO_T}no" >&6
5314fi
5315rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
5316 echo "$as_me:$LINENO: checking if we have an in-memory credentials cache" >&5
5317echo $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
5321cat confdefs.h >>conftest.$ac_ext
5322cat >>conftest.$ac_ext <<_ACEOF
5323/* end confdefs.h. */
5324#include <Kerberos/Kerberos.h>
5325int
5326main ()
5327{
5328cc_context_t c;
5329 (void) cc_initialize (&c, 0, NULL, NULL);
5330 ;
5331 return 0;
5332}
5333_ACEOF
5334rm -f conftest.$ac_objext
5335if { (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
5356cat >>confdefs.h <<\_ACEOF
5357#define USE_CCAPI 1
5358_ACEOF
5359
5360 LIBS="$LIBS -framework Security"
5361 echo "$as_me:$LINENO: result: yes" >&5
5362echo "${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
5365echo "$as_me: error: *** Need a security framework to use the credentials cache API ***" >&2;}
5366 { (exit 1); exit 1; }; }
5367 fi
5368else
5369 echo "$as_me: failed program was:" >&5
5370sed 's/^/| /' conftest.$ac_ext >&5
5371
5372echo "$as_me:$LINENO: result: no" >&5
5373echo "${ECHO_T}no" >&6
5374
5375fi
5376rm -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
54static ssh_gss_kex_mapping *gss_enc2oid = NULL; 54static ssh_gss_kex_mapping *gss_enc2oid = NULL;
55 55
56int
57ssh_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
64char * 69char *
65ssh_gssapi_client_mechanisms(char *host) { 70ssh_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
146gss_OID 154gss_OID
147ssh_gssapi_id_kex(Gssctxt *ctx, char *name) { 155ssh_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 */
71int 72int
72ssh_gssapi_server_check_mech(gss_OID oid, void *data) { 73ssh_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 */
319OM_uint32
320ssh_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
diff --git a/kex.c b/kex.c
index e0b9d5872..47983f8d9 100644
--- a/kex.c
+++ b/kex.c
@@ -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
diff --git a/kex.h b/kex.h
index 370e3e873..1c4d1a718 100644
--- a/kex.h
+++ b/kex.h
@@ -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;
diff --git a/kexgssc.c b/kexgssc.c
index eee96dd23..9830ad384 100644
--- a/kexgssc.c
+++ b/kexgssc.c
@@ -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
43void 43void
44kexgss_client(Kex *kex) { 44kexgss_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}
diff --git a/kexgsss.c b/kexgsss.c
index 80c133ac9..6447dc97b 100644
--- a/kexgsss.c
+++ b/kexgsss.c
@@ -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}
diff --git a/monitor.c b/monitor.c
index e9693ef63..fbb15312e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -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)
1942int 1943int
1943mm_answer_gss_sign(int socket, Buffer *m) 1944mm_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. */
diff --git a/ssh-gss.h b/ssh-gss.h
index e5699baf3..213930103 100644
--- a/ssh-gss.h
+++ b/ssh-gss.h
@@ -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
72typedef struct { 75typedef struct {
73 char *filename; 76 char *filename;
@@ -130,19 +133,19 @@ OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
130void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); 133void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
131 134
132typedef int ssh_gssapi_check_fn(gss_OID, void *); 135typedef int ssh_gssapi_check_fn(gss_OID, void *);
133char *ssh_gssapi_client_mechanisms(char *host); 136char *ssh_gssapi_client_mechanisms(const char *host);
134char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, void *); 137char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, void *);
135int ssh_gssapi_check_mechanism(gss_OID, void *); 138int ssh_gssapi_check_mechanism(gss_OID, void *);
136gss_OID ssh_gssapi_id_kex(Gssctxt *, char *); 139gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int *);
137 140
138char *ssh_gssapi_server_mechanisms(void);
139int ssh_gssapi_server_check_mech(gss_OID, void *); 141int ssh_gssapi_server_check_mech(gss_OID, void *);
140int ssh_gssapi_userok(char *name); 142int ssh_gssapi_userok(char *name);
141OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 143OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
142void ssh_gssapi_do_child(char ***, u_int *); 144void ssh_gssapi_do_child(char ***, u_int *);
143void ssh_gssapi_cleanup_creds(void); 145void ssh_gssapi_cleanup_creds(void);
144void ssh_gssapi_storecreds(void); 146void ssh_gssapi_storecreds(void);
145 147char * ssh_gssapi_server_mechanisms(void);
148int 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.
479The default is 479The default is
480.Dq no . 480.Dq no .
481Note that this option applies to protocol version 2 only. 481Note that this option applies to protocol version 2 only.
482.It Cm GSSAPITrustDns
483Set to
484.Dq yes to indicate that the DNS is trusted to securely canonicalize
485the name of the host being connected to. If
486.Dq no, the hostname entered on the
487command line will be passed untouched to the GSSAPI library.
488The default is
489.Dq no .
490This option only applies to protocol version 2 connections using GSSAPI
491key exchange.
482.It Cm HashKnownHosts 492.It Cm HashKnownHosts
483Indicates that 493Indicates 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 *);
245void input_gssapi_hash(int type, u_int32_t, void *); 259void input_gssapi_hash(int type, u_int32_t, void *);
246void input_gssapi_error(int, u_int32_t, void *); 260void input_gssapi_error(int, u_int32_t, void *);
247void input_gssapi_errtok(int, u_int32_t, void *); 261void input_gssapi_errtok(int, u_int32_t, void *);
248int userauth_gsskeyx(Authctxt *authctxt); 262int userauth_gsskeyex(Authctxt *authctxt);
249#endif 263#endif
250 264
251void userauth(Authctxt *, char *); 265void userauth(Authctxt *, char *);
@@ -261,8 +275,8 @@ static char *authmethods_get(void);
261 275
262Authmethod authmethods[] = { 276Authmethod 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
777int 791int
778userauth_gsskeyx(Authctxt *authctxt) 792userauth_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;
diff --git a/sshd.c b/sshd.c
index df6d1e374..85b679d5e 100644
--- a/sshd.c
+++ b/sshd.c
@@ -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.
277The default is 277The default is
278.Dq no . 278.Dq no .
279Note that this option applies to protocol version 2 only. 279Note that this option applies to protocol version 2 only.
280.It Cm GSSAPIKeyExchange
281Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
282doesn't rely on ssh keys to verify host identity.
283The default is
284.Dq no .
285Note that this option applies to protocol version 2 only.
280.It Cm GSSAPICleanupCredentials 286.It Cm GSSAPICleanupCredentials
281Specifies whether to automatically destroy the user's credentials cache 287Specifies whether to automatically destroy the user's credentials cache
282on logout. 288on logout.