summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in4
-rw-r--r--auth-krb5.c17
-rw-r--r--auth.h1
-rw-r--r--auth2-gss.c41
-rw-r--r--auth2.c7
-rw-r--r--config.h.in6
-rwxr-xr-xconfigure123
-rw-r--r--configure.ac24
-rw-r--r--gss-genr.c173
-rw-r--r--gss-serv.c33
-rw-r--r--kex.c14
-rw-r--r--kex.h12
-rw-r--r--kexgssc.c303
-rw-r--r--kexgsss.c256
-rw-r--r--key.c2
-rw-r--r--key.h1
-rw-r--r--monitor.c58
-rw-r--r--monitor.h1
-rw-r--r--monitor_wrap.c23
-rw-r--r--monitor_wrap.h1
-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.h22
-rw-r--r--ssh_config.510
-rw-r--r--sshconnect2.c94
-rw-r--r--sshd.c121
-rw-r--r--sshd_config.56
29 files changed, 1351 insertions, 26 deletions
diff --git a/Makefile.in b/Makefile.in
index af881c521..f1b45cdde 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -71,7 +71,7 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o buffer.o \
71 atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ 71 atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
72 monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \ 72 monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \
73 kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \ 73 kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \
74 entropy.o scard-opensc.o gss-genr.o 74 entropy.o scard-opensc.o gss-genr.o kexgssc.o
75 75
76SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ 76SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
77 sshconnect.o sshconnect1.o sshconnect2.o 77 sshconnect.o sshconnect1.o sshconnect2.o
@@ -84,7 +84,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
84 auth2-none.o auth2-passwd.o auth2-pubkey.o \ 84 auth2-none.o auth2-passwd.o auth2-pubkey.o \
85 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \ 85 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \
86 auth-krb5.o \ 86 auth-krb5.o \
87 auth2-gss.o gss-serv.o gss-serv-krb5.o \ 87 auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\
88 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ 88 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
89 audit.o audit-bsm.o 89 audit.o audit-bsm.o
90 90
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 8b814ba6a..456d28f37 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 95844a05e..539654ee0 100644
--- a/auth2-gss.c
+++ b/auth2-gss.c
@@ -46,6 +46,39 @@ static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
46static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); 46static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
47static void input_gssapi_errtok(int, u_int32_t, void *); 47static void input_gssapi_errtok(int, u_int32_t, void *);
48 48
49/*
50 * The 'gssapi_keyex' userauth mechanism.
51 */
52static int
53userauth_gsskeyex(Authctxt *authctxt)
54{
55 int authenticated = 0;
56 Buffer b;
57 gss_buffer_desc mic, gssbuf;
58 u_int len;
59
60 mic.value = packet_get_string(&len);
61 mic.length = len;
62
63 packet_check_eom();
64
65 ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
66 "gssapi-keyex");
67
68 gssbuf.value = buffer_ptr(&b);
69 gssbuf.length = buffer_len(&b);
70
71 /* gss_kex_context is NULL with privsep, so we can't check it here */
72 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
73 &gssbuf, &mic))))
74 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
75
76 buffer_free(&b);
77 xfree(mic.value);
78
79 return (authenticated);
80}
81
49/* 82/*
50 * We only support those mechanisms that we know about (ie ones that we know 83 * We only support those mechanisms that we know about (ie ones that we know
51 * how to check local user kuserok and the like) 84 * how to check local user kuserok and the like)
@@ -96,11 +129,13 @@ userauth_gssapi(Authctxt *authctxt)
96 129
97 if (!present) { 130 if (!present) {
98 xfree(doid); 131 xfree(doid);
132 authctxt->server_caused_failure = 1;
99 return (0); 133 return (0);
100 } 134 }
101 135
102 if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) { 136 if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) {
103 xfree(doid); 137 xfree(doid);
138 authctxt->server_caused_failure = 1;
104 return (0); 139 return (0);
105 } 140 }
106 141
@@ -284,6 +319,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
284 userauth_finish(authctxt, authenticated, "gssapi-with-mic"); 319 userauth_finish(authctxt, authenticated, "gssapi-with-mic");
285} 320}
286 321
322Authmethod method_gsskeyex = {
323 "gssapi-keyex",
324 userauth_gsskeyex,
325 &options.gss_authentication
326};
327
287Authmethod method_gssapi = { 328Authmethod method_gssapi = {
288 "gssapi-with-mic", 329 "gssapi-with-mic",
289 userauth_gssapi, 330 userauth_gssapi,
diff --git a/auth2.c b/auth2.c
index d255242ed..6e58797bd 100644
--- a/auth2.c
+++ b/auth2.c
@@ -55,6 +55,7 @@ extern Authmethod method_passwd;
55extern Authmethod method_kbdint; 55extern Authmethod method_kbdint;
56extern Authmethod method_hostbased; 56extern Authmethod method_hostbased;
57#ifdef GSSAPI 57#ifdef GSSAPI
58extern Authmethod method_gsskeyex;
58extern Authmethod method_gssapi; 59extern Authmethod method_gssapi;
59#endif 60#endif
60 61
@@ -62,6 +63,7 @@ Authmethod *authmethods[] = {
62 &method_none, 63 &method_none,
63 &method_pubkey, 64 &method_pubkey,
64#ifdef GSSAPI 65#ifdef GSSAPI
66 &method_gsskeyex,
65 &method_gssapi, 67 &method_gssapi,
66#endif 68#endif
67 &method_passwd, 69 &method_passwd,
@@ -188,6 +190,7 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
188#endif 190#endif
189 191
190 authctxt->postponed = 0; 192 authctxt->postponed = 0;
193 authctxt->server_caused_failure = 0;
191 194
192 /* try to authenticate user */ 195 /* try to authenticate user */
193 m = authmethod_lookup(method); 196 m = authmethod_lookup(method);
@@ -258,7 +261,9 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method)
258 /* now we can break out */ 261 /* now we can break out */
259 authctxt->success = 1; 262 authctxt->success = 1;
260 } else { 263 } else {
261 if (authctxt->failures++ > options.max_authtries) { 264 /* Dont count server configuration issues against the client */
265 if (!authctxt->server_caused_failure &&
266 authctxt->failures++ > options.max_authtries) {
262#ifdef SSH_AUDIT_EVENTS 267#ifdef SSH_AUDIT_EVENTS
263 PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); 268 PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
264#endif 269#endif
diff --git a/config.h.in b/config.h.in
index 4dd4f0878..3101aba54 100644
--- a/config.h.in
+++ b/config.h.in
@@ -1213,6 +1213,9 @@
1213/* Use btmp to log bad logins */ 1213/* Use btmp to log bad logins */
1214#undef USE_BTMP 1214#undef USE_BTMP
1215 1215
1216/* platform uses an in-memory credentials cache */
1217#undef USE_CCAPI
1218
1216/* Use libedit for sftp */ 1219/* Use libedit for sftp */
1217#undef USE_LIBEDIT 1220#undef USE_LIBEDIT
1218 1221
@@ -1228,6 +1231,9 @@
1228/* Define if you want smartcard support using sectok */ 1231/* Define if you want smartcard support using sectok */
1229#undef USE_SECTOK 1232#undef USE_SECTOK
1230 1233
1234/* platform has the Security Authorization Session API */
1235#undef USE_SECURITY_SESSION_API
1236
1231/* Define if you shouldn't strip 'tty' from your ttyname in [uw]tmp */ 1237/* Define if you shouldn't strip 'tty' from your ttyname in [uw]tmp */
1232#undef WITH_ABBREV_NO_TTY 1238#undef WITH_ABBREV_NO_TTY
1233 1239
diff --git a/configure b/configure
index 5a5e162bd..de1d8e81e 100755
--- a/configure
+++ b/configure
@@ -5285,6 +5285,125 @@ cat >>confdefs.h <<_ACEOF
5285#define BIND_8_COMPAT 1 5285#define BIND_8_COMPAT 1
5286_ACEOF 5286_ACEOF
5287 5287
5288 echo "$as_me:$LINENO: checking if we have the Security Authorization Session API" >&5
5289echo $ECHO_N "checking if we have the Security Authorization Session API... $ECHO_C" >&6
5290 cat >conftest.$ac_ext <<_ACEOF
5291/* confdefs.h. */
5292_ACEOF
5293cat confdefs.h >>conftest.$ac_ext
5294cat >>conftest.$ac_ext <<_ACEOF
5295/* end confdefs.h. */
5296#include <Security/AuthSession.h>
5297int
5298main ()
5299{
5300SessionCreate(0, 0);
5301 ;
5302 return 0;
5303}
5304_ACEOF
5305rm -f conftest.$ac_objext
5306if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
5307 (eval $ac_compile) 2>conftest.er1
5308 ac_status=$?
5309 grep -v '^ *+' conftest.er1 >conftest.err
5310 rm -f conftest.er1
5311 cat conftest.err >&5
5312 echo "$as_me:$LINENO: \$? = $ac_status" >&5
5313 (exit $ac_status); } &&
5314 { ac_try='test -z "$ac_c_werror_flag"
5315 || test ! -s conftest.err'
5316 { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
5317 (eval $ac_try) 2>&5
5318 ac_status=$?
5319 echo "$as_me:$LINENO: \$? = $ac_status" >&5
5320 (exit $ac_status); }; } &&
5321 { ac_try='test -s conftest.$ac_objext'
5322 { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
5323 (eval $ac_try) 2>&5
5324 ac_status=$?
5325 echo "$as_me:$LINENO: \$? = $ac_status" >&5
5326 (exit $ac_status); }; }; then
5327 ac_cv_use_security_session_api="yes"
5328
5329cat >>confdefs.h <<\_ACEOF
5330#define USE_SECURITY_SESSION_API 1
5331_ACEOF
5332
5333 LIBS="$LIBS -framework Security"
5334 echo "$as_me:$LINENO: result: yes" >&5
5335echo "${ECHO_T}yes" >&6
5336else
5337 echo "$as_me: failed program was:" >&5
5338sed 's/^/| /' conftest.$ac_ext >&5
5339
5340ac_cv_use_security_session_api="no"
5341 echo "$as_me:$LINENO: result: no" >&5
5342echo "${ECHO_T}no" >&6
5343fi
5344rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
5345 echo "$as_me:$LINENO: checking if we have an in-memory credentials cache" >&5
5346echo $ECHO_N "checking if we have an in-memory credentials cache... $ECHO_C" >&6
5347 cat >conftest.$ac_ext <<_ACEOF
5348/* confdefs.h. */
5349_ACEOF
5350cat confdefs.h >>conftest.$ac_ext
5351cat >>conftest.$ac_ext <<_ACEOF
5352/* end confdefs.h. */
5353#include <Kerberos/Kerberos.h>
5354int
5355main ()
5356{
5357cc_context_t c;
5358 (void) cc_initialize (&c, 0, NULL, NULL);
5359 ;
5360 return 0;
5361}
5362_ACEOF
5363rm -f conftest.$ac_objext
5364if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
5365 (eval $ac_compile) 2>conftest.er1
5366 ac_status=$?
5367 grep -v '^ *+' conftest.er1 >conftest.err
5368 rm -f conftest.er1
5369 cat conftest.err >&5
5370 echo "$as_me:$LINENO: \$? = $ac_status" >&5
5371 (exit $ac_status); } &&
5372 { ac_try='test -z "$ac_c_werror_flag"
5373 || test ! -s conftest.err'
5374 { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
5375 (eval $ac_try) 2>&5
5376 ac_status=$?
5377 echo "$as_me:$LINENO: \$? = $ac_status" >&5
5378 (exit $ac_status); }; } &&
5379 { ac_try='test -s conftest.$ac_objext'
5380 { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
5381 (eval $ac_try) 2>&5
5382 ac_status=$?
5383 echo "$as_me:$LINENO: \$? = $ac_status" >&5
5384 (exit $ac_status); }; }; then
5385
5386cat >>confdefs.h <<\_ACEOF
5387#define USE_CCAPI 1
5388_ACEOF
5389
5390 LIBS="$LIBS -framework Security"
5391 echo "$as_me:$LINENO: result: yes" >&5
5392echo "${ECHO_T}yes" >&6
5393 if test "x$ac_cv_use_security_session_api" = "xno"; then
5394 { { echo "$as_me:$LINENO: error: *** Need a security framework to use the credentials cache API ***" >&5
5395echo "$as_me: error: *** Need a security framework to use the credentials cache API ***" >&2;}
5396 { (exit 1); exit 1; }; }
5397 fi
5398else
5399 echo "$as_me: failed program was:" >&5
5400sed 's/^/| /' conftest.$ac_ext >&5
5401
5402echo "$as_me:$LINENO: result: no" >&5
5403echo "${ECHO_T}no" >&6
5404
5405fi
5406rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
5288 ;; 5407 ;;
5289*-*-hpux*) 5408*-*-hpux*)
5290 # first we define all of the options common to all HP-UX releases 5409 # first we define all of the options common to all HP-UX releases
@@ -27224,9 +27343,9 @@ exec 6>&1
27224exec 5>>config.log 27343exec 5>>config.log
27225{ 27344{
27226 echo 27345 echo
27227 sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<BOXI_EOF 27346 sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
27228## Running $as_me. ## 27347## Running $as_me. ##
27229BOXI_EOF 27348_ASBOX
27230} >&5 27349} >&5
27231cat >&5 <<_CSEOF 27350cat >&5 <<_CSEOF
27232 27351
diff --git a/configure.ac b/configure.ac
index ff1972ed6..cfaaca92d 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/gss-genr.c b/gss-genr.c
index c2b4f2dd8..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
@@ -32,12 +32,152 @@
32#include "bufaux.h" 32#include "bufaux.h"
33#include "log.h" 33#include "log.h"
34#include "ssh2.h" 34#include "ssh2.h"
35#include <openssl/evp.h>
35 36
36#include "ssh-gss.h" 37#include "ssh-gss.h"
37 38
38extern u_char *session_id2; 39extern u_char *session_id2;
39extern u_int session_id2_len; 40extern u_int session_id2_len;
40 41
42typedef struct {
43 char *encoded;
44 gss_OID oid;
45} ssh_gss_kex_mapping;
46
47/*
48 * XXX - It would be nice to find a more elegant way of handling the
49 * XXX passing of the key exchange context to the userauth routines
50 */
51
52Gssctxt *gss_kex_context = NULL;
53
54static ssh_gss_kex_mapping *gss_enc2oid = NULL;
55
56int
57ssh_gssapi_oid_table_ok() {
58 return (gss_enc2oid != NULL);
59}
60
61/*
62 * Return a list of the gss-group1-sha1 mechanisms supported by this program
63 *
64 * We test mechanisms to ensure that we can use them, to avoid starting
65 * a key exchange with a bad mechanism
66 */
67
68
69char *
70ssh_gssapi_client_mechanisms(const char *host) {
71 gss_OID_set gss_supported;
72 OM_uint32 min_status;
73
74 gss_indicate_mechs(&min_status, &gss_supported);
75
76 return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
77 (void *)host));
78}
79
80char *
81ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
82 void *data) {
83 Buffer buf;
84 int i, oidpos, enclen;
85 char *mechs, *encoded;
86 char digest[EVP_MAX_MD_SIZE];
87 char deroid[2];
88 const EVP_MD *evp_md = EVP_md5();
89 EVP_MD_CTX md;
90
91 if (gss_enc2oid != NULL) {
92 for (i=0;gss_enc2oid[i].encoded!=NULL;i++)
93 xfree(gss_enc2oid[i].encoded);
94 xfree(gss_enc2oid);
95 }
96
97 gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping)*
98 (gss_supported->count+1));
99
100 buffer_init(&buf);
101
102 oidpos = 0;
103 for (i = 0;i < gss_supported->count;i++) {
104 if (gss_supported->elements[i].length < 128 &&
105 (*check)(&(gss_supported->elements[i]), data)) {
106
107 deroid[0] = SSH_GSS_OIDTYPE;
108 deroid[1] = gss_supported->elements[i].length;
109
110 EVP_DigestInit(&md, evp_md);
111 EVP_DigestUpdate(&md, deroid, 2);
112 EVP_DigestUpdate(&md,
113 gss_supported->elements[i].elements,
114 gss_supported->elements[i].length);
115 EVP_DigestFinal(&md, digest, NULL);
116
117 encoded = xmalloc(EVP_MD_size(evp_md)*2);
118 enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
119 encoded, EVP_MD_size(evp_md)*2);
120
121 if (oidpos != 0)
122 buffer_put_char(&buf, ',');
123
124 buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
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);
130 buffer_append(&buf, encoded, enclen);
131
132 gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
133 gss_enc2oid[oidpos].encoded = encoded;
134 oidpos++;
135 }
136 }
137 gss_enc2oid[oidpos].oid = NULL;
138 gss_enc2oid[oidpos].encoded = NULL;
139
140 buffer_put_char(&buf, '\0');
141
142 mechs = xmalloc(buffer_len(&buf));
143 buffer_get(&buf, mechs, buffer_len(&buf));
144 buffer_free(&buf);
145
146 if (strlen(mechs) == 0) {
147 xfree(mechs);
148 mechs = NULL;
149 }
150
151 return (mechs);
152}
153
154gss_OID
155ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int *gex) {
156 int i = 0;
157
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 {
167 return NULL;
168 }
169
170 while (gss_enc2oid[i].encoded != NULL &&
171 strcmp(name, gss_enc2oid[i].encoded) != 0) {
172 i++;
173 }
174
175 if (gss_enc2oid[i].oid != NULL && ctx != NULL)
176 ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
177
178 return gss_enc2oid[i].oid;
179}
180
41/* Check that the OID in a data stream matches that in the context */ 181/* Check that the OID in a data stream matches that in the context */
42int 182int
43ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) 183ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
@@ -248,6 +388,9 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx)
248OM_uint32 388OM_uint32
249ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) 389ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
250{ 390{
391 if (ctx == NULL)
392 return -1;
393
251 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, 394 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
252 GSS_C_QOP_DEFAULT, buffer, hash))) 395 GSS_C_QOP_DEFAULT, buffer, hash)))
253 ssh_gssapi_error(ctx); 396 ssh_gssapi_error(ctx);
@@ -255,6 +398,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
255 return (ctx->major); 398 return (ctx->major);
256} 399}
257 400
401/* Priviledged when used by server */
402OM_uint32
403ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
404{
405 if (ctx == NULL)
406 return -1;
407
408 ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
409 gssbuf, gssmic, NULL);
410
411 return (ctx->major);
412}
413
258void 414void
259ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, 415ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
260 const char *context) 416 const char *context)
@@ -277,4 +433,19 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
277 return (ssh_gssapi_acquire_cred(*ctx)); 433 return (ssh_gssapi_acquire_cred(*ctx));
278} 434}
279 435
436int
437ssh_gssapi_check_mechanism(gss_OID oid, void *host) {
438 Gssctxt * ctx = NULL;
439 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
440 OM_uint32 major, minor;
441
442 ssh_gssapi_build_ctx(&ctx);
443 ssh_gssapi_set_oid(ctx, oid);
444 ssh_gssapi_import_name(ctx, host);
445 major = ssh_gssapi_init_ctx(ctx, 0, GSS_C_NO_BUFFER, &token, NULL);
446 gss_release_buffer(&minor, &token);
447 ssh_gssapi_delete_ctx(&ctx);
448 return (!GSS_ERROR(major));
449}
450
280#endif /* GSSAPI */ 451#endif /* GSSAPI */
diff --git a/gss-serv.c b/gss-serv.c
index 26eec25bd..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
@@ -58,6 +59,28 @@ ssh_gssapi_mech* supported_mechs[]= {
58}; 59};
59 60
60/* Unprivileged */ 61/* Unprivileged */
62char *
63ssh_gssapi_server_mechanisms() {
64 gss_OID_set supported;
65
66 ssh_gssapi_supported_oids(&supported);
67 return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
68 NULL));
69}
70
71/* Unprivileged */
72int
73ssh_gssapi_server_check_mech(gss_OID oid, void *data) {
74 Gssctxt * ctx = NULL;
75 int res;
76
77 res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
78 ssh_gssapi_delete_ctx(&ctx);
79
80 return (res);
81}
82
83/* Unprivileged */
61void 84void
62ssh_gssapi_supported_oids(gss_OID_set *oidset) 85ssh_gssapi_supported_oids(gss_OID_set *oidset)
63{ 86{
@@ -293,14 +316,4 @@ ssh_gssapi_userok(char *user)
293 return (0); 316 return (0);
294} 317}
295 318
296/* Privileged */
297OM_uint32
298ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
299{
300 ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
301 gssbuf, gssmic, NULL);
302
303 return (ctx->major);
304}
305
306#endif 319#endif
diff --git a/kex.c b/kex.c
index cd71be9ca..47983f8d9 100644
--- a/kex.c
+++ b/kex.c
@@ -42,6 +42,10 @@ RCSID("$OpenBSD: kex.c,v 1.65 2005/11/04 05:15:59 djm Exp $");
42#include "dispatch.h" 42#include "dispatch.h"
43#include "monitor.h" 43#include "monitor.h"
44 44
45#ifdef GSSAPI
46#include "ssh-gss.h"
47#endif
48
45#define KEX_COOKIE_LEN 16 49#define KEX_COOKIE_LEN 16
46 50
47/* prototype */ 51/* prototype */
@@ -301,6 +305,16 @@ choose_kex(Kex *k, char *client, char *server)
301 } else if (strcmp(k->name, KEX_DHGEX_SHA1) == 0) { 305 } else if (strcmp(k->name, KEX_DHGEX_SHA1) == 0) {
302 k->kex_type = KEX_DH_GEX_SHA1; 306 k->kex_type = KEX_DH_GEX_SHA1;
303 k->evp_md = EVP_sha1(); 307 k->evp_md = EVP_sha1();
308#ifdef GSSAPI
309 } else if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID,
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) {
315 k->kex_type = KEX_GSS_GRP1_SHA1;
316 k->evp_md = EVP_sha1();
317#endif
304 } else 318 } else
305 fatal("bad kex alg %s", k->name); 319 fatal("bad kex alg %s", k->name);
306} 320}
diff --git a/kex.h b/kex.h
index bbd931e04..1c4d1a718 100644
--- a/kex.h
+++ b/kex.h
@@ -63,6 +63,8 @@ enum kex_exchange {
63 KEX_DH_GRP1_SHA1, 63 KEX_DH_GRP1_SHA1,
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,
67 KEX_GSS_GEX_SHA1,
66 KEX_MAX 68 KEX_MAX
67}; 69};
68 70
@@ -115,6 +117,11 @@ struct Kex {
115 int done; 117 int done;
116 int flags; 118 int flags;
117 const EVP_MD *evp_md; 119 const EVP_MD *evp_md;
120#ifdef GSSAPI
121 int gss_deleg_creds;
122 int gss_trust_dns;
123 char *gss_host;
124#endif
118 char *client_version_string; 125 char *client_version_string;
119 char *server_version_string; 126 char *server_version_string;
120 int (*verify_host_key)(Key *); 127 int (*verify_host_key)(Key *);
@@ -137,6 +144,11 @@ void kexdh_server(Kex *);
137void kexgex_client(Kex *); 144void kexgex_client(Kex *);
138void kexgex_server(Kex *); 145void kexgex_server(Kex *);
139 146
147#ifdef GSSAPI
148void kexgss_client(Kex *);
149void kexgss_server(Kex *);
150#endif
151
140void 152void
141kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, 153kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
142 BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); 154 BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *);
diff --git a/kexgssc.c b/kexgssc.c
new file mode 100644
index 000000000..9830ad384
--- /dev/null
+++ b/kexgssc.c
@@ -0,0 +1,303 @@
1/*
2 * Copyright (c) 2001-2005 Simon Wilkinson. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
26
27#ifdef GSSAPI
28
29#include <openssl/crypto.h>
30#include <openssl/bn.h>
31
32#include "xmalloc.h"
33#include "buffer.h"
34#include "bufaux.h"
35#include "kex.h"
36#include "log.h"
37#include "packet.h"
38#include "dh.h"
39#include "canohost.h"
40#include "ssh2.h"
41#include "ssh-gss.h"
42
43void
44kexgss_client(Kex *kex) {
45 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
46 gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
47 Gssctxt *ctxt;
48 OM_uint32 maj_status, min_status, ret_flags;
49 u_int klen, kout, slen = 0, hashlen, strlen;
50 DH *dh;
51 BIGNUM *dh_server_pub = NULL;
52 BIGNUM *shared_secret = NULL;
53 BIGNUM *p = NULL;
54 BIGNUM *g = NULL;
55 u_char *kbuf, *hash;
56 u_char *serverhostkey = NULL;
57 char *msg;
58 char *lang;
59 int type = 0;
60 int first = 1;
61 int gex = 0;
62 int nbits, min, max;
63
64 /* Initialise our GSSAPI world */
65 ssh_gssapi_build_ctx(&ctxt);
66 if (ssh_gssapi_id_kex(ctxt, kex->name, &gex) == NULL)
67 fatal("Couldn't identify host exchange");
68
69 if (ssh_gssapi_import_name(ctxt, kex->gss_host))
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 }
102
103 /* Step 1 - e is dh->pub_key */
104 dh_gen_key(dh, kex->we_need * 8);
105
106 /* This is f, we initialise it now to make life easier */
107 dh_server_pub = BN_new();
108 if (dh_server_pub == NULL)
109 fatal("dh_server_pub == NULL");
110
111 token_ptr = GSS_C_NO_BUFFER;
112
113 do {
114 debug("Calling gss_init_sec_context");
115
116 maj_status = ssh_gssapi_init_ctx(ctxt,
117 kex->gss_deleg_creds, token_ptr, &send_tok,
118 &ret_flags);
119
120 if (GSS_ERROR(maj_status)) {
121 if (send_tok.length != 0) {
122 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
123 packet_put_string(send_tok.value,
124 send_tok.length);
125 }
126 fatal("gss_init_context failed");
127 }
128
129 /* If we've got an old receive buffer get rid of it */
130 if (token_ptr != GSS_C_NO_BUFFER)
131 xfree(recv_tok.value);
132
133 if (maj_status == GSS_S_COMPLETE) {
134 /* If mutual state flag is not true, kex fails */
135 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
136 fatal("Mutual authentication failed");
137
138 /* If integ avail flag is not true kex fails */
139 if (!(ret_flags & GSS_C_INTEG_FLAG))
140 fatal("Integrity check failed");
141 }
142
143 /*
144 * If we have data to send, then the last message that we
145 * received cannot have been a 'complete'.
146 */
147 if (send_tok.length != 0) {
148 if (first) {
149 packet_start(SSH2_MSG_KEXGSS_INIT);
150 packet_put_string(send_tok.value,
151 send_tok.length);
152 packet_put_bignum2(dh->pub_key);
153 first = 0;
154 } else {
155 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
156 packet_put_string(send_tok.value,
157 send_tok.length);
158 }
159 packet_send();
160 gss_release_buffer(&min_status, &send_tok);
161
162 /* If we've sent them data, they should reply */
163 do {
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
174 switch (type) {
175 case SSH2_MSG_KEXGSS_CONTINUE:
176 debug("Received GSSAPI_CONTINUE");
177 if (maj_status == GSS_S_COMPLETE)
178 fatal("GSSAPI Continue received from server when complete");
179 recv_tok.value = packet_get_string(&strlen);
180 recv_tok.length = strlen;
181 break;
182 case SSH2_MSG_KEXGSS_COMPLETE:
183 debug("Received GSSAPI_COMPLETE");
184 packet_get_bignum2(dh_server_pub);
185 msg_tok.value = packet_get_string(&strlen);
186 msg_tok.length = strlen;
187
188 /* Is there a token included? */
189 if (packet_get_char()) {
190 recv_tok.value=
191 packet_get_string(&strlen);
192 recv_tok.length = strlen;
193 /* If we're already complete - protocol error */
194 if (maj_status == GSS_S_COMPLETE)
195 packet_disconnect("Protocol error: received token when complete");
196 } else {
197 /* No token included */
198 if (maj_status != GSS_S_COMPLETE)
199 packet_disconnect("Protocol error: did not receive final token");
200 }
201 break;
202 case SSH2_MSG_KEXGSS_ERROR:
203 debug("Received Error");
204 maj_status = packet_get_int();
205 min_status = packet_get_int();
206 msg = packet_get_string(NULL);
207 lang = packet_get_string(NULL);
208 fatal("GSSAPI Error: \n%s",msg);
209 default:
210 packet_disconnect("Protocol error: didn't expect packet type %d",
211 type);
212 }
213 token_ptr = &recv_tok;
214 } else {
215 /* No data, and not complete */
216 if (maj_status != GSS_S_COMPLETE)
217 fatal("Not complete, and no token output");
218 }
219 } while (maj_status & GSS_S_CONTINUE_NEEDED);
220
221 /*
222 * We _must_ have received a COMPLETE message in reply from the
223 * server, which will have set dh_server_pub and msg_tok
224 */
225
226 if (type != SSH2_MSG_KEXGSS_COMPLETE)
227 fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
228
229 /* Check f in range [1, p-1] */
230 if (!dh_pub_is_valid(dh, dh_server_pub))
231 packet_disconnect("bad server public DH value");
232
233 /* compute K=f^x mod p */
234 klen = DH_size(dh);
235 kbuf = xmalloc(klen);
236 kout = DH_compute_key(kbuf, dh_server_pub, dh);
237
238 shared_secret = BN_new();
239 BN_bin2bn(kbuf,kout, shared_secret);
240 memset(kbuf, 0, klen);
241 xfree(kbuf);
242
243 if (gex) {
244 kexgex_hash(
245 kex->evp_md,
246 kex->client_version_string,
247 kex->server_version_string,
248 buffer_ptr(&kex->my), buffer_len(&kex->my),
249 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
250 serverhostkey, slen,
251 min, nbits, max,
252 dh->p, dh->g,
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
272 gssbuf.value = hash;
273 gssbuf.length = hashlen;
274
275 /* Verify that the hash matches the MIC we just got. */
276 if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
277 packet_disconnect("Hash's MIC didn't verify");
278
279 xfree(msg_tok.value);
280
281 DH_free(dh);
282 if (serverhostkey)
283 xfree(serverhostkey);
284 BN_clear_free(dh_server_pub);
285
286 /* save session id */
287 if (kex->session_id == NULL) {
288 kex->session_id_len = hashlen;
289 kex->session_id = xmalloc(kex->session_id_len);
290 memcpy(kex->session_id, hash, kex->session_id_len);
291 }
292
293 if (gss_kex_context == NULL)
294 gss_kex_context = ctxt;
295 else
296 ssh_gssapi_delete_ctx(&ctxt);
297
298 kex_derive_keys(kex, hash, hashlen, shared_secret);
299 BN_clear_free(shared_secret);
300 kex_finish(kex);
301}
302
303#endif /* GSSAPI */
diff --git a/kexgsss.c b/kexgsss.c
new file mode 100644
index 000000000..6447dc97b
--- /dev/null
+++ b/kexgsss.c
@@ -0,0 +1,256 @@
1/*
2 * Copyright (c) 2001-2005 Simon Wilkinson. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
26
27#ifdef GSSAPI
28
29#include <openssl/crypto.h>
30#include <openssl/bn.h>
31
32#include "xmalloc.h"
33#include "buffer.h"
34#include "bufaux.h"
35#include "kex.h"
36#include "log.h"
37#include "packet.h"
38#include "dh.h"
39#include "ssh2.h"
40#include "ssh-gss.h"
41#include "monitor_wrap.h"
42
43void
44kexgss_server(Kex *kex)
45{
46 OM_uint32 maj_status, min_status;
47
48 /*
49 * Some GSSAPI implementations use the input value of ret_flags (an
50 * output variable) as a means of triggering mechanism specific
51 * features. Initializing it to zero avoids inadvertently
52 * activating this non-standard behaviour.
53 */
54
55 OM_uint32 ret_flags = 0;
56 gss_buffer_desc gssbuf, recv_tok, msg_tok;
57 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
58 Gssctxt *ctxt = NULL;
59 u_int slen, klen, kout, hashlen;
60 u_char *kbuf, *hash;
61 DH *dh;
62 int min = -1, max = -1, nbits = -1;
63 BIGNUM *shared_secret = NULL;
64 BIGNUM *dh_client_pub = NULL;
65 int type = 0;
66 int gex;
67 gss_OID oid;
68
69 /* Initialise GSSAPI */
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
78 debug2("%s: Identifying %s", __func__, kex->name);
79 oid = ssh_gssapi_id_kex(NULL, kex->name, &gex);
80 if (oid == NULL)
81 fatal("Unknown gssapi mechanism");
82
83 debug2("%s: Acquiring credentials", __func__);
84
85 if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
86 fatal("Unable to acquire credentials for the server");
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
116 do {
117 debug("Wait SSH2_MSG_GSSAPI_INIT");
118 type = packet_read();
119 switch(type) {
120 case SSH2_MSG_KEXGSS_INIT:
121 if (dh_client_pub != NULL)
122 fatal("Received KEXGSS_INIT after initialising");
123 recv_tok.value = packet_get_string(&slen);
124 recv_tok.length = slen;
125
126 if ((dh_client_pub = BN_new()) == NULL)
127 fatal("dh_client_pub == NULL");
128
129 packet_get_bignum2(dh_client_pub);
130
131 /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
132 break;
133 case SSH2_MSG_KEXGSS_CONTINUE:
134 recv_tok.value = packet_get_string(&slen);
135 recv_tok.length = slen;
136 break;
137 default:
138 packet_disconnect(
139 "Protocol error: didn't expect packet type %d",
140 type);
141 }
142
143 maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
144 &send_tok, &ret_flags));
145
146 xfree(recv_tok.value);
147
148 if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
149 fatal("Zero length token output when incomplete");
150
151 if (dh_client_pub == NULL)
152 fatal("No client public key");
153
154 if (maj_status & GSS_S_CONTINUE_NEEDED) {
155 debug("Sending GSSAPI_CONTINUE");
156 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
157 packet_put_string(send_tok.value, send_tok.length);
158 packet_send();
159 gss_release_buffer(&min_status, &send_tok);
160 }
161 } while (maj_status & GSS_S_CONTINUE_NEEDED);
162
163 if (GSS_ERROR(maj_status)) {
164 if (send_tok.length > 0) {
165 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
166 packet_put_string(send_tok.value, send_tok.length);
167 packet_send();
168 }
169 fatal("accept_ctx died");
170 }
171
172 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
173 fatal("Mutual Authentication flag wasn't set");
174
175 if (!(ret_flags & GSS_C_INTEG_FLAG))
176 fatal("Integrity flag wasn't set");
177
178 if (!dh_pub_is_valid(dh, dh_client_pub))
179 packet_disconnect("bad client public DH value");
180
181 klen = DH_size(dh);
182 kbuf = xmalloc(klen);
183 kout = DH_compute_key(kbuf, dh_client_pub, dh);
184
185 shared_secret = BN_new();
186 BN_bin2bn(kbuf, kout, shared_secret);
187 memset(kbuf, 0, klen);
188 xfree(kbuf);
189
190 if (gex) {
191 kexgex_hash(
192 kex->evp_md,
193 kex->client_version_string, kex->server_version_string,
194 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
195 buffer_ptr(&kex->my), buffer_len(&kex->my),
196 NULL, 0,
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 }
216 BN_free(dh_client_pub);
217
218 if (kex->session_id == NULL) {
219 kex->session_id_len = hashlen;
220 kex->session_id = xmalloc(kex->session_id_len);
221 memcpy(kex->session_id, hash, kex->session_id_len);
222 }
223
224 gssbuf.value = hash;
225 gssbuf.length = hashlen;
226
227 if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok))))
228 fatal("Couldn't get MIC");
229
230 packet_start(SSH2_MSG_KEXGSS_COMPLETE);
231 packet_put_bignum2(dh->pub_key);
232 packet_put_string((char *)msg_tok.value,msg_tok.length);
233
234 if (send_tok.length != 0) {
235 packet_put_char(1); /* true */
236 packet_put_string((char *)send_tok.value, send_tok.length);
237 } else {
238 packet_put_char(0); /* false */
239 }
240 packet_send();
241
242 gss_release_buffer(&min_status, &send_tok);
243 gss_release_buffer(&min_status, &msg_tok);
244
245 if (gss_kex_context == NULL)
246 gss_kex_context = ctxt;
247 else
248 ssh_gssapi_delete_ctx(&ctxt);
249
250 DH_free(dh);
251
252 kex_derive_keys(kex, hash, hashlen, shared_secret);
253 BN_clear_free(shared_secret);
254 kex_finish(kex);
255}
256#endif /* GSSAPI */
diff --git a/key.c b/key.c
index 08c158b59..239a35919 100644
--- a/key.c
+++ b/key.c
@@ -650,6 +650,8 @@ key_type_from_name(char *name)
650 return KEY_RSA; 650 return KEY_RSA;
651 } else if (strcmp(name, "ssh-dss") == 0) { 651 } else if (strcmp(name, "ssh-dss") == 0) {
652 return KEY_DSA; 652 return KEY_DSA;
653 } else if (strcmp(name, "null") == 0) {
654 return KEY_NULL;
653 } 655 }
654 debug2("key_type_from_name: unknown key type '%s'", name); 656 debug2("key_type_from_name: unknown key type '%s'", name);
655 return KEY_UNSPEC; 657 return KEY_UNSPEC;
diff --git a/key.h b/key.h
index 50df8500b..6358e955f 100644
--- a/key.h
+++ b/key.h
@@ -34,6 +34,7 @@ enum types {
34 KEY_RSA1, 34 KEY_RSA1,
35 KEY_RSA, 35 KEY_RSA,
36 KEY_DSA, 36 KEY_DSA,
37 KEY_NULL,
37 KEY_UNSPEC 38 KEY_UNSPEC
38}; 39};
39enum fp_type { 40enum fp_type {
diff --git a/monitor.c b/monitor.c
index e6f648b0b..57d2c376c 100644
--- a/monitor.c
+++ b/monitor.c
@@ -141,6 +141,7 @@ int mm_answer_gss_setup_ctx(int, Buffer *);
141int mm_answer_gss_accept_ctx(int, Buffer *); 141int mm_answer_gss_accept_ctx(int, Buffer *);
142int mm_answer_gss_userok(int, Buffer *); 142int mm_answer_gss_userok(int, Buffer *);
143int mm_answer_gss_checkmic(int, Buffer *); 143int mm_answer_gss_checkmic(int, Buffer *);
144int mm_answer_gss_sign(int, Buffer *);
144#endif 145#endif
145 146
146#ifdef SSH_AUDIT_EVENTS 147#ifdef SSH_AUDIT_EVENTS
@@ -209,11 +210,17 @@ struct mon_table mon_dispatch_proto20[] = {
209 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, 210 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
210 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, 211 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
211 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, 212 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
213 {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
212#endif 214#endif
213 {0, 0, NULL} 215 {0, 0, NULL}
214}; 216};
215 217
216struct mon_table mon_dispatch_postauth20[] = { 218struct mon_table mon_dispatch_postauth20[] = {
219#ifdef GSSAPI
220 {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
221 {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
222 {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
223#endif
217 {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, 224 {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
218 {MONITOR_REQ_SIGN, 0, mm_answer_sign}, 225 {MONITOR_REQ_SIGN, 0, mm_answer_sign},
219 {MONITOR_REQ_PTY, 0, mm_answer_pty}, 226 {MONITOR_REQ_PTY, 0, mm_answer_pty},
@@ -318,6 +325,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
318 /* Permit requests for moduli and signatures */ 325 /* Permit requests for moduli and signatures */
319 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 326 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
320 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 327 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
328#ifdef GSSAPI
329 /* and for the GSSAPI key exchange */
330 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
331#endif
321 } else { 332 } else {
322 mon_dispatch = mon_dispatch_proto15; 333 mon_dispatch = mon_dispatch_proto15;
323 334
@@ -391,6 +402,10 @@ monitor_child_postauth(struct monitor *pmonitor)
391 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 402 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
392 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 403 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
393 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 404 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
405#ifdef GSSAPI
406 /* and for the GSSAPI key exchange */
407 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
408#endif
394 } else { 409 } else {
395 mon_dispatch = mon_dispatch_postauth15; 410 mon_dispatch = mon_dispatch_postauth15;
396 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 411 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
@@ -1621,6 +1636,10 @@ mm_get_kex(Buffer *m)
1621 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; 1636 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
1622 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; 1637 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
1623 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 1638 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
1639#ifdef GSSAPI
1640 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
1641 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
1642#endif
1624 kex->server = 1; 1643 kex->server = 1;
1625 kex->hostkey_type = buffer_get_int(m); 1644 kex->hostkey_type = buffer_get_int(m);
1626 kex->kex_type = buffer_get_int(m); 1645 kex->kex_type = buffer_get_int(m);
@@ -1863,6 +1882,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
1863 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); 1882 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
1864 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); 1883 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
1865 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); 1884 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
1885 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
1866 } 1886 }
1867 return (0); 1887 return (0);
1868} 1888}
@@ -1913,4 +1933,42 @@ mm_answer_gss_userok(int sock, Buffer *m)
1913 /* Monitor loop will terminate if authenticated */ 1933 /* Monitor loop will terminate if authenticated */
1914 return (authenticated); 1934 return (authenticated);
1915} 1935}
1936
1937int
1938mm_answer_gss_sign(int socket, Buffer *m)
1939{
1940 gss_buffer_desc data;
1941 gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
1942 OM_uint32 major, minor;
1943 u_int len;
1944
1945 data.value = buffer_get_string(m, &len);
1946 data.length = len;
1947 if (data.length != 20)
1948 fatal("%s: data length incorrect: %d", __func__, data.length);
1949
1950 /* Save the session ID on the first time around */
1951 if (session_id2_len == 0) {
1952 session_id2_len = data.length;
1953 session_id2 = xmalloc(session_id2_len);
1954 memcpy(session_id2, data.value, session_id2_len);
1955 }
1956 major = ssh_gssapi_sign(gsscontext, &data, &hash);
1957
1958 xfree(data.value);
1959
1960 buffer_clear(m);
1961 buffer_put_int(m, major);
1962 buffer_put_string(m, hash.value, hash.length);
1963
1964 mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
1965
1966 gss_release_buffer(&minor, &hash);
1967
1968 /* Turn on getpwnam permissions */
1969 monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
1970
1971 return (0);
1972}
1973
1916#endif /* GSSAPI */ 1974#endif /* GSSAPI */
diff --git a/monitor.h b/monitor.h
index 13ce3e1ca..7b306b4af 100644
--- a/monitor.h
+++ b/monitor.h
@@ -53,6 +53,7 @@ enum monitor_reqtype {
53 MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP, 53 MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP,
54 MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK, 54 MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK,
55 MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC, 55 MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC,
56 MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN,
56 MONITOR_REQ_PAM_START, 57 MONITOR_REQ_PAM_START,
57 MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, 58 MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT,
58 MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, 59 MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX,
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 3b50753de..c94675c6f 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1215,4 +1215,27 @@ mm_ssh_gssapi_userok(char *user)
1215 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); 1215 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
1216 return (authenticated); 1216 return (authenticated);
1217} 1217}
1218
1219OM_uint32
1220mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
1221{
1222 Buffer m;
1223 OM_uint32 major;
1224 u_int len;
1225
1226 buffer_init(&m);
1227 buffer_put_string(&m, data->value, data->length);
1228
1229 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
1230 mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
1231
1232 major = buffer_get_int(&m);
1233 hash->value = buffer_get_string(&m, &len);
1234 hash->length = len;
1235
1236 buffer_free(&m);
1237
1238 return(major);
1239}
1240
1218#endif /* GSSAPI */ 1241#endif /* GSSAPI */
diff --git a/monitor_wrap.h b/monitor_wrap.h
index 310b42513..871eabb9d 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -63,6 +63,7 @@ OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
63 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); 63 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
64int mm_ssh_gssapi_userok(char *user); 64int mm_ssh_gssapi_userok(char *user);
65OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 65OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
66OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
66#endif 67#endif
67 68
68#ifdef USE_PAM 69#ifdef USE_PAM
diff --git a/readconf.c b/readconf.c
index 1fbf59793..355a41ccb 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,
@@ -145,9 +146,11 @@ static struct {
145#if defined(GSSAPI) 146#if defined(GSSAPI)
146 { "gssapiauthentication", oGssAuthentication }, 147 { "gssapiauthentication", oGssAuthentication },
147 { "gssapidelegatecredentials", oGssDelegateCreds }, 148 { "gssapidelegatecredentials", oGssDelegateCreds },
149 { "gssapitrustdns", oGssTrustDns },
148#else 150#else
149 { "gssapiauthentication", oUnsupported }, 151 { "gssapiauthentication", oUnsupported },
150 { "gssapidelegatecredentials", oUnsupported }, 152 { "gssapidelegatecredentials", oUnsupported },
153 { "gssapitrustdns", oUnsupported },
151#endif 154#endif
152 { "fallbacktorsh", oDeprecated }, 155 { "fallbacktorsh", oDeprecated },
153 { "usersh", oDeprecated }, 156 { "usersh", oDeprecated },
@@ -420,6 +423,10 @@ parse_flag:
420 intptr = &options->gss_deleg_creds; 423 intptr = &options->gss_deleg_creds;
421 goto parse_flag; 424 goto parse_flag;
422 425
426 case oGssTrustDns:
427 intptr = &options->gss_trust_dns;
428 goto parse_flag;
429
423 case oBatchMode: 430 case oBatchMode:
424 intptr = &options->batch_mode; 431 intptr = &options->batch_mode;
425 goto parse_flag; 432 goto parse_flag;
@@ -971,6 +978,7 @@ initialize_options(Options * options)
971 options->challenge_response_authentication = -1; 978 options->challenge_response_authentication = -1;
972 options->gss_authentication = -1; 979 options->gss_authentication = -1;
973 options->gss_deleg_creds = -1; 980 options->gss_deleg_creds = -1;
981 options->gss_trust_dns = -1;
974 options->password_authentication = -1; 982 options->password_authentication = -1;
975 options->kbd_interactive_authentication = -1; 983 options->kbd_interactive_authentication = -1;
976 options->kbd_interactive_devices = NULL; 984 options->kbd_interactive_devices = NULL;
@@ -1059,6 +1067,8 @@ fill_default_options(Options * options)
1059 options->gss_authentication = 0; 1067 options->gss_authentication = 0;
1060 if (options->gss_deleg_creds == -1) 1068 if (options->gss_deleg_creds == -1)
1061 options->gss_deleg_creds = 0; 1069 options->gss_deleg_creds = 0;
1070 if (options->gss_trust_dns == -1)
1071 options->gss_trust_dns = 0;
1062 if (options->password_authentication == -1) 1072 if (options->password_authentication == -1)
1063 options->password_authentication = 1; 1073 options->password_authentication = 1;
1064 if (options->kbd_interactive_authentication == -1) 1074 if (options->kbd_interactive_authentication == -1)
diff --git a/readconf.h b/readconf.h
index 4565b2c2c..bb70e9373 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 52fb49a6f..213930103 100644
--- a/ssh-gss.h
+++ b/ssh-gss.h
@@ -62,6 +62,16 @@
62 62
63#define SSH_GSS_OIDTYPE 0x06 63#define SSH_GSS_OIDTYPE 0x06
64 64
65#define SSH2_MSG_KEXGSS_INIT 30
66#define SSH2_MSG_KEXGSS_CONTINUE 31
67#define SSH2_MSG_KEXGSS_COMPLETE 32
68#define SSH2_MSG_KEXGSS_HOSTKEY 33
69#define SSH2_MSG_KEXGSS_ERROR 34
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-"
74
65typedef struct { 75typedef struct {
66 char *filename; 76 char *filename;
67 char *envvar; 77 char *envvar;
@@ -99,6 +109,7 @@ typedef struct {
99} Gssctxt; 109} Gssctxt;
100 110
101extern ssh_gssapi_mech *supported_mechs[]; 111extern ssh_gssapi_mech *supported_mechs[];
112extern Gssctxt *gss_kex_context;
102 113
103int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); 114int ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
104void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); 115void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
@@ -121,13 +132,20 @@ OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
121OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); 132OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
122void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); 133void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
123 134
124/* In the server */ 135typedef int ssh_gssapi_check_fn(gss_OID, void *);
136char *ssh_gssapi_client_mechanisms(const char *host);
137char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, void *);
138int ssh_gssapi_check_mechanism(gss_OID, void *);
139gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int *);
140
141int ssh_gssapi_server_check_mech(gss_OID, void *);
125int ssh_gssapi_userok(char *name); 142int ssh_gssapi_userok(char *name);
126OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 143OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
127void ssh_gssapi_do_child(char ***, u_int *); 144void ssh_gssapi_do_child(char ***, u_int *);
128void ssh_gssapi_cleanup_creds(void); 145void ssh_gssapi_cleanup_creds(void);
129void ssh_gssapi_storecreds(void); 146void ssh_gssapi_storecreds(void);
130 147char * ssh_gssapi_server_mechanisms(void);
148int ssh_gssapi_oid_table_ok();
131#endif /* GSSAPI */ 149#endif /* GSSAPI */
132 150
133#endif /* _SSH_GSS_H */ 151#endif /* _SSH_GSS_H */
diff --git a/ssh_config.5 b/ssh_config.5
index 5c94ffc9c..5c41189fa 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -471,6 +471,16 @@ Forward (delegate) credentials to the server.
471The default is 471The default is
472.Dq no . 472.Dq no .
473Note that this option applies to protocol version 2 only. 473Note that this option applies to protocol version 2 only.
474.It Cm GSSAPITrustDns
475Set to
476.Dq yes to indicate that the DNS is trusted to securely canonicalize
477the name of the host being connected to. If
478.Dq no, the hostname entered on the
479command line will be passed untouched to the GSSAPI library.
480The default is
481.Dq no .
482This option only applies to protocol version 2 connections using GSSAPI
483key exchange.
474.It Cm HashKnownHosts 484.It Cm HashKnownHosts
475Indicates that 485Indicates that
476.Nm ssh 486.Nm ssh
diff --git a/sshconnect2.c b/sshconnect2.c
index adf967281..1a69c6b2b 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -84,9 +84,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
84{ 84{
85 Kex *kex; 85 Kex *kex;
86 86
87#ifdef GSSAPI
88 char *orig, *gss;
89 int len;
90 char *gss_host;
91#endif
92
87 xxx_host = host; 93 xxx_host = host;
88 xxx_hostaddr = hostaddr; 94 xxx_hostaddr = hostaddr;
89 95
96#ifdef GSSAPI
97 /* Add the GSSAPI mechanisms currently supported on this client to
98 * the key exchange algorithm proposal */
99 orig = myproposal[PROPOSAL_KEX_ALGS];
100 if (options.gss_trust_dns)
101 gss_host = (char *)get_canonical_hostname(1);
102 else
103 gss_host = host;
104
105 gss = ssh_gssapi_client_mechanisms(gss_host);
106 if (gss) {
107 debug("Offering GSSAPI proposal: %s", gss);
108 len = strlen(orig) + strlen(gss) + 2;
109 myproposal[PROPOSAL_KEX_ALGS] = xmalloc(len);
110 snprintf(myproposal[PROPOSAL_KEX_ALGS], len, "%s,%s", gss,
111 orig);
112 }
113#endif
114
90 if (options.ciphers == (char *)-1) { 115 if (options.ciphers == (char *)-1) {
91 logit("No valid ciphers for protocol version 2 given, using defaults."); 116 logit("No valid ciphers for protocol version 2 given, using defaults.");
92 options.ciphers = NULL; 117 options.ciphers = NULL;
@@ -114,6 +139,18 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
114 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 139 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
115 options.hostkeyalgorithms; 140 options.hostkeyalgorithms;
116 141
142#ifdef GSSAPI
143 /* If we've got GSSAPI algorithms, then we also support the
144 * 'null' hostkey, as a last resort */
145 if (gss) {
146 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
147 len = strlen(orig) + sizeof(",null");
148 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = xmalloc(len);
149 snprintf(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], len,
150 "%s,null", orig);
151 }
152#endif
153
117 if (options.rekey_limit) 154 if (options.rekey_limit)
118 packet_set_rekey_limit(options.rekey_limit); 155 packet_set_rekey_limit(options.rekey_limit);
119 156
@@ -122,10 +159,20 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
122 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; 159 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
123 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; 160 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
124 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 161 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
162#ifdef GSSAPI
163 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
164 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
165#endif
125 kex->client_version_string=client_version_string; 166 kex->client_version_string=client_version_string;
126 kex->server_version_string=server_version_string; 167 kex->server_version_string=server_version_string;
127 kex->verify_host_key=&verify_host_key_callback; 168 kex->verify_host_key=&verify_host_key_callback;
128 169
170#ifdef GSSAPI
171 kex->gss_deleg_creds = options.gss_deleg_creds;
172 kex->gss_trust_dns = options.gss_trust_dns;
173 kex->gss_host = gss_host;
174#endif
175
129 xxx_kex = kex; 176 xxx_kex = kex;
130 177
131 dispatch_run(DISPATCH_BLOCK, &kex->done, kex); 178 dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
@@ -208,6 +255,7 @@ void input_gssapi_token(int type, u_int32_t, void *);
208void input_gssapi_hash(int type, u_int32_t, void *); 255void input_gssapi_hash(int type, u_int32_t, void *);
209void input_gssapi_error(int, u_int32_t, void *); 256void input_gssapi_error(int, u_int32_t, void *);
210void input_gssapi_errtok(int, u_int32_t, void *); 257void input_gssapi_errtok(int, u_int32_t, void *);
258int userauth_gsskeyex(Authctxt *authctxt);
211#endif 259#endif
212 260
213void userauth(Authctxt *, char *); 261void userauth(Authctxt *, char *);
@@ -223,6 +271,10 @@ static char *authmethods_get(void);
223 271
224Authmethod authmethods[] = { 272Authmethod authmethods[] = {
225#ifdef GSSAPI 273#ifdef GSSAPI
274 {"gssapi-keyex",
275 userauth_gsskeyex,
276 &options.gss_authentication,
277 NULL},
226 {"gssapi-with-mic", 278 {"gssapi-with-mic",
227 userauth_gssapi, 279 userauth_gssapi,
228 &options.gss_authentication, 280 &options.gss_authentication,
@@ -706,6 +758,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
706 xfree(msg); 758 xfree(msg);
707 xfree(lang); 759 xfree(lang);
708} 760}
761
762int
763userauth_gsskeyex(Authctxt *authctxt)
764{
765 Buffer b;
766 gss_buffer_desc gssbuf;
767 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
768 OM_uint32 ms;
769
770 static int attempt = 0;
771 if (attempt++ >= 1)
772 return (0);
773
774 if (gss_kex_context == NULL) {
775 debug("No valid Key exchange context");
776 return (0);
777 }
778
779 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
780 "gssapi-keyex");
781
782 gssbuf.value = buffer_ptr(&b);
783 gssbuf.length = buffer_len(&b);
784
785 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
786 buffer_free(&b);
787 return (0);
788 }
789
790 packet_start(SSH2_MSG_USERAUTH_REQUEST);
791 packet_put_cstring(authctxt->server_user);
792 packet_put_cstring(authctxt->service);
793 packet_put_cstring(authctxt->method->name);
794 packet_put_string(mic.value, mic.length);
795 packet_send();
796
797 buffer_free(&b);
798 gss_release_buffer(&ms, &mic);
799
800 return (1);
801}
802
709#endif /* GSSAPI */ 803#endif /* GSSAPI */
710 804
711int 805int
diff --git a/sshd.c b/sshd.c
index def90d827..1eac32797 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>
@@ -1123,10 +1127,13 @@ main(int ac, char **av)
1123 logit("Disabling protocol version 1. Could not load host key"); 1127 logit("Disabling protocol version 1. Could not load host key");
1124 options.protocol &= ~SSH_PROTO_1; 1128 options.protocol &= ~SSH_PROTO_1;
1125 } 1129 }
1130#ifndef GSSAPI
1131 /* The GSSAPI key exchange can run without a host key */
1126 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { 1132 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
1127 logit("Disabling protocol version 2. Could not load host key"); 1133 logit("Disabling protocol version 2. Could not load host key");
1128 options.protocol &= ~SSH_PROTO_2; 1134 options.protocol &= ~SSH_PROTO_2;
1129 } 1135 }
1136#endif
1130 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { 1137 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
1131 logit("sshd: no hostkeys available -- exiting."); 1138 logit("sshd: no hostkeys available -- exiting.");
1132 exit(1); 1139 exit(1);
@@ -1674,6 +1681,60 @@ main(int ac, char **av)
1674 /* Log the connection. */ 1681 /* Log the connection. */
1675 verbose("Connection from %.500s port %d", remote_ip, remote_port); 1682 verbose("Connection from %.500s port %d", remote_ip, remote_port);
1676 1683
1684#ifdef USE_SECURITY_SESSION_API
1685 /*
1686 * Create a new security session for use by the new user login if
1687 * the current session is the root session or we are not launched
1688 * by inetd (eg: debugging mode or server mode). We do not
1689 * necessarily need to create a session if we are launched from
1690 * inetd because Panther xinetd will create a session for us.
1691 *
1692 * The only case where this logic will fail is if there is an
1693 * inetd running in a non-root session which is not creating
1694 * new sessions for us. Then all the users will end up in the
1695 * same session (bad).
1696 *
1697 * When the client exits, the session will be destroyed for us
1698 * automatically.
1699 *
1700 * We must create the session before any credentials are stored
1701 * (including AFS pags, which happens a few lines below).
1702 */
1703 {
1704 OSStatus err = 0;
1705 SecuritySessionId sid = 0;
1706 SessionAttributeBits sattrs = 0;
1707
1708 err = SessionGetInfo(callerSecuritySession, &sid, &sattrs);
1709 if (err)
1710 error("SessionGetInfo() failed with error %.8X",
1711 (unsigned) err);
1712 else
1713 debug("Current Session ID is %.8X / Session Attributes are %.8X",
1714 (unsigned) sid, (unsigned) sattrs);
1715
1716 if (inetd_flag && !(sattrs & sessionIsRoot))
1717 debug("Running in inetd mode in a non-root session... "
1718 "assuming inetd created the session for us.");
1719 else {
1720 debug("Creating new security session...");
1721 err = SessionCreate(0, sessionHasTTY | sessionIsRemote);
1722 if (err)
1723 error("SessionCreate() failed with error %.8X",
1724 (unsigned) err);
1725
1726 err = SessionGetInfo(callerSecuritySession, &sid,
1727 &sattrs);
1728 if (err)
1729 error("SessionGetInfo() failed with error %.8X",
1730 (unsigned) err);
1731 else
1732 debug("New Session ID is %.8X / Session Attributes are %.8X",
1733 (unsigned) sid, (unsigned) sattrs);
1734 }
1735 }
1736#endif
1737
1677 /* 1738 /*
1678 * We don't want to listen forever unless the other side 1739 * We don't want to listen forever unless the other side
1679 * successfully authenticates itself. So we set up an alarm which is 1740 * successfully authenticates itself. So we set up an alarm which is
@@ -2028,13 +2089,63 @@ do_ssh2_kex(void)
2028 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); 2089 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
2029 2090
2030 /* start key exchange */ 2091 /* start key exchange */
2031 kex = kex_setup(myproposal); 2092
2032 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; 2093#ifdef GSSAPI
2094 {
2095 char *orig;
2096 char *gss = NULL;
2097 char *newstr = NULL;
2098 orig = myproposal[PROPOSAL_KEX_ALGS];
2099
2100 /*
2101 * If we don't have a host key, then there's no point advertising
2102 * the other key exchange algorithms
2103 */
2104
2105 if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
2106 orig = NULL;
2107
2108 if (options.gss_keyex)
2109 gss = ssh_gssapi_server_mechanisms();
2110 else
2111 gss = NULL;
2112
2113 if (gss && orig) {
2114 int len = strlen(orig) + strlen(gss) + 2;
2115 newstr = xmalloc(len);
2116 snprintf(newstr, len, "%s,%s", gss, orig);
2117 } else if (gss) {
2118 newstr = gss;
2119 } else if (orig) {
2120 newstr = orig;
2121 }
2122 /*
2123 * If we've got GSSAPI mechanisms, then we've got the 'null' host
2124 * key alg, but we can't tell people about it unless its the only
2125 * host key algorithm we support
2126 */
2127 if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
2128 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
2129
2130 if (newstr)
2131 myproposal[PROPOSAL_KEX_ALGS] = newstr;
2132 else
2133 fatal("No supported key exchange algorithms");
2134 }
2135#endif
2136
2137 /* start key exchange */
2138 kex = kex_setup(myproposal);
2139 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
2033 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; 2140 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
2034 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 2141 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
2035 kex->server = 1; 2142#ifdef GSSAPI
2036 kex->client_version_string=client_version_string; 2143 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
2037 kex->server_version_string=server_version_string; 2144 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
2145#endif
2146 kex->server = 1;
2147 kex->client_version_string=client_version_string;
2148 kex->server_version_string=server_version_string;
2038 kex->load_host_key=&get_hostkey_by_type; 2149 kex->load_host_key=&get_hostkey_by_type;
2039 kex->host_key_index=&get_hostkey_index; 2150 kex->host_key_index=&get_hostkey_index;
2040 2151
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.