Alexander Pyhalov
2017-03-27 ada565bc1fc8f66545b5c722725fc523aff5469c
openssh: update to 7.4p1
7 files deleted
4 files added
3 files modified
25 files renamed
10776 ■■■■■ changed files
components/network/openssh/Makefile 7 ●●●●● patch | view | raw | blame | history
components/network/openssh/README 18 ●●●● patch | view | raw | blame | history
components/network/openssh/manifests/sample-manifest.p5m 2 ●●●●● patch | view | raw | blame | history
components/network/openssh/patches/0001-Include-priv.h-for-priv_set_t.patch 25 ●●●●● patch | view | raw | blame | history
components/network/openssh/patches/0001-Skip-config-check.patch 10 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0002-PAM-Support.patch 14 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0003-lastlogin.patch 38 ●●●●● patch | view | raw | blame | history
components/network/openssh/patches/0004-Reorganise-man-pages-into-Illumos-numbering-adjust-t.patch 3983 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0004-lastlogin.patch 52 ●●●●● patch | view | raw | blame | history
components/network/openssh/patches/0005-Deprecated-SunSSH-options.patch 12 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0006-GSS-store-creds-for-Solaris.patch 22 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0007-DTrace-support-for-SFTP.patch 34 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0008-Add-DisableBanner-option.patch 90 ●●●●● patch | view | raw | blame | history
components/network/openssh/patches/0009-PAM-conversation-fix.patch 98 ●●●●● patch | view | raw | blame | history
components/network/openssh/patches/0010-PAM-conversation-fix.patch 104 ●●●●● patch | view | raw | blame | history
components/network/openssh/patches/0010-PAM-enhancements-for-Solaris.patch 250 ●●●●● patch | view | raw | blame | history
components/network/openssh/patches/0011-SunSSH-compat-default-config-values.patch 151 ●●●●● patch | view | raw | blame | history
components/network/openssh/patches/0012-Deprecate-SunSSH-compatible-server-options.patch 10 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0012-SunSSH-compat-default-config-values.patch 135 ●●●●● patch | view | raw | blame | history
components/network/openssh/patches/0013-Solaris-Auditing-support.patch 90 ●●●●● patch | view | raw | blame | history
components/network/openssh/patches/0014-GSS-API-key-exchange-support.patch 3303 ●●●●● patch | view | raw | blame | history
components/network/openssh/patches/0015-Enable-login-to-a-role-if-PAM-is-ok-with-it.patch 45 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0015-GSS-API-key-exchange-support.patch 1931 ●●●●● patch | view | raw | blame | history
components/network/openssh/patches/0016-PAM-setcred-failures.patch 12 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0017-Don-t-call-do_pam_setcred-twice.patch 8 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0018-Per-session-xauthfile.patch 30 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0019-PubKeyPlugin-support.patch 38 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0020-Compatibility-fix-for-ListenAddress.patch 10 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0021-Try-to-create-privsep-chroot-dir-if-it-doesn-t-exist.patch 10 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0022-Hack-around-umac_ctx-name-punning.patch 35 ●●●●● patch | view | raw | blame | history
components/network/openssh/patches/0025-Re-enable-DSA-keys-for-pk-auth.patch 22 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0026-Don-t-use-krb5-config-to-check-for-GSSAPI-on-Illumos.patch 16 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0027-Set-default-sshd-options-based-on-etc-default-login.patch 35 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0028-Compatibility-for-SunSSH_1.5-should-include-old-DH-K.patch 8 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0029-Accept-LANG-and-LC_-environment-variables-from-clien.patch 47 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0030-Temporarily-set-ssh-keygen-and-ssh-add-to-old-FP-for.patch 12 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0031-Restore-tcpwrappers-libwrap-support.patch 42 ●●●● patch | view | raw | blame | history
components/network/openssh/patches/0101-unregister-kexinit-handler.patch 27 ●●●●● patch | view | raw | blame | history
components/network/openssh/patches/1000-dtrace32.patch patch | view | raw | blame | history
components/network/openssh/Makefile
@@ -23,19 +23,18 @@
include ../../../make-rules/shared-macros.mk
COMPONENT_NAME=        openssh
COMPONENT_VERSION=    7.2p2
COMPONENT_VERSION=    7.4p1
HUMAN_VERSION=        $(COMPONENT_VERSION)
COMPONENT_SRC=        $(COMPONENT_NAME)-$(COMPONENT_VERSION)
COMPONENT_REVISION=    4
# Version for IPS.  The encoding rules are:
#   OpenSSH <x>.<y>p<n>     => IPS <x>.<y>.0.<n>
#   OpenSSH <x>.<y>.<z>p<n> => IPS <x>.<y>.<z>.<n>
IPS_COMPONENT_VERSION=    7.2.0.2
IPS_COMPONENT_VERSION=    7.4.0.1
COMPONENT_PROJECT_URL=    http://www.openssh.org/
COMPONENT_ARCHIVE=    $(COMPONENT_SRC).tar.gz
COMPONENT_ARCHIVE_HASH=    sha256:a72781d1a043876a224ff1b0032daa4094d87565a68528759c1c2cab5482548c
COMPONENT_ARCHIVE_HASH=    sha256:1b1fc4a14e2024293181924ed24872e6f2e06293f3e8926a376b8aec481f19d1
COMPONENT_ARCHIVE_URL=    http://mirror.yandex.ru/pub/OpenBSD/OpenSSH/portable/$(COMPONENT_ARCHIVE)
COMPONENT_BUGDB=utility/openssh
components/network/openssh/README
@@ -2,13 +2,13 @@
https://github.com/joyent/illumos-extra/tree/master/openssh/Patches
(including patches from userland-gate, which were updated by Alex Wilson to work with 7.2p2)
We don't need the following patches due to difference in OpenSSH and OpenSSL packaging
    0024-Add-SMF-manifest-and-method-and-install-them.patch
    0026-Add-with-key-dir-configure-option-to-place-SSH-host-.patch
    0025-Make-default-sshd_config-more-like-the-old-illumos-o.patch
    0034-Let-us-put-a-fallback-copy-of-DH-moduli-in-a-system-.patch
    1002-sunw_ssl.patch
    0022-Add-SMF-manifest-and-method-and-install-them.patch
    0024-Add-with-key-dir-configure-option-to-place-SSH-host-.patch
    0023-Make-default-sshd_config-more-like-the-old-illumos-o.patch
    0032-Let-us-put-a-fallback-copy-of-DH-moduli-in-a-system-.patch
    1001-sunw_ssl.patch
The following patches were modified to apply without patches which we don't use
    0029-Set-default-sshd-options-based-on-etc-default-login.patch
    1001-dtrace32.patch
The following is a patch from openssh-portable head
    0101-unregister-kexinit-handler.patch
    0027-Set-default-sshd-options-based-on-etc-default-login.patch
    1000-dtrace32.patch
The following patches were modified to suit OI:
    0011-SunSSH-compat-default-config-values.patch
components/network/openssh/manifests/sample-manifest.p5m
@@ -27,7 +27,6 @@
file path=etc/ssh/sshd_config
file path=usr/bin/scp
file path=usr/bin/sftp
link path=usr/bin/slogin target=./ssh
file path=usr/bin/ssh
file path=usr/bin/ssh-add
file path=usr/bin/ssh-agent
@@ -40,7 +39,6 @@
file path=usr/lib/ssh/sshd
file path=usr/share/man/man1/scp.1
file path=usr/share/man/man1/sftp.1
link path=usr/share/man/man1/slogin.1 target=./ssh.1
file path=usr/share/man/man1/ssh-add.1
file path=usr/share/man/man1/ssh-agent.1
file path=usr/share/man/man1/ssh-keygen.1
components/network/openssh/patches/0001-Include-priv.h-for-priv_set_t.patch
File was deleted
components/network/openssh/patches/0001-Skip-config-check.patch
File was renamed from components/network/openssh/patches/0002-Skip-config-check.patch
@@ -1,7 +1,7 @@
From 41b029a3dab10a1bd3d2924a3b6c891b74102599 Mon Sep 17 00:00:00 2001
From f1b0f2c40b09b0a280b097b6ce39a5767e6f6edd Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:31:53 -0700
Subject: [PATCH 02/34] Skip config check
Subject: [PATCH 01/34] Skip config check
#
# This change is to remove some misleading error messages when running
@@ -15,10 +15,10 @@
 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/Makefile.in b/Makefile.in
index d401787..c124ef6 100644
index e10f3742..4bbfb736 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -291,7 +291,16 @@ install-nokeys: $(CONFIGFILES) $(MANPAGES) $(TARGETS) install-files install-sysc
@@ -302,7 +302,16 @@ install-nokeys: $(CONFIGFILES) $(MANPAGES) $(TARGETS) install-files install-sysc
 install-nosysconf: $(CONFIGFILES) $(MANPAGES) $(TARGETS) install-files
 
 check-config:
@@ -37,5 +37,5 @@
 install-files:
     $(srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0002-PAM-Support.patch
File was renamed from components/network/openssh/patches/0003-PAM-Support.patch
@@ -1,7 +1,7 @@
From a77f4c6668feb9c991a7985425ce949c5f323f09 Mon Sep 17 00:00:00 2001
From 0b9b897495b16fe4efeb8060a97c00bbbab28c0d Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:34:19 -0700
Subject: [PATCH 03/34] PAM Support
Subject: [PATCH 02/34] PAM Support
#
# To comply to the Solaris PAM policy, the UsePAM option is changed to be
@@ -15,10 +15,10 @@
 1 file changed, 14 insertions(+)
diff --git a/servconf.c b/servconf.c
index b19d30e..c6f4bdd 100644
index 795ddbab..409d4800 100644
--- a/servconf.c
+++ b/servconf.c
@@ -199,7 +199,12 @@ fill_default_server_options(ServerOptions *options)
@@ -194,7 +194,12 @@ fill_default_server_options(ServerOptions *options)
 
     /* Portable-specific options */
     if (options->use_pam == -1)
@@ -30,8 +30,8 @@
+#endif
 
     /* Standard Options */
     if (options->protocol == SSH_PROTO_UNKNOWN)
@@ -1008,8 +1013,17 @@ process_server_config_line(ServerOptions *options, char *line,
     if (options->num_host_key_files == 0) {
@@ -998,8 +1003,17 @@ process_server_config_line(ServerOptions *options, char *line,
     switch (opcode) {
     /* Portable-specific options */
     case sUsePAM:
@@ -50,5 +50,5 @@
     /* Standard Options */
     case sBadOption:
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0003-lastlogin.patch
New file
@@ -0,0 +1,38 @@
From c68ffbb72771d1c8c05f8e92f3d3bf448f2e800d Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:34:41 -0700
Subject: [PATCH 03/34] lastlogin
*** old/servconf.c Wed Sep 17 02:54:26 2014
---
 sshd_config.5 | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/sshd_config.5 b/sshd_config.5
index 32b29d24..9eea74bd 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -1260,8 +1260,8 @@ Specifies whether
 .Xr sshd 8
 should print the date and time of the last user login when a user logs
 in interactively.
-The default is
-.Cm yes .
+On Solaris this option is always ignored since pam_unix_session(5)
+reports the last login time.
 .It Cm PrintMotd
 Specifies whether
 .Xr sshd 8
@@ -1667,7 +1667,8 @@ This file should be writable by root only, but it is recommended
 .El
 .Sh SEE ALSO
 .Xr sftp-server 8 ,
-.Xr sshd 8
+.Xr sshd 8 ,
+.Xr pam_unix_session 5
 .Sh AUTHORS
 .An -nosplit
 OpenSSH is a derivative of the original and free
--
2.11.0
components/network/openssh/patches/0004-Reorganise-man-pages-into-Illumos-numbering-adjust-t.patch
File was renamed from components/network/openssh/patches/0005-Reorganise-man-pages-into-Illumos-numbering-adjust-t.patch
Diff too large
components/network/openssh/patches/0004-lastlogin.patch
File was deleted
components/network/openssh/patches/0005-Deprecated-SunSSH-options.patch
File was renamed from components/network/openssh/patches/0006-Deprecated-SunSSH-options.patch
@@ -1,7 +1,7 @@
From 229f03b20eb7ad551ba02508eb742c2ea5b88e7b Mon Sep 17 00:00:00 2001
From 3d182d824ed1f288830a7e42b6a4a45d5564691a Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:35:12 -0700
Subject: [PATCH 06/34] Deprecated SunSSH options
Subject: [PATCH 05/34] Deprecated SunSSH options
#
# To make the transition from SunSSH to OpenSSH as smooth as possible, we
@@ -16,12 +16,12 @@
 1 file changed, 18 insertions(+)
diff --git a/readconf.c b/readconf.c
index 69d4553..0e955ae 100644
index fa3fab8f..e11a928d 100644
--- a/readconf.c
+++ b/readconf.c
@@ -282,6 +282,24 @@ static struct {
     { "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
@@ -297,6 +297,24 @@ static struct {
     { "ignoreunknown", oIgnoreUnknown },
     { "proxyjump", oProxyJump },
 
+#ifdef DEPRECATE_SUNSSH_OPT
+        /*
@@ -45,5 +45,5 @@
 };
 
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0006-GSS-store-creds-for-Solaris.patch
File was renamed from components/network/openssh/patches/0007-GSS-store-creds-for-Solaris.patch
@@ -1,7 +1,7 @@
From 6d8577b5a662b85a13a56aa8d41a589dc1ad0eae Mon Sep 17 00:00:00 2001
From 8952e72b9cf0f8a14d728feaeb2f5fe85ebbeae0 Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:35:34 -0700
Subject: [PATCH 07/34] GSS store creds for Solaris
Subject: [PATCH 06/34] GSS store creds for Solaris
---
 configure.ac    |  3 +++
@@ -12,10 +12,10 @@
 5 files changed, 71 insertions(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index 7258cc0..5dceabd 100644
index eb9f45dc..f5deed69 100644
--- a/configure.ac
+++ b/configure.ac
@@ -942,6 +942,9 @@ mips-sony-bsd|mips-sony-newsos4)
@@ -949,6 +949,9 @@ mips-sony-bsd|mips-sony-newsos4)
         ],
     )
     TEST_SHELL=$SHELL    # let configure find us a capable shell
@@ -26,7 +26,7 @@
 *-*-sunos4*)
     CPPFLAGS="$CPPFLAGS -DSUNOS4"
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
index 795992d..6e6cff7 100644
index 795992d9..6e6cff7b 100644
--- a/gss-serv-krb5.c
+++ b/gss-serv-krb5.c
@@ -110,7 +110,7 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
@@ -59,7 +59,7 @@
 
 #endif /* KRB5 */
diff --git a/gss-serv.c b/gss-serv.c
index 53993d6..209ffe8 100644
index 53993d67..209ffe82 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -320,22 +320,66 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
@@ -130,10 +130,10 @@
 
 /* This allows GSSAPI methods to do things to the childs environment based
diff --git a/servconf.c b/servconf.c
index c6f4bdd..1872661 100644
index 409d4800..e98c6500 100644
--- a/servconf.c
+++ b/servconf.c
@@ -496,7 +496,11 @@ static struct {
@@ -484,7 +484,11 @@ static struct {
     { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
 #ifdef GSSAPI
     { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
@@ -146,10 +146,10 @@
 #else
     { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
diff --git a/sshd.c b/sshd.c
index 430569c..68fd1ea 100644
index 1dc4d182..e39b3024 100644
--- a/sshd.c
+++ b/sshd.c
@@ -2234,9 +2234,23 @@ main(int ac, char **av)
@@ -2048,9 +2048,23 @@ main(int ac, char **av)
 
 #ifdef GSSAPI
     if (options.gss_authentication) {
@@ -174,5 +174,5 @@
 #endif
 #ifdef USE_PAM
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0007-DTrace-support-for-SFTP.patch
File was renamed from components/network/openssh/patches/0008-DTrace-support-for-SFTP.patch
@@ -1,7 +1,7 @@
From c1905780db9f622c36dae810897d23f66d2faafb Mon Sep 17 00:00:00 2001
From 4afef59e9cfdc88092899a6abdff720d39b0ddd3 Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:35:43 -0700
Subject: [PATCH 08/34] DTrace support for SFTP
Subject: [PATCH 07/34] DTrace support for SFTP
---
 Makefile.in          | 24 ++++++++++++++---
@@ -15,7 +15,7 @@
 create mode 100644 sftp_provider_impl.h
diff --git a/Makefile.in b/Makefile.in
index 11e01ac..61a97de 100644
index 6541b3bb..82065077 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -26,6 +26,7 @@ ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass
@@ -27,14 +27,14 @@
 SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
 STRIP_OPT=@STRIP_OPT@
@@ -85,6 +86,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
     atomicio.o key.o dispatch.o mac.o uidswap.o uuencode.o misc.o \
     atomicio.o key.o dispatch.o mac.o uidswap.o uuencode.o misc.o utf8.o \
     monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
     msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
+    sftp_provider.o \
     ssh-pkcs11.o smult_curve25519_ref.o \
     poly1305.o chacha.o cipher-chachapoly.o \
     ssh-ed25519.o digest-openssl.o digest-libc.o hmac.o \
@@ -110,7 +112,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
@@ -110,7 +112,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \
     sftp-server.o sftp-common.o \
     sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
     sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o \
@@ -56,7 +56,7 @@
     $(LD) -o $@ progressmeter.o sftp.o sftp-client.o sftp-common.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT)
@@ -225,9 +227,22 @@ umac128.o:    umac.c
         -Dumac_update=umac128_update -Dumac_final=umac128_final \
         -Dumac_delete=umac128_delete
         -Dumac_delete=umac128_delete -Dumac_ctx=umac128_ctx
 
+# dtrace sftp
+sftp_provider.h: $(srcdir)/sftp_provider.d
@@ -78,7 +78,7 @@
     rm -f regress/unittests/test_helper/*.a
     rm -f regress/unittests/test_helper/*.o
     rm -f regress/unittests/sshbuf/*.o
@@ -336,6 +351,7 @@ install-files:
@@ -347,6 +362,7 @@ install-files:
     $(INSTALL) -m 644 sftp-server.1m.out $(DESTDIR)$(mandir)/$(mansubdir)1m/sftp-server.1m
     $(INSTALL) -m 644 ssh-keysign.1m.out $(DESTDIR)$(mandir)/$(mansubdir)1m/ssh-keysign.1m
     $(INSTALL) -m 644 ssh-pkcs11-helper.1m.out $(DESTDIR)$(mandir)/$(mansubdir)1m/ssh-pkcs11-helper.1m
@@ -87,10 +87,10 @@
 install-sysconf:
     if [ ! -d $(DESTDIR)$(sysconfdir) ]; then \
diff --git a/sftp-server.c b/sftp-server.c
index e11a1b8..0e6a15a 100644
index 3619cdfc..78167f9d 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -54,6 +54,9 @@
@@ -50,6 +50,9 @@
 
 #include "sftp.h"
 #include "sftp-common.h"
@@ -100,7 +100,7 @@
 
 /* Our verbosity */
 static LogLevel log_level = SYSLOG_LEVEL_ERROR;
@@ -740,14 +743,17 @@ process_read(u_int32_t id)
@@ -736,14 +739,17 @@ process_read(u_int32_t id)
     u_int32_t len;
     int r, handle, fd, ret, status = SSH2_FX_FAILURE;
     u_int64_t off;
@@ -119,7 +119,7 @@
     if (len > sizeof buf) {
         len = sizeof buf;
         debug2("read change len %d", len);
@@ -758,7 +764,13 @@ process_read(u_int32_t id)
@@ -754,7 +760,13 @@ process_read(u_int32_t id)
             error("process_read: seek failed");
             status = errno_to_portable(errno);
         } else {
@@ -133,7 +133,7 @@
             if (ret < 0) {
                 status = errno_to_portable(errno);
             } else if (ret == 0) {
@@ -781,14 +793,16 @@ process_write(u_int32_t id)
@@ -777,14 +789,16 @@ process_write(u_int32_t id)
     size_t len;
     int r, handle, fd, ret, status;
     u_char *data;
@@ -151,7 +151,7 @@
     fd = handle_to_fd(handle);
 
     if (fd < 0)
@@ -800,7 +814,14 @@ process_write(u_int32_t id)
@@ -796,7 +810,14 @@ process_write(u_int32_t id)
             error("process_write: seek failed");
         } else {
 /* XXX ATOMICIO ? */
@@ -168,7 +168,7 @@
                 status = errno_to_portable(errno);
diff --git a/sftp64.d b/sftp64.d
new file mode 100644
index 0000000..8305d0a
index 00000000..8305d0af
--- /dev/null
+++ b/sftp64.d
@@ -0,0 +1,56 @@
@@ -230,7 +230,7 @@
+};
diff --git a/sftp_provider.d b/sftp_provider.d
new file mode 100644
index 0000000..99e9920
index 00000000..99e99202
--- /dev/null
+++ b/sftp_provider.d
@@ -0,0 +1,61 @@
@@ -297,7 +297,7 @@
+#pragma D attributes Evolving/Evolving/ISA provider sftp args
diff --git a/sftp_provider_impl.h b/sftp_provider_impl.h
new file mode 100644
index 0000000..4b18e6e
index 00000000..4b18e6ec
--- /dev/null
+++ b/sftp_provider_impl.h
@@ -0,0 +1,73 @@
@@ -375,5 +375,5 @@
+
+#endif /* _SFTP_PROVIDER_IMPL_H */
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0008-Add-DisableBanner-option.patch
File was renamed from components/network/openssh/patches/0009-Add-DisableBanner-option.patch
@@ -1,40 +1,40 @@
From d0fcfc84c64162fcc8db7f7a9a41912fb257c885 Mon Sep 17 00:00:00 2001
From 09ad0aa54f500a5e3aef488bb4755bd480c4b8fa Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:36:00 -0700
Subject: [PATCH 09/34] Add DisableBanner option
Subject: [PATCH 08/34] Add DisableBanner option
---
 readconf.c    | 31 +++++++++++++++++++++++++++++++
 readconf.h    |  9 +++++++++
 ssh_config.4  |  8 ++++++++
 sshconnect2.c | 17 +++++++++++++++++
 4 files changed, 65 insertions(+)
 sshconnect2.c | 31 +++++++++++++++++++++++++++----
 4 files changed, 75 insertions(+), 4 deletions(-)
diff --git a/readconf.c b/readconf.c
index 0e955ae..dca9c94 100644
index e11a928d..b8c40291 100644
--- a/readconf.c
+++ b/readconf.c
@@ -151,6 +151,9 @@ typedef enum {
@@ -163,6 +163,9 @@ typedef enum {
     oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
     oSendEnv, oControlPath, oControlMaster, oControlPersist,
     oHashKnownHosts,
+#ifdef DISABLE_BANNER
+#ifdef DISABLE_BANNER
+    oDisableBanner,
+#endif
     oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
     oVisualHostKey,
     oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
@@ -258,6 +261,9 @@ static struct {
     { "controlmaster", oControlMaster },
@@ -272,6 +275,9 @@ static struct {
     { "controlpersist", oControlPersist },
     { "hashknownhosts", oHashKnownHosts },
     { "include", oInclude },
+#ifdef DISABLE_BANNER
+    { "disablebanner", oDisableBanner },
+#endif
     { "tunnel", oTunnel },
     { "tunneldevice", oTunnelDevice },
     { "localcommand", oLocalCommand },
@@ -786,6 +792,17 @@ static const struct multistate multistate_canonicalizehostname[] = {
@@ -812,6 +818,17 @@ static const struct multistate multistate_canonicalizehostname[] = {
     { NULL, -1 }
 };
 
@@ -46,27 +46,27 @@
+    { "no",                SSH_DISABLEBANNER_NO },
+    { "in-exec-mode",        SSH_DISABLEBANNER_INEXECMODE },
+    { NULL, -1 }
+};
+};
+#endif
+
 /*
  * Processes a single option line as used in the configuration files. This
  * only sets those values that have not already been set.
@@ -1561,6 +1578,13 @@ parse_keytypes:
         multistate_ptr = multistate_yesnoaskconfirm;
         goto parse_multistate;
@@ -1674,6 +1691,13 @@ parse_keytypes:
         charptr = &options->identity_agent;
         goto parse_string;
 
+#ifdef DISABLE_BANNER
+    case oDisableBanner:
+            intptr = &options->disable_banner;
+                multistate_ptr = multistate_disablebanner;
+                goto parse_multistate;
+                goto parse_multistate;
+#endif
+
     case oDeprecated:
         debug("%s line %d: Deprecated option \"%s\"",
             filename, linenum, keyword);
@@ -1732,6 +1756,9 @@ initialize_options(Options * options)
@@ -1864,6 +1888,9 @@ initialize_options(Options * options)
     options->ip_qos_bulk = -1;
     options->request_tty = -1;
     options->proxy_use_fdpass = -1;
@@ -76,7 +76,7 @@
     options->ignored_unknown = NULL;
     options->num_canonical_domains = 0;
     options->num_permitted_cnames = 0;
@@ -1917,6 +1944,10 @@ fill_default_options(Options * options)
@@ -2058,6 +2085,10 @@ fill_default_options(Options * options)
         options->canonicalize_fallback_local = 1;
     if (options->canonicalize_hostname == -1)
         options->canonicalize_hostname = SSH_CANONICALISE_NO;
@@ -88,11 +88,11 @@
         options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
     if (options->update_hostkeys == -1)
diff --git a/readconf.h b/readconf.h
index c84d068..9aefd9e 100644
index cef55f71..8005ebdd 100644
--- a/readconf.h
+++ b/readconf.h
@@ -159,6 +159,9 @@ typedef struct {
     char   *pubkey_key_types;
@@ -169,6 +169,9 @@ typedef struct {
     char   *jump_extra;
 
     char    *ignored_unknown; /* Pattern list of unknown tokens to ignore */
+#ifdef DISABLE_BANNER
@@ -101,7 +101,7 @@
 }       Options;
 
 #define SSH_CANONICALISE_NO    0
@@ -184,6 +187,12 @@ typedef struct {
@@ -195,6 +198,12 @@ typedef struct {
 #define SSH_UPDATE_HOSTKEYS_YES    1
 #define SSH_UPDATE_HOSTKEYS_ASK    2
 
@@ -115,29 +115,29 @@
 void     fill_default_options(Options *);
 void     fill_default_options_for_canonicalization(Options *);
diff --git a/ssh_config.4 b/ssh_config.4
index e190f6d..b0e22bc 100644
index ff5dc74b..6b790fb7 100644
--- a/ssh_config.4
+++ b/ssh_config.4
@@ -643,6 +643,14 @@ If set to a time in seconds, or a time in any of the formats documented in
@@ -572,6 +572,14 @@ If set to a time in seconds, or a time in any of the formats documented in
 then the backgrounded master connection will automatically terminate
 after it has remained idle (with no client connections) for the
 specified time.
+.It Cm DisableBanner
+If set to yes, disables the display of the  banner  message.
+If set to in-exec-mode, disables the display of banner message when in remote
+If set to in-exec-mode, disables the display of banner message when in remote
+command mode only.
+.Pp
+The default value is no, which means that the banner is displayed unless the
+The default value is no, which means that the banner is displayed unless the
+log level  is  QUIET, FATAL, or ERROR. See also the Banner option in
+.Xr sshd_config 4 . This option applies to protocol version 2 only.
 .It Cm DynamicForward
 Specifies that a TCP port on the local machine be forwarded
 over the secure channel, and the application
diff --git a/sshconnect2.c b/sshconnect2.c
index f79c96b..a32204f 100644
index 103a2b36..56942ca7 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -81,6 +81,10 @@ extern char *client_version_string;
@@ -82,6 +82,10 @@ extern char *client_version_string;
 extern char *server_version_string;
 extern Options options;
 
@@ -148,10 +148,19 @@
 /*
  * SSH2 key exchange
  */
@@ -502,7 +506,20 @@ input_userauth_banner(int type, u_int32_t seq, void *ctxt)
     debug3("input_userauth_banner");
     raw = packet_get_string(&len);
@@ -499,15 +503,34 @@ input_userauth_error(int type, u_int32_t seq, void *ctxt)
 int
 input_userauth_banner(int type, u_int32_t seq, void *ctxt)
 {
-    char *msg, *lang;
+    char *msg, *lang, *raw;
     u_int len;
     debug3("%s", __func__);
-    msg = packet_get_string(&len);
+    raw = packet_get_string(&len);
     lang = packet_get_string(NULL);
-    if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO)
+
+#ifdef DISABLE_BANNER
+    /*
@@ -159,16 +168,25 @@
+     * a banner in error log level or lower. If the log level is higher,
+     * use DisableBanner option to decide whether to display it or not.
+     */
+    if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO &&
+    if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO &&
+            (options.disable_banner == SSH_DISABLEBANNER_NO ||
+            (options.disable_banner == SSH_DISABLEBANNER_INEXECMODE &&
+            buffer_len(&command) == 0))) {
+#else
     if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO) {
+    if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO) {
+#endif
         if (len > 65536)
             len = 65536;
         msg = xmalloc(len * 4 + 1); /* max expansion from strnvis() */
+        if (len > 65536)
+            len = 65536;
+        msg = xmalloc(len * 4 + 1); /* max expansion from strnvis() */
+        strnvis(msg, raw, len * 4 + 1, VIS_SAFE|VIS_OCTAL|VIS_NOSLASH);
         fmprintf(stderr, "%s", msg);
-    free(msg);
+        free(msg);
+    }
+    free(raw);
     free(lang);
     return 0;
 }
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0009-PAM-conversation-fix.patch
New file
@@ -0,0 +1,98 @@
From 021fca2b8ff90ee195aab3ae1ee82b461b752100 Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:36:13 -0700
Subject: [PATCH 09/34] PAM conversation fix
---
 auth-pam.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)
diff --git a/auth-pam.c b/auth-pam.c
index 7d8b2926..ee09b804 100644
--- a/auth-pam.c
+++ b/auth-pam.c
@@ -1130,11 +1130,13 @@ free_pam_environment(char **env)
     free(env);
 }
+#ifndef PAM_BUGFIX
 /*
  * "Blind" conversation function for password authentication.  Assumes that
  * echo-off prompts are for the password and stores messages for later
  * display.
  */
+#endif
 static int
 sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
     struct pam_response **resp, void *data)
@@ -1156,12 +1158,24 @@ sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
     for (i = 0; i < n; ++i) {
         switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
         case PAM_PROMPT_ECHO_OFF:
+#ifdef PAM_BUGFIX
+            /*
+             * PAM conversation function for the password userauth
+             * method (non-interactive) really cannot do any
+             * prompting.  We set the PAM_AUTHTOK item in
+             * sshpam_auth_passwd()to avoid conversation. If some
+             * modules still try to converse, then the password
+             * userauth will fail.
+             */
+            goto fail;
+#else
             if (sshpam_password == NULL)
                 goto fail;
             if ((reply[i].resp = strdup(sshpam_password)) == NULL)
                 goto fail;
             reply[i].resp_retcode = PAM_SUCCESS;
             break;
+#endif
         case PAM_ERROR_MSG:
         case PAM_TEXT_INFO:
             len = strlen(PAM_MSG_MEMBER(msg, i, msg));
@@ -1197,6 +1211,9 @@ static struct pam_conv passwd_conv = { sshpam_passwd_conv, NULL };
 int
 sshpam_auth_passwd(Authctxt *authctxt, const char *password)
 {
+#ifdef PAM_BUGFIX
+    int set_item_rtn;
+#endif
     int flags = (options.permit_empty_passwd == 0 ?
         PAM_DISALLOW_NULL_AUTHTOK : 0);
     char *fake = NULL;
@@ -1217,6 +1234,15 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password)
         options.permit_root_login != PERMIT_YES))
         sshpam_password = fake = fake_password(password);
+#ifdef PAM_BUGFIX
+    sshpam_err = pam_set_item(sshpam_handle, PAM_AUTHTOK, password);
+    if (sshpam_err != PAM_SUCCESS) {
+        debug("PAM: %s: failed to set PAM_AUTHTOK: %s", __func__,
+            pam_strerror(sshpam_handle, sshpam_err));
+        return 0;
+    }
+#endif
+
     sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
         (const void *)&passwd_conv);
     if (sshpam_err != PAM_SUCCESS)
@@ -1228,6 +1254,16 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password)
     free(fake);
     if (sshpam_err == PAM_MAXTRIES)
         sshpam_set_maxtries_reached(1);
+
+#ifdef PAM_BUGFIX
+    set_item_rtn = pam_set_item(sshpam_handle, PAM_AUTHTOK, NULL);
+    if (set_item_rtn != PAM_SUCCESS) {
+        debug("PAM: %s: failed to set PAM_AUTHTOK: %s", __func__,
+            pam_strerror(sshpam_handle, set_item_rtn));
+        return 0;
+    }
+#endif
+
     if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
         debug("PAM: password authentication accepted for %.100s",
             authctxt->user);
--
2.11.0
components/network/openssh/patches/0010-PAM-conversation-fix.patch
File was deleted
components/network/openssh/patches/0010-PAM-enhancements-for-Solaris.patch
File was renamed from components/network/openssh/patches/0011-PAM-enhancements-for-Solaris.patch
@@ -1,38 +1,26 @@
From 44ace33bdb8ac3a8033dabcde4d5c8242fcec169 Mon Sep 17 00:00:00 2001
From ed82a32f2970ccafe09d94de469de246ac8b795f Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:36:19 -0700
Subject: [PATCH 11/34] PAM enhancements for Solaris
Subject: [PATCH 10/34] PAM enhancements for Solaris
#
# This patch contains a couple of PAM enhancements:
#   1) Each SSHv2 userauth method has its own PAM service name so that PAM can
#      be used to control what userauth methods are allowed.
#   2) The PAMServiceName and PAMServicePrefix options.
#
# We have contributed back this feature to the OpenSSH upstream community.
# For more information, see https://bugzilla.mindrot.org/show_bug.cgi?id=2246
# In the future, if these enhancements are accepted by the upsteam in a
# later release, we will remove this patch when we upgrade to that release.
#
---
 auth-pam.c     | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 auth.h         |   3 ++
 auth2.c        |  61 ++++++++++++++++++++++++++++-
 monitor.c      |  63 ++++++++++++++++++++++++++++++
 monitor.c      |  65 +++++++++++++++++++++++++++++++
 monitor.h      |   3 ++
 monitor_wrap.c |  18 +++++++++
 servconf.c     |  56 +++++++++++++++++++++++++++
 servconf.h     |  10 +++++
 sshd.1m        |  27 +++++++++++++
 sshd.c         |   5 +++
 sshd_config.4  |  18 ++++++++-
 11 files changed, 379 insertions(+), 4 deletions(-)
 10 files changed, 376 insertions(+), 4 deletions(-)
diff --git a/auth-pam.c b/auth-pam.c
index 92c3b1c..4ca0a58 100644
index ee09b804..70a25c19 100644
--- a/auth-pam.c
+++ b/auth-pam.c
@@ -618,6 +618,72 @@ sshpam_cleanup(void)
@@ -617,6 +617,72 @@ sshpam_cleanup(void)
     sshpam_handle = NULL;
 }
 
@@ -89,14 +77,14 @@
+             * Although OpenSSH only supports "gssapi-with-mic"
+             * for now. We will still map any userauth method
+                         * prefixed with "gssapi-" to the gssapi PAM service.
+             */
+             */
+            snprintf(svcname, BUFSIZ, "%s-gssapi",
+                options.pam_service_prefix);
+        }
+        return svcname;
+    } else {
+        /* SSHv1 doesn't get to be so cool */
+            snprintf(svcname, BUFSIZ, "sshd-v1");
+        snprintf(svcname, BUFSIZ, "sshd-v1");
+    }
+    return svcname;
+}
@@ -105,9 +93,9 @@
 static int
 sshpam_init(Authctxt *authctxt)
 {
@@ -625,18 +691,71 @@ sshpam_init(Authctxt *authctxt)
     const char *pam_rhost, *pam_user, *user = authctxt->user;
@@ -624,18 +690,71 @@ sshpam_init(Authctxt *authctxt)
     const char **ptr_pam_user = &pam_user;
     struct ssh *ssh = active_state; /* XXX */
 
+#ifdef PAM_ENHANCEMENT
+    const char *pam_service;
@@ -123,35 +111,35 @@
+            /* get the pam service name */
+        sshpam_err = pam_get_item(sshpam_handle,
+            PAM_SERVICE, (sshpam_const void **)ptr_pam_service);
+                if (sshpam_err != PAM_SUCCESS)
+        if (sshpam_err != PAM_SUCCESS)
+            fatal("Failed to get the PAM service name");
+        debug3("Previous pam_service is %s", pam_service ?
+                    pam_service : "NULL");
+            pam_service : "NULL");
+
+        /* get the pam user name */
+        sshpam_err = pam_get_item(sshpam_handle,
+            PAM_USER, (sshpam_const void **)ptr_pam_user);
+
+        /*
+         * only need to re-start if either user or service is
+         * only need to re-start if either user or service is
+                 * different.
+                 */
+        if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0
+            && strncmp(svc, pam_service, strlen(svc)) == 0) {
+                free(svc);
+            free(svc);
+            return (0);
+                }
+        }
+
+        /*
+         * Clean up previous PAM state.  No need to clean up session
+         * Clean up previous PAM state.  No need to clean up session
+         * and creds.
+         */
+                sshpam_authenticated = 0;
+                sshpam_account_status = -1;
+        sshpam_authenticated = 0;
+        sshpam_account_status = -1;
+
+        sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, NULL);
+             if (sshpam_err != PAM_SUCCESS)
+                debug3("Cannot remove PAM conv"); /* a warning only */
+        if (sshpam_err != PAM_SUCCESS)
+            debug3("Cannot remove PAM conv"); /* a warning only */
+#else /* Original */
         /* We already have a PAM context; check if the user matches */
         sshpam_err = pam_get_item(sshpam_handle,
@@ -178,7 +166,7 @@
 
     if (sshpam_err != PAM_SUCCESS) {
diff --git a/auth.h b/auth.h
index 2160154..985053c 100644
index 338a62da..4a7f2c1f 100644
--- a/auth.h
+++ b/auth.h
@@ -81,6 +81,9 @@ struct Authctxt {
@@ -186,13 +174,13 @@
     struct sshkey    **prev_userkeys;
     u_int         nprev_userkeys;
+#ifdef PAM_ENHANCEMENT
+        char            *authmethod_name;
+#endif
+    char        *authmethod_name;
+#endif
 };
 /*
  * Every authentication method has to handle authentication requests for
diff --git a/auth2.c b/auth2.c
index 7177962..32ba663 100644
index 9108b861..4623ae02 100644
--- a/auth2.c
+++ b/auth2.c
@@ -243,10 +243,21 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
@@ -207,7 +195,7 @@
+         * Start PAM here and once only, if each userauth does not
+         * has its own PAM service.
+         */
+            if (options.use_pam && !options.pam_service_per_authmethod)
+        if (options.use_pam && !options.pam_service_per_authmethod)
+            PRIVSEP(start_pam(authctxt));
+#else
         if (options.use_pam)
@@ -224,13 +212,13 @@
+
+#if defined(USE_PAM) && defined(PAM_ENHANCEMENT)
+        /* start PAM service for each userauth */
+                if (options.use_pam && options.pam_service_per_authmethod) {
+                       if (authctxt->authmethod_name != NULL)
+                        free(authctxt->authmethod_name);
+                        authctxt->authmethod_name = xstrdup(method);
+                        if (use_privsep)
+                                mm_inform_authmethod(method);
+                PRIVSEP(start_pam(authctxt));
+        if (options.use_pam && options.pam_service_per_authmethod) {
+            if (authctxt->authmethod_name != NULL)
+                free(authctxt->authmethod_name);
+            authctxt->authmethod_name = xstrdup(method);
+            if (use_privsep)
+                mm_inform_authmethod(method);
+            PRIVSEP(start_pam(authctxt));
+        }
+#endif
         debug2("input_userauth_request: try method %s", method);
@@ -254,8 +242,8 @@
+
+#if defined(USE_PAM) && defined(PAM_ENHANCEMENT)
+                /*
+                 * If each userauth has its own PAM service, then PAM need to
+                 * perform account check for this service.
+                 * If each userauth has its own PAM service, then PAM needs to
+                 * perform the account check for this service.
+                 */
+                if (options.use_pam && options.pam_service_per_authmethod &&
+                    !PRIVSEP(do_pam_account())) {
@@ -282,12 +270,12 @@
+        /*
+         * PAM needs to perform account checks after auth. However, if each
+         * userauth has its own PAM service and options.num_auth_methods != 0,
+         * then no need to perform account checking, because it was done
+         * then no need to perform account checking, because it was done
+         * already.
+         */
+        if (options.use_pam && authenticated &&
+            !(options.num_auth_methods != 0 &&
+            options.pam_service_per_authmethod)){
+    if (options.use_pam && authenticated &&
+        !(options.num_auth_methods != 0 &&
+        options.pam_service_per_authmethod)) {
+#else
     if (options.use_pam && authenticated) {
+#endif
@@ -301,10 +289,10 @@
-
-
diff --git a/monitor.c b/monitor.c
index ac7dd30..63bde62 100644
index 43f48470..8f044f4e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -126,6 +126,9 @@ int mm_answer_sign(int, Buffer *);
@@ -127,6 +127,9 @@ int mm_answer_sign(int, Buffer *);
 int mm_answer_pwnamallow(int, Buffer *);
 int mm_answer_auth2_read_banner(int, Buffer *);
 int mm_answer_authserv(int, Buffer *);
@@ -314,7 +302,7 @@
 int mm_answer_authpassword(int, Buffer *);
 int mm_answer_bsdauthquery(int, Buffer *);
 int mm_answer_bsdauthrespond(int, Buffer *);
@@ -205,10 +208,17 @@ struct mon_table mon_dispatch_proto20[] = {
@@ -202,10 +205,17 @@ struct mon_table mon_dispatch_proto20[] = {
     {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
     {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
     {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
@@ -330,34 +318,35 @@
     {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
+#endif
     {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
     {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
     {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
@@ -370,6 +380,24 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
             if (!compat20)
                 fatal("AuthenticationMethods is not supported"
                     "with SSH protocol 1");
     {MONITOR_REQ_PAM_INIT_CTX, MON_ONCE, mm_answer_pam_init_ctx},
     {MONITOR_REQ_PAM_QUERY, 0, mm_answer_pam_query},
@@ -311,6 +321,25 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
         /* Special handling for multiple required authentications */
         if (options.num_auth_methods != 0) {
+
+#if defined(USE_PAM) && defined(PAM_ENHANCEMENT)
+                        /*
+                         * If each userauth has its own PAM service, then PAM
+                         * need to perform account check for this service.
+                         */
+                        if (options.use_pam && authenticated &&
+                            options.pam_service_per_authmethod) {
+                                Buffer m;
+            /*
+             * If each userauth has its own PAM service, then PAM
+             * need to perform account check for this service.
+             */
+            if (options.use_pam && authenticated &&
+                options.pam_service_per_authmethod) {
+                Buffer m;
+
+                                buffer_init(&m);
+                                mm_request_receive_expect(pmonitor->m_sendfd,
+                                    MONITOR_REQ_PAM_ACCOUNT, &m);
+                                authenticated =
+                                    mm_answer_pam_account(pmonitor->m_sendfd, &m);
+                                buffer_free(&m);
+                         }
+                buffer_init(&m);
+                mm_request_receive_expect(pmonitor->m_sendfd,
+                    MONITOR_REQ_PAM_ACCOUNT, &m);
+                authenticated = mm_answer_pam_account(
+                    pmonitor->m_sendfd, &m);
+                buffer_free(&m);
+            }
+#endif
+
             if (authenticated &&
                 !auth2_update_methods_lists(authctxt,
                 auth_method, auth_submethod)) {
@@ -388,8 +416,21 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
@@ -329,8 +358,21 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
                 !auth_root_allowed(auth_method))
                 authenticated = 0;
 #ifdef USE_PAM
@@ -366,12 +355,12 @@
+                         * PAM needs to perform account checks after auth.
+                         * However, if each userauth has its own PAM service
+                         * and options.num_auth_methods != 0, then no need to
+                         * perform account checking, because it was done
+                         * perform account checking, because it was done
+                         * already.
+                         */
+                        if (options.use_pam && authenticated &&
+                            !(options.num_auth_methods != 0 &&
+                            options.pam_service_per_authmethod)) {
+            if (options.use_pam && authenticated &&
+                !(options.num_auth_methods != 0 &&
+                options.pam_service_per_authmethod)) {
+#else
             /* PAM needs to perform account checks after auth */
             if (options.use_pam && authenticated) {
@@ -379,18 +368,19 @@
                 Buffer m;
 
                 buffer_init(&m);
@@ -859,6 +900,10 @@ mm_answer_pwnamallow(int sock, Buffer *m)
         /* Allow service/style information on the auth context */
         monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
         monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1);
@@ -771,6 +813,11 @@ mm_answer_pwnamallow(int sock, Buffer *m)
     monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
     monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1);
+#ifdef PAM_ENHANCEMENT
+                /* Allow authmethod information on the auth context */
+        monitor_permit(mon_dispatch, MONITOR_REQ_AUTHMETHOD, 1);
+    /* Allow authmethod information on the auth context */
+    monitor_permit(mon_dispatch, MONITOR_REQ_AUTHMETHOD, 1);
+#endif
     }
+
 #ifdef USE_PAM
     if (options.use_pam)
@@ -899,6 +944,24 @@ mm_answer_authserv(int sock, Buffer *m)
         monitor_permit(mon_dispatch, MONITOR_REQ_PAM_START, 1);
@@ -810,6 +857,24 @@ mm_answer_authserv(int sock, Buffer *m)
     return (0);
 }
 
@@ -416,7 +406,7 @@
 mm_answer_authpassword(int sock, Buffer *m)
 {
diff --git a/monitor.h b/monitor.h
index 93b8b66..da63e7d 100644
index d68f6745..36e73f79 100644
--- a/monitor.h
+++ b/monitor.h
@@ -65,6 +65,9 @@ enum monitor_reqtype {
@@ -424,13 +414,13 @@
     MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
 
+#ifdef PAM_ENHANCEMENT
+        MONITOR_REQ_AUTHMETHOD = 114,
+#endif
+    MONITOR_REQ_AUTHMETHOD = 114,
+#endif
 };
 
 struct mm_master;
 struct monitor {
diff --git a/monitor_wrap.c b/monitor_wrap.c
index c5db6df..30e3c15 100644
index 64ff9288..bc6382f3 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -345,6 +345,24 @@ mm_inform_authserv(char *service, char *style)
@@ -459,18 +449,18 @@
 int
 mm_auth_password(Authctxt *authctxt, char *password)
diff --git a/servconf.c b/servconf.c
index 1872661..b16a8be 100644
index e98c6500..36eb9057 100644
--- a/servconf.c
+++ b/servconf.c
@@ -169,6 +169,18 @@ initialize_server_options(ServerOptions *options)
     options->ip_qos_bulk = -1;
@@ -164,6 +164,18 @@ initialize_server_options(ServerOptions *options)
     options->version_addendum = NULL;
     options->fingerprint_hash = -1;
     options->disable_forwarding = -1;
+#ifdef PAM_ENHANCEMENT
+    options->pam_service_name = NULL;
+    options->pam_service_prefix = NULL;
+
+    /*
+    /*
+     * Each user method will have its own PAM service by default.
+     * However, if PAMServiceName is specified or the protocal version
+     * is not compat20, then there will be only one PAM service for the
@@ -481,7 +471,7 @@
 }
 
 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
@@ -352,6 +364,12 @@ fill_default_server_options(ServerOptions *options)
@@ -330,6 +342,12 @@ fill_default_server_options(ServerOptions *options)
         options->ip_qos_bulk = IPTOS_THROUGHPUT;
     if (options->version_addendum == NULL)
         options->version_addendum = xstrdup("");
@@ -494,7 +484,7 @@
     if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
         options->fwd_opts.streamlocal_bind_mask = 0177;
     if (options->fwd_opts.streamlocal_bind_unlink == -1)
@@ -428,6 +446,9 @@ typedef enum {
@@ -416,6 +434,9 @@ typedef enum {
     sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
     sUsePrivilegeSeparation, sAllowAgentForwarding,
     sHostCertificate,
@@ -504,7 +494,7 @@
     sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
     sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
     sKexAlgorithms, sIPQoS, sVersionAddendum,
@@ -566,6 +587,10 @@ static struct {
@@ -554,6 +575,10 @@ static struct {
     { "forcecommand", sForceCommand, SSHCFG_ALL },
     { "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
     { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
@@ -515,7 +505,7 @@
     { "revokedkeys", sRevokedKeys, SSHCFG_ALL },
     { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
     { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
@@ -1868,6 +1893,37 @@ process_server_config_line(ServerOptions *options, char *line,
@@ -1854,6 +1879,37 @@ process_server_config_line(ServerOptions *options, char *line,
             options->fingerprint_hash = value;
         break;
 
@@ -551,10 +541,10 @@
+        break;
+
     case sDeprecated:
         logit("%s line %d: Deprecated option %s",
             filename, linenum, arg);
     case sIgnore:
     case sUnsupported:
diff --git a/servconf.h b/servconf.h
index f4137af..8c86b57 100644
index 5853a974..104852f7 100644
--- a/servconf.h
+++ b/servconf.h
@@ -54,6 +54,10 @@
@@ -568,7 +558,7 @@
 typedef struct {
     u_int    num_ports;
     u_int    ports_from_cmdline;
@@ -194,6 +198,12 @@ typedef struct {
@@ -188,6 +192,12 @@ typedef struct {
     u_int    num_auth_methods;
     char   *auth_methods[MAX_AUTH_METHODS];
 
@@ -577,15 +567,15 @@
+    char   *pam_service_name;
+    int    pam_service_per_authmethod;
+#endif
+
+
     int    fingerprint_hash;
 }       ServerOptions;
 
diff --git a/sshd.1m b/sshd.1m
index dac5c14..500c4d5 100644
index b767cc7a..387ea69e 100644
--- a/sshd.1m
+++ b/sshd.1m
@@ -977,6 +977,33 @@ concurrently for different ports, this contains the process ID of the one
@@ -920,6 +920,33 @@ concurrently for different ports, this contains the process ID of the one
 started last).
 The content of this file is not sensitive; it can be world-readable.
 .El
@@ -619,58 +609,42 @@
 .Sh SEE ALSO
 .Xr scp 1 ,
 .Xr sftp 1 ,
diff --git a/sshd.c b/sshd.c
index 68fd1ea..418e1fd 100644
--- a/sshd.c
+++ b/sshd.c
@@ -2165,6 +2165,11 @@ main(int ac, char **av)
     sshd_exchange_identification(sock_in, sock_out);
+#ifdef PAM_ENHANCEMENT
+    if (!compat20)
+            options.pam_service_per_authmethod = 0;
+#endif
+
     /* In inetd mode, generate ephemeral key only for proto 1 connections */
     if (!compat20 && inetd_flag && sensitive_data.server_key == NULL)
         generate_ephemeral_server_key();
diff --git a/sshd_config.4 b/sshd_config.4
index 6351b43..f45ddef 100644
index efb10c97..7e4a376b 100644
--- a/sshd_config.4
+++ b/sshd_config.4
@@ -1168,6 +1168,21 @@ The probability increases linearly and all connection attempts
 are refused if the number of unauthenticated connections reaches
 .Dq full
 (60).
@@ -1117,6 +1117,21 @@ will refuse connection attempts with a probability of rate/100 (30%)
 if there are currently start (10) unauthenticated connections.
 The probability increases linearly and all connection attempts
 are refused if the number of unauthenticated connections reaches full (60).
+.It Cm PAMServiceName
+Specifies the PAM service name for the PAM session. The PAMServiceName and
+Specifies the PAM service name for the PAM session. The PAMServiceName and
+PAMServicePrefix options are mutually exclusive and if both set, sshd does not
+start. If this option is set the service name is the same for all user
+authentication methods. The option has no default value. See PAMServicePrefix
+start. If this option is set the service name is the same for all user
+authentication methods. The option has no default value. See PAMServicePrefix
+for more information.
+.It Cm PAMServicePrefix
+Specifies the PAM service name prefix for service names used for individual
+user authentication methods. The default is sshd. The PAMServiceName and
+PAMServicePrefix options are mutually exclusive and if both set, sshd does not
+Specifies the PAM service name prefix for service names used for individual
+user authentication methods. The default is sshd. The PAMServiceName and
+PAMServicePrefix options are mutually exclusive and if both set, sshd does not
+start.
+.Pp
+For example, if this option is set to admincli, the service name for the
+keyboard-interactive authentication method is admincli-kbdint instead of the
+For example, if this option is set to admincli, the service name for the
+keyboard-interactive authentication method is admincli-kbdint instead of the
+default sshd-kbdint.
 .It Cm PasswordAuthentication
 Specifies whether password authentication is allowed.
 The default is
@@ -1582,8 +1597,7 @@ If
@@ -1472,8 +1487,7 @@ If
 is enabled, you will not be able to run
 .Xr sshd 1M
 as a non-root user.
-The default is
-.Dq no .
-.Cm no .
+On Solaris, the option is always enabled.
 .It Cm UsePrivilegeSeparation
 Specifies whether
 .Xr sshd 1M
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0011-SunSSH-compat-default-config-values.patch
New file
@@ -0,0 +1,151 @@
From 7081a3dbfcee88b8b813cc0dbba8bf1479d356cb Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:36:22 -0700
Subject: [PATCH 11/34] SunSSH compat default config values
Some options in OpenSSH have different default values from those in SunSSH.
To make the transition smoother from SunSSH to OpenSSH, we change default
values for the following options to be as same as those in SunSSH.
  GSSAPIAuthentication (for both server and client)
  X11Forwarding        (for server)
  ForwardX11Trusted    (for client)
This is for Solaris only, we will not contribute back these changes to the
upstream.
---
 readconf.c    | 8 ++++++++
 servconf.c    | 8 ++++++++
 ssh_config.4  | 7 +++++--
 sshd_config.4 | 8 ++++----
 4 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/readconf.c b/readconf.c
index b8c40291..e6fd1420 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1931,7 +1931,11 @@ fill_default_options(Options * options)
     if (options->forward_x11 == -1)
         options->forward_x11 = 0;
     if (options->forward_x11_trusted == -1)
+#ifdef OPTION_DEFAULT_VALUE
+        options->forward_x11_trusted = 1;
+#else
         options->forward_x11_trusted = 0;
+#endif
     if (options->forward_x11_timeout == -1)
         options->forward_x11_timeout = 1200;
     /*
@@ -1964,7 +1968,11 @@ fill_default_options(Options * options)
     if (options->challenge_response_authentication == -1)
         options->challenge_response_authentication = 1;
     if (options->gss_authentication == -1)
+#ifdef OPTION_DEFAULT_VALUE
+        options->gss_authentication = 1;
+#else
         options->gss_authentication = 0;
+#endif
     if (options->gss_deleg_creds == -1)
         options->gss_deleg_creds = 0;
     if (options->password_authentication == -1)
diff --git a/servconf.c b/servconf.c
index 36eb9057..6f11010a 100644
--- a/servconf.c
+++ b/servconf.c
@@ -249,7 +249,11 @@ fill_default_server_options(ServerOptions *options)
     if (options->print_lastlog == -1)
         options->print_lastlog = 1;
     if (options->x11_forwarding == -1)
+#ifdef OPTION_DEFAULT_VALUE
+        options->x11_forwarding = 1;
+#else
         options->x11_forwarding = 0;
+#endif
     if (options->x11_display_offset == -1)
         options->x11_display_offset = 10;
     if (options->x11_use_localhost == -1)
@@ -283,7 +287,11 @@ fill_default_server_options(ServerOptions *options)
     if (options->kerberos_get_afs_token == -1)
         options->kerberos_get_afs_token = 0;
     if (options->gss_authentication == -1)
+#ifdef OPTION_DEFAULT_VALUE
+        options->gss_authentication = 1;
+#else
         options->gss_authentication = 0;
+#endif
     if (options->gss_cleanup_creds == -1)
         options->gss_cleanup_creds = 1;
     if (options->gss_strict_acceptor == -1)
diff --git a/ssh_config.4 b/ssh_config.4
index 6b790fb7..0953f11c 100644
--- a/ssh_config.4
+++ b/ssh_config.4
@@ -728,6 +728,9 @@ Furthermore, the
 token used for the session will be set to expire after 20 minutes.
 Remote clients will be refused access after this time.
 .Pp
+The default on Solaris is
+.Dq yes .
+.Pp
 See the X11 SECURITY extension specification for full details on
 the restrictions imposed on untrusted clients.
 .It Cm GatewayPorts
@@ -754,8 +757,8 @@ The default is
 .Pa /etc/ssh/ssh_known_hosts2 .
 .It Cm GSSAPIAuthentication
 Specifies whether user authentication based on GSSAPI is allowed.
-The default is
-.Cm no .
+The default on Solaris is
+.Dq yes .
 .It Cm GSSAPIDelegateCredentials
 Forward (delegate) credentials to the server.
 The default is
diff --git a/sshd_config.4 b/sshd_config.4
index 7e4a376b..45c54629 100644
--- a/sshd_config.4
+++ b/sshd_config.4
@@ -621,8 +621,8 @@ The default is
 .Cm no .
 .It Cm GSSAPIAuthentication
 Specifies whether user authentication based on GSSAPI is allowed.
-The default is
-.Cm no .
+The default on Solaris is
+.Cm yes .
 .It Cm GSSAPICleanupCredentials
 Specifies whether to automatically destroy the user's credentials cache
 on logout.
@@ -1527,8 +1527,8 @@ The argument must be
 .Cm yes
 or
 .Cm no .
-The default is
-.Cm no .
+The default on Solaris is
+.Cm yes .
 .Pp
 When X11 forwarding is enabled, there may be additional exposure to
 the server and to client displays if the
--- openssh-7.4p1/sshd_config.1    2017-03-27 13:57:07.982442673 +0300
+++ openssh-7.4p1/sshd_config    2017-03-27 13:57:23.383736783 +0300
@@ -72,7 +72,7 @@
 #KerberosGetAFSToken no
 # GSSAPI options
-#GSSAPIAuthentication no
+#GSSAPIAuthentication yes
 #GSSAPICleanupCredentials yes
 #GSSAPIStrictAcceptorCheck yes
 #GSSAPIKeyExchange no
--- openssh-7.4p1/ssh_config.1    2017-03-27 13:58:08.152109125 +0300
+++ openssh-7.4p1/ssh_config    2017-03-27 13:58:16.102388539 +0300
@@ -24,7 +24,7 @@
 #   RSAAuthentication yes
 #   PasswordAuthentication yes
 #   HostbasedAuthentication no
-#   GSSAPIAuthentication no
+#   GSSAPIAuthentication yes
 #   GSSAPIDelegateCredentials no
 #   GSSAPIKeyExchange no
 #   GSSAPITrustDNS no
components/network/openssh/patches/0012-Deprecate-SunSSH-compatible-server-options.patch
File was renamed from components/network/openssh/patches/0013-Deprecate-SunSSH-compatible-server-options.patch
@@ -1,7 +1,7 @@
From 60e5aa52c6b3504b937ecf455be4b95d6ae1656c Mon Sep 17 00:00:00 2001
From 099bbc48c48f25dc657a6c2b4c1521ba9023f380 Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:36:33 -0700
Subject: [PATCH 13/34] Deprecate SunSSH compatible server options
Subject: [PATCH 12/34] Deprecate SunSSH compatible server options
#
# Originally we planned to only deprecate client config (ssh_config) options
@@ -23,10 +23,10 @@
 1 file changed, 23 insertions(+)
diff --git a/servconf.c b/servconf.c
index bac51a3..434cafc 100644
index 6f11010a..c0aba508 100644
--- a/servconf.c
+++ b/servconf.c
@@ -599,6 +599,29 @@ static struct {
@@ -587,6 +587,29 @@ static struct {
     { "pamserviceprefix", sPAMServicePrefix, SSHCFG_GLOBAL },
     { "pamservicename", sPAMServiceName, SSHCFG_GLOBAL },
 #endif
@@ -57,5 +57,5 @@
     { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
     { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0012-SunSSH-compat-default-config-values.patch
File was deleted
components/network/openssh/patches/0013-Solaris-Auditing-support.patch
File was renamed from components/network/openssh/patches/0014-Solaris-Auditing-support.patch
@@ -1,46 +1,24 @@
From 785d51f8667359a362893f13e8762d0e814ceeda Mon Sep 17 00:00:00 2001
From dad178a7fb894660036982a75b4e1c30e71cbd33 Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:37:01 -0700
Subject: [PATCH 14/34] Solaris Auditing support
Subject: [PATCH 13/34] Solaris Auditing support
#
# Add Solaris Auditing configuration (--with-audit=solaris) to openssh-6.5p1.
#
# Add phase 1 Solaris Auditing of sshd login/logout to openssh-6.5p1.
#
# Additional Solaris Auditing should include audit of password
#  change.
# Presuming it is appropriate, this patch should/will be updated
#  with additional files and updates to sources/audit-solaris.c
#
# Code is developed by the Solaris Audit team.
# It should/will likely be contributed up stream when done.
# This patch relies on sources/audit-solaris.c being copied into
#  the openssh source directory by the Makefile that configures
#  using --with-audit=solaris.
#
# The up stream community has been contacted about the plans.
#  No reply has yet been received.
#
# An additional patch relying on the --with-audit=solaris configuration
#  should/will be created for sftp Solaris Audit and password change.
#
---
 INSTALL         |  15 +-
 Makefile.in     |   2 +-
 README.platform |   7 +-
 audit-solaris.c | 562 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 audit-solaris.c | 574 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 configure.ac    |   9 +-
 defines.h       |   5 +
 sshd.c          |   6 +
 7 files changed, 597 insertions(+), 9 deletions(-)
 7 files changed, 609 insertions(+), 9 deletions(-)
 create mode 100644 audit-solaris.c
diff --git a/INSTALL b/INSTALL
index cbbb2df..765d4aa 100644
index 6bc80b68..03417493 100644
--- a/INSTALL
+++ b/INSTALL
@@ -92,9 +92,13 @@ http://www.gnu.org/software/autoconf/
@@ -98,9 +98,13 @@ http://www.gnu.org/software/autoconf/
 
 Basic Security Module (BSM):
 
@@ -57,7 +35,7 @@
 
 
 2. Building / Installation
@@ -147,8 +151,9 @@ name).
@@ -153,8 +157,9 @@ name).
 There are a few other options to the configure script:
 
 --with-audit=[module] enable additional auditing via the specified module.
@@ -70,20 +48,20 @@
 --with-pam enables PAM support. If PAM support is compiled in, it must
 also be enabled in sshd_config (refer to the UsePAM directive).
diff --git a/Makefile.in b/Makefile.in
index 61a97de..abc9285 100644
index 82065077..48d773de 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -100,7 +100,7 @@ SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
     sshconnect.o sshconnect1.o sshconnect2.o mux.o
 
 SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
 SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \
-    audit.o audit-bsm.o audit-linux.o platform.o \
+    audit.o audit-bsm.o audit-linux.o audit-solaris.o platform.o \
     sshpty.o sshlogin.o servconf.o serverloop.o \
     auth.o auth1.o auth2.o auth-options.o session.o \
     auth-chall.o auth2-chall.o groupaccess.o \
     auth.o auth2.o auth-options.o session.o \
     auth2-chall.o groupaccess.o \
diff --git a/README.platform b/README.platform
index 8d75c16..616200b 100644
index c7be95fb..ae461550 100644
--- a/README.platform
+++ b/README.platform
@@ -71,8 +71,8 @@ zlib-devel and pam-devel, on Debian based distros these may be
@@ -109,7 +87,7 @@
 -------------------
diff --git a/audit-solaris.c b/audit-solaris.c
new file mode 100644
index 0000000..abf870c
index 00000000..fc0839f5
--- /dev/null
+++ b/audit-solaris.c
@@ -0,0 +1,574 @@
@@ -294,31 +272,23 @@
+    if (adt_load_termid(peer, &tid) != 0) {
+        error("adt audit_connection_from: unable to load tid for %d:%s",
+            peer, strerror(errno));
+        return;
+        goto err;
+    }
+    if (adt_start_session(&ah, NULL, 0) != 0) {
+        error("adt audit_connection_from: unable to start session "
+            "for %s:%d:%s", host, port, strerror(errno));
+        free(tid);
+        tid = NULL;
+        return;
+        goto err;
+    }
+    if (adt_set_user(ah, ADT_NO_AUDIT, ADT_NO_AUDIT, 0,
+        ADT_NO_AUDIT, tid, ADT_SETTID) != 0) {
+        error("adt audit_connection_from: unable to set user "
+            "for %s:%d:%s", host, port, strerror(errno));
+        free(tid);
+        tid = NULL;
+        (void) adt_end_session(ah);
+        return;
+        goto err;
+    }
+    if (adt_set_proc(ah) != 0) {
+        error("adt audit_connection_from: unable to set proc "
+            "for %s:%d:%s", host, port, strerror(errno));
+        free(tid);
+        tid = NULL;
+        (void) adt_end_session(ah);
+        return;
+        goto err;
+    }
+    (void) adt_end_session(ah);
+    debug("adt audit_connection_from(%s, %d): peerfd=%d", host, port,
@@ -327,6 +297,14 @@
+        "peerfd=%d\n", getpid(), getuid(), geteuid(), host, port,
+        (void *)the_authctxt, peer);
+    __audit_pidinfo();
+    return;
+
+err:
+    free(tid);
+    tid = NULL;
+    if (ah != NULL) {
+        (void) adt_end_session(ah);
+    }
+}
+
+/*
@@ -688,10 +666,10 @@
+}
+#endif    /* USE_SOLARIS_AUDIT */
diff --git a/configure.ac b/configure.ac
index 5dceabd..4192a45 100644
index f5deed69..7a36eee9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1551,7 +1551,7 @@ AC_ARG_WITH([libedit],
@@ -1561,7 +1561,7 @@ AC_ARG_WITH([libedit],
 
 AUDIT_MODULE=none
 AC_ARG_WITH([audit],
@@ -700,7 +678,7 @@
     [
       AC_MSG_CHECKING([for supported audit module])
       case "$withval" in
@@ -1588,6 +1588,13 @@ AC_ARG_WITH([audit],
@@ -1598,6 +1598,13 @@ AC_ARG_WITH([audit],
         SSHDLIBS="$SSHDLIBS -laudit"
         AC_DEFINE([USE_LINUX_AUDIT], [1], [Use Linux audit module])
         ;;
@@ -715,10 +693,10 @@
         AUDIT_MODULE=debug
         AC_MSG_RESULT([debug])
diff --git a/defines.h b/defines.h
index a438ddd..6196188 100644
index c89f85a8..a2ec7361 100644
--- a/defines.h
+++ b/defines.h
@@ -635,6 +635,11 @@ struct winsize {
@@ -645,6 +645,11 @@ struct winsize {
 # define CUSTOM_SSH_AUDIT_EVENTS
 #endif
 
@@ -731,10 +709,10 @@
 #  define __func__ __FUNCTION__
 #elif !defined(HAVE___func__)
diff --git a/sshd.c b/sshd.c
index 418e1fd..37cb5fa 100644
index e39b3024..eee363ab 100644
--- a/sshd.c
+++ b/sshd.c
@@ -2234,7 +2234,9 @@ main(int ac, char **av)
@@ -2043,7 +2043,9 @@ main(int ac, char **av)
     }
 
 #ifdef SSH_AUDIT_EVENTS
@@ -744,7 +722,7 @@
 #endif
 
 #ifdef GSSAPI
@@ -2264,6 +2266,10 @@ main(int ac, char **av)
@@ -2073,6 +2075,10 @@ main(int ac, char **av)
         do_pam_session();
     }
 #endif
@@ -756,5 +734,5 @@
     /*
      * In privilege separation, we fork another child and prepare
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0014-GSS-API-key-exchange-support.patch
New file
@@ -0,0 +1,3303 @@
From 278ee810256afaeddb45f851ce71d5c6fdb70792 Mon Sep 17 00:00:00 2001
From: Simon Wilkinson <simon@sxw.org.uk>
Date: Fri, 27 Jan 2017 16:46:31 -0800
Subject: [PATCH 14/34] GSS-API key exchange support
---
 ChangeLog.gssapi | 113 +++++++++++++++++++
 Makefile.in      |   3 +-
 auth-krb5.c      |  17 ++-
 auth.c           |  96 +---------------
 auth2-gss.c      |  48 +++++++-
 auth2.c          |   2 +
 canohost.c       |  93 +++++++++++++++
 canohost.h       |   3 +
 clientloop.c     |  15 ++-
 configure.ac     |  24 ++++
 gss-genr.c       | 275 +++++++++++++++++++++++++++++++++++++++++++-
 gss-serv-krb5.c  |  87 ++++++++++++--
 gss-serv.c       | 224 +++++++++++++++++++++++++++++++++---
 kex.c            |  19 ++++
 kex.h            |  14 +++
 kexgssc.c        | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 kexgsss.c        | 296 ++++++++++++++++++++++++++++++++++++++++++++++++
 monitor.c        | 115 +++++++++++++++++--
 monitor.h        |   2 +
 monitor_wrap.c   |  47 +++++++-
 monitor_wrap.h   |   4 +-
 readconf.c       |  42 +++++++
 readconf.h       |   5 +
 servconf.c       |  28 ++++-
 servconf.h       |   2 +
 ssh-gss.h        |  41 ++++++-
 ssh_config       |   2 +
 ssh_config.4     |  32 ++++++
 sshconnect2.c    | 131 ++++++++++++++++++++-
 sshd.c           | 112 +++++++++++++++++-
 sshd_config      |   2 +
 sshd_config.4    |  10 ++
 sshkey.c         |   3 +-
 sshkey.h         |   1 +
 34 files changed, 2099 insertions(+), 148 deletions(-)
 create mode 100644 ChangeLog.gssapi
 create mode 100644 kexgssc.c
 create mode 100644 kexgsss.c
diff --git a/ChangeLog.gssapi b/ChangeLog.gssapi
new file mode 100644
index 00000000..f117a336
--- /dev/null
+++ b/ChangeLog.gssapi
@@ -0,0 +1,113 @@
+20110101
+  - Finally update for OpenSSH 5.6p1
+  - Add GSSAPIServerIdentity option from Jim Basney
+
+20100308
+  - [ Makefile.in, key.c, key.h ]
+    Updates for OpenSSH 5.4p1
+  - [ servconf.c ]
+    Include GSSAPI options in the sshd -T configuration dump, and flag
+    some older configuration options as being unsupported. Thanks to Colin
+    Watson.
+  -
+
+20100124
+  - [ sshconnect2.c ]
+    Adapt to deal with additional element in Authmethod structure. Thanks to
+    Colin Watson
+
+20090615
+  - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c
+      sshd.c ]
+    Fix issues identified by Greg Hudson following a code review
+    Check return value of gss_indicate_mechs
+    Protect GSSAPI calls in monitor, so they can only be used if enabled
+    Check return values of bignum functions in key exchange
+    Use BN_clear_free to clear other side's DH value
+    Make ssh_gssapi_id_kex more robust
+    Only configure kex table pointers if GSSAPI is enabled
+    Don't leak mechanism list, or gss mechanism list
+    Cast data.length before printing
+    If serverkey isn't provided, use an empty string, rather than NULL
+
+20090201
+  - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h
+      ssh_config.5 sshconnet2.c ]
+    Add support for the GSSAPIClientIdentity option, which allows the user
+    to specify which GSSAPI identity to use to contact a given server
+
+20080404
+  - [ gss-serv.c ]
+    Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow
+    been omitted from a previous version of this patch. Reported by Borislav
+    Stoichkov
+
+20070317
+  - [ gss-serv-krb5.c ]
+    Remove C99ism, where new_ccname was being declared in the middle of a
+    function
+
+20061220
+  - [ servconf.c ]
+    Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and
+    documented, behaviour. Reported by Dan Watson.
+
+20060910
+  - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c
+      ssh-gss.h ]
+    add support for gss-group14-sha1 key exchange mechanisms
+  - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ]
+    Add GSSAPIStrictAcceptorCheck option to allow the disabling of
+    acceptor principal checking on multi-homed machines.
+    <Bugzilla #928>
+  - [ sshd_config ssh_config ]
+    Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample
+    configuration files
+  - [ kexgss.c kegsss.c sshconnect2.c sshd.c ]
+    Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf()
+    Limit length of error messages displayed by client
+
+20060909
+  - [ gss-genr.c gss-serv.c ]
+    move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server
+    only, where they belong
+    <Bugzilla #1225>
+
+20060829
+  - [ gss-serv-krb5.c ]
+    Fix CCAPI credentials cache name when creating KRB5CCNAME environment
+    variable
+
+20060828
+  - [ gss-genr.c ]
+    Avoid Heimdal context freeing problem
+    <Fixed upstream 20060829>
+
+20060818
+  - [ gss-genr.c ssh-gss.h sshconnect2.c ]
+    Make sure that SPENGO is disabled
+    <Bugzilla #1218 - Fixed upstream 20060818>
+
+20060421
+  - [ gssgenr.c, sshconnect2.c ]
+    a few type changes (signed versus unsigned, int versus size_t) to
+    fix compiler errors/warnings
+    (from jbasney AT ncsa.uiuc.edu)
+  - [ kexgssc.c, sshconnect2.c ]
+    fix uninitialized variable warnings
+    (from jbasney AT ncsa.uiuc.edu)
+  - [ gssgenr.c ]
+    pass oid to gss_display_status (helpful when using GSSAPI mechglue)
+    (from jbasney AT ncsa.uiuc.edu)
+    <Bugzilla #1220 >
+  - [ gss-serv-krb5.c ]
+    #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H
+    (from jbasney AT ncsa.uiuc.edu)
+    <Fixed upstream 20060304>
+  - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c
+    add client-side GssapiKeyExchange option
+    (from jbasney AT ncsa.uiuc.edu)
+  - [ sshconnect2.c ]
+    add support for GssapiTrustDns option for gssapi-with-mic
+    (from jbasney AT ncsa.uiuc.edu)
+    <gssapi-with-mic support is Bugzilla #1008>
diff --git a/Makefile.in b/Makefile.in
index 48d773de..47dbceff 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -94,6 +94,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
     kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
     kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \
     kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \
+    kexgssc.o \
     platform-pledge.o platform-tracing.o
 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
@@ -107,7 +108,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \
     auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \
     auth2-none.o auth2-passwd.o auth2-pubkey.o \
     monitor.o monitor_wrap.o auth-krb5.o \
-    auth2-gss.o gss-serv.o gss-serv-krb5.o \
+    auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \
     loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
     sftp-server.o sftp-common.o \
     sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
diff --git a/auth-krb5.c b/auth-krb5.c
index a5a81ed2..38e7fee2 100644
--- a/auth-krb5.c
+++ b/auth-krb5.c
@@ -182,8 +182,13 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
     len = strlen(authctxt->krb5_ticket_file) + 6;
     authctxt->krb5_ccname = xmalloc(len);
+#ifdef USE_CCAPI
+    snprintf(authctxt->krb5_ccname, len, "API:%s",
+        authctxt->krb5_ticket_file);
+#else
     snprintf(authctxt->krb5_ccname, len, "FILE:%s",
         authctxt->krb5_ticket_file);
+#endif
 #ifdef USE_PAM
     if (options.use_pam)
@@ -240,15 +245,22 @@ krb5_cleanup_proc(Authctxt *authctxt)
 #ifndef HEIMDAL
 krb5_error_code
 ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
-    int tmpfd, ret, oerrno;
+    int ret, oerrno;
     char ccname[40];
     mode_t old_umask;
+#ifdef USE_CCAPI
+    char cctemplate[] = "API:krb5cc_%d";
+#else
+    char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX";
+    int tmpfd;
+#endif
     ret = snprintf(ccname, sizeof(ccname),
-        "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
+        cctemplate, geteuid());
     if (ret < 0 || (size_t)ret >= sizeof(ccname))
         return ENOMEM;
+#ifndef USE_CCAPI
     old_umask = umask(0177);
     tmpfd = mkstemp(ccname + strlen("FILE:"));
     oerrno = errno;
@@ -265,6 +277,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
         return oerrno;
     }
     close(tmpfd);
+#endif
     return (krb5_cc_resolve(ctx, ccname, ccache));
 }
diff --git a/auth.c b/auth.c
index 6ee6116d..c6390687 100644
--- a/auth.c
+++ b/auth.c
@@ -372,7 +372,8 @@ auth_root_allowed(const char *method)
     case PERMIT_NO_PASSWD:
         if (strcmp(method, "publickey") == 0 ||
             strcmp(method, "hostbased") == 0 ||
-            strcmp(method, "gssapi-with-mic") == 0)
+            strcmp(method, "gssapi-with-mic") == 0 ||
+            strcmp(method, "gssapi-keyex") == 0)
             return 1;
         break;
     case PERMIT_FORCED_ONLY:
@@ -795,99 +796,6 @@ fakepw(void)
 }
 /*
- * Returns the remote DNS hostname as a string. The returned string must not
- * be freed. NB. this will usually trigger a DNS query the first time it is
- * called.
- * This function does additional checks on the hostname to mitigate some
- * attacks on legacy rhosts-style authentication.
- * XXX is RhostsRSAAuthentication vulnerable to these?
- * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?)
- */
-
-static char *
-remote_hostname(struct ssh *ssh)
-{
-    struct sockaddr_storage from;
-    socklen_t fromlen;
-    struct addrinfo hints, *ai, *aitop;
-    char name[NI_MAXHOST], ntop2[NI_MAXHOST];
-    const char *ntop = ssh_remote_ipaddr(ssh);
-
-    /* Get IP address of client. */
-    fromlen = sizeof(from);
-    memset(&from, 0, sizeof(from));
-    if (getpeername(ssh_packet_get_connection_in(ssh),
-        (struct sockaddr *)&from, &fromlen) < 0) {
-        debug("getpeername failed: %.100s", strerror(errno));
-        return strdup(ntop);
-    }
-
-    ipv64_normalise_mapped(&from, &fromlen);
-    if (from.ss_family == AF_INET6)
-        fromlen = sizeof(struct sockaddr_in6);
-
-    debug3("Trying to reverse map address %.100s.", ntop);
-    /* Map the IP address to a host name. */
-    if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
-        NULL, 0, NI_NAMEREQD) != 0) {
-        /* Host name not found.  Use ip address. */
-        return strdup(ntop);
-    }
-
-    /*
-     * if reverse lookup result looks like a numeric hostname,
-     * someone is trying to trick us by PTR record like following:
-     *    1.1.1.10.in-addr.arpa.    IN PTR    2.3.4.5
-     */
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_socktype = SOCK_DGRAM;    /*dummy*/
-    hints.ai_flags = AI_NUMERICHOST;
-    if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
-        logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
-            name, ntop);
-        freeaddrinfo(ai);
-        return strdup(ntop);
-    }
-
-    /* Names are stored in lowercase. */
-    lowercase(name);
-
-    /*
-     * Map it back to an IP address and check that the given
-     * address actually is an address of this host.  This is
-     * necessary because anyone with access to a name server can
-     * define arbitrary names for an IP address. Mapping from
-     * name to IP address can be trusted better (but can still be
-     * fooled if the intruder has access to the name server of
-     * the domain).
-     */
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = from.ss_family;
-    hints.ai_socktype = SOCK_STREAM;
-    if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
-        logit("reverse mapping checking getaddrinfo for %.700s "
-            "[%s] failed.", name, ntop);
-        return strdup(ntop);
-    }
-    /* Look for the address from the list of addresses. */
-    for (ai = aitop; ai; ai = ai->ai_next) {
-        if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
-            sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
-            (strcmp(ntop, ntop2) == 0))
-                break;
-    }
-    freeaddrinfo(aitop);
-    /* If we reached the end of the list, the address was not there. */
-    if (ai == NULL) {
-        /* Address not found for the host name. */
-        logit("Address %.100s maps to %.600s, but this does not "
-            "map back to the address.", ntop, name);
-        return strdup(ntop);
-    }
-    return strdup(name);
-}
-
-/*
  * Return the canonical name of the host in the other side of the current
  * connection.  The host name is cached, so it is efficient to call this
  * several times.
diff --git a/auth2-gss.c b/auth2-gss.c
index 1ca83577..3b5036df 100644
--- a/auth2-gss.c
+++ b/auth2-gss.c
@@ -1,7 +1,7 @@
 /* $OpenBSD: auth2-gss.c,v 1.22 2015/01/19 20:07:45 markus Exp $ */
 /*
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -53,6 +53,40 @@ static int input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
 static int input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
 static int input_gssapi_errtok(int, u_int32_t, void *);
+/*
+ * The 'gssapi_keyex' userauth mechanism.
+ */
+static int
+userauth_gsskeyex(Authctxt *authctxt)
+{
+    int authenticated = 0;
+    Buffer b;
+    gss_buffer_desc mic, gssbuf;
+    u_int len;
+
+    mic.value = packet_get_string(&len);
+    mic.length = len;
+
+    packet_check_eom();
+
+    ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
+        "gssapi-keyex");
+
+    gssbuf.value = buffer_ptr(&b);
+    gssbuf.length = buffer_len(&b);
+
+    /* gss_kex_context is NULL with privsep, so we can't check it here */
+    if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
+        &gssbuf, &mic))))
+        authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
+            authctxt->pw));
+
+    buffer_free(&b);
+    free(mic.value);
+
+    return (authenticated);
+}
+
 /*
  * We only support those mechanisms that we know about (ie ones that we know
  * how to check local user kuserok and the like)
@@ -238,7 +272,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
     packet_check_eom();
-    authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
+    authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
+        authctxt->pw));
     authctxt->postponed = 0;
     dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
@@ -274,7 +309,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
     gssbuf.length = buffer_len(&b);
     if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
-        authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
+        authenticated =
+            PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
     else
         logit("GSSAPI MIC check failed");
@@ -290,6 +326,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
     return 0;
 }
+Authmethod method_gsskeyex = {
+    "gssapi-keyex",
+    userauth_gsskeyex,
+    &options.gss_authentication
+};
+
 Authmethod method_gssapi = {
     "gssapi-with-mic",
     userauth_gssapi,
diff --git a/auth2.c b/auth2.c
index 4623ae02..6a9f936b 100644
--- a/auth2.c
+++ b/auth2.c
@@ -70,6 +70,7 @@ extern Authmethod method_passwd;
 extern Authmethod method_kbdint;
 extern Authmethod method_hostbased;
 #ifdef GSSAPI
+extern Authmethod method_gsskeyex;
 extern Authmethod method_gssapi;
 #endif
@@ -77,6 +78,7 @@ Authmethod *authmethods[] = {
     &method_none,
     &method_pubkey,
 #ifdef GSSAPI
+    &method_gsskeyex,
     &method_gssapi,
 #endif
     &method_passwd,
diff --git a/canohost.c b/canohost.c
index f71a0856..404731d2 100644
--- a/canohost.c
+++ b/canohost.c
@@ -35,6 +35,99 @@
 #include "canohost.h"
 #include "misc.h"
+/*
+ * Returns the remote DNS hostname as a string. The returned string must not
+ * be freed. NB. this will usually trigger a DNS query the first time it is
+ * called.
+ * This function does additional checks on the hostname to mitigate some
+ * attacks on legacy rhosts-style authentication.
+ * XXX is RhostsRSAAuthentication vulnerable to these?
+ * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?)
+ */
+
+char *
+remote_hostname(struct ssh *ssh)
+{
+    struct sockaddr_storage from;
+    socklen_t fromlen;
+    struct addrinfo hints, *ai, *aitop;
+    char name[NI_MAXHOST], ntop2[NI_MAXHOST];
+    const char *ntop = ssh_remote_ipaddr(ssh);
+
+    /* Get IP address of client. */
+    fromlen = sizeof(from);
+    memset(&from, 0, sizeof(from));
+    if (getpeername(ssh_packet_get_connection_in(ssh),
+        (struct sockaddr *)&from, &fromlen) < 0) {
+        debug("getpeername failed: %.100s", strerror(errno));
+        return strdup(ntop);
+    }
+
+    ipv64_normalise_mapped(&from, &fromlen);
+    if (from.ss_family == AF_INET6)
+        fromlen = sizeof(struct sockaddr_in6);
+
+    debug3("Trying to reverse map address %.100s.", ntop);
+    /* Map the IP address to a host name. */
+    if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
+        NULL, 0, NI_NAMEREQD) != 0) {
+        /* Host name not found.  Use ip address. */
+        return strdup(ntop);
+    }
+
+    /*
+     * if reverse lookup result looks like a numeric hostname,
+     * someone is trying to trick us by PTR record like following:
+     *    1.1.1.10.in-addr.arpa.    IN PTR    2.3.4.5
+     */
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_socktype = SOCK_DGRAM;    /*dummy*/
+    hints.ai_flags = AI_NUMERICHOST;
+    if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
+        logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
+            name, ntop);
+        freeaddrinfo(ai);
+        return strdup(ntop);
+    }
+
+    /* Names are stored in lowercase. */
+    lowercase(name);
+
+    /*
+     * Map it back to an IP address and check that the given
+     * address actually is an address of this host.  This is
+     * necessary because anyone with access to a name server can
+     * define arbitrary names for an IP address. Mapping from
+     * name to IP address can be trusted better (but can still be
+     * fooled if the intruder has access to the name server of
+     * the domain).
+     */
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = from.ss_family;
+    hints.ai_socktype = SOCK_STREAM;
+    if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
+        logit("reverse mapping checking getaddrinfo for %.700s "
+            "[%s] failed.", name, ntop);
+        return strdup(ntop);
+    }
+    /* Look for the address from the list of addresses. */
+    for (ai = aitop; ai; ai = ai->ai_next) {
+        if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
+            sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
+            (strcmp(ntop, ntop2) == 0))
+                break;
+    }
+    freeaddrinfo(aitop);
+    /* If we reached the end of the list, the address was not there. */
+    if (ai == NULL) {
+        /* Address not found for the host name. */
+        logit("Address %.100s maps to %.600s, but this does not "
+            "map back to the address.", ntop, name);
+        return strdup(ntop);
+    }
+    return strdup(name);
+}
+
 void
 ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len)
 {
diff --git a/canohost.h b/canohost.h
index 26d62855..0cadc9f1 100644
--- a/canohost.h
+++ b/canohost.h
@@ -15,6 +15,9 @@
 #ifndef _CANOHOST_H
 #define _CANOHOST_H
+struct ssh;
+
+char        *remote_hostname(struct ssh *);
 char        *get_peer_ipaddr(int);
 int         get_peer_port(int);
 char        *get_local_ipaddr(int);
diff --git a/clientloop.c b/clientloop.c
index 4289a408..99c68b69 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -113,6 +113,10 @@
 #include "ssherr.h"
 #include "hostfile.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
 /* import options */
 extern Options options;
@@ -1664,9 +1668,18 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
             break;
         /* Do channel operations unless rekeying in progress. */
-        if (!ssh_packet_is_rekeying(active_state))
+        if (!ssh_packet_is_rekeying(active_state)) {
             channel_after_select(readset, writeset);
+#ifdef GSSAPI
+            if (options.gss_renewal_rekey &&
+                ssh_gssapi_credentials_updated(NULL)) {
+                debug("credentials updated - forcing rekey");
+                need_rekeying = 1;
+            }
+#endif
+        }
+
         /* Buffer input from the connection.  */
         client_process_net_input(readset);
diff --git a/configure.ac b/configure.ac
index 7a36eee9..1635897c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -623,6 +623,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
         [Use tunnel device compatibility to OpenBSD])
     AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
         [Prepend the address family to IP tunnel traffic])
+    AC_MSG_CHECKING([if we have the Security Authorization Session API])
+    AC_TRY_COMPILE([#include <Security/AuthSession.h>],
+        [SessionCreate(0, 0);],
+        [ac_cv_use_security_session_api="yes"
+         AC_DEFINE([USE_SECURITY_SESSION_API], [1],
+            [platform has the Security Authorization Session API])
+         LIBS="$LIBS -framework Security"
+         AC_MSG_RESULT([yes])],
+        [ac_cv_use_security_session_api="no"
+         AC_MSG_RESULT([no])])
+    AC_MSG_CHECKING([if we have an in-memory credentials cache])
+    AC_TRY_COMPILE(
+        [#include <Kerberos/Kerberos.h>],
+        [cc_context_t c;
+         (void) cc_initialize (&c, 0, NULL, NULL);],
+        [AC_DEFINE([USE_CCAPI], [1],
+            [platform uses an in-memory credentials cache])
+         LIBS="$LIBS -framework Security"
+         AC_MSG_RESULT([yes])
+         if test "x$ac_cv_use_security_session_api" = "xno"; then
+            AC_MSG_ERROR([*** Need a security framework to use the credentials cache API ***])
+        fi],
+        [AC_MSG_RESULT([no])]
+    )
     m4_pattern_allow([AU_IPv])
     AC_CHECK_DECL([AU_IPv4], [],
         AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records])
diff --git a/gss-genr.c b/gss-genr.c
index 62559ed9..0b3ae073 100644
--- a/gss-genr.c
+++ b/gss-genr.c
@@ -1,7 +1,7 @@
 /* $OpenBSD: gss-genr.c,v 1.24 2016/09/12 01:22:38 deraadt Exp $ */
 /*
- * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -40,12 +40,167 @@
 #include "buffer.h"
 #include "log.h"
 #include "ssh2.h"
+#include "cipher.h"
+#include "key.h"
+#include "kex.h"
+#include <openssl/evp.h>
 #include "ssh-gss.h"
 extern u_char *session_id2;
 extern u_int session_id2_len;
+typedef struct {
+    char *encoded;
+    gss_OID oid;
+} ssh_gss_kex_mapping;
+
+/*
+ * XXX - It would be nice to find a more elegant way of handling the
+ * XXX   passing of the key exchange context to the userauth routines
+ */
+
+Gssctxt *gss_kex_context = NULL;
+
+static ssh_gss_kex_mapping *gss_enc2oid = NULL;
+
+int
+ssh_gssapi_oid_table_ok(void) {
+    return (gss_enc2oid != NULL);
+}
+
+/*
+ * Return a list of the gss-group1-sha1 mechanisms supported by this program
+ *
+ * We test mechanisms to ensure that we can use them, to avoid starting
+ * a key exchange with a bad mechanism
+ */
+
+char *
+ssh_gssapi_client_mechanisms(const char *host, const char *client) {
+    gss_OID_set gss_supported;
+    OM_uint32 min_status;
+
+    if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
+        return NULL;
+
+    return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
+        host, client));
+}
+
+char *
+ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
+    const char *host, const char *client) {
+    Buffer buf;
+    size_t i;
+    int oidpos, enclen;
+    char *mechs, *encoded;
+    u_char digest[EVP_MAX_MD_SIZE];
+    char deroid[2];
+    const EVP_MD *evp_md = EVP_md5();
+    EVP_MD_CTX md;
+
+    if (gss_enc2oid != NULL) {
+        for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
+            free(gss_enc2oid[i].encoded);
+        free(gss_enc2oid);
+    }
+
+    gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
+        (gss_supported->count + 1));
+
+    buffer_init(&buf);
+
+    oidpos = 0;
+    for (i = 0; i < gss_supported->count; i++) {
+        if (gss_supported->elements[i].length < 128 &&
+            (*check)(NULL, &(gss_supported->elements[i]), host, client)) {
+
+            deroid[0] = SSH_GSS_OIDTYPE;
+            deroid[1] = gss_supported->elements[i].length;
+
+            EVP_DigestInit(&md, evp_md);
+            EVP_DigestUpdate(&md, deroid, 2);
+            EVP_DigestUpdate(&md,
+                gss_supported->elements[i].elements,
+                gss_supported->elements[i].length);
+            EVP_DigestFinal(&md, digest, NULL);
+
+            encoded = xmalloc(EVP_MD_size(evp_md) * 2);
+            enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
+                encoded, EVP_MD_size(evp_md) * 2);
+
+            if (oidpos != 0)
+                buffer_put_char(&buf, ',');
+
+            buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
+                sizeof(KEX_GSS_GEX_SHA1_ID) - 1);
+            buffer_append(&buf, encoded, enclen);
+            buffer_put_char(&buf, ',');
+            buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID,
+                sizeof(KEX_GSS_GRP1_SHA1_ID) - 1);
+            buffer_append(&buf, encoded, enclen);
+            buffer_put_char(&buf, ',');
+            buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID,
+                sizeof(KEX_GSS_GRP14_SHA1_ID) - 1);
+            buffer_append(&buf, encoded, enclen);
+
+            gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
+            gss_enc2oid[oidpos].encoded = encoded;
+            oidpos++;
+        }
+    }
+    gss_enc2oid[oidpos].oid = NULL;
+    gss_enc2oid[oidpos].encoded = NULL;
+
+    buffer_put_char(&buf, '\0');
+
+    mechs = xmalloc(buffer_len(&buf));
+    buffer_get(&buf, mechs, buffer_len(&buf));
+    buffer_free(&buf);
+
+    if (strlen(mechs) == 0) {
+        free(mechs);
+        mechs = NULL;
+    }
+
+    return (mechs);
+}
+
+gss_OID
+ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
+    int i = 0;
+
+    switch (kex_type) {
+    case KEX_GSS_GRP1_SHA1:
+        if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID))
+            return GSS_C_NO_OID;
+        name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
+        break;
+    case KEX_GSS_GRP14_SHA1:
+        if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID))
+            return GSS_C_NO_OID;
+        name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
+        break;
+    case KEX_GSS_GEX_SHA1:
+        if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID))
+            return GSS_C_NO_OID;
+        name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
+        break;
+    default:
+        return GSS_C_NO_OID;
+    }
+
+    while (gss_enc2oid[i].encoded != NULL &&
+        strcmp(name, gss_enc2oid[i].encoded) != 0)
+        i++;
+
+    if (gss_enc2oid[i].oid != NULL && ctx != NULL)
+        ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
+
+    return gss_enc2oid[i].oid;
+}
+
 /* Check that the OID in a data stream matches that in the context */
 int
 ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
@@ -198,7 +353,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
     }
     ctx->major = gss_init_sec_context(&ctx->minor,
-        GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid,
+        ctx->client_creds, &ctx->context, ctx->name, ctx->oid,
         GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
         0, NULL, recv_tok, NULL, send_tok, flags, NULL);
@@ -228,8 +383,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
 }
 OM_uint32
+ssh_gssapi_client_identity(Gssctxt *ctx, const char *name)
+{
+    gss_buffer_desc gssbuf;
+    gss_name_t gssname;
+    OM_uint32 status;
+    gss_OID_set oidset;
+
+    gssbuf.value = (void *) name;
+    gssbuf.length = strlen(gssbuf.value);
+
+    gss_create_empty_oid_set(&status, &oidset);
+    gss_add_oid_set_member(&status, ctx->oid, &oidset);
+
+    ctx->major = gss_import_name(&ctx->minor, &gssbuf,
+        GSS_C_NT_USER_NAME, &gssname);
+
+    if (!ctx->major)
+        ctx->major = gss_acquire_cred(&ctx->minor,
+            gssname, 0, oidset, GSS_C_INITIATE,
+            &ctx->client_creds, NULL, NULL);
+
+    gss_release_name(&status, &gssname);
+    gss_release_oid_set(&status, &oidset);
+
+    if (ctx->major)
+        ssh_gssapi_error(ctx);
+
+    return(ctx->major);
+}
+
+OM_uint32
 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
 {
+    if (ctx == NULL)
+        return -1;
+
     if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
         GSS_C_QOP_DEFAULT, buffer, hash)))
         ssh_gssapi_error(ctx);
@@ -237,6 +426,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
     return (ctx->major);
 }
+/* Priviledged when used by server */
+OM_uint32
+ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
+{
+    if (ctx == NULL)
+        return -1;
+
+    ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
+        gssbuf, gssmic, NULL);
+
+    return (ctx->major);
+}
+
 void
 ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
     const char *context)
@@ -250,11 +452,16 @@ ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
 }
 int
-ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
+ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host,
+    const char *client)
 {
     gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
     OM_uint32 major, minor;
     gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
+    Gssctxt *intctx = NULL;
+
+    if (ctx == NULL)
+        ctx = &intctx;
     /* RFC 4462 says we MUST NOT do SPNEGO */
     if (oid->length == spnego_oid.length &&
@@ -264,6 +471,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
     ssh_gssapi_build_ctx(ctx);
     ssh_gssapi_set_oid(*ctx, oid);
     major = ssh_gssapi_import_name(*ctx, host);
+
+    if (!GSS_ERROR(major) && client)
+        major = ssh_gssapi_client_identity(*ctx, client);
+
     if (!GSS_ERROR(major)) {
         major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token,
             NULL);
@@ -273,10 +484,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
                 GSS_C_NO_BUFFER);
     }
-    if (GSS_ERROR(major))
+    if (GSS_ERROR(major) || intctx != NULL)
         ssh_gssapi_delete_ctx(ctx);
     return (!GSS_ERROR(major));
 }
+int
+ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
+    static gss_name_t saved_name = GSS_C_NO_NAME;
+    static OM_uint32 saved_lifetime = 0;
+    static gss_OID saved_mech = GSS_C_NO_OID;
+    static gss_name_t name;
+    static OM_uint32 last_call = 0;
+    OM_uint32 lifetime, now, major, minor;
+    int equal;
+
+    now = time(NULL);
+
+    if (ctxt) {
+        debug("Rekey has happened - updating saved versions");
+
+        if (saved_name != GSS_C_NO_NAME)
+            gss_release_name(&minor, &saved_name);
+
+        major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
+            &saved_name, &saved_lifetime, NULL, NULL);
+
+        if (!GSS_ERROR(major)) {
+            saved_mech = ctxt->oid;
+                saved_lifetime+= now;
+        } else {
+            /* Handle the error */
+        }
+        return 0;
+    }
+
+    if (now - last_call < 10)
+        return 0;
+
+    last_call = now;
+
+    if (saved_mech == GSS_C_NO_OID)
+        return 0;
+
+    major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
+        &name, &lifetime, NULL, NULL);
+    if (major == GSS_S_CREDENTIALS_EXPIRED)
+        return 0;
+    else if (GSS_ERROR(major))
+        return 0;
+
+    major = gss_compare_name(&minor, saved_name, name, &equal);
+    gss_release_name(&minor, &name);
+    if (GSS_ERROR(major))
+        return 0;
+
+    if (equal && (saved_lifetime < lifetime + now - 10))
+        return 1;
+
+    return 0;
+}
+
 #endif /* GSSAPI */
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
index 6e6cff7b..fcfb86a8 100644
--- a/gss-serv-krb5.c
+++ b/gss-serv-krb5.c
@@ -1,7 +1,7 @@
 /* $OpenBSD: gss-serv-krb5.c,v 1.8 2013/07/20 01:55:13 djm Exp $ */
 /*
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -121,8 +121,8 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
     krb5_error_code problem;
     krb5_principal princ;
     OM_uint32 maj_status, min_status;
-    int len;
     const char *errmsg;
+    const char *new_ccname;
     if (client->creds == NULL) {
         debug("No credentials stored");
@@ -181,11 +181,16 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
         return;
     }
-    client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache));
+    new_ccname = krb5_cc_get_name(krb_context, ccache);
+
     client->store.envvar = "KRB5CCNAME";
-    len = strlen(client->store.filename) + 6;
-    client->store.envval = xmalloc(len);
-    snprintf(client->store.envval, len, "FILE:%s", client->store.filename);
+#ifdef USE_CCAPI
+    xasprintf(&client->store.envval, "API:%s", new_ccname);
+    client->store.filename = NULL;
+#else
+    xasprintf(&client->store.envval, "FILE:%s", new_ccname);
+    client->store.filename = xstrdup(new_ccname);
+#endif
 #ifdef USE_PAM
     if (options.use_pam)
@@ -196,6 +201,72 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
     return;
 }
+
+int
+ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store,
+    ssh_gssapi_client *client)
+{
+    krb5_ccache ccache = NULL;
+    krb5_principal principal = NULL;
+    char *name = NULL;
+    krb5_error_code problem;
+    OM_uint32 maj_status, min_status;
+
+       if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) {
+                logit("krb5_cc_resolve(): %.100s",
+                    krb5_get_err_text(krb_context, problem));
+                return 0;
+           }
+
+    /* Find out who the principal in this cache is */
+    if ((problem = krb5_cc_get_principal(krb_context, ccache,
+        &principal))) {
+        logit("krb5_cc_get_principal(): %.100s",
+            krb5_get_err_text(krb_context, problem));
+        krb5_cc_close(krb_context, ccache);
+        return 0;
+    }
+
+    if ((problem = krb5_unparse_name(krb_context, principal, &name))) {
+        logit("krb5_unparse_name(): %.100s",
+            krb5_get_err_text(krb_context, problem));
+        krb5_free_principal(krb_context, principal);
+        krb5_cc_close(krb_context, ccache);
+        return 0;
+    }
+
+
+    if (strcmp(name,client->exportedname.value)!=0) {
+        debug("Name in local credentials cache differs. Not storing");
+        krb5_free_principal(krb_context, principal);
+        krb5_cc_close(krb_context, ccache);
+        krb5_free_unparsed_name(krb_context, name);
+        return 0;
+    }
+    krb5_free_unparsed_name(krb_context, name);
+
+    /* Name matches, so lets get on with it! */
+
+    if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) {
+        logit("krb5_cc_initialize(): %.100s",
+            krb5_get_err_text(krb_context, problem));
+        krb5_free_principal(krb_context, principal);
+        krb5_cc_close(krb_context, ccache);
+        return 0;
+    }
+
+    krb5_free_principal(krb_context, principal);
+
+    if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds,
+        ccache))) {
+        logit("gss_krb5_copy_ccache() failed. Sorry!");
+        krb5_cc_close(krb_context, ccache);
+        return 0;
+    }
+
+    return 1;
+}
+
 #endif /* #ifndef USE_GSS_STORE_CRED */
 ssh_gssapi_mech gssapi_kerberos_mech = {
@@ -206,9 +277,11 @@ ssh_gssapi_mech gssapi_kerberos_mech = {
     &ssh_gssapi_krb5_userok,
     NULL,
 #ifdef USE_GSS_STORE_CRED
+    NULL,
     NULL
 #else
-    &ssh_gssapi_krb5_storecreds
+    &ssh_gssapi_krb5_storecreds,
+    &ssh_gssapi_krb5_updatecreds
 #endif
 };
diff --git a/gss-serv.c b/gss-serv.c
index 209ffe82..3f9dfe5c 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -1,7 +1,7 @@
 /* $OpenBSD: gss-serv.c,v 1.29 2015/05/22 03:50:02 djm Exp $ */
 /*
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -45,17 +45,22 @@
 #include "session.h"
 #include "misc.h"
 #include "servconf.h"
+#include "uidswap.h"
 #include "ssh-gss.h"
+#include "monitor_wrap.h"
+
+extern ServerOptions options;
 extern ServerOptions options;
 static ssh_gssapi_client gssapi_client =
     { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
-    GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL, NULL}};
+    GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME,  NULL,
+    {NULL, NULL, NULL, NULL, NULL}, 0, 0};
 ssh_gssapi_mech gssapi_null_mech =
-    { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
+    { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
 #ifdef KRB5
 extern ssh_gssapi_mech gssapi_kerberos_mech;
@@ -142,6 +147,28 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
 }
 /* Unprivileged */
+char *
+ssh_gssapi_server_mechanisms(void) {
+    if (supported_oids == NULL)
+        ssh_gssapi_prepare_supported_oids();
+    return (ssh_gssapi_kex_mechs(supported_oids,
+        &ssh_gssapi_server_check_mech, NULL, NULL));
+}
+
+/* Unprivileged */
+int
+ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
+    const char *dummy) {
+    Gssctxt *ctx = NULL;
+    int res;
+
+    res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
+    ssh_gssapi_delete_ctx(&ctx);
+
+    return (res);
+}
+
+/* Unprivileged */
 void
 ssh_gssapi_supported_oids(gss_OID_set *oidset)
 {
@@ -151,7 +178,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset)
     gss_OID_set supported;
     gss_create_empty_oid_set(&min_status, oidset);
-    gss_indicate_mechs(&min_status, &supported);
+
+    if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
+        return;
     while (supported_mechs[i]->name != NULL) {
         if (GSS_ERROR(gss_test_oid_set_member(&min_status,
@@ -277,8 +306,48 @@ OM_uint32
 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
 {
     int i = 0;
+    int equal = 0;
+    gss_name_t new_name = GSS_C_NO_NAME;
+    gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
+
+    if (options.gss_store_rekey && client->used && ctx->client_creds) {
+        if (client->mech->oid.length != ctx->oid->length ||
+            (memcmp(client->mech->oid.elements,
+             ctx->oid->elements, ctx->oid->length) !=0)) {
+            debug("Rekeyed credentials have different mechanism");
+            return GSS_S_COMPLETE;
+        }
-    gss_buffer_desc ename;
+        if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
+            ctx->client_creds, ctx->oid, &new_name,
+            NULL, NULL, NULL))) {
+            ssh_gssapi_error(ctx);
+            return (ctx->major);
+        }
+
+        ctx->major = gss_compare_name(&ctx->minor, client->name,
+            new_name, &equal);
+
+        if (GSS_ERROR(ctx->major)) {
+            ssh_gssapi_error(ctx);
+            return (ctx->major);
+        }
+
+        if (!equal) {
+            debug("Rekeyed credentials have different name");
+            return GSS_S_COMPLETE;
+        }
+
+        debug("Marking rekeyed credentials for export");
+
+        gss_release_name(&ctx->minor, &client->name);
+        gss_release_cred(&ctx->minor, &client->creds);
+        client->name = new_name;
+        client->creds = ctx->client_creds;
+            ctx->client_creds = GSS_C_NO_CREDENTIAL;
+        client->updated = 1;
+        return GSS_S_COMPLETE;
+    }
     client->mech = NULL;
@@ -293,6 +362,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
     if (client->mech == NULL)
         return GSS_S_FAILURE;
+    if (ctx->client_creds &&
+        (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
+         ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
+        ssh_gssapi_error(ctx);
+        return (ctx->major);
+    }
+
     if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
         &client->displayname, NULL))) {
         ssh_gssapi_error(ctx);
@@ -310,6 +386,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
         return (ctx->major);
     }
+    gss_release_buffer(&ctx->minor, &ename);
+
     /* We can't copy this structure, so we just move the pointer to it */
     client->creds = ctx->client_creds;
     ctx->client_creds = GSS_C_NO_CREDENTIAL;
@@ -401,7 +479,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep)
 /* Privileged */
 int
-ssh_gssapi_userok(char *user)
+ssh_gssapi_userok(char *user, struct passwd *pw)
 {
     OM_uint32 lmin;
@@ -411,9 +489,11 @@ ssh_gssapi_userok(char *user)
         return 0;
     }
     if (gssapi_client.mech && gssapi_client.mech->userok)
-        if ((*gssapi_client.mech->userok)(&gssapi_client, user))
+        if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
+            gssapi_client.used = 1;
+            gssapi_client.store.owner = pw;
             return 1;
-        else {
+        } else {
             /* Destroy delegated credentials if userok fails */
             gss_release_buffer(&lmin, &gssapi_client.displayname);
             gss_release_buffer(&lmin, &gssapi_client.exportedname);
@@ -427,14 +507,130 @@ ssh_gssapi_userok(char *user)
     return (0);
 }
-/* Privileged */
-OM_uint32
-ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
+/* These bits are only used for rekeying. The unpriviledged child is running
+ * as the user, the monitor is root.
+ *
+ * In the child, we want to :
+ *    *) Ask the monitor to store our credentials into the store we specify
+ *    *) If it succeeds, maybe do a PAM update
+ */
+
+/* Stuff for PAM */
+
+#ifdef USE_PAM
+static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg,
+    struct pam_response **resp, void *data)
 {
-    ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
-        gssbuf, gssmic, NULL);
+    return (PAM_CONV_ERR);
+}
+#endif
-    return (ctx->major);
+void
+ssh_gssapi_rekey_creds(void) {
+    int ok;
+    int ret;
+#ifdef USE_PAM
+    pam_handle_t *pamh = NULL;
+    struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
+    char *envstr;
+#endif
+
+    if (gssapi_client.store.filename == NULL &&
+        gssapi_client.store.envval == NULL &&
+        gssapi_client.store.envvar == NULL)
+        return;
+
+    ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
+
+    if (!ok)
+        return;
+
+    debug("Rekeyed credentials stored successfully");
+
+    /* Actually managing to play with the ssh pam stack from here will
+     * be next to impossible. In any case, we may want different options
+     * for rekeying. So, use our own :)
+     */
+#ifdef USE_PAM
+    if (!use_privsep) {
+        debug("Not even going to try and do PAM with privsep disabled");
+        return;
+    }
+
+    ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
+         &pamconv, &pamh);
+    if (ret)
+        return;
+
+    xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar,
+        gssapi_client.store.envval);
+
+    ret = pam_putenv(pamh, envstr);
+    if (!ret)
+        pam_setcred(pamh, PAM_REINITIALIZE_CRED);
+    pam_end(pamh, PAM_SUCCESS);
+#endif
+}
+
+int
+ssh_gssapi_update_creds(ssh_gssapi_ccache *store)
+{
+    OM_uint32 maj_status, min_status;
+    int ok = 0;
+
+    /* Check we've got credentials to store */
+    if (!gssapi_client.updated)
+        return 0;
+
+    gssapi_client.updated = 0;
+
+#ifdef USE_GSS_STORE_CRED
+    if (gssapi_client.creds == NULL) {
+        debug("No credentials stored");
+        return;
+    }
+
+    maj_status = gss_store_cred(&min_status, gssapi_client.creds,
+        GSS_C_INITIATE, &gssapi_client.mech->oid, 1, 1, NULL, NULL);
+
+    if (GSS_ERROR(maj_status)) {
+        Buffer b;
+        gss_buffer_desc msg;
+        OM_uint32 lmin;
+        OM_uint32 more = 0;
+        buffer_init(&b);
+        /* GSS-API error */
+        do {
+            gss_display_status(&lmin, maj_status, GSS_C_GSS_CODE,
+                GSS_C_NULL_OID, &more, &msg);
+            buffer_append(&b, msg.value, msg.length);
+            buffer_put_char(&b, '\n');
+            gss_release_buffer(&lmin, &msg);
+        } while (more != 0);
+        /* Mechanism specific error */
+        do {
+            gss_display_status(&lmin, min_status, GSS_C_MECH_CODE,
+                &gssapi_client.mech->oid, &more, &msg);
+            buffer_append(&b, msg.value, msg.length);
+            buffer_put_char(&b, '\n');
+            gss_release_buffer(&lmin, &msg);
+        } while (more != 0);
+        buffer_put_char(&b, '\0');
+        error("GSS-API error while storing delegated credentials: %s",
+            buffer_ptr(&b));
+        buffer_free(&b);
+    }
+#else    /* #ifdef USE_GSS_STORE_CRED */
+    temporarily_use_uid(gssapi_client.store.owner);
+    if (gssapi_client.mech && gssapi_client.mech->updatecreds)
+        ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client);
+    else
+        debug("No update function for this mechanism");
+
+    restore_uid();
+
+    return ok;
+#endif    /* #ifdef USE_GSS_STORE_CRED */
 }
 #endif
diff --git a/kex.c b/kex.c
index 6a94bc53..d8708684 100644
--- a/kex.c
+++ b/kex.c
@@ -54,6 +54,10 @@
 #include "sshbuf.h"
 #include "digest.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
 # if defined(HAVE_EVP_SHA256)
 # define evp_ssh_sha256 EVP_sha256
@@ -113,6 +117,14 @@ static const struct kexalg kexalgs[] = {
 #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
     { NULL, -1, -1, -1},
 };
+static const struct kexalg kexalg_prefixes[] = {
+#ifdef GSSAPI
+    { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
+    { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
+    { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
+#endif
+    { NULL, -1, -1, -1 },
+};
 char *
 kex_alg_list(char sep)
@@ -145,6 +157,10 @@ kex_alg_by_name(const char *name)
         if (strcmp(k->name, name) == 0)
             return k;
     }
+    for (k = kexalg_prefixes; k->name != NULL; k++) {
+        if (strncmp(k->name, name, strlen(k->name)) == 0)
+            return k;
+    }
     return NULL;
 }
@@ -597,6 +613,9 @@ kex_free(struct kex *kex)
     sshbuf_free(kex->peer);
     sshbuf_free(kex->my);
     free(kex->session_id);
+#ifdef GSSAPI
+    free(kex->gss_host);
+#endif /* GSSAPI */
     free(kex->client_version_string);
     free(kex->server_version_string);
     free(kex->failed_choice);
diff --git a/kex.h b/kex.h
index 3794f212..fd56171d 100644
--- a/kex.h
+++ b/kex.h
@@ -99,6 +99,9 @@ enum kex_exchange {
     KEX_DH_GEX_SHA256,
     KEX_ECDH_SHA2,
     KEX_C25519_SHA256,
+    KEX_GSS_GRP1_SHA1,
+    KEX_GSS_GRP14_SHA1,
+    KEX_GSS_GEX_SHA1,
     KEX_MAX
 };
@@ -147,6 +150,12 @@ struct kex {
     u_int    flags;
     int    hash_alg;
     int    ec_nid;
+#ifdef GSSAPI
+    int    gss_deleg_creds;
+    int    gss_trust_dns;
+    char    *gss_host;
+    char    *gss_client;
+#endif
     char    *client_version_string;
     char    *server_version_string;
     char    *failed_choice;
@@ -197,6 +206,11 @@ int     kexecdh_server(struct ssh *);
 int     kexc25519_client(struct ssh *);
 int     kexc25519_server(struct ssh *);
+#ifdef GSSAPI
+int     kexgss_client(struct ssh *);
+int     kexgss_server(struct ssh *);
+#endif
+
 int     kex_dh_hash(int, const char *, const char *,
     const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
     const BIGNUM *, const BIGNUM *, const BIGNUM *, u_char *, size_t *);
diff --git a/kexgssc.c b/kexgssc.c
new file mode 100644
index 00000000..a77d3712
--- /dev/null
+++ b/kexgssc.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#ifdef GSSAPI
+
+#include "includes.h"
+
+#include <openssl/crypto.h>
+#include <openssl/bn.h>
+
+#include <string.h>
+#include <signal.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "ssh2.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "log.h"
+#include "packet.h"
+#include "dh.h"
+#include "digest.h"
+
+#include "ssh-gss.h"
+
+int
+kexgss_client(struct ssh *ssh) {
+    gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
+    Gssctxt *ctxt;
+    OM_uint32 maj_status, min_status, ret_flags;
+    u_int klen, kout, slen = 0, strlen;
+    DH *dh;
+    BIGNUM *dh_server_pub = NULL;
+    BIGNUM *shared_secret = NULL;
+    BIGNUM *p = NULL;
+    BIGNUM *g = NULL;
+    u_char *kbuf;
+    u_char *serverhostkey = NULL;
+    u_char *empty = "";
+    char *msg;
+    int type = 0;
+    int first = 1;
+    int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
+    u_char hash[SSH_DIGEST_MAX_LENGTH];
+    size_t hashlen;
+
+    /* Initialise our GSSAPI world */
+    ssh_gssapi_build_ctx(&ctxt);
+    if (ssh_gssapi_id_kex(ctxt, ssh->kex->name, ssh->kex->kex_type)
+        == GSS_C_NO_OID)
+        fatal("Couldn't identify host exchange");
+
+    if (ssh_gssapi_import_name(ctxt, ssh->kex->gss_host))
+        fatal("Couldn't import hostname");
+
+    if (ssh->kex->gss_client &&
+        ssh_gssapi_client_identity(ctxt, ssh->kex->gss_client))
+        fatal("Couldn't acquire client credentials");
+
+    switch (ssh->kex->kex_type) {
+    case KEX_GSS_GRP1_SHA1:
+        dh = dh_new_group1();
+        break;
+    case KEX_GSS_GRP14_SHA1:
+        dh = dh_new_group14();
+        break;
+    case KEX_GSS_GEX_SHA1:
+        debug("Doing group exchange\n");
+        nbits = dh_estimate(ssh->kex->we_need * 8);
+        packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
+        packet_put_int(min);
+        packet_put_int(nbits);
+        packet_put_int(max);
+
+        packet_send();
+
+        packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
+
+        if ((p = BN_new()) == NULL)
+            fatal("BN_new() failed");
+        packet_get_bignum2(p);
+        if ((g = BN_new()) == NULL)
+            fatal("BN_new() failed");
+        packet_get_bignum2(g);
+        packet_check_eom();
+
+        if (BN_num_bits(p) < min || BN_num_bits(p) > max)
+            fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
+                min, BN_num_bits(p), max);
+
+        dh = dh_new_group(g, p);
+        break;
+    default:
+        fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type);
+    }
+
+    /* Step 1 - e is dh->pub_key */
+    dh_gen_key(dh, ssh->kex->we_need * 8);
+
+    /* This is f, we initialise it now to make life easier */
+    dh_server_pub = BN_new();
+    if (dh_server_pub == NULL)
+        fatal("dh_server_pub == NULL");
+
+    token_ptr = GSS_C_NO_BUFFER;
+
+    do {
+        debug("Calling gss_init_sec_context");
+
+        maj_status = ssh_gssapi_init_ctx(ctxt,
+            ssh->kex->gss_deleg_creds, token_ptr, &send_tok,
+            &ret_flags);
+
+        if (GSS_ERROR(maj_status)) {
+            if (send_tok.length != 0) {
+                packet_start(SSH2_MSG_KEXGSS_CONTINUE);
+                packet_put_string(send_tok.value,
+                    send_tok.length);
+            }
+            fatal("gss_init_context failed");
+        }
+
+        /* If we've got an old receive buffer get rid of it */
+        if (token_ptr != GSS_C_NO_BUFFER)
+            free(recv_tok.value);
+
+        if (maj_status == GSS_S_COMPLETE) {
+            /* If mutual state flag is not true, kex fails */
+            if (!(ret_flags & GSS_C_MUTUAL_FLAG))
+                fatal("Mutual authentication failed");
+
+            /* If integ avail flag is not true kex fails */
+            if (!(ret_flags & GSS_C_INTEG_FLAG))
+                fatal("Integrity check failed");
+        }
+
+        /*
+         * If we have data to send, then the last message that we
+         * received cannot have been a 'complete'.
+         */
+        if (send_tok.length != 0) {
+            if (first) {
+                packet_start(SSH2_MSG_KEXGSS_INIT);
+                packet_put_string(send_tok.value,
+                    send_tok.length);
+                packet_put_bignum2(dh->pub_key);
+                first = 0;
+            } else {
+                packet_start(SSH2_MSG_KEXGSS_CONTINUE);
+                packet_put_string(send_tok.value,
+                    send_tok.length);
+            }
+            packet_send();
+            gss_release_buffer(&min_status, &send_tok);
+
+            /* If we've sent them data, they should reply */
+            do {
+                type = packet_read();
+                if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
+                    debug("Received KEXGSS_HOSTKEY");
+                    if (serverhostkey)
+                        fatal("Server host key received more than once");
+                    serverhostkey =
+                        packet_get_string(&slen);
+                }
+            } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
+
+            switch (type) {
+            case SSH2_MSG_KEXGSS_CONTINUE:
+                debug("Received GSSAPI_CONTINUE");
+                if (maj_status == GSS_S_COMPLETE)
+                    fatal("GSSAPI Continue received from server when complete");
+                recv_tok.value = packet_get_string(&strlen);
+                recv_tok.length = strlen;
+                break;
+            case SSH2_MSG_KEXGSS_COMPLETE:
+                debug("Received GSSAPI_COMPLETE");
+                packet_get_bignum2(dh_server_pub);
+                msg_tok.value =  packet_get_string(&strlen);
+                msg_tok.length = strlen;
+
+                /* Is there a token included? */
+                if (packet_get_char()) {
+                    recv_tok.value=
+                        packet_get_string(&strlen);
+                    recv_tok.length = strlen;
+                    /* If we're already complete - protocol error */
+                    if (maj_status == GSS_S_COMPLETE)
+                        packet_disconnect("Protocol error: received token when complete");
+                    } else {
+                        /* No token included */
+                        if (maj_status != GSS_S_COMPLETE)
+                            packet_disconnect("Protocol error: did not receive final token");
+                }
+                break;
+            case SSH2_MSG_KEXGSS_ERROR:
+                debug("Received Error");
+                maj_status = packet_get_int();
+                min_status = packet_get_int();
+                msg = packet_get_string(NULL);
+                (void) packet_get_string_ptr(NULL);
+                fatal("GSSAPI Error: \n%.400s",msg);
+            default:
+                packet_disconnect("Protocol error: didn't expect packet type %d",
+                    type);
+            }
+            token_ptr = &recv_tok;
+        } else {
+            /* No data, and not complete */
+            if (maj_status != GSS_S_COMPLETE)
+                fatal("Not complete, and no token output");
+        }
+    } while (maj_status & GSS_S_CONTINUE_NEEDED);
+
+    /*
+     * We _must_ have received a COMPLETE message in reply from the
+     * server, which will have set dh_server_pub and msg_tok
+     */
+
+    if (type != SSH2_MSG_KEXGSS_COMPLETE)
+        fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
+
+    /* Check f in range [1, p-1] */
+    if (!dh_pub_is_valid(dh, dh_server_pub))
+        packet_disconnect("bad server public DH value");
+
+    /* compute K=f^x mod p */
+    klen = DH_size(dh);
+    kbuf = xmalloc(klen);
+    kout = DH_compute_key(kbuf, dh_server_pub, dh);
+    if (kout < 0)
+        fatal("DH_compute_key: failed");
+
+    shared_secret = BN_new();
+    if (shared_secret == NULL)
+        fatal("kexgss_client: BN_new failed");
+
+    if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
+        fatal("kexdh_client: BN_bin2bn failed");
+
+    memset(kbuf, 0, klen);
+    free(kbuf);
+
+    hashlen = sizeof(hash);
+    switch (ssh->kex->kex_type) {
+    case KEX_GSS_GRP1_SHA1:
+    case KEX_GSS_GRP14_SHA1:
+        kex_dh_hash(
+            ssh->kex->hash_alg,
+            ssh->kex->client_version_string,
+            ssh->kex->server_version_string,
+            buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my),
+            buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer),
+            (serverhostkey ? serverhostkey : empty), slen,
+            dh->pub_key,    /* e */
+            dh_server_pub,    /* f */
+            shared_secret,    /* K */
+            hash, &hashlen
+        );
+        break;
+    case KEX_GSS_GEX_SHA1:
+        kexgex_hash(
+            ssh->kex->hash_alg,
+            ssh->kex->client_version_string,
+            ssh->kex->server_version_string,
+            buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my),
+            buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer),
+            (serverhostkey ? serverhostkey : empty), slen,
+             min, nbits, max,
+            dh->p, dh->g,
+            dh->pub_key,
+            dh_server_pub,
+            shared_secret,
+            hash, &hashlen
+        );
+        break;
+    default:
+        fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type);
+    }
+
+    gssbuf.value = hash;
+    gssbuf.length = hashlen;
+
+    /* Verify that the hash matches the MIC we just got. */
+    if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
+        packet_disconnect("Hash's MIC didn't verify");
+
+    free(msg_tok.value);
+
+    DH_free(dh);
+    free(serverhostkey);
+    BN_clear_free(dh_server_pub);
+
+    /* save session id */
+    if (ssh->kex->session_id == NULL) {
+        ssh->kex->session_id_len = hashlen;
+        ssh->kex->session_id = xmalloc(ssh->kex->session_id_len);
+        memcpy(ssh->kex->session_id, hash, ssh->kex->session_id_len);
+    }
+
+    if (ssh->kex->gss_deleg_creds)
+        ssh_gssapi_credentials_updated(ctxt);
+
+    if (gss_kex_context == NULL)
+        gss_kex_context = ctxt;
+    else
+        ssh_gssapi_delete_ctx(&ctxt);
+
+    kex_derive_keys_bn(ssh, hash, hashlen, shared_secret);
+    BN_clear_free(shared_secret);
+    return kex_send_newkeys(ssh);
+}
+
+#endif /* GSSAPI */
diff --git a/kexgsss.c b/kexgsss.c
new file mode 100644
index 00000000..0e5ff55b
--- /dev/null
+++ b/kexgsss.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#ifdef GSSAPI
+
+#include <string.h>
+#include <signal.h>
+
+#include <openssl/crypto.h>
+#include <openssl/bn.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "ssh2.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "log.h"
+#include "packet.h"
+#include "dh.h"
+#include "ssh-gss.h"
+#include "monitor_wrap.h"
+#include "misc.h"
+#include "servconf.h"
+#include "digest.h"
+
+extern ServerOptions options;
+
+int
+kexgss_server(struct ssh *ssh)
+{
+    OM_uint32 maj_status, min_status;
+
+    /*
+     * Some GSSAPI implementations use the input value of ret_flags (an
+      * output variable) as a means of triggering mechanism specific
+      * features. Initializing it to zero avoids inadvertently
+      * activating this non-standard behaviour.
+     */
+
+    OM_uint32 ret_flags = 0;
+    gss_buffer_desc gssbuf, recv_tok, msg_tok;
+    gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+    Gssctxt *ctxt = NULL;
+    u_int slen, klen, kout;
+    u_char *kbuf;
+    DH *dh;
+    int min = -1, max = -1, nbits = -1;
+    BIGNUM *shared_secret = NULL;
+    BIGNUM *dh_client_pub = NULL;
+    int type = 0;
+    gss_OID oid;
+    char *mechs;
+    u_char hash[SSH_DIGEST_MAX_LENGTH];
+    size_t hashlen;
+
+    /* Initialise GSSAPI */
+
+    /* If we're rekeying, privsep means that some of the private structures
+     * in the GSSAPI code are no longer available. This kludges them back
+     * into life
+     */
+    if (!ssh_gssapi_oid_table_ok()) {
+        mechs = ssh_gssapi_server_mechanisms();
+        free(mechs);
+    }
+
+    debug2("%s: Identifying %s", __func__, ssh->kex->name);
+    oid = ssh_gssapi_id_kex(NULL, ssh->kex->name, ssh->kex->kex_type);
+    if (oid == GSS_C_NO_OID)
+       fatal("Unknown gssapi mechanism");
+
+    debug2("%s: Acquiring credentials", __func__);
+
+    if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
+        fatal("Unable to acquire credentials for the server");
+
+    switch (ssh->kex->kex_type) {
+    case KEX_GSS_GRP1_SHA1:
+        dh = dh_new_group1();
+        break;
+    case KEX_GSS_GRP14_SHA1:
+        dh = dh_new_group14();
+        break;
+    case KEX_GSS_GEX_SHA1:
+        debug("Doing group exchange");
+        packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ);
+        min = packet_get_int();
+        nbits = packet_get_int();
+        max = packet_get_int();
+        packet_check_eom();
+        if (max < min || nbits < min || max < nbits)
+            fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
+                min, nbits, max);
+        dh = PRIVSEP(choose_dh(MAX(DH_GRP_MIN, min),
+            nbits, MIN(DH_GRP_MAX, max)));
+        if (dh == NULL)
+            packet_disconnect("Protocol error: no matching group found");
+
+        packet_start(SSH2_MSG_KEXGSS_GROUP);
+        packet_put_bignum2(dh->p);
+        packet_put_bignum2(dh->g);
+        packet_send();
+
+        packet_write_wait();
+        break;
+    default:
+        fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type);
+    }
+
+    dh_gen_key(dh, ssh->kex->we_need * 8);
+
+    do {
+        debug("Wait SSH2_MSG_GSSAPI_INIT");
+        type = packet_read();
+        switch(type) {
+        case SSH2_MSG_KEXGSS_INIT:
+            if (dh_client_pub != NULL)
+                fatal("Received KEXGSS_INIT after initialising");
+            recv_tok.value = packet_get_string(&slen);
+            recv_tok.length = slen;
+
+            if ((dh_client_pub = BN_new()) == NULL)
+                fatal("dh_client_pub == NULL");
+
+            packet_get_bignum2(dh_client_pub);
+
+            /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
+            break;
+        case SSH2_MSG_KEXGSS_CONTINUE:
+            recv_tok.value = packet_get_string(&slen);
+            recv_tok.length = slen;
+            break;
+        default:
+            packet_disconnect(
+                "Protocol error: didn't expect packet type %d",
+                type);
+        }
+
+        maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
+            &send_tok, &ret_flags));
+
+        free(recv_tok.value);
+
+        if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
+            fatal("Zero length token output when incomplete");
+
+        if (dh_client_pub == NULL)
+            fatal("No client public key");
+
+        if (maj_status & GSS_S_CONTINUE_NEEDED) {
+            debug("Sending GSSAPI_CONTINUE");
+            packet_start(SSH2_MSG_KEXGSS_CONTINUE);
+            packet_put_string(send_tok.value, send_tok.length);
+            packet_send();
+            gss_release_buffer(&min_status, &send_tok);
+        }
+    } while (maj_status & GSS_S_CONTINUE_NEEDED);
+
+    if (GSS_ERROR(maj_status)) {
+        if (send_tok.length > 0) {
+            packet_start(SSH2_MSG_KEXGSS_CONTINUE);
+            packet_put_string(send_tok.value, send_tok.length);
+            packet_send();
+        }
+        fatal("accept_ctx died");
+    }
+
+    if (!(ret_flags & GSS_C_MUTUAL_FLAG))
+        fatal("Mutual Authentication flag wasn't set");
+
+    if (!(ret_flags & GSS_C_INTEG_FLAG))
+        fatal("Integrity flag wasn't set");
+
+    if (!dh_pub_is_valid(dh, dh_client_pub))
+        packet_disconnect("bad client public DH value");
+
+    klen = DH_size(dh);
+    kbuf = xmalloc(klen);
+    kout = DH_compute_key(kbuf, dh_client_pub, dh);
+    if (kout < 0)
+        fatal("DH_compute_key: failed");
+
+    shared_secret = BN_new();
+    if (shared_secret == NULL)
+        fatal("kexgss_server: BN_new failed");
+
+    if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
+        fatal("kexgss_server: BN_bin2bn failed");
+
+    memset(kbuf, 0, klen);
+    free(kbuf);
+
+    hashlen = sizeof(hash);
+    switch (ssh->kex->kex_type) {
+    case KEX_GSS_GRP1_SHA1:
+    case KEX_GSS_GRP14_SHA1:
+        kex_dh_hash(
+            ssh->kex->hash_alg,
+            ssh->kex->client_version_string, ssh->kex->server_version_string,
+            buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer),
+            buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my),
+            NULL, 0, /* Change this if we start sending host keys */
+            dh_client_pub, dh->pub_key, shared_secret,
+            hash, &hashlen
+        );
+        break;
+    case KEX_GSS_GEX_SHA1:
+        kexgex_hash(
+            ssh->kex->hash_alg,
+            ssh->kex->client_version_string, ssh->kex->server_version_string,
+            buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer),
+            buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my),
+            NULL, 0,
+            min, nbits, max,
+            dh->p, dh->g,
+            dh_client_pub,
+            dh->pub_key,
+            shared_secret,
+            hash, &hashlen
+        );
+        break;
+    default:
+        fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type);
+    }
+
+    BN_clear_free(dh_client_pub);
+
+    if (ssh->kex->session_id == NULL) {
+        ssh->kex->session_id_len = hashlen;
+        ssh->kex->session_id = xmalloc(ssh->kex->session_id_len);
+        memcpy(ssh->kex->session_id, hash, ssh->kex->session_id_len);
+    }
+
+    gssbuf.value = hash;
+    gssbuf.length = hashlen;
+
+    if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok))))
+        fatal("Couldn't get MIC");
+
+    packet_start(SSH2_MSG_KEXGSS_COMPLETE);
+    packet_put_bignum2(dh->pub_key);
+    packet_put_string(msg_tok.value,msg_tok.length);
+
+    if (send_tok.length != 0) {
+        packet_put_char(1); /* true */
+        packet_put_string(send_tok.value, send_tok.length);
+    } else {
+        packet_put_char(0); /* false */
+    }
+    packet_send();
+
+    gss_release_buffer(&min_status, &send_tok);
+    gss_release_buffer(&min_status, &msg_tok);
+
+    if (gss_kex_context == NULL)
+        gss_kex_context = ctxt;
+    else
+        ssh_gssapi_delete_ctx(&ctxt);
+
+    DH_free(dh);
+
+    kex_derive_keys_bn(ssh, hash, hashlen, shared_secret);
+    BN_clear_free(shared_secret);
+    kex_send_newkeys(ssh);
+
+    /* If this was a rekey, then save out any delegated credentials we
+     * just exchanged.  */
+    if (options.gss_store_rekey)
+        ssh_gssapi_rekey_creds();
+    return 0;
+}
+#endif /* GSSAPI */
diff --git a/monitor.c b/monitor.c
index 8f044f4e..b0c9b4f4 100644
--- a/monitor.c
+++ b/monitor.c
@@ -160,6 +160,8 @@ int mm_answer_gss_setup_ctx(int, Buffer *);
 int mm_answer_gss_accept_ctx(int, Buffer *);
 int mm_answer_gss_userok(int, Buffer *);
 int mm_answer_gss_checkmic(int, Buffer *);
+int mm_answer_gss_sign(int, Buffer *);
+int mm_answer_gss_updatecreds(int, Buffer *);
 #endif
 #ifdef SSH_AUDIT_EVENTS
@@ -240,11 +242,18 @@ struct mon_table mon_dispatch_proto20[] = {
     {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
     {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok},
     {MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic},
+    {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
 #endif
     {0, 0, NULL}
 };
 struct mon_table mon_dispatch_postauth20[] = {
+#ifdef GSSAPI
+    {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
+    {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
+    {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
+    {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
+#endif
 #ifdef WITH_OPENSSL
     {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
 #endif
@@ -311,6 +320,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
     /* Permit requests for moduli and signatures */
     monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
     monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
+#ifdef GSSAPI
+    /* and for the GSSAPI key exchange */
+    monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
+#endif
     /* The first few requests do not require asynchronous access */
     while (!authenticated) {
@@ -442,6 +455,10 @@ monitor_child_postauth(struct monitor *pmonitor)
     monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
     monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
     monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
+#ifdef GSSAPI
+    /* and for the GSSAPI key exchange */
+    monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
+#endif
     if (!no_pty_flag) {
         monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
@@ -1666,6 +1683,13 @@ monitor_apply_keystate(struct monitor *pmonitor)
 # endif
 #endif /* WITH_OPENSSL */
         kex->kex[KEX_C25519_SHA256] = kexc25519_server;
+#ifdef GSSAPI
+        if (options.gss_keyex) {
+            kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
+            kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
+            kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
+        }
+#endif
         kex->load_host_public_key=&get_hostkey_public_by_type;
         kex->load_host_private_key=&get_hostkey_private_by_type;
         kex->host_key_index=&get_hostkey_index;
@@ -1745,8 +1769,8 @@ mm_answer_gss_setup_ctx(int sock, Buffer *m)
     OM_uint32 major;
     u_int len;
-    if (!options.gss_authentication)
-        fatal("%s: GSSAPI authentication not enabled", __func__);
+    if (!options.gss_authentication && !options.gss_keyex)
+        fatal("%s: GSSAPI not enabled", __func__);
     goid.elements = buffer_get_string(m, &len);
     goid.length = len;
@@ -1775,8 +1799,8 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
     OM_uint32 flags = 0; /* GSI needs this */
     u_int len;
-    if (!options.gss_authentication)
-        fatal("%s: GSSAPI authentication not enabled", __func__);
+    if (!options.gss_authentication && !options.gss_keyex)
+        fatal("%s: GSSAPI not enabled", __func__);
     in.value = buffer_get_string(m, &len);
     in.length = len;
@@ -1795,6 +1819,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
         monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
         monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
         monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
+        monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
     }
     return (0);
 }
@@ -1806,8 +1831,8 @@ mm_answer_gss_checkmic(int sock, Buffer *m)
     OM_uint32 ret;
     u_int len;
-    if (!options.gss_authentication)
-        fatal("%s: GSSAPI authentication not enabled", __func__);
+    if (!options.gss_authentication && !options.gss_keyex)
+        fatal("%s: GSSAPI not enabled", __func__);
     gssbuf.value = buffer_get_string(m, &len);
     gssbuf.length = len;
@@ -1835,10 +1860,11 @@ mm_answer_gss_userok(int sock, Buffer *m)
 {
     int authenticated;
-    if (!options.gss_authentication)
-        fatal("%s: GSSAPI authentication not enabled", __func__);
+    if (!options.gss_authentication && !options.gss_keyex)
+        fatal("%s: GSSAPI not enabled", __func__);
-    authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
+    authenticated = authctxt->valid &&
+        ssh_gssapi_userok(authctxt->user, authctxt->pw);
     buffer_clear(m);
     buffer_put_int(m, authenticated);
@@ -1851,5 +1877,76 @@ mm_answer_gss_userok(int sock, Buffer *m)
     /* Monitor loop will terminate if authenticated */
     return (authenticated);
 }
+
+int
+mm_answer_gss_sign(int socket, Buffer *m)
+{
+    gss_buffer_desc data;
+    gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
+    OM_uint32 major, minor;
+    u_int len;
+
+    if (!options.gss_authentication && !options.gss_keyex)
+        fatal("%s: GSSAPI not enabled", __func__);
+
+    data.value = buffer_get_string(m, &len);
+    data.length = len;
+    if (data.length != 20)
+        fatal("%s: data length incorrect: %d", __func__,
+            (int) data.length);
+
+    /* Save the session ID on the first time around */
+    if (session_id2_len == 0) {
+        session_id2_len = data.length;
+        session_id2 = xmalloc(session_id2_len);
+        memcpy(session_id2, data.value, session_id2_len);
+    }
+    major = ssh_gssapi_sign(gsscontext, &data, &hash);
+
+    free(data.value);
+
+    buffer_clear(m);
+    buffer_put_int(m, major);
+    buffer_put_string(m, hash.value, hash.length);
+
+    mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
+
+    gss_release_buffer(&minor, &hash);
+
+    /* Turn on getpwnam permissions */
+    monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
+
+    /* And credential updating, for when rekeying */
+    monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1);
+
+    return (0);
+}
+
+int
+mm_answer_gss_updatecreds(int socket, Buffer *m) {
+    ssh_gssapi_ccache store;
+    int ok;
+
+    if (!options.gss_authentication && !options.gss_keyex)
+        fatal("%s: GSSAPI not enabled", __func__);
+
+    store.filename = buffer_get_string(m, NULL);
+    store.envvar   = buffer_get_string(m, NULL);
+    store.envval   = buffer_get_string(m, NULL);
+
+    ok = ssh_gssapi_update_creds(&store);
+
+    free(store.filename);
+    free(store.envvar);
+    free(store.envval);
+
+    buffer_clear(m);
+    buffer_put_int(m, ok);
+
+    mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m);
+
+    return(0);
+}
+
 #endif /* GSSAPI */
diff --git a/monitor.h b/monitor.h
index 36e73f79..bcf9f125 100644
--- a/monitor.h
+++ b/monitor.h
@@ -68,6 +68,8 @@ enum monitor_reqtype {
 #ifdef PAM_ENHANCEMENT
     MONITOR_REQ_AUTHMETHOD = 114,
 #endif
+    MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151,
+    MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153,
 };
 struct monitor {
diff --git a/monitor_wrap.c b/monitor_wrap.c
index bc6382f3..6cacbbab 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -942,7 +942,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
 }
 int
-mm_ssh_gssapi_userok(char *user)
+mm_ssh_gssapi_userok(char *user, struct passwd *pw)
 {
     Buffer m;
     int authenticated = 0;
@@ -959,5 +959,50 @@ mm_ssh_gssapi_userok(char *user)
     debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
     return (authenticated);
 }
+
+OM_uint32
+mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
+{
+    Buffer m;
+    OM_uint32 major;
+    u_int len;
+
+    buffer_init(&m);
+    buffer_put_string(&m, data->value, data->length);
+
+    mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
+    mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
+
+    major = buffer_get_int(&m);
+    hash->value = buffer_get_string(&m, &len);
+    hash->length = len;
+
+    buffer_free(&m);
+
+    return(major);
+}
+
+int
+mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store)
+{
+    Buffer m;
+    int ok;
+
+    buffer_init(&m);
+
+    buffer_put_cstring(&m, store->filename ? store->filename : "");
+    buffer_put_cstring(&m, store->envvar ? store->envvar : "");
+    buffer_put_cstring(&m, store->envval ? store->envval : "");
+
+    mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m);
+    mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m);
+
+    ok = buffer_get_int(&m);
+
+    buffer_free(&m);
+
+    return (ok);
+}
+
 #endif /* GSSAPI */
diff --git a/monitor_wrap.h b/monitor_wrap.h
index db5902f5..8f9dd896 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -55,8 +55,10 @@ int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int);
 OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
 OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
    gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
-int mm_ssh_gssapi_userok(char *user);
+int mm_ssh_gssapi_userok(char *user, struct passwd *);
 OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
+OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
+int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
 #endif
 #ifdef USE_PAM
diff --git a/readconf.c b/readconf.c
index e6fd1420..1efbab9b 100644
--- a/readconf.c
+++ b/readconf.c
@@ -160,6 +160,8 @@ typedef enum {
     oClearAllForwardings, oNoHostAuthenticationForLocalhost,
     oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
     oAddressFamily, oGssAuthentication, oGssDelegateCreds,
+    oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey,
+    oGssServerIdentity,
     oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
     oSendEnv, oControlPath, oControlMaster, oControlPersist,
     oHashKnownHosts,
@@ -208,10 +210,19 @@ static struct {
     { "afstokenpassing", oUnsupported },
 #if defined(GSSAPI)
     { "gssapiauthentication", oGssAuthentication },
+    { "gssapikeyexchange", oGssKeyEx },
     { "gssapidelegatecredentials", oGssDelegateCreds },
+    { "gssapitrustdns", oGssTrustDns },
+    { "gssapiclientidentity", oGssClientIdentity },
+    { "gssapiserveridentity", oGssServerIdentity },
+    { "gssapirenewalforcesrekey", oGssRenewalRekey },
 #else
     { "gssapiauthentication", oUnsupported },
+    { "gssapikeyexchange", oUnsupported },
     { "gssapidelegatecredentials", oUnsupported },
+    { "gssapitrustdns", oUnsupported },
+    { "gssapiclientidentity", oUnsupported },
+    { "gssapirenewalforcesrekey", oUnsupported },
 #endif
     { "fallbacktorsh", oDeprecated },
     { "usersh", oDeprecated },
@@ -996,10 +1007,30 @@ parse_time:
         intptr = &options->gss_authentication;
         goto parse_flag;
+    case oGssKeyEx:
+        intptr = &options->gss_keyex;
+        goto parse_flag;
+
     case oGssDelegateCreds:
         intptr = &options->gss_deleg_creds;
         goto parse_flag;
+    case oGssTrustDns:
+        intptr = &options->gss_trust_dns;
+        goto parse_flag;
+
+    case oGssClientIdentity:
+        charptr = &options->gss_client_identity;
+        goto parse_string;
+
+    case oGssServerIdentity:
+        charptr = &options->gss_server_identity;
+        goto parse_string;
+
+    case oGssRenewalRekey:
+        intptr = &options->gss_renewal_rekey;
+        goto parse_flag;
+
     case oBatchMode:
         intptr = &options->batch_mode;
         goto parse_flag;
@@ -1818,7 +1849,12 @@ initialize_options(Options * options)
     options->pubkey_authentication = -1;
     options->challenge_response_authentication = -1;
     options->gss_authentication = -1;
+    options->gss_keyex = -1;
     options->gss_deleg_creds = -1;
+    options->gss_trust_dns = -1;
+    options->gss_renewal_rekey = -1;
+    options->gss_client_identity = NULL;
+    options->gss_server_identity = NULL;
     options->password_authentication = -1;
     options->kbd_interactive_authentication = -1;
     options->kbd_interactive_devices = NULL;
@@ -1973,8 +2009,14 @@ fill_default_options(Options * options)
 #else
         options->gss_authentication = 0;
 #endif
+    if (options->gss_keyex == -1)
+        options->gss_keyex = 0;
     if (options->gss_deleg_creds == -1)
         options->gss_deleg_creds = 0;
+    if (options->gss_trust_dns == -1)
+        options->gss_trust_dns = 0;
+    if (options->gss_renewal_rekey == -1)
+        options->gss_renewal_rekey = 0;
     if (options->password_authentication == -1)
         options->password_authentication = 1;
     if (options->kbd_interactive_authentication == -1)
diff --git a/readconf.h b/readconf.h
index 8005ebdd..35fb4ad0 100644
--- a/readconf.h
+++ b/readconf.h
@@ -45,7 +45,12 @@ typedef struct {
     int     challenge_response_authentication;
                     /* Try S/Key or TIS, authentication. */
     int     gss_authentication;    /* Try GSS authentication */
+    int     gss_keyex;        /* Try GSS key exchange */
     int     gss_deleg_creds;    /* Delegate GSS credentials */
+    int    gss_trust_dns;        /* Trust DNS for GSS canonicalization */
+    int    gss_renewal_rekey;    /* Credential renewal forces rekey */
+    char    *gss_client_identity;   /* Principal to initiate GSSAPI with */
+    char    *gss_server_identity;   /* GSSAPI target principal */
     int     password_authentication;    /* Try password
                          * authentication. */
     int     kbd_interactive_authentication; /* Try keyboard-interactive auth. */
diff --git a/servconf.c b/servconf.c
index c0aba508..881edd95 100644
--- a/servconf.c
+++ b/servconf.c
@@ -113,8 +113,10 @@ initialize_server_options(ServerOptions *options)
     options->kerberos_ticket_cleanup = -1;
     options->kerberos_get_afs_token = -1;
     options->gss_authentication=-1;
+    options->gss_keyex = -1;
     options->gss_cleanup_creds = -1;
     options->gss_strict_acceptor = -1;
+    options->gss_store_rekey = -1;
     options->password_authentication = -1;
     options->kbd_interactive_authentication = -1;
     options->challenge_response_authentication = -1;
@@ -292,10 +294,14 @@ fill_default_server_options(ServerOptions *options)
 #else
         options->gss_authentication = 0;
 #endif
+    if (options->gss_keyex == -1)
+        options->gss_keyex = 0;
     if (options->gss_cleanup_creds == -1)
         options->gss_cleanup_creds = 1;
     if (options->gss_strict_acceptor == -1)
-        options->gss_strict_acceptor = 0;
+        options->gss_strict_acceptor = 1;
+    if (options->gss_store_rekey == -1)
+        options->gss_store_rekey = 0;
     if (options->password_authentication == -1)
         options->password_authentication = 1;
     if (options->kbd_interactive_authentication == -1)
@@ -438,6 +444,7 @@ typedef enum {
     sHostKeyAlgorithms,
     sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
     sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
+    sGssKeyEx, sGssStoreRekey,
     sAcceptEnv, sPermitTunnel,
     sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
     sUsePrivilegeSeparation, sAllowAgentForwarding,
@@ -518,12 +525,20 @@ static struct {
 #else /* USE_GSS_STORE_CRED */
     { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
 #endif /* USE_GSS_STORE_CRED */
+    { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
     { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
+    { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
+    { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
 #else
     { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
     { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
+    { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
     { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
+    { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
+    { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
 #endif
+    { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
+    { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
     { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
     { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
     { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
@@ -1281,6 +1296,10 @@ process_server_config_line(ServerOptions *options, char *line,
         intptr = &options->gss_authentication;
         goto parse_flag;
+    case sGssKeyEx:
+        intptr = &options->gss_keyex;
+        goto parse_flag;
+
     case sGssCleanupCreds:
         intptr = &options->gss_cleanup_creds;
         goto parse_flag;
@@ -1289,6 +1308,10 @@ process_server_config_line(ServerOptions *options, char *line,
         intptr = &options->gss_strict_acceptor;
         goto parse_flag;
+    case sGssStoreRekey:
+        intptr = &options->gss_store_rekey;
+        goto parse_flag;
+
     case sPasswordAuthentication:
         intptr = &options->password_authentication;
         goto parse_flag;
@@ -2353,7 +2376,10 @@ dump_config(ServerOptions *o)
 #endif
 #ifdef GSSAPI
     dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
+    dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
     dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
+    dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
+    dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey);
 #endif
     dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
     dump_cfg_fmtint(sKbdInteractiveAuthentication,
diff --git a/servconf.h b/servconf.h
index 104852f7..729819e7 100644
--- a/servconf.h
+++ b/servconf.h
@@ -116,8 +116,10 @@ typedef struct {
     int     kerberos_get_afs_token;        /* If true, try to get AFS token if
                          * authenticated with Kerberos. */
     int     gss_authentication;    /* If true, permit GSSAPI authentication */
+    int     gss_keyex;        /* If true, permit GSSAPI key exchange */
     int     gss_cleanup_creds;    /* If true, destroy cred cache on logout */
     int     gss_strict_acceptor;    /* If true, restrict the GSSAPI acceptor name */
+    int     gss_store_rekey;
     int     password_authentication;    /* If true, permit password
                          * authentication. */
     int     kbd_interactive_authentication;    /* If true, permit */
diff --git a/ssh-gss.h b/ssh-gss.h
index a99d7f08..914701bc 100644
--- a/ssh-gss.h
+++ b/ssh-gss.h
@@ -1,6 +1,6 @@
 /* $OpenBSD: ssh-gss.h,v 1.11 2014/02/26 20:28:44 djm Exp $ */
 /*
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -61,10 +61,22 @@
 #define SSH_GSS_OIDTYPE 0x06
+#define SSH2_MSG_KEXGSS_INIT                            30
+#define SSH2_MSG_KEXGSS_CONTINUE                        31
+#define SSH2_MSG_KEXGSS_COMPLETE                        32
+#define SSH2_MSG_KEXGSS_HOSTKEY                         33
+#define SSH2_MSG_KEXGSS_ERROR                           34
+#define SSH2_MSG_KEXGSS_GROUPREQ            40
+#define SSH2_MSG_KEXGSS_GROUP                41
+#define KEX_GSS_GRP1_SHA1_ID                "gss-group1-sha1-"
+#define KEX_GSS_GRP14_SHA1_ID                "gss-group14-sha1-"
+#define KEX_GSS_GEX_SHA1_ID                "gss-gex-sha1-"
+
 typedef struct {
     char *filename;
     char *envvar;
     char *envval;
+    struct passwd *owner;
     void *data;
 } ssh_gssapi_ccache;
@@ -72,8 +84,11 @@ typedef struct {
     gss_buffer_desc displayname;
     gss_buffer_desc exportedname;
     gss_cred_id_t creds;
+    gss_name_t name;
     struct ssh_gssapi_mech_struct *mech;
     ssh_gssapi_ccache store;
+    int used;
+    int updated;
 } ssh_gssapi_client;
 typedef struct ssh_gssapi_mech_struct {
@@ -84,6 +99,7 @@ typedef struct ssh_gssapi_mech_struct {
     int (*userok) (ssh_gssapi_client *, char *);
     int (*localname) (ssh_gssapi_client *, char **);
     void (*storecreds) (ssh_gssapi_client *);
+    int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *);
 } ssh_gssapi_mech;
 typedef struct {
@@ -94,10 +110,11 @@ typedef struct {
     gss_OID        oid; /* client */
     gss_cred_id_t    creds; /* server */
     gss_name_t    client; /* server */
-    gss_cred_id_t    client_creds; /* server */
+    gss_cred_id_t    client_creds; /* both */
 } Gssctxt;
 extern ssh_gssapi_mech *supported_mechs[];
+extern Gssctxt *gss_kex_context;
 int  ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
 void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
@@ -119,16 +136,32 @@ void ssh_gssapi_build_ctx(Gssctxt **);
 void ssh_gssapi_delete_ctx(Gssctxt **);
 OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
 void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
-int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *);
+int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *);
+OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
+int ssh_gssapi_credentials_updated(Gssctxt *);
 /* In the server */
+typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *,
+    const char *);
+char *ssh_gssapi_client_mechanisms(const char *, const char *);
+char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *,
+    const char *);
+gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int);
+int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *,
+    const char *);
 OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
-int ssh_gssapi_userok(char *name);
+int ssh_gssapi_userok(char *name, struct passwd *);
 OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
 void ssh_gssapi_do_child(char ***, u_int *);
 void ssh_gssapi_cleanup_creds(void);
 void ssh_gssapi_storecreds(void);
+char *ssh_gssapi_server_mechanisms(void);
+int ssh_gssapi_oid_table_ok(void);
+
+int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
+void ssh_gssapi_rekey_creds(void);
+
 #endif /* GSSAPI */
 #endif /* _SSH_GSS_H */
diff --git a/ssh_config b/ssh_config
index 90fb63f0..4e879cd2 100644
--- a/ssh_config
+++ b/ssh_config
@@ -26,6 +26,8 @@
 #   HostbasedAuthentication no
 #   GSSAPIAuthentication no
 #   GSSAPIDelegateCredentials no
+#   GSSAPIKeyExchange no
+#   GSSAPITrustDNS no
 #   BatchMode no
 #   CheckHostIP yes
 #   AddressFamily any
diff --git a/ssh_config.4 b/ssh_config.4
index 0953f11c..4492ecaf 100644
--- a/ssh_config.4
+++ b/ssh_config.4
@@ -759,10 +759,42 @@ The default is
 Specifies whether user authentication based on GSSAPI is allowed.
 The default on Solaris is
 .Dq yes .
+.It Cm GSSAPIKeyExchange
+Specifies whether key exchange based on GSSAPI may be used. When using
+GSSAPI key exchange the server need not have a host key.
+The default is
+.Cm no .
+.It Cm GSSAPIClientIdentity
+If set, specifies the GSSAPI client identity that ssh should use when
+connecting to the server. The default is unset, which means that the default
+identity will be used.
+.It Cm GSSAPIServerIdentity
+If set, specifies the GSSAPI server identity that ssh should expect when
+connecting to the server. The default is unset, which means that the
+expected GSSAPI server identity will be determined from the target
+hostname.
 .It Cm GSSAPIDelegateCredentials
 Forward (delegate) credentials to the server.
 The default is
 .Cm no .
+.It Cm GSSAPIRenewalForcesRekey
+If set to
+.Cm yes
+then renewal of the client's GSSAPI credentials will force the rekeying of the
+ssh connection. With a compatible server, this can delegate the renewed
+credentials to a session on the server.
+The default is
+.Cm no .
+.It Cm GSSAPITrustDns
+Set to
+.Cm yes
+to indicate that the DNS is trusted to securely canonicalize
+the name of the host being connected to. If
+.Cm no ,
+the hostname entered on the
+command line will be passed untouched to the GSSAPI library.
+The default is
+.Cm no .
 .It Cm HashKnownHosts
 Indicates that
 .Xr ssh 1
diff --git a/sshconnect2.c b/sshconnect2.c
index 56942ca7..7959d048 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -166,6 +166,11 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
     struct kex *kex;
     int r;
+#ifdef GSSAPI
+    char *orig = NULL, *gss = NULL;
+    char *gss_host = NULL;
+#endif
+
     xxx_host = host;
     xxx_hostaddr = hostaddr;
@@ -196,6 +201,35 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
             order_hostkeyalgs(host, hostaddr, port));
     }
+#ifdef GSSAPI
+    if (options.gss_keyex) {
+        /* Add the GSSAPI mechanisms currently supported on this
+         * client to the key exchange algorithm proposal */
+        orig = myproposal[PROPOSAL_KEX_ALGS];
+
+        if (options.gss_server_identity)
+            gss_host = xstrdup(options.gss_server_identity);
+        else if (options.gss_trust_dns)
+            gss_host = remote_hostname(active_state);
+        else
+            gss_host = xstrdup(host);
+
+        gss = ssh_gssapi_client_mechanisms(gss_host,
+            options.gss_client_identity);
+        if (gss) {
+            debug("Offering GSSAPI proposal: %s", gss);
+            xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
+                "%s,%s", gss, orig);
+
+            /* If we've got GSSAPI algorithms, then we also
+             * support the 'null' hostkey, as a last resort */
+            orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
+            xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
+                "%s,null", orig);
+        }
+    }
+#endif
+
     if (options.rekey_limit || options.rekey_interval)
         packet_set_rekey_limits((u_int32_t)options.rekey_limit,
             (time_t)options.rekey_interval);
@@ -217,15 +251,41 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
 # endif
 #endif
     kex->kex[KEX_C25519_SHA256] = kexc25519_client;
+#ifdef GSSAPI
+    if (options.gss_keyex) {
+        kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
+        kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
+        kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
+    }
+#endif
     kex->client_version_string=client_version_string;
     kex->server_version_string=server_version_string;
     kex->verify_host_key=&verify_host_key_callback;
+#ifdef GSSAPI
+    if (options.gss_keyex) {
+        kex->gss_deleg_creds = options.gss_deleg_creds;
+        kex->gss_trust_dns = options.gss_trust_dns;
+        kex->gss_client = options.gss_client_identity;
+        kex->gss_host = gss_host;
+    }
+#endif
+
     dispatch_run(DISPATCH_BLOCK, &kex->done, active_state);
     /* remove ext-info from the KEX proposals for rekeying */
     myproposal[PROPOSAL_KEX_ALGS] =
         compat_kex_proposal(options.kex_algorithms);
+#ifdef GSSAPI
+    /* repair myproposal after it was crumpled by the */
+    /* ext-info removal above */
+    if (gss) {
+        orig = myproposal[PROPOSAL_KEX_ALGS];
+        xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
+            "%s,%s", gss, orig);
+        free(gss);
+    }
+#endif
     if ((r = kex_prop2buf(kex->my, myproposal)) != 0)
         fatal("kex_prop2buf: %s", ssh_err(r));
@@ -315,6 +375,7 @@ int    input_gssapi_token(int type, u_int32_t, void *);
 int    input_gssapi_hash(int type, u_int32_t, void *);
 int    input_gssapi_error(int, u_int32_t, void *);
 int    input_gssapi_errtok(int, u_int32_t, void *);
+int    userauth_gsskeyex(Authctxt *authctxt);
 #endif
 void    userauth(Authctxt *, char *);
@@ -331,6 +392,11 @@ static char *authmethods_get(void);
 Authmethod authmethods[] = {
 #ifdef GSSAPI
+    {"gssapi-keyex",
+        userauth_gsskeyex,
+        NULL,
+        &options.gss_authentication,
+        NULL},
     {"gssapi-with-mic",
         userauth_gssapi,
         NULL,
@@ -675,25 +741,40 @@ userauth_gssapi(Authctxt *authctxt)
     static u_int mech = 0;
     OM_uint32 min;
     int ok = 0;
+    char *gss_host;
+
+    if (options.gss_server_identity)
+        gss_host = xstrdup(options.gss_server_identity);
+    else if (options.gss_trust_dns)
+        gss_host = remote_hostname(active_state);
+    else
+        gss_host = xstrdup(authctxt->host);
     /* Try one GSSAPI method at a time, rather than sending them all at
      * once. */
     if (gss_supported == NULL)
-        gss_indicate_mechs(&min, &gss_supported);
+        if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
+            gss_supported = NULL;
+            free(gss_host);
+            return 0;
+        }
     /* Check to see if the mechanism is usable before we offer it */
     while (mech < gss_supported->count && !ok) {
         /* My DER encoding requires length<128 */
         if (gss_supported->elements[mech].length < 128 &&
             ssh_gssapi_check_mechanism(&gssctxt,
-            &gss_supported->elements[mech], authctxt->host)) {
+            &gss_supported->elements[mech], gss_host,
+                    options.gss_client_identity)) {
             ok = 1; /* Mechanism works */
         } else {
             mech++;
         }
     }
+    free(gss_host);
+
     if (!ok)
         return 0;
@@ -784,8 +865,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
 {
     Authctxt *authctxt = ctxt;
     Gssctxt *gssctxt;
-    int oidlen;
-    char *oidv;
+    u_int oidlen;
+    u_char *oidv;
     if (authctxt == NULL)
         fatal("input_gssapi_response: no authentication context");
@@ -898,6 +979,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
     free(lang);
     return 0;
 }
+
+int
+userauth_gsskeyex(Authctxt *authctxt)
+{
+    Buffer b;
+    gss_buffer_desc gssbuf;
+    gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
+    OM_uint32 ms;
+
+    static int attempt = 0;
+    if (attempt++ >= 1)
+        return (0);
+
+    if (gss_kex_context == NULL) {
+        debug("No valid Key exchange context");
+        return (0);
+    }
+
+    ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
+        "gssapi-keyex");
+
+    gssbuf.value = buffer_ptr(&b);
+    gssbuf.length = buffer_len(&b);
+
+    if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
+        buffer_free(&b);
+        return (0);
+    }
+
+    packet_start(SSH2_MSG_USERAUTH_REQUEST);
+    packet_put_cstring(authctxt->server_user);
+    packet_put_cstring(authctxt->service);
+    packet_put_cstring(authctxt->method->name);
+    packet_put_string(mic.value, mic.length);
+    packet_send();
+
+    buffer_free(&b);
+    gss_release_buffer(&ms, &mic);
+
+    return (1);
+}
+
 #endif /* GSSAPI */
 int
diff --git a/sshd.c b/sshd.c
index eee363ab..e460c238 100644
--- a/sshd.c
+++ b/sshd.c
@@ -123,6 +123,10 @@
 #include "version.h"
 #include "ssherr.h"
+#ifdef USE_SECURITY_SESSION_API
+#include <Security/AuthSession.h>
+#endif
+
 /* Re-exec fds */
 #define REEXEC_DEVCRYPTO_RESERVED_FD    (STDERR_FILENO + 1)
 #define REEXEC_STARTUP_PIPE_FD        (STDERR_FILENO + 2)
@@ -531,7 +535,7 @@ privsep_preauth_child(void)
 #ifdef GSSAPI
     /* Cache supported mechanism OIDs for later use */
-    if (options.gss_authentication)
+    if (options.gss_authentication || options.gss_keyex)
         ssh_gssapi_prepare_supported_oids();
 #endif
@@ -1705,10 +1709,13 @@ main(int ac, char **av)
             key ? "private" : "agent", i, sshkey_ssh_name(pubkey), fp);
         free(fp);
     }
+#ifndef GSSAPI
+    /* The GSSAPI key exchange can run without a host key */
     if (!sensitive_data.have_ssh2_key) {
         logit("sshd: no hostkeys available -- exiting.");
         exit(1);
     }
+#endif
     /*
      * Load certificates. They are stored in an array at identical
@@ -1978,6 +1985,60 @@ main(int ac, char **av)
         remote_ip, remote_port, laddr,  ssh_local_port(ssh));
     free(laddr);
+#ifdef USE_SECURITY_SESSION_API
+    /*
+     * Create a new security session for use by the new user login if
+     * the current session is the root session or we are not launched
+     * by inetd (eg: debugging mode or server mode).  We do not
+     * necessarily need to create a session if we are launched from
+     * inetd because Panther xinetd will create a session for us.
+     *
+     * The only case where this logic will fail is if there is an
+     * inetd running in a non-root session which is not creating
+     * new sessions for us.  Then all the users will end up in the
+     * same session (bad).
+     *
+     * When the client exits, the session will be destroyed for us
+     * automatically.
+     *
+     * We must create the session before any credentials are stored
+     * (including AFS pags, which happens a few lines below).
+     */
+    {
+        OSStatus err = 0;
+        SecuritySessionId sid = 0;
+        SessionAttributeBits sattrs = 0;
+
+        err = SessionGetInfo(callerSecuritySession, &sid, &sattrs);
+        if (err)
+            error("SessionGetInfo() failed with error %.8X",
+                (unsigned) err);
+        else
+            debug("Current Session ID is %.8X / Session Attributes are %.8X",
+                (unsigned) sid, (unsigned) sattrs);
+
+        if (inetd_flag && !(sattrs & sessionIsRoot))
+            debug("Running in inetd mode in a non-root session... "
+                "assuming inetd created the session for us.");
+        else {
+            debug("Creating new security session...");
+            err = SessionCreate(0, sessionHasTTY | sessionIsRemote);
+            if (err)
+                error("SessionCreate() failed with error %.8X",
+                    (unsigned) err);
+
+            err = SessionGetInfo(callerSecuritySession, &sid,
+                &sattrs);
+            if (err)
+                error("SessionGetInfo() failed with error %.8X",
+                    (unsigned) err);
+            else
+                debug("New Session ID is %.8X / Session Attributes are %.8X",
+                    (unsigned) sid, (unsigned) sattrs);
+        }
+    }
+#endif
+
     /*
      * We don't want to listen forever unless the other side
      * successfully authenticates itself.  So we set up an alarm which is
@@ -2179,6 +2240,48 @@ do_ssh2_kex(void)
     myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal(
         list_hostkey_types());
+#ifdef GSSAPI
+    {
+    char *orig;
+    char *gss = NULL;
+    char *newstr = NULL;
+    orig = myproposal[PROPOSAL_KEX_ALGS];
+
+    /*
+     * If we don't have a host key, then there's no point advertising
+     * the other key exchange algorithms
+     */
+
+    if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
+        orig = NULL;
+
+    if (options.gss_keyex)
+        gss = ssh_gssapi_server_mechanisms();
+    else
+        gss = NULL;
+
+    if (gss && orig)
+        xasprintf(&newstr, "%s,%s", gss, orig);
+    else if (gss)
+        newstr = gss;
+    else if (orig)
+        newstr = orig;
+
+    /*
+     * If we've got GSSAPI mechanisms, then we've got the 'null' host
+     * key alg, but we can't tell people about it unless its the only
+       * host key algorithm we support
+     */
+    if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
+        myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
+
+    if (newstr)
+        myproposal[PROPOSAL_KEX_ALGS] = newstr;
+    else
+        fatal("No supported key exchange algorithms");
+    }
+#endif
+
     /* start key exchange */
     if ((r = kex_setup(active_state, myproposal)) != 0)
         fatal("kex_setup: %s", ssh_err(r));
@@ -2196,6 +2299,13 @@ do_ssh2_kex(void)
 # endif
 #endif
     kex->kex[KEX_C25519_SHA256] = kexc25519_server;
+#ifdef GSSAPI
+    if (options.gss_keyex) {
+        kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
+        kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
+        kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
+    }
+#endif
     kex->server = 1;
     kex->client_version_string=client_version_string;
     kex->server_version_string=server_version_string;
diff --git a/sshd_config b/sshd_config
index 9f09e4a6..00e5a728 100644
--- a/sshd_config
+++ b/sshd_config
@@ -70,6 +70,8 @@ AuthorizedKeysFile    .ssh/authorized_keys
 # GSSAPI options
 #GSSAPIAuthentication no
 #GSSAPICleanupCredentials yes
+#GSSAPIStrictAcceptorCheck yes
+#GSSAPIKeyExchange no
 # Set this to 'yes' to enable PAM authentication, account processing,
 # and session processing. If this is enabled, PAM authentication will
diff --git a/sshd_config.4 b/sshd_config.4
index 45c54629..de03ac5e 100644
--- a/sshd_config.4
+++ b/sshd_config.4
@@ -623,6 +623,11 @@ The default is
 Specifies whether user authentication based on GSSAPI is allowed.
 The default on Solaris is
 .Cm yes .
+.It Cm GSSAPIKeyExchange
+Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
+doesn't rely on ssh keys to verify host identity.
+The default is
+.Cm no .
 .It Cm GSSAPICleanupCredentials
 Specifies whether to automatically destroy the user's credentials cache
 on logout.
@@ -642,6 +647,11 @@ machine's default store.
 This facility is provided to assist with operation on multi homed machines.
 The default is
 .Cm yes .
+.It Cm GSSAPIStoreCredentialsOnRekey
+Controls whether the user's GSSAPI credentials should be updated following a
+successful connection rekeying. This option can be used to accepted renewed
+or updated credentials from a compatible client. The default is
+.Cm no .
 .It Cm HostbasedAcceptedKeyTypes
 Specifies the key types that will be accepted for hostbased authentication
 as a comma-separated pattern list.
diff --git a/sshkey.c b/sshkey.c
index c01da6c3..377d72fa 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -114,6 +114,7 @@ static const struct keytype keytypes[] = {
 #  endif /* OPENSSL_HAS_NISTP521 */
 # endif /* OPENSSL_HAS_ECC */
 #endif /* WITH_OPENSSL */
+    { "null", "null", KEY_NULL, 0, 0, 0 },
     { NULL, NULL, -1, -1, 0, 0 }
 };
@@ -202,7 +203,7 @@ sshkey_alg_list(int certs_only, int plain_only, char sep)
     const struct keytype *kt;
     for (kt = keytypes; kt->type != -1; kt++) {
-        if (kt->name == NULL || kt->sigonly)
+        if (kt->name == NULL || kt->sigonly || kt->type == KEY_NULL)
             continue;
         if ((certs_only && !kt->cert) || (plain_only && kt->cert))
             continue;
diff --git a/sshkey.h b/sshkey.h
index f3936384..7eb2a139 100644
--- a/sshkey.h
+++ b/sshkey.h
@@ -62,6 +62,7 @@ enum sshkey_types {
     KEY_DSA_CERT,
     KEY_ECDSA_CERT,
     KEY_ED25519_CERT,
+    KEY_NULL,
     KEY_UNSPEC
 };
--
2.11.0
components/network/openssh/patches/0015-Enable-login-to-a-role-if-PAM-is-ok-with-it.patch
File was renamed from components/network/openssh/patches/0016-Enable-login-to-a-role-if-PAM-is-ok-with-it.patch
@@ -1,22 +1,22 @@
From d9c44a1bca6f053bebcdf9eb185fbe09fd11f19e Mon Sep 17 00:00:00 2001
From bc29dcd14f8623098d2383bd36e486145948a653 Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:38:19 -0700
Subject: [PATCH 16/34] Enable login to a role if PAM is ok with it
Subject: [PATCH 15/34] Enable login to a role if PAM is ok with it
---
 auth-pam.c        | 14 ++++++++++++++
 auth-pam.h        |  3 +++
 auth-pam.h        |  4 ++++
 auth.h            |  3 +++
 auth2-hostbased.c | 10 ++++++++++
 auth2.c           |  8 ++++++++
 monitor.c         | 15 ++++++++++++++-
 6 files changed, 52 insertions(+), 1 deletion(-)
 6 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/auth-pam.c b/auth-pam.c
index 4ca0a58..d049779 100644
index 70a25c19..46bf722e 100644
--- a/auth-pam.c
+++ b/auth-pam.c
@@ -1039,6 +1039,20 @@ do_pam_account(void)
@@ -1069,6 +1069,20 @@ do_pam_account(void)
     return (sshpam_account_status);
 }
 
@@ -35,38 +35,39 @@
+#endif
+
 void
 do_pam_set_tty(const char *tty)
 do_pam_setcred(int init)
 {
diff --git a/auth-pam.h b/auth-pam.h
index a1a2b52..6c41fd9 100644
index c47b442e..892a27bc 100644
--- a/auth-pam.h
+++ b/auth-pam.h
@@ -35,6 +35,9 @@ void start_pam(Authctxt *);
@@ -29,6 +29,10 @@ void start_pam(Authctxt *);
 void finish_pam(void);
 u_int do_pam_account(void);
 void do_pam_session(void);
+#ifdef HAVE_PAM_AUSER
+void do_pam_set_auser(const char *);
+#endif
 void do_pam_set_tty(const char *);
+void do_pam_set_tty(const char *);
 void do_pam_setcred(int );
 void do_pam_chauthtok(void);
 int do_pam_putenv(char *, char *);
diff --git a/auth.h b/auth.h
index 985053c..6883f16 100644
index 4a7f2c1f..b4efc255 100644
--- a/auth.h
+++ b/auth.h
@@ -84,6 +84,9 @@ struct Authctxt {
 #ifdef PAM_ENHANCEMENT
         char            *authmethod_name;
 #endif
     char        *authmethod_name;
 #endif
+#ifdef HAVE_PAM_AUSER
+    char        *auser;
+#endif
+#endif
 };
 /*
  * Every authentication method has to handle authentication requests for
diff --git a/auth2-hostbased.c b/auth2-hostbased.c
index e2327cf..c0fcc4d 100644
index 1b3c3b20..2c51bd2b 100644
--- a/auth2-hostbased.c
+++ b/auth2-hostbased.c
@@ -85,6 +85,9 @@ userauth_hostbased(Authctxt *authctxt)
@@ -94,7 +95,7 @@
 done:
     debug2("userauth_hostbased: authenticated %d", authenticated);
diff --git a/auth2.c b/auth2.c
index 5a3ef1b..b456237 100644
index 6a9f936b..e68aa6d3 100644
--- a/auth2.c
+++ b/auth2.c
@@ -339,6 +339,14 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
@@ -113,10 +114,10 @@
 
 #if defined(USE_PAM) && defined(PAM_ENHANCEMENT)
diff --git a/monitor.c b/monitor.c
index dc3e7bf..ef6b45b 100644
index b0c9b4f4..d2ad5425 100644
--- a/monitor.c
+++ b/monitor.c
@@ -460,6 +460,12 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
@@ -404,6 +404,12 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
         }
     }
 
@@ -129,7 +130,7 @@
     if (!authctxt->valid)
         fatal("%s: authenticated invalid user", __func__);
     if (strcmp(auth_method, "unknown") == 0)
@@ -688,12 +694,14 @@ monitor_reset_key_state(void)
@@ -603,12 +609,14 @@ monitor_reset_key_state(void)
 {
     /* reset state */
     free(key_blob);
@@ -145,9 +146,9 @@
     hostbased_chost = NULL;
 }
 
@@ -1143,6 +1151,11 @@ mm_answer_pam_account(int sock, Buffer *m)
@@ -1066,6 +1074,11 @@ mm_answer_pam_account(int sock, Buffer *m)
     if (!options.use_pam)
         fatal("UsePAM not set, but ended up in %s anyway", __func__);
         fatal("%s: PAM not enabled", __func__);
 
+#ifdef HAVE_PAM_AUSER
+    if (hostbased_cuser != NULL)
@@ -158,5 +159,5 @@
 
     buffer_put_int(m, ret);
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0015-GSS-API-key-exchange-support.patch
File was deleted
components/network/openssh/patches/0016-PAM-setcred-failures.patch
File was renamed from components/network/openssh/patches/0017-PAM-setcred-failures.patch
@@ -1,7 +1,7 @@
From 94dc5c2ab3457fd002a10e9d2a42059a17ed83b6 Mon Sep 17 00:00:00 2001
From 37431ef55b807e6d00fd45b54a57b7ba6df81b95 Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:38:26 -0700
Subject: [PATCH 17/34] PAM setcred failures
Subject: [PATCH 16/34] PAM setcred failures
#
# This patch contains bug fixes to the PAM credential and session operations.
@@ -20,10 +20,10 @@
 1 file changed, 13 insertions(+)
diff --git a/auth-pam.c b/auth-pam.c
index d049779..8bad498 100644
index 46bf722e..dcd0f208 100644
--- a/auth-pam.c
+++ b/auth-pam.c
@@ -1084,12 +1084,19 @@ do_pam_setcred(int init)
@@ -1102,12 +1102,19 @@ do_pam_setcred(int init)
         sshpam_cred_established = 1;
         return;
     }
@@ -43,7 +43,7 @@
 }
 
 static int
@@ -1182,10 +1189,16 @@ do_pam_session(void)
@@ -1200,10 +1207,16 @@ do_pam_session(void)
     if (sshpam_err == PAM_SUCCESS)
         sshpam_session_open = 1;
     else {
@@ -61,5 +61,5 @@
 
 }
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0017-Don-t-call-do_pam_setcred-twice.patch
File was renamed from components/network/openssh/patches/0018-Don-t-call-do_pam_setcred-twice.patch
@@ -1,7 +1,7 @@
From 6a7f4e87eace242d1761b5a8c3a17c119f9b527f Mon Sep 17 00:00:00 2001
From 1881e2dc1ef484c877e60a40c820f4d2df980a48 Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:38:41 -0700
Subject: [PATCH 18/34] Don't call do_pam_setcred twice
Subject: [PATCH 17/34] Don't call do_pam_setcred twice
# This issue has been raised with the upstream OpenSSH community:
#
@@ -30,7 +30,7 @@
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/platform.c b/platform.c
index ee313da..8362a08 100644
index 973a63e4..fc9c079e 100644
--- a/platform.c
+++ b/platform.c
@@ -145,7 +145,7 @@ platform_setusercontext(struct passwd *pw)
@@ -43,5 +43,5 @@
      * PAM credentials may take the form of supplementary groups.
      * These will have been wiped by the above initgroups() call.
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0018-Per-session-xauthfile.patch
File was renamed from components/network/openssh/patches/0019-Per-session-xauthfile.patch
@@ -1,7 +1,7 @@
From a0027fbda837126e12d04098019a133ea83a9b75 Mon Sep 17 00:00:00 2001
From cb6c8f4391f75983553dc576014ab58695eee3eb Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Tue, 22 Dec 2015 17:12:50 -0800
Subject: [PATCH 19/34] Per-session xauthfile
Subject: [PATCH 18/34] Per-session xauthfile
This patch is to fix a X11 connection failure when a user's home directory
is read-only.
@@ -16,7 +16,7 @@
 2 files changed, 137 insertions(+), 4 deletions(-)
diff --git a/session.c b/session.c
index 87fddfc..36f8c62 100644
index a08aa69d..9586901e 100644
--- a/session.c
+++ b/session.c
@@ -63,6 +63,10 @@
@@ -30,7 +30,7 @@
 #include "openbsd-compat/sys-queue.h"
 #include "xmalloc.h"
 #include "ssh.h"
@@ -133,6 +137,11 @@ static void do_authenticated2(Authctxt *);
@@ -131,6 +135,11 @@ static void do_authenticated2(Authctxt *);
 
 static int session_pty_req(Session *);
 
@@ -42,7 +42,7 @@
 /* import */
 extern ServerOptions options;
 extern char *__progname;
@@ -1242,6 +1251,11 @@ do_setup_env(Session *s, const char *shell)
@@ -1056,6 +1065,11 @@ do_setup_env(Session *s, const char *shell)
     if (getenv("TZ"))
         child_set_env(&env, &envsize, "TZ", getenv("TZ"));
 
@@ -52,9 +52,9 @@
+#endif
+
     /* Set custom environment options from RSA authentication. */
     if (!options.use_login) {
         while (custom_environment) {
@@ -2189,6 +2203,11 @@ session_x11_req(Session *s)
     while (custom_environment) {
         struct envstring *ce = custom_environment;
@@ -1958,6 +1972,11 @@ session_x11_req(Session *s)
 {
     int success;
 
@@ -66,7 +66,7 @@
     if (s->auth_proto != NULL || s->auth_data != NULL) {
         error("session_x11_req: session %d: "
             "x11 forwarding already active", s->self);
@@ -2200,19 +2219,78 @@ session_x11_req(Session *s)
@@ -1969,19 +1988,78 @@ session_x11_req(Session *s)
     s->screen = packet_get_int();
     packet_check_eom();
 
@@ -149,7 +149,7 @@
     return success;
 }
 
@@ -2403,6 +2481,51 @@ session_pty_cleanup(Session *s)
@@ -2170,6 +2248,51 @@ session_pty_cleanup(Session *s)
     PRIVSEP(session_pty_cleanup2(s));
 }
 
@@ -201,7 +201,7 @@
 static char *
 sig2name(int sig)
 {
@@ -2542,6 +2665,9 @@ session_close(Session *s)
@@ -2310,6 +2433,9 @@ session_close(Session *s)
     free(s->auth_display);
     free(s->auth_data);
     free(s->auth_proto);
@@ -211,7 +211,7 @@
     free(s->subsys);
     if (s->env != NULL) {
         for (i = 0; i < s->num_env; i++) {
@@ -2793,6 +2919,10 @@ do_cleanup(Authctxt *authctxt)
@@ -2556,6 +2682,10 @@ do_cleanup(Authctxt *authctxt)
     /* remove agent socket */
     auth_sock_cleanup_proc(authctxt->pw);
 
@@ -223,7 +223,7 @@
      * Cleanup ptys/utmp only if privsep is disabled,
      * or if running in monitor.
diff --git a/session.h b/session.h
index 6a2f35e..276cd04 100644
index 98e1dafe..f211c19c 100644
--- a/session.h
+++ b/session.h
@@ -49,6 +49,9 @@ struct Session {
@@ -235,7 +235,7 @@
+#endif
     int    single_connection;
 
     /* proto 2 */
     int    chanid;
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0019-PubKeyPlugin-support.patch
File was renamed from components/network/openssh/patches/0020-PubKeyPlugin-support.patch
@@ -1,7 +1,7 @@
From 730e53f3bebc365d2d2a2b48679e89196f7a3aee Mon Sep 17 00:00:00 2001
From 1e9262a6ff5a256ef884dcb6cb4c188f33721c7c Mon Sep 17 00:00:00 2001
From: Alex Wilson <alex.wilson@joyent.com>
Date: Mon, 3 Aug 2015 16:27:44 -0700
Subject: [PATCH 20/34] PubKeyPlugin support
Subject: [PATCH 19/34] PubKeyPlugin support
This adds the PubKeyPlugin directive and associated code from
SunSSH, allowing an in-process shared library to be called
@@ -13,7 +13,7 @@
 3 files changed, 155 insertions(+)
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index 41b34ae..c920e49 100644
index 20f3309e..01daef4a 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -22,6 +22,11 @@
@@ -58,7 +58,7 @@
 static int
 userauth_pubkey(Authctxt *authctxt)
 {
@@ -1038,6 +1054,125 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
@@ -1071,6 +1087,125 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
     return found_key;
 }
 
@@ -184,7 +184,7 @@
 /*
  * Check whether key authenticates and authorises the user.
  */
@@ -1056,6 +1191,10 @@ user_key_allowed(struct passwd *pw, Key *key, int auth_attempt)
@@ -1089,6 +1224,10 @@ user_key_allowed(struct passwd *pw, Key *key, int auth_attempt)
     if (success)
         return success;
 
@@ -196,10 +196,10 @@
     if (success > 0)
         return success;
diff --git a/servconf.c b/servconf.c
index 157a64a..7e6c7f8 100644
index 881edd95..b492f32b 100644
--- a/servconf.c
+++ b/servconf.c
@@ -182,6 +182,7 @@ initialize_server_options(ServerOptions *options)
@@ -178,6 +178,7 @@ initialize_server_options(ServerOptions *options)
      */
     options->pam_service_per_authmethod = 1;
 #endif
@@ -207,23 +207,23 @@
 }
 
 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
@@ -472,6 +473,7 @@ typedef enum {
@@ -459,6 +460,7 @@ typedef enum {
     sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
     sStreamLocalBindMask, sStreamLocalBindUnlink,
     sAllowStreamLocalForwarding, sFingerprintHash,
     sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
+    sPubKeyPlugin,
     sDeprecated, sUnsupported
     sDeprecated, sIgnore, sUnsupported
 } ServerOpCodes;
 
@@ -647,6 +649,7 @@ static struct {
     { "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL },
@@ -641,6 +643,7 @@ static struct {
     { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
     { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
     { "disableforwarding", sDisableForwarding, SSHCFG_ALL },
+    { "pubkeyplugin", sPubKeyPlugin, SSHCFG_ALL },
     { NULL, sBadOption, 0 }
 };
 
@@ -1969,6 +1972,18 @@ process_server_config_line(ServerOptions *options, char *line,
@@ -1964,6 +1967,18 @@ process_server_config_line(ServerOptions *options, char *line,
         }
         break;
 
@@ -240,20 +240,20 @@
+        break;
+
     case sDeprecated:
         logit("%s line %d: Deprecated option %s",
             filename, linenum, arg);
     case sIgnore:
     case sUnsupported:
diff --git a/servconf.h b/servconf.h
index 2175645..80e152f 100644
index 729819e7..4197ffde 100644
--- a/servconf.h
+++ b/servconf.h
@@ -206,6 +206,7 @@ typedef struct {
@@ -201,6 +201,7 @@ typedef struct {
 #endif
     int    fingerprint_hash;
+    char   *pubkey_plugin;
 }       ServerOptions;
 
 /* Information about the incoming connection as used by Match */
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0020-Compatibility-fix-for-ListenAddress.patch
File was renamed from components/network/openssh/patches/0021-Compatibility-fix-for-ListenAddress.patch
@@ -1,7 +1,7 @@
From 89cc9519a677be0208678a3e3c80584b4f7c7a74 Mon Sep 17 00:00:00 2001
From 4b48c7d021681a1e5b2d44dd0c5cad31238b8083 Mon Sep 17 00:00:00 2001
From: Alex Wilson <alex.wilson@joyent.com>
Date: Mon, 3 Aug 2015 17:27:41 -0700
Subject: [PATCH 21/34] Compatibility fix for "ListenAddress ::"
Subject: [PATCH 20/34] Compatibility fix for "ListenAddress ::"
In SunSSH, a config that specifies only "ListenAddress ::" in
fact will listen on both IPv4 and IPv6.
@@ -10,10 +10,10 @@
 1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/servconf.c b/servconf.c
index 7e6c7f8..1b6cc34 100644
index b492f32b..1501af6a 100644
--- a/servconf.c
+++ b/servconf.c
@@ -769,11 +769,22 @@ process_queued_listen_addrs(ServerOptions *options)
@@ -763,11 +763,22 @@ process_queued_listen_addrs(ServerOptions *options)
         options->address_family = AF_UNSPEC;
 
     for (i = 0; i < options->num_queued_listens; i++) {
@@ -39,5 +39,5 @@
     options->queued_listen_addrs = NULL;
     free(options->queued_listen_ports);
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0021-Try-to-create-privsep-chroot-dir-if-it-doesn-t-exist.patch
File was renamed from components/network/openssh/patches/0023-Try-to-create-privsep-chroot-dir-if-it-doesn-t-exist.patch
@@ -1,7 +1,7 @@
From d383529c65321d6c0fa10230b3d3f05941fd20eb Mon Sep 17 00:00:00 2001
From e68e88d2de7449b53c98ad7fc3e1ff169313bef3 Mon Sep 17 00:00:00 2001
From: Alex Wilson <alex.wilson@joyent.com>
Date: Wed, 5 Aug 2015 12:25:15 -0700
Subject: [PATCH 23/34] Try to create privsep chroot dir if it doesn't exist
Subject: [PATCH 21/34] Try to create privsep chroot dir if it doesn't exist
 yet
---
@@ -9,10 +9,10 @@
 1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/sshd.c b/sshd.c
index f34d804..a912c1c 100644
index e460c238..67171704 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1917,11 +1917,30 @@ main(int ac, char **av)
@@ -1762,11 +1762,30 @@ main(int ac, char **av)
 
     if (use_privsep) {
         struct stat st;
@@ -47,5 +47,5 @@
 #ifdef HAVE_CYGWIN
         if (check_ntsec(_PATH_PRIVSEP_CHROOT_DIR) &&
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0022-Hack-around-umac_ctx-name-punning.patch
File was deleted
components/network/openssh/patches/0025-Re-enable-DSA-keys-for-pk-auth.patch
File was renamed from components/network/openssh/patches/0027-Re-enable-DSA-keys-for-pk-auth.patch
@@ -1,7 +1,7 @@
From 6fdd7632d7cfad601e3b354bc2a676932050060e Mon Sep 17 00:00:00 2001
From 2e157a62ac6bb1ab68f65fe8cc62c125fa485edc Mon Sep 17 00:00:00 2001
From: Alex Wilson <alex.wilson@joyent.com>
Date: Wed, 19 Aug 2015 11:35:32 -0700
Subject: [PATCH 27/34] Re-enable DSA keys for pk auth
Subject: [PATCH 25/34] Re-enable DSA keys for pk auth
---
 myproposal.h  | 4 +++-
@@ -10,10 +10,10 @@
 3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/myproposal.h b/myproposal.h
index bdd0596..7b15897 100644
index 072e36ec..f6322a73 100644
--- a/myproposal.h
+++ b/myproposal.h
@@ -99,11 +99,13 @@
@@ -108,11 +108,13 @@
     HOSTKEY_ECDSA_CERT_METHODS \
     "ssh-ed25519-cert-v01@openssh.com," \
     "ssh-rsa-cert-v01@openssh.com," \
@@ -29,10 +29,10 @@
 /* the actual algorithms */
 
diff --git a/ssh_config.4 b/ssh_config.4
index f4b471e..0e17ef9 100644
index 4492ecaf..dadd092a 100644
--- a/ssh_config.4
+++ b/ssh_config.4
@@ -1344,8 +1344,9 @@ ecdsa-sha2-nistp384-cert-v01@openssh.com,
@@ -1314,8 +1314,9 @@ ecdsa-sha2-nistp384-cert-v01@openssh.com,
 ecdsa-sha2-nistp521-cert-v01@openssh.com,
 ssh-ed25519-cert-v01@openssh.com,
 ssh-rsa-cert-v01@openssh.com,
@@ -42,12 +42,12 @@
+ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa,ssh-dss
 .Ed
 .Pp
 The
 The list of available key types may also be obtained using
diff --git a/sshd_config.4 b/sshd_config.4
index 0dec36c..8f0dbc4 100644
index de03ac5e..6a6f940b 100644
--- a/sshd_config.4
+++ b/sshd_config.4
@@ -1377,8 +1377,9 @@ ecdsa-sha2-nistp384-cert-v01@openssh.com,
@@ -1312,8 +1312,9 @@ ecdsa-sha2-nistp384-cert-v01@openssh.com,
 ecdsa-sha2-nistp521-cert-v01@openssh.com,
 ssh-ed25519-cert-v01@openssh.com,
 ssh-rsa-cert-v01@openssh.com,
@@ -57,7 +57,7 @@
+ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa,ssh-dss
 .Ed
 .Pp
 The
 The list of available key types may also be obtained using
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0026-Don-t-use-krb5-config-to-check-for-GSSAPI-on-Illumos.patch
File was renamed from components/network/openssh/patches/0028-Don-t-use-krb5-config-to-check-for-GSSAPI-on-Illumos.patch
@@ -1,18 +1,18 @@
From 6df7c448336d7997c27fb13b18154d4cc2aa9f7b Mon Sep 17 00:00:00 2001
From 1a9462ad1d73af0c20e31258bd501f5320ca01df Mon Sep 17 00:00:00 2001
From: Alex Wilson <alex.wilson@joyent.com>
Date: Fri, 21 Aug 2015 18:47:46 -0700
Subject: [PATCH 28/34] Don't use krb5-config to check for GSSAPI on Illumos
Subject: [PATCH 26/34] Don't use krb5-config to check for GSSAPI on Illumos
---
 configure.ac | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index 1846eb2..580fa5c 100644
index c7a8e662..5e64db3b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4081,6 +4081,11 @@ AC_ARG_WITH([kerberos5],
         AC_PATH_PROG([KRB5CONF], [krb5-config],
@@ -4207,6 +4207,11 @@ AC_ARG_WITH([kerberos5],
         AC_PATH_TOOL([KRB5CONF], [krb5-config],
                  [$KRB5ROOT/bin/krb5-config],
                  [$KRB5ROOT/bin:$PATH])
+        # Illumos has GSS but krb5-config doesn't talk about it
@@ -23,15 +23,15 @@
         if test -x $KRB5CONF ; then
             K5CFLAGS="`$KRB5CONF --cflags`"
             K5LIBS="`$KRB5CONF --libs`"
@@ -4122,7 +4127,7 @@ AC_ARG_WITH([kerberos5],
@@ -4248,7 +4253,7 @@ AC_ARG_WITH([kerberos5],
                      AC_CHECK_LIB([des], [des_cbc_encrypt],
                        [K5LIBS="$K5LIBS -ldes"])
                        ], [ AC_MSG_RESULT([no])
-                     K5LIBS="-lkrb5 -lk5crypto -lcom_err"
+                     K5LIBS="-lkrb5"
             ])
             AC_SEARCH_LIBS([dn_expand], [resolv])
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0027-Set-default-sshd-options-based-on-etc-default-login.patch
File was renamed from components/network/openssh/patches/0029-Set-default-sshd-options-based-on-etc-default-login.patch
@@ -1,7 +1,7 @@
From 3f7d2b018be50877e3e3489fbe5735fde48ed8e8 Mon Sep 17 00:00:00 2001
From 846518269f65af1f02714c311eb33dfa4cb291b4 Mon Sep 17 00:00:00 2001
From: Alex Wilson <alex.wilson@joyent.com>
Date: Mon, 24 Aug 2015 18:57:27 -0700
Subject: [PATCH 29/34] Set default sshd options based on /etc/default/login
Subject: [PATCH 27/34] Set default sshd options based on /etc/default/login
---
 pathnames.h   |  1 +
@@ -10,19 +10,19 @@
 3 files changed, 77 insertions(+), 2 deletions(-)
diff --git a/pathnames.h b/pathnames.h
index 0b2281b..11c9bf6 100644
index 7915c405..40284a1f 100644
--- a/pathnames.h
+++ b/pathnames.h
@@ -46,6 +46,7 @@
@@ -42,6 +42,7 @@
 #define _PATH_HOST_ED25519_KEY_FILE    SSHDIR "/ssh_host_ed25519_key"
 #define _PATH_HOST_RSA_KEY_FILE        SSHDIR "/ssh_host_rsa_key"
 #define _PATH_DH_MODULI            SSHDIR "/moduli"
+#define _PATH_DEFAULT_LOGIN        ETCDIR "/default/login"
 /* Backwards compatibility */
 #define _PATH_DH_PRIMES            SSHDIR "/primes"
 
 #ifndef _PATH_SSH_PROGRAM
 #define _PATH_SSH_PROGRAM        "/usr/bin/ssh"
diff --git a/servconf.c b/servconf.c
index 1b6cc34..0ee50e3 100644
index 1501af6a..91f8c942 100644
--- a/servconf.c
+++ b/servconf.c
@@ -30,6 +30,7 @@
@@ -33,7 +33,7 @@
 #include <errno.h>
 #ifdef HAVE_UTIL_H
 #include <util.h>
@@ -192,6 +193,64 @@ option_clear_or_none(const char *o)
@@ -188,6 +189,64 @@ option_clear_or_none(const char *o)
     return o == NULL || strcasecmp(o, "none") == 0;
 }
 
@@ -98,20 +98,20 @@
 static void
 assemble_algorithms(ServerOptions *o)
 {
@@ -220,6 +279,8 @@ fill_default_server_options(ServerOptions *options)
@@ -216,6 +275,8 @@ fill_default_server_options(ServerOptions *options)
         options->use_pam = 0;
 #endif
 
+    deflt_fill_default_server_options(options);
+
     /* Standard Options */
     if (options->protocol == SSH_PROTO_UNKNOWN)
         options->protocol = SSH_PROTO_2;
     if (options->num_host_key_files == 0) {
         /* fill default hostkeys for protocols */
diff --git a/sshd_config.4 b/sshd_config.4
index 8f0dbc4..85c7f26 100644
index 6a6f940b..0b2393dd 100644
--- a/sshd_config.4
+++ b/sshd_config.4
@@ -1137,7 +1137,13 @@ Specifies the maximum number of authentication attempts permitted per
@@ -1099,7 +1099,13 @@ Specifies the maximum number of authentication attempts permitted per
 connection.
 Once the number of failures reaches half this value,
 additional failures are logged.
@@ -126,12 +126,12 @@
 .It Cm MaxSessions
 Specifies the maximum number of open shell, login or subsystem (e.g. sftp)
 sessions permitted per network connection.
@@ -1196,7 +1202,14 @@ The default is
@@ -1150,7 +1156,14 @@ The default is
 When password authentication is allowed, it specifies whether the
 server allows login to accounts with empty password strings.
 The default is
-.Dq no .
+.Dq no
-.Cm no .
+.Cm no
+unless
+.Dq PASSREQ=YES
+is present in
@@ -143,5 +143,4 @@
 Specifies the destinations to which TCP port forwarding is permitted.
 The forwarding specification must be one of the following forms:
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0028-Compatibility-for-SunSSH_1.5-should-include-old-DH-K.patch
File was renamed from components/network/openssh/patches/0030-Compatibility-for-SunSSH_1.5-should-include-old-DH-K.patch
@@ -1,7 +1,7 @@
From 1aaf7bb147a3e1f382bc997f7ae3debd5d476fce Mon Sep 17 00:00:00 2001
From 17a12b9efaef1f92d91b51dd8fbaa452aa138451 Mon Sep 17 00:00:00 2001
From: Alex Wilson <alex.wilson@joyent.com>
Date: Fri, 4 Sep 2015 10:38:28 -0700
Subject: [PATCH 30/34] Compatibility for SunSSH_1.5* should include old DH KEx
Subject: [PATCH 28/34] Compatibility for SunSSH_1.5* should include old DH KEx
 algos
We use the kex compat mechanism here to recognise old SunSSH
@@ -15,7 +15,7 @@
 1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/compat.c b/compat.c
index 5583804..e2bebee 100644
index 69a104fb..55fb3d93 100644
--- a/compat.c
+++ b/compat.c
@@ -92,7 +92,9 @@ compat_datafellows(const char *version)
@@ -71,5 +71,5 @@
     debug2("%s: compat KEX proposal: %s", __func__, p);
     if (*p == '\0')
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0029-Accept-LANG-and-LC_-environment-variables-from-clien.patch
File was renamed from components/network/openssh/patches/0031-Accept-LANG-and-LC_-environment-variables-from-clien.patch
@@ -1,23 +1,23 @@
From af59564785eeeef3c8f9441a41c36c25cfcdd282 Mon Sep 17 00:00:00 2001
From baeb17eb76772a2dbbcc4d52a22ddfc405276db1 Mon Sep 17 00:00:00 2001
From: Alex Wilson <alex.wilson@joyent.com>
Date: Fri, 4 Sep 2015 11:04:30 -0700
Subject: [PATCH 31/34] Accept LANG and LC_* environment variables from clients
Subject: [PATCH 29/34] Accept LANG and LC_* environment variables from clients
 by default
This preserves most of the old SunSSH locale negotiation
behaviour (at least the parts that are most commonly used).
---
 servconf.c    | 27 +++++++++++++++++++++++++--
 session.c     | 26 ++++++++++++++++++++++++--
 session.c     | 25 +++++++++++++++++++++++--
 sshd_config   |  4 ++++
 sshd_config.4 | 13 ++++++++++++-
 4 files changed, 65 insertions(+), 5 deletions(-)
 4 files changed, 64 insertions(+), 5 deletions(-)
diff --git a/servconf.c b/servconf.c
index 0ee50e3..b91fd7d 100644
index 91f8c942..6f1f0068 100644
--- a/servconf.c
+++ b/servconf.c
@@ -155,7 +155,7 @@ initialize_server_options(ServerOptions *options)
@@ -150,7 +150,7 @@ initialize_server_options(ServerOptions *options)
     options->client_alive_interval = -1;
     options->client_alive_count_max = -1;
     options->num_authkeys_files = 0;
@@ -26,7 +26,7 @@
     options->permit_tun = -1;
     options->num_permitted_opens = -1;
     options->adm_forced_command = NULL;
@@ -423,6 +423,25 @@ fill_default_server_options(ServerOptions *options)
@@ -400,6 +400,25 @@ fill_default_server_options(ServerOptions *options)
         options->max_sessions = DEFAULT_SESSIONS_MAX;
     if (options->use_dns == -1)
         options->use_dns = 0;
@@ -52,7 +52,7 @@
     if (options->client_alive_interval == -1)
         options->client_alive_interval = 0;
     if (options->client_alive_count_max == -1)
@@ -1773,11 +1792,15 @@ process_server_config_line(ServerOptions *options, char *line,
@@ -1748,11 +1767,15 @@ process_server_config_line(ServerOptions *options, char *line,
             if (strchr(arg, '=') != NULL)
                 fatal("%s line %d: Invalid environment name.",
                     filename, linenum);
@@ -68,7 +68,7 @@
             options->accept_env[options->num_accept_env++] =
                 xstrdup(arg);
         }
@@ -2219,7 +2242,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
@@ -2224,7 +2247,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
     } \
 } while(0)
 #define M_CP_STRARRAYOPT(n, num_n) do {\
@@ -78,10 +78,10 @@
             dst->n[dst->num_n] = xstrdup(src->n[dst->num_n]); \
     } \
diff --git a/session.c b/session.c
index 36f8c62..cabd1d2 100644
index 9586901e..13ee4bbe 100644
--- a/session.c
+++ b/session.c
@@ -1043,6 +1043,18 @@ child_set_env(char ***envp, u_int *envsizep, const char *name,
@@ -860,6 +860,18 @@ child_set_env(char ***envp, u_int *envsizep, const char *name,
 }
 
 /*
@@ -100,7 +100,7 @@
  * Reads environment variables from the given file and adds/overrides them
  * into the environment.  If the file does not exist, this does nothing.
  * Otherwise, it must consist of empty lines, comments (line starts with '#')
@@ -1204,6 +1216,16 @@ do_setup_env(Session *s, const char *shell)
@@ -1022,6 +1034,16 @@ do_setup_env(Session *s, const char *shell)
     ssh_gssapi_do_child(&env, &envsize);
 #endif
 
@@ -114,25 +114,24 @@
+    child_inherit_env(&env, &envsize, "LC_MONETARY");
+    child_inherit_env(&env, &envsize, "LC_MESSAGES");
+
     if (!options.use_login) {
         /* Set basic environment. */
         for (i = 0; i < s->num_env; i++)
@@ -1248,8 +1270,8 @@ do_setup_env(Session *s, const char *shell)
         /* Normal systems set SHELL by default. */
         child_set_env(&env, &envsize, "SHELL", shell);
     }
     /* Set basic environment. */
     for (i = 0; i < s->num_env; i++)
         child_set_env(&env, &envsize, s->env[i].name, s->env[i].val);
@@ -1062,8 +1084,7 @@ do_setup_env(Session *s, const char *shell)
     /* Normal systems set SHELL by default. */
     child_set_env(&env, &envsize, "SHELL", shell);
-    if (getenv("TZ"))
-        child_set_env(&env, &envsize, "TZ", getenv("TZ"));
+
+    child_inherit_env(&env, &envsize, "TZ");
 
 #ifdef PER_SESSION_XAUTHFILE
         if (s->auth_file != NULL)
diff --git a/sshd_config b/sshd_config
index 05317eb..83c5e01 100644
index 62027108..9fcf2ca1 100644
--- a/sshd_config
+++ b/sshd_config
@@ -38,6 +38,10 @@ HostKey /var/ssh/ssh_host_ed25519_key
@@ -27,6 +27,10 @@ Port 22
 SyslogFacility AUTH
 LogLevel INFO
 
@@ -144,7 +143,7 @@
 
 #LoginGraceTime 2m
diff --git a/sshd_config.4 b/sshd_config.4
index 85c7f26..a1456db 100644
index 0b2393dd..fbd9b1cd 100644
--- a/sshd_config.4
+++ b/sshd_config.4
@@ -85,7 +85,18 @@ directives.
@@ -168,5 +167,5 @@
 Specifies which address family should be used by
 .Xr sshd 1M .
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0030-Temporarily-set-ssh-keygen-and-ssh-add-to-old-FP-for.patch
File was renamed from components/network/openssh/patches/0032-Temporarily-set-ssh-keygen-and-ssh-add-to-old-FP-for.patch
@@ -1,7 +1,7 @@
From 1242df0d1cab712ccbb60a0daaacb24e11af120f Mon Sep 17 00:00:00 2001
From 30642080c5d8b89043ff645010b5bbfc03c81aa5 Mon Sep 17 00:00:00 2001
From: Alex Wilson <alex.wilson@joyent.com>
Date: Wed, 9 Sep 2015 10:36:05 -0700
Subject: [PATCH 32/34] Temporarily set ssh-keygen and ssh-add to old FP format
Subject: [PATCH 30/34] Temporarily set ssh-keygen and ssh-add to old FP format
SDC and its users have a lot of scripts that expect ssh-add
and ssh-keygen to return fingerprints in the old format.
@@ -13,7 +13,7 @@
 2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/ssh-add.c b/ssh-add.c
index fb9a53e..c63488a 100644
index fb9a53e6..c63488a3 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -52,6 +52,7 @@
@@ -67,7 +67,7 @@
                 fatal("Invalid hash algorithm \"%s\"", optarg);
             break;
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 4785201..25b8049 100644
index 2a7939bf..6c0355bb 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -37,6 +37,7 @@
@@ -134,7 +134,7 @@
         comment ? comment : "no comment", sshkey_type(public));
     if (log_level >= SYSLOG_LEVEL_VERBOSE)
         printf("%s\n", ra);
@@ -2297,6 +2310,7 @@ main(int argc, char **argv)
@@ -2303,6 +2316,7 @@ main(int argc, char **argv)
             break;
         case 'E':
             fingerprint_hash = ssh_digest_alg_by_name(optarg);
@@ -143,5 +143,5 @@
                 fatal("Invalid hash algorithm \"%s\"", optarg);
             break;
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0031-Restore-tcpwrappers-libwrap-support.patch
File was renamed from components/network/openssh/patches/0033-Restore-tcpwrappers-libwrap-support.patch
@@ -1,21 +1,21 @@
From 607f7c1f63e9e7b6fbab274736537177e8e1fd55 Mon Sep 17 00:00:00 2001
From accb8ef16ca7b9273135ffb4cdc040383f87bfb9 Mon Sep 17 00:00:00 2001
From: Alex Wilson <alex.wilson@joyent.com>
Date: Wed, 16 Sep 2015 10:54:13 -0700
Subject: [PATCH 33/34] Restore tcpwrappers/libwrap support
Subject: [PATCH 31/34] Restore tcpwrappers/libwrap support
This reverts commit f9696566fb41320820f3b257ab564fa321bb3751
and commit f2719b7c2b8a3b14d778d8a6d8dc729b5174b054.
---
 configure.ac | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sshd.1m      |  7 +++++++
 sshd.c       | 25 +++++++++++++++++++++++++
 3 files changed, 89 insertions(+)
 sshd.c       | 29 +++++++++++++++++++++++++++++
 3 files changed, 93 insertions(+)
diff --git a/configure.ac b/configure.ac
index 580fa5c..ed56471 100644
index 5e64db3b..bf9c5449 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1460,6 +1460,62 @@ AC_ARG_WITH([skey],
@@ -1494,6 +1494,62 @@ AC_ARG_WITH([skey],
     ]
 )
 
@@ -78,7 +78,7 @@
 # Check whether user wants to use ldns
 LDNS_MSG="no"
 AC_ARG_WITH(ldns,
@@ -5010,6 +5066,7 @@ echo "                 KerberosV support: $KRB5_MSG"
@@ -5136,6 +5192,7 @@ echo "                 KerberosV support: $KRB5_MSG"
 echo "                   SELinux support: $SELINUX_MSG"
 echo "                 Smartcard support: $SCARD_MSG"
 echo "                     S/KEY support: $SKEY_MSG"
@@ -87,10 +87,10 @@
 echo "                   libedit support: $LIBEDIT_MSG"
 echo "  Solaris process contract support: $SPC_MSG"
diff --git a/sshd.1m b/sshd.1m
index 500c4d5..8d096e8 100644
index 387ea69e..55cf3f0d 100644
--- a/sshd.1m
+++ b/sshd.1m
@@ -880,6 +880,12 @@ the user's home directory becomes accessible.
@@ -825,6 +825,12 @@ the user's home directory becomes accessible.
 This file should be writable only by the user, and need not be
 readable by anyone else.
 .Pp
@@ -103,7 +103,7 @@
 .It Pa /etc/hosts.equiv
 This file is for host-based authentication (see
 .Xr ssh 1 ) .
@@ -1013,6 +1019,7 @@ Each SSHv2 userauth type has its own PAM service name:
@@ -956,6 +962,7 @@ Each SSHv2 userauth type has its own PAM service name:
 .Xr ssh-keygen 1 ,
 .Xr ssh-keyscan 1 ,
 .Xr chroot 2 ,
@@ -112,12 +112,12 @@
 .Xr moduli 4 ,
 .Xr sshd_config 4 ,
diff --git a/sshd.c b/sshd.c
index a912c1c..b8c11de 100644
index 67171704..75da16b7 100644
--- a/sshd.c
+++ b/sshd.c
@@ -125,6 +125,13 @@
 #include "version.h"
 #include "ssherr.h"
@@ -127,6 +127,17 @@
 #include <Security/AuthSession.h>
 #endif
 
+#ifdef LIBWRAP
+#include <tcpd.h>
@@ -126,10 +126,14 @@
+int deny_severity;
+#endif /* LIBWRAP */
+
 #ifndef O_NOCTTY
 #define O_NOCTTY    0
 #endif
@@ -2166,6 +2173,24 @@ main(int ac, char **av)
+#ifndef O_NOCTTY
+#define O_NOCTTY    0
+#endif
+
 /* Re-exec fds */
 #define REEXEC_DEVCRYPTO_RESERVED_FD    (STDERR_FILENO + 1)
 #define REEXEC_STARTUP_PIPE_FD        (STDERR_FILENO + 2)
@@ -1997,6 +2008,24 @@ main(int ac, char **av)
 #ifdef SSH_AUDIT_EVENTS
     audit_connection_from(remote_ip, remote_port);
 #endif
@@ -155,5 +159,5 @@
     /* Log the connection. */
     laddr = get_local_ipaddr(sock_in);
-- 
2.5.4 (Apple Git-61)
2.11.0
components/network/openssh/patches/0101-unregister-kexinit-handler.patch
File was deleted
components/network/openssh/patches/1000-dtrace32.patch