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.c275
-rw-r--r--gss-serv-krb5.c85
-rw-r--r--gss-serv.c221
-rw-r--r--kex.c16
-rw-r--r--kex.h14
-rw-r--r--kexgssc.c332
-rw-r--r--kexgsss.c289
-rw-r--r--key.c3
-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.h41
-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, 2051 insertions, 59 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 28a8ec41b..ee1d2c3b8 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 ssh-pkcs11.o krl.o smult_curve25519_ref.o \ 77 ssh-pkcs11.o krl.o smult_curve25519_ref.o \
77 kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \ 78 kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \
@@ -91,7 +92,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
91 auth2-none.o auth2-passwd.o auth2-pubkey.o \ 92 auth2-none.o auth2-passwd.o auth2-pubkey.o \
92 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \ 93 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \
93 kexc25519s.o auth-krb5.o \ 94 kexc25519s.o auth-krb5.o \
94 auth2-gss.o gss-serv.o gss-serv-krb5.o \ 95 auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \
95 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ 96 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
96 sftp-server.o sftp-common.o \ 97 sftp-server.o sftp-common.o \
97 roaming_common.o roaming_serv.o \ 98 roaming_common.o roaming_serv.o \
diff --git a/auth-krb5.c b/auth-krb5.c
index 6c62bdf54..69a1a53e2 100644
--- a/auth-krb5.c
+++ b/auth-krb5.c
@@ -182,8 +182,13 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
182 182
183 len = strlen(authctxt->krb5_ticket_file) + 6; 183 len = strlen(authctxt->krb5_ticket_file) + 6;
184 authctxt->krb5_ccname = xmalloc(len); 184 authctxt->krb5_ccname = xmalloc(len);
185#ifdef USE_CCAPI
186 snprintf(authctxt->krb5_ccname, len, "API:%s",
187 authctxt->krb5_ticket_file);
188#else
185 snprintf(authctxt->krb5_ccname, len, "FILE:%s", 189 snprintf(authctxt->krb5_ccname, len, "FILE:%s",
186 authctxt->krb5_ticket_file); 190 authctxt->krb5_ticket_file);
191#endif
187 192
188#ifdef USE_PAM 193#ifdef USE_PAM
189 if (options.use_pam) 194 if (options.use_pam)
@@ -240,15 +245,22 @@ krb5_cleanup_proc(Authctxt *authctxt)
240#ifndef HEIMDAL 245#ifndef HEIMDAL
241krb5_error_code 246krb5_error_code
242ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { 247ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
243 int tmpfd, ret, oerrno; 248 int ret, oerrno;
244 char ccname[40]; 249 char ccname[40];
245 mode_t old_umask; 250 mode_t old_umask;
251#ifdef USE_CCAPI
252 char cctemplate[] = "API:krb5cc_%d";
253#else
254 char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX";
255 int tmpfd;
256#endif
246 257
247 ret = snprintf(ccname, sizeof(ccname), 258 ret = snprintf(ccname, sizeof(ccname),
248 "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); 259 cctemplate, geteuid());
249 if (ret < 0 || (size_t)ret >= sizeof(ccname)) 260 if (ret < 0 || (size_t)ret >= sizeof(ccname))
250 return ENOMEM; 261 return ENOMEM;
251 262
263#ifndef USE_CCAPI
252 old_umask = umask(0177); 264 old_umask = umask(0177);
253 tmpfd = mkstemp(ccname + strlen("FILE:")); 265 tmpfd = mkstemp(ccname + strlen("FILE:"));
254 oerrno = errno; 266 oerrno = errno;
@@ -265,6 +277,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
265 return oerrno; 277 return oerrno;
266 } 278 }
267 close(tmpfd); 279 close(tmpfd);
280#endif
268 281
269 return (krb5_cc_resolve(ctx, ccname, ccache)); 282 return (krb5_cc_resolve(ctx, ccname, ccache));
270} 283}
diff --git a/auth2-gss.c b/auth2-gss.c
index c28a705cb..3ff2d726b 100644
--- a/auth2-gss.c
+++ b/auth2-gss.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: auth2-gss.c,v 1.21 2014/02/26 20:28:44 djm Exp $ */ 1/* $OpenBSD: auth2-gss.c,v 1.21 2014/02/26 20:28:44 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 free(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)
@@ -235,7 +269,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
235 269
236 packet_check_eom(); 270 packet_check_eom();
237 271
238 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); 272 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
273 authctxt->pw));
239 274
240 authctxt->postponed = 0; 275 authctxt->postponed = 0;
241 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 276 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
@@ -270,7 +305,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
270 gssbuf.length = buffer_len(&b); 305 gssbuf.length = buffer_len(&b);
271 306
272 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) 307 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
273 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); 308 authenticated =
309 PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
274 else 310 else
275 logit("GSSAPI MIC check failed"); 311 logit("GSSAPI MIC check failed");
276 312
@@ -285,6 +321,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
285 userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL); 321 userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
286} 322}
287 323
324Authmethod method_gsskeyex = {
325 "gssapi-keyex",
326 userauth_gsskeyex,
327 &options.gss_authentication
328};
329
288Authmethod method_gssapi = { 330Authmethod method_gssapi = {
289 "gssapi-with-mic", 331 "gssapi-with-mic",
290 userauth_gssapi, 332 userauth_gssapi,
diff --git a/auth2.c b/auth2.c
index a5490c009..fbe3e1bac 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 75
@@ -76,6 +77,7 @@ Authmethod *authmethods[] = {
76 &method_none, 77 &method_none,
77 &method_pubkey, 78 &method_pubkey,
78#ifdef GSSAPI 79#ifdef GSSAPI
80 &method_gsskeyex,
79 &method_gssapi, 81 &method_gssapi,
80#endif 82#endif
81 &method_passwd, 83 &method_passwd,
diff --git a/clientloop.c b/clientloop.c
index 59ad3a2c3..6d8cd7ddb 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
@@ -1608,6 +1612,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1608 /* Do channel operations unless rekeying in progress. */ 1612 /* Do channel operations unless rekeying in progress. */
1609 if (!rekeying) { 1613 if (!rekeying) {
1610 channel_after_select(readset, writeset); 1614 channel_after_select(readset, writeset);
1615
1616#ifdef GSSAPI
1617 if (options.gss_renewal_rekey &&
1618 ssh_gssapi_credentials_updated(NULL)) {
1619 debug("credentials updated - forcing rekey");
1620 need_rekeying = 1;
1621 }
1622#endif
1623
1611 if (need_rekeying || packet_need_rekeying()) { 1624 if (need_rekeying || packet_need_rekeying()) {
1612 debug("need rekeying"); 1625 debug("need rekeying");
1613 xxx_kex->done = 0; 1626 xxx_kex->done = 0;
diff --git a/config.h.in b/config.h.in
index 0401ad181..6bc422c3e 100644
--- a/config.h.in
+++ b/config.h.in
@@ -1622,6 +1622,9 @@
1622/* Use btmp to log bad logins */ 1622/* Use btmp to log bad logins */
1623#undef USE_BTMP 1623#undef USE_BTMP
1624 1624
1625/* platform uses an in-memory credentials cache */
1626#undef USE_CCAPI
1627
1625/* Use libedit for sftp */ 1628/* Use libedit for sftp */
1626#undef USE_LIBEDIT 1629#undef USE_LIBEDIT
1627 1630
@@ -1637,6 +1640,9 @@
1637/* Use PIPES instead of a socketpair() */ 1640/* Use PIPES instead of a socketpair() */
1638#undef USE_PIPES 1641#undef USE_PIPES
1639 1642
1643/* platform has the Security Authorization Session API */
1644#undef USE_SECURITY_SESSION_API
1645
1640/* Define if you have Solaris process contracts */ 1646/* Define if you have Solaris process contracts */
1641#undef USE_SOLARIS_PROCESS_CONTRACTS 1647#undef USE_SOLARIS_PROCESS_CONTRACTS
1642 1648
diff --git a/configure b/configure
index d690393a3..b6b5b6d8d 100755
--- a/configure
+++ b/configure
@@ -7170,6 +7170,63 @@ $as_echo "#define SSH_TUN_COMPAT_AF 1" >>confdefs.h
7170 7170
7171$as_echo "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h 7171$as_echo "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h
7172 7172
7173 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have the Security Authorization Session API" >&5
7174$as_echo_n "checking if we have the Security Authorization Session API... " >&6; }
7175 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
7176/* end confdefs.h. */
7177#include <Security/AuthSession.h>
7178int
7179main ()
7180{
7181SessionCreate(0, 0);
7182 ;
7183 return 0;
7184}
7185_ACEOF
7186if ac_fn_c_try_compile "$LINENO"; then :
7187 ac_cv_use_security_session_api="yes"
7188
7189$as_echo "#define USE_SECURITY_SESSION_API 1" >>confdefs.h
7190
7191 LIBS="$LIBS -framework Security"
7192 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
7193$as_echo "yes" >&6; }
7194else
7195 ac_cv_use_security_session_api="no"
7196 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
7197$as_echo "no" >&6; }
7198fi
7199rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
7200 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have an in-memory credentials cache" >&5
7201$as_echo_n "checking if we have an in-memory credentials cache... " >&6; }
7202 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
7203/* end confdefs.h. */
7204#include <Kerberos/Kerberos.h>
7205int
7206main ()
7207{
7208cc_context_t c;
7209 (void) cc_initialize (&c, 0, NULL, NULL);
7210 ;
7211 return 0;
7212}
7213_ACEOF
7214if ac_fn_c_try_compile "$LINENO"; then :
7215
7216$as_echo "#define USE_CCAPI 1" >>confdefs.h
7217
7218 LIBS="$LIBS -framework Security"
7219 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
7220$as_echo "yes" >&6; }
7221 if test "x$ac_cv_use_security_session_api" = "xno"; then
7222 as_fn_error $? "*** Need a security framework to use the credentials cache API ***" "$LINENO" 5
7223 fi
7224else
7225 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
7226$as_echo "no" >&6; }
7227
7228fi
7229rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
7173 7230
7174 ac_fn_c_check_decl "$LINENO" "AU_IPv4" "ac_cv_have_decl_AU_IPv4" "$ac_includes_default" 7231 ac_fn_c_check_decl "$LINENO" "AU_IPv4" "ac_cv_have_decl_AU_IPv4" "$ac_includes_default"
7175if test "x$ac_cv_have_decl_AU_IPv4" = xyes; then : 7232if test "x$ac_cv_have_decl_AU_IPv4" = xyes; then :
diff --git a/configure.ac b/configure.ac
index 7c6ce08d8..d235fb06b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -584,6 +584,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
584 [Use tunnel device compatibility to OpenBSD]) 584 [Use tunnel device compatibility to OpenBSD])
585 AC_DEFINE([SSH_TUN_PREPEND_AF], [1], 585 AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
586 [Prepend the address family to IP tunnel traffic]) 586 [Prepend the address family to IP tunnel traffic])
587 AC_MSG_CHECKING([if we have the Security Authorization Session API])
588 AC_TRY_COMPILE([#include <Security/AuthSession.h>],
589 [SessionCreate(0, 0);],
590 [ac_cv_use_security_session_api="yes"
591 AC_DEFINE([USE_SECURITY_SESSION_API], [1],
592 [platform has the Security Authorization Session API])
593 LIBS="$LIBS -framework Security"
594 AC_MSG_RESULT([yes])],
595 [ac_cv_use_security_session_api="no"
596 AC_MSG_RESULT([no])])
597 AC_MSG_CHECKING([if we have an in-memory credentials cache])
598 AC_TRY_COMPILE(
599 [#include <Kerberos/Kerberos.h>],
600 [cc_context_t c;
601 (void) cc_initialize (&c, 0, NULL, NULL);],
602 [AC_DEFINE([USE_CCAPI], [1],
603 [platform uses an in-memory credentials cache])
604 LIBS="$LIBS -framework Security"
605 AC_MSG_RESULT([yes])
606 if test "x$ac_cv_use_security_session_api" = "xno"; then
607 AC_MSG_ERROR([*** Need a security framework to use the credentials cache API ***])
608 fi],
609 [AC_MSG_RESULT([no])]
610 )
587 m4_pattern_allow([AU_IPv]) 611 m4_pattern_allow([AU_IPv])
588 AC_CHECK_DECL([AU_IPv4], [], 612 AC_CHECK_DECL([AU_IPv4], [],
589 AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records]) 613 AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records])
diff --git a/gss-genr.c b/gss-genr.c
index b39281bc1..1e569adc3 100644
--- a/gss-genr.c
+++ b/gss-genr.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-genr.c,v 1.22 2013/11/08 00:39:15 djm Exp $ */ 1/* $OpenBSD: gss-genr.c,v 1.22 2013/11/08 00:39:15 djm 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(void) {
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 free(gss_enc2oid[i].encoded);
105 free(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 free(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,66 @@ 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
502 now = time(NULL);
503
504 if (ctxt) {
505 debug("Rekey has happened - updating saved versions");
506
507 if (saved_name != GSS_C_NO_NAME)
508 gss_release_name(&minor, &saved_name);
509
510 major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
511 &saved_name, &saved_lifetime, NULL, NULL);
512
513 if (!GSS_ERROR(major)) {
514 saved_mech = ctxt->oid;
515 saved_lifetime+= now;
516 } else {
517 /* Handle the error */
518 }
519 return 0;
520 }
521
522 if (now - last_call < 10)
523 return 0;
524
525 last_call = now;
526
527 if (saved_mech == GSS_C_NO_OID)
528 return 0;
529
530 major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
531 &name, &lifetime, NULL, NULL);
532 if (major == GSS_S_CREDENTIALS_EXPIRED)
533 return 0;
534 else if (GSS_ERROR(major))
535 return 0;
536
537 major = gss_compare_name(&minor, saved_name, name, &equal);
538 gss_release_name(&minor, &name);
539 if (GSS_ERROR(major))
540 return 0;
541
542 if (equal && (saved_lifetime < lifetime + now - 10))
543 return 1;
544
545 return 0;
546}
547
281#endif /* GSSAPI */ 548#endif /* GSSAPI */
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
index 759fa104f..e678a2757 100644
--- a/gss-serv-krb5.c
+++ b/gss-serv-krb5.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-serv-krb5.c,v 1.8 2013/07/20 01:55:13 djm Exp $ */ 1/* $OpenBSD: gss-serv-krb5.c,v 1.8 2013/07/20 01:55:13 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
@@ -120,8 +120,8 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
120 krb5_error_code problem; 120 krb5_error_code problem;
121 krb5_principal princ; 121 krb5_principal princ;
122 OM_uint32 maj_status, min_status; 122 OM_uint32 maj_status, min_status;
123 int len;
124 const char *errmsg; 123 const char *errmsg;
124 const char *new_ccname;
125 125
126 if (client->creds == NULL) { 126 if (client->creds == NULL) {
127 debug("No credentials stored"); 127 debug("No credentials stored");
@@ -180,11 +180,16 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
180 return; 180 return;
181 } 181 }
182 182
183 client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); 183 new_ccname = krb5_cc_get_name(krb_context, ccache);
184
184 client->store.envvar = "KRB5CCNAME"; 185 client->store.envvar = "KRB5CCNAME";
185 len = strlen(client->store.filename) + 6; 186#ifdef USE_CCAPI
186 client->store.envval = xmalloc(len); 187 xasprintf(&client->store.envval, "API:%s", new_ccname);
187 snprintf(client->store.envval, len, "FILE:%s", client->store.filename); 188 client->store.filename = NULL;
189#else
190 xasprintf(&client->store.envval, "FILE:%s", new_ccname);
191 client->store.filename = xstrdup(new_ccname);
192#endif
188 193
189#ifdef USE_PAM 194#ifdef USE_PAM
190 if (options.use_pam) 195 if (options.use_pam)
@@ -196,6 +201,71 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
196 return; 201 return;
197} 202}
198 203
204int
205ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store,
206 ssh_gssapi_client *client)
207{
208 krb5_ccache ccache = NULL;
209 krb5_principal principal = NULL;
210 char *name = NULL;
211 krb5_error_code problem;
212 OM_uint32 maj_status, min_status;
213
214 if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) {
215 logit("krb5_cc_resolve(): %.100s",
216 krb5_get_err_text(krb_context, problem));
217 return 0;
218 }
219
220 /* Find out who the principal in this cache is */
221 if ((problem = krb5_cc_get_principal(krb_context, ccache,
222 &principal))) {
223 logit("krb5_cc_get_principal(): %.100s",
224 krb5_get_err_text(krb_context, problem));
225 krb5_cc_close(krb_context, ccache);
226 return 0;
227 }
228
229 if ((problem = krb5_unparse_name(krb_context, principal, &name))) {
230 logit("krb5_unparse_name(): %.100s",
231 krb5_get_err_text(krb_context, problem));
232 krb5_free_principal(krb_context, principal);
233 krb5_cc_close(krb_context, ccache);
234 return 0;
235 }
236
237
238 if (strcmp(name,client->exportedname.value)!=0) {
239 debug("Name in local credentials cache differs. Not storing");
240 krb5_free_principal(krb_context, principal);
241 krb5_cc_close(krb_context, ccache);
242 krb5_free_unparsed_name(krb_context, name);
243 return 0;
244 }
245 krb5_free_unparsed_name(krb_context, name);
246
247 /* Name matches, so lets get on with it! */
248
249 if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) {
250 logit("krb5_cc_initialize(): %.100s",
251 krb5_get_err_text(krb_context, problem));
252 krb5_free_principal(krb_context, principal);
253 krb5_cc_close(krb_context, ccache);
254 return 0;
255 }
256
257 krb5_free_principal(krb_context, principal);
258
259 if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds,
260 ccache))) {
261 logit("gss_krb5_copy_ccache() failed. Sorry!");
262 krb5_cc_close(krb_context, ccache);
263 return 0;
264 }
265
266 return 1;
267}
268
199ssh_gssapi_mech gssapi_kerberos_mech = { 269ssh_gssapi_mech gssapi_kerberos_mech = {
200 "toWM5Slw5Ew8Mqkay+al2g==", 270 "toWM5Slw5Ew8Mqkay+al2g==",
201 "Kerberos", 271 "Kerberos",
@@ -203,7 +273,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = {
203 NULL, 273 NULL,
204 &ssh_gssapi_krb5_userok, 274 &ssh_gssapi_krb5_userok,
205 NULL, 275 NULL,
206 &ssh_gssapi_krb5_storecreds 276 &ssh_gssapi_krb5_storecreds,
277 &ssh_gssapi_krb5_updatecreds
207}; 278};
208 279
209#endif /* KRB5 */ 280#endif /* KRB5 */
diff --git a/gss-serv.c b/gss-serv.c
index e61b37bec..c33463bdf 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-serv.c,v 1.26 2014/02/26 20:28:44 djm Exp $ */ 1/* $OpenBSD: gss-serv.c,v 1.26 2014/02/26 20:28:44 djm 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,21 @@
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, NULL}}; 58 GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL,
59 {NULL, NULL, NULL, NULL, NULL}, 0, 0};
54 60
55ssh_gssapi_mech gssapi_null_mech = 61ssh_gssapi_mech gssapi_null_mech =
56 { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; 62 { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
57 63
58#ifdef KRB5 64#ifdef KRB5
59extern ssh_gssapi_mech gssapi_kerberos_mech; 65extern ssh_gssapi_mech gssapi_kerberos_mech;
@@ -100,25 +106,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx)
100 char lname[MAXHOSTNAMELEN]; 106 char lname[MAXHOSTNAMELEN];
101 gss_OID_set oidset; 107 gss_OID_set oidset;
102 108
103 gss_create_empty_oid_set(&status, &oidset); 109 if (options.gss_strict_acceptor) {
104 gss_add_oid_set_member(&status, ctx->oid, &oidset); 110 gss_create_empty_oid_set(&status, &oidset);
111 gss_add_oid_set_member(&status, ctx->oid, &oidset);
105 112
106 if (gethostname(lname, MAXHOSTNAMELEN)) { 113 if (gethostname(lname, MAXHOSTNAMELEN)) {
107 gss_release_oid_set(&status, &oidset); 114 gss_release_oid_set(&status, &oidset);
108 return (-1); 115 return (-1);
109 } 116 }
117
118 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
119 gss_release_oid_set(&status, &oidset);
120 return (ctx->major);
121 }
122
123 if ((ctx->major = gss_acquire_cred(&ctx->minor,
124 ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds,
125 NULL, NULL)))
126 ssh_gssapi_error(ctx);
110 127
111 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
112 gss_release_oid_set(&status, &oidset); 128 gss_release_oid_set(&status, &oidset);
113 return (ctx->major); 129 return (ctx->major);
130 } else {
131 ctx->name = GSS_C_NO_NAME;
132 ctx->creds = GSS_C_NO_CREDENTIAL;
114 } 133 }
115 134 return GSS_S_COMPLETE;
116 if ((ctx->major = gss_acquire_cred(&ctx->minor,
117 ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
118 ssh_gssapi_error(ctx);
119
120 gss_release_oid_set(&status, &oidset);
121 return (ctx->major);
122} 135}
123 136
124/* Privileged */ 137/* Privileged */
@@ -133,6 +146,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
133} 146}
134 147
135/* Unprivileged */ 148/* Unprivileged */
149char *
150ssh_gssapi_server_mechanisms(void) {
151 gss_OID_set supported;
152
153 ssh_gssapi_supported_oids(&supported);
154 return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
155 NULL, NULL));
156}
157
158/* Unprivileged */
159int
160ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
161 const char *dummy) {
162 Gssctxt *ctx = NULL;
163 int res;
164
165 res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
166 ssh_gssapi_delete_ctx(&ctx);
167
168 return (res);
169}
170
171/* Unprivileged */
136void 172void
137ssh_gssapi_supported_oids(gss_OID_set *oidset) 173ssh_gssapi_supported_oids(gss_OID_set *oidset)
138{ 174{
@@ -142,7 +178,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset)
142 gss_OID_set supported; 178 gss_OID_set supported;
143 179
144 gss_create_empty_oid_set(&min_status, oidset); 180 gss_create_empty_oid_set(&min_status, oidset);
145 gss_indicate_mechs(&min_status, &supported); 181
182 if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
183 return;
146 184
147 while (supported_mechs[i]->name != NULL) { 185 while (supported_mechs[i]->name != NULL) {
148 if (GSS_ERROR(gss_test_oid_set_member(&min_status, 186 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
@@ -268,8 +306,48 @@ OM_uint32
268ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 306ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
269{ 307{
270 int i = 0; 308 int i = 0;
309 int equal = 0;
310 gss_name_t new_name = GSS_C_NO_NAME;
311 gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
312
313 if (options.gss_store_rekey && client->used && ctx->client_creds) {
314 if (client->mech->oid.length != ctx->oid->length ||
315 (memcmp(client->mech->oid.elements,
316 ctx->oid->elements, ctx->oid->length) !=0)) {
317 debug("Rekeyed credentials have different mechanism");
318 return GSS_S_COMPLETE;
319 }
320
321 if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
322 ctx->client_creds, ctx->oid, &new_name,
323 NULL, NULL, NULL))) {
324 ssh_gssapi_error(ctx);
325 return (ctx->major);
326 }
327
328 ctx->major = gss_compare_name(&ctx->minor, client->name,
329 new_name, &equal);
271 330
272 gss_buffer_desc ename; 331 if (GSS_ERROR(ctx->major)) {
332 ssh_gssapi_error(ctx);
333 return (ctx->major);
334 }
335
336 if (!equal) {
337 debug("Rekeyed credentials have different name");
338 return GSS_S_COMPLETE;
339 }
340
341 debug("Marking rekeyed credentials for export");
342
343 gss_release_name(&ctx->minor, &client->name);
344 gss_release_cred(&ctx->minor, &client->creds);
345 client->name = new_name;
346 client->creds = ctx->client_creds;
347 ctx->client_creds = GSS_C_NO_CREDENTIAL;
348 client->updated = 1;
349 return GSS_S_COMPLETE;
350 }
273 351
274 client->mech = NULL; 352 client->mech = NULL;
275 353
@@ -284,6 +362,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
284 if (client->mech == NULL) 362 if (client->mech == NULL)
285 return GSS_S_FAILURE; 363 return GSS_S_FAILURE;
286 364
365 if (ctx->client_creds &&
366 (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
367 ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
368 ssh_gssapi_error(ctx);
369 return (ctx->major);
370 }
371
287 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, 372 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
288 &client->displayname, NULL))) { 373 &client->displayname, NULL))) {
289 ssh_gssapi_error(ctx); 374 ssh_gssapi_error(ctx);
@@ -301,6 +386,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
301 return (ctx->major); 386 return (ctx->major);
302 } 387 }
303 388
389 gss_release_buffer(&ctx->minor, &ename);
390
304 /* We can't copy this structure, so we just move the pointer to it */ 391 /* We can't copy this structure, so we just move the pointer to it */
305 client->creds = ctx->client_creds; 392 client->creds = ctx->client_creds;
306 ctx->client_creds = GSS_C_NO_CREDENTIAL; 393 ctx->client_creds = GSS_C_NO_CREDENTIAL;
@@ -348,7 +435,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep)
348 435
349/* Privileged */ 436/* Privileged */
350int 437int
351ssh_gssapi_userok(char *user) 438ssh_gssapi_userok(char *user, struct passwd *pw)
352{ 439{
353 OM_uint32 lmin; 440 OM_uint32 lmin;
354 441
@@ -358,9 +445,11 @@ ssh_gssapi_userok(char *user)
358 return 0; 445 return 0;
359 } 446 }
360 if (gssapi_client.mech && gssapi_client.mech->userok) 447 if (gssapi_client.mech && gssapi_client.mech->userok)
361 if ((*gssapi_client.mech->userok)(&gssapi_client, user)) 448 if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
449 gssapi_client.used = 1;
450 gssapi_client.store.owner = pw;
362 return 1; 451 return 1;
363 else { 452 } else {
364 /* Destroy delegated credentials if userok fails */ 453 /* Destroy delegated credentials if userok fails */
365 gss_release_buffer(&lmin, &gssapi_client.displayname); 454 gss_release_buffer(&lmin, &gssapi_client.displayname);
366 gss_release_buffer(&lmin, &gssapi_client.exportedname); 455 gss_release_buffer(&lmin, &gssapi_client.exportedname);
@@ -374,14 +463,90 @@ ssh_gssapi_userok(char *user)
374 return (0); 463 return (0);
375} 464}
376 465
377/* Privileged */ 466/* These bits are only used for rekeying. The unpriviledged child is running
378OM_uint32 467 * as the user, the monitor is root.
379ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) 468 *
469 * In the child, we want to :
470 * *) Ask the monitor to store our credentials into the store we specify
471 * *) If it succeeds, maybe do a PAM update
472 */
473
474/* Stuff for PAM */
475
476#ifdef USE_PAM
477static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg,
478 struct pam_response **resp, void *data)
380{ 479{
381 ctx->major = gss_verify_mic(&ctx->minor, ctx->context, 480 return (PAM_CONV_ERR);
382 gssbuf, gssmic, NULL); 481}
482#endif
383 483
384 return (ctx->major); 484void
485ssh_gssapi_rekey_creds(void) {
486 int ok;
487 int ret;
488#ifdef USE_PAM
489 pam_handle_t *pamh = NULL;
490 struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
491 char *envstr;
492#endif
493
494 if (gssapi_client.store.filename == NULL &&
495 gssapi_client.store.envval == NULL &&
496 gssapi_client.store.envvar == NULL)
497 return;
498
499 ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
500
501 if (!ok)
502 return;
503
504 debug("Rekeyed credentials stored successfully");
505
506 /* Actually managing to play with the ssh pam stack from here will
507 * be next to impossible. In any case, we may want different options
508 * for rekeying. So, use our own :)
509 */
510#ifdef USE_PAM
511 if (!use_privsep) {
512 debug("Not even going to try and do PAM with privsep disabled");
513 return;
514 }
515
516 ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
517 &pamconv, &pamh);
518 if (ret)
519 return;
520
521 xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar,
522 gssapi_client.store.envval);
523
524 ret = pam_putenv(pamh, envstr);
525 if (!ret)
526 pam_setcred(pamh, PAM_REINITIALIZE_CRED);
527 pam_end(pamh, PAM_SUCCESS);
528#endif
529}
530
531int
532ssh_gssapi_update_creds(ssh_gssapi_ccache *store) {
533 int ok = 0;
534
535 /* Check we've got credentials to store */
536 if (!gssapi_client.updated)
537 return 0;
538
539 gssapi_client.updated = 0;
540
541 temporarily_use_uid(gssapi_client.store.owner);
542 if (gssapi_client.mech && gssapi_client.mech->updatecreds)
543 ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client);
544 else
545 debug("No update function for this mechanism");
546
547 restore_uid();
548
549 return ok;
385} 550}
386 551
387#endif 552#endif
diff --git a/kex.c b/kex.c
index 74e2b8682..d114ee3e0 100644
--- a/kex.c
+++ b/kex.c
@@ -51,6 +51,10 @@
51#include "roaming.h" 51#include "roaming.h"
52#include "digest.h" 52#include "digest.h"
53 53
54#ifdef GSSAPI
55#include "ssh-gss.h"
56#endif
57
54#if OPENSSL_VERSION_NUMBER >= 0x00907000L 58#if OPENSSL_VERSION_NUMBER >= 0x00907000L
55# if defined(HAVE_EVP_SHA256) 59# if defined(HAVE_EVP_SHA256)
56# define evp_ssh_sha256 EVP_sha256 60# define evp_ssh_sha256 EVP_sha256
@@ -92,6 +96,14 @@ static const struct kexalg kexalgs[] = {
92#endif 96#endif
93 { NULL, -1, -1, -1}, 97 { NULL, -1, -1, -1},
94}; 98};
99static const struct kexalg kexalg_prefixes[] = {
100#ifdef GSSAPI
101 { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
102 { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
103 { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
104#endif
105 { NULL, -1, -1, -1 },
106};
95 107
96char * 108char *
97kex_alg_list(char sep) 109kex_alg_list(char sep)
@@ -120,6 +132,10 @@ kex_alg_by_name(const char *name)
120 if (strcmp(k->name, name) == 0) 132 if (strcmp(k->name, name) == 0)
121 return k; 133 return k;
122 } 134 }
135 for (k = kexalg_prefixes; k->name != NULL; k++) {
136 if (strncmp(k->name, name, strlen(k->name)) == 0)
137 return k;
138 }
123 return NULL; 139 return NULL;
124} 140}
125 141
diff --git a/kex.h b/kex.h
index c85680eea..ea698c467 100644
--- a/kex.h
+++ b/kex.h
@@ -76,6 +76,9 @@ enum kex_exchange {
76 KEX_DH_GEX_SHA256, 76 KEX_DH_GEX_SHA256,
77 KEX_ECDH_SHA2, 77 KEX_ECDH_SHA2,
78 KEX_C25519_SHA256, 78 KEX_C25519_SHA256,
79 KEX_GSS_GRP1_SHA1,
80 KEX_GSS_GRP14_SHA1,
81 KEX_GSS_GEX_SHA1,
79 KEX_MAX 82 KEX_MAX
80}; 83};
81 84
@@ -135,6 +138,12 @@ struct Kex {
135 int flags; 138 int flags;
136 int hash_alg; 139 int hash_alg;
137 int ec_nid; 140 int ec_nid;
141#ifdef GSSAPI
142 int gss_deleg_creds;
143 int gss_trust_dns;
144 char *gss_host;
145 char *gss_client;
146#endif
138 char *client_version_string; 147 char *client_version_string;
139 char *server_version_string; 148 char *server_version_string;
140 int (*verify_host_key)(Key *); 149 int (*verify_host_key)(Key *);
@@ -167,6 +176,11 @@ void kexecdh_server(Kex *);
167void kexc25519_client(Kex *); 176void kexc25519_client(Kex *);
168void kexc25519_server(Kex *); 177void kexc25519_server(Kex *);
169 178
179#ifdef GSSAPI
180void kexgss_client(Kex *);
181void kexgss_server(Kex *);
182#endif
183
170void 184void
171kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, 185kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
172 BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); 186 BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *);
diff --git a/kexgssc.c b/kexgssc.c
new file mode 100644
index 000000000..92a31c5a3
--- /dev/null
+++ b/kexgssc.c
@@ -0,0 +1,332 @@
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 int type = 0;
65 int first = 1;
66 int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
67
68 /* Initialise our GSSAPI world */
69 ssh_gssapi_build_ctx(&ctxt);
70 if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type)
71 == GSS_C_NO_OID)
72 fatal("Couldn't identify host exchange");
73
74 if (ssh_gssapi_import_name(ctxt, kex->gss_host))
75 fatal("Couldn't import hostname");
76
77 if (kex->gss_client &&
78 ssh_gssapi_client_identity(ctxt, kex->gss_client))
79 fatal("Couldn't acquire client credentials");
80
81 switch (kex->kex_type) {
82 case KEX_GSS_GRP1_SHA1:
83 dh = dh_new_group1();
84 break;
85 case KEX_GSS_GRP14_SHA1:
86 dh = dh_new_group14();
87 break;
88 case KEX_GSS_GEX_SHA1:
89 debug("Doing group exchange\n");
90 nbits = dh_estimate(kex->we_need * 8);
91 packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
92 packet_put_int(min);
93 packet_put_int(nbits);
94 packet_put_int(max);
95
96 packet_send();
97
98 packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
99
100 if ((p = BN_new()) == NULL)
101 fatal("BN_new() failed");
102 packet_get_bignum2(p);
103 if ((g = BN_new()) == NULL)
104 fatal("BN_new() failed");
105 packet_get_bignum2(g);
106 packet_check_eom();
107
108 if (BN_num_bits(p) < min || BN_num_bits(p) > max)
109 fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
110 min, BN_num_bits(p), max);
111
112 dh = dh_new_group(g, p);
113 break;
114 default:
115 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
116 }
117
118 /* Step 1 - e is dh->pub_key */
119 dh_gen_key(dh, kex->we_need * 8);
120
121 /* This is f, we initialise it now to make life easier */
122 dh_server_pub = BN_new();
123 if (dh_server_pub == NULL)
124 fatal("dh_server_pub == NULL");
125
126 token_ptr = GSS_C_NO_BUFFER;
127
128 do {
129 debug("Calling gss_init_sec_context");
130
131 maj_status = ssh_gssapi_init_ctx(ctxt,
132 kex->gss_deleg_creds, token_ptr, &send_tok,
133 &ret_flags);
134
135 if (GSS_ERROR(maj_status)) {
136 if (send_tok.length != 0) {
137 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
138 packet_put_string(send_tok.value,
139 send_tok.length);
140 }
141 fatal("gss_init_context failed");
142 }
143
144 /* If we've got an old receive buffer get rid of it */
145 if (token_ptr != GSS_C_NO_BUFFER)
146 free(recv_tok.value);
147
148 if (maj_status == GSS_S_COMPLETE) {
149 /* If mutual state flag is not true, kex fails */
150 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
151 fatal("Mutual authentication failed");
152
153 /* If integ avail flag is not true kex fails */
154 if (!(ret_flags & GSS_C_INTEG_FLAG))
155 fatal("Integrity check failed");
156 }
157
158 /*
159 * If we have data to send, then the last message that we
160 * received cannot have been a 'complete'.
161 */
162 if (send_tok.length != 0) {
163 if (first) {
164 packet_start(SSH2_MSG_KEXGSS_INIT);
165 packet_put_string(send_tok.value,
166 send_tok.length);
167 packet_put_bignum2(dh->pub_key);
168 first = 0;
169 } else {
170 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
171 packet_put_string(send_tok.value,
172 send_tok.length);
173 }
174 packet_send();
175 gss_release_buffer(&min_status, &send_tok);
176
177 /* If we've sent them data, they should reply */
178 do {
179 type = packet_read();
180 if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
181 debug("Received KEXGSS_HOSTKEY");
182 if (serverhostkey)
183 fatal("Server host key received more than once");
184 serverhostkey =
185 packet_get_string(&slen);
186 }
187 } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
188
189 switch (type) {
190 case SSH2_MSG_KEXGSS_CONTINUE:
191 debug("Received GSSAPI_CONTINUE");
192 if (maj_status == GSS_S_COMPLETE)
193 fatal("GSSAPI Continue received from server when complete");
194 recv_tok.value = packet_get_string(&strlen);
195 recv_tok.length = strlen;
196 break;
197 case SSH2_MSG_KEXGSS_COMPLETE:
198 debug("Received GSSAPI_COMPLETE");
199 packet_get_bignum2(dh_server_pub);
200 msg_tok.value = packet_get_string(&strlen);
201 msg_tok.length = strlen;
202
203 /* Is there a token included? */
204 if (packet_get_char()) {
205 recv_tok.value=
206 packet_get_string(&strlen);
207 recv_tok.length = strlen;
208 /* If we're already complete - protocol error */
209 if (maj_status == GSS_S_COMPLETE)
210 packet_disconnect("Protocol error: received token when complete");
211 } else {
212 /* No token included */
213 if (maj_status != GSS_S_COMPLETE)
214 packet_disconnect("Protocol error: did not receive final token");
215 }
216 break;
217 case SSH2_MSG_KEXGSS_ERROR:
218 debug("Received Error");
219 maj_status = packet_get_int();
220 min_status = packet_get_int();
221 msg = packet_get_string(NULL);
222 (void) packet_get_string_ptr(NULL);
223 fatal("GSSAPI Error: \n%.400s",msg);
224 default:
225 packet_disconnect("Protocol error: didn't expect packet type %d",
226 type);
227 }
228 token_ptr = &recv_tok;
229 } else {
230 /* No data, and not complete */
231 if (maj_status != GSS_S_COMPLETE)
232 fatal("Not complete, and no token output");
233 }
234 } while (maj_status & GSS_S_CONTINUE_NEEDED);
235
236 /*
237 * We _must_ have received a COMPLETE message in reply from the
238 * server, which will have set dh_server_pub and msg_tok
239 */
240
241 if (type != SSH2_MSG_KEXGSS_COMPLETE)
242 fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
243
244 /* Check f in range [1, p-1] */
245 if (!dh_pub_is_valid(dh, dh_server_pub))
246 packet_disconnect("bad server public DH value");
247
248 /* compute K=f^x mod p */
249 klen = DH_size(dh);
250 kbuf = xmalloc(klen);
251 kout = DH_compute_key(kbuf, dh_server_pub, dh);
252 if (kout < 0)
253 fatal("DH_compute_key: failed");
254
255 shared_secret = BN_new();
256 if (shared_secret == NULL)
257 fatal("kexgss_client: BN_new failed");
258
259 if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
260 fatal("kexdh_client: BN_bin2bn failed");
261
262 memset(kbuf, 0, klen);
263 free(kbuf);
264
265 switch (kex->kex_type) {
266 case KEX_GSS_GRP1_SHA1:
267 case KEX_GSS_GRP14_SHA1:
268 kex_dh_hash( kex->client_version_string,
269 kex->server_version_string,
270 buffer_ptr(&kex->my), buffer_len(&kex->my),
271 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
272 (serverhostkey ? serverhostkey : empty), slen,
273 dh->pub_key, /* e */
274 dh_server_pub, /* f */
275 shared_secret, /* K */
276 &hash, &hashlen
277 );
278 break;
279 case KEX_GSS_GEX_SHA1:
280 kexgex_hash(
281 kex->hash_alg,
282 kex->client_version_string,
283 kex->server_version_string,
284 buffer_ptr(&kex->my), buffer_len(&kex->my),
285 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
286 (serverhostkey ? serverhostkey : empty), slen,
287 min, nbits, max,
288 dh->p, dh->g,
289 dh->pub_key,
290 dh_server_pub,
291 shared_secret,
292 &hash, &hashlen
293 );
294 break;
295 default:
296 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
297 }
298
299 gssbuf.value = hash;
300 gssbuf.length = hashlen;
301
302 /* Verify that the hash matches the MIC we just got. */
303 if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
304 packet_disconnect("Hash's MIC didn't verify");
305
306 free(msg_tok.value);
307
308 DH_free(dh);
309 free(serverhostkey);
310 BN_clear_free(dh_server_pub);
311
312 /* save session id */
313 if (kex->session_id == NULL) {
314 kex->session_id_len = hashlen;
315 kex->session_id = xmalloc(kex->session_id_len);
316 memcpy(kex->session_id, hash, kex->session_id_len);
317 }
318
319 if (kex->gss_deleg_creds)
320 ssh_gssapi_credentials_updated(ctxt);
321
322 if (gss_kex_context == NULL)
323 gss_kex_context = ctxt;
324 else
325 ssh_gssapi_delete_ctx(&ctxt);
326
327 kex_derive_keys_bn(kex, hash, hashlen, shared_secret);
328 BN_clear_free(shared_secret);
329 kex_finish(kex);
330}
331
332#endif /* GSSAPI */
diff --git a/kexgsss.c b/kexgsss.c
new file mode 100644
index 000000000..809525924
--- /dev/null
+++ b/kexgsss.c
@@ -0,0 +1,289 @@
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 mechs = ssh_gssapi_server_mechanisms();
83 free(mechs);
84 }
85
86 debug2("%s: Identifying %s", __func__, kex->name);
87 oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type);
88 if (oid == GSS_C_NO_OID)
89 fatal("Unknown gssapi mechanism");
90
91 debug2("%s: Acquiring credentials", __func__);
92
93 if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
94 fatal("Unable to acquire credentials for the server");
95
96 switch (kex->kex_type) {
97 case KEX_GSS_GRP1_SHA1:
98 dh = dh_new_group1();
99 break;
100 case KEX_GSS_GRP14_SHA1:
101 dh = dh_new_group14();
102 break;
103 case KEX_GSS_GEX_SHA1:
104 debug("Doing group exchange");
105 packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ);
106 min = packet_get_int();
107 nbits = packet_get_int();
108 max = packet_get_int();
109 min = MAX(DH_GRP_MIN, min);
110 max = MIN(DH_GRP_MAX, max);
111 packet_check_eom();
112 if (max < min || nbits < min || max < nbits)
113 fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
114 min, nbits, max);
115 dh = PRIVSEP(choose_dh(min, nbits, max));
116 if (dh == NULL)
117 packet_disconnect("Protocol error: no matching group found");
118
119 packet_start(SSH2_MSG_KEXGSS_GROUP);
120 packet_put_bignum2(dh->p);
121 packet_put_bignum2(dh->g);
122 packet_send();
123
124 packet_write_wait();
125 break;
126 default:
127 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
128 }
129
130 dh_gen_key(dh, kex->we_need * 8);
131
132 do {
133 debug("Wait SSH2_MSG_GSSAPI_INIT");
134 type = packet_read();
135 switch(type) {
136 case SSH2_MSG_KEXGSS_INIT:
137 if (dh_client_pub != NULL)
138 fatal("Received KEXGSS_INIT after initialising");
139 recv_tok.value = packet_get_string(&slen);
140 recv_tok.length = slen;
141
142 if ((dh_client_pub = BN_new()) == NULL)
143 fatal("dh_client_pub == NULL");
144
145 packet_get_bignum2(dh_client_pub);
146
147 /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
148 break;
149 case SSH2_MSG_KEXGSS_CONTINUE:
150 recv_tok.value = packet_get_string(&slen);
151 recv_tok.length = slen;
152 break;
153 default:
154 packet_disconnect(
155 "Protocol error: didn't expect packet type %d",
156 type);
157 }
158
159 maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
160 &send_tok, &ret_flags));
161
162 free(recv_tok.value);
163
164 if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
165 fatal("Zero length token output when incomplete");
166
167 if (dh_client_pub == NULL)
168 fatal("No client public key");
169
170 if (maj_status & GSS_S_CONTINUE_NEEDED) {
171 debug("Sending GSSAPI_CONTINUE");
172 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
173 packet_put_string(send_tok.value, send_tok.length);
174 packet_send();
175 gss_release_buffer(&min_status, &send_tok);
176 }
177 } while (maj_status & GSS_S_CONTINUE_NEEDED);
178
179 if (GSS_ERROR(maj_status)) {
180 if (send_tok.length > 0) {
181 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
182 packet_put_string(send_tok.value, send_tok.length);
183 packet_send();
184 }
185 fatal("accept_ctx died");
186 }
187
188 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
189 fatal("Mutual Authentication flag wasn't set");
190
191 if (!(ret_flags & GSS_C_INTEG_FLAG))
192 fatal("Integrity flag wasn't set");
193
194 if (!dh_pub_is_valid(dh, dh_client_pub))
195 packet_disconnect("bad client public DH value");
196
197 klen = DH_size(dh);
198 kbuf = xmalloc(klen);
199 kout = DH_compute_key(kbuf, dh_client_pub, dh);
200 if (kout < 0)
201 fatal("DH_compute_key: failed");
202
203 shared_secret = BN_new();
204 if (shared_secret == NULL)
205 fatal("kexgss_server: BN_new failed");
206
207 if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
208 fatal("kexgss_server: BN_bin2bn failed");
209
210 memset(kbuf, 0, klen);
211 free(kbuf);
212
213 switch (kex->kex_type) {
214 case KEX_GSS_GRP1_SHA1:
215 case KEX_GSS_GRP14_SHA1:
216 kex_dh_hash(
217 kex->client_version_string, kex->server_version_string,
218 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
219 buffer_ptr(&kex->my), buffer_len(&kex->my),
220 NULL, 0, /* Change this if we start sending host keys */
221 dh_client_pub, dh->pub_key, shared_secret,
222 &hash, &hashlen
223 );
224 break;
225 case KEX_GSS_GEX_SHA1:
226 kexgex_hash(
227 kex->hash_alg,
228 kex->client_version_string, kex->server_version_string,
229 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
230 buffer_ptr(&kex->my), buffer_len(&kex->my),
231 NULL, 0,
232 min, nbits, max,
233 dh->p, dh->g,
234 dh_client_pub,
235 dh->pub_key,
236 shared_secret,
237 &hash, &hashlen
238 );
239 break;
240 default:
241 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
242 }
243
244 BN_clear_free(dh_client_pub);
245
246 if (kex->session_id == NULL) {
247 kex->session_id_len = hashlen;
248 kex->session_id = xmalloc(kex->session_id_len);
249 memcpy(kex->session_id, hash, kex->session_id_len);
250 }
251
252 gssbuf.value = hash;
253 gssbuf.length = hashlen;
254
255 if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok))))
256 fatal("Couldn't get MIC");
257
258 packet_start(SSH2_MSG_KEXGSS_COMPLETE);
259 packet_put_bignum2(dh->pub_key);
260 packet_put_string(msg_tok.value,msg_tok.length);
261
262 if (send_tok.length != 0) {
263 packet_put_char(1); /* true */
264 packet_put_string(send_tok.value, send_tok.length);
265 } else {
266 packet_put_char(0); /* false */
267 }
268 packet_send();
269
270 gss_release_buffer(&min_status, &send_tok);
271 gss_release_buffer(&min_status, &msg_tok);
272
273 if (gss_kex_context == NULL)
274 gss_kex_context = ctxt;
275 else
276 ssh_gssapi_delete_ctx(&ctxt);
277
278 DH_free(dh);
279
280 kex_derive_keys_bn(kex, hash, hashlen, shared_secret);
281 BN_clear_free(shared_secret);
282 kex_finish(kex);
283
284 /* If this was a rekey, then save out any delegated credentials we
285 * just exchanged. */
286 if (options.gss_store_rekey)
287 ssh_gssapi_rekey_creds();
288}
289#endif /* GSSAPI */
diff --git a/key.c b/key.c
index 168e1b7d7..3d640e79f 100644
--- a/key.c
+++ b/key.c
@@ -985,6 +985,7 @@ static const struct keytype keytypes[] = {
985 KEY_DSA_CERT_V00, 0, 1 }, 985 KEY_DSA_CERT_V00, 0, 1 },
986 { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", 986 { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT",
987 KEY_ED25519_CERT, 0, 1 }, 987 KEY_ED25519_CERT, 0, 1 },
988 { "null", "null", KEY_NULL, 0, 0 },
988 { NULL, NULL, -1, -1, 0 } 989 { NULL, NULL, -1, -1, 0 }
989}; 990};
990 991
@@ -1063,7 +1064,7 @@ key_alg_list(int certs_only, int plain_only)
1063 const struct keytype *kt; 1064 const struct keytype *kt;
1064 1065
1065 for (kt = keytypes; kt->type != -1; kt++) { 1066 for (kt = keytypes; kt->type != -1; kt++) {
1066 if (kt->name == NULL) 1067 if (kt->name == NULL || kt->type == KEY_NULL)
1067 continue; 1068 continue;
1068 if ((certs_only && !kt->cert) || (plain_only && kt->cert)) 1069 if ((certs_only && !kt->cert) || (plain_only && kt->cert))
1069 continue; 1070 continue;
diff --git a/key.h b/key.h
index d8ad13d08..c8aeba29e 100644
--- a/key.h
+++ b/key.h
@@ -46,6 +46,7 @@ enum types {
46 KEY_ED25519_CERT, 46 KEY_ED25519_CERT,
47 KEY_RSA_CERT_V00, 47 KEY_RSA_CERT_V00,
48 KEY_DSA_CERT_V00, 48 KEY_DSA_CERT_V00,
49 KEY_NULL,
49 KEY_UNSPEC 50 KEY_UNSPEC
50}; 51};
51enum fp_type { 52enum fp_type {
diff --git a/monitor.c b/monitor.c
index 531c4f9a8..291881493 100644
--- a/monitor.c
+++ b/monitor.c
@@ -175,6 +175,8 @@ int mm_answer_gss_setup_ctx(int, Buffer *);
175int mm_answer_gss_accept_ctx(int, Buffer *); 175int mm_answer_gss_accept_ctx(int, Buffer *);
176int mm_answer_gss_userok(int, Buffer *); 176int mm_answer_gss_userok(int, Buffer *);
177int mm_answer_gss_checkmic(int, Buffer *); 177int mm_answer_gss_checkmic(int, Buffer *);
178int mm_answer_gss_sign(int, Buffer *);
179int mm_answer_gss_updatecreds(int, Buffer *);
178#endif 180#endif
179 181
180#ifdef SSH_AUDIT_EVENTS 182#ifdef SSH_AUDIT_EVENTS
@@ -247,11 +249,18 @@ struct mon_table mon_dispatch_proto20[] = {
247 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, 249 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
248 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, 250 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
249 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, 251 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
252 {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
250#endif 253#endif
251 {0, 0, NULL} 254 {0, 0, NULL}
252}; 255};
253 256
254struct mon_table mon_dispatch_postauth20[] = { 257struct mon_table mon_dispatch_postauth20[] = {
258#ifdef GSSAPI
259 {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
260 {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
261 {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
262 {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
263#endif
255 {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, 264 {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
256 {MONITOR_REQ_SIGN, 0, mm_answer_sign}, 265 {MONITOR_REQ_SIGN, 0, mm_answer_sign},
257 {MONITOR_REQ_PTY, 0, mm_answer_pty}, 266 {MONITOR_REQ_PTY, 0, mm_answer_pty},
@@ -360,6 +369,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
360 /* Permit requests for moduli and signatures */ 369 /* Permit requests for moduli and signatures */
361 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 370 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
362 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 371 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
372#ifdef GSSAPI
373 /* and for the GSSAPI key exchange */
374 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
375#endif
363 } else { 376 } else {
364 mon_dispatch = mon_dispatch_proto15; 377 mon_dispatch = mon_dispatch_proto15;
365 378
@@ -465,6 +478,10 @@ monitor_child_postauth(struct monitor *pmonitor)
465 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 478 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
466 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 479 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
467 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 480 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
481#ifdef GSSAPI
482 /* and for the GSSAPI key exchange */
483 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
484#endif
468 } else { 485 } else {
469 mon_dispatch = mon_dispatch_postauth15; 486 mon_dispatch = mon_dispatch_postauth15;
470 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 487 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
@@ -1834,6 +1851,13 @@ mm_get_kex(Buffer *m)
1834 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 1851 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
1835 kex->kex[KEX_ECDH_SHA2] = kexecdh_server; 1852 kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
1836 kex->kex[KEX_C25519_SHA256] = kexc25519_server; 1853 kex->kex[KEX_C25519_SHA256] = kexc25519_server;
1854#ifdef GSSAPI
1855 if (options.gss_keyex) {
1856 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
1857 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
1858 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
1859 }
1860#endif
1837 kex->server = 1; 1861 kex->server = 1;
1838 kex->hostkey_type = buffer_get_int(m); 1862 kex->hostkey_type = buffer_get_int(m);
1839 kex->kex_type = buffer_get_int(m); 1863 kex->kex_type = buffer_get_int(m);
@@ -2041,6 +2065,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer *m)
2041 OM_uint32 major; 2065 OM_uint32 major;
2042 u_int len; 2066 u_int len;
2043 2067
2068 if (!options.gss_authentication && !options.gss_keyex)
2069 fatal("In GSSAPI monitor when GSSAPI is disabled");
2070
2044 goid.elements = buffer_get_string(m, &len); 2071 goid.elements = buffer_get_string(m, &len);
2045 goid.length = len; 2072 goid.length = len;
2046 2073
@@ -2068,6 +2095,9 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
2068 OM_uint32 flags = 0; /* GSI needs this */ 2095 OM_uint32 flags = 0; /* GSI needs this */
2069 u_int len; 2096 u_int len;
2070 2097
2098 if (!options.gss_authentication && !options.gss_keyex)
2099 fatal("In GSSAPI monitor when GSSAPI is disabled");
2100
2071 in.value = buffer_get_string(m, &len); 2101 in.value = buffer_get_string(m, &len);
2072 in.length = len; 2102 in.length = len;
2073 major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); 2103 major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
@@ -2085,6 +2115,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
2085 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); 2115 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
2086 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); 2116 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
2087 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); 2117 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
2118 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
2088 } 2119 }
2089 return (0); 2120 return (0);
2090} 2121}
@@ -2096,6 +2127,9 @@ mm_answer_gss_checkmic(int sock, Buffer *m)
2096 OM_uint32 ret; 2127 OM_uint32 ret;
2097 u_int len; 2128 u_int len;
2098 2129
2130 if (!options.gss_authentication && !options.gss_keyex)
2131 fatal("In GSSAPI monitor when GSSAPI is disabled");
2132
2099 gssbuf.value = buffer_get_string(m, &len); 2133 gssbuf.value = buffer_get_string(m, &len);
2100 gssbuf.length = len; 2134 gssbuf.length = len;
2101 mic.value = buffer_get_string(m, &len); 2135 mic.value = buffer_get_string(m, &len);
@@ -2122,7 +2156,11 @@ mm_answer_gss_userok(int sock, Buffer *m)
2122{ 2156{
2123 int authenticated; 2157 int authenticated;
2124 2158
2125 authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); 2159 if (!options.gss_authentication && !options.gss_keyex)
2160 fatal("In GSSAPI monitor when GSSAPI is disabled");
2161
2162 authenticated = authctxt->valid &&
2163 ssh_gssapi_userok(authctxt->user, authctxt->pw);
2126 2164
2127 buffer_clear(m); 2165 buffer_clear(m);
2128 buffer_put_int(m, authenticated); 2166 buffer_put_int(m, authenticated);
@@ -2135,5 +2173,73 @@ mm_answer_gss_userok(int sock, Buffer *m)
2135 /* Monitor loop will terminate if authenticated */ 2173 /* Monitor loop will terminate if authenticated */
2136 return (authenticated); 2174 return (authenticated);
2137} 2175}
2176
2177int
2178mm_answer_gss_sign(int socket, Buffer *m)
2179{
2180 gss_buffer_desc data;
2181 gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
2182 OM_uint32 major, minor;
2183 u_int len;
2184
2185 if (!options.gss_authentication && !options.gss_keyex)
2186 fatal("In GSSAPI monitor when GSSAPI is disabled");
2187
2188 data.value = buffer_get_string(m, &len);
2189 data.length = len;
2190 if (data.length != 20)
2191 fatal("%s: data length incorrect: %d", __func__,
2192 (int) data.length);
2193
2194 /* Save the session ID on the first time around */
2195 if (session_id2_len == 0) {
2196 session_id2_len = data.length;
2197 session_id2 = xmalloc(session_id2_len);
2198 memcpy(session_id2, data.value, session_id2_len);
2199 }
2200 major = ssh_gssapi_sign(gsscontext, &data, &hash);
2201
2202 free(data.value);
2203
2204 buffer_clear(m);
2205 buffer_put_int(m, major);
2206 buffer_put_string(m, hash.value, hash.length);
2207
2208 mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
2209
2210 gss_release_buffer(&minor, &hash);
2211
2212 /* Turn on getpwnam permissions */
2213 monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
2214
2215 /* And credential updating, for when rekeying */
2216 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1);
2217
2218 return (0);
2219}
2220
2221int
2222mm_answer_gss_updatecreds(int socket, Buffer *m) {
2223 ssh_gssapi_ccache store;
2224 int ok;
2225
2226 store.filename = buffer_get_string(m, NULL);
2227 store.envvar = buffer_get_string(m, NULL);
2228 store.envval = buffer_get_string(m, NULL);
2229
2230 ok = ssh_gssapi_update_creds(&store);
2231
2232 free(store.filename);
2233 free(store.envvar);
2234 free(store.envval);
2235
2236 buffer_clear(m);
2237 buffer_put_int(m, ok);
2238
2239 mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m);
2240
2241 return(0);
2242}
2243
2138#endif /* GSSAPI */ 2244#endif /* GSSAPI */
2139 2245
diff --git a/monitor.h b/monitor.h
index 5bc41b513..7f32b0c0c 100644
--- a/monitor.h
+++ b/monitor.h
@@ -65,6 +65,9 @@ enum monitor_reqtype {
65 MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, 65 MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
66 MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, 66 MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
67 67
68 MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151,
69 MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153,
70
68}; 71};
69 72
70struct mm_master; 73struct mm_master;
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 1a47e4174..60b987dce 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,5 +1288,50 @@ 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
diff --git a/monitor_wrap.h b/monitor_wrap.h
index 18c25010d..a4e9d24b3 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 dc884c9b1..7613ff2d9 100644
--- a/readconf.c
+++ b/readconf.c
@@ -141,6 +141,8 @@ typedef enum {
141 oClearAllForwardings, oNoHostAuthenticationForLocalhost, 141 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
142 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 142 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
143 oAddressFamily, oGssAuthentication, oGssDelegateCreds, 143 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
144 oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey,
145 oGssServerIdentity,
144 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 146 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
145 oSendEnv, oControlPath, oControlMaster, oControlPersist, 147 oSendEnv, oControlPath, oControlMaster, oControlPersist,
146 oHashKnownHosts, 148 oHashKnownHosts,
@@ -183,10 +185,19 @@ static struct {
183 { "afstokenpassing", oUnsupported }, 185 { "afstokenpassing", oUnsupported },
184#if defined(GSSAPI) 186#if defined(GSSAPI)
185 { "gssapiauthentication", oGssAuthentication }, 187 { "gssapiauthentication", oGssAuthentication },
188 { "gssapikeyexchange", oGssKeyEx },
186 { "gssapidelegatecredentials", oGssDelegateCreds }, 189 { "gssapidelegatecredentials", oGssDelegateCreds },
190 { "gssapitrustdns", oGssTrustDns },
191 { "gssapiclientidentity", oGssClientIdentity },
192 { "gssapiserveridentity", oGssServerIdentity },
193 { "gssapirenewalforcesrekey", oGssRenewalRekey },
187#else 194#else
188 { "gssapiauthentication", oUnsupported }, 195 { "gssapiauthentication", oUnsupported },
196 { "gssapikeyexchange", oUnsupported },
189 { "gssapidelegatecredentials", oUnsupported }, 197 { "gssapidelegatecredentials", oUnsupported },
198 { "gssapitrustdns", oUnsupported },
199 { "gssapiclientidentity", oUnsupported },
200 { "gssapirenewalforcesrekey", oUnsupported },
190#endif 201#endif
191 { "fallbacktorsh", oDeprecated }, 202 { "fallbacktorsh", oDeprecated },
192 { "usersh", oDeprecated }, 203 { "usersh", oDeprecated },
@@ -841,10 +852,30 @@ parse_time:
841 intptr = &options->gss_authentication; 852 intptr = &options->gss_authentication;
842 goto parse_flag; 853 goto parse_flag;
843 854
855 case oGssKeyEx:
856 intptr = &options->gss_keyex;
857 goto parse_flag;
858
844 case oGssDelegateCreds: 859 case oGssDelegateCreds:
845 intptr = &options->gss_deleg_creds; 860 intptr = &options->gss_deleg_creds;
846 goto parse_flag; 861 goto parse_flag;
847 862
863 case oGssTrustDns:
864 intptr = &options->gss_trust_dns;
865 goto parse_flag;
866
867 case oGssClientIdentity:
868 charptr = &options->gss_client_identity;
869 goto parse_string;
870
871 case oGssServerIdentity:
872 charptr = &options->gss_server_identity;
873 goto parse_string;
874
875 case oGssRenewalRekey:
876 intptr = &options->gss_renewal_rekey;
877 goto parse_flag;
878
848 case oBatchMode: 879 case oBatchMode:
849 intptr = &options->batch_mode; 880 intptr = &options->batch_mode;
850 goto parse_flag; 881 goto parse_flag;
@@ -1497,7 +1528,12 @@ initialize_options(Options * options)
1497 options->pubkey_authentication = -1; 1528 options->pubkey_authentication = -1;
1498 options->challenge_response_authentication = -1; 1529 options->challenge_response_authentication = -1;
1499 options->gss_authentication = -1; 1530 options->gss_authentication = -1;
1531 options->gss_keyex = -1;
1500 options->gss_deleg_creds = -1; 1532 options->gss_deleg_creds = -1;
1533 options->gss_trust_dns = -1;
1534 options->gss_renewal_rekey = -1;
1535 options->gss_client_identity = NULL;
1536 options->gss_server_identity = NULL;
1501 options->password_authentication = -1; 1537 options->password_authentication = -1;
1502 options->kbd_interactive_authentication = -1; 1538 options->kbd_interactive_authentication = -1;
1503 options->kbd_interactive_devices = NULL; 1539 options->kbd_interactive_devices = NULL;
@@ -1616,8 +1652,14 @@ fill_default_options(Options * options)
1616 options->challenge_response_authentication = 1; 1652 options->challenge_response_authentication = 1;
1617 if (options->gss_authentication == -1) 1653 if (options->gss_authentication == -1)
1618 options->gss_authentication = 0; 1654 options->gss_authentication = 0;
1655 if (options->gss_keyex == -1)
1656 options->gss_keyex = 0;
1619 if (options->gss_deleg_creds == -1) 1657 if (options->gss_deleg_creds == -1)
1620 options->gss_deleg_creds = 0; 1658 options->gss_deleg_creds = 0;
1659 if (options->gss_trust_dns == -1)
1660 options->gss_trust_dns = 0;
1661 if (options->gss_renewal_rekey == -1)
1662 options->gss_renewal_rekey = 0;
1621 if (options->password_authentication == -1) 1663 if (options->password_authentication == -1)
1622 options->password_authentication = 1; 1664 options->password_authentication = 1;
1623 if (options->kbd_interactive_authentication == -1) 1665 if (options->kbd_interactive_authentication == -1)
diff --git a/readconf.h b/readconf.h
index 75e3f8f7a..5cc97f0da 100644
--- a/readconf.h
+++ b/readconf.h
@@ -54,7 +54,12 @@ typedef struct {
54 int challenge_response_authentication; 54 int challenge_response_authentication;
55 /* Try S/Key or TIS, authentication. */ 55 /* Try S/Key or TIS, authentication. */
56 int gss_authentication; /* Try GSS authentication */ 56 int gss_authentication; /* Try GSS authentication */
57 int gss_keyex; /* Try GSS key exchange */
57 int gss_deleg_creds; /* Delegate GSS credentials */ 58 int gss_deleg_creds; /* Delegate GSS credentials */
59 int gss_trust_dns; /* Trust DNS for GSS canonicalization */
60 int gss_renewal_rekey; /* Credential renewal forces rekey */
61 char *gss_client_identity; /* Principal to initiate GSSAPI with */
62 char *gss_server_identity; /* GSSAPI target principal */
58 int password_authentication; /* Try password 63 int password_authentication; /* Try password
59 * authentication. */ 64 * authentication. */
60 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ 65 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */
diff --git a/servconf.c b/servconf.c
index 7ba65d51d..0083cf896 100644
--- a/servconf.c
+++ b/servconf.c
@@ -108,7 +108,10 @@ initialize_server_options(ServerOptions *options)
108 options->kerberos_ticket_cleanup = -1; 108 options->kerberos_ticket_cleanup = -1;
109 options->kerberos_get_afs_token = -1; 109 options->kerberos_get_afs_token = -1;
110 options->gss_authentication=-1; 110 options->gss_authentication=-1;
111 options->gss_keyex = -1;
111 options->gss_cleanup_creds = -1; 112 options->gss_cleanup_creds = -1;
113 options->gss_strict_acceptor = -1;
114 options->gss_store_rekey = -1;
112 options->password_authentication = -1; 115 options->password_authentication = -1;
113 options->kbd_interactive_authentication = -1; 116 options->kbd_interactive_authentication = -1;
114 options->challenge_response_authentication = -1; 117 options->challenge_response_authentication = -1;
@@ -244,8 +247,14 @@ fill_default_server_options(ServerOptions *options)
244 options->kerberos_get_afs_token = 0; 247 options->kerberos_get_afs_token = 0;
245 if (options->gss_authentication == -1) 248 if (options->gss_authentication == -1)
246 options->gss_authentication = 0; 249 options->gss_authentication = 0;
250 if (options->gss_keyex == -1)
251 options->gss_keyex = 0;
247 if (options->gss_cleanup_creds == -1) 252 if (options->gss_cleanup_creds == -1)
248 options->gss_cleanup_creds = 1; 253 options->gss_cleanup_creds = 1;
254 if (options->gss_strict_acceptor == -1)
255 options->gss_strict_acceptor = 1;
256 if (options->gss_store_rekey == -1)
257 options->gss_store_rekey = 0;
249 if (options->password_authentication == -1) 258 if (options->password_authentication == -1)
250 options->password_authentication = 1; 259 options->password_authentication = 1;
251 if (options->kbd_interactive_authentication == -1) 260 if (options->kbd_interactive_authentication == -1)
@@ -340,7 +349,9 @@ typedef enum {
340 sBanner, sUseDNS, sHostbasedAuthentication, 349 sBanner, sUseDNS, sHostbasedAuthentication,
341 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, 350 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
342 sClientAliveCountMax, sAuthorizedKeysFile, 351 sClientAliveCountMax, sAuthorizedKeysFile,
343 sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, 352 sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
353 sGssKeyEx, sGssStoreRekey,
354 sAcceptEnv, sPermitTunnel,
344 sMatch, sPermitOpen, sForceCommand, sChrootDirectory, 355 sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
345 sUsePrivilegeSeparation, sAllowAgentForwarding, 356 sUsePrivilegeSeparation, sAllowAgentForwarding,
346 sHostCertificate, 357 sHostCertificate,
@@ -407,10 +418,20 @@ static struct {
407#ifdef GSSAPI 418#ifdef GSSAPI
408 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, 419 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
409 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, 420 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
421 { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
422 { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
423 { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
424 { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
410#else 425#else
411 { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, 426 { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
412 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, 427 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
428 { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
429 { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
430 { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
431 { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
413#endif 432#endif
433 { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
434 { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
414 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, 435 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
415 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, 436 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
416 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, 437 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
@@ -1086,10 +1107,22 @@ process_server_config_line(ServerOptions *options, char *line,
1086 intptr = &options->gss_authentication; 1107 intptr = &options->gss_authentication;
1087 goto parse_flag; 1108 goto parse_flag;
1088 1109
1110 case sGssKeyEx:
1111 intptr = &options->gss_keyex;
1112 goto parse_flag;
1113
1089 case sGssCleanupCreds: 1114 case sGssCleanupCreds:
1090 intptr = &options->gss_cleanup_creds; 1115 intptr = &options->gss_cleanup_creds;
1091 goto parse_flag; 1116 goto parse_flag;
1092 1117
1118 case sGssStrictAcceptor:
1119 intptr = &options->gss_strict_acceptor;
1120 goto parse_flag;
1121
1122 case sGssStoreRekey:
1123 intptr = &options->gss_store_rekey;
1124 goto parse_flag;
1125
1093 case sPasswordAuthentication: 1126 case sPasswordAuthentication:
1094 intptr = &options->password_authentication; 1127 intptr = &options->password_authentication;
1095 goto parse_flag; 1128 goto parse_flag;
@@ -1995,7 +2028,10 @@ dump_config(ServerOptions *o)
1995#endif 2028#endif
1996#ifdef GSSAPI 2029#ifdef GSSAPI
1997 dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); 2030 dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
2031 dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
1998 dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); 2032 dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
2033 dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
2034 dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey);
1999#endif 2035#endif
2000 dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); 2036 dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
2001 dump_cfg_fmtint(sKbdInteractiveAuthentication, 2037 dump_cfg_fmtint(sKbdInteractiveAuthentication,
diff --git a/servconf.h b/servconf.h
index 752d1c5ae..c922eb50c 100644
--- a/servconf.h
+++ b/servconf.h
@@ -112,7 +112,10 @@ typedef struct {
112 int kerberos_get_afs_token; /* If true, try to get AFS token if 112 int kerberos_get_afs_token; /* If true, try to get AFS token if
113 * authenticated with Kerberos. */ 113 * authenticated with Kerberos. */
114 int gss_authentication; /* If true, permit GSSAPI authentication */ 114 int gss_authentication; /* If true, permit GSSAPI authentication */
115 int gss_keyex; /* If true, permit GSSAPI key exchange */
115 int gss_cleanup_creds; /* If true, destroy cred cache on logout */ 116 int gss_cleanup_creds; /* If true, destroy cred cache on logout */
117 int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */
118 int gss_store_rekey;
116 int password_authentication; /* If true, permit password 119 int password_authentication; /* If true, permit password
117 * authentication. */ 120 * authentication. */
118 int kbd_interactive_authentication; /* If true, permit */ 121 int kbd_interactive_authentication; /* If true, permit */
diff --git a/ssh-gss.h b/ssh-gss.h
index a99d7f08b..914701bcf 100644
--- a/ssh-gss.h
+++ b/ssh-gss.h
@@ -1,6 +1,6 @@
1/* $OpenBSD: ssh-gss.h,v 1.11 2014/02/26 20:28:44 djm Exp $ */ 1/* $OpenBSD: ssh-gss.h,v 1.11 2014/02/26 20:28:44 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);
@@ -119,16 +136,32 @@ void ssh_gssapi_build_ctx(Gssctxt **);
119void ssh_gssapi_delete_ctx(Gssctxt **); 136void ssh_gssapi_delete_ctx(Gssctxt **);
120OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); 137OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
121void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); 138void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
122int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); 139int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *);
140OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
141int ssh_gssapi_credentials_updated(Gssctxt *);
123 142
124/* In the server */ 143/* In the server */
144typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *,
145 const char *);
146char *ssh_gssapi_client_mechanisms(const char *, const char *);
147char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *,
148 const char *);
149gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int);
150int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *,
151 const char *);
125OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); 152OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
126int ssh_gssapi_userok(char *name); 153int ssh_gssapi_userok(char *name, struct passwd *);
127OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 154OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
128void ssh_gssapi_do_child(char ***, u_int *); 155void ssh_gssapi_do_child(char ***, u_int *);
129void ssh_gssapi_cleanup_creds(void); 156void ssh_gssapi_cleanup_creds(void);
130void ssh_gssapi_storecreds(void); 157void ssh_gssapi_storecreds(void);
131 158
159char *ssh_gssapi_server_mechanisms(void);
160int ssh_gssapi_oid_table_ok(void);
161
162int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
163void ssh_gssapi_rekey_creds(void);
164
132#endif /* GSSAPI */ 165#endif /* GSSAPI */
133 166
134#endif /* _SSH_GSS_H */ 167#endif /* _SSH_GSS_H */
diff --git a/ssh_config b/ssh_config
index 03a228fbd..228e5abce 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 b5803920f..e7accd6a3 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -682,11 +682,43 @@ Specifies whether user authentication based on GSSAPI is allowed.
682The default is 682The default is
683.Dq no . 683.Dq no .
684Note that this option applies to protocol version 2 only. 684Note that this option applies to protocol version 2 only.
685.It Cm GSSAPIKeyExchange
686Specifies whether key exchange based on GSSAPI may be used. When using
687GSSAPI key exchange the server need not have a host key.
688The default is
689.Dq no .
690Note that this option applies to protocol version 2 only.
691.It Cm GSSAPIClientIdentity
692If set, specifies the GSSAPI client identity that ssh should use when
693connecting to the server. The default is unset, which means that the default
694identity will be used.
695.It Cm GSSAPIServerIdentity
696If set, specifies the GSSAPI server identity that ssh should expect when
697connecting to the server. The default is unset, which means that the
698expected GSSAPI server identity will be determined from the target
699hostname.
685.It Cm GSSAPIDelegateCredentials 700.It Cm GSSAPIDelegateCredentials
686Forward (delegate) credentials to the server. 701Forward (delegate) credentials to the server.
687The default is 702The default is
688.Dq no . 703.Dq no .
689Note that this option applies to protocol version 2 only. 704Note that this option applies to protocol version 2 connections using GSSAPI.
705.It Cm GSSAPIRenewalForcesRekey
706If set to
707.Dq yes
708then renewal of the client's GSSAPI credentials will force the rekeying of the
709ssh connection. With a compatible server, this can delegate the renewed
710credentials to a session on the server.
711The default is
712.Dq no .
713.It Cm GSSAPITrustDns
714Set to
715.Dq yes to indicate that the DNS is trusted to securely canonicalize
716the name of the host being connected to. If
717.Dq no, the hostname entered on the
718command line will be passed untouched to the GSSAPI library.
719The default is
720.Dq no .
721This option only applies to protocol version 2 connections using GSSAPI.
690.It Cm HashKnownHosts 722.It Cm HashKnownHosts
691Indicates that 723Indicates that
692.Xr ssh 1 724.Xr ssh 1
diff --git a/sshconnect2.c b/sshconnect2.c
index 7f4ff4189..66cb03527 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -158,9 +158,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
158{ 158{
159 Kex *kex; 159 Kex *kex;
160 160
161#ifdef GSSAPI
162 char *orig = NULL, *gss = NULL;
163 char *gss_host = NULL;
164#endif
165
161 xxx_host = host; 166 xxx_host = host;
162 xxx_hostaddr = hostaddr; 167 xxx_hostaddr = hostaddr;
163 168
169#ifdef GSSAPI
170 if (options.gss_keyex) {
171 /* Add the GSSAPI mechanisms currently supported on this
172 * client to the key exchange algorithm proposal */
173 orig = myproposal[PROPOSAL_KEX_ALGS];
174
175 if (options.gss_trust_dns)
176 gss_host = (char *)get_canonical_hostname(1);
177 else
178 gss_host = host;
179
180 gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity);
181 if (gss) {
182 debug("Offering GSSAPI proposal: %s", gss);
183 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
184 "%s,%s", gss, orig);
185 }
186 }
187#endif
188
164 if (options.ciphers == (char *)-1) { 189 if (options.ciphers == (char *)-1) {
165 logit("No valid ciphers for protocol version 2 given, using defaults."); 190 logit("No valid ciphers for protocol version 2 given, using defaults.");
166 options.ciphers = NULL; 191 options.ciphers = NULL;
@@ -196,6 +221,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
196 if (options.kex_algorithms != NULL) 221 if (options.kex_algorithms != NULL)
197 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; 222 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
198 223
224#ifdef GSSAPI
225 /* If we've got GSSAPI algorithms, then we also support the
226 * 'null' hostkey, as a last resort */
227 if (options.gss_keyex && gss) {
228 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
229 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
230 "%s,null", orig);
231 free(gss);
232 }
233#endif
234
199 if (options.rekey_limit || options.rekey_interval) 235 if (options.rekey_limit || options.rekey_interval)
200 packet_set_rekey_limits((u_int32_t)options.rekey_limit, 236 packet_set_rekey_limits((u_int32_t)options.rekey_limit,
201 (time_t)options.rekey_interval); 237 (time_t)options.rekey_interval);
@@ -208,10 +244,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
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;
210 kex->kex[KEX_C25519_SHA256] = kexc25519_client; 246 kex->kex[KEX_C25519_SHA256] = kexc25519_client;
247#ifdef GSSAPI
248 if (options.gss_keyex) {
249 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
250 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
251 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
252 }
253#endif
211 kex->client_version_string=client_version_string; 254 kex->client_version_string=client_version_string;
212 kex->server_version_string=server_version_string; 255 kex->server_version_string=server_version_string;
213 kex->verify_host_key=&verify_host_key_callback; 256 kex->verify_host_key=&verify_host_key_callback;
214 257
258#ifdef GSSAPI
259 if (options.gss_keyex) {
260 kex->gss_deleg_creds = options.gss_deleg_creds;
261 kex->gss_trust_dns = options.gss_trust_dns;
262 kex->gss_client = options.gss_client_identity;
263 if (options.gss_server_identity) {
264 kex->gss_host = options.gss_server_identity;
265 } else {
266 kex->gss_host = gss_host;
267 }
268 }
269#endif
270
215 xxx_kex = kex; 271 xxx_kex = kex;
216 272
217 dispatch_run(DISPATCH_BLOCK, &kex->done, kex); 273 dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
@@ -301,6 +357,7 @@ void input_gssapi_token(int type, u_int32_t, void *);
301void input_gssapi_hash(int type, u_int32_t, void *); 357void input_gssapi_hash(int type, u_int32_t, void *);
302void input_gssapi_error(int, u_int32_t, void *); 358void input_gssapi_error(int, u_int32_t, void *);
303void input_gssapi_errtok(int, u_int32_t, void *); 359void input_gssapi_errtok(int, u_int32_t, void *);
360int userauth_gsskeyex(Authctxt *authctxt);
304#endif 361#endif
305 362
306void userauth(Authctxt *, char *); 363void userauth(Authctxt *, char *);
@@ -316,6 +373,11 @@ static char *authmethods_get(void);
316 373
317Authmethod authmethods[] = { 374Authmethod authmethods[] = {
318#ifdef GSSAPI 375#ifdef GSSAPI
376 {"gssapi-keyex",
377 userauth_gsskeyex,
378 NULL,
379 &options.gss_authentication,
380 NULL},
319 {"gssapi-with-mic", 381 {"gssapi-with-mic",
320 userauth_gssapi, 382 userauth_gssapi,
321 NULL, 383 NULL,
@@ -612,19 +674,31 @@ userauth_gssapi(Authctxt *authctxt)
612 static u_int mech = 0; 674 static u_int mech = 0;
613 OM_uint32 min; 675 OM_uint32 min;
614 int ok = 0; 676 int ok = 0;
677 const char *gss_host;
678
679 if (options.gss_server_identity)
680 gss_host = options.gss_server_identity;
681 else if (options.gss_trust_dns)
682 gss_host = get_canonical_hostname(1);
683 else
684 gss_host = authctxt->host;
615 685
616 /* Try one GSSAPI method at a time, rather than sending them all at 686 /* Try one GSSAPI method at a time, rather than sending them all at
617 * once. */ 687 * once. */
618 688
619 if (gss_supported == NULL) 689 if (gss_supported == NULL)
620 gss_indicate_mechs(&min, &gss_supported); 690 if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
691 gss_supported = NULL;
692 return 0;
693 }
621 694
622 /* Check to see if the mechanism is usable before we offer it */ 695 /* Check to see if the mechanism is usable before we offer it */
623 while (mech < gss_supported->count && !ok) { 696 while (mech < gss_supported->count && !ok) {
624 /* My DER encoding requires length<128 */ 697 /* My DER encoding requires length<128 */
625 if (gss_supported->elements[mech].length < 128 && 698 if (gss_supported->elements[mech].length < 128 &&
626 ssh_gssapi_check_mechanism(&gssctxt, 699 ssh_gssapi_check_mechanism(&gssctxt,
627 &gss_supported->elements[mech], authctxt->host)) { 700 &gss_supported->elements[mech], gss_host,
701 options.gss_client_identity)) {
628 ok = 1; /* Mechanism works */ 702 ok = 1; /* Mechanism works */
629 } else { 703 } else {
630 mech++; 704 mech++;
@@ -721,8 +795,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
721{ 795{
722 Authctxt *authctxt = ctxt; 796 Authctxt *authctxt = ctxt;
723 Gssctxt *gssctxt; 797 Gssctxt *gssctxt;
724 int oidlen; 798 u_int oidlen;
725 char *oidv; 799 u_char *oidv;
726 800
727 if (authctxt == NULL) 801 if (authctxt == NULL)
728 fatal("input_gssapi_response: no authentication context"); 802 fatal("input_gssapi_response: no authentication context");
@@ -831,6 +905,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
831 free(msg); 905 free(msg);
832 free(lang); 906 free(lang);
833} 907}
908
909int
910userauth_gsskeyex(Authctxt *authctxt)
911{
912 Buffer b;
913 gss_buffer_desc gssbuf;
914 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
915 OM_uint32 ms;
916
917 static int attempt = 0;
918 if (attempt++ >= 1)
919 return (0);
920
921 if (gss_kex_context == NULL) {
922 debug("No valid Key exchange context");
923 return (0);
924 }
925
926 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
927 "gssapi-keyex");
928
929 gssbuf.value = buffer_ptr(&b);
930 gssbuf.length = buffer_len(&b);
931
932 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
933 buffer_free(&b);
934 return (0);
935 }
936
937 packet_start(SSH2_MSG_USERAUTH_REQUEST);
938 packet_put_cstring(authctxt->server_user);
939 packet_put_cstring(authctxt->service);
940 packet_put_cstring(authctxt->method->name);
941 packet_put_string(mic.value, mic.length);
942 packet_send();
943
944 buffer_free(&b);
945 gss_release_buffer(&ms, &mic);
946
947 return (1);
948}
949
834#endif /* GSSAPI */ 950#endif /* GSSAPI */
835 951
836int 952int
diff --git a/sshd.c b/sshd.c
index 7523de977..d787fea7b 100644
--- a/sshd.c
+++ b/sshd.c
@@ -122,6 +122,10 @@
122#include "ssh-sandbox.h" 122#include "ssh-sandbox.h"
123#include "version.h" 123#include "version.h"
124 124
125#ifdef USE_SECURITY_SESSION_API
126#include <Security/AuthSession.h>
127#endif
128
125#ifdef LIBWRAP 129#ifdef LIBWRAP
126#include <tcpd.h> 130#include <tcpd.h>
127#include <syslog.h> 131#include <syslog.h>
@@ -1728,10 +1732,13 @@ main(int ac, char **av)
1728 logit("Disabling protocol version 1. Could not load host key"); 1732 logit("Disabling protocol version 1. Could not load host key");
1729 options.protocol &= ~SSH_PROTO_1; 1733 options.protocol &= ~SSH_PROTO_1;
1730 } 1734 }
1735#ifndef GSSAPI
1736 /* The GSSAPI key exchange can run without a host key */
1731 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { 1737 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
1732 logit("Disabling protocol version 2. Could not load host key"); 1738 logit("Disabling protocol version 2. Could not load host key");
1733 options.protocol &= ~SSH_PROTO_2; 1739 options.protocol &= ~SSH_PROTO_2;
1734 } 1740 }
1741#endif
1735 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { 1742 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
1736 logit("sshd: no hostkeys available -- exiting."); 1743 logit("sshd: no hostkeys available -- exiting.");
1737 exit(1); 1744 exit(1);
@@ -2058,6 +2065,60 @@ main(int ac, char **av)
2058 remote_ip, remote_port, 2065 remote_ip, remote_port,
2059 get_local_ipaddr(sock_in), get_local_port()); 2066 get_local_ipaddr(sock_in), get_local_port());
2060 2067
2068#ifdef USE_SECURITY_SESSION_API
2069 /*
2070 * Create a new security session for use by the new user login if
2071 * the current session is the root session or we are not launched
2072 * by inetd (eg: debugging mode or server mode). We do not
2073 * necessarily need to create a session if we are launched from
2074 * inetd because Panther xinetd will create a session for us.
2075 *
2076 * The only case where this logic will fail is if there is an
2077 * inetd running in a non-root session which is not creating
2078 * new sessions for us. Then all the users will end up in the
2079 * same session (bad).
2080 *
2081 * When the client exits, the session will be destroyed for us
2082 * automatically.
2083 *
2084 * We must create the session before any credentials are stored
2085 * (including AFS pags, which happens a few lines below).
2086 */
2087 {
2088 OSStatus err = 0;
2089 SecuritySessionId sid = 0;
2090 SessionAttributeBits sattrs = 0;
2091
2092 err = SessionGetInfo(callerSecuritySession, &sid, &sattrs);
2093 if (err)
2094 error("SessionGetInfo() failed with error %.8X",
2095 (unsigned) err);
2096 else
2097 debug("Current Session ID is %.8X / Session Attributes are %.8X",
2098 (unsigned) sid, (unsigned) sattrs);
2099
2100 if (inetd_flag && !(sattrs & sessionIsRoot))
2101 debug("Running in inetd mode in a non-root session... "
2102 "assuming inetd created the session for us.");
2103 else {
2104 debug("Creating new security session...");
2105 err = SessionCreate(0, sessionHasTTY | sessionIsRemote);
2106 if (err)
2107 error("SessionCreate() failed with error %.8X",
2108 (unsigned) err);
2109
2110 err = SessionGetInfo(callerSecuritySession, &sid,
2111 &sattrs);
2112 if (err)
2113 error("SessionGetInfo() failed with error %.8X",
2114 (unsigned) err);
2115 else
2116 debug("New Session ID is %.8X / Session Attributes are %.8X",
2117 (unsigned) sid, (unsigned) sattrs);
2118 }
2119 }
2120#endif
2121
2061 /* 2122 /*
2062 * We don't want to listen forever unless the other side 2123 * We don't want to listen forever unless the other side
2063 * successfully authenticates itself. So we set up an alarm which is 2124 * successfully authenticates itself. So we set up an alarm which is
@@ -2469,6 +2530,48 @@ do_ssh2_kex(void)
2469 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( 2530 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal(
2470 list_hostkey_types()); 2531 list_hostkey_types());
2471 2532
2533#ifdef GSSAPI
2534 {
2535 char *orig;
2536 char *gss = NULL;
2537 char *newstr = NULL;
2538 orig = myproposal[PROPOSAL_KEX_ALGS];
2539
2540 /*
2541 * If we don't have a host key, then there's no point advertising
2542 * the other key exchange algorithms
2543 */
2544
2545 if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
2546 orig = NULL;
2547
2548 if (options.gss_keyex)
2549 gss = ssh_gssapi_server_mechanisms();
2550 else
2551 gss = NULL;
2552
2553 if (gss && orig)
2554 xasprintf(&newstr, "%s,%s", gss, orig);
2555 else if (gss)
2556 newstr = gss;
2557 else if (orig)
2558 newstr = orig;
2559
2560 /*
2561 * If we've got GSSAPI mechanisms, then we've got the 'null' host
2562 * key alg, but we can't tell people about it unless its the only
2563 * host key algorithm we support
2564 */
2565 if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
2566 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
2567
2568 if (newstr)
2569 myproposal[PROPOSAL_KEX_ALGS] = newstr;
2570 else
2571 fatal("No supported key exchange algorithms");
2572 }
2573#endif
2574
2472 /* start key exchange */ 2575 /* start key exchange */
2473 kex = kex_setup(myproposal); 2576 kex = kex_setup(myproposal);
2474 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; 2577 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
@@ -2477,6 +2580,13 @@ do_ssh2_kex(void)
2477 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 2580 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
2478 kex->kex[KEX_ECDH_SHA2] = kexecdh_server; 2581 kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
2479 kex->kex[KEX_C25519_SHA256] = kexc25519_server; 2582 kex->kex[KEX_C25519_SHA256] = kexc25519_server;
2583#ifdef GSSAPI
2584 if (options.gss_keyex) {
2585 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
2586 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
2587 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
2588 }
2589#endif
2480 kex->server = 1; 2590 kex->server = 1;
2481 kex->client_version_string=client_version_string; 2591 kex->client_version_string=client_version_string;
2482 kex->server_version_string=server_version_string; 2592 kex->server_version_string=server_version_string;
diff --git a/sshd_config b/sshd_config
index e9045bc4d..d9b859407 100644
--- a/sshd_config
+++ b/sshd_config
@@ -84,6 +84,8 @@ AuthorizedKeysFile .ssh/authorized_keys
84# GSSAPI options 84# GSSAPI options
85#GSSAPIAuthentication no 85#GSSAPIAuthentication no
86#GSSAPICleanupCredentials yes 86#GSSAPICleanupCredentials yes
87#GSSAPIStrictAcceptorCheck yes
88#GSSAPIKeyExchange no
87 89
88# Set this to 'yes' to enable PAM authentication, account processing, 90# Set this to 'yes' to enable PAM authentication, account processing,
89# and session processing. If this is enabled, PAM authentication will 91# and session processing. If this is enabled, PAM authentication will
diff --git a/sshd_config.5 b/sshd_config.5
index ce71efe3c..ceed88a1d 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -493,12 +493,40 @@ Specifies whether user authentication based on GSSAPI is allowed.
493The default is 493The default is
494.Dq no . 494.Dq no .
495Note that this option applies to protocol version 2 only. 495Note that this option applies to protocol version 2 only.
496.It Cm GSSAPIKeyExchange
497Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
498doesn't rely on ssh keys to verify host identity.
499The default is
500.Dq no .
501Note that this option applies to protocol version 2 only.
496.It Cm GSSAPICleanupCredentials 502.It Cm GSSAPICleanupCredentials
497Specifies whether to automatically destroy the user's credentials cache 503Specifies whether to automatically destroy the user's credentials cache
498on logout. 504on logout.
499The default is 505The default is
500.Dq yes . 506.Dq yes .
501Note that this option applies to protocol version 2 only. 507Note that this option applies to protocol version 2 only.
508.It Cm GSSAPIStrictAcceptorCheck
509Determines whether to be strict about the identity of the GSSAPI acceptor
510a client authenticates against. If
511.Dq yes
512then the client must authenticate against the
513.Pa host
514service on the current hostname. If
515.Dq no
516then the client may authenticate against any service key stored in the
517machine's default store. This facility is provided to assist with operation
518on multi homed machines.
519The default is
520.Dq yes .
521Note that this option applies only to protocol version 2 GSSAPI connections,
522and setting it to
523.Dq no
524may only work with recent Kerberos GSSAPI libraries.
525.It Cm GSSAPIStoreCredentialsOnRekey
526Controls whether the user's GSSAPI credentials should be updated following a
527successful connection rekeying. This option can be used to accepted renewed
528or updated credentials from a compatible client. The default is
529.Dq no .
502.It Cm HostbasedAuthentication 530.It Cm HostbasedAuthentication
503Specifies whether rhosts or /etc/hosts.equiv authentication together 531Specifies whether rhosts or /etc/hosts.equiv authentication together
504with successful public key client host authentication is allowed 532with successful public key client host authentication is allowed