summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.gssapi113
-rw-r--r--Makefile.in3
-rw-r--r--auth-krb5.c17
-rw-r--r--auth2-gss.c48
-rw-r--r--auth2.c2
-rw-r--r--clientloop.c13
-rw-r--r--config.h.in6
-rwxr-xr-xconfigure57
-rw-r--r--configure.ac24
-rw-r--r--gss-genr.c276
-rw-r--r--gss-serv-krb5.c84
-rw-r--r--gss-serv.c220
-rw-r--r--kex.c18
-rw-r--r--kex.h14
-rw-r--r--kexgssc.c334
-rw-r--r--kexgsss.c288
-rw-r--r--key.c4
-rw-r--r--key.h1
-rw-r--r--monitor.c108
-rw-r--r--monitor.h3
-rw-r--r--monitor_wrap.c47
-rw-r--r--monitor_wrap.h4
-rw-r--r--readconf.c42
-rw-r--r--readconf.h5
-rw-r--r--servconf.c38
-rw-r--r--servconf.h3
-rw-r--r--ssh-gss.h39
-rw-r--r--ssh_config2
-rw-r--r--ssh_config.534
-rw-r--r--sshconnect2.c124
-rw-r--r--sshd.c110
-rw-r--r--sshd_config2
-rw-r--r--sshd_config.528
33 files changed, 2054 insertions, 57 deletions
diff --git a/ChangeLog.gssapi b/ChangeLog.gssapi
new file mode 100644
index 000000000..f117a336a
--- /dev/null
+++ b/ChangeLog.gssapi
@@ -0,0 +1,113 @@
120110101
2 - Finally update for OpenSSH 5.6p1
3 - Add GSSAPIServerIdentity option from Jim Basney
4
520100308
6 - [ Makefile.in, key.c, key.h ]
7 Updates for OpenSSH 5.4p1
8 - [ servconf.c ]
9 Include GSSAPI options in the sshd -T configuration dump, and flag
10 some older configuration options as being unsupported. Thanks to Colin
11 Watson.
12 -
13
1420100124
15 - [ sshconnect2.c ]
16 Adapt to deal with additional element in Authmethod structure. Thanks to
17 Colin Watson
18
1920090615
20 - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c
21 sshd.c ]
22 Fix issues identified by Greg Hudson following a code review
23 Check return value of gss_indicate_mechs
24 Protect GSSAPI calls in monitor, so they can only be used if enabled
25 Check return values of bignum functions in key exchange
26 Use BN_clear_free to clear other side's DH value
27 Make ssh_gssapi_id_kex more robust
28 Only configure kex table pointers if GSSAPI is enabled
29 Don't leak mechanism list, or gss mechanism list
30 Cast data.length before printing
31 If serverkey isn't provided, use an empty string, rather than NULL
32
3320090201
34 - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h
35 ssh_config.5 sshconnet2.c ]
36 Add support for the GSSAPIClientIdentity option, which allows the user
37 to specify which GSSAPI identity to use to contact a given server
38
3920080404
40 - [ gss-serv.c ]
41 Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow
42 been omitted from a previous version of this patch. Reported by Borislav
43 Stoichkov
44
4520070317
46 - [ gss-serv-krb5.c ]
47 Remove C99ism, where new_ccname was being declared in the middle of a
48 function
49
5020061220
51 - [ servconf.c ]
52 Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and
53 documented, behaviour. Reported by Dan Watson.
54
5520060910
56 - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c
57 ssh-gss.h ]
58 add support for gss-group14-sha1 key exchange mechanisms
59 - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ]
60 Add GSSAPIStrictAcceptorCheck option to allow the disabling of
61 acceptor principal checking on multi-homed machines.
62 <Bugzilla #928>
63 - [ sshd_config ssh_config ]
64 Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample
65 configuration files
66 - [ kexgss.c kegsss.c sshconnect2.c sshd.c ]
67 Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf()
68 Limit length of error messages displayed by client
69
7020060909
71 - [ gss-genr.c gss-serv.c ]
72 move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server
73 only, where they belong
74 <Bugzilla #1225>
75
7620060829
77 - [ gss-serv-krb5.c ]
78 Fix CCAPI credentials cache name when creating KRB5CCNAME environment
79 variable
80
8120060828
82 - [ gss-genr.c ]
83 Avoid Heimdal context freeing problem
84 <Fixed upstream 20060829>
85
8620060818
87 - [ gss-genr.c ssh-gss.h sshconnect2.c ]
88 Make sure that SPENGO is disabled
89 <Bugzilla #1218 - Fixed upstream 20060818>
90
9120060421
92 - [ gssgenr.c, sshconnect2.c ]
93 a few type changes (signed versus unsigned, int versus size_t) to
94 fix compiler errors/warnings
95 (from jbasney AT ncsa.uiuc.edu)
96 - [ kexgssc.c, sshconnect2.c ]
97 fix uninitialized variable warnings
98 (from jbasney AT ncsa.uiuc.edu)
99 - [ gssgenr.c ]
100 pass oid to gss_display_status (helpful when using GSSAPI mechglue)
101 (from jbasney AT ncsa.uiuc.edu)
102 <Bugzilla #1220 >
103 - [ gss-serv-krb5.c ]
104 #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H
105 (from jbasney AT ncsa.uiuc.edu)
106 <Fixed upstream 20060304>
107 - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c
108 add client-side GssapiKeyExchange option
109 (from jbasney AT ncsa.uiuc.edu)
110 - [ sshconnect2.c ]
111 add support for GssapiTrustDns option for gssapi-with-mic
112 (from jbasney AT ncsa.uiuc.edu)
113 <gssapi-with-mic support is Bugzilla #1008>
diff --git a/Makefile.in b/Makefile.in
index d327787b0..dd0502e63 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -72,6 +72,7 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \
72 atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ 72 atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
73 monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ 73 monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
74 kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \ 74 kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \
75 kexgssc.o \
75 msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ 76 msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
76 jpake.o schnorr.o ssh-pkcs11.o krl.o 77 jpake.o schnorr.o ssh-pkcs11.o krl.o
77 78
@@ -88,7 +89,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
88 auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-jpake.o \ 89 auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-jpake.o \
89 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \ 90 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \
90 auth-krb5.o \ 91 auth-krb5.o \
91 auth2-gss.o gss-serv.o gss-serv-krb5.o \ 92 auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\
92 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ 93 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
93 sftp-server.o sftp-common.o \ 94 sftp-server.o sftp-common.o \
94 roaming_common.o roaming_serv.o \ 95 roaming_common.o roaming_serv.o \
diff --git a/auth-krb5.c b/auth-krb5.c
index 922c66c66..4c2375462 100644
--- a/auth-krb5.c
+++ b/auth-krb5.c
@@ -170,8 +170,13 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
170 170
171 len = strlen(authctxt->krb5_ticket_file) + 6; 171 len = strlen(authctxt->krb5_ticket_file) + 6;
172 authctxt->krb5_ccname = xmalloc(len); 172 authctxt->krb5_ccname = xmalloc(len);
173#ifdef USE_CCAPI
174 snprintf(authctxt->krb5_ccname, len, "API:%s",
175 authctxt->krb5_ticket_file);
176#else
173 snprintf(authctxt->krb5_ccname, len, "FILE:%s", 177 snprintf(authctxt->krb5_ccname, len, "FILE:%s",
174 authctxt->krb5_ticket_file); 178 authctxt->krb5_ticket_file);
179#endif
175 180
176#ifdef USE_PAM 181#ifdef USE_PAM
177 if (options.use_pam) 182 if (options.use_pam)
@@ -226,15 +231,22 @@ krb5_cleanup_proc(Authctxt *authctxt)
226#ifndef HEIMDAL 231#ifndef HEIMDAL
227krb5_error_code 232krb5_error_code
228ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { 233ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
229 int tmpfd, ret, oerrno; 234 int ret, oerrno;
230 char ccname[40]; 235 char ccname[40];
231 mode_t old_umask; 236 mode_t old_umask;
237#ifdef USE_CCAPI
238 char cctemplate[] = "API:krb5cc_%d";
239#else
240 char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX";
241 int tmpfd;
242#endif
232 243
233 ret = snprintf(ccname, sizeof(ccname), 244 ret = snprintf(ccname, sizeof(ccname),
234 "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); 245 cctemplate, geteuid());
235 if (ret < 0 || (size_t)ret >= sizeof(ccname)) 246 if (ret < 0 || (size_t)ret >= sizeof(ccname))
236 return ENOMEM; 247 return ENOMEM;
237 248
249#ifndef USE_CCAPI
238 old_umask = umask(0177); 250 old_umask = umask(0177);
239 tmpfd = mkstemp(ccname + strlen("FILE:")); 251 tmpfd = mkstemp(ccname + strlen("FILE:"));
240 oerrno = errno; 252 oerrno = errno;
@@ -251,6 +263,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
251 return oerrno; 263 return oerrno;
252 } 264 }
253 close(tmpfd); 265 close(tmpfd);
266#endif
254 267
255 return (krb5_cc_resolve(ctx, ccname, ccache)); 268 return (krb5_cc_resolve(ctx, ccname, ccache));
256} 269}
diff --git a/auth2-gss.c b/auth2-gss.c
index 93d576bfb..17d4a3a84 100644
--- a/auth2-gss.c
+++ b/auth2-gss.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: auth2-gss.c,v 1.18 2012/12/02 20:34:09 djm Exp $ */ 1/* $OpenBSD: auth2-gss.c,v 1.18 2012/12/02 20:34:09 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 4 * Copyright (c) 2001-2007 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
@@ -52,6 +52,40 @@ static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
52static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); 52static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
53static void input_gssapi_errtok(int, u_int32_t, void *); 53static void input_gssapi_errtok(int, u_int32_t, void *);
54 54
55/*
56 * The 'gssapi_keyex' userauth mechanism.
57 */
58static int
59userauth_gsskeyex(Authctxt *authctxt)
60{
61 int authenticated = 0;
62 Buffer b;
63 gss_buffer_desc mic, gssbuf;
64 u_int len;
65
66 mic.value = packet_get_string(&len);
67 mic.length = len;
68
69 packet_check_eom();
70
71 ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
72 "gssapi-keyex");
73
74 gssbuf.value = buffer_ptr(&b);
75 gssbuf.length = buffer_len(&b);
76
77 /* gss_kex_context is NULL with privsep, so we can't check it here */
78 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
79 &gssbuf, &mic))))
80 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
81 authctxt->pw));
82
83 buffer_free(&b);
84 xfree(mic.value);
85
86 return (authenticated);
87}
88
55/* 89/*
56 * We only support those mechanisms that we know about (ie ones that we know 90 * We only support those mechanisms that we know about (ie ones that we know
57 * how to check local user kuserok and the like) 91 * how to check local user kuserok and the like)
@@ -244,7 +278,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
244 278
245 packet_check_eom(); 279 packet_check_eom();
246 280
247 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); 281 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
282 authctxt->pw));
248 283
249 authctxt->postponed = 0; 284 authctxt->postponed = 0;
250 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 285 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
@@ -279,7 +314,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
279 gssbuf.length = buffer_len(&b); 314 gssbuf.length = buffer_len(&b);
280 315
281 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) 316 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
282 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); 317 authenticated =
318 PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
283 else 319 else
284 logit("GSSAPI MIC check failed"); 320 logit("GSSAPI MIC check failed");
285 321
@@ -294,6 +330,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
294 userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL); 330 userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
295} 331}
296 332
333Authmethod method_gsskeyex = {
334 "gssapi-keyex",
335 userauth_gsskeyex,
336 &options.gss_authentication
337};
338
297Authmethod method_gssapi = { 339Authmethod method_gssapi = {
298 "gssapi-with-mic", 340 "gssapi-with-mic",
299 userauth_gssapi, 341 userauth_gssapi,
diff --git a/auth2.c b/auth2.c
index e367a1045..d25940036 100644
--- a/auth2.c
+++ b/auth2.c
@@ -69,6 +69,7 @@ extern Authmethod method_passwd;
69extern Authmethod method_kbdint; 69extern Authmethod method_kbdint;
70extern Authmethod method_hostbased; 70extern Authmethod method_hostbased;
71#ifdef GSSAPI 71#ifdef GSSAPI
72extern Authmethod method_gsskeyex;
72extern Authmethod method_gssapi; 73extern Authmethod method_gssapi;
73#endif 74#endif
74#ifdef JPAKE 75#ifdef JPAKE
@@ -79,6 +80,7 @@ Authmethod *authmethods[] = {
79 &method_none, 80 &method_none,
80 &method_pubkey, 81 &method_pubkey,
81#ifdef GSSAPI 82#ifdef GSSAPI
83 &method_gsskeyex,
82 &method_gssapi, 84 &method_gssapi,
83#endif 85#endif
84#ifdef JPAKE 86#ifdef JPAKE
diff --git a/clientloop.c b/clientloop.c
index c1d1d4472..2ef816ab3 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -111,6 +111,10 @@
111#include "msg.h" 111#include "msg.h"
112#include "roaming.h" 112#include "roaming.h"
113 113
114#ifdef GSSAPI
115#include "ssh-gss.h"
116#endif
117
114/* import options */ 118/* import options */
115extern Options options; 119extern Options options;
116 120
@@ -1599,6 +1603,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1599 /* Do channel operations unless rekeying in progress. */ 1603 /* Do channel operations unless rekeying in progress. */
1600 if (!rekeying) { 1604 if (!rekeying) {
1601 channel_after_select(readset, writeset); 1605 channel_after_select(readset, writeset);
1606
1607#ifdef GSSAPI
1608 if (options.gss_renewal_rekey &&
1609 ssh_gssapi_credentials_updated(GSS_C_NO_CONTEXT)) {
1610 debug("credentials updated - forcing rekey");
1611 need_rekeying = 1;
1612 }
1613#endif
1614
1602 if (need_rekeying || packet_need_rekeying()) { 1615 if (need_rekeying || packet_need_rekeying()) {
1603 debug("need rekeying"); 1616 debug("need rekeying");
1604 xxx_kex->done = 0; 1617 xxx_kex->done = 0;
diff --git a/config.h.in b/config.h.in
index ea3591a0b..67858ef6d 100644
--- a/config.h.in
+++ b/config.h.in
@@ -1511,6 +1511,9 @@
1511/* Use btmp to log bad logins */ 1511/* Use btmp to log bad logins */
1512#undef USE_BTMP 1512#undef USE_BTMP
1513 1513
1514/* platform uses an in-memory credentials cache */
1515#undef USE_CCAPI
1516
1514/* Use libedit for sftp */ 1517/* Use libedit for sftp */
1515#undef USE_LIBEDIT 1518#undef USE_LIBEDIT
1516 1519
@@ -1526,6 +1529,9 @@
1526/* Use PIPES instead of a socketpair() */ 1529/* Use PIPES instead of a socketpair() */
1527#undef USE_PIPES 1530#undef USE_PIPES
1528 1531
1532/* platform has the Security Authorization Session API */
1533#undef USE_SECURITY_SESSION_API
1534
1529/* Define if you have Solaris process contracts */ 1535/* Define if you have Solaris process contracts */
1530#undef USE_SOLARIS_PROCESS_CONTRACTS 1536#undef USE_SOLARIS_PROCESS_CONTRACTS
1531 1537
diff --git a/configure b/configure
index c36bb1907..c4d1ed0d2 100755
--- a/configure
+++ b/configure
@@ -6588,6 +6588,63 @@ $as_echo "#define SSH_TUN_COMPAT_AF 1" >>confdefs.h
6588 6588
6589$as_echo "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h 6589$as_echo "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h
6590 6590
6591 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have the Security Authorization Session API" >&5
6592$as_echo_n "checking if we have the Security Authorization Session API... " >&6; }
6593 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
6594/* end confdefs.h. */
6595#include <Security/AuthSession.h>
6596int
6597main ()
6598{
6599SessionCreate(0, 0);
6600 ;
6601 return 0;
6602}
6603_ACEOF
6604if ac_fn_c_try_compile "$LINENO"; then :
6605 ac_cv_use_security_session_api="yes"
6606
6607$as_echo "#define USE_SECURITY_SESSION_API 1" >>confdefs.h
6608
6609 LIBS="$LIBS -framework Security"
6610 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
6611$as_echo "yes" >&6; }
6612else
6613 ac_cv_use_security_session_api="no"
6614 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
6615$as_echo "no" >&6; }
6616fi
6617rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
6618 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have an in-memory credentials cache" >&5
6619$as_echo_n "checking if we have an in-memory credentials cache... " >&6; }
6620 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
6621/* end confdefs.h. */
6622#include <Kerberos/Kerberos.h>
6623int
6624main ()
6625{
6626cc_context_t c;
6627 (void) cc_initialize (&c, 0, NULL, NULL);
6628 ;
6629 return 0;
6630}
6631_ACEOF
6632if ac_fn_c_try_compile "$LINENO"; then :
6633
6634$as_echo "#define USE_CCAPI 1" >>confdefs.h
6635
6636 LIBS="$LIBS -framework Security"
6637 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
6638$as_echo "yes" >&6; }
6639 if test "x$ac_cv_use_security_session_api" = "xno"; then
6640 as_fn_error $? "*** Need a security framework to use the credentials cache API ***" "$LINENO" 5
6641 fi
6642else
6643 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
6644$as_echo "no" >&6; }
6645
6646fi
6647rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
6591 6648
6592 ac_fn_c_check_decl "$LINENO" "AU_IPv4" "ac_cv_have_decl_AU_IPv4" "$ac_includes_default" 6649 ac_fn_c_check_decl "$LINENO" "AU_IPv4" "ac_cv_have_decl_AU_IPv4" "$ac_includes_default"
6593if test "x$ac_cv_have_decl_AU_IPv4" = xyes; then : 6650if test "x$ac_cv_have_decl_AU_IPv4" = xyes; then :
diff --git a/configure.ac b/configure.ac
index 88dd29e9d..271a63a46 100644
--- a/configure.ac
+++ b/configure.ac
@@ -533,6 +533,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
533 [Use tunnel device compatibility to OpenBSD]) 533 [Use tunnel device compatibility to OpenBSD])
534 AC_DEFINE([SSH_TUN_PREPEND_AF], [1], 534 AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
535 [Prepend the address family to IP tunnel traffic]) 535 [Prepend the address family to IP tunnel traffic])
536 AC_MSG_CHECKING([if we have the Security Authorization Session API])
537 AC_TRY_COMPILE([#include <Security/AuthSession.h>],
538 [SessionCreate(0, 0);],
539 [ac_cv_use_security_session_api="yes"
540 AC_DEFINE([USE_SECURITY_SESSION_API], [1],
541 [platform has the Security Authorization Session API])
542 LIBS="$LIBS -framework Security"
543 AC_MSG_RESULT([yes])],
544 [ac_cv_use_security_session_api="no"
545 AC_MSG_RESULT([no])])
546 AC_MSG_CHECKING([if we have an in-memory credentials cache])
547 AC_TRY_COMPILE(
548 [#include <Kerberos/Kerberos.h>],
549 [cc_context_t c;
550 (void) cc_initialize (&c, 0, NULL, NULL);],
551 [AC_DEFINE([USE_CCAPI], [1],
552 [platform uses an in-memory credentials cache])
553 LIBS="$LIBS -framework Security"
554 AC_MSG_RESULT([yes])
555 if test "x$ac_cv_use_security_session_api" = "xno"; then
556 AC_MSG_ERROR([*** Need a security framework to use the credentials cache API ***])
557 fi],
558 [AC_MSG_RESULT([no])]
559 )
536 m4_pattern_allow([AU_IPv]) 560 m4_pattern_allow([AU_IPv])
537 AC_CHECK_DECL([AU_IPv4], [], 561 AC_CHECK_DECL([AU_IPv4], [],
538 AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records]) 562 AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records])
diff --git a/gss-genr.c b/gss-genr.c
index 842f38582..f9b39cfd5 100644
--- a/gss-genr.c
+++ b/gss-genr.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-genr.c,v 1.20 2009/06/22 05:39:28 dtucker Exp $ */ 1/* $OpenBSD: gss-genr.c,v 1.20 2009/06/22 05:39:28 dtucker Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. 4 * Copyright (c) 2001-2009 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
@@ -39,12 +39,167 @@
39#include "buffer.h" 39#include "buffer.h"
40#include "log.h" 40#include "log.h"
41#include "ssh2.h" 41#include "ssh2.h"
42#include "cipher.h"
43#include "key.h"
44#include "kex.h"
45#include <openssl/evp.h>
42 46
43#include "ssh-gss.h" 47#include "ssh-gss.h"
44 48
45extern u_char *session_id2; 49extern u_char *session_id2;
46extern u_int session_id2_len; 50extern u_int session_id2_len;
47 51
52typedef struct {
53 char *encoded;
54 gss_OID oid;
55} ssh_gss_kex_mapping;
56
57/*
58 * XXX - It would be nice to find a more elegant way of handling the
59 * XXX passing of the key exchange context to the userauth routines
60 */
61
62Gssctxt *gss_kex_context = NULL;
63
64static ssh_gss_kex_mapping *gss_enc2oid = NULL;
65
66int
67ssh_gssapi_oid_table_ok() {
68 return (gss_enc2oid != NULL);
69}
70
71/*
72 * Return a list of the gss-group1-sha1 mechanisms supported by this program
73 *
74 * We test mechanisms to ensure that we can use them, to avoid starting
75 * a key exchange with a bad mechanism
76 */
77
78char *
79ssh_gssapi_client_mechanisms(const char *host, const char *client) {
80 gss_OID_set gss_supported;
81 OM_uint32 min_status;
82
83 if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
84 return NULL;
85
86 return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
87 host, client));
88}
89
90char *
91ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
92 const char *host, const char *client) {
93 Buffer buf;
94 size_t i;
95 int oidpos, enclen;
96 char *mechs, *encoded;
97 u_char digest[EVP_MAX_MD_SIZE];
98 char deroid[2];
99 const EVP_MD *evp_md = EVP_md5();
100 EVP_MD_CTX md;
101
102 if (gss_enc2oid != NULL) {
103 for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
104 xfree(gss_enc2oid[i].encoded);
105 xfree(gss_enc2oid);
106 }
107
108 gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
109 (gss_supported->count + 1));
110
111 buffer_init(&buf);
112
113 oidpos = 0;
114 for (i = 0; i < gss_supported->count; i++) {
115 if (gss_supported->elements[i].length < 128 &&
116 (*check)(NULL, &(gss_supported->elements[i]), host, client)) {
117
118 deroid[0] = SSH_GSS_OIDTYPE;
119 deroid[1] = gss_supported->elements[i].length;
120
121 EVP_DigestInit(&md, evp_md);
122 EVP_DigestUpdate(&md, deroid, 2);
123 EVP_DigestUpdate(&md,
124 gss_supported->elements[i].elements,
125 gss_supported->elements[i].length);
126 EVP_DigestFinal(&md, digest, NULL);
127
128 encoded = xmalloc(EVP_MD_size(evp_md) * 2);
129 enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
130 encoded, EVP_MD_size(evp_md) * 2);
131
132 if (oidpos != 0)
133 buffer_put_char(&buf, ',');
134
135 buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
136 sizeof(KEX_GSS_GEX_SHA1_ID) - 1);
137 buffer_append(&buf, encoded, enclen);
138 buffer_put_char(&buf, ',');
139 buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID,
140 sizeof(KEX_GSS_GRP1_SHA1_ID) - 1);
141 buffer_append(&buf, encoded, enclen);
142 buffer_put_char(&buf, ',');
143 buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID,
144 sizeof(KEX_GSS_GRP14_SHA1_ID) - 1);
145 buffer_append(&buf, encoded, enclen);
146
147 gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
148 gss_enc2oid[oidpos].encoded = encoded;
149 oidpos++;
150 }
151 }
152 gss_enc2oid[oidpos].oid = NULL;
153 gss_enc2oid[oidpos].encoded = NULL;
154
155 buffer_put_char(&buf, '\0');
156
157 mechs = xmalloc(buffer_len(&buf));
158 buffer_get(&buf, mechs, buffer_len(&buf));
159 buffer_free(&buf);
160
161 if (strlen(mechs) == 0) {
162 xfree(mechs);
163 mechs = NULL;
164 }
165
166 return (mechs);
167}
168
169gss_OID
170ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
171 int i = 0;
172
173 switch (kex_type) {
174 case KEX_GSS_GRP1_SHA1:
175 if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID))
176 return GSS_C_NO_OID;
177 name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
178 break;
179 case KEX_GSS_GRP14_SHA1:
180 if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID))
181 return GSS_C_NO_OID;
182 name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
183 break;
184 case KEX_GSS_GEX_SHA1:
185 if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID))
186 return GSS_C_NO_OID;
187 name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
188 break;
189 default:
190 return GSS_C_NO_OID;
191 }
192
193 while (gss_enc2oid[i].encoded != NULL &&
194 strcmp(name, gss_enc2oid[i].encoded) != 0)
195 i++;
196
197 if (gss_enc2oid[i].oid != NULL && ctx != NULL)
198 ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
199
200 return gss_enc2oid[i].oid;
201}
202
48/* Check that the OID in a data stream matches that in the context */ 203/* Check that the OID in a data stream matches that in the context */
49int 204int
50ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) 205ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
@@ -197,7 +352,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
197 } 352 }
198 353
199 ctx->major = gss_init_sec_context(&ctx->minor, 354 ctx->major = gss_init_sec_context(&ctx->minor,
200 GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, 355 ctx->client_creds, &ctx->context, ctx->name, ctx->oid,
201 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, 356 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
202 0, NULL, recv_tok, NULL, send_tok, flags, NULL); 357 0, NULL, recv_tok, NULL, send_tok, flags, NULL);
203 358
@@ -227,8 +382,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
227} 382}
228 383
229OM_uint32 384OM_uint32
385ssh_gssapi_client_identity(Gssctxt *ctx, const char *name)
386{
387 gss_buffer_desc gssbuf;
388 gss_name_t gssname;
389 OM_uint32 status;
390 gss_OID_set oidset;
391
392 gssbuf.value = (void *) name;
393 gssbuf.length = strlen(gssbuf.value);
394
395 gss_create_empty_oid_set(&status, &oidset);
396 gss_add_oid_set_member(&status, ctx->oid, &oidset);
397
398 ctx->major = gss_import_name(&ctx->minor, &gssbuf,
399 GSS_C_NT_USER_NAME, &gssname);
400
401 if (!ctx->major)
402 ctx->major = gss_acquire_cred(&ctx->minor,
403 gssname, 0, oidset, GSS_C_INITIATE,
404 &ctx->client_creds, NULL, NULL);
405
406 gss_release_name(&status, &gssname);
407 gss_release_oid_set(&status, &oidset);
408
409 if (ctx->major)
410 ssh_gssapi_error(ctx);
411
412 return(ctx->major);
413}
414
415OM_uint32
230ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) 416ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
231{ 417{
418 if (ctx == NULL)
419 return -1;
420
232 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, 421 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
233 GSS_C_QOP_DEFAULT, buffer, hash))) 422 GSS_C_QOP_DEFAULT, buffer, hash)))
234 ssh_gssapi_error(ctx); 423 ssh_gssapi_error(ctx);
@@ -236,6 +425,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
236 return (ctx->major); 425 return (ctx->major);
237} 426}
238 427
428/* Priviledged when used by server */
429OM_uint32
430ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
431{
432 if (ctx == NULL)
433 return -1;
434
435 ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
436 gssbuf, gssmic, NULL);
437
438 return (ctx->major);
439}
440
239void 441void
240ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, 442ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
241 const char *context) 443 const char *context)
@@ -249,11 +451,16 @@ ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
249} 451}
250 452
251int 453int
252ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) 454ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host,
455 const char *client)
253{ 456{
254 gss_buffer_desc token = GSS_C_EMPTY_BUFFER; 457 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
255 OM_uint32 major, minor; 458 OM_uint32 major, minor;
256 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; 459 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
460 Gssctxt *intctx = NULL;
461
462 if (ctx == NULL)
463 ctx = &intctx;
257 464
258 /* RFC 4462 says we MUST NOT do SPNEGO */ 465 /* RFC 4462 says we MUST NOT do SPNEGO */
259 if (oid->length == spnego_oid.length && 466 if (oid->length == spnego_oid.length &&
@@ -263,6 +470,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
263 ssh_gssapi_build_ctx(ctx); 470 ssh_gssapi_build_ctx(ctx);
264 ssh_gssapi_set_oid(*ctx, oid); 471 ssh_gssapi_set_oid(*ctx, oid);
265 major = ssh_gssapi_import_name(*ctx, host); 472 major = ssh_gssapi_import_name(*ctx, host);
473
474 if (!GSS_ERROR(major) && client)
475 major = ssh_gssapi_client_identity(*ctx, client);
476
266 if (!GSS_ERROR(major)) { 477 if (!GSS_ERROR(major)) {
267 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, 478 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token,
268 NULL); 479 NULL);
@@ -272,10 +483,67 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
272 GSS_C_NO_BUFFER); 483 GSS_C_NO_BUFFER);
273 } 484 }
274 485
275 if (GSS_ERROR(major)) 486 if (GSS_ERROR(major) || intctx != NULL)
276 ssh_gssapi_delete_ctx(ctx); 487 ssh_gssapi_delete_ctx(ctx);
277 488
278 return (!GSS_ERROR(major)); 489 return (!GSS_ERROR(major));
279} 490}
280 491
492int
493ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
494 static gss_name_t saved_name = GSS_C_NO_NAME;
495 static OM_uint32 saved_lifetime = 0;
496 static gss_OID saved_mech = GSS_C_NO_OID;
497 static gss_name_t name;
498 static OM_uint32 last_call = 0;
499 OM_uint32 lifetime, now, major, minor;
500 int equal;
501 gss_cred_usage_t usage = GSS_C_INITIATE;
502
503 now = time(NULL);
504
505 if (ctxt) {
506 debug("Rekey has happened - updating saved versions");
507
508 if (saved_name != GSS_C_NO_NAME)
509 gss_release_name(&minor, &saved_name);
510
511 major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
512 &saved_name, &saved_lifetime, NULL, NULL);
513
514 if (!GSS_ERROR(major)) {
515 saved_mech = ctxt->oid;
516 saved_lifetime+= now;
517 } else {
518 /* Handle the error */
519 }
520 return 0;
521 }
522
523 if (now - last_call < 10)
524 return 0;
525
526 last_call = now;
527
528 if (saved_mech == GSS_C_NO_OID)
529 return 0;
530
531 major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
532 &name, &lifetime, NULL, NULL);
533 if (major == GSS_S_CREDENTIALS_EXPIRED)
534 return 0;
535 else if (GSS_ERROR(major))
536 return 0;
537
538 major = gss_compare_name(&minor, saved_name, name, &equal);
539 gss_release_name(&minor, &name);
540 if (GSS_ERROR(major))
541 return 0;
542
543 if (equal && (saved_lifetime < lifetime + now - 10))
544 return 1;
545
546 return 0;
547}
548
281#endif /* GSSAPI */ 549#endif /* GSSAPI */
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
index 5a625acb8..e7170ee41 100644
--- a/gss-serv-krb5.c
+++ b/gss-serv-krb5.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-serv-krb5.c,v 1.7 2006/08/03 03:34:42 deraadt Exp $ */ 1/* $OpenBSD: gss-serv-krb5.c,v 1.7 2006/08/03 03:34:42 deraadt Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 4 * Copyright (c) 2001-2007 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
@@ -120,6 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
120 krb5_principal princ; 120 krb5_principal princ;
121 OM_uint32 maj_status, min_status; 121 OM_uint32 maj_status, min_status;
122 int len; 122 int len;
123 const char *new_ccname;
123 124
124 if (client->creds == NULL) { 125 if (client->creds == NULL) {
125 debug("No credentials stored"); 126 debug("No credentials stored");
@@ -168,11 +169,16 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
168 return; 169 return;
169 } 170 }
170 171
171 client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); 172 new_ccname = krb5_cc_get_name(krb_context, ccache);
173
172 client->store.envvar = "KRB5CCNAME"; 174 client->store.envvar = "KRB5CCNAME";
173 len = strlen(client->store.filename) + 6; 175#ifdef USE_CCAPI
174 client->store.envval = xmalloc(len); 176 xasprintf(&client->store.envval, "API:%s", new_ccname);
175 snprintf(client->store.envval, len, "FILE:%s", client->store.filename); 177 client->store.filename = NULL;
178#else
179 xasprintf(&client->store.envval, "FILE:%s", new_ccname);
180 client->store.filename = xstrdup(new_ccname);
181#endif
176 182
177#ifdef USE_PAM 183#ifdef USE_PAM
178 if (options.use_pam) 184 if (options.use_pam)
@@ -184,6 +190,71 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
184 return; 190 return;
185} 191}
186 192
193int
194ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store,
195 ssh_gssapi_client *client)
196{
197 krb5_ccache ccache = NULL;
198 krb5_principal principal = NULL;
199 char *name = NULL;
200 krb5_error_code problem;
201 OM_uint32 maj_status, min_status;
202
203 if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) {
204 logit("krb5_cc_resolve(): %.100s",
205 krb5_get_err_text(krb_context, problem));
206 return 0;
207 }
208
209 /* Find out who the principal in this cache is */
210 if ((problem = krb5_cc_get_principal(krb_context, ccache,
211 &principal))) {
212 logit("krb5_cc_get_principal(): %.100s",
213 krb5_get_err_text(krb_context, problem));
214 krb5_cc_close(krb_context, ccache);
215 return 0;
216 }
217
218 if ((problem = krb5_unparse_name(krb_context, principal, &name))) {
219 logit("krb5_unparse_name(): %.100s",
220 krb5_get_err_text(krb_context, problem));
221 krb5_free_principal(krb_context, principal);
222 krb5_cc_close(krb_context, ccache);
223 return 0;
224 }
225
226
227 if (strcmp(name,client->exportedname.value)!=0) {
228 debug("Name in local credentials cache differs. Not storing");
229 krb5_free_principal(krb_context, principal);
230 krb5_cc_close(krb_context, ccache);
231 krb5_free_unparsed_name(krb_context, name);
232 return 0;
233 }
234 krb5_free_unparsed_name(krb_context, name);
235
236 /* Name matches, so lets get on with it! */
237
238 if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) {
239 logit("krb5_cc_initialize(): %.100s",
240 krb5_get_err_text(krb_context, problem));
241 krb5_free_principal(krb_context, principal);
242 krb5_cc_close(krb_context, ccache);
243 return 0;
244 }
245
246 krb5_free_principal(krb_context, principal);
247
248 if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds,
249 ccache))) {
250 logit("gss_krb5_copy_ccache() failed. Sorry!");
251 krb5_cc_close(krb_context, ccache);
252 return 0;
253 }
254
255 return 1;
256}
257
187ssh_gssapi_mech gssapi_kerberos_mech = { 258ssh_gssapi_mech gssapi_kerberos_mech = {
188 "toWM5Slw5Ew8Mqkay+al2g==", 259 "toWM5Slw5Ew8Mqkay+al2g==",
189 "Kerberos", 260 "Kerberos",
@@ -191,7 +262,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = {
191 NULL, 262 NULL,
192 &ssh_gssapi_krb5_userok, 263 &ssh_gssapi_krb5_userok,
193 NULL, 264 NULL,
194 &ssh_gssapi_krb5_storecreds 265 &ssh_gssapi_krb5_storecreds,
266 &ssh_gssapi_krb5_updatecreds
195}; 267};
196 268
197#endif /* KRB5 */ 269#endif /* KRB5 */
diff --git a/gss-serv.c b/gss-serv.c
index c719c1306..380895ea5 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-serv.c,v 1.23 2011/08/01 19:18:15 markus Exp $ */ 1/* $OpenBSD: gss-serv.c,v 1.23 2011/08/01 19:18:15 markus Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 4 * Copyright (c) 2001-2009 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
@@ -45,15 +45,20 @@
45#include "channels.h" 45#include "channels.h"
46#include "session.h" 46#include "session.h"
47#include "misc.h" 47#include "misc.h"
48#include "servconf.h"
49#include "uidswap.h"
48 50
49#include "ssh-gss.h" 51#include "ssh-gss.h"
52#include "monitor_wrap.h"
53
54extern ServerOptions options;
50 55
51static ssh_gssapi_client gssapi_client = 56static ssh_gssapi_client gssapi_client =
52 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, 57 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
53 GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}}; 58 GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL}, 0, 0};
54 59
55ssh_gssapi_mech gssapi_null_mech = 60ssh_gssapi_mech gssapi_null_mech =
56 { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; 61 { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
57 62
58#ifdef KRB5 63#ifdef KRB5
59extern ssh_gssapi_mech gssapi_kerberos_mech; 64extern ssh_gssapi_mech gssapi_kerberos_mech;
@@ -81,25 +86,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx)
81 char lname[MAXHOSTNAMELEN]; 86 char lname[MAXHOSTNAMELEN];
82 gss_OID_set oidset; 87 gss_OID_set oidset;
83 88
84 gss_create_empty_oid_set(&status, &oidset); 89 if (options.gss_strict_acceptor) {
85 gss_add_oid_set_member(&status, ctx->oid, &oidset); 90 gss_create_empty_oid_set(&status, &oidset);
91 gss_add_oid_set_member(&status, ctx->oid, &oidset);
86 92
87 if (gethostname(lname, MAXHOSTNAMELEN)) { 93 if (gethostname(lname, MAXHOSTNAMELEN)) {
88 gss_release_oid_set(&status, &oidset); 94 gss_release_oid_set(&status, &oidset);
89 return (-1); 95 return (-1);
90 } 96 }
97
98 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
99 gss_release_oid_set(&status, &oidset);
100 return (ctx->major);
101 }
102
103 if ((ctx->major = gss_acquire_cred(&ctx->minor,
104 ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds,
105 NULL, NULL)))
106 ssh_gssapi_error(ctx);
91 107
92 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
93 gss_release_oid_set(&status, &oidset); 108 gss_release_oid_set(&status, &oidset);
94 return (ctx->major); 109 return (ctx->major);
110 } else {
111 ctx->name = GSS_C_NO_NAME;
112 ctx->creds = GSS_C_NO_CREDENTIAL;
95 } 113 }
96 114 return GSS_S_COMPLETE;
97 if ((ctx->major = gss_acquire_cred(&ctx->minor,
98 ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
99 ssh_gssapi_error(ctx);
100
101 gss_release_oid_set(&status, &oidset);
102 return (ctx->major);
103} 115}
104 116
105/* Privileged */ 117/* Privileged */
@@ -114,6 +126,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
114} 126}
115 127
116/* Unprivileged */ 128/* Unprivileged */
129char *
130ssh_gssapi_server_mechanisms() {
131 gss_OID_set supported;
132
133 ssh_gssapi_supported_oids(&supported);
134 return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
135 NULL, NULL));
136}
137
138/* Unprivileged */
139int
140ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
141 const char *dummy) {
142 Gssctxt *ctx = NULL;
143 int res;
144
145 res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
146 ssh_gssapi_delete_ctx(&ctx);
147
148 return (res);
149}
150
151/* Unprivileged */
117void 152void
118ssh_gssapi_supported_oids(gss_OID_set *oidset) 153ssh_gssapi_supported_oids(gss_OID_set *oidset)
119{ 154{
@@ -123,7 +158,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset)
123 gss_OID_set supported; 158 gss_OID_set supported;
124 159
125 gss_create_empty_oid_set(&min_status, oidset); 160 gss_create_empty_oid_set(&min_status, oidset);
126 gss_indicate_mechs(&min_status, &supported); 161
162 if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
163 return;
127 164
128 while (supported_mechs[i]->name != NULL) { 165 while (supported_mechs[i]->name != NULL) {
129 if (GSS_ERROR(gss_test_oid_set_member(&min_status, 166 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
@@ -249,8 +286,48 @@ OM_uint32
249ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 286ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
250{ 287{
251 int i = 0; 288 int i = 0;
289 int equal = 0;
290 gss_name_t new_name = GSS_C_NO_NAME;
291 gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
292
293 if (options.gss_store_rekey && client->used && ctx->client_creds) {
294 if (client->mech->oid.length != ctx->oid->length ||
295 (memcmp(client->mech->oid.elements,
296 ctx->oid->elements, ctx->oid->length) !=0)) {
297 debug("Rekeyed credentials have different mechanism");
298 return GSS_S_COMPLETE;
299 }
300
301 if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
302 ctx->client_creds, ctx->oid, &new_name,
303 NULL, NULL, NULL))) {
304 ssh_gssapi_error(ctx);
305 return (ctx->major);
306 }
307
308 ctx->major = gss_compare_name(&ctx->minor, client->name,
309 new_name, &equal);
252 310
253 gss_buffer_desc ename; 311 if (GSS_ERROR(ctx->major)) {
312 ssh_gssapi_error(ctx);
313 return (ctx->major);
314 }
315
316 if (!equal) {
317 debug("Rekeyed credentials have different name");
318 return GSS_S_COMPLETE;
319 }
320
321 debug("Marking rekeyed credentials for export");
322
323 gss_release_name(&ctx->minor, &client->name);
324 gss_release_cred(&ctx->minor, &client->creds);
325 client->name = new_name;
326 client->creds = ctx->client_creds;
327 ctx->client_creds = GSS_C_NO_CREDENTIAL;
328 client->updated = 1;
329 return GSS_S_COMPLETE;
330 }
254 331
255 client->mech = NULL; 332 client->mech = NULL;
256 333
@@ -265,6 +342,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
265 if (client->mech == NULL) 342 if (client->mech == NULL)
266 return GSS_S_FAILURE; 343 return GSS_S_FAILURE;
267 344
345 if (ctx->client_creds &&
346 (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
347 ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
348 ssh_gssapi_error(ctx);
349 return (ctx->major);
350 }
351
268 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, 352 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
269 &client->displayname, NULL))) { 353 &client->displayname, NULL))) {
270 ssh_gssapi_error(ctx); 354 ssh_gssapi_error(ctx);
@@ -282,6 +366,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
282 return (ctx->major); 366 return (ctx->major);
283 } 367 }
284 368
369 gss_release_buffer(&ctx->minor, &ename);
370
285 /* We can't copy this structure, so we just move the pointer to it */ 371 /* We can't copy this structure, so we just move the pointer to it */
286 client->creds = ctx->client_creds; 372 client->creds = ctx->client_creds;
287 ctx->client_creds = GSS_C_NO_CREDENTIAL; 373 ctx->client_creds = GSS_C_NO_CREDENTIAL;
@@ -329,7 +415,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep)
329 415
330/* Privileged */ 416/* Privileged */
331int 417int
332ssh_gssapi_userok(char *user) 418ssh_gssapi_userok(char *user, struct passwd *pw)
333{ 419{
334 OM_uint32 lmin; 420 OM_uint32 lmin;
335 421
@@ -339,9 +425,11 @@ ssh_gssapi_userok(char *user)
339 return 0; 425 return 0;
340 } 426 }
341 if (gssapi_client.mech && gssapi_client.mech->userok) 427 if (gssapi_client.mech && gssapi_client.mech->userok)
342 if ((*gssapi_client.mech->userok)(&gssapi_client, user)) 428 if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
429 gssapi_client.used = 1;
430 gssapi_client.store.owner = pw;
343 return 1; 431 return 1;
344 else { 432 } else {
345 /* Destroy delegated credentials if userok fails */ 433 /* Destroy delegated credentials if userok fails */
346 gss_release_buffer(&lmin, &gssapi_client.displayname); 434 gss_release_buffer(&lmin, &gssapi_client.displayname);
347 gss_release_buffer(&lmin, &gssapi_client.exportedname); 435 gss_release_buffer(&lmin, &gssapi_client.exportedname);
@@ -354,14 +442,90 @@ ssh_gssapi_userok(char *user)
354 return (0); 442 return (0);
355} 443}
356 444
357/* Privileged */ 445/* These bits are only used for rekeying. The unpriviledged child is running
358OM_uint32 446 * as the user, the monitor is root.
359ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) 447 *
448 * In the child, we want to :
449 * *) Ask the monitor to store our credentials into the store we specify
450 * *) If it succeeds, maybe do a PAM update
451 */
452
453/* Stuff for PAM */
454
455#ifdef USE_PAM
456static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg,
457 struct pam_response **resp, void *data)
360{ 458{
361 ctx->major = gss_verify_mic(&ctx->minor, ctx->context, 459 return (PAM_CONV_ERR);
362 gssbuf, gssmic, NULL); 460}
461#endif
363 462
364 return (ctx->major); 463void
464ssh_gssapi_rekey_creds() {
465 int ok;
466 int ret;
467#ifdef USE_PAM
468 pam_handle_t *pamh = NULL;
469 struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
470 char *envstr;
471#endif
472
473 if (gssapi_client.store.filename == NULL &&
474 gssapi_client.store.envval == NULL &&
475 gssapi_client.store.envvar == NULL)
476 return;
477
478 ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
479
480 if (!ok)
481 return;
482
483 debug("Rekeyed credentials stored successfully");
484
485 /* Actually managing to play with the ssh pam stack from here will
486 * be next to impossible. In any case, we may want different options
487 * for rekeying. So, use our own :)
488 */
489#ifdef USE_PAM
490 if (!use_privsep) {
491 debug("Not even going to try and do PAM with privsep disabled");
492 return;
493 }
494
495 ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
496 &pamconv, &pamh);
497 if (ret)
498 return;
499
500 xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar,
501 gssapi_client.store.envval);
502
503 ret = pam_putenv(pamh, envstr);
504 if (!ret)
505 pam_setcred(pamh, PAM_REINITIALIZE_CRED);
506 pam_end(pamh, PAM_SUCCESS);
507#endif
508}
509
510int
511ssh_gssapi_update_creds(ssh_gssapi_ccache *store) {
512 int ok = 0;
513
514 /* Check we've got credentials to store */
515 if (!gssapi_client.updated)
516 return 0;
517
518 gssapi_client.updated = 0;
519
520 temporarily_use_uid(gssapi_client.store.owner);
521 if (gssapi_client.mech && gssapi_client.mech->updatecreds)
522 ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client);
523 else
524 debug("No update function for this mechanism");
525
526 restore_uid();
527
528 return ok;
365} 529}
366 530
367#endif 531#endif
diff --git a/kex.c b/kex.c
index 57a79dd9e..f9e7a9c09 100644
--- a/kex.c
+++ b/kex.c
@@ -50,6 +50,10 @@
50#include "monitor.h" 50#include "monitor.h"
51#include "roaming.h" 51#include "roaming.h"
52 52
53#ifdef GSSAPI
54#include "ssh-gss.h"
55#endif
56
53#if OPENSSL_VERSION_NUMBER >= 0x00907000L 57#if OPENSSL_VERSION_NUMBER >= 0x00907000L
54# if defined(HAVE_EVP_SHA256) 58# if defined(HAVE_EVP_SHA256)
55# define evp_ssh_sha256 EVP_sha256 59# define evp_ssh_sha256 EVP_sha256
@@ -369,6 +373,20 @@ choose_kex(Kex *k, char *client, char *server)
369 k->kex_type = KEX_ECDH_SHA2; 373 k->kex_type = KEX_ECDH_SHA2;
370 k->evp_md = kex_ecdh_name_to_evpmd(k->name); 374 k->evp_md = kex_ecdh_name_to_evpmd(k->name);
371#endif 375#endif
376#ifdef GSSAPI
377 } else if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID,
378 sizeof(KEX_GSS_GEX_SHA1_ID) - 1) == 0) {
379 k->kex_type = KEX_GSS_GEX_SHA1;
380 k->evp_md = EVP_sha1();
381 } else if (strncmp(k->name, KEX_GSS_GRP1_SHA1_ID,
382 sizeof(KEX_GSS_GRP1_SHA1_ID) - 1) == 0) {
383 k->kex_type = KEX_GSS_GRP1_SHA1;
384 k->evp_md = EVP_sha1();
385 } else if (strncmp(k->name, KEX_GSS_GRP14_SHA1_ID,
386 sizeof(KEX_GSS_GRP14_SHA1_ID) - 1) == 0) {
387 k->kex_type = KEX_GSS_GRP14_SHA1;
388 k->evp_md = EVP_sha1();
389#endif
372 } else 390 } else
373 fatal("bad kex alg %s", k->name); 391 fatal("bad kex alg %s", k->name);
374} 392}
diff --git a/kex.h b/kex.h
index 46731fa45..8013ab8a4 100644
--- a/kex.h
+++ b/kex.h
@@ -73,6 +73,9 @@ enum kex_exchange {
73 KEX_DH_GEX_SHA1, 73 KEX_DH_GEX_SHA1,
74 KEX_DH_GEX_SHA256, 74 KEX_DH_GEX_SHA256,
75 KEX_ECDH_SHA2, 75 KEX_ECDH_SHA2,
76 KEX_GSS_GRP1_SHA1,
77 KEX_GSS_GRP14_SHA1,
78 KEX_GSS_GEX_SHA1,
76 KEX_MAX 79 KEX_MAX
77}; 80};
78 81
@@ -131,6 +134,12 @@ struct Kex {
131 sig_atomic_t done; 134 sig_atomic_t done;
132 int flags; 135 int flags;
133 const EVP_MD *evp_md; 136 const EVP_MD *evp_md;
137#ifdef GSSAPI
138 int gss_deleg_creds;
139 int gss_trust_dns;
140 char *gss_host;
141 char *gss_client;
142#endif
134 char *client_version_string; 143 char *client_version_string;
135 char *server_version_string; 144 char *server_version_string;
136 int (*verify_host_key)(Key *); 145 int (*verify_host_key)(Key *);
@@ -158,6 +167,11 @@ void kexgex_server(Kex *);
158void kexecdh_client(Kex *); 167void kexecdh_client(Kex *);
159void kexecdh_server(Kex *); 168void kexecdh_server(Kex *);
160 169
170#ifdef GSSAPI
171void kexgss_client(Kex *);
172void kexgss_server(Kex *);
173#endif
174
161void 175void
162kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, 176kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
163 BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); 177 BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *);
diff --git a/kexgssc.c b/kexgssc.c
new file mode 100644
index 000000000..39be40531
--- /dev/null
+++ b/kexgssc.c
@@ -0,0 +1,334 @@
1/*
2 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
26
27#ifdef GSSAPI
28
29#include "includes.h"
30
31#include <openssl/crypto.h>
32#include <openssl/bn.h>
33
34#include <string.h>
35
36#include "xmalloc.h"
37#include "buffer.h"
38#include "ssh2.h"
39#include "key.h"
40#include "cipher.h"
41#include "kex.h"
42#include "log.h"
43#include "packet.h"
44#include "dh.h"
45
46#include "ssh-gss.h"
47
48void
49kexgss_client(Kex *kex) {
50 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
51 gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
52 Gssctxt *ctxt;
53 OM_uint32 maj_status, min_status, ret_flags;
54 u_int klen, kout, slen = 0, hashlen, strlen;
55 DH *dh;
56 BIGNUM *dh_server_pub = NULL;
57 BIGNUM *shared_secret = NULL;
58 BIGNUM *p = NULL;
59 BIGNUM *g = NULL;
60 u_char *kbuf, *hash;
61 u_char *serverhostkey = NULL;
62 u_char *empty = "";
63 char *msg;
64 char *lang;
65 int type = 0;
66 int first = 1;
67 int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
68
69 /* Initialise our GSSAPI world */
70 ssh_gssapi_build_ctx(&ctxt);
71 if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type)
72 == GSS_C_NO_OID)
73 fatal("Couldn't identify host exchange");
74
75 if (ssh_gssapi_import_name(ctxt, kex->gss_host))
76 fatal("Couldn't import hostname");
77
78 if (kex->gss_client &&
79 ssh_gssapi_client_identity(ctxt, kex->gss_client))
80 fatal("Couldn't acquire client credentials");
81
82 switch (kex->kex_type) {
83 case KEX_GSS_GRP1_SHA1:
84 dh = dh_new_group1();
85 break;
86 case KEX_GSS_GRP14_SHA1:
87 dh = dh_new_group14();
88 break;
89 case KEX_GSS_GEX_SHA1:
90 debug("Doing group exchange\n");
91 nbits = dh_estimate(kex->we_need * 8);
92 packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
93 packet_put_int(min);
94 packet_put_int(nbits);
95 packet_put_int(max);
96
97 packet_send();
98
99 packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
100
101 if ((p = BN_new()) == NULL)
102 fatal("BN_new() failed");
103 packet_get_bignum2(p);
104 if ((g = BN_new()) == NULL)
105 fatal("BN_new() failed");
106 packet_get_bignum2(g);
107 packet_check_eom();
108
109 if (BN_num_bits(p) < min || BN_num_bits(p) > max)
110 fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
111 min, BN_num_bits(p), max);
112
113 dh = dh_new_group(g, p);
114 break;
115 default:
116 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
117 }
118
119 /* Step 1 - e is dh->pub_key */
120 dh_gen_key(dh, kex->we_need * 8);
121
122 /* This is f, we initialise it now to make life easier */
123 dh_server_pub = BN_new();
124 if (dh_server_pub == NULL)
125 fatal("dh_server_pub == NULL");
126
127 token_ptr = GSS_C_NO_BUFFER;
128
129 do {
130 debug("Calling gss_init_sec_context");
131
132 maj_status = ssh_gssapi_init_ctx(ctxt,
133 kex->gss_deleg_creds, token_ptr, &send_tok,
134 &ret_flags);
135
136 if (GSS_ERROR(maj_status)) {
137 if (send_tok.length != 0) {
138 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
139 packet_put_string(send_tok.value,
140 send_tok.length);
141 }
142 fatal("gss_init_context failed");
143 }
144
145 /* If we've got an old receive buffer get rid of it */
146 if (token_ptr != GSS_C_NO_BUFFER)
147 xfree(recv_tok.value);
148
149 if (maj_status == GSS_S_COMPLETE) {
150 /* If mutual state flag is not true, kex fails */
151 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
152 fatal("Mutual authentication failed");
153
154 /* If integ avail flag is not true kex fails */
155 if (!(ret_flags & GSS_C_INTEG_FLAG))
156 fatal("Integrity check failed");
157 }
158
159 /*
160 * If we have data to send, then the last message that we
161 * received cannot have been a 'complete'.
162 */
163 if (send_tok.length != 0) {
164 if (first) {
165 packet_start(SSH2_MSG_KEXGSS_INIT);
166 packet_put_string(send_tok.value,
167 send_tok.length);
168 packet_put_bignum2(dh->pub_key);
169 first = 0;
170 } else {
171 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
172 packet_put_string(send_tok.value,
173 send_tok.length);
174 }
175 packet_send();
176 gss_release_buffer(&min_status, &send_tok);
177
178 /* If we've sent them data, they should reply */
179 do {
180 type = packet_read();
181 if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
182 debug("Received KEXGSS_HOSTKEY");
183 if (serverhostkey)
184 fatal("Server host key received more than once");
185 serverhostkey =
186 packet_get_string(&slen);
187 }
188 } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
189
190 switch (type) {
191 case SSH2_MSG_KEXGSS_CONTINUE:
192 debug("Received GSSAPI_CONTINUE");
193 if (maj_status == GSS_S_COMPLETE)
194 fatal("GSSAPI Continue received from server when complete");
195 recv_tok.value = packet_get_string(&strlen);
196 recv_tok.length = strlen;
197 break;
198 case SSH2_MSG_KEXGSS_COMPLETE:
199 debug("Received GSSAPI_COMPLETE");
200 packet_get_bignum2(dh_server_pub);
201 msg_tok.value = packet_get_string(&strlen);
202 msg_tok.length = strlen;
203
204 /* Is there a token included? */
205 if (packet_get_char()) {
206 recv_tok.value=
207 packet_get_string(&strlen);
208 recv_tok.length = strlen;
209 /* If we're already complete - protocol error */
210 if (maj_status == GSS_S_COMPLETE)
211 packet_disconnect("Protocol error: received token when complete");
212 } else {
213 /* No token included */
214 if (maj_status != GSS_S_COMPLETE)
215 packet_disconnect("Protocol error: did not receive final token");
216 }
217 break;
218 case SSH2_MSG_KEXGSS_ERROR:
219 debug("Received Error");
220 maj_status = packet_get_int();
221 min_status = packet_get_int();
222 msg = packet_get_string(NULL);
223 lang = packet_get_string(NULL);
224 fatal("GSSAPI Error: \n%.400s",msg);
225 default:
226 packet_disconnect("Protocol error: didn't expect packet type %d",
227 type);
228 }
229 token_ptr = &recv_tok;
230 } else {
231 /* No data, and not complete */
232 if (maj_status != GSS_S_COMPLETE)
233 fatal("Not complete, and no token output");
234 }
235 } while (maj_status & GSS_S_CONTINUE_NEEDED);
236
237 /*
238 * We _must_ have received a COMPLETE message in reply from the
239 * server, which will have set dh_server_pub and msg_tok
240 */
241
242 if (type != SSH2_MSG_KEXGSS_COMPLETE)
243 fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
244
245 /* Check f in range [1, p-1] */
246 if (!dh_pub_is_valid(dh, dh_server_pub))
247 packet_disconnect("bad server public DH value");
248
249 /* compute K=f^x mod p */
250 klen = DH_size(dh);
251 kbuf = xmalloc(klen);
252 kout = DH_compute_key(kbuf, dh_server_pub, dh);
253 if (kout < 0)
254 fatal("DH_compute_key: failed");
255
256 shared_secret = BN_new();
257 if (shared_secret == NULL)
258 fatal("kexgss_client: BN_new failed");
259
260 if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
261 fatal("kexdh_client: BN_bin2bn failed");
262
263 memset(kbuf, 0, klen);
264 xfree(kbuf);
265
266 switch (kex->kex_type) {
267 case KEX_GSS_GRP1_SHA1:
268 case KEX_GSS_GRP14_SHA1:
269 kex_dh_hash( kex->client_version_string,
270 kex->server_version_string,
271 buffer_ptr(&kex->my), buffer_len(&kex->my),
272 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
273 (serverhostkey ? serverhostkey : empty), slen,
274 dh->pub_key, /* e */
275 dh_server_pub, /* f */
276 shared_secret, /* K */
277 &hash, &hashlen
278 );
279 break;
280 case KEX_GSS_GEX_SHA1:
281 kexgex_hash(
282 kex->evp_md,
283 kex->client_version_string,
284 kex->server_version_string,
285 buffer_ptr(&kex->my), buffer_len(&kex->my),
286 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
287 (serverhostkey ? serverhostkey : empty), slen,
288 min, nbits, max,
289 dh->p, dh->g,
290 dh->pub_key,
291 dh_server_pub,
292 shared_secret,
293 &hash, &hashlen
294 );
295 break;
296 default:
297 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
298 }
299
300 gssbuf.value = hash;
301 gssbuf.length = hashlen;
302
303 /* Verify that the hash matches the MIC we just got. */
304 if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
305 packet_disconnect("Hash's MIC didn't verify");
306
307 xfree(msg_tok.value);
308
309 DH_free(dh);
310 if (serverhostkey)
311 xfree(serverhostkey);
312 BN_clear_free(dh_server_pub);
313
314 /* save session id */
315 if (kex->session_id == NULL) {
316 kex->session_id_len = hashlen;
317 kex->session_id = xmalloc(kex->session_id_len);
318 memcpy(kex->session_id, hash, kex->session_id_len);
319 }
320
321 if (kex->gss_deleg_creds)
322 ssh_gssapi_credentials_updated(ctxt);
323
324 if (gss_kex_context == NULL)
325 gss_kex_context = ctxt;
326 else
327 ssh_gssapi_delete_ctx(&ctxt);
328
329 kex_derive_keys(kex, hash, hashlen, shared_secret);
330 BN_clear_free(shared_secret);
331 kex_finish(kex);
332}
333
334#endif /* GSSAPI */
diff --git a/kexgsss.c b/kexgsss.c
new file mode 100644
index 000000000..0c3eeaa63
--- /dev/null
+++ b/kexgsss.c
@@ -0,0 +1,288 @@
1/*
2 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
26
27#ifdef GSSAPI
28
29#include <string.h>
30
31#include <openssl/crypto.h>
32#include <openssl/bn.h>
33
34#include "xmalloc.h"
35#include "buffer.h"
36#include "ssh2.h"
37#include "key.h"
38#include "cipher.h"
39#include "kex.h"
40#include "log.h"
41#include "packet.h"
42#include "dh.h"
43#include "ssh-gss.h"
44#include "monitor_wrap.h"
45#include "servconf.h"
46
47extern ServerOptions options;
48
49void
50kexgss_server(Kex *kex)
51{
52 OM_uint32 maj_status, min_status;
53
54 /*
55 * Some GSSAPI implementations use the input value of ret_flags (an
56 * output variable) as a means of triggering mechanism specific
57 * features. Initializing it to zero avoids inadvertently
58 * activating this non-standard behaviour.
59 */
60
61 OM_uint32 ret_flags = 0;
62 gss_buffer_desc gssbuf, recv_tok, msg_tok;
63 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
64 Gssctxt *ctxt = NULL;
65 u_int slen, klen, kout, hashlen;
66 u_char *kbuf, *hash;
67 DH *dh;
68 int min = -1, max = -1, nbits = -1;
69 BIGNUM *shared_secret = NULL;
70 BIGNUM *dh_client_pub = NULL;
71 int type = 0;
72 gss_OID oid;
73 char *mechs;
74
75 /* Initialise GSSAPI */
76
77 /* If we're rekeying, privsep means that some of the private structures
78 * in the GSSAPI code are no longer available. This kludges them back
79 * into life
80 */
81 if (!ssh_gssapi_oid_table_ok())
82 if ((mechs = ssh_gssapi_server_mechanisms()))
83 xfree(mechs);
84
85 debug2("%s: Identifying %s", __func__, kex->name);
86 oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type);
87 if (oid == GSS_C_NO_OID)
88 fatal("Unknown gssapi mechanism");
89
90 debug2("%s: Acquiring credentials", __func__);
91
92 if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
93 fatal("Unable to acquire credentials for the server");
94
95 switch (kex->kex_type) {
96 case KEX_GSS_GRP1_SHA1:
97 dh = dh_new_group1();
98 break;
99 case KEX_GSS_GRP14_SHA1:
100 dh = dh_new_group14();
101 break;
102 case KEX_GSS_GEX_SHA1:
103 debug("Doing group exchange");
104 packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ);
105 min = packet_get_int();
106 nbits = packet_get_int();
107 max = packet_get_int();
108 min = MAX(DH_GRP_MIN, min);
109 max = MIN(DH_GRP_MAX, max);
110 packet_check_eom();
111 if (max < min || nbits < min || max < nbits)
112 fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
113 min, nbits, max);
114 dh = PRIVSEP(choose_dh(min, nbits, max));
115 if (dh == NULL)
116 packet_disconnect("Protocol error: no matching group found");
117
118 packet_start(SSH2_MSG_KEXGSS_GROUP);
119 packet_put_bignum2(dh->p);
120 packet_put_bignum2(dh->g);
121 packet_send();
122
123 packet_write_wait();
124 break;
125 default:
126 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
127 }
128
129 dh_gen_key(dh, kex->we_need * 8);
130
131 do {
132 debug("Wait SSH2_MSG_GSSAPI_INIT");
133 type = packet_read();
134 switch(type) {
135 case SSH2_MSG_KEXGSS_INIT:
136 if (dh_client_pub != NULL)
137 fatal("Received KEXGSS_INIT after initialising");
138 recv_tok.value = packet_get_string(&slen);
139 recv_tok.length = slen;
140
141 if ((dh_client_pub = BN_new()) == NULL)
142 fatal("dh_client_pub == NULL");
143
144 packet_get_bignum2(dh_client_pub);
145
146 /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
147 break;
148 case SSH2_MSG_KEXGSS_CONTINUE:
149 recv_tok.value = packet_get_string(&slen);
150 recv_tok.length = slen;
151 break;
152 default:
153 packet_disconnect(
154 "Protocol error: didn't expect packet type %d",
155 type);
156 }
157
158 maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
159 &send_tok, &ret_flags));
160
161 xfree(recv_tok.value);
162
163 if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
164 fatal("Zero length token output when incomplete");
165
166 if (dh_client_pub == NULL)
167 fatal("No client public key");
168
169 if (maj_status & GSS_S_CONTINUE_NEEDED) {
170 debug("Sending GSSAPI_CONTINUE");
171 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
172 packet_put_string(send_tok.value, send_tok.length);
173 packet_send();
174 gss_release_buffer(&min_status, &send_tok);
175 }
176 } while (maj_status & GSS_S_CONTINUE_NEEDED);
177
178 if (GSS_ERROR(maj_status)) {
179 if (send_tok.length > 0) {
180 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
181 packet_put_string(send_tok.value, send_tok.length);
182 packet_send();
183 }
184 fatal("accept_ctx died");
185 }
186
187 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
188 fatal("Mutual Authentication flag wasn't set");
189
190 if (!(ret_flags & GSS_C_INTEG_FLAG))
191 fatal("Integrity flag wasn't set");
192
193 if (!dh_pub_is_valid(dh, dh_client_pub))
194 packet_disconnect("bad client public DH value");
195
196 klen = DH_size(dh);
197 kbuf = xmalloc(klen);
198 kout = DH_compute_key(kbuf, dh_client_pub, dh);
199 if (kout < 0)
200 fatal("DH_compute_key: failed");
201
202 shared_secret = BN_new();
203 if (shared_secret == NULL)
204 fatal("kexgss_server: BN_new failed");
205
206 if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
207 fatal("kexgss_server: BN_bin2bn failed");
208
209 memset(kbuf, 0, klen);
210 xfree(kbuf);
211
212 switch (kex->kex_type) {
213 case KEX_GSS_GRP1_SHA1:
214 case KEX_GSS_GRP14_SHA1:
215 kex_dh_hash(
216 kex->client_version_string, kex->server_version_string,
217 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
218 buffer_ptr(&kex->my), buffer_len(&kex->my),
219 NULL, 0, /* Change this if we start sending host keys */
220 dh_client_pub, dh->pub_key, shared_secret,
221 &hash, &hashlen
222 );
223 break;
224 case KEX_GSS_GEX_SHA1:
225 kexgex_hash(
226 kex->evp_md,
227 kex->client_version_string, kex->server_version_string,
228 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
229 buffer_ptr(&kex->my), buffer_len(&kex->my),
230 NULL, 0,
231 min, nbits, max,
232 dh->p, dh->g,
233 dh_client_pub,
234 dh->pub_key,
235 shared_secret,
236 &hash, &hashlen
237 );
238 break;
239 default:
240 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
241 }
242
243 BN_clear_free(dh_client_pub);
244
245 if (kex->session_id == NULL) {
246 kex->session_id_len = hashlen;
247 kex->session_id = xmalloc(kex->session_id_len);
248 memcpy(kex->session_id, hash, kex->session_id_len);
249 }
250
251 gssbuf.value = hash;
252 gssbuf.length = hashlen;
253
254 if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok))))
255 fatal("Couldn't get MIC");
256
257 packet_start(SSH2_MSG_KEXGSS_COMPLETE);
258 packet_put_bignum2(dh->pub_key);
259 packet_put_string(msg_tok.value,msg_tok.length);
260
261 if (send_tok.length != 0) {
262 packet_put_char(1); /* true */
263 packet_put_string(send_tok.value, send_tok.length);
264 } else {
265 packet_put_char(0); /* false */
266 }
267 packet_send();
268
269 gss_release_buffer(&min_status, &send_tok);
270 gss_release_buffer(&min_status, &msg_tok);
271
272 if (gss_kex_context == NULL)
273 gss_kex_context = ctxt;
274 else
275 ssh_gssapi_delete_ctx(&ctxt);
276
277 DH_free(dh);
278
279 kex_derive_keys(kex, hash, hashlen, shared_secret);
280 BN_clear_free(shared_secret);
281 kex_finish(kex);
282
283 /* If this was a rekey, then save out any delegated credentials we
284 * just exchanged. */
285 if (options.gss_store_rekey)
286 ssh_gssapi_rekey_creds();
287}
288#endif /* GSSAPI */
diff --git a/key.c b/key.c
index 4cc5c5d35..fdfed5c56 100644
--- a/key.c
+++ b/key.c
@@ -976,6 +976,8 @@ key_ssh_name_from_type_nid(int type, int nid)
976 } 976 }
977 break; 977 break;
978#endif /* OPENSSL_HAS_ECC */ 978#endif /* OPENSSL_HAS_ECC */
979 case KEY_NULL:
980 return "null";
979 } 981 }
980 return "ssh-unknown"; 982 return "ssh-unknown";
981} 983}
@@ -1281,6 +1283,8 @@ key_type_from_name(char *name)
1281 strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0) { 1283 strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0) {
1282 return KEY_ECDSA_CERT; 1284 return KEY_ECDSA_CERT;
1283#endif 1285#endif
1286 } else if (strcmp(name, "null") == 0) {
1287 return KEY_NULL;
1284 } 1288 }
1285 1289
1286 debug2("key_type_from_name: unknown key type '%s'", name); 1290 debug2("key_type_from_name: unknown key type '%s'", name);
diff --git a/key.h b/key.h
index ebdf45677..4beaf202e 100644
--- a/key.h
+++ b/key.h
@@ -44,6 +44,7 @@ enum types {
44 KEY_ECDSA_CERT, 44 KEY_ECDSA_CERT,
45 KEY_RSA_CERT_V00, 45 KEY_RSA_CERT_V00,
46 KEY_DSA_CERT_V00, 46 KEY_DSA_CERT_V00,
47 KEY_NULL,
47 KEY_UNSPEC 48 KEY_UNSPEC
48}; 49};
49enum fp_type { 50enum fp_type {
diff --git a/monitor.c b/monitor.c
index 8006b833c..d7a782f89 100644
--- a/monitor.c
+++ b/monitor.c
@@ -180,6 +180,8 @@ int mm_answer_gss_setup_ctx(int, Buffer *);
180int mm_answer_gss_accept_ctx(int, Buffer *); 180int mm_answer_gss_accept_ctx(int, Buffer *);
181int mm_answer_gss_userok(int, Buffer *); 181int mm_answer_gss_userok(int, Buffer *);
182int mm_answer_gss_checkmic(int, Buffer *); 182int mm_answer_gss_checkmic(int, Buffer *);
183int mm_answer_gss_sign(int, Buffer *);
184int mm_answer_gss_updatecreds(int, Buffer *);
183#endif 185#endif
184 186
185#ifdef SSH_AUDIT_EVENTS 187#ifdef SSH_AUDIT_EVENTS
@@ -252,6 +254,7 @@ struct mon_table mon_dispatch_proto20[] = {
252 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, 254 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
253 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, 255 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
254 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, 256 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
257 {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
255#endif 258#endif
256#ifdef JPAKE 259#ifdef JPAKE
257 {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata}, 260 {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata},
@@ -264,6 +267,12 @@ struct mon_table mon_dispatch_proto20[] = {
264}; 267};
265 268
266struct mon_table mon_dispatch_postauth20[] = { 269struct mon_table mon_dispatch_postauth20[] = {
270#ifdef GSSAPI
271 {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
272 {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
273 {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
274 {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
275#endif
267 {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, 276 {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
268 {MONITOR_REQ_SIGN, 0, mm_answer_sign}, 277 {MONITOR_REQ_SIGN, 0, mm_answer_sign},
269 {MONITOR_REQ_PTY, 0, mm_answer_pty}, 278 {MONITOR_REQ_PTY, 0, mm_answer_pty},
@@ -372,6 +381,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
372 /* Permit requests for moduli and signatures */ 381 /* Permit requests for moduli and signatures */
373 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 382 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
374 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 383 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
384#ifdef GSSAPI
385 /* and for the GSSAPI key exchange */
386 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
387#endif
375 } else { 388 } else {
376 mon_dispatch = mon_dispatch_proto15; 389 mon_dispatch = mon_dispatch_proto15;
377 390
@@ -487,6 +500,10 @@ monitor_child_postauth(struct monitor *pmonitor)
487 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 500 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
488 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 501 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
489 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 502 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
503#ifdef GSSAPI
504 /* and for the GSSAPI key exchange */
505 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
506#endif
490 } else { 507 } else {
491 mon_dispatch = mon_dispatch_postauth15; 508 mon_dispatch = mon_dispatch_postauth15;
492 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 509 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
@@ -1836,6 +1853,13 @@ mm_get_kex(Buffer *m)
1836 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 1853 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
1837 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 1854 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
1838 kex->kex[KEX_ECDH_SHA2] = kexecdh_server; 1855 kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
1856#ifdef GSSAPI
1857 if (options.gss_keyex) {
1858 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
1859 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
1860 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
1861 }
1862#endif
1839 kex->server = 1; 1863 kex->server = 1;
1840 kex->hostkey_type = buffer_get_int(m); 1864 kex->hostkey_type = buffer_get_int(m);
1841 kex->kex_type = buffer_get_int(m); 1865 kex->kex_type = buffer_get_int(m);
@@ -2042,6 +2066,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer *m)
2042 OM_uint32 major; 2066 OM_uint32 major;
2043 u_int len; 2067 u_int len;
2044 2068
2069 if (!options.gss_authentication && !options.gss_keyex)
2070 fatal("In GSSAPI monitor when GSSAPI is disabled");
2071
2045 goid.elements = buffer_get_string(m, &len); 2072 goid.elements = buffer_get_string(m, &len);
2046 goid.length = len; 2073 goid.length = len;
2047 2074
@@ -2069,6 +2096,9 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
2069 OM_uint32 flags = 0; /* GSI needs this */ 2096 OM_uint32 flags = 0; /* GSI needs this */
2070 u_int len; 2097 u_int len;
2071 2098
2099 if (!options.gss_authentication && !options.gss_keyex)
2100 fatal("In GSSAPI monitor when GSSAPI is disabled");
2101
2072 in.value = buffer_get_string(m, &len); 2102 in.value = buffer_get_string(m, &len);
2073 in.length = len; 2103 in.length = len;
2074 major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); 2104 major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
@@ -2086,6 +2116,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
2086 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); 2116 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
2087 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); 2117 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
2088 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); 2118 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
2119 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
2089 } 2120 }
2090 return (0); 2121 return (0);
2091} 2122}
@@ -2097,6 +2128,9 @@ mm_answer_gss_checkmic(int sock, Buffer *m)
2097 OM_uint32 ret; 2128 OM_uint32 ret;
2098 u_int len; 2129 u_int len;
2099 2130
2131 if (!options.gss_authentication && !options.gss_keyex)
2132 fatal("In GSSAPI monitor when GSSAPI is disabled");
2133
2100 gssbuf.value = buffer_get_string(m, &len); 2134 gssbuf.value = buffer_get_string(m, &len);
2101 gssbuf.length = len; 2135 gssbuf.length = len;
2102 mic.value = buffer_get_string(m, &len); 2136 mic.value = buffer_get_string(m, &len);
@@ -2123,7 +2157,11 @@ mm_answer_gss_userok(int sock, Buffer *m)
2123{ 2157{
2124 int authenticated; 2158 int authenticated;
2125 2159
2126 authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); 2160 if (!options.gss_authentication && !options.gss_keyex)
2161 fatal("In GSSAPI monitor when GSSAPI is disabled");
2162
2163 authenticated = authctxt->valid &&
2164 ssh_gssapi_userok(authctxt->user, authctxt->pw);
2127 2165
2128 buffer_clear(m); 2166 buffer_clear(m);
2129 buffer_put_int(m, authenticated); 2167 buffer_put_int(m, authenticated);
@@ -2136,6 +2174,74 @@ mm_answer_gss_userok(int sock, Buffer *m)
2136 /* Monitor loop will terminate if authenticated */ 2174 /* Monitor loop will terminate if authenticated */
2137 return (authenticated); 2175 return (authenticated);
2138} 2176}
2177
2178int
2179mm_answer_gss_sign(int socket, Buffer *m)
2180{
2181 gss_buffer_desc data;
2182 gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
2183 OM_uint32 major, minor;
2184 u_int len;
2185
2186 if (!options.gss_authentication && !options.gss_keyex)
2187 fatal("In GSSAPI monitor when GSSAPI is disabled");
2188
2189 data.value = buffer_get_string(m, &len);
2190 data.length = len;
2191 if (data.length != 20)
2192 fatal("%s: data length incorrect: %d", __func__,
2193 (int) data.length);
2194
2195 /* Save the session ID on the first time around */
2196 if (session_id2_len == 0) {
2197 session_id2_len = data.length;
2198 session_id2 = xmalloc(session_id2_len);
2199 memcpy(session_id2, data.value, session_id2_len);
2200 }
2201 major = ssh_gssapi_sign(gsscontext, &data, &hash);
2202
2203 xfree(data.value);
2204
2205 buffer_clear(m);
2206 buffer_put_int(m, major);
2207 buffer_put_string(m, hash.value, hash.length);
2208
2209 mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
2210
2211 gss_release_buffer(&minor, &hash);
2212
2213 /* Turn on getpwnam permissions */
2214 monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
2215
2216 /* And credential updating, for when rekeying */
2217 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1);
2218
2219 return (0);
2220}
2221
2222int
2223mm_answer_gss_updatecreds(int socket, Buffer *m) {
2224 ssh_gssapi_ccache store;
2225 int ok;
2226
2227 store.filename = buffer_get_string(m, NULL);
2228 store.envvar = buffer_get_string(m, NULL);
2229 store.envval = buffer_get_string(m, NULL);
2230
2231 ok = ssh_gssapi_update_creds(&store);
2232
2233 xfree(store.filename);
2234 xfree(store.envvar);
2235 xfree(store.envval);
2236
2237 buffer_clear(m);
2238 buffer_put_int(m, ok);
2239
2240 mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m);
2241
2242 return(0);
2243}
2244
2139#endif /* GSSAPI */ 2245#endif /* GSSAPI */
2140 2246
2141#ifdef JPAKE 2247#ifdef JPAKE
diff --git a/monitor.h b/monitor.h
index 2caa46933..9aa4e6fe5 100644
--- a/monitor.h
+++ b/monitor.h
@@ -70,6 +70,9 @@ enum monitor_reqtype {
70 MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, 70 MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
71 MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, 71 MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
72 72
73 MONITOR_REQ_GSSSIGN = 200, MONITOR_ANS_GSSSIGN = 201,
74 MONITOR_REQ_GSSUPCREDS = 202, MONITOR_ANS_GSSUPCREDS = 203,
75
73}; 76};
74 77
75struct mm_master; 78struct mm_master;
diff --git a/monitor_wrap.c b/monitor_wrap.c
index ea654a73f..ed8dbdadf 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1271,7 +1271,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
1271} 1271}
1272 1272
1273int 1273int
1274mm_ssh_gssapi_userok(char *user) 1274mm_ssh_gssapi_userok(char *user, struct passwd *pw)
1275{ 1275{
1276 Buffer m; 1276 Buffer m;
1277 int authenticated = 0; 1277 int authenticated = 0;
@@ -1288,6 +1288,51 @@ mm_ssh_gssapi_userok(char *user)
1288 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); 1288 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
1289 return (authenticated); 1289 return (authenticated);
1290} 1290}
1291
1292OM_uint32
1293mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
1294{
1295 Buffer m;
1296 OM_uint32 major;
1297 u_int len;
1298
1299 buffer_init(&m);
1300 buffer_put_string(&m, data->value, data->length);
1301
1302 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
1303 mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
1304
1305 major = buffer_get_int(&m);
1306 hash->value = buffer_get_string(&m, &len);
1307 hash->length = len;
1308
1309 buffer_free(&m);
1310
1311 return(major);
1312}
1313
1314int
1315mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store)
1316{
1317 Buffer m;
1318 int ok;
1319
1320 buffer_init(&m);
1321
1322 buffer_put_cstring(&m, store->filename ? store->filename : "");
1323 buffer_put_cstring(&m, store->envvar ? store->envvar : "");
1324 buffer_put_cstring(&m, store->envval ? store->envval : "");
1325
1326 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m);
1327 mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m);
1328
1329 ok = buffer_get_int(&m);
1330
1331 buffer_free(&m);
1332
1333 return (ok);
1334}
1335
1291#endif /* GSSAPI */ 1336#endif /* GSSAPI */
1292 1337
1293#ifdef JPAKE 1338#ifdef JPAKE
diff --git a/monitor_wrap.h b/monitor_wrap.h
index 0c7f2e384..ec9b9b1c3 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -58,8 +58,10 @@ BIGNUM *mm_auth_rsa_generate_challenge(Key *);
58OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); 58OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
59OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, 59OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
60 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); 60 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
61int mm_ssh_gssapi_userok(char *user); 61int mm_ssh_gssapi_userok(char *user, struct passwd *);
62OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 62OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
63OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
64int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
63#endif 65#endif
64 66
65#ifdef USE_PAM 67#ifdef USE_PAM
diff --git a/readconf.c b/readconf.c
index 097bb0515..99c04a9de 100644
--- a/readconf.c
+++ b/readconf.c
@@ -129,6 +129,8 @@ typedef enum {
129 oClearAllForwardings, oNoHostAuthenticationForLocalhost, 129 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
130 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 130 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
131 oAddressFamily, oGssAuthentication, oGssDelegateCreds, 131 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
132 oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey,
133 oGssServerIdentity,
132 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 134 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
133 oSendEnv, oControlPath, oControlMaster, oControlPersist, 135 oSendEnv, oControlPath, oControlMaster, oControlPersist,
134 oHashKnownHosts, 136 oHashKnownHosts,
@@ -169,10 +171,19 @@ static struct {
169 { "afstokenpassing", oUnsupported }, 171 { "afstokenpassing", oUnsupported },
170#if defined(GSSAPI) 172#if defined(GSSAPI)
171 { "gssapiauthentication", oGssAuthentication }, 173 { "gssapiauthentication", oGssAuthentication },
174 { "gssapikeyexchange", oGssKeyEx },
172 { "gssapidelegatecredentials", oGssDelegateCreds }, 175 { "gssapidelegatecredentials", oGssDelegateCreds },
176 { "gssapitrustdns", oGssTrustDns },
177 { "gssapiclientidentity", oGssClientIdentity },
178 { "gssapiserveridentity", oGssServerIdentity },
179 { "gssapirenewalforcesrekey", oGssRenewalRekey },
173#else 180#else
174 { "gssapiauthentication", oUnsupported }, 181 { "gssapiauthentication", oUnsupported },
182 { "gssapikeyexchange", oUnsupported },
175 { "gssapidelegatecredentials", oUnsupported }, 183 { "gssapidelegatecredentials", oUnsupported },
184 { "gssapitrustdns", oUnsupported },
185 { "gssapiclientidentity", oUnsupported },
186 { "gssapirenewalforcesrekey", oUnsupported },
176#endif 187#endif
177 { "fallbacktorsh", oDeprecated }, 188 { "fallbacktorsh", oDeprecated },
178 { "usersh", oDeprecated }, 189 { "usersh", oDeprecated },
@@ -483,10 +494,30 @@ parse_flag:
483 intptr = &options->gss_authentication; 494 intptr = &options->gss_authentication;
484 goto parse_flag; 495 goto parse_flag;
485 496
497 case oGssKeyEx:
498 intptr = &options->gss_keyex;
499 goto parse_flag;
500
486 case oGssDelegateCreds: 501 case oGssDelegateCreds:
487 intptr = &options->gss_deleg_creds; 502 intptr = &options->gss_deleg_creds;
488 goto parse_flag; 503 goto parse_flag;
489 504
505 case oGssTrustDns:
506 intptr = &options->gss_trust_dns;
507 goto parse_flag;
508
509 case oGssClientIdentity:
510 charptr = &options->gss_client_identity;
511 goto parse_string;
512
513 case oGssServerIdentity:
514 charptr = &options->gss_server_identity;
515 goto parse_string;
516
517 case oGssRenewalRekey:
518 intptr = &options->gss_renewal_rekey;
519 goto parse_flag;
520
490 case oBatchMode: 521 case oBatchMode:
491 intptr = &options->batch_mode; 522 intptr = &options->batch_mode;
492 goto parse_flag; 523 goto parse_flag;
@@ -1139,7 +1170,12 @@ initialize_options(Options * options)
1139 options->pubkey_authentication = -1; 1170 options->pubkey_authentication = -1;
1140 options->challenge_response_authentication = -1; 1171 options->challenge_response_authentication = -1;
1141 options->gss_authentication = -1; 1172 options->gss_authentication = -1;
1173 options->gss_keyex = -1;
1142 options->gss_deleg_creds = -1; 1174 options->gss_deleg_creds = -1;
1175 options->gss_trust_dns = -1;
1176 options->gss_renewal_rekey = -1;
1177 options->gss_client_identity = NULL;
1178 options->gss_server_identity = NULL;
1143 options->password_authentication = -1; 1179 options->password_authentication = -1;
1144 options->kbd_interactive_authentication = -1; 1180 options->kbd_interactive_authentication = -1;
1145 options->kbd_interactive_devices = NULL; 1181 options->kbd_interactive_devices = NULL;
@@ -1239,8 +1275,14 @@ fill_default_options(Options * options)
1239 options->challenge_response_authentication = 1; 1275 options->challenge_response_authentication = 1;
1240 if (options->gss_authentication == -1) 1276 if (options->gss_authentication == -1)
1241 options->gss_authentication = 0; 1277 options->gss_authentication = 0;
1278 if (options->gss_keyex == -1)
1279 options->gss_keyex = 0;
1242 if (options->gss_deleg_creds == -1) 1280 if (options->gss_deleg_creds == -1)
1243 options->gss_deleg_creds = 0; 1281 options->gss_deleg_creds = 0;
1282 if (options->gss_trust_dns == -1)
1283 options->gss_trust_dns = 0;
1284 if (options->gss_renewal_rekey == -1)
1285 options->gss_renewal_rekey = 0;
1244 if (options->password_authentication == -1) 1286 if (options->password_authentication == -1)
1245 options->password_authentication = 1; 1287 options->password_authentication = 1;
1246 if (options->kbd_interactive_authentication == -1) 1288 if (options->kbd_interactive_authentication == -1)
diff --git a/readconf.h b/readconf.h
index be30ee0e1..41f1befae 100644
--- a/readconf.h
+++ b/readconf.h
@@ -48,7 +48,12 @@ typedef struct {
48 int challenge_response_authentication; 48 int challenge_response_authentication;
49 /* Try S/Key or TIS, authentication. */ 49 /* Try S/Key or TIS, authentication. */
50 int gss_authentication; /* Try GSS authentication */ 50 int gss_authentication; /* Try GSS authentication */
51 int gss_keyex; /* Try GSS key exchange */
51 int gss_deleg_creds; /* Delegate GSS credentials */ 52 int gss_deleg_creds; /* Delegate GSS credentials */
53 int gss_trust_dns; /* Trust DNS for GSS canonicalization */
54 int gss_renewal_rekey; /* Credential renewal forces rekey */
55 char *gss_client_identity; /* Principal to initiate GSSAPI with */
56 char *gss_server_identity; /* GSSAPI target principal */
52 int password_authentication; /* Try password 57 int password_authentication; /* Try password
53 * authentication. */ 58 * authentication. */
54 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ 59 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */
diff --git a/servconf.c b/servconf.c
index b2a60fd6c..cdc029308 100644
--- a/servconf.c
+++ b/servconf.c
@@ -102,7 +102,10 @@ initialize_server_options(ServerOptions *options)
102 options->kerberos_ticket_cleanup = -1; 102 options->kerberos_ticket_cleanup = -1;
103 options->kerberos_get_afs_token = -1; 103 options->kerberos_get_afs_token = -1;
104 options->gss_authentication=-1; 104 options->gss_authentication=-1;
105 options->gss_keyex = -1;
105 options->gss_cleanup_creds = -1; 106 options->gss_cleanup_creds = -1;
107 options->gss_strict_acceptor = -1;
108 options->gss_store_rekey = -1;
106 options->password_authentication = -1; 109 options->password_authentication = -1;
107 options->kbd_interactive_authentication = -1; 110 options->kbd_interactive_authentication = -1;
108 options->challenge_response_authentication = -1; 111 options->challenge_response_authentication = -1;
@@ -233,8 +236,14 @@ fill_default_server_options(ServerOptions *options)
233 options->kerberos_get_afs_token = 0; 236 options->kerberos_get_afs_token = 0;
234 if (options->gss_authentication == -1) 237 if (options->gss_authentication == -1)
235 options->gss_authentication = 0; 238 options->gss_authentication = 0;
239 if (options->gss_keyex == -1)
240 options->gss_keyex = 0;
236 if (options->gss_cleanup_creds == -1) 241 if (options->gss_cleanup_creds == -1)
237 options->gss_cleanup_creds = 1; 242 options->gss_cleanup_creds = 1;
243 if (options->gss_strict_acceptor == -1)
244 options->gss_strict_acceptor = 1;
245 if (options->gss_store_rekey == -1)
246 options->gss_store_rekey = 0;
238 if (options->password_authentication == -1) 247 if (options->password_authentication == -1)
239 options->password_authentication = 1; 248 options->password_authentication = 1;
240 if (options->kbd_interactive_authentication == -1) 249 if (options->kbd_interactive_authentication == -1)
@@ -327,7 +336,9 @@ typedef enum {
327 sBanner, sUseDNS, sHostbasedAuthentication, 336 sBanner, sUseDNS, sHostbasedAuthentication,
328 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, 337 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
329 sClientAliveCountMax, sAuthorizedKeysFile, 338 sClientAliveCountMax, sAuthorizedKeysFile,
330 sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, 339 sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
340 sGssKeyEx, sGssStoreRekey,
341 sAcceptEnv, sPermitTunnel,
331 sMatch, sPermitOpen, sForceCommand, sChrootDirectory, 342 sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
332 sUsePrivilegeSeparation, sAllowAgentForwarding, 343 sUsePrivilegeSeparation, sAllowAgentForwarding,
333 sZeroKnowledgePasswordAuthentication, sHostCertificate, 344 sZeroKnowledgePasswordAuthentication, sHostCertificate,
@@ -393,10 +404,20 @@ static struct {
393#ifdef GSSAPI 404#ifdef GSSAPI
394 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, 405 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
395 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, 406 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
407 { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
408 { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
409 { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
410 { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
396#else 411#else
397 { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, 412 { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
398 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, 413 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
414 { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
415 { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
416 { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
417 { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
399#endif 418#endif
419 { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
420 { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
400 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, 421 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
401 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, 422 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
402 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, 423 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
@@ -1049,10 +1070,22 @@ process_server_config_line(ServerOptions *options, char *line,
1049 intptr = &options->gss_authentication; 1070 intptr = &options->gss_authentication;
1050 goto parse_flag; 1071 goto parse_flag;
1051 1072
1073 case sGssKeyEx:
1074 intptr = &options->gss_keyex;
1075 goto parse_flag;
1076
1052 case sGssCleanupCreds: 1077 case sGssCleanupCreds:
1053 intptr = &options->gss_cleanup_creds; 1078 intptr = &options->gss_cleanup_creds;
1054 goto parse_flag; 1079 goto parse_flag;
1055 1080
1081 case sGssStrictAcceptor:
1082 intptr = &options->gss_strict_acceptor;
1083 goto parse_flag;
1084
1085 case sGssStoreRekey:
1086 intptr = &options->gss_store_rekey;
1087 goto parse_flag;
1088
1056 case sPasswordAuthentication: 1089 case sPasswordAuthentication:
1057 intptr = &options->password_authentication; 1090 intptr = &options->password_authentication;
1058 goto parse_flag; 1091 goto parse_flag;
@@ -1927,7 +1960,10 @@ dump_config(ServerOptions *o)
1927#endif 1960#endif
1928#ifdef GSSAPI 1961#ifdef GSSAPI
1929 dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); 1962 dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
1963 dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
1930 dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); 1964 dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
1965 dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
1966 dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey);
1931#endif 1967#endif
1932#ifdef JPAKE 1968#ifdef JPAKE
1933 dump_cfg_fmtint(sZeroKnowledgePasswordAuthentication, 1969 dump_cfg_fmtint(sZeroKnowledgePasswordAuthentication,
diff --git a/servconf.h b/servconf.h
index 870c70982..06e21a93d 100644
--- a/servconf.h
+++ b/servconf.h
@@ -110,7 +110,10 @@ typedef struct {
110 int kerberos_get_afs_token; /* If true, try to get AFS token if 110 int kerberos_get_afs_token; /* If true, try to get AFS token if
111 * authenticated with Kerberos. */ 111 * authenticated with Kerberos. */
112 int gss_authentication; /* If true, permit GSSAPI authentication */ 112 int gss_authentication; /* If true, permit GSSAPI authentication */
113 int gss_keyex; /* If true, permit GSSAPI key exchange */
113 int gss_cleanup_creds; /* If true, destroy cred cache on logout */ 114 int gss_cleanup_creds; /* If true, destroy cred cache on logout */
115 int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */
116 int gss_store_rekey;
114 int password_authentication; /* If true, permit password 117 int password_authentication; /* If true, permit password
115 * authentication. */ 118 * authentication. */
116 int kbd_interactive_authentication; /* If true, permit */ 119 int kbd_interactive_authentication; /* If true, permit */
diff --git a/ssh-gss.h b/ssh-gss.h
index 077e13ce4..bc6e8f946 100644
--- a/ssh-gss.h
+++ b/ssh-gss.h
@@ -1,6 +1,6 @@
1/* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */ 1/* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 3 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
@@ -61,10 +61,22 @@
61 61
62#define SSH_GSS_OIDTYPE 0x06 62#define SSH_GSS_OIDTYPE 0x06
63 63
64#define SSH2_MSG_KEXGSS_INIT 30
65#define SSH2_MSG_KEXGSS_CONTINUE 31
66#define SSH2_MSG_KEXGSS_COMPLETE 32
67#define SSH2_MSG_KEXGSS_HOSTKEY 33
68#define SSH2_MSG_KEXGSS_ERROR 34
69#define SSH2_MSG_KEXGSS_GROUPREQ 40
70#define SSH2_MSG_KEXGSS_GROUP 41
71#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-"
72#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-"
73#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-"
74
64typedef struct { 75typedef struct {
65 char *filename; 76 char *filename;
66 char *envvar; 77 char *envvar;
67 char *envval; 78 char *envval;
79 struct passwd *owner;
68 void *data; 80 void *data;
69} ssh_gssapi_ccache; 81} ssh_gssapi_ccache;
70 82
@@ -72,8 +84,11 @@ typedef struct {
72 gss_buffer_desc displayname; 84 gss_buffer_desc displayname;
73 gss_buffer_desc exportedname; 85 gss_buffer_desc exportedname;
74 gss_cred_id_t creds; 86 gss_cred_id_t creds;
87 gss_name_t name;
75 struct ssh_gssapi_mech_struct *mech; 88 struct ssh_gssapi_mech_struct *mech;
76 ssh_gssapi_ccache store; 89 ssh_gssapi_ccache store;
90 int used;
91 int updated;
77} ssh_gssapi_client; 92} ssh_gssapi_client;
78 93
79typedef struct ssh_gssapi_mech_struct { 94typedef struct ssh_gssapi_mech_struct {
@@ -84,6 +99,7 @@ typedef struct ssh_gssapi_mech_struct {
84 int (*userok) (ssh_gssapi_client *, char *); 99 int (*userok) (ssh_gssapi_client *, char *);
85 int (*localname) (ssh_gssapi_client *, char **); 100 int (*localname) (ssh_gssapi_client *, char **);
86 void (*storecreds) (ssh_gssapi_client *); 101 void (*storecreds) (ssh_gssapi_client *);
102 int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *);
87} ssh_gssapi_mech; 103} ssh_gssapi_mech;
88 104
89typedef struct { 105typedef struct {
@@ -94,10 +110,11 @@ typedef struct {
94 gss_OID oid; /* client */ 110 gss_OID oid; /* client */
95 gss_cred_id_t creds; /* server */ 111 gss_cred_id_t creds; /* server */
96 gss_name_t client; /* server */ 112 gss_name_t client; /* server */
97 gss_cred_id_t client_creds; /* server */ 113 gss_cred_id_t client_creds; /* both */
98} Gssctxt; 114} Gssctxt;
99 115
100extern ssh_gssapi_mech *supported_mechs[]; 116extern ssh_gssapi_mech *supported_mechs[];
117extern Gssctxt *gss_kex_context;
101 118
102int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); 119int ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
103void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); 120void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
@@ -117,16 +134,30 @@ void ssh_gssapi_build_ctx(Gssctxt **);
117void ssh_gssapi_delete_ctx(Gssctxt **); 134void ssh_gssapi_delete_ctx(Gssctxt **);
118OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); 135OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
119void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); 136void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
120int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); 137int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *);
138OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
139int ssh_gssapi_credentials_updated(Gssctxt *);
121 140
122/* In the server */ 141/* In the server */
142typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *,
143 const char *);
144char *ssh_gssapi_client_mechanisms(const char *, const char *);
145char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *,
146 const char *);
147gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int);
148int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *,
149 const char *);
123OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); 150OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
124int ssh_gssapi_userok(char *name); 151int ssh_gssapi_userok(char *name, struct passwd *);
125OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 152OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
126void ssh_gssapi_do_child(char ***, u_int *); 153void ssh_gssapi_do_child(char ***, u_int *);
127void ssh_gssapi_cleanup_creds(void); 154void ssh_gssapi_cleanup_creds(void);
128void ssh_gssapi_storecreds(void); 155void ssh_gssapi_storecreds(void);
129 156
157char *ssh_gssapi_server_mechanisms(void);
158int ssh_gssapi_oid_table_ok();
159
160int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
130#endif /* GSSAPI */ 161#endif /* GSSAPI */
131 162
132#endif /* _SSH_GSS_H */ 163#endif /* _SSH_GSS_H */
diff --git a/ssh_config b/ssh_config
index 18936740f..2c06ba707 100644
--- a/ssh_config
+++ b/ssh_config
@@ -26,6 +26,8 @@
26# HostbasedAuthentication no 26# HostbasedAuthentication no
27# GSSAPIAuthentication no 27# GSSAPIAuthentication no
28# GSSAPIDelegateCredentials no 28# GSSAPIDelegateCredentials no
29# GSSAPIKeyExchange no
30# GSSAPITrustDNS no
29# BatchMode no 31# BatchMode no
30# CheckHostIP yes 32# CheckHostIP yes
31# AddressFamily any 33# AddressFamily any
diff --git a/ssh_config.5 b/ssh_config.5
index 269529c00..bd3a7127a 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -530,11 +530,43 @@ Specifies whether user authentication based on GSSAPI is allowed.
530The default is 530The default is
531.Dq no . 531.Dq no .
532Note that this option applies to protocol version 2 only. 532Note that this option applies to protocol version 2 only.
533.It Cm GSSAPIKeyExchange
534Specifies whether key exchange based on GSSAPI may be used. When using
535GSSAPI key exchange the server need not have a host key.
536The default is
537.Dq no .
538Note that this option applies to protocol version 2 only.
539.It Cm GSSAPIClientIdentity
540If set, specifies the GSSAPI client identity that ssh should use when
541connecting to the server. The default is unset, which means that the default
542identity will be used.
543.It Cm GSSAPIServerIdentity
544If set, specifies the GSSAPI server identity that ssh should expect when
545connecting to the server. The default is unset, which means that the
546expected GSSAPI server identity will be determined from the target
547hostname.
533.It Cm GSSAPIDelegateCredentials 548.It Cm GSSAPIDelegateCredentials
534Forward (delegate) credentials to the server. 549Forward (delegate) credentials to the server.
535The default is 550The default is
536.Dq no . 551.Dq no .
537Note that this option applies to protocol version 2 only. 552Note that this option applies to protocol version 2 connections using GSSAPI.
553.It Cm GSSAPIRenewalForcesRekey
554If set to
555.Dq yes
556then renewal of the client's GSSAPI credentials will force the rekeying of the
557ssh connection. With a compatible server, this can delegate the renewed
558credentials to a session on the server.
559The default is
560.Dq no .
561.It Cm GSSAPITrustDns
562Set to
563.Dq yes to indicate that the DNS is trusted to securely canonicalize
564the name of the host being connected to. If
565.Dq no, the hostname entered on the
566command line will be passed untouched to the GSSAPI library.
567The default is
568.Dq no .
569This option only applies to protocol version 2 connections using GSSAPI.
538.It Cm HashKnownHosts 570.It Cm HashKnownHosts
539Indicates that 571Indicates that
540.Xr ssh 1 572.Xr ssh 1
diff --git a/sshconnect2.c b/sshconnect2.c
index d6af0b940..8015b1bdf 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -160,9 +160,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
160{ 160{
161 Kex *kex; 161 Kex *kex;
162 162
163#ifdef GSSAPI
164 char *orig = NULL, *gss = NULL;
165 char *gss_host = NULL;
166#endif
167
163 xxx_host = host; 168 xxx_host = host;
164 xxx_hostaddr = hostaddr; 169 xxx_hostaddr = hostaddr;
165 170
171#ifdef GSSAPI
172 if (options.gss_keyex) {
173 /* Add the GSSAPI mechanisms currently supported on this
174 * client to the key exchange algorithm proposal */
175 orig = myproposal[PROPOSAL_KEX_ALGS];
176
177 if (options.gss_trust_dns)
178 gss_host = (char *)get_canonical_hostname(1);
179 else
180 gss_host = host;
181
182 gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity);
183 if (gss) {
184 debug("Offering GSSAPI proposal: %s", gss);
185 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
186 "%s,%s", gss, orig);
187 }
188 }
189#endif
190
166 if (options.ciphers == (char *)-1) { 191 if (options.ciphers == (char *)-1) {
167 logit("No valid ciphers for protocol version 2 given, using defaults."); 192 logit("No valid ciphers for protocol version 2 given, using defaults.");
168 options.ciphers = NULL; 193 options.ciphers = NULL;
@@ -197,6 +222,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
197 if (options.kex_algorithms != NULL) 222 if (options.kex_algorithms != NULL)
198 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; 223 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
199 224
225#ifdef GSSAPI
226 /* If we've got GSSAPI algorithms, then we also support the
227 * 'null' hostkey, as a last resort */
228 if (options.gss_keyex && gss) {
229 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
230 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
231 "%s,null", orig);
232 xfree(gss);
233 }
234#endif
235
200 if (options.rekey_limit) 236 if (options.rekey_limit)
201 packet_set_rekey_limit((u_int32_t)options.rekey_limit); 237 packet_set_rekey_limit((u_int32_t)options.rekey_limit);
202 238
@@ -207,10 +243,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
207 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 243 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
208 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 244 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
209 kex->kex[KEX_ECDH_SHA2] = kexecdh_client; 245 kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
246#ifdef GSSAPI
247 if (options.gss_keyex) {
248 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
249 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
250 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
251 }
252#endif
210 kex->client_version_string=client_version_string; 253 kex->client_version_string=client_version_string;
211 kex->server_version_string=server_version_string; 254 kex->server_version_string=server_version_string;
212 kex->verify_host_key=&verify_host_key_callback; 255 kex->verify_host_key=&verify_host_key_callback;
213 256
257#ifdef GSSAPI
258 if (options.gss_keyex) {
259 kex->gss_deleg_creds = options.gss_deleg_creds;
260 kex->gss_trust_dns = options.gss_trust_dns;
261 kex->gss_client = options.gss_client_identity;
262 if (options.gss_server_identity) {
263 kex->gss_host = options.gss_server_identity;
264 } else {
265 kex->gss_host = gss_host;
266 }
267 }
268#endif
269
214 xxx_kex = kex; 270 xxx_kex = kex;
215 271
216 dispatch_run(DISPATCH_BLOCK, &kex->done, kex); 272 dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
@@ -306,6 +362,7 @@ void input_gssapi_token(int type, u_int32_t, void *);
306void input_gssapi_hash(int type, u_int32_t, void *); 362void input_gssapi_hash(int type, u_int32_t, void *);
307void input_gssapi_error(int, u_int32_t, void *); 363void input_gssapi_error(int, u_int32_t, void *);
308void input_gssapi_errtok(int, u_int32_t, void *); 364void input_gssapi_errtok(int, u_int32_t, void *);
365int userauth_gsskeyex(Authctxt *authctxt);
309#endif 366#endif
310 367
311void userauth(Authctxt *, char *); 368void userauth(Authctxt *, char *);
@@ -321,6 +378,11 @@ static char *authmethods_get(void);
321 378
322Authmethod authmethods[] = { 379Authmethod authmethods[] = {
323#ifdef GSSAPI 380#ifdef GSSAPI
381 {"gssapi-keyex",
382 userauth_gsskeyex,
383 NULL,
384 &options.gss_authentication,
385 NULL},
324 {"gssapi-with-mic", 386 {"gssapi-with-mic",
325 userauth_gssapi, 387 userauth_gssapi,
326 NULL, 388 NULL,
@@ -627,19 +689,31 @@ userauth_gssapi(Authctxt *authctxt)
627 static u_int mech = 0; 689 static u_int mech = 0;
628 OM_uint32 min; 690 OM_uint32 min;
629 int ok = 0; 691 int ok = 0;
692 const char *gss_host;
693
694 if (options.gss_server_identity)
695 gss_host = options.gss_server_identity;
696 else if (options.gss_trust_dns)
697 gss_host = get_canonical_hostname(1);
698 else
699 gss_host = authctxt->host;
630 700
631 /* Try one GSSAPI method at a time, rather than sending them all at 701 /* Try one GSSAPI method at a time, rather than sending them all at
632 * once. */ 702 * once. */
633 703
634 if (gss_supported == NULL) 704 if (gss_supported == NULL)
635 gss_indicate_mechs(&min, &gss_supported); 705 if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
706 gss_supported = NULL;
707 return 0;
708 }
636 709
637 /* Check to see if the mechanism is usable before we offer it */ 710 /* Check to see if the mechanism is usable before we offer it */
638 while (mech < gss_supported->count && !ok) { 711 while (mech < gss_supported->count && !ok) {
639 /* My DER encoding requires length<128 */ 712 /* My DER encoding requires length<128 */
640 if (gss_supported->elements[mech].length < 128 && 713 if (gss_supported->elements[mech].length < 128 &&
641 ssh_gssapi_check_mechanism(&gssctxt, 714 ssh_gssapi_check_mechanism(&gssctxt,
642 &gss_supported->elements[mech], authctxt->host)) { 715 &gss_supported->elements[mech], gss_host,
716 options.gss_client_identity)) {
643 ok = 1; /* Mechanism works */ 717 ok = 1; /* Mechanism works */
644 } else { 718 } else {
645 mech++; 719 mech++;
@@ -736,8 +810,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
736{ 810{
737 Authctxt *authctxt = ctxt; 811 Authctxt *authctxt = ctxt;
738 Gssctxt *gssctxt; 812 Gssctxt *gssctxt;
739 int oidlen; 813 u_int oidlen;
740 char *oidv; 814 u_char *oidv;
741 815
742 if (authctxt == NULL) 816 if (authctxt == NULL)
743 fatal("input_gssapi_response: no authentication context"); 817 fatal("input_gssapi_response: no authentication context");
@@ -847,6 +921,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
847 xfree(msg); 921 xfree(msg);
848 xfree(lang); 922 xfree(lang);
849} 923}
924
925int
926userauth_gsskeyex(Authctxt *authctxt)
927{
928 Buffer b;
929 gss_buffer_desc gssbuf;
930 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
931 OM_uint32 ms;
932
933 static int attempt = 0;
934 if (attempt++ >= 1)
935 return (0);
936
937 if (gss_kex_context == NULL) {
938 debug("No valid Key exchange context");
939 return (0);
940 }
941
942 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
943 "gssapi-keyex");
944
945 gssbuf.value = buffer_ptr(&b);
946 gssbuf.length = buffer_len(&b);
947
948 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
949 buffer_free(&b);
950 return (0);
951 }
952
953 packet_start(SSH2_MSG_USERAUTH_REQUEST);
954 packet_put_cstring(authctxt->server_user);
955 packet_put_cstring(authctxt->service);
956 packet_put_cstring(authctxt->method->name);
957 packet_put_string(mic.value, mic.length);
958 packet_send();
959
960 buffer_free(&b);
961 gss_release_buffer(&ms, &mic);
962
963 return (1);
964}
965
850#endif /* GSSAPI */ 966#endif /* GSSAPI */
851 967
852int 968int
diff --git a/sshd.c b/sshd.c
index 3e9d17640..d8faaebd5 100644
--- a/sshd.c
+++ b/sshd.c
@@ -121,6 +121,10 @@
121#include "ssh-sandbox.h" 121#include "ssh-sandbox.h"
122#include "version.h" 122#include "version.h"
123 123
124#ifdef USE_SECURITY_SESSION_API
125#include <Security/AuthSession.h>
126#endif
127
124#ifdef LIBWRAP 128#ifdef LIBWRAP
125#include <tcpd.h> 129#include <tcpd.h>
126#include <syslog.h> 130#include <syslog.h>
@@ -1645,10 +1649,13 @@ main(int ac, char **av)
1645 logit("Disabling protocol version 1. Could not load host key"); 1649 logit("Disabling protocol version 1. Could not load host key");
1646 options.protocol &= ~SSH_PROTO_1; 1650 options.protocol &= ~SSH_PROTO_1;
1647 } 1651 }
1652#ifndef GSSAPI
1653 /* The GSSAPI key exchange can run without a host key */
1648 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { 1654 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
1649 logit("Disabling protocol version 2. Could not load host key"); 1655 logit("Disabling protocol version 2. Could not load host key");
1650 options.protocol &= ~SSH_PROTO_2; 1656 options.protocol &= ~SSH_PROTO_2;
1651 } 1657 }
1658#endif
1652 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { 1659 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
1653 logit("sshd: no hostkeys available -- exiting."); 1660 logit("sshd: no hostkeys available -- exiting.");
1654 exit(1); 1661 exit(1);
@@ -1976,6 +1983,60 @@ main(int ac, char **av)
1976 /* Log the connection. */ 1983 /* Log the connection. */
1977 verbose("Connection from %.500s port %d", remote_ip, remote_port); 1984 verbose("Connection from %.500s port %d", remote_ip, remote_port);
1978 1985
1986#ifdef USE_SECURITY_SESSION_API
1987 /*
1988 * Create a new security session for use by the new user login if
1989 * the current session is the root session or we are not launched
1990 * by inetd (eg: debugging mode or server mode). We do not
1991 * necessarily need to create a session if we are launched from
1992 * inetd because Panther xinetd will create a session for us.
1993 *
1994 * The only case where this logic will fail is if there is an
1995 * inetd running in a non-root session which is not creating
1996 * new sessions for us. Then all the users will end up in the
1997 * same session (bad).
1998 *
1999 * When the client exits, the session will be destroyed for us
2000 * automatically.
2001 *
2002 * We must create the session before any credentials are stored
2003 * (including AFS pags, which happens a few lines below).
2004 */
2005 {
2006 OSStatus err = 0;
2007 SecuritySessionId sid = 0;
2008 SessionAttributeBits sattrs = 0;
2009
2010 err = SessionGetInfo(callerSecuritySession, &sid, &sattrs);
2011 if (err)
2012 error("SessionGetInfo() failed with error %.8X",
2013 (unsigned) err);
2014 else
2015 debug("Current Session ID is %.8X / Session Attributes are %.8X",
2016 (unsigned) sid, (unsigned) sattrs);
2017
2018 if (inetd_flag && !(sattrs & sessionIsRoot))
2019 debug("Running in inetd mode in a non-root session... "
2020 "assuming inetd created the session for us.");
2021 else {
2022 debug("Creating new security session...");
2023 err = SessionCreate(0, sessionHasTTY | sessionIsRemote);
2024 if (err)
2025 error("SessionCreate() failed with error %.8X",
2026 (unsigned) err);
2027
2028 err = SessionGetInfo(callerSecuritySession, &sid,
2029 &sattrs);
2030 if (err)
2031 error("SessionGetInfo() failed with error %.8X",
2032 (unsigned) err);
2033 else
2034 debug("New Session ID is %.8X / Session Attributes are %.8X",
2035 (unsigned) sid, (unsigned) sattrs);
2036 }
2037 }
2038#endif
2039
1979 /* 2040 /*
1980 * We don't want to listen forever unless the other side 2041 * We don't want to listen forever unless the other side
1981 * successfully authenticates itself. So we set up an alarm which is 2042 * successfully authenticates itself. So we set up an alarm which is
@@ -2357,6 +2418,48 @@ do_ssh2_kex(void)
2357 2418
2358 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); 2419 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
2359 2420
2421#ifdef GSSAPI
2422 {
2423 char *orig;
2424 char *gss = NULL;
2425 char *newstr = NULL;
2426 orig = myproposal[PROPOSAL_KEX_ALGS];
2427
2428 /*
2429 * If we don't have a host key, then there's no point advertising
2430 * the other key exchange algorithms
2431 */
2432
2433 if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
2434 orig = NULL;
2435
2436 if (options.gss_keyex)
2437 gss = ssh_gssapi_server_mechanisms();
2438 else
2439 gss = NULL;
2440
2441 if (gss && orig)
2442 xasprintf(&newstr, "%s,%s", gss, orig);
2443 else if (gss)
2444 newstr = gss;
2445 else if (orig)
2446 newstr = orig;
2447
2448 /*
2449 * If we've got GSSAPI mechanisms, then we've got the 'null' host
2450 * key alg, but we can't tell people about it unless its the only
2451 * host key algorithm we support
2452 */
2453 if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
2454 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
2455
2456 if (newstr)
2457 myproposal[PROPOSAL_KEX_ALGS] = newstr;
2458 else
2459 fatal("No supported key exchange algorithms");
2460 }
2461#endif
2462
2360 /* start key exchange */ 2463 /* start key exchange */
2361 kex = kex_setup(myproposal); 2464 kex = kex_setup(myproposal);
2362 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; 2465 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
@@ -2364,6 +2467,13 @@ do_ssh2_kex(void)
2364 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 2467 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
2365 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 2468 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
2366 kex->kex[KEX_ECDH_SHA2] = kexecdh_server; 2469 kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
2470#ifdef GSSAPI
2471 if (options.gss_keyex) {
2472 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
2473 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
2474 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
2475 }
2476#endif
2367 kex->server = 1; 2477 kex->server = 1;
2368 kex->client_version_string=client_version_string; 2478 kex->client_version_string=client_version_string;
2369 kex->server_version_string=server_version_string; 2479 kex->server_version_string=server_version_string;
diff --git a/sshd_config b/sshd_config
index 9cd2fddce..1af2afd7a 100644
--- a/sshd_config
+++ b/sshd_config
@@ -80,6 +80,8 @@ AuthorizedKeysFile .ssh/authorized_keys
80# GSSAPI options 80# GSSAPI options
81#GSSAPIAuthentication no 81#GSSAPIAuthentication no
82#GSSAPICleanupCredentials yes 82#GSSAPICleanupCredentials yes
83#GSSAPIStrictAcceptorCheck yes
84#GSSAPIKeyExchange no
83 85
84# Set this to 'yes' to enable PAM authentication, account processing, 86# Set this to 'yes' to enable PAM authentication, account processing,
85# and session processing. If this is enabled, PAM authentication will 87# and session processing. If this is enabled, PAM authentication will
diff --git a/sshd_config.5 b/sshd_config.5
index cfa480697..935bb62fa 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -481,12 +481,40 @@ Specifies whether user authentication based on GSSAPI is allowed.
481The default is 481The default is
482.Dq no . 482.Dq no .
483Note that this option applies to protocol version 2 only. 483Note that this option applies to protocol version 2 only.
484.It Cm GSSAPIKeyExchange
485Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
486doesn't rely on ssh keys to verify host identity.
487The default is
488.Dq no .
489Note that this option applies to protocol version 2 only.
484.It Cm GSSAPICleanupCredentials 490.It Cm GSSAPICleanupCredentials
485Specifies whether to automatically destroy the user's credentials cache 491Specifies whether to automatically destroy the user's credentials cache
486on logout. 492on logout.
487The default is 493The default is
488.Dq yes . 494.Dq yes .
489Note that this option applies to protocol version 2 only. 495Note that this option applies to protocol version 2 only.
496.It Cm GSSAPIStrictAcceptorCheck
497Determines whether to be strict about the identity of the GSSAPI acceptor
498a client authenticates against. If
499.Dq yes
500then the client must authenticate against the
501.Pa host
502service on the current hostname. If
503.Dq no
504then the client may authenticate against any service key stored in the
505machine's default store. This facility is provided to assist with operation
506on multi homed machines.
507The default is
508.Dq yes .
509Note that this option applies only to protocol version 2 GSSAPI connections,
510and setting it to
511.Dq no
512may only work with recent Kerberos GSSAPI libraries.
513.It Cm GSSAPIStoreCredentialsOnRekey
514Controls whether the user's GSSAPI credentials should be updated following a
515successful connection rekeying. This option can be used to accepted renewed
516or updated credentials from a compatible client. The default is
517.Dq no .
490.It Cm HostbasedAuthentication 518.It Cm HostbasedAuthentication
491Specifies whether rhosts or /etc/hosts.equiv authentication together 519Specifies whether rhosts or /etc/hosts.equiv authentication together
492with successful public key client host authentication is allowed 520with successful public key client host authentication is allowed