summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Wilkinson <simon@sxw.org.uk>2014-02-09 16:09:48 +0000
committerColin Watson <cjwatson@debian.org>2014-02-09 16:16:58 +0000
commit950be7e1b1a01ee9b25e2a72726a6370b8acacb6 (patch)
tree64829a84f903d7e2d3270c43e3f80df7db2a6a10
parentee196dab7c5f97f0b80c8099343a375bead92010 (diff)
GSSAPI key exchange support
This patch has been rejected upstream: "None of the OpenSSH developers are in favour of adding this, and this situation has not changed for several years. This is not a slight on Simon's patch, which is of fine quality, but just that a) we don't trust GSSAPI implementations that much and b) we don't like adding new KEX since they are pre-auth attack surface. This one is particularly scary, since it requires hooks out to typically root-owned system resources." However, quite a lot of people rely on this in Debian, and it's better to have it merged into the main openssh package rather than having separate -krb5 packages (as we used to have). It seems to have a generally good security history. Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242 Last-Updated: 2013-11-09 Patch-Name: gssapi.patch
-rw-r--r--ChangeLog.gssapi113
-rw-r--r--Makefile.in3
-rw-r--r--auth-krb5.c17
-rw-r--r--auth2-gss.c48
-rw-r--r--auth2.c2
-rw-r--r--clientloop.c13
-rw-r--r--config.h.in6
-rwxr-xr-xconfigure57
-rw-r--r--configure.ac24
-rw-r--r--gss-genr.c276
-rw-r--r--gss-serv-krb5.c84
-rw-r--r--gss-serv.c221
-rw-r--r--kex.c16
-rw-r--r--kex.h14
-rw-r--r--kexgssc.c333
-rw-r--r--kexgsss.c289
-rw-r--r--key.c1
-rw-r--r--key.h1
-rw-r--r--monitor.c108
-rw-r--r--monitor.h3
-rw-r--r--monitor_wrap.c47
-rw-r--r--monitor_wrap.h4
-rw-r--r--readconf.c42
-rw-r--r--readconf.h5
-rw-r--r--servconf.c38
-rw-r--r--servconf.h3
-rw-r--r--ssh-gss.h39
-rw-r--r--ssh_config2
-rw-r--r--ssh_config.534
-rw-r--r--sshconnect2.c124
-rw-r--r--sshd.c110
-rw-r--r--sshd_config2
-rw-r--r--sshd_config.528
33 files changed, 2050 insertions, 57 deletions
diff --git a/ChangeLog.gssapi b/ChangeLog.gssapi
new file mode 100644
index 000000000..f117a336a
--- /dev/null
+++ b/ChangeLog.gssapi
@@ -0,0 +1,113 @@
120110101
2 - Finally update for OpenSSH 5.6p1
3 - Add GSSAPIServerIdentity option from Jim Basney
4
520100308
6 - [ Makefile.in, key.c, key.h ]
7 Updates for OpenSSH 5.4p1
8 - [ servconf.c ]
9 Include GSSAPI options in the sshd -T configuration dump, and flag
10 some older configuration options as being unsupported. Thanks to Colin
11 Watson.
12 -
13
1420100124
15 - [ sshconnect2.c ]
16 Adapt to deal with additional element in Authmethod structure. Thanks to
17 Colin Watson
18
1920090615
20 - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c
21 sshd.c ]
22 Fix issues identified by Greg Hudson following a code review
23 Check return value of gss_indicate_mechs
24 Protect GSSAPI calls in monitor, so they can only be used if enabled
25 Check return values of bignum functions in key exchange
26 Use BN_clear_free to clear other side's DH value
27 Make ssh_gssapi_id_kex more robust
28 Only configure kex table pointers if GSSAPI is enabled
29 Don't leak mechanism list, or gss mechanism list
30 Cast data.length before printing
31 If serverkey isn't provided, use an empty string, rather than NULL
32
3320090201
34 - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h
35 ssh_config.5 sshconnet2.c ]
36 Add support for the GSSAPIClientIdentity option, which allows the user
37 to specify which GSSAPI identity to use to contact a given server
38
3920080404
40 - [ gss-serv.c ]
41 Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow
42 been omitted from a previous version of this patch. Reported by Borislav
43 Stoichkov
44
4520070317
46 - [ gss-serv-krb5.c ]
47 Remove C99ism, where new_ccname was being declared in the middle of a
48 function
49
5020061220
51 - [ servconf.c ]
52 Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and
53 documented, behaviour. Reported by Dan Watson.
54
5520060910
56 - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c
57 ssh-gss.h ]
58 add support for gss-group14-sha1 key exchange mechanisms
59 - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ]
60 Add GSSAPIStrictAcceptorCheck option to allow the disabling of
61 acceptor principal checking on multi-homed machines.
62 <Bugzilla #928>
63 - [ sshd_config ssh_config ]
64 Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample
65 configuration files
66 - [ kexgss.c kegsss.c sshconnect2.c sshd.c ]
67 Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf()
68 Limit length of error messages displayed by client
69
7020060909
71 - [ gss-genr.c gss-serv.c ]
72 move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server
73 only, where they belong
74 <Bugzilla #1225>
75
7620060829
77 - [ gss-serv-krb5.c ]
78 Fix CCAPI credentials cache name when creating KRB5CCNAME environment
79 variable
80
8120060828
82 - [ gss-genr.c ]
83 Avoid Heimdal context freeing problem
84 <Fixed upstream 20060829>
85
8620060818
87 - [ gss-genr.c ssh-gss.h sshconnect2.c ]
88 Make sure that SPENGO is disabled
89 <Bugzilla #1218 - Fixed upstream 20060818>
90
9120060421
92 - [ gssgenr.c, sshconnect2.c ]
93 a few type changes (signed versus unsigned, int versus size_t) to
94 fix compiler errors/warnings
95 (from jbasney AT ncsa.uiuc.edu)
96 - [ kexgssc.c, sshconnect2.c ]
97 fix uninitialized variable warnings
98 (from jbasney AT ncsa.uiuc.edu)
99 - [ gssgenr.c ]
100 pass oid to gss_display_status (helpful when using GSSAPI mechglue)
101 (from jbasney AT ncsa.uiuc.edu)
102 <Bugzilla #1220 >
103 - [ gss-serv-krb5.c ]
104 #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H
105 (from jbasney AT ncsa.uiuc.edu)
106 <Fixed upstream 20060304>
107 - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c
108 add client-side GssapiKeyExchange option
109 (from jbasney AT ncsa.uiuc.edu)
110 - [ sshconnect2.c ]
111 add support for GssapiTrustDns option for gssapi-with-mic
112 (from jbasney AT ncsa.uiuc.edu)
113 <gssapi-with-mic support is Bugzilla #1008>
diff --git a/Makefile.in b/Makefile.in
index 92c95a928..f9799268a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -72,6 +72,7 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \
72 atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ 72 atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
73 monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ 73 monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
74 kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \ 74 kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \
75 kexgssc.o \
75 msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ 76 msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
76 jpake.o schnorr.o ssh-pkcs11.o krl.o 77 jpake.o schnorr.o ssh-pkcs11.o krl.o
77 78
@@ -88,7 +89,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
88 auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-jpake.o \ 89 auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-jpake.o \
89 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \ 90 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \
90 auth-krb5.o \ 91 auth-krb5.o \
91 auth2-gss.o gss-serv.o gss-serv-krb5.o \ 92 auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\
92 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ 93 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
93 sftp-server.o sftp-common.o \ 94 sftp-server.o sftp-common.o \
94 roaming_common.o roaming_serv.o \ 95 roaming_common.o roaming_serv.o \
diff --git a/auth-krb5.c b/auth-krb5.c
index 7c83f597f..5613b5772 100644
--- a/auth-krb5.c
+++ b/auth-krb5.c
@@ -181,8 +181,13 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
181 181
182 len = strlen(authctxt->krb5_ticket_file) + 6; 182 len = strlen(authctxt->krb5_ticket_file) + 6;
183 authctxt->krb5_ccname = xmalloc(len); 183 authctxt->krb5_ccname = xmalloc(len);
184#ifdef USE_CCAPI
185 snprintf(authctxt->krb5_ccname, len, "API:%s",
186 authctxt->krb5_ticket_file);
187#else
184 snprintf(authctxt->krb5_ccname, len, "FILE:%s", 188 snprintf(authctxt->krb5_ccname, len, "FILE:%s",
185 authctxt->krb5_ticket_file); 189 authctxt->krb5_ticket_file);
190#endif
186 191
187#ifdef USE_PAM 192#ifdef USE_PAM
188 if (options.use_pam) 193 if (options.use_pam)
@@ -239,15 +244,22 @@ krb5_cleanup_proc(Authctxt *authctxt)
239#ifndef HEIMDAL 244#ifndef HEIMDAL
240krb5_error_code 245krb5_error_code
241ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { 246ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
242 int tmpfd, ret, oerrno; 247 int ret, oerrno;
243 char ccname[40]; 248 char ccname[40];
244 mode_t old_umask; 249 mode_t old_umask;
250#ifdef USE_CCAPI
251 char cctemplate[] = "API:krb5cc_%d";
252#else
253 char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX";
254 int tmpfd;
255#endif
245 256
246 ret = snprintf(ccname, sizeof(ccname), 257 ret = snprintf(ccname, sizeof(ccname),
247 "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); 258 cctemplate, geteuid());
248 if (ret < 0 || (size_t)ret >= sizeof(ccname)) 259 if (ret < 0 || (size_t)ret >= sizeof(ccname))
249 return ENOMEM; 260 return ENOMEM;
250 261
262#ifndef USE_CCAPI
251 old_umask = umask(0177); 263 old_umask = umask(0177);
252 tmpfd = mkstemp(ccname + strlen("FILE:")); 264 tmpfd = mkstemp(ccname + strlen("FILE:"));
253 oerrno = errno; 265 oerrno = errno;
@@ -264,6 +276,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
264 return oerrno; 276 return oerrno;
265 } 277 }
266 close(tmpfd); 278 close(tmpfd);
279#endif
267 280
268 return (krb5_cc_resolve(ctx, ccname, ccache)); 281 return (krb5_cc_resolve(ctx, ccname, ccache));
269} 282}
diff --git a/auth2-gss.c b/auth2-gss.c
index 638d8f88e..b8db8204f 100644
--- a/auth2-gss.c
+++ b/auth2-gss.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: auth2-gss.c,v 1.20 2013/05/17 00:13:13 djm Exp $ */ 1/* $OpenBSD: auth2-gss.c,v 1.20 2013/05/17 00:13: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
@@ -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)
@@ -240,7 +274,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
240 274
241 packet_check_eom(); 275 packet_check_eom();
242 276
243 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); 277 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
278 authctxt->pw));
244 279
245 authctxt->postponed = 0; 280 authctxt->postponed = 0;
246 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 281 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
@@ -275,7 +310,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
275 gssbuf.length = buffer_len(&b); 310 gssbuf.length = buffer_len(&b);
276 311
277 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) 312 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
278 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); 313 authenticated =
314 PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
279 else 315 else
280 logit("GSSAPI MIC check failed"); 316 logit("GSSAPI MIC check failed");
281 317
@@ -290,6 +326,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
290 userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL); 326 userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
291} 327}
292 328
329Authmethod method_gsskeyex = {
330 "gssapi-keyex",
331 userauth_gsskeyex,
332 &options.gss_authentication
333};
334
293Authmethod method_gssapi = { 335Authmethod method_gssapi = {
294 "gssapi-with-mic", 336 "gssapi-with-mic",
295 userauth_gssapi, 337 userauth_gssapi,
diff --git a/auth2.c b/auth2.c
index f0cab8cc0..6ed8f042b 100644
--- a/auth2.c
+++ b/auth2.c
@@ -69,6 +69,7 @@ extern Authmethod method_passwd;
69extern Authmethod method_kbdint; 69extern Authmethod method_kbdint;
70extern Authmethod method_hostbased; 70extern Authmethod method_hostbased;
71#ifdef GSSAPI 71#ifdef GSSAPI
72extern Authmethod method_gsskeyex;
72extern Authmethod method_gssapi; 73extern Authmethod method_gssapi;
73#endif 74#endif
74#ifdef JPAKE 75#ifdef JPAKE
@@ -79,6 +80,7 @@ Authmethod *authmethods[] = {
79 &method_none, 80 &method_none,
80 &method_pubkey, 81 &method_pubkey,
81#ifdef GSSAPI 82#ifdef GSSAPI
83 &method_gsskeyex,
82 &method_gssapi, 84 &method_gssapi,
83#endif 85#endif
84#ifdef JPAKE 86#ifdef JPAKE
diff --git a/clientloop.c b/clientloop.c
index 23c2f2396..311dc1393 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(GSS_C_NO_CONTEXT)) {
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 b75e501b2..34f1c9c53 100644
--- a/config.h.in
+++ b/config.h.in
@@ -1546,6 +1546,9 @@
1546/* Use btmp to log bad logins */ 1546/* Use btmp to log bad logins */
1547#undef USE_BTMP 1547#undef USE_BTMP
1548 1548
1549/* platform uses an in-memory credentials cache */
1550#undef USE_CCAPI
1551
1549/* Use libedit for sftp */ 1552/* Use libedit for sftp */
1550#undef USE_LIBEDIT 1553#undef USE_LIBEDIT
1551 1554
@@ -1561,6 +1564,9 @@
1561/* Use PIPES instead of a socketpair() */ 1564/* Use PIPES instead of a socketpair() */
1562#undef USE_PIPES 1565#undef USE_PIPES
1563 1566
1567/* platform has the Security Authorization Session API */
1568#undef USE_SECURITY_SESSION_API
1569
1564/* Define if you have Solaris process contracts */ 1570/* Define if you have Solaris process contracts */
1565#undef USE_SOLARIS_PROCESS_CONTRACTS 1571#undef USE_SOLARIS_PROCESS_CONTRACTS
1566 1572
diff --git a/configure b/configure
index 0d6fad5f4..ceb1b5d6d 100755
--- a/configure
+++ b/configure
@@ -6780,6 +6780,63 @@ $as_echo "#define SSH_TUN_COMPAT_AF 1" >>confdefs.h
6780 6780
6781$as_echo "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h 6781$as_echo "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h
6782 6782
6783 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have the Security Authorization Session API" >&5
6784$as_echo_n "checking if we have the Security Authorization Session API... " >&6; }
6785 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
6786/* end confdefs.h. */
6787#include <Security/AuthSession.h>
6788int
6789main ()
6790{
6791SessionCreate(0, 0);
6792 ;
6793 return 0;
6794}
6795_ACEOF
6796if ac_fn_c_try_compile "$LINENO"; then :
6797 ac_cv_use_security_session_api="yes"
6798
6799$as_echo "#define USE_SECURITY_SESSION_API 1" >>confdefs.h
6800
6801 LIBS="$LIBS -framework Security"
6802 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
6803$as_echo "yes" >&6; }
6804else
6805 ac_cv_use_security_session_api="no"
6806 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
6807$as_echo "no" >&6; }
6808fi
6809rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
6810 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have an in-memory credentials cache" >&5
6811$as_echo_n "checking if we have an in-memory credentials cache... " >&6; }
6812 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
6813/* end confdefs.h. */
6814#include <Kerberos/Kerberos.h>
6815int
6816main ()
6817{
6818cc_context_t c;
6819 (void) cc_initialize (&c, 0, NULL, NULL);
6820 ;
6821 return 0;
6822}
6823_ACEOF
6824if ac_fn_c_try_compile "$LINENO"; then :
6825
6826$as_echo "#define USE_CCAPI 1" >>confdefs.h
6827
6828 LIBS="$LIBS -framework Security"
6829 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
6830$as_echo "yes" >&6; }
6831 if test "x$ac_cv_use_security_session_api" = "xno"; then
6832 as_fn_error $? "*** Need a security framework to use the credentials cache API ***" "$LINENO" 5
6833 fi
6834else
6835 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
6836$as_echo "no" >&6; }
6837
6838fi
6839rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
6783 6840
6784 ac_fn_c_check_decl "$LINENO" "AU_IPv4" "ac_cv_have_decl_AU_IPv4" "$ac_includes_default" 6841 ac_fn_c_check_decl "$LINENO" "AU_IPv4" "ac_cv_have_decl_AU_IPv4" "$ac_includes_default"
6785if test "x$ac_cv_have_decl_AU_IPv4" = xyes; then : 6842if test "x$ac_cv_have_decl_AU_IPv4" = xyes; then :
diff --git a/configure.ac b/configure.ac
index 4a1b50331..4c1a6589e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -548,6 +548,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
548 [Use tunnel device compatibility to OpenBSD]) 548 [Use tunnel device compatibility to OpenBSD])
549 AC_DEFINE([SSH_TUN_PREPEND_AF], [1], 549 AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
550 [Prepend the address family to IP tunnel traffic]) 550 [Prepend the address family to IP tunnel traffic])
551 AC_MSG_CHECKING([if we have the Security Authorization Session API])
552 AC_TRY_COMPILE([#include <Security/AuthSession.h>],
553 [SessionCreate(0, 0);],
554 [ac_cv_use_security_session_api="yes"
555 AC_DEFINE([USE_SECURITY_SESSION_API], [1],
556 [platform has the Security Authorization Session API])
557 LIBS="$LIBS -framework Security"
558 AC_MSG_RESULT([yes])],
559 [ac_cv_use_security_session_api="no"
560 AC_MSG_RESULT([no])])
561 AC_MSG_CHECKING([if we have an in-memory credentials cache])
562 AC_TRY_COMPILE(
563 [#include <Kerberos/Kerberos.h>],
564 [cc_context_t c;
565 (void) cc_initialize (&c, 0, NULL, NULL);],
566 [AC_DEFINE([USE_CCAPI], [1],
567 [platform uses an in-memory credentials cache])
568 LIBS="$LIBS -framework Security"
569 AC_MSG_RESULT([yes])
570 if test "x$ac_cv_use_security_session_api" = "xno"; then
571 AC_MSG_ERROR([*** Need a security framework to use the credentials cache API ***])
572 fi],
573 [AC_MSG_RESULT([no])]
574 )
551 m4_pattern_allow([AU_IPv]) 575 m4_pattern_allow([AU_IPv])
552 AC_CHECK_DECL([AU_IPv4], [], 576 AC_CHECK_DECL([AU_IPv4], [],
553 AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records]) 577 AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records])
diff --git a/gss-genr.c b/gss-genr.c
index b39281bc1..b7d1b7dbf 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() {
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,67 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
272 GSS_C_NO_BUFFER); 483 GSS_C_NO_BUFFER);
273 } 484 }
274 485
275 if (GSS_ERROR(major)) 486 if (GSS_ERROR(major) || intctx != NULL)
276 ssh_gssapi_delete_ctx(ctx); 487 ssh_gssapi_delete_ctx(ctx);
277 488
278 return (!GSS_ERROR(major)); 489 return (!GSS_ERROR(major));
279} 490}
280 491
492int
493ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
494 static gss_name_t saved_name = GSS_C_NO_NAME;
495 static OM_uint32 saved_lifetime = 0;
496 static gss_OID saved_mech = GSS_C_NO_OID;
497 static gss_name_t name;
498 static OM_uint32 last_call = 0;
499 OM_uint32 lifetime, now, major, minor;
500 int equal;
501 gss_cred_usage_t usage = GSS_C_INITIATE;
502
503 now = time(NULL);
504
505 if (ctxt) {
506 debug("Rekey has happened - updating saved versions");
507
508 if (saved_name != GSS_C_NO_NAME)
509 gss_release_name(&minor, &saved_name);
510
511 major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
512 &saved_name, &saved_lifetime, NULL, NULL);
513
514 if (!GSS_ERROR(major)) {
515 saved_mech = ctxt->oid;
516 saved_lifetime+= now;
517 } else {
518 /* Handle the error */
519 }
520 return 0;
521 }
522
523 if (now - last_call < 10)
524 return 0;
525
526 last_call = now;
527
528 if (saved_mech == GSS_C_NO_OID)
529 return 0;
530
531 major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
532 &name, &lifetime, NULL, NULL);
533 if (major == GSS_S_CREDENTIALS_EXPIRED)
534 return 0;
535 else if (GSS_ERROR(major))
536 return 0;
537
538 major = gss_compare_name(&minor, saved_name, name, &equal);
539 gss_release_name(&minor, &name);
540 if (GSS_ERROR(major))
541 return 0;
542
543 if (equal && (saved_lifetime < lifetime + now - 10))
544 return 1;
545
546 return 0;
547}
548
281#endif /* GSSAPI */ 549#endif /* GSSAPI */
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
index 87f26831a..c55446a0b 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
@@ -122,6 +122,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
122 OM_uint32 maj_status, min_status; 122 OM_uint32 maj_status, min_status;
123 int len; 123 int len;
124 const char *errmsg; 124 const char *errmsg;
125 const char *new_ccname;
125 126
126 if (client->creds == NULL) { 127 if (client->creds == NULL) {
127 debug("No credentials stored"); 128 debug("No credentials stored");
@@ -174,11 +175,16 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
174 return; 175 return;
175 } 176 }
176 177
177 client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); 178 new_ccname = krb5_cc_get_name(krb_context, ccache);
179
178 client->store.envvar = "KRB5CCNAME"; 180 client->store.envvar = "KRB5CCNAME";
179 len = strlen(client->store.filename) + 6; 181#ifdef USE_CCAPI
180 client->store.envval = xmalloc(len); 182 xasprintf(&client->store.envval, "API:%s", new_ccname);
181 snprintf(client->store.envval, len, "FILE:%s", client->store.filename); 183 client->store.filename = NULL;
184#else
185 xasprintf(&client->store.envval, "FILE:%s", new_ccname);
186 client->store.filename = xstrdup(new_ccname);
187#endif
182 188
183#ifdef USE_PAM 189#ifdef USE_PAM
184 if (options.use_pam) 190 if (options.use_pam)
@@ -190,6 +196,71 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
190 return; 196 return;
191} 197}
192 198
199int
200ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store,
201 ssh_gssapi_client *client)
202{
203 krb5_ccache ccache = NULL;
204 krb5_principal principal = NULL;
205 char *name = NULL;
206 krb5_error_code problem;
207 OM_uint32 maj_status, min_status;
208
209 if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) {
210 logit("krb5_cc_resolve(): %.100s",
211 krb5_get_err_text(krb_context, problem));
212 return 0;
213 }
214
215 /* Find out who the principal in this cache is */
216 if ((problem = krb5_cc_get_principal(krb_context, ccache,
217 &principal))) {
218 logit("krb5_cc_get_principal(): %.100s",
219 krb5_get_err_text(krb_context, problem));
220 krb5_cc_close(krb_context, ccache);
221 return 0;
222 }
223
224 if ((problem = krb5_unparse_name(krb_context, principal, &name))) {
225 logit("krb5_unparse_name(): %.100s",
226 krb5_get_err_text(krb_context, problem));
227 krb5_free_principal(krb_context, principal);
228 krb5_cc_close(krb_context, ccache);
229 return 0;
230 }
231
232
233 if (strcmp(name,client->exportedname.value)!=0) {
234 debug("Name in local credentials cache differs. Not storing");
235 krb5_free_principal(krb_context, principal);
236 krb5_cc_close(krb_context, ccache);
237 krb5_free_unparsed_name(krb_context, name);
238 return 0;
239 }
240 krb5_free_unparsed_name(krb_context, name);
241
242 /* Name matches, so lets get on with it! */
243
244 if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) {
245 logit("krb5_cc_initialize(): %.100s",
246 krb5_get_err_text(krb_context, problem));
247 krb5_free_principal(krb_context, principal);
248 krb5_cc_close(krb_context, ccache);
249 return 0;
250 }
251
252 krb5_free_principal(krb_context, principal);
253
254 if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds,
255 ccache))) {
256 logit("gss_krb5_copy_ccache() failed. Sorry!");
257 krb5_cc_close(krb_context, ccache);
258 return 0;
259 }
260
261 return 1;
262}
263
193ssh_gssapi_mech gssapi_kerberos_mech = { 264ssh_gssapi_mech gssapi_kerberos_mech = {
194 "toWM5Slw5Ew8Mqkay+al2g==", 265 "toWM5Slw5Ew8Mqkay+al2g==",
195 "Kerberos", 266 "Kerberos",
@@ -197,7 +268,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = {
197 NULL, 268 NULL,
198 &ssh_gssapi_krb5_userok, 269 &ssh_gssapi_krb5_userok,
199 NULL, 270 NULL,
200 &ssh_gssapi_krb5_storecreds 271 &ssh_gssapi_krb5_storecreds,
272 &ssh_gssapi_krb5_updatecreds
201}; 273};
202 274
203#endif /* KRB5 */ 275#endif /* KRB5 */
diff --git a/gss-serv.c b/gss-serv.c
index 95348e251..97f366fdf 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-serv.c,v 1.24 2013/07/20 01:55:13 djm Exp $ */ 1/* $OpenBSD: gss-serv.c,v 1.24 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-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;
@@ -81,25 +87,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx)
81 char lname[MAXHOSTNAMELEN]; 87 char lname[MAXHOSTNAMELEN];
82 gss_OID_set oidset; 88 gss_OID_set oidset;
83 89
84 gss_create_empty_oid_set(&status, &oidset); 90 if (options.gss_strict_acceptor) {
85 gss_add_oid_set_member(&status, ctx->oid, &oidset); 91 gss_create_empty_oid_set(&status, &oidset);
92 gss_add_oid_set_member(&status, ctx->oid, &oidset);
86 93
87 if (gethostname(lname, MAXHOSTNAMELEN)) { 94 if (gethostname(lname, MAXHOSTNAMELEN)) {
88 gss_release_oid_set(&status, &oidset); 95 gss_release_oid_set(&status, &oidset);
89 return (-1); 96 return (-1);
90 } 97 }
98
99 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
100 gss_release_oid_set(&status, &oidset);
101 return (ctx->major);
102 }
103
104 if ((ctx->major = gss_acquire_cred(&ctx->minor,
105 ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds,
106 NULL, NULL)))
107 ssh_gssapi_error(ctx);
91 108
92 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
93 gss_release_oid_set(&status, &oidset); 109 gss_release_oid_set(&status, &oidset);
94 return (ctx->major); 110 return (ctx->major);
111 } else {
112 ctx->name = GSS_C_NO_NAME;
113 ctx->creds = GSS_C_NO_CREDENTIAL;
95 } 114 }
96 115 return GSS_S_COMPLETE;
97 if ((ctx->major = gss_acquire_cred(&ctx->minor,
98 ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
99 ssh_gssapi_error(ctx);
100
101 gss_release_oid_set(&status, &oidset);
102 return (ctx->major);
103} 116}
104 117
105/* Privileged */ 118/* Privileged */
@@ -114,6 +127,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
114} 127}
115 128
116/* Unprivileged */ 129/* Unprivileged */
130char *
131ssh_gssapi_server_mechanisms() {
132 gss_OID_set supported;
133
134 ssh_gssapi_supported_oids(&supported);
135 return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
136 NULL, NULL));
137}
138
139/* Unprivileged */
140int
141ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
142 const char *dummy) {
143 Gssctxt *ctx = NULL;
144 int res;
145
146 res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
147 ssh_gssapi_delete_ctx(&ctx);
148
149 return (res);
150}
151
152/* Unprivileged */
117void 153void
118ssh_gssapi_supported_oids(gss_OID_set *oidset) 154ssh_gssapi_supported_oids(gss_OID_set *oidset)
119{ 155{
@@ -123,7 +159,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset)
123 gss_OID_set supported; 159 gss_OID_set supported;
124 160
125 gss_create_empty_oid_set(&min_status, oidset); 161 gss_create_empty_oid_set(&min_status, oidset);
126 gss_indicate_mechs(&min_status, &supported); 162
163 if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
164 return;
127 165
128 while (supported_mechs[i]->name != NULL) { 166 while (supported_mechs[i]->name != NULL) {
129 if (GSS_ERROR(gss_test_oid_set_member(&min_status, 167 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
@@ -249,8 +287,48 @@ OM_uint32
249ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 287ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
250{ 288{
251 int i = 0; 289 int i = 0;
290 int equal = 0;
291 gss_name_t new_name = GSS_C_NO_NAME;
292 gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
293
294 if (options.gss_store_rekey && client->used && ctx->client_creds) {
295 if (client->mech->oid.length != ctx->oid->length ||
296 (memcmp(client->mech->oid.elements,
297 ctx->oid->elements, ctx->oid->length) !=0)) {
298 debug("Rekeyed credentials have different mechanism");
299 return GSS_S_COMPLETE;
300 }
301
302 if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
303 ctx->client_creds, ctx->oid, &new_name,
304 NULL, NULL, NULL))) {
305 ssh_gssapi_error(ctx);
306 return (ctx->major);
307 }
308
309 ctx->major = gss_compare_name(&ctx->minor, client->name,
310 new_name, &equal);
252 311
253 gss_buffer_desc ename; 312 if (GSS_ERROR(ctx->major)) {
313 ssh_gssapi_error(ctx);
314 return (ctx->major);
315 }
316
317 if (!equal) {
318 debug("Rekeyed credentials have different name");
319 return GSS_S_COMPLETE;
320 }
321
322 debug("Marking rekeyed credentials for export");
323
324 gss_release_name(&ctx->minor, &client->name);
325 gss_release_cred(&ctx->minor, &client->creds);
326 client->name = new_name;
327 client->creds = ctx->client_creds;
328 ctx->client_creds = GSS_C_NO_CREDENTIAL;
329 client->updated = 1;
330 return GSS_S_COMPLETE;
331 }
254 332
255 client->mech = NULL; 333 client->mech = NULL;
256 334
@@ -265,6 +343,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
265 if (client->mech == NULL) 343 if (client->mech == NULL)
266 return GSS_S_FAILURE; 344 return GSS_S_FAILURE;
267 345
346 if (ctx->client_creds &&
347 (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
348 ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
349 ssh_gssapi_error(ctx);
350 return (ctx->major);
351 }
352
268 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, 353 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
269 &client->displayname, NULL))) { 354 &client->displayname, NULL))) {
270 ssh_gssapi_error(ctx); 355 ssh_gssapi_error(ctx);
@@ -282,6 +367,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
282 return (ctx->major); 367 return (ctx->major);
283 } 368 }
284 369
370 gss_release_buffer(&ctx->minor, &ename);
371
285 /* We can't copy this structure, so we just move the pointer to it */ 372 /* We can't copy this structure, so we just move the pointer to it */
286 client->creds = ctx->client_creds; 373 client->creds = ctx->client_creds;
287 ctx->client_creds = GSS_C_NO_CREDENTIAL; 374 ctx->client_creds = GSS_C_NO_CREDENTIAL;
@@ -329,7 +416,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep)
329 416
330/* Privileged */ 417/* Privileged */
331int 418int
332ssh_gssapi_userok(char *user) 419ssh_gssapi_userok(char *user, struct passwd *pw)
333{ 420{
334 OM_uint32 lmin; 421 OM_uint32 lmin;
335 422
@@ -339,9 +426,11 @@ ssh_gssapi_userok(char *user)
339 return 0; 426 return 0;
340 } 427 }
341 if (gssapi_client.mech && gssapi_client.mech->userok) 428 if (gssapi_client.mech && gssapi_client.mech->userok)
342 if ((*gssapi_client.mech->userok)(&gssapi_client, user)) 429 if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
430 gssapi_client.used = 1;
431 gssapi_client.store.owner = pw;
343 return 1; 432 return 1;
344 else { 433 } else {
345 /* Destroy delegated credentials if userok fails */ 434 /* Destroy delegated credentials if userok fails */
346 gss_release_buffer(&lmin, &gssapi_client.displayname); 435 gss_release_buffer(&lmin, &gssapi_client.displayname);
347 gss_release_buffer(&lmin, &gssapi_client.exportedname); 436 gss_release_buffer(&lmin, &gssapi_client.exportedname);
@@ -354,14 +443,90 @@ ssh_gssapi_userok(char *user)
354 return (0); 443 return (0);
355} 444}
356 445
357/* Privileged */ 446/* These bits are only used for rekeying. The unpriviledged child is running
358OM_uint32 447 * as the user, the monitor is root.
359ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) 448 *
449 * In the child, we want to :
450 * *) Ask the monitor to store our credentials into the store we specify
451 * *) If it succeeds, maybe do a PAM update
452 */
453
454/* Stuff for PAM */
455
456#ifdef USE_PAM
457static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg,
458 struct pam_response **resp, void *data)
360{ 459{
361 ctx->major = gss_verify_mic(&ctx->minor, ctx->context, 460 return (PAM_CONV_ERR);
362 gssbuf, gssmic, NULL); 461}
462#endif
363 463
364 return (ctx->major); 464void
465ssh_gssapi_rekey_creds() {
466 int ok;
467 int ret;
468#ifdef USE_PAM
469 pam_handle_t *pamh = NULL;
470 struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
471 char *envstr;
472#endif
473
474 if (gssapi_client.store.filename == NULL &&
475 gssapi_client.store.envval == NULL &&
476 gssapi_client.store.envvar == NULL)
477 return;
478
479 ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
480
481 if (!ok)
482 return;
483
484 debug("Rekeyed credentials stored successfully");
485
486 /* Actually managing to play with the ssh pam stack from here will
487 * be next to impossible. In any case, we may want different options
488 * for rekeying. So, use our own :)
489 */
490#ifdef USE_PAM
491 if (!use_privsep) {
492 debug("Not even going to try and do PAM with privsep disabled");
493 return;
494 }
495
496 ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
497 &pamconv, &pamh);
498 if (ret)
499 return;
500
501 xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar,
502 gssapi_client.store.envval);
503
504 ret = pam_putenv(pamh, envstr);
505 if (!ret)
506 pam_setcred(pamh, PAM_REINITIALIZE_CRED);
507 pam_end(pamh, PAM_SUCCESS);
508#endif
509}
510
511int
512ssh_gssapi_update_creds(ssh_gssapi_ccache *store) {
513 int ok = 0;
514
515 /* Check we've got credentials to store */
516 if (!gssapi_client.updated)
517 return 0;
518
519 gssapi_client.updated = 0;
520
521 temporarily_use_uid(gssapi_client.store.owner);
522 if (gssapi_client.mech && gssapi_client.mech->updatecreds)
523 ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client);
524 else
525 debug("No update function for this mechanism");
526
527 restore_uid();
528
529 return ok;
365} 530}
366 531
367#endif 532#endif
diff --git a/kex.c b/kex.c
index 54bd1a438..1ec278245 100644
--- a/kex.c
+++ b/kex.c
@@ -50,6 +50,10 @@
50#include "monitor.h" 50#include "monitor.h"
51#include "roaming.h" 51#include "roaming.h"
52 52
53#ifdef GSSAPI
54#include "ssh-gss.h"
55#endif
56
53#if OPENSSL_VERSION_NUMBER >= 0x00907000L 57#if OPENSSL_VERSION_NUMBER >= 0x00907000L
54# if defined(HAVE_EVP_SHA256) 58# if defined(HAVE_EVP_SHA256)
55# define evp_ssh_sha256 EVP_sha256 59# define evp_ssh_sha256 EVP_sha256
@@ -82,6 +86,14 @@ static const struct kexalg kexalgs[] = {
82#endif 86#endif
83 { NULL, -1, -1, NULL}, 87 { NULL, -1, -1, NULL},
84}; 88};
89static const struct kexalg kexalg_prefixes[] = {
90#ifdef GSSAPI
91 { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, EVP_sha1 },
92 { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, EVP_sha1 },
93 { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, EVP_sha1 },
94#endif
95 { NULL, -1, -1, NULL },
96};
85 97
86char * 98char *
87kex_alg_list(void) 99kex_alg_list(void)
@@ -110,6 +122,10 @@ kex_alg_by_name(const char *name)
110 if (strcmp(k->name, name) == 0) 122 if (strcmp(k->name, name) == 0)
111 return k; 123 return k;
112 } 124 }
125 for (k = kexalg_prefixes; k->name != NULL; k++) {
126 if (strncmp(k->name, name, strlen(k->name)) == 0)
127 return k;
128 }
113 return NULL; 129 return NULL;
114} 130}
115 131
diff --git a/kex.h b/kex.h
index 9f1e1adb3..d5046c627 100644
--- a/kex.h
+++ b/kex.h
@@ -74,6 +74,9 @@ enum kex_exchange {
74 KEX_DH_GEX_SHA1, 74 KEX_DH_GEX_SHA1,
75 KEX_DH_GEX_SHA256, 75 KEX_DH_GEX_SHA256,
76 KEX_ECDH_SHA2, 76 KEX_ECDH_SHA2,
77 KEX_GSS_GRP1_SHA1,
78 KEX_GSS_GRP14_SHA1,
79 KEX_GSS_GEX_SHA1,
77 KEX_MAX 80 KEX_MAX
78}; 81};
79 82
@@ -133,6 +136,12 @@ struct Kex {
133 int flags; 136 int flags;
134 const EVP_MD *evp_md; 137 const EVP_MD *evp_md;
135 int ec_nid; 138 int ec_nid;
139#ifdef GSSAPI
140 int gss_deleg_creds;
141 int gss_trust_dns;
142 char *gss_host;
143 char *gss_client;
144#endif
136 char *client_version_string; 145 char *client_version_string;
137 char *server_version_string; 146 char *server_version_string;
138 int (*verify_host_key)(Key *); 147 int (*verify_host_key)(Key *);
@@ -162,6 +171,11 @@ void kexgex_server(Kex *);
162void kexecdh_client(Kex *); 171void kexecdh_client(Kex *);
163void kexecdh_server(Kex *); 172void kexecdh_server(Kex *);
164 173
174#ifdef GSSAPI
175void kexgss_client(Kex *);
176void kexgss_server(Kex *);
177#endif
178
165void 179void
166kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, 180kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
167 BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); 181 BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *);
diff --git a/kexgssc.c b/kexgssc.c
new file mode 100644
index 000000000..616893c7e
--- /dev/null
+++ b/kexgssc.c
@@ -0,0 +1,333 @@
1/*
2 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
26
27#ifdef GSSAPI
28
29#include "includes.h"
30
31#include <openssl/crypto.h>
32#include <openssl/bn.h>
33
34#include <string.h>
35
36#include "xmalloc.h"
37#include "buffer.h"
38#include "ssh2.h"
39#include "key.h"
40#include "cipher.h"
41#include "kex.h"
42#include "log.h"
43#include "packet.h"
44#include "dh.h"
45
46#include "ssh-gss.h"
47
48void
49kexgss_client(Kex *kex) {
50 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
51 gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
52 Gssctxt *ctxt;
53 OM_uint32 maj_status, min_status, ret_flags;
54 u_int klen, kout, slen = 0, hashlen, strlen;
55 DH *dh;
56 BIGNUM *dh_server_pub = NULL;
57 BIGNUM *shared_secret = NULL;
58 BIGNUM *p = NULL;
59 BIGNUM *g = NULL;
60 u_char *kbuf, *hash;
61 u_char *serverhostkey = NULL;
62 u_char *empty = "";
63 char *msg;
64 char *lang;
65 int type = 0;
66 int first = 1;
67 int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
68
69 /* Initialise our GSSAPI world */
70 ssh_gssapi_build_ctx(&ctxt);
71 if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type)
72 == GSS_C_NO_OID)
73 fatal("Couldn't identify host exchange");
74
75 if (ssh_gssapi_import_name(ctxt, kex->gss_host))
76 fatal("Couldn't import hostname");
77
78 if (kex->gss_client &&
79 ssh_gssapi_client_identity(ctxt, kex->gss_client))
80 fatal("Couldn't acquire client credentials");
81
82 switch (kex->kex_type) {
83 case KEX_GSS_GRP1_SHA1:
84 dh = dh_new_group1();
85 break;
86 case KEX_GSS_GRP14_SHA1:
87 dh = dh_new_group14();
88 break;
89 case KEX_GSS_GEX_SHA1:
90 debug("Doing group exchange\n");
91 nbits = dh_estimate(kex->we_need * 8);
92 packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
93 packet_put_int(min);
94 packet_put_int(nbits);
95 packet_put_int(max);
96
97 packet_send();
98
99 packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
100
101 if ((p = BN_new()) == NULL)
102 fatal("BN_new() failed");
103 packet_get_bignum2(p);
104 if ((g = BN_new()) == NULL)
105 fatal("BN_new() failed");
106 packet_get_bignum2(g);
107 packet_check_eom();
108
109 if (BN_num_bits(p) < min || BN_num_bits(p) > max)
110 fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
111 min, BN_num_bits(p), max);
112
113 dh = dh_new_group(g, p);
114 break;
115 default:
116 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
117 }
118
119 /* Step 1 - e is dh->pub_key */
120 dh_gen_key(dh, kex->we_need * 8);
121
122 /* This is f, we initialise it now to make life easier */
123 dh_server_pub = BN_new();
124 if (dh_server_pub == NULL)
125 fatal("dh_server_pub == NULL");
126
127 token_ptr = GSS_C_NO_BUFFER;
128
129 do {
130 debug("Calling gss_init_sec_context");
131
132 maj_status = ssh_gssapi_init_ctx(ctxt,
133 kex->gss_deleg_creds, token_ptr, &send_tok,
134 &ret_flags);
135
136 if (GSS_ERROR(maj_status)) {
137 if (send_tok.length != 0) {
138 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
139 packet_put_string(send_tok.value,
140 send_tok.length);
141 }
142 fatal("gss_init_context failed");
143 }
144
145 /* If we've got an old receive buffer get rid of it */
146 if (token_ptr != GSS_C_NO_BUFFER)
147 free(recv_tok.value);
148
149 if (maj_status == GSS_S_COMPLETE) {
150 /* If mutual state flag is not true, kex fails */
151 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
152 fatal("Mutual authentication failed");
153
154 /* If integ avail flag is not true kex fails */
155 if (!(ret_flags & GSS_C_INTEG_FLAG))
156 fatal("Integrity check failed");
157 }
158
159 /*
160 * If we have data to send, then the last message that we
161 * received cannot have been a 'complete'.
162 */
163 if (send_tok.length != 0) {
164 if (first) {
165 packet_start(SSH2_MSG_KEXGSS_INIT);
166 packet_put_string(send_tok.value,
167 send_tok.length);
168 packet_put_bignum2(dh->pub_key);
169 first = 0;
170 } else {
171 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
172 packet_put_string(send_tok.value,
173 send_tok.length);
174 }
175 packet_send();
176 gss_release_buffer(&min_status, &send_tok);
177
178 /* If we've sent them data, they should reply */
179 do {
180 type = packet_read();
181 if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
182 debug("Received KEXGSS_HOSTKEY");
183 if (serverhostkey)
184 fatal("Server host key received more than once");
185 serverhostkey =
186 packet_get_string(&slen);
187 }
188 } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
189
190 switch (type) {
191 case SSH2_MSG_KEXGSS_CONTINUE:
192 debug("Received GSSAPI_CONTINUE");
193 if (maj_status == GSS_S_COMPLETE)
194 fatal("GSSAPI Continue received from server when complete");
195 recv_tok.value = packet_get_string(&strlen);
196 recv_tok.length = strlen;
197 break;
198 case SSH2_MSG_KEXGSS_COMPLETE:
199 debug("Received GSSAPI_COMPLETE");
200 packet_get_bignum2(dh_server_pub);
201 msg_tok.value = packet_get_string(&strlen);
202 msg_tok.length = strlen;
203
204 /* Is there a token included? */
205 if (packet_get_char()) {
206 recv_tok.value=
207 packet_get_string(&strlen);
208 recv_tok.length = strlen;
209 /* If we're already complete - protocol error */
210 if (maj_status == GSS_S_COMPLETE)
211 packet_disconnect("Protocol error: received token when complete");
212 } else {
213 /* No token included */
214 if (maj_status != GSS_S_COMPLETE)
215 packet_disconnect("Protocol error: did not receive final token");
216 }
217 break;
218 case SSH2_MSG_KEXGSS_ERROR:
219 debug("Received Error");
220 maj_status = packet_get_int();
221 min_status = packet_get_int();
222 msg = packet_get_string(NULL);
223 lang = packet_get_string(NULL);
224 fatal("GSSAPI Error: \n%.400s",msg);
225 default:
226 packet_disconnect("Protocol error: didn't expect packet type %d",
227 type);
228 }
229 token_ptr = &recv_tok;
230 } else {
231 /* No data, and not complete */
232 if (maj_status != GSS_S_COMPLETE)
233 fatal("Not complete, and no token output");
234 }
235 } while (maj_status & GSS_S_CONTINUE_NEEDED);
236
237 /*
238 * We _must_ have received a COMPLETE message in reply from the
239 * server, which will have set dh_server_pub and msg_tok
240 */
241
242 if (type != SSH2_MSG_KEXGSS_COMPLETE)
243 fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
244
245 /* Check f in range [1, p-1] */
246 if (!dh_pub_is_valid(dh, dh_server_pub))
247 packet_disconnect("bad server public DH value");
248
249 /* compute K=f^x mod p */
250 klen = DH_size(dh);
251 kbuf = xmalloc(klen);
252 kout = DH_compute_key(kbuf, dh_server_pub, dh);
253 if (kout < 0)
254 fatal("DH_compute_key: failed");
255
256 shared_secret = BN_new();
257 if (shared_secret == NULL)
258 fatal("kexgss_client: BN_new failed");
259
260 if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
261 fatal("kexdh_client: BN_bin2bn failed");
262
263 memset(kbuf, 0, klen);
264 free(kbuf);
265
266 switch (kex->kex_type) {
267 case KEX_GSS_GRP1_SHA1:
268 case KEX_GSS_GRP14_SHA1:
269 kex_dh_hash( kex->client_version_string,
270 kex->server_version_string,
271 buffer_ptr(&kex->my), buffer_len(&kex->my),
272 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
273 (serverhostkey ? serverhostkey : empty), slen,
274 dh->pub_key, /* e */
275 dh_server_pub, /* f */
276 shared_secret, /* K */
277 &hash, &hashlen
278 );
279 break;
280 case KEX_GSS_GEX_SHA1:
281 kexgex_hash(
282 kex->evp_md,
283 kex->client_version_string,
284 kex->server_version_string,
285 buffer_ptr(&kex->my), buffer_len(&kex->my),
286 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
287 (serverhostkey ? serverhostkey : empty), slen,
288 min, nbits, max,
289 dh->p, dh->g,
290 dh->pub_key,
291 dh_server_pub,
292 shared_secret,
293 &hash, &hashlen
294 );
295 break;
296 default:
297 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
298 }
299
300 gssbuf.value = hash;
301 gssbuf.length = hashlen;
302
303 /* Verify that the hash matches the MIC we just got. */
304 if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
305 packet_disconnect("Hash's MIC didn't verify");
306
307 free(msg_tok.value);
308
309 DH_free(dh);
310 free(serverhostkey);
311 BN_clear_free(dh_server_pub);
312
313 /* save session id */
314 if (kex->session_id == NULL) {
315 kex->session_id_len = hashlen;
316 kex->session_id = xmalloc(kex->session_id_len);
317 memcpy(kex->session_id, hash, kex->session_id_len);
318 }
319
320 if (kex->gss_deleg_creds)
321 ssh_gssapi_credentials_updated(ctxt);
322
323 if (gss_kex_context == NULL)
324 gss_kex_context = ctxt;
325 else
326 ssh_gssapi_delete_ctx(&ctxt);
327
328 kex_derive_keys(kex, hash, hashlen, shared_secret);
329 BN_clear_free(shared_secret);
330 kex_finish(kex);
331}
332
333#endif /* GSSAPI */
diff --git a/kexgsss.c b/kexgsss.c
new file mode 100644
index 000000000..18b065b10
--- /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->evp_md,
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(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 55ee78998..2591635bc 100644
--- a/key.c
+++ b/key.c
@@ -933,6 +933,7 @@ static const struct keytype keytypes[] = {
933 KEY_RSA_CERT_V00, 0, 1 }, 933 KEY_RSA_CERT_V00, 0, 1 },
934 { "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00", 934 { "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00",
935 KEY_DSA_CERT_V00, 0, 1 }, 935 KEY_DSA_CERT_V00, 0, 1 },
936 { "null", "null", KEY_NULL, 0, 0 },
936 { NULL, NULL, -1, -1, 0 } 937 { NULL, NULL, -1, -1, 0 }
937}; 938};
938 939
diff --git a/key.h b/key.h
index 17358ae1f..b57d6a4c4 100644
--- a/key.h
+++ b/key.h
@@ -44,6 +44,7 @@ enum types {
44 KEY_ECDSA_CERT, 44 KEY_ECDSA_CERT,
45 KEY_RSA_CERT_V00, 45 KEY_RSA_CERT_V00,
46 KEY_DSA_CERT_V00, 46 KEY_DSA_CERT_V00,
47 KEY_NULL,
47 KEY_UNSPEC 48 KEY_UNSPEC
48}; 49};
49enum fp_type { 50enum fp_type {
diff --git a/monitor.c b/monitor.c
index 44dff98c9..9079c9762 100644
--- a/monitor.c
+++ b/monitor.c
@@ -181,6 +181,8 @@ int mm_answer_gss_setup_ctx(int, Buffer *);
181int mm_answer_gss_accept_ctx(int, Buffer *); 181int mm_answer_gss_accept_ctx(int, Buffer *);
182int mm_answer_gss_userok(int, Buffer *); 182int mm_answer_gss_userok(int, Buffer *);
183int mm_answer_gss_checkmic(int, Buffer *); 183int mm_answer_gss_checkmic(int, Buffer *);
184int mm_answer_gss_sign(int, Buffer *);
185int mm_answer_gss_updatecreds(int, Buffer *);
184#endif 186#endif
185 187
186#ifdef SSH_AUDIT_EVENTS 188#ifdef SSH_AUDIT_EVENTS
@@ -253,6 +255,7 @@ struct mon_table mon_dispatch_proto20[] = {
253 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, 255 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
254 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, 256 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
255 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, 257 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
258 {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
256#endif 259#endif
257#ifdef JPAKE 260#ifdef JPAKE
258 {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata}, 261 {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata},
@@ -265,6 +268,12 @@ struct mon_table mon_dispatch_proto20[] = {
265}; 268};
266 269
267struct mon_table mon_dispatch_postauth20[] = { 270struct mon_table mon_dispatch_postauth20[] = {
271#ifdef GSSAPI
272 {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
273 {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
274 {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
275 {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
276#endif
268 {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, 277 {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
269 {MONITOR_REQ_SIGN, 0, mm_answer_sign}, 278 {MONITOR_REQ_SIGN, 0, mm_answer_sign},
270 {MONITOR_REQ_PTY, 0, mm_answer_pty}, 279 {MONITOR_REQ_PTY, 0, mm_answer_pty},
@@ -373,6 +382,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
373 /* Permit requests for moduli and signatures */ 382 /* Permit requests for moduli and signatures */
374 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 383 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
375 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 384 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
385#ifdef GSSAPI
386 /* and for the GSSAPI key exchange */
387 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
388#endif
376 } else { 389 } else {
377 mon_dispatch = mon_dispatch_proto15; 390 mon_dispatch = mon_dispatch_proto15;
378 391
@@ -487,6 +500,10 @@ monitor_child_postauth(struct monitor *pmonitor)
487 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 500 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
488 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 501 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
489 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 502 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
503#ifdef GSSAPI
504 /* and for the GSSAPI key exchange */
505 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
506#endif
490 } else { 507 } else {
491 mon_dispatch = mon_dispatch_postauth15; 508 mon_dispatch = mon_dispatch_postauth15;
492 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 509 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
@@ -1855,6 +1872,13 @@ mm_get_kex(Buffer *m)
1855 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 1872 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
1856 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 1873 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
1857 kex->kex[KEX_ECDH_SHA2] = kexecdh_server; 1874 kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
1875#ifdef GSSAPI
1876 if (options.gss_keyex) {
1877 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
1878 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
1879 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
1880 }
1881#endif
1858 kex->server = 1; 1882 kex->server = 1;
1859 kex->hostkey_type = buffer_get_int(m); 1883 kex->hostkey_type = buffer_get_int(m);
1860 kex->kex_type = buffer_get_int(m); 1884 kex->kex_type = buffer_get_int(m);
@@ -2062,6 +2086,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer *m)
2062 OM_uint32 major; 2086 OM_uint32 major;
2063 u_int len; 2087 u_int len;
2064 2088
2089 if (!options.gss_authentication && !options.gss_keyex)
2090 fatal("In GSSAPI monitor when GSSAPI is disabled");
2091
2065 goid.elements = buffer_get_string(m, &len); 2092 goid.elements = buffer_get_string(m, &len);
2066 goid.length = len; 2093 goid.length = len;
2067 2094
@@ -2089,6 +2116,9 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
2089 OM_uint32 flags = 0; /* GSI needs this */ 2116 OM_uint32 flags = 0; /* GSI needs this */
2090 u_int len; 2117 u_int len;
2091 2118
2119 if (!options.gss_authentication && !options.gss_keyex)
2120 fatal("In GSSAPI monitor when GSSAPI is disabled");
2121
2092 in.value = buffer_get_string(m, &len); 2122 in.value = buffer_get_string(m, &len);
2093 in.length = len; 2123 in.length = len;
2094 major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); 2124 major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
@@ -2106,6 +2136,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
2106 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); 2136 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
2107 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); 2137 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
2108 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); 2138 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
2139 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
2109 } 2140 }
2110 return (0); 2141 return (0);
2111} 2142}
@@ -2117,6 +2148,9 @@ mm_answer_gss_checkmic(int sock, Buffer *m)
2117 OM_uint32 ret; 2148 OM_uint32 ret;
2118 u_int len; 2149 u_int len;
2119 2150
2151 if (!options.gss_authentication && !options.gss_keyex)
2152 fatal("In GSSAPI monitor when GSSAPI is disabled");
2153
2120 gssbuf.value = buffer_get_string(m, &len); 2154 gssbuf.value = buffer_get_string(m, &len);
2121 gssbuf.length = len; 2155 gssbuf.length = len;
2122 mic.value = buffer_get_string(m, &len); 2156 mic.value = buffer_get_string(m, &len);
@@ -2143,7 +2177,11 @@ mm_answer_gss_userok(int sock, Buffer *m)
2143{ 2177{
2144 int authenticated; 2178 int authenticated;
2145 2179
2146 authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); 2180 if (!options.gss_authentication && !options.gss_keyex)
2181 fatal("In GSSAPI monitor when GSSAPI is disabled");
2182
2183 authenticated = authctxt->valid &&
2184 ssh_gssapi_userok(authctxt->user, authctxt->pw);
2147 2185
2148 buffer_clear(m); 2186 buffer_clear(m);
2149 buffer_put_int(m, authenticated); 2187 buffer_put_int(m, authenticated);
@@ -2156,6 +2194,74 @@ mm_answer_gss_userok(int sock, Buffer *m)
2156 /* Monitor loop will terminate if authenticated */ 2194 /* Monitor loop will terminate if authenticated */
2157 return (authenticated); 2195 return (authenticated);
2158} 2196}
2197
2198int
2199mm_answer_gss_sign(int socket, Buffer *m)
2200{
2201 gss_buffer_desc data;
2202 gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
2203 OM_uint32 major, minor;
2204 u_int len;
2205
2206 if (!options.gss_authentication && !options.gss_keyex)
2207 fatal("In GSSAPI monitor when GSSAPI is disabled");
2208
2209 data.value = buffer_get_string(m, &len);
2210 data.length = len;
2211 if (data.length != 20)
2212 fatal("%s: data length incorrect: %d", __func__,
2213 (int) data.length);
2214
2215 /* Save the session ID on the first time around */
2216 if (session_id2_len == 0) {
2217 session_id2_len = data.length;
2218 session_id2 = xmalloc(session_id2_len);
2219 memcpy(session_id2, data.value, session_id2_len);
2220 }
2221 major = ssh_gssapi_sign(gsscontext, &data, &hash);
2222
2223 free(data.value);
2224
2225 buffer_clear(m);
2226 buffer_put_int(m, major);
2227 buffer_put_string(m, hash.value, hash.length);
2228
2229 mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
2230
2231 gss_release_buffer(&minor, &hash);
2232
2233 /* Turn on getpwnam permissions */
2234 monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
2235
2236 /* And credential updating, for when rekeying */
2237 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1);
2238
2239 return (0);
2240}
2241
2242int
2243mm_answer_gss_updatecreds(int socket, Buffer *m) {
2244 ssh_gssapi_ccache store;
2245 int ok;
2246
2247 store.filename = buffer_get_string(m, NULL);
2248 store.envvar = buffer_get_string(m, NULL);
2249 store.envval = buffer_get_string(m, NULL);
2250
2251 ok = ssh_gssapi_update_creds(&store);
2252
2253 free(store.filename);
2254 free(store.envvar);
2255 free(store.envval);
2256
2257 buffer_clear(m);
2258 buffer_put_int(m, ok);
2259
2260 mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m);
2261
2262 return(0);
2263}
2264
2159#endif /* GSSAPI */ 2265#endif /* GSSAPI */
2160 2266
2161#ifdef JPAKE 2267#ifdef JPAKE
diff --git a/monitor.h b/monitor.h
index 2caa46933..315ef996d 100644
--- a/monitor.h
+++ b/monitor.h
@@ -70,6 +70,9 @@ enum monitor_reqtype {
70 MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, 70 MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
71 MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, 71 MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
72 72
73 MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151,
74 MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153,
75
73}; 76};
74 77
75struct mm_master; 78struct mm_master;
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 4ce469605..44019f32a 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1273,7 +1273,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
1273} 1273}
1274 1274
1275int 1275int
1276mm_ssh_gssapi_userok(char *user) 1276mm_ssh_gssapi_userok(char *user, struct passwd *pw)
1277{ 1277{
1278 Buffer m; 1278 Buffer m;
1279 int authenticated = 0; 1279 int authenticated = 0;
@@ -1290,6 +1290,51 @@ mm_ssh_gssapi_userok(char *user)
1290 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); 1290 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
1291 return (authenticated); 1291 return (authenticated);
1292} 1292}
1293
1294OM_uint32
1295mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
1296{
1297 Buffer m;
1298 OM_uint32 major;
1299 u_int len;
1300
1301 buffer_init(&m);
1302 buffer_put_string(&m, data->value, data->length);
1303
1304 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
1305 mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
1306
1307 major = buffer_get_int(&m);
1308 hash->value = buffer_get_string(&m, &len);
1309 hash->length = len;
1310
1311 buffer_free(&m);
1312
1313 return(major);
1314}
1315
1316int
1317mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store)
1318{
1319 Buffer m;
1320 int ok;
1321
1322 buffer_init(&m);
1323
1324 buffer_put_cstring(&m, store->filename ? store->filename : "");
1325 buffer_put_cstring(&m, store->envvar ? store->envvar : "");
1326 buffer_put_cstring(&m, store->envval ? store->envval : "");
1327
1328 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m);
1329 mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m);
1330
1331 ok = buffer_get_int(&m);
1332
1333 buffer_free(&m);
1334
1335 return (ok);
1336}
1337
1293#endif /* GSSAPI */ 1338#endif /* GSSAPI */
1294 1339
1295#ifdef JPAKE 1340#ifdef JPAKE
diff --git a/monitor_wrap.h b/monitor_wrap.h
index 0c7f2e384..ec9b9b1c3 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -58,8 +58,10 @@ BIGNUM *mm_auth_rsa_generate_challenge(Key *);
58OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); 58OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
59OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, 59OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
60 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); 60 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
61int mm_ssh_gssapi_userok(char *user); 61int mm_ssh_gssapi_userok(char *user, struct passwd *);
62OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 62OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
63OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
64int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
63#endif 65#endif
64 66
65#ifdef USE_PAM 67#ifdef USE_PAM
diff --git a/readconf.c b/readconf.c
index 1464430a4..2695fd6c0 100644
--- a/readconf.c
+++ b/readconf.c
@@ -132,6 +132,8 @@ typedef enum {
132 oClearAllForwardings, oNoHostAuthenticationForLocalhost, 132 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
133 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 133 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
134 oAddressFamily, oGssAuthentication, oGssDelegateCreds, 134 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
135 oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey,
136 oGssServerIdentity,
135 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 137 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
136 oSendEnv, oControlPath, oControlMaster, oControlPersist, 138 oSendEnv, oControlPath, oControlMaster, oControlPersist,
137 oHashKnownHosts, 139 oHashKnownHosts,
@@ -172,10 +174,19 @@ static struct {
172 { "afstokenpassing", oUnsupported }, 174 { "afstokenpassing", oUnsupported },
173#if defined(GSSAPI) 175#if defined(GSSAPI)
174 { "gssapiauthentication", oGssAuthentication }, 176 { "gssapiauthentication", oGssAuthentication },
177 { "gssapikeyexchange", oGssKeyEx },
175 { "gssapidelegatecredentials", oGssDelegateCreds }, 178 { "gssapidelegatecredentials", oGssDelegateCreds },
179 { "gssapitrustdns", oGssTrustDns },
180 { "gssapiclientidentity", oGssClientIdentity },
181 { "gssapiserveridentity", oGssServerIdentity },
182 { "gssapirenewalforcesrekey", oGssRenewalRekey },
176#else 183#else
177 { "gssapiauthentication", oUnsupported }, 184 { "gssapiauthentication", oUnsupported },
185 { "gssapikeyexchange", oUnsupported },
178 { "gssapidelegatecredentials", oUnsupported }, 186 { "gssapidelegatecredentials", oUnsupported },
187 { "gssapitrustdns", oUnsupported },
188 { "gssapiclientidentity", oUnsupported },
189 { "gssapirenewalforcesrekey", oUnsupported },
179#endif 190#endif
180 { "fallbacktorsh", oDeprecated }, 191 { "fallbacktorsh", oDeprecated },
181 { "usersh", oDeprecated }, 192 { "usersh", oDeprecated },
@@ -516,10 +527,30 @@ parse_flag:
516 intptr = &options->gss_authentication; 527 intptr = &options->gss_authentication;
517 goto parse_flag; 528 goto parse_flag;
518 529
530 case oGssKeyEx:
531 intptr = &options->gss_keyex;
532 goto parse_flag;
533
519 case oGssDelegateCreds: 534 case oGssDelegateCreds:
520 intptr = &options->gss_deleg_creds; 535 intptr = &options->gss_deleg_creds;
521 goto parse_flag; 536 goto parse_flag;
522 537
538 case oGssTrustDns:
539 intptr = &options->gss_trust_dns;
540 goto parse_flag;
541
542 case oGssClientIdentity:
543 charptr = &options->gss_client_identity;
544 goto parse_string;
545
546 case oGssServerIdentity:
547 charptr = &options->gss_server_identity;
548 goto parse_string;
549
550 case oGssRenewalRekey:
551 intptr = &options->gss_renewal_rekey;
552 goto parse_flag;
553
523 case oBatchMode: 554 case oBatchMode:
524 intptr = &options->batch_mode; 555 intptr = &options->batch_mode;
525 goto parse_flag; 556 goto parse_flag;
@@ -1168,7 +1199,12 @@ initialize_options(Options * options)
1168 options->pubkey_authentication = -1; 1199 options->pubkey_authentication = -1;
1169 options->challenge_response_authentication = -1; 1200 options->challenge_response_authentication = -1;
1170 options->gss_authentication = -1; 1201 options->gss_authentication = -1;
1202 options->gss_keyex = -1;
1171 options->gss_deleg_creds = -1; 1203 options->gss_deleg_creds = -1;
1204 options->gss_trust_dns = -1;
1205 options->gss_renewal_rekey = -1;
1206 options->gss_client_identity = NULL;
1207 options->gss_server_identity = NULL;
1172 options->password_authentication = -1; 1208 options->password_authentication = -1;
1173 options->kbd_interactive_authentication = -1; 1209 options->kbd_interactive_authentication = -1;
1174 options->kbd_interactive_devices = NULL; 1210 options->kbd_interactive_devices = NULL;
@@ -1268,8 +1304,14 @@ fill_default_options(Options * options)
1268 options->challenge_response_authentication = 1; 1304 options->challenge_response_authentication = 1;
1269 if (options->gss_authentication == -1) 1305 if (options->gss_authentication == -1)
1270 options->gss_authentication = 0; 1306 options->gss_authentication = 0;
1307 if (options->gss_keyex == -1)
1308 options->gss_keyex = 0;
1271 if (options->gss_deleg_creds == -1) 1309 if (options->gss_deleg_creds == -1)
1272 options->gss_deleg_creds = 0; 1310 options->gss_deleg_creds = 0;
1311 if (options->gss_trust_dns == -1)
1312 options->gss_trust_dns = 0;
1313 if (options->gss_renewal_rekey == -1)
1314 options->gss_renewal_rekey = 0;
1273 if (options->password_authentication == -1) 1315 if (options->password_authentication == -1)
1274 options->password_authentication = 1; 1316 options->password_authentication = 1;
1275 if (options->kbd_interactive_authentication == -1) 1317 if (options->kbd_interactive_authentication == -1)
diff --git a/readconf.h b/readconf.h
index 23fc500da..675b35dfe 100644
--- a/readconf.h
+++ b/readconf.h
@@ -48,7 +48,12 @@ typedef struct {
48 int challenge_response_authentication; 48 int challenge_response_authentication;
49 /* Try S/Key or TIS, authentication. */ 49 /* Try S/Key or TIS, authentication. */
50 int gss_authentication; /* Try GSS authentication */ 50 int gss_authentication; /* Try GSS authentication */
51 int gss_keyex; /* Try GSS key exchange */
51 int gss_deleg_creds; /* Delegate GSS credentials */ 52 int gss_deleg_creds; /* Delegate GSS credentials */
53 int gss_trust_dns; /* Trust DNS for GSS canonicalization */
54 int gss_renewal_rekey; /* Credential renewal forces rekey */
55 char *gss_client_identity; /* Principal to initiate GSSAPI with */
56 char *gss_server_identity; /* GSSAPI target principal */
52 int password_authentication; /* Try password 57 int password_authentication; /* Try password
53 * authentication. */ 58 * authentication. */
54 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ 59 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */
diff --git a/servconf.c b/servconf.c
index 747edde6c..c938ae399 100644
--- a/servconf.c
+++ b/servconf.c
@@ -107,7 +107,10 @@ initialize_server_options(ServerOptions *options)
107 options->kerberos_ticket_cleanup = -1; 107 options->kerberos_ticket_cleanup = -1;
108 options->kerberos_get_afs_token = -1; 108 options->kerberos_get_afs_token = -1;
109 options->gss_authentication=-1; 109 options->gss_authentication=-1;
110 options->gss_keyex = -1;
110 options->gss_cleanup_creds = -1; 111 options->gss_cleanup_creds = -1;
112 options->gss_strict_acceptor = -1;
113 options->gss_store_rekey = -1;
111 options->password_authentication = -1; 114 options->password_authentication = -1;
112 options->kbd_interactive_authentication = -1; 115 options->kbd_interactive_authentication = -1;
113 options->challenge_response_authentication = -1; 116 options->challenge_response_authentication = -1;
@@ -240,8 +243,14 @@ fill_default_server_options(ServerOptions *options)
240 options->kerberos_get_afs_token = 0; 243 options->kerberos_get_afs_token = 0;
241 if (options->gss_authentication == -1) 244 if (options->gss_authentication == -1)
242 options->gss_authentication = 0; 245 options->gss_authentication = 0;
246 if (options->gss_keyex == -1)
247 options->gss_keyex = 0;
243 if (options->gss_cleanup_creds == -1) 248 if (options->gss_cleanup_creds == -1)
244 options->gss_cleanup_creds = 1; 249 options->gss_cleanup_creds = 1;
250 if (options->gss_strict_acceptor == -1)
251 options->gss_strict_acceptor = 1;
252 if (options->gss_store_rekey == -1)
253 options->gss_store_rekey = 0;
245 if (options->password_authentication == -1) 254 if (options->password_authentication == -1)
246 options->password_authentication = 1; 255 options->password_authentication = 1;
247 if (options->kbd_interactive_authentication == -1) 256 if (options->kbd_interactive_authentication == -1)
@@ -338,7 +347,9 @@ typedef enum {
338 sBanner, sUseDNS, sHostbasedAuthentication, 347 sBanner, sUseDNS, sHostbasedAuthentication,
339 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, 348 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
340 sClientAliveCountMax, sAuthorizedKeysFile, 349 sClientAliveCountMax, sAuthorizedKeysFile,
341 sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, 350 sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
351 sGssKeyEx, sGssStoreRekey,
352 sAcceptEnv, sPermitTunnel,
342 sMatch, sPermitOpen, sForceCommand, sChrootDirectory, 353 sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
343 sUsePrivilegeSeparation, sAllowAgentForwarding, 354 sUsePrivilegeSeparation, sAllowAgentForwarding,
344 sZeroKnowledgePasswordAuthentication, sHostCertificate, 355 sZeroKnowledgePasswordAuthentication, sHostCertificate,
@@ -405,10 +416,20 @@ static struct {
405#ifdef GSSAPI 416#ifdef GSSAPI
406 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, 417 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
407 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, 418 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
419 { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
420 { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
421 { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
422 { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
408#else 423#else
409 { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, 424 { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
410 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, 425 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
426 { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
427 { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
428 { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
429 { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
411#endif 430#endif
431 { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
432 { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
412 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, 433 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
413 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, 434 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
414 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, 435 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
@@ -1073,10 +1094,22 @@ process_server_config_line(ServerOptions *options, char *line,
1073 intptr = &options->gss_authentication; 1094 intptr = &options->gss_authentication;
1074 goto parse_flag; 1095 goto parse_flag;
1075 1096
1097 case sGssKeyEx:
1098 intptr = &options->gss_keyex;
1099 goto parse_flag;
1100
1076 case sGssCleanupCreds: 1101 case sGssCleanupCreds:
1077 intptr = &options->gss_cleanup_creds; 1102 intptr = &options->gss_cleanup_creds;
1078 goto parse_flag; 1103 goto parse_flag;
1079 1104
1105 case sGssStrictAcceptor:
1106 intptr = &options->gss_strict_acceptor;
1107 goto parse_flag;
1108
1109 case sGssStoreRekey:
1110 intptr = &options->gss_store_rekey;
1111 goto parse_flag;
1112
1080 case sPasswordAuthentication: 1113 case sPasswordAuthentication:
1081 intptr = &options->password_authentication; 1114 intptr = &options->password_authentication;
1082 goto parse_flag; 1115 goto parse_flag;
@@ -1983,7 +2016,10 @@ dump_config(ServerOptions *o)
1983#endif 2016#endif
1984#ifdef GSSAPI 2017#ifdef GSSAPI
1985 dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); 2018 dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
2019 dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
1986 dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); 2020 dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
2021 dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
2022 dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey);
1987#endif 2023#endif
1988#ifdef JPAKE 2024#ifdef JPAKE
1989 dump_cfg_fmtint(sZeroKnowledgePasswordAuthentication, 2025 dump_cfg_fmtint(sZeroKnowledgePasswordAuthentication,
diff --git a/servconf.h b/servconf.h
index 98aad8ba2..ab6e34669 100644
--- a/servconf.h
+++ b/servconf.h
@@ -111,7 +111,10 @@ typedef struct {
111 int kerberos_get_afs_token; /* If true, try to get AFS token if 111 int kerberos_get_afs_token; /* If true, try to get AFS token if
112 * authenticated with Kerberos. */ 112 * authenticated with Kerberos. */
113 int gss_authentication; /* If true, permit GSSAPI authentication */ 113 int gss_authentication; /* If true, permit GSSAPI authentication */
114 int gss_keyex; /* If true, permit GSSAPI key exchange */
114 int gss_cleanup_creds; /* If true, destroy cred cache on logout */ 115 int gss_cleanup_creds; /* If true, destroy cred cache on logout */
116 int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */
117 int gss_store_rekey;
115 int password_authentication; /* If true, permit password 118 int password_authentication; /* If true, permit password
116 * authentication. */ 119 * authentication. */
117 int kbd_interactive_authentication; /* If true, permit */ 120 int kbd_interactive_authentication; /* If true, permit */
diff --git a/ssh-gss.h b/ssh-gss.h
index 077e13ce4..bc6e8f946 100644
--- a/ssh-gss.h
+++ b/ssh-gss.h
@@ -1,6 +1,6 @@
1/* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */ 1/* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 3 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
@@ -61,10 +61,22 @@
61 61
62#define SSH_GSS_OIDTYPE 0x06 62#define SSH_GSS_OIDTYPE 0x06
63 63
64#define SSH2_MSG_KEXGSS_INIT 30
65#define SSH2_MSG_KEXGSS_CONTINUE 31
66#define SSH2_MSG_KEXGSS_COMPLETE 32
67#define SSH2_MSG_KEXGSS_HOSTKEY 33
68#define SSH2_MSG_KEXGSS_ERROR 34
69#define SSH2_MSG_KEXGSS_GROUPREQ 40
70#define SSH2_MSG_KEXGSS_GROUP 41
71#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-"
72#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-"
73#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-"
74
64typedef struct { 75typedef struct {
65 char *filename; 76 char *filename;
66 char *envvar; 77 char *envvar;
67 char *envval; 78 char *envval;
79 struct passwd *owner;
68 void *data; 80 void *data;
69} ssh_gssapi_ccache; 81} ssh_gssapi_ccache;
70 82
@@ -72,8 +84,11 @@ typedef struct {
72 gss_buffer_desc displayname; 84 gss_buffer_desc displayname;
73 gss_buffer_desc exportedname; 85 gss_buffer_desc exportedname;
74 gss_cred_id_t creds; 86 gss_cred_id_t creds;
87 gss_name_t name;
75 struct ssh_gssapi_mech_struct *mech; 88 struct ssh_gssapi_mech_struct *mech;
76 ssh_gssapi_ccache store; 89 ssh_gssapi_ccache store;
90 int used;
91 int updated;
77} ssh_gssapi_client; 92} ssh_gssapi_client;
78 93
79typedef struct ssh_gssapi_mech_struct { 94typedef struct ssh_gssapi_mech_struct {
@@ -84,6 +99,7 @@ typedef struct ssh_gssapi_mech_struct {
84 int (*userok) (ssh_gssapi_client *, char *); 99 int (*userok) (ssh_gssapi_client *, char *);
85 int (*localname) (ssh_gssapi_client *, char **); 100 int (*localname) (ssh_gssapi_client *, char **);
86 void (*storecreds) (ssh_gssapi_client *); 101 void (*storecreds) (ssh_gssapi_client *);
102 int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *);
87} ssh_gssapi_mech; 103} ssh_gssapi_mech;
88 104
89typedef struct { 105typedef struct {
@@ -94,10 +110,11 @@ typedef struct {
94 gss_OID oid; /* client */ 110 gss_OID oid; /* client */
95 gss_cred_id_t creds; /* server */ 111 gss_cred_id_t creds; /* server */
96 gss_name_t client; /* server */ 112 gss_name_t client; /* server */
97 gss_cred_id_t client_creds; /* server */ 113 gss_cred_id_t client_creds; /* both */
98} Gssctxt; 114} Gssctxt;
99 115
100extern ssh_gssapi_mech *supported_mechs[]; 116extern ssh_gssapi_mech *supported_mechs[];
117extern Gssctxt *gss_kex_context;
101 118
102int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); 119int ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
103void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); 120void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
@@ -117,16 +134,30 @@ void ssh_gssapi_build_ctx(Gssctxt **);
117void ssh_gssapi_delete_ctx(Gssctxt **); 134void ssh_gssapi_delete_ctx(Gssctxt **);
118OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); 135OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
119void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); 136void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
120int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); 137int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *);
138OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
139int ssh_gssapi_credentials_updated(Gssctxt *);
121 140
122/* In the server */ 141/* In the server */
142typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *,
143 const char *);
144char *ssh_gssapi_client_mechanisms(const char *, const char *);
145char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *,
146 const char *);
147gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int);
148int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *,
149 const char *);
123OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); 150OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
124int ssh_gssapi_userok(char *name); 151int ssh_gssapi_userok(char *name, struct passwd *);
125OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 152OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
126void ssh_gssapi_do_child(char ***, u_int *); 153void ssh_gssapi_do_child(char ***, u_int *);
127void ssh_gssapi_cleanup_creds(void); 154void ssh_gssapi_cleanup_creds(void);
128void ssh_gssapi_storecreds(void); 155void ssh_gssapi_storecreds(void);
129 156
157char *ssh_gssapi_server_mechanisms(void);
158int ssh_gssapi_oid_table_ok();
159
160int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
130#endif /* GSSAPI */ 161#endif /* GSSAPI */
131 162
132#endif /* _SSH_GSS_H */ 163#endif /* _SSH_GSS_H */
diff --git a/ssh_config b/ssh_config
index bb4081936..32343213f 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 5d76c6d2d..e72919a89 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -529,11 +529,43 @@ Specifies whether user authentication based on GSSAPI is allowed.
529The default is 529The default is
530.Dq no . 530.Dq no .
531Note that this option applies to protocol version 2 only. 531Note that this option applies to protocol version 2 only.
532.It Cm GSSAPIKeyExchange
533Specifies whether key exchange based on GSSAPI may be used. When using
534GSSAPI key exchange the server need not have a host key.
535The default is
536.Dq no .
537Note that this option applies to protocol version 2 only.
538.It Cm GSSAPIClientIdentity
539If set, specifies the GSSAPI client identity that ssh should use when
540connecting to the server. The default is unset, which means that the default
541identity will be used.
542.It Cm GSSAPIServerIdentity
543If set, specifies the GSSAPI server identity that ssh should expect when
544connecting to the server. The default is unset, which means that the
545expected GSSAPI server identity will be determined from the target
546hostname.
532.It Cm GSSAPIDelegateCredentials 547.It Cm GSSAPIDelegateCredentials
533Forward (delegate) credentials to the server. 548Forward (delegate) credentials to the server.
534The default is 549The default is
535.Dq no . 550.Dq no .
536Note that this option applies to protocol version 2 only. 551Note that this option applies to protocol version 2 connections using GSSAPI.
552.It Cm GSSAPIRenewalForcesRekey
553If set to
554.Dq yes
555then renewal of the client's GSSAPI credentials will force the rekeying of the
556ssh connection. With a compatible server, this can delegate the renewed
557credentials to a session on the server.
558The default is
559.Dq no .
560.It Cm GSSAPITrustDns
561Set to
562.Dq yes to indicate that the DNS is trusted to securely canonicalize
563the name of the host being connected to. If
564.Dq no, the hostname entered on the
565command line will be passed untouched to the GSSAPI library.
566The default is
567.Dq no .
568This option only applies to protocol version 2 connections using GSSAPI.
537.It Cm HashKnownHosts 569.It Cm HashKnownHosts
538Indicates that 570Indicates that
539.Xr ssh 1 571.Xr ssh 1
diff --git a/sshconnect2.c b/sshconnect2.c
index 70e3cd8c9..0b13530ce 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -160,9 +160,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
160{ 160{
161 Kex *kex; 161 Kex *kex;
162 162
163#ifdef GSSAPI
164 char *orig = NULL, *gss = NULL;
165 char *gss_host = NULL;
166#endif
167
163 xxx_host = host; 168 xxx_host = host;
164 xxx_hostaddr = hostaddr; 169 xxx_hostaddr = hostaddr;
165 170
171#ifdef GSSAPI
172 if (options.gss_keyex) {
173 /* Add the GSSAPI mechanisms currently supported on this
174 * client to the key exchange algorithm proposal */
175 orig = myproposal[PROPOSAL_KEX_ALGS];
176
177 if (options.gss_trust_dns)
178 gss_host = (char *)get_canonical_hostname(1);
179 else
180 gss_host = host;
181
182 gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity);
183 if (gss) {
184 debug("Offering GSSAPI proposal: %s", gss);
185 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
186 "%s,%s", gss, orig);
187 }
188 }
189#endif
190
166 if (options.ciphers == (char *)-1) { 191 if (options.ciphers == (char *)-1) {
167 logit("No valid ciphers for protocol version 2 given, using defaults."); 192 logit("No valid ciphers for protocol version 2 given, using defaults.");
168 options.ciphers = NULL; 193 options.ciphers = NULL;
@@ -197,6 +222,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
197 if (options.kex_algorithms != NULL) 222 if (options.kex_algorithms != NULL)
198 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; 223 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
199 224
225#ifdef GSSAPI
226 /* If we've got GSSAPI algorithms, then we also support the
227 * 'null' hostkey, as a last resort */
228 if (options.gss_keyex && gss) {
229 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
230 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
231 "%s,null", orig);
232 free(gss);
233 }
234#endif
235
200 if (options.rekey_limit || options.rekey_interval) 236 if (options.rekey_limit || options.rekey_interval)
201 packet_set_rekey_limits((u_int32_t)options.rekey_limit, 237 packet_set_rekey_limits((u_int32_t)options.rekey_limit,
202 (time_t)options.rekey_interval); 238 (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_SHA1] = kexgex_client; 244 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
209 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 245 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
210 kex->kex[KEX_ECDH_SHA2] = kexecdh_client; 246 kex->kex[KEX_ECDH_SHA2] = kexecdh_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);
@@ -307,6 +363,7 @@ void input_gssapi_token(int type, u_int32_t, void *);
307void input_gssapi_hash(int type, u_int32_t, void *); 363void input_gssapi_hash(int type, u_int32_t, void *);
308void input_gssapi_error(int, u_int32_t, void *); 364void input_gssapi_error(int, u_int32_t, void *);
309void input_gssapi_errtok(int, u_int32_t, void *); 365void input_gssapi_errtok(int, u_int32_t, void *);
366int userauth_gsskeyex(Authctxt *authctxt);
310#endif 367#endif
311 368
312void userauth(Authctxt *, char *); 369void userauth(Authctxt *, char *);
@@ -322,6 +379,11 @@ static char *authmethods_get(void);
322 379
323Authmethod authmethods[] = { 380Authmethod authmethods[] = {
324#ifdef GSSAPI 381#ifdef GSSAPI
382 {"gssapi-keyex",
383 userauth_gsskeyex,
384 NULL,
385 &options.gss_authentication,
386 NULL},
325 {"gssapi-with-mic", 387 {"gssapi-with-mic",
326 userauth_gssapi, 388 userauth_gssapi,
327 NULL, 389 NULL,
@@ -625,19 +687,31 @@ userauth_gssapi(Authctxt *authctxt)
625 static u_int mech = 0; 687 static u_int mech = 0;
626 OM_uint32 min; 688 OM_uint32 min;
627 int ok = 0; 689 int ok = 0;
690 const char *gss_host;
691
692 if (options.gss_server_identity)
693 gss_host = options.gss_server_identity;
694 else if (options.gss_trust_dns)
695 gss_host = get_canonical_hostname(1);
696 else
697 gss_host = authctxt->host;
628 698
629 /* Try one GSSAPI method at a time, rather than sending them all at 699 /* Try one GSSAPI method at a time, rather than sending them all at
630 * once. */ 700 * once. */
631 701
632 if (gss_supported == NULL) 702 if (gss_supported == NULL)
633 gss_indicate_mechs(&min, &gss_supported); 703 if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
704 gss_supported = NULL;
705 return 0;
706 }
634 707
635 /* Check to see if the mechanism is usable before we offer it */ 708 /* Check to see if the mechanism is usable before we offer it */
636 while (mech < gss_supported->count && !ok) { 709 while (mech < gss_supported->count && !ok) {
637 /* My DER encoding requires length<128 */ 710 /* My DER encoding requires length<128 */
638 if (gss_supported->elements[mech].length < 128 && 711 if (gss_supported->elements[mech].length < 128 &&
639 ssh_gssapi_check_mechanism(&gssctxt, 712 ssh_gssapi_check_mechanism(&gssctxt,
640 &gss_supported->elements[mech], authctxt->host)) { 713 &gss_supported->elements[mech], gss_host,
714 options.gss_client_identity)) {
641 ok = 1; /* Mechanism works */ 715 ok = 1; /* Mechanism works */
642 } else { 716 } else {
643 mech++; 717 mech++;
@@ -734,8 +808,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
734{ 808{
735 Authctxt *authctxt = ctxt; 809 Authctxt *authctxt = ctxt;
736 Gssctxt *gssctxt; 810 Gssctxt *gssctxt;
737 int oidlen; 811 u_int oidlen;
738 char *oidv; 812 u_char *oidv;
739 813
740 if (authctxt == NULL) 814 if (authctxt == NULL)
741 fatal("input_gssapi_response: no authentication context"); 815 fatal("input_gssapi_response: no authentication context");
@@ -844,6 +918,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
844 free(msg); 918 free(msg);
845 free(lang); 919 free(lang);
846} 920}
921
922int
923userauth_gsskeyex(Authctxt *authctxt)
924{
925 Buffer b;
926 gss_buffer_desc gssbuf;
927 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
928 OM_uint32 ms;
929
930 static int attempt = 0;
931 if (attempt++ >= 1)
932 return (0);
933
934 if (gss_kex_context == NULL) {
935 debug("No valid Key exchange context");
936 return (0);
937 }
938
939 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
940 "gssapi-keyex");
941
942 gssbuf.value = buffer_ptr(&b);
943 gssbuf.length = buffer_len(&b);
944
945 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
946 buffer_free(&b);
947 return (0);
948 }
949
950 packet_start(SSH2_MSG_USERAUTH_REQUEST);
951 packet_put_cstring(authctxt->server_user);
952 packet_put_cstring(authctxt->service);
953 packet_put_cstring(authctxt->method->name);
954 packet_put_string(mic.value, mic.length);
955 packet_send();
956
957 buffer_free(&b);
958 gss_release_buffer(&ms, &mic);
959
960 return (1);
961}
962
847#endif /* GSSAPI */ 963#endif /* GSSAPI */
848 964
849int 965int
diff --git a/sshd.c b/sshd.c
index 174cc7a42..4eddeb8d8 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>
@@ -1703,10 +1707,13 @@ main(int ac, char **av)
1703 logit("Disabling protocol version 1. Could not load host key"); 1707 logit("Disabling protocol version 1. Could not load host key");
1704 options.protocol &= ~SSH_PROTO_1; 1708 options.protocol &= ~SSH_PROTO_1;
1705 } 1709 }
1710#ifndef GSSAPI
1711 /* The GSSAPI key exchange can run without a host key */
1706 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { 1712 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
1707 logit("Disabling protocol version 2. Could not load host key"); 1713 logit("Disabling protocol version 2. Could not load host key");
1708 options.protocol &= ~SSH_PROTO_2; 1714 options.protocol &= ~SSH_PROTO_2;
1709 } 1715 }
1716#endif
1710 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { 1717 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
1711 logit("sshd: no hostkeys available -- exiting."); 1718 logit("sshd: no hostkeys available -- exiting.");
1712 exit(1); 1719 exit(1);
@@ -2035,6 +2042,60 @@ main(int ac, char **av)
2035 /* Log the connection. */ 2042 /* Log the connection. */
2036 verbose("Connection from %.500s port %d", remote_ip, remote_port); 2043 verbose("Connection from %.500s port %d", remote_ip, remote_port);
2037 2044
2045#ifdef USE_SECURITY_SESSION_API
2046 /*
2047 * Create a new security session for use by the new user login if
2048 * the current session is the root session or we are not launched
2049 * by inetd (eg: debugging mode or server mode). We do not
2050 * necessarily need to create a session if we are launched from
2051 * inetd because Panther xinetd will create a session for us.
2052 *
2053 * The only case where this logic will fail is if there is an
2054 * inetd running in a non-root session which is not creating
2055 * new sessions for us. Then all the users will end up in the
2056 * same session (bad).
2057 *
2058 * When the client exits, the session will be destroyed for us
2059 * automatically.
2060 *
2061 * We must create the session before any credentials are stored
2062 * (including AFS pags, which happens a few lines below).
2063 */
2064 {
2065 OSStatus err = 0;
2066 SecuritySessionId sid = 0;
2067 SessionAttributeBits sattrs = 0;
2068
2069 err = SessionGetInfo(callerSecuritySession, &sid, &sattrs);
2070 if (err)
2071 error("SessionGetInfo() failed with error %.8X",
2072 (unsigned) err);
2073 else
2074 debug("Current Session ID is %.8X / Session Attributes are %.8X",
2075 (unsigned) sid, (unsigned) sattrs);
2076
2077 if (inetd_flag && !(sattrs & sessionIsRoot))
2078 debug("Running in inetd mode in a non-root session... "
2079 "assuming inetd created the session for us.");
2080 else {
2081 debug("Creating new security session...");
2082 err = SessionCreate(0, sessionHasTTY | sessionIsRemote);
2083 if (err)
2084 error("SessionCreate() failed with error %.8X",
2085 (unsigned) err);
2086
2087 err = SessionGetInfo(callerSecuritySession, &sid,
2088 &sattrs);
2089 if (err)
2090 error("SessionGetInfo() failed with error %.8X",
2091 (unsigned) err);
2092 else
2093 debug("New Session ID is %.8X / Session Attributes are %.8X",
2094 (unsigned) sid, (unsigned) sattrs);
2095 }
2096 }
2097#endif
2098
2038 /* 2099 /*
2039 * We don't want to listen forever unless the other side 2100 * We don't want to listen forever unless the other side
2040 * successfully authenticates itself. So we set up an alarm which is 2101 * successfully authenticates itself. So we set up an alarm which is
@@ -2439,6 +2500,48 @@ do_ssh2_kex(void)
2439 2500
2440 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); 2501 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
2441 2502
2503#ifdef GSSAPI
2504 {
2505 char *orig;
2506 char *gss = NULL;
2507 char *newstr = NULL;
2508 orig = myproposal[PROPOSAL_KEX_ALGS];
2509
2510 /*
2511 * If we don't have a host key, then there's no point advertising
2512 * the other key exchange algorithms
2513 */
2514
2515 if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
2516 orig = NULL;
2517
2518 if (options.gss_keyex)
2519 gss = ssh_gssapi_server_mechanisms();
2520 else
2521 gss = NULL;
2522
2523 if (gss && orig)
2524 xasprintf(&newstr, "%s,%s", gss, orig);
2525 else if (gss)
2526 newstr = gss;
2527 else if (orig)
2528 newstr = orig;
2529
2530 /*
2531 * If we've got GSSAPI mechanisms, then we've got the 'null' host
2532 * key alg, but we can't tell people about it unless its the only
2533 * host key algorithm we support
2534 */
2535 if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
2536 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
2537
2538 if (newstr)
2539 myproposal[PROPOSAL_KEX_ALGS] = newstr;
2540 else
2541 fatal("No supported key exchange algorithms");
2542 }
2543#endif
2544
2442 /* start key exchange */ 2545 /* start key exchange */
2443 kex = kex_setup(myproposal); 2546 kex = kex_setup(myproposal);
2444 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; 2547 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
@@ -2446,6 +2549,13 @@ do_ssh2_kex(void)
2446 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 2549 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
2447 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 2550 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
2448 kex->kex[KEX_ECDH_SHA2] = kexecdh_server; 2551 kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
2552#ifdef GSSAPI
2553 if (options.gss_keyex) {
2554 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
2555 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
2556 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
2557 }
2558#endif
2449 kex->server = 1; 2559 kex->server = 1;
2450 kex->client_version_string=client_version_string; 2560 kex->client_version_string=client_version_string;
2451 kex->server_version_string=server_version_string; 2561 kex->server_version_string=server_version_string;
diff --git a/sshd_config b/sshd_config
index b786361d1..945014124 100644
--- a/sshd_config
+++ b/sshd_config
@@ -83,6 +83,8 @@ AuthorizedKeysFile .ssh/authorized_keys
83# GSSAPI options 83# GSSAPI options
84#GSSAPIAuthentication no 84#GSSAPIAuthentication no
85#GSSAPICleanupCredentials yes 85#GSSAPICleanupCredentials yes
86#GSSAPIStrictAcceptorCheck yes
87#GSSAPIKeyExchange no
86 88
87# Set this to 'yes' to enable PAM authentication, account processing, 89# Set this to 'yes' to enable PAM authentication, account processing,
88# and session processing. If this is enabled, PAM authentication will 90# and session processing. If this is enabled, PAM authentication will
diff --git a/sshd_config.5 b/sshd_config.5
index 3abac6c10..525d9c858 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -484,12 +484,40 @@ Specifies whether user authentication based on GSSAPI is allowed.
484The default is 484The default is
485.Dq no . 485.Dq no .
486Note that this option applies to protocol version 2 only. 486Note that this option applies to protocol version 2 only.
487.It Cm GSSAPIKeyExchange
488Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
489doesn't rely on ssh keys to verify host identity.
490The default is
491.Dq no .
492Note that this option applies to protocol version 2 only.
487.It Cm GSSAPICleanupCredentials 493.It Cm GSSAPICleanupCredentials
488Specifies whether to automatically destroy the user's credentials cache 494Specifies whether to automatically destroy the user's credentials cache
489on logout. 495on logout.
490The default is 496The default is
491.Dq yes . 497.Dq yes .
492Note that this option applies to protocol version 2 only. 498Note that this option applies to protocol version 2 only.
499.It Cm GSSAPIStrictAcceptorCheck
500Determines whether to be strict about the identity of the GSSAPI acceptor
501a client authenticates against. If
502.Dq yes
503then the client must authenticate against the
504.Pa host
505service on the current hostname. If
506.Dq no
507then the client may authenticate against any service key stored in the
508machine's default store. This facility is provided to assist with operation
509on multi homed machines.
510The default is
511.Dq yes .
512Note that this option applies only to protocol version 2 GSSAPI connections,
513and setting it to
514.Dq no
515may only work with recent Kerberos GSSAPI libraries.
516.It Cm GSSAPIStoreCredentialsOnRekey
517Controls whether the user's GSSAPI credentials should be updated following a
518successful connection rekeying. This option can be used to accepted renewed
519or updated credentials from a compatible client. The default is
520.Dq no .
493.It Cm HostbasedAuthentication 521.It Cm HostbasedAuthentication
494Specifies whether rhosts or /etc/hosts.equiv authentication together 522Specifies whether rhosts or /etc/hosts.equiv authentication together
495with successful public key client host authentication is allowed 523with successful public key client host authentication is allowed