[153360] trunk/dports/net/openssh

ionic at macports.org ionic at macports.org
Thu Sep 29 06:49:15 PDT 2016


Revision: 153360
          https://trac.macports.org/changeset/153360
Author:   ionic at macports.org
Date:     2016-09-29 06:49:14 -0700 (Thu, 29 Sep 2016)
Log Message:
-----------
net/openssh: update to 7.3p1. Fixes: #51951, #48981, #50805.

Changes:
  - Rebase patches.
  - Update to newer HPN patchset version. Notable changes: HPN can't be
    forcefully disabled (if the variant has been selected), the None
    Cipher can't be forcefully enabled at compile time anymore. For HPN
    itself, this is fine, enabling the None Cipher will need to set
    NoneEnabled=yes on the server side and both NoneEnabled=yes and
    NoneSwitch=yes on the client side.
  - The sandbox check now doesn't try to access a private header
    anymore.
  - The removed slogin binary is provided as wrapper outputting a
    warning message on STDERR and executing the ssh binary.
  - none_cipher variant removed with no replacement, the code is always
    compiled when using the hpn variant now.

Modified Paths:
--------------
    trunk/dports/net/openssh/Portfile
    trunk/dports/net/openssh/files/0002-Apple-keychain-integration-other-changes.patch
    trunk/dports/net/openssh/files/launchd.patch
    trunk/dports/net/openssh/files/pam.patch
    trunk/dports/net/openssh/files/patch-sandbox-darwin.c-apple-sandbox-named-external.diff
    trunk/dports/net/openssh/files/patch-sshd.c-apple-sandbox-named-external.diff

Added Paths:
-----------
    trunk/dports/net/openssh/files/openssh-7.3p1-gsskex-all-20141021-mp-20160929.patch
    trunk/dports/net/openssh/files/openssh-7.3p1-hpnssh14v11.diff
    trunk/dports/net/openssh/files/slogin

Removed Paths:
-------------
    trunk/dports/net/openssh/files/openssh-7.2p1-gsskex-all-20141021-mp-20160301.patch
    trunk/dports/net/openssh/files/openssh-7.2p1-hpnssh14v5.diff

Modified: trunk/dports/net/openssh/Portfile
===================================================================
--- trunk/dports/net/openssh/Portfile	2016-09-29 13:44:26 UTC (rev 153359)
+++ trunk/dports/net/openssh/Portfile	2016-09-29 13:49:14 UTC (rev 153360)
@@ -4,8 +4,8 @@
 PortSystem          1.0
 
 name                openssh
-version             7.2p1
-revision            1
+version             7.3p1
+revision            0
 categories          net
 platforms           darwin
 maintainers         nomaintainer
@@ -28,8 +28,8 @@
 homepage            http://www.openbsd.org/openssh/
 
 checksums           ${distfiles} \
-                    rmd160  8af707c17337f223d5cbd1c7510f73dde2b22ff5 \
-                    sha256  973cc37b2f3597e4cf599b09e604e79c0fe5d9b6f595a24e91ed0662860b4ac3
+                    rmd160  823fc1e16c5d27a2361ed0b22f5ee24be11d2c13 \
+                    sha256  3ffb989a6dcaa69594c3b550d4855a5a2e1718ccdde7f5e36387b424220fbecc
 
 master_sites        openbsd:OpenSSH/portable \
                     ftp://ftp.cise.ufl.edu/pub/mirrors/openssh/portable/ \
@@ -72,7 +72,8 @@
 configure.cppflags-append -DBROKEN_STRNVIS=1
 
 # Use Apple's sandboxing feature
-configure.cppflags-append -D__APPLE_SANDBOX_NAMED_EXTERNAL__
+configure.cppflags-append -D__APPLE_SANDBOX_NAMED_EXTERNAL__ \
+                          -D__APPLE_API_STRICT_CONFORMANCE
 configure.ldflags-append  -Wl,-search_paths_first
 configure.args      --with-ssl-dir=${prefix} \
                     --sysconfdir=${prefix}/etc/ssh \
@@ -128,9 +129,13 @@
 }
 
 variant hpn conflicts gsskex description {Apply high performance patch} {
-    # http://www.psc.edu/index.php/hpn-ssh
-    # http://www.freshports.org/security/openssh-portable/ is usually quick in
-    # updating the HPN patch for new versions, take a look there, too.
+    # Old location(s):
+    #   http://www.psc.edu/index.php/hpn-ssh
+    # Current location(s):
+    #   http://hpnssh.sourceforge.net/
+    #   http://www.freshports.org/security/openssh-portable/
+    #     (is usually quick in updating the HPN patch for new versions,
+    #      take a look there, too.)
 
     # Formerly from FreeBSD, now copied over from FreeBSD's ports directory.
     #patch_sites-append     http://mirror.shatow.net/freebsd/${name}/ \
@@ -140,7 +145,7 @@
     #                       rmd160  0cf7ffdd9b60d518d76076faf31df6a7a6d4ae52 \
     #                       sha256  846ad51577de8308d60dbfaa58ba18d112d0732fdf21063ebc78407fc8e4a7b6
 
-    set hpn_patchfile       ${name}-${version}-hpnssh14v5.diff
+    set hpn_patchfile       ${name}-${version}-hpnssh14v11.diff
     patchfiles-append       ${hpn_patchfile}
 
     use_autoreconf          yes
@@ -148,14 +153,10 @@
     configure.args-append   --with-hpn
 }
 
-variant none_cipher conflicts gsskex requires hpn description {Enable optional NONE cipher in HPN patchset} {
-    configure.args-append   --with-nonecipher
-}
-
 variant gsskex conflicts hpn requires kerberos5 description "Add OpenSSH GSSAPI key exchange patch" {
     use_autoreconf          yes
     patchfiles-append       0002-Apple-keychain-integration-other-changes.patch \
-                            openssh-7.2p1-gsskex-all-20141021-mp-20160301.patch
+                            openssh-7.3p1-gsskex-all-20141021-mp-20160929.patch
     configure.cppflags-append \
                             -F/System/Library/Frameworks/DirectoryService.framework \
                             -F/System/Library/Frameworks/CoreFoundation.framework \
@@ -180,6 +181,21 @@
     depends_lib-append      port:kerberos5
     configure.args-delete   --without-kerberos5
     configure.args-append   --with-kerberos5=${prefix}
+
+    if {${os.platform} eq "darwin"} {
+        post-extract {
+            xinstall -m 0755 -W "${filespath}" slogin "${worksrcpath}/"
+        }
+
+        pre-configure {
+            reinplace -W "${worksrcpath}" "s|@@PREFIX@@|${prefix}|" slogin
+        }
+
+        post-destroot {
+            xinstall -m 0755 ${worksrcpath}/slogin \
+                             ${destroot}${prefix}/bin/
+        }
+    }
 }
 
 variant ldns description "Use ldns for DNSSEC support" {

Modified: trunk/dports/net/openssh/files/0002-Apple-keychain-integration-other-changes.patch
===================================================================
--- trunk/dports/net/openssh/files/0002-Apple-keychain-integration-other-changes.patch	2016-09-29 13:44:26 UTC (rev 153359)
+++ trunk/dports/net/openssh/files/0002-Apple-keychain-integration-other-changes.patch	2016-09-29 13:49:14 UTC (rev 153360)
@@ -1,5 +1,5 @@
---- a/Makefile.in	2016-02-26 04:40:04.000000000 +0100
-+++ b/Makefile.in	2016-03-01 02:14:38.000000000 +0100
+--- a/Makefile.in	2016-09-29 10:37:08.000000000 +0200
++++ b/Makefile.in	2016-09-29 11:02:49.000000000 +0200
 @@ -59,6 +59,7 @@ SED=@SED@
  ENT=@ENT@
  XAUTH_PATH=@XAUTH_PATH@
@@ -52,7 +52,7 @@
  
  ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o
  	$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
-@@ -309,7 +313,7 @@ install-files:
+@@ -312,7 +316,7 @@ install-files:
  	$(INSTALL) -m 0755 $(STRIP_OPT) ssh-keygen$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT)
  	$(INSTALL) -m 0755 $(STRIP_OPT) ssh-keyscan$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT)
  	$(INSTALL) -m 0755 $(STRIP_OPT) sshd$(EXEEXT) $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
@@ -61,8 +61,8 @@
  	$(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
  	$(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT)
  	$(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
---- a/audit-bsm.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/audit-bsm.c	2016-03-01 02:14:38.000000000 +0100
+--- a/audit-bsm.c	2016-09-29 10:37:08.000000000 +0200
++++ b/audit-bsm.c	2016-09-29 11:32:27.000000000 +0200
 @@ -263,7 +263,12 @@ bsm_audit_record(int typ, char *string, 
  	pid_t		pid = getpid();
  	AuditInfoTermID	tid = ssh_bsm_tid;
@@ -72,13 +72,13 @@
 +		error("BSM audit: audit record internal error (NULL ctxt)");
 +		abort();
 +	}
-+	
++
 +	if (the_authctxt->valid) {
  		uid = the_authctxt->pw->pw_uid;
  		gid = the_authctxt->pw->pw_gid;
  	}
---- a/auth-pam.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/auth-pam.c	2016-03-01 02:14:38.000000000 +0100
+--- a/auth-pam.c	2016-09-29 11:02:49.000000000 +0200
++++ b/auth-pam.c	2016-09-29 11:30:33.000000000 +0200
 @@ -794,10 +794,11 @@ sshpam_query(void *ctx, char **name, cha
  				free(msg);
  				return (0);
@@ -87,15 +87,15 @@
 +			error("PAM: %s for %s%.100s from %.100s via %s", msg,
  			    sshpam_authctxt->valid ? "" : "illegal user ",
  			    sshpam_authctxt->user,
--			    get_remote_name_or_ip(utmp_len, options.use_dns));
-+			    get_remote_name_or_ip(utmp_len, options.use_dns),
-+			    get_local_ipaddr(packet_get_connection_in()));
+-			    auth_get_canonical_hostname(ssh, options.use_dns));
++			    auth_get_canonical_hostname(ssh, options.use_dns),
++			    get_local_ipaddr(ssh_packet_get_connection_in(ssh)));
  			/* FALLTHROUGH */
  		default:
  			*num = 0;
---- a/auth.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/auth.c	2016-03-01 02:22:17.000000000 +0100
-@@ -212,7 +212,7 @@ allowed_user(struct passwd * pw)
+--- a/auth.c	2016-09-29 10:37:08.000000000 +0200
++++ b/auth.c	2016-09-29 11:02:49.000000000 +0200
+@@ -215,7 +215,7 @@ allowed_user(struct passwd * pw)
  	}
  	if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
  		/* Get the user's group access list (primary and supplementary) */
@@ -104,8 +104,8 @@
  			logit("User %.100s from %.100s not allowed because "
  			    "not in any group", pw->pw_name, hostname);
  			return 0;
---- a/authfd.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/authfd.c	2016-03-01 02:14:38.000000000 +0100
+--- a/authfd.c	2016-09-29 10:37:08.000000000 +0200
++++ b/authfd.c	2016-09-29 11:02:49.000000000 +0200
 @@ -165,6 +165,29 @@ ssh_request_reply(int sock, struct sshbu
  }
  
@@ -136,8 +136,8 @@
   * Closes the agent socket if it should be closed (depends on how it was
   * obtained).  The argument must have been returned by
   * ssh_get_authentication_socket().
---- a/authfd.h	2016-02-26 04:40:04.000000000 +0100
-+++ b/authfd.h	2016-03-01 02:14:38.000000000 +0100
+--- a/authfd.h	2016-09-29 10:37:08.000000000 +0200
++++ b/authfd.h	2016-09-29 11:02:49.000000000 +0200
 @@ -43,6 +43,9 @@ int	ssh_agent_sign(int sock, struct sshk
  	    u_char **sigp, size_t *lenp,
  	    const u_char *data, size_t datalen, const char *alg, u_int compat);
@@ -158,10 +158,10 @@
  #define	SSH_AGENT_CONSTRAIN_LIFETIME		1
  #define	SSH_AGENT_CONSTRAIN_CONFIRM		2
  
---- a/config.h.in	2016-02-28 01:19:09.000000000 +0100
-+++ b/config.h.in	2016-03-01 02:14:39.000000000 +0100
+--- a/config.h.in	2016-09-29 10:37:08.000000000 +0200
++++ b/config.h.in	2016-09-29 11:02:49.000000000 +0200
 @@ -78,6 +78,18 @@
- /* FreeBSD strnvis argument order is swapped compared to OpenBSD */
+ /* missing VIS_ALL */
  #undef BROKEN_STRNVIS
  
 +/* platform uses an in-memory credentials cache */
@@ -179,9 +179,9 @@
  /* tcgetattr with ICANON may hang */
  #undef BROKEN_TCGETATTR_ICANON
  
---- a/configure.ac	2016-02-26 04:40:04.000000000 +0100
-+++ b/configure.ac	2016-03-01 02:14:39.000000000 +0100
-@@ -4916,10 +4916,40 @@ AC_CHECK_MEMBER([struct utmp.ut_line], [
+--- a/configure.ac	2016-09-29 10:37:08.000000000 +0200
++++ b/configure.ac	2016-09-29 11:02:49.000000000 +0200
+@@ -4972,10 +4972,40 @@ AC_CHECK_MEMBER([struct utmp.ut_line], [
  #endif
  	])
  
@@ -222,8 +222,8 @@
  if test "x$ac_cv_func_getaddrinfo" != "xyes" ; then
  	TEST_SSH_IPV6=no
  else
---- a/groupaccess.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/groupaccess.c	2016-03-01 02:14:39.000000000 +0100
+--- a/groupaccess.c	2016-09-29 10:37:08.000000000 +0200
++++ b/groupaccess.c	2016-09-29 11:32:59.000000000 +0200
 @@ -34,38 +34,67 @@
  #include <string.h>
  #include <limits.h>
@@ -274,9 +274,8 @@
  	ngroups = NGROUPS_MAX;
  #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
  	ngroups = MAX(NGROUPS_MAX, sysconf(_SC_NGROUPS_MAX));
--#endif
+ #endif
 -
-+#endif	
  	groups_bygid = xcalloc(ngroups, sizeof(*groups_bygid));
 +#else
 +	if (-1 == (ngroups = getgrouplist_2(pw->pw_name, pw->pw_gid,
@@ -332,8 +331,8 @@
  	return 0;
  }
  
---- a/groupaccess.h	2016-02-26 04:40:04.000000000 +0100
-+++ b/groupaccess.h	2016-03-01 02:14:39.000000000 +0100
+--- a/groupaccess.h	2016-09-29 10:37:08.000000000 +0200
++++ b/groupaccess.h	2016-09-29 11:02:49.000000000 +0200
 @@ -27,7 +27,7 @@
  #ifndef GROUPACCESS_H
  #define GROUPACCESS_H
@@ -344,26 +343,26 @@
  int	 ga_match_pattern_list(const char *);
  void	 ga_free(void);
 --- /dev/null	1970-01-01 00:00:00.000000000 +0000
-+++ b/keychain.c	2016-03-01 02:14:39.000000000 +0100
++++ b/keychain.c	2016-09-29 11:33:39.000000000 +0200
 @@ -0,0 +1,694 @@
 +/*
 + * Copyright (c) 2007 Apple Inc. All rights reserved.
 + *
 + * @APPLE_BSD_LICENSE_HEADER_START@
-+ * 
++ *
 + * 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. 
++ *     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. 
++ *     documentation and/or other materials provided with the distribution.
 + * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
 + *     contributors may be used to endorse or promote products derived from
-+ *     this software without specific prior written permission. 
-+ * 
++ *     this software without specific prior written permission.
++ *
 + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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
@@ -374,7 +373,7 @@
 + * 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.
-+ * 
++ *
 + * @APPLE_BSD_LICENSE_HEADER_END@
 + */
 +
@@ -1041,26 +1040,26 @@
 +
 +}
 --- /dev/null	1970-01-01 00:00:00.000000000 +0000
-+++ b/keychain.h	2016-03-01 02:14:39.000000000 +0100
++++ b/keychain.h	2016-09-29 11:34:19.000000000 +0200
 @@ -0,0 +1,45 @@
 +/*
 + * Copyright (c) 2007 Apple Inc. All rights reserved.
 + *
 + * @APPLE_BSD_LICENSE_HEADER_START@
-+ * 
++ *
 + * 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. 
++ *     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. 
++ *     documentation and/or other materials provided with the distribution.
 + * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
 + *     contributors may be used to endorse or promote products derived from
-+ *     this software without specific prior written permission. 
-+ * 
++ *     this software without specific prior written permission.
++ *
 + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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
@@ -1071,7 +1070,7 @@
 + * 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.
-+ * 
++ *
 + * @APPLE_BSD_LICENSE_HEADER_END@
 + */
 +
@@ -1088,9 +1087,9 @@
 +int	 add_identities_using_keychain(
 +	     int (*add_identity)(const char *, const char *));
 +char	*keychain_read_passphrase(const char *filename, int oAskPassGUI);
---- a/readconf.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/readconf.c	2016-03-01 02:14:39.000000000 +0100
-@@ -156,6 +156,9 @@ typedef enum {
+--- a/readconf.c	2016-09-29 10:37:08.000000000 +0200
++++ b/readconf.c	2016-09-29 11:14:22.000000000 +0200
+@@ -168,6 +168,9 @@ typedef enum {
  	oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
  	oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
  	oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
@@ -1099,18 +1098,18 @@
 +#endif
  	oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
  	oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
- 	oPubkeyAcceptedKeyTypes,
-@@ -281,6 +284,9 @@ static struct {
- 	{ "hostbasedkeytypes", oHostbasedKeyTypes },
+ 	oPubkeyAcceptedKeyTypes, oProxyJump,
+@@ -296,6 +299,9 @@ static struct {
  	{ "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
  	{ "ignoreunknown", oIgnoreUnknown },
+ 	{ "proxyjump", oProxyJump },
 +#ifdef __APPLE_KEYCHAIN__
 +	{ "askpassgui", oAskPassGUI },
 +#endif
  
  	{ NULL, oBadOption }
  };
-@@ -1433,6 +1439,12 @@ parse_keytypes:
+@@ -1543,6 +1549,12 @@ parse_keytypes:
  		charptr = &options->ignored_unknown;
  		goto parse_string;
  
@@ -1123,7 +1122,7 @@
  	case oProxyUseFdpass:
  		intptr = &options->proxy_use_fdpass;
  		goto parse_flag;
-@@ -1715,6 +1727,9 @@ initialize_options(Options * options)
+@@ -1848,6 +1860,9 @@ initialize_options(Options * options)
  	options->request_tty = -1;
  	options->proxy_use_fdpass = -1;
  	options->ignored_unknown = NULL;
@@ -1133,7 +1132,7 @@
  	options->num_canonical_domains = 0;
  	options->num_permitted_cnames = 0;
  	options->canonicalize_max_dots = -1;
-@@ -1891,6 +1906,10 @@ fill_default_options(Options * options)
+@@ -2033,6 +2048,10 @@ fill_default_options(Options * options)
  		options->ip_qos_bulk = IPTOS_THROUGHPUT;
  	if (options->request_tty == -1)
  		options->request_tty = REQUEST_TTY_AUTO;
@@ -1144,10 +1143,10 @@
  	if (options->proxy_use_fdpass == -1)
  		options->proxy_use_fdpass = 0;
  	if (options->canonicalize_max_dots == -1)
---- a/readconf.h	2016-02-26 04:40:04.000000000 +0100
-+++ b/readconf.h	2016-03-01 02:14:39.000000000 +0100
-@@ -159,6 +159,10 @@ typedef struct {
- 	char   *pubkey_key_types;
+--- a/readconf.h	2016-09-29 10:37:08.000000000 +0200
++++ b/readconf.h	2016-09-29 11:02:49.000000000 +0200
+@@ -169,6 +169,10 @@ typedef struct {
+ 	char   *jump_extra;
  
  	char	*ignored_unknown; /* Pattern list of unknown tokens to ignore */
 +
@@ -1157,8 +1156,8 @@
  }       Options;
  
  #define SSH_CANONICALISE_NO	0
---- a/scp.1	2016-02-26 04:40:04.000000000 +0100
-+++ b/scp.1	2016-03-01 02:14:39.000000000 +0100
+--- a/scp.1	2016-09-29 10:37:08.000000000 +0200
++++ b/scp.1	2016-09-29 11:02:50.000000000 +0200
 @@ -19,7 +19,7 @@
  .Sh SYNOPSIS
  .Nm scp
@@ -1177,8 +1176,8 @@
  .It Fl c Ar cipher
  Selects the cipher to use for encrypting the data transfer.
  This option is directly passed to
---- a/scp.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/scp.c	2016-03-01 02:14:39.000000000 +0100
+--- a/scp.c	2016-09-29 10:37:08.000000000 +0200
++++ b/scp.c	2016-09-29 11:34:54.000000000 +0200
 @@ -78,6 +78,9 @@
  #ifdef HAVE_SYS_STAT_H
  # include <sys/stat.h>
@@ -1189,9 +1188,9 @@
  #ifdef HAVE_POLL_H
  #include <poll.h>
  #else
-@@ -115,6 +118,11 @@
- #include "misc.h"
+@@ -117,6 +120,11 @@
  #include "progressmeter.h"
+ #include "utf8.h"
  
 +#ifdef HAVE_COPYFILE_H
 +#include <libgen.h>
@@ -1201,7 +1200,7 @@
  extern char *__progname;
  
  #define COPY_BUFLEN	16384
-@@ -151,6 +159,12 @@ char *ssh_program = _PATH_SSH_PROGRAM;
+@@ -153,6 +161,12 @@ char *ssh_program = _PATH_SSH_PROGRAM;
  /* This is used to store the pid of ssh_program */
  pid_t do_cmd_pid = -1;
  
@@ -1214,7 +1213,7 @@
  static void
  killchild(int signo)
  {
-@@ -396,7 +410,11 @@ main(int argc, char **argv)
+@@ -400,7 +414,11 @@ main(int argc, char **argv)
  	addargs(&args, "-oClearAllForwardings=yes");
  
  	fflag = tflag = 0;
@@ -1226,7 +1225,7 @@
  		switch (ch) {
  		/* User-visible flags. */
  		case '1':
-@@ -457,6 +475,11 @@ main(int argc, char **argv)
+@@ -461,6 +479,11 @@ main(int argc, char **argv)
  			showprogress = 0;
  			break;
  
@@ -1238,7 +1237,7 @@
  		/* Server options. */
  		case 'd':
  			targetshouldbedirectory = 1;
-@@ -516,7 +539,12 @@ main(int argc, char **argv)
+@@ -520,7 +543,12 @@ main(int argc, char **argv)
  	remin = remout = -1;
  	do_cmd_pid = -1;
  	/* Command to be executed on remote system using "ssh". */
@@ -1251,7 +1250,7 @@
  	    verbose_mode ? " -v" : "",
  	    iamrecursive ? " -r" : "", pflag ? " -p" : "",
  	    targetshouldbedirectory ? " -d" : "");
-@@ -762,6 +790,10 @@ source(int argc, char **argv)
+@@ -766,6 +794,10 @@ source(int argc, char **argv)
  	int fd = -1, haderr, indx;
  	char *last, *name, buf[2048], encname[PATH_MAX];
  	int len;
@@ -1262,7 +1261,7 @@
  
  	for (indx = 0; indx < argc; ++indx) {
  		name = argv[indx];
-@@ -769,12 +801,26 @@ source(int argc, char **argv)
+@@ -773,12 +805,26 @@ source(int argc, char **argv)
  		len = strlen(name);
  		while (len > 1 && name[len-1] == '/')
  			name[--len] = '\0';
@@ -1289,7 +1288,7 @@
  		if (fstat(fd, &stb) < 0) {
  syserr:			run_err("%s: %s", name, strerror(errno));
  			goto next;
-@@ -861,6 +907,36 @@ next:			if (fd != -1) {
+@@ -862,6 +908,36 @@ next:			if (fd != -1) {
  		else
  			run_err("%s: %s", name, strerror(haderr));
  		(void) response();
@@ -1323,10 +1322,10 @@
 +		} else
 +		    md_flag = 0;
 +#endif
+ 		if (showprogress)
+ 			stop_progress_meter();
  	}
- }
- 
-@@ -952,6 +1028,10 @@ sink(int argc, char **argv)
+@@ -955,6 +1031,10 @@ sink(int argc, char **argv)
  	if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
  		targisdir = 1;
  	for (first = 1;; first = 0) {
@@ -1337,7 +1336,7 @@
  		cp = buf;
  		if (atomicio(read, remin, cp, 1) != 1)
  			return;
-@@ -1097,10 +1177,51 @@ sink(int argc, char **argv)
+@@ -1103,10 +1183,51 @@ sink(int argc, char **argv)
  		}
  		omode = mode;
  		mode |= S_IWUSR;
@@ -1382,14 +1381,14 @@
 +			fst.fst_posmode = F_PEOFPOSMODE;
 +			fst.fst_offset = 0;
 +			fst.fst_length = size;
-+				
++
 +			(void) fcntl(ofd, F_PREALLOCATE, &fst);
 +		}
-+#endif /* __APPLE_XSAN__ */		
++#endif /* __APPLE_XSAN__ */
  		(void) atomicio(vwrite, remout, "", 1);
  		if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) {
  			(void) close(ofd);
-@@ -1185,6 +1306,29 @@ bad:			run_err("%s: %s", np, strerror(er
+@@ -1189,6 +1310,29 @@ bad:			run_err("%s: %s", np, strerror(er
  			wrerrno = errno;
  		}
  		(void) response();
@@ -1416,10 +1415,10 @@
 +			}
 +		} else
 +#endif
+ 		if (showprogress)
+ 			stop_progress_meter();
  		if (setimes && wrerr == NO) {
- 			setimes = 0;
- 			if (utimes(np, tv) < 0) {
-@@ -1246,7 +1390,11 @@ void
+@@ -1257,7 +1401,11 @@ void
  usage(void)
  {
  	(void) fprintf(stderr,
@@ -1431,8 +1430,8 @@
  	    "           [-l limit] [-o ssh_option] [-P port] [-S program]\n"
  	    "           [[user@]host1:]file1 ... [[user@]host2:]file2\n");
  	exit(1);
---- a/servconf.c	2016-03-01 02:14:29.000000000 +0100
-+++ b/servconf.c	2016-03-01 02:14:39.000000000 +0100
+--- a/servconf.c	2016-09-29 10:37:08.000000000 +0200
++++ b/servconf.c	2016-09-29 11:02:50.000000000 +0200
 @@ -292,7 +292,7 @@ fill_default_server_options(ServerOption
  	if (options->gss_strict_acceptor == -1)
  		options->gss_strict_acceptor = 0;
@@ -1442,7 +1441,7 @@
  	if (options->kbd_interactive_authentication == -1)
  		options->kbd_interactive_authentication = 0;
  	if (options->challenge_response_authentication == -1)
-@@ -762,7 +762,7 @@ match_cfg_line_group(const char *grps, i
+@@ -771,7 +771,7 @@ match_cfg_line_group(const char *grps, i
  	if ((pw = getpwnam(user)) == NULL) {
  		debug("Can't match group at line %d because user %.100s does "
  		    "not exist", line, user);
@@ -1451,9 +1450,9 @@
  		debug("Can't Match group because user %.100s not in any group "
  		    "at line %d", user, line);
  	} else if (ga_match_pattern_list(grps) != 1) {
---- a/session.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/session.c	2016-03-01 02:14:39.000000000 +0100
-@@ -2111,8 +2111,10 @@ session_pty_req(Session *s)
+--- a/session.c	2016-09-29 10:37:08.000000000 +0200
++++ b/session.c	2016-09-29 11:02:50.000000000 +0200
+@@ -2140,8 +2140,10 @@ session_pty_req(Session *s)
  		n_bytes = packet_remaining();
  	tty_parse_modes(s->ttyfd, &n_bytes);
  
@@ -1464,7 +1463,7 @@
  
  	/* Set window size from the packet. */
  	pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
-@@ -2352,9 +2354,11 @@ session_pty_cleanup2(Session *s)
+@@ -2387,9 +2389,11 @@ session_pty_cleanup2(Session *s)
  	if (s->pid != 0)
  		record_logout(s->pid, s->tty, s->pw->pw_name);
  
@@ -1476,8 +1475,8 @@
  
  	/*
  	 * Close the server side of the socket pairs.  We must do this after
---- a/ssh-add.0	2016-02-28 01:18:35.000000000 +0100
-+++ b/ssh-add.0	2016-03-01 02:14:39.000000000 +0100
+--- a/ssh-add.0	2016-09-29 10:37:08.000000000 +0200
++++ b/ssh-add.0	2016-09-29 11:02:50.000000000 +0200
 @@ -4,7 +4,7 @@ NAME
       ssh-add M-bM-^@M-^S adds private key identities to the authentication agent
  
@@ -1501,8 +1500,8 @@
       -s pkcs11
               Add keys provided by the PKCS#11 shared library pkcs11.
  
---- a/ssh-add.1	2016-02-26 04:40:04.000000000 +0100
-+++ b/ssh-add.1	2016-03-01 02:14:39.000000000 +0100
+--- a/ssh-add.1	2016-09-29 10:37:08.000000000 +0200
++++ b/ssh-add.1	2016-09-29 11:02:50.000000000 +0200
 @@ -43,7 +43,7 @@
  .Nd adds private key identities to the authentication agent
  .Sh SYNOPSIS
@@ -1526,8 +1525,8 @@
  .It Fl s Ar pkcs11
  Add keys provided by the PKCS#11 shared library
  .Ar pkcs11 .
---- a/ssh-add.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/ssh-add.c	2016-03-01 02:14:39.000000000 +0100
+--- a/ssh-add.c	2016-09-29 10:37:08.000000000 +0200
++++ b/ssh-add.c	2016-09-29 11:02:50.000000000 +0200
 @@ -65,6 +65,7 @@
  #include "misc.h"
  #include "ssherr.h"
@@ -1685,8 +1684,8 @@
  			    argv[i]) == -1)
  				ret = 1;
  		}
---- a/ssh-agent.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/ssh-agent.c	2016-03-01 02:14:39.000000000 +0100
+--- a/ssh-agent.c	2016-09-29 10:37:08.000000000 +0200
++++ b/ssh-agent.c	2016-09-29 11:02:50.000000000 +0200
 @@ -71,6 +71,9 @@
  #ifdef HAVE_UTIL_H
  # include <util.h>
@@ -1712,7 +1711,7 @@
  
  #ifdef ENABLE_PKCS11
  #include "ssh-pkcs11.h"
-@@ -840,6 +846,61 @@ process_remove_smartcard_key(SocketEntry
+@@ -837,6 +843,61 @@ process_remove_smartcard_key(SocketEntry
  }
  #endif /* ENABLE_PKCS11 */
  
@@ -1774,7 +1773,7 @@
  /* dispatch incoming messages */
  
  static void
-@@ -934,6 +995,9 @@ process_message(SocketEntry *e)
+@@ -931,6 +992,9 @@ process_message(SocketEntry *e)
  		process_remove_smartcard_key(e);
  		break;
  #endif /* ENABLE_PKCS11 */
@@ -1784,7 +1783,7 @@
  	default:
  		/* Unknown message.  Respond with failure. */
  		error("Unknown message %d", type);
-@@ -1184,7 +1248,11 @@ usage(void)
+@@ -1181,7 +1245,11 @@ usage(void)
  int
  main(int ac, char **av)
  {
@@ -1796,7 +1795,7 @@
  	int sock, fd, ch, result, saved_errno;
  	u_int nalloc;
  	char *shell, *format, *pidstr, *agentsocket = NULL;
-@@ -1220,7 +1288,11 @@ main(int ac, char **av)
+@@ -1214,7 +1282,11 @@ main(int ac, char **av)
  	__progname = ssh_get_progname(av[0]);
  	seed_rng();
  
@@ -1808,7 +1807,7 @@
  		switch (ch) {
  		case 'E':
  			fingerprint_hash = ssh_digest_alg_by_name(optarg);
-@@ -1235,6 +1307,11 @@ main(int ac, char **av)
+@@ -1229,6 +1301,11 @@ main(int ac, char **av)
  		case 'k':
  			k_flag++;
  			break;
@@ -1820,7 +1819,7 @@
  		case 's':
  			if (c_flag)
  				usage();
-@@ -1266,7 +1343,11 @@ main(int ac, char **av)
+@@ -1260,7 +1337,11 @@ main(int ac, char **av)
  	ac -= optind;
  	av += optind;
  
@@ -1832,7 +1831,7 @@
  		usage();
  
  	if (ac == 0 && !c_flag && !s_flag) {
-@@ -1322,6 +1403,53 @@ main(int ac, char **av)
+@@ -1316,6 +1397,53 @@ main(int ac, char **av)
  	 * Create socket early so it will exist before command gets run from
  	 * the parent.
  	 */
@@ -1886,7 +1885,7 @@
  	prev_mask = umask(0177);
  	sock = unix_listener(socket_name, SSH_LISTEN_BACKLOG, 0);
  	if (sock < 0) {
-@@ -1330,6 +1458,14 @@ main(int ac, char **av)
+@@ -1324,6 +1452,14 @@ main(int ac, char **av)
  		cleanup_exit(1);
  	}
  	umask(prev_mask);
@@ -1901,7 +1900,7 @@
  
  	/*
  	 * Fork, and have the parent execute the command, if any, or present
-@@ -1407,6 +1543,7 @@ skip:
+@@ -1401,6 +1537,7 @@ skip:
  	pkcs11_init(0);
  #endif
  	new_socket(AUTH_SOCKET, sock);
@@ -1909,7 +1908,7 @@
  	if (ac > 0)
  		parent_alive_interval = 10;
  	idtab_init();
-@@ -1420,6 +1557,10 @@ skip:
+@@ -1414,6 +1551,10 @@ skip:
  		fatal("%s: pledge: %s", __progname, strerror(errno));
  	platform_pledge_agent();
  
@@ -1920,8 +1919,8 @@
  	while (1) {
  		prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp);
  		result = select(max_fd + 1, readsetp, writesetp, NULL, tvp);
---- a/ssh-keysign.8	2016-02-26 04:40:04.000000000 +0100
-+++ b/ssh-keysign.8	2016-03-01 02:14:39.000000000 +0100
+--- a/ssh-keysign.8	2016-09-29 10:37:08.000000000 +0200
++++ b/ssh-keysign.8	2016-09-29 11:02:50.000000000 +0200
 @@ -72,6 +72,9 @@ accessible to others.
  Since they are readable only by root,
  .Nm
@@ -1932,8 +1931,8 @@
  .Pp
  .It Pa /etc/ssh/ssh_host_dsa_key-cert.pub
  .It Pa /etc/ssh/ssh_host_ecdsa_key-cert.pub
---- a/sshconnect1.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/sshconnect1.c	2016-03-01 02:14:39.000000000 +0100
+--- a/sshconnect1.c	2016-09-29 10:37:08.000000000 +0200
++++ b/sshconnect1.c	2016-09-29 11:02:50.000000000 +0200
 @@ -51,6 +51,7 @@
  #include "auth.h"
  #include "digest.h"
@@ -1953,17 +1952,17 @@
  			passphrase = read_passphrase(buf, 0);
  			if (strcmp(passphrase, "") != 0) {
  				private = key_load_private_type(KEY_RSA1,
---- a/sshconnect2.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/sshconnect2.c	2016-03-01 02:24:20.000000000 +0100
-@@ -71,6 +71,7 @@
- #include "uidswap.h"
+--- a/sshconnect2.c	2016-09-29 10:37:08.000000000 +0200
++++ b/sshconnect2.c	2016-09-29 11:17:29.000000000 +0200
+@@ -72,6 +72,7 @@
  #include "hostfile.h"
  #include "ssherr.h"
+ #include "utf8.h"
 +#include "keychain.h"
  
  #ifdef GSSAPI
  #include "ssh-gss.h"
-@@ -1215,6 +1216,10 @@ load_identity_file(Identity *id)
+@@ -1205,6 +1206,10 @@ load_identity_file(Identity *id)
  		if (i == 0)
  			passphrase = "";
  		else {
@@ -1974,8 +1973,8 @@
  			passphrase = read_passphrase(prompt, 0);
  			if (*passphrase == '\0') {
  				debug2("no passphrase given, try next key");
---- a/sshd.0	2016-02-28 01:18:36.000000000 +0100
-+++ b/sshd.0	2016-03-01 02:14:39.000000000 +0100
+--- a/sshd.0	2016-09-29 10:37:08.000000000 +0200
++++ b/sshd.0	2016-09-29 11:02:50.000000000 +0200
 @@ -651,8 +651,7 @@ FILES
  
  SEE ALSO
@@ -1986,8 +1985,8 @@
  
  AUTHORS
       OpenSSH is a derivative of the original and free ssh 1.2.12 release by
---- a/sshd.8	2016-02-26 04:40:04.000000000 +0100
-+++ b/sshd.8	2016-03-01 02:14:39.000000000 +0100
+--- a/sshd.8	2016-09-29 10:37:08.000000000 +0200
++++ b/sshd.8	2016-09-29 11:02:50.000000000 +0200
 @@ -986,10 +986,7 @@ The content of this file is not sensitiv
  .Xr ssh-keygen 1 ,
  .Xr ssh-keyscan 1 ,
@@ -1999,9 +1998,9 @@
  .Xr sftp-server 8
  .Sh AUTHORS
  OpenSSH is a derivative of the original and free
---- a/sshd.c	2016-03-01 02:14:34.000000000 +0100
-+++ b/sshd.c	2016-03-01 02:14:39.000000000 +0100
-@@ -2239,6 +2239,12 @@ main(int ac, char **av)
+--- a/sshd.c	2016-09-29 10:37:05.000000000 +0200
++++ b/sshd.c	2016-09-29 11:02:50.000000000 +0200
+@@ -2295,6 +2295,12 @@ main(int ac, char **av)
  	audit_event(SSH_AUTH_SUCCESS);
  #endif
  
@@ -2014,7 +2013,7 @@
  #ifdef GSSAPI
  	if (options.gss_authentication) {
  		temporarily_use_uid(authctxt->pw);
-@@ -2246,12 +2252,6 @@ main(int ac, char **av)
+@@ -2302,12 +2308,6 @@ main(int ac, char **av)
  		restore_uid();
  	}
  #endif
@@ -2027,18 +2026,18 @@
  
  	/*
  	 * In privilege separation, we fork another child and prepare
---- a/sshd_config	2016-02-26 04:40:04.000000000 +0100
-+++ b/sshd_config	2016-03-01 02:14:39.000000000 +0100
-@@ -35,7 +35,7 @@
+--- a/sshd_config	2016-09-29 10:37:08.000000000 +0200
++++ b/sshd_config	2016-09-29 11:18:08.000000000 +0200
+@@ -34,7 +34,7 @@
+ #RekeyLimit default none
  
  # Logging
- # obsoletes QuietMode and FascistLogging
 -#SyslogFacility AUTH
 +SyslogFacility AUTHPRIV
  #LogLevel INFO
  
  # Authentication:
-@@ -68,8 +68,9 @@ AuthorizedKeysFile	.ssh/authorized_keys
+@@ -67,8 +67,9 @@ AuthorizedKeysFile	.ssh/authorized_keys
  # Don't read the user's ~/.rhosts and ~/.shosts files
  #IgnoreRhosts yes
  
@@ -2050,7 +2049,7 @@
  #PermitEmptyPasswords no
  
  # Change to no to disable s/key passwords
-@@ -94,7 +95,10 @@ AuthorizedKeysFile	.ssh/authorized_keys
+@@ -93,7 +94,10 @@ AuthorizedKeysFile	.ssh/authorized_keys
  # If you just want the PAM account and session checks to run without
  # PAM authentication, then enable this but set PasswordAuthentication
  # and ChallengeResponseAuthentication to 'no'.
@@ -2062,9 +2061,9 @@
  
  #AllowAgentForwarding yes
  #AllowTcpForwarding yes
---- a/sshd_config.0	2016-02-28 01:18:36.000000000 +0100
-+++ b/sshd_config.0	2016-03-01 02:14:39.000000000 +0100
-@@ -689,7 +689,7 @@ DESCRIPTION
+--- a/sshd_config.0	2016-09-29 10:37:08.000000000 +0200
++++ b/sshd_config.0	2016-09-29 11:02:50.000000000 +0200
+@@ -696,7 +696,7 @@ DESCRIPTION
  
       PasswordAuthentication
               Specifies whether password authentication is allowed.  The
@@ -2073,7 +2072,7 @@
  
       PermitEmptyPasswords
               When password authentication is allowed, it specifies whether the
-@@ -949,7 +949,7 @@ DESCRIPTION
+@@ -958,7 +958,7 @@ DESCRIPTION
               either PasswordAuthentication or ChallengeResponseAuthentication.
  
               If UsePAM is enabled, you will not be able to run sshd(8) as a
@@ -2082,9 +2081,9 @@
  
       UsePrivilegeSeparation
               Specifies whether sshd(8) separates privileges by creating an
---- a/sshd_config.5	2016-02-26 04:40:04.000000000 +0100
-+++ b/sshd_config.5	2016-03-01 02:14:39.000000000 +0100
-@@ -1171,7 +1171,7 @@ are refused if the number of unauthentic
+--- a/sshd_config.5	2016-09-29 10:37:08.000000000 +0200
++++ b/sshd_config.5	2016-09-29 11:02:50.000000000 +0200
+@@ -1180,7 +1180,7 @@ are refused if the number of unauthentic
  .It Cm PasswordAuthentication
  Specifies whether password authentication is allowed.
  The default is
@@ -2093,7 +2092,7 @@
  .It Cm PermitEmptyPasswords
  When password authentication is allowed, it specifies whether the
  server allows login to accounts with empty password strings.
-@@ -1583,7 +1583,7 @@ is enabled, you will not be able to run
+@@ -1595,7 +1595,7 @@ is enabled, you will not be able to run
  .Xr sshd 8
  as a non-root user.
  The default is

Modified: trunk/dports/net/openssh/files/launchd.patch
===================================================================
--- trunk/dports/net/openssh/files/launchd.patch	2016-09-29 13:44:26 UTC (rev 153359)
+++ trunk/dports/net/openssh/files/launchd.patch	2016-09-29 13:49:14 UTC (rev 153360)
@@ -1,6 +1,6 @@
---- a/channels.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/channels.c	2016-03-01 00:35:58.000000000 +0100
-@@ -4037,15 +4037,35 @@ x11_connect_display(void)
+--- a/channels.c	2016-07-28 00:54:27.000000000 +0200
++++ b/channels.c	2016-09-29 06:55:54.000000000 +0200
+@@ -4041,15 +4041,35 @@ x11_connect_display(void)
  	 * connection to the real X server.
  	 */
  
@@ -43,9 +43,9 @@
  	}
  #endif
  	/*
---- a/clientloop.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/clientloop.c	2016-03-01 00:49:24.000000000 +0100
-@@ -313,6 +313,10 @@ client_x11_get_proto(const char *display
+--- a/clientloop.c	2016-07-28 00:54:27.000000000 +0200
++++ b/clientloop.c	2016-09-29 06:55:55.000000000 +0200
+@@ -316,6 +316,10 @@ client_x11_get_proto(const char *display
  	struct stat st;
  	u_int now, x11_timeout_real;
  
@@ -56,7 +56,7 @@
  	*_proto = proto;
  	*_data = data;
  	proto[0] = data[0] = xauthfile[0] = xauthdir[0] = '\0';
-@@ -329,6 +333,34 @@ client_x11_get_proto(const char *display
+@@ -332,6 +336,34 @@ client_x11_get_proto(const char *display
  	}
  
  	if (xauth_path != NULL) {
@@ -91,7 +91,7 @@
  		/*
  		 * Handle FamilyLocal case where $DISPLAY does
  		 * not match an authorization entry.  For this we
-@@ -438,6 +470,9 @@ client_x11_get_proto(const char *display
+@@ -441,6 +473,9 @@ client_x11_get_proto(const char *display
  	if (!got_data) {
  		u_int32_t rnd = 0;
  

Deleted: trunk/dports/net/openssh/files/openssh-7.2p1-gsskex-all-20141021-mp-20160301.patch
===================================================================
--- trunk/dports/net/openssh/files/openssh-7.2p1-gsskex-all-20141021-mp-20160301.patch	2016-09-29 13:44:26 UTC (rev 153359)
+++ trunk/dports/net/openssh/files/openssh-7.2p1-gsskex-all-20141021-mp-20160301.patch	2016-09-29 13:49:14 UTC (rev 153360)
@@ -1,3021 +0,0 @@
-From 1c1b6fa17982eb622e2c4e8f4a279f2113f57413 Mon Sep 17 00:00:00 2001
-From: Simon Wilkinson <simon at sxw.org.uk>
-Date: Sun, 9 Feb 2014 16:09:48 +0000
-Subject: GSSAPI key exchange support
-
-This patch has been rejected upstream: "None of the OpenSSH developers are
-in favour of adding this, and this situation has not changed for several
-years.  This is not a slight on Simon's patch, which is of fine quality, but
-just that a) we don't trust GSSAPI implementations that much and b) we don't
-like adding new KEX since they are pre-auth attack surface.  This one is
-particularly scary, since it requires hooks out to typically root-owned
-system resources."
-
-However, quite a lot of people rely on this in Debian, and it's better to
-have it merged into the main openssh package rather than having separate
--krb5 packages (as we used to have).  It seems to have a generally good
-security history.
-
-Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242
-Last-Updated: 2014-10-07
-
-Patch-Name: gssapi.patch
-
-
-Updated by: Mihai Moldovan <ionic at macports.org>
-Patch-Name: openssh-6.7p1-gsskex-all-20141021-284f364.patch
-Abstract: Updated for OpenSSH 7.2p1 with MacPorts patches for integration
-          with Apple's launchd, pam, sandbox and KeyChain.
-          WARNING: the commit ID does NOT match this patch. It is merely
-                   provided for reference.
-Last-Updated: 2016-03-01
-X-Ref: http://pkgs.fedoraproject.org/cgit/rpms/openssh.git/tree/openssh-7.2p1-gsskex.patch?id=13073f8d9ccec27646453f729aaa2952ae86ad01
-X-Ref: http://sources.debian.net/data/main/o/openssh/1:7.1p2-2/debian/patches/gssapi.patch (N.B.: original patch still references 7.1p2 - no newer version available currently)
----
- ChangeLog.gssapi | 113 +++++++++++++++++++
- Makefile.in      |   3 +-
- auth-krb5.c      |  17 ++-
- auth2-gss.c      |  48 +++++++-
- auth2.c          |   2 +
- clientloop.c     |  13 +++
- config.h.in      |   6 +
- configure        |  57 ++++++++++
- configure.ac     |  24 ++++
- gss-genr.c       | 275 ++++++++++++++++++++++++++++++++++++++++++++-
- gss-serv-krb5.c  |  85 ++++++++++++--
- gss-serv.c       | 221 +++++++++++++++++++++++++++++++-----
- kex.c            |  16 +++
- kex.h            |  14 +++
- kexgssc.c        | 332 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
- kexgsss.c        | 290 ++++++++++++++++++++++++++++++++++++++++++++++++
- monitor.c        | 108 +++++++++++++++++-
- monitor.h        |   3 +
- monitor_wrap.c   |  47 +++++++-
- monitor_wrap.h   |   4 +-
- readconf.c       |  42 +++++++
- readconf.h       |   5 +
- servconf.c       |  38 ++++++-
- servconf.h       |   3 +
- ssh-gss.h        |  41 ++++++-
- ssh_config       |   2 +
- ssh_config.5     |  34 +++++-
- sshconnect2.c    | 124 ++++++++++++++++++++-
- sshd.c           | 110 ++++++++++++++++++
- sshd_config      |   2 +
- sshd_config.5    |  28 +++++
- sshkey.c         |   3 +-
- sshkey.h         |   1 +
- 33 files changed, 2052 insertions(+), 59 deletions(-)
- create mode 100644 ChangeLog.gssapi
- create mode 100644 kexgssc.c
- create mode 100644 kexgsss.c
-
---- /dev/null	1970-01-01 00:00:00.000000000 +0000
-+++ b/ChangeLog.gssapi	2016-03-01 02:26:25.000000000 +0100
-@@ -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>
---- a/Makefile.in	2016-03-01 02:14:38.000000000 +0100
-+++ b/Makefile.in	2016-03-01 02:26:25.000000000 +0100
-@@ -93,7 +93,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 \
--	platform-pledge.o
-+	platform-pledge.o kexgssc.o
- 
- SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
- 	sshconnect.o sshconnect1.o sshconnect2.o mux.o
-@@ -106,7 +106,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw
- 	auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \
- 	auth2-none.o auth2-passwd.o auth2-pubkey.o \
- 	monitor_mm.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 \
---- a/auth-krb5.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/auth-krb5.c	2016-03-01 02:26:25.000000000 +0100
-@@ -183,8 +183,13 @@ auth_krb5_password(Authctxt *authctxt, c
- 
- 	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)
-@@ -241,15 +246,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;
-@@ -266,6 +278,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_c
- 		return oerrno;
- 	}
- 	close(tmpfd);
-+#endif
- 
- 	return (krb5_cc_resolve(ctx, ccname, ccache));
- }
---- a/auth2-gss.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/auth2-gss.c	2016-03-01 02:26:25.000000000 +0100
-@@ -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
-@@ -54,6 +54,40 @@ static int input_gssapi_exchange_complet
- 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,
- 
- 	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 ple
- 	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 ple
- 	return 0;
- }
- 
-+Authmethod method_gsskeyex = {
-+	"gssapi-keyex",
-+	userauth_gsskeyex,
-+	&options.gss_authentication
-+};
-+
- Authmethod method_gssapi = {
- 	"gssapi-with-mic",
- 	userauth_gssapi,
---- a/auth2.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/auth2.c	2016-03-01 02:26:25.000000000 +0100
-@@ -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,
---- a/clientloop.c	2016-03-01 02:14:25.000000000 +0100
-+++ b/clientloop.c	2016-03-01 02:26:25.000000000 +0100
-@@ -114,6 +114,10 @@
- #include "ssherr.h"
- #include "hostfile.h"
- 
-+#ifdef GSSAPI
-+#include "ssh-gss.h"
-+#endif
-+
- /* import options */
- extern Options options;
- 
-@@ -1697,9 +1701,18 @@ client_loop(int have_pty, int escape_cha
- 			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(GSS_C_NO_CONTEXT)) {
-+				debug("credentials updated - forcing rekey");
-+				need_rekeying = 1;
-+			}
-+#endif
-+		}
-+
- 		/* Buffer input from the connection.  */
- 		client_process_net_input(readset);
- 
---- a/config.h.in	2016-03-01 02:14:39.000000000 +0100
-+++ b/config.h.in	2016-03-01 02:26:25.000000000 +0100
-@@ -1653,6 +1653,9 @@
- /* Use btmp to log bad logins */
- #undef USE_BTMP
- 
-+/* platform uses an in-memory credentials cache */
-+#undef USE_CCAPI
-+
- /* Use libedit for sftp */
- #undef USE_LIBEDIT
- 
-@@ -1671,6 +1674,9 @@
- /* Define if you have Solaris privileges */
- #undef USE_SOLARIS_PRIVS
- 
-+/* platform has the Security Authorization Session API */
-+#undef USE_SECURITY_SESSION_API
-+
- /* Define if you have Solaris process contracts */
- #undef USE_SOLARIS_PROCESS_CONTRACTS
- 
---- a/configure.ac	2016-03-01 02:14:39.000000000 +0100
-+++ b/configure.ac	2016-03-01 02:26:25.000000000 +0100
-@@ -632,6 +632,30 @@ main() { if (NSVersionOfRunTimeLibrary("
- 	    [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])
---- a/gss-genr.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/gss-genr.c	2016-03-01 02:26:25.000000000 +0100
-@@ -1,7 +1,7 @@
- /* $OpenBSD: gss-genr.c,v 1.23 2015/01/20 23:14:00 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
-@@ -41,12 +41,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)
-@@ -199,7 +354,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int de
- 	}
- 
- 	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);
- 
-@@ -229,8 +384,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, con
- }
- 
- 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);
-@@ -238,6 +427,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer
- 	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)
-@@ -251,11 +453,16 @@ ssh_gssapi_buildmic(Buffer *b, const cha
- }
- 
- 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 && 
-@@ -265,6 +472,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx
- 	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);
-@@ -274,10 +485,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx
- 			    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 */
---- a/gss-serv-krb5.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/gss-serv-krb5.c	2016-03-01 02:26:25.000000000 +0100
-@@ -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_cl
- 	krb5_error_code problem;
- 	krb5_principal princ;
- 	OM_uint32 maj_status, min_status;
--	int len;
- 	const char *errmsg;
-+	const char *new_ccname, *new_cctype;
- 
- 	if (client->creds == NULL) {
- 		debug("No credentials stored");
-@@ -181,11 +181,26 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
- 		return;
- 	}
- 
--	client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache));
-+	new_cctype = krb5_cc_get_type(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
-+	if (new_ccname[0] == ':')
-+		new_ccname++;
-+	xasprintf(&client->store.envval, "%s:%s", new_cctype, new_ccname);
-+	if (strcmp(new_cctype, "DIR") == 0) {
-+		char *p;
-+		p = strrchr(client->store.envval, '/');
-+		if (p)
-+			*p = '\0';
-+	}
-+	if ((strcmp(new_cctype, "FILE") == 0) || (strcmp(new_cctype, "DIR") == 0))
-+		client->store.filename = xstrdup(new_ccname);
-+#endif
- 
- #ifdef USE_PAM
- 	if (options.use_pam)
-@@ -194,9 +209,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
- 
- 	krb5_cc_close(krb_context, ccache);
- 
-+	client->store.data = krb_context;
-+
- 	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;
-+}
-+
- ssh_gssapi_mech gssapi_kerberos_mech = {
- 	"toWM5Slw5Ew8Mqkay+al2g==",
- 	"Kerberos",
-@@ -204,7 +286,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = {
- 	NULL,
- 	&ssh_gssapi_krb5_userok,
- 	NULL,
--	&ssh_gssapi_krb5_storecreds
-+	&ssh_gssapi_krb5_storecreds,
-+	&ssh_gssapi_krb5_updatecreds
- };
- 
- #endif /* KRB5 */
---- a/gss-serv.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/gss-serv.c	2016-03-01 03:36:06.000000000 +0100
-@@ -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,20 @@
- #include "session.h"
- #include "misc.h"
- #include "servconf.h"
-+#include "uidswap.h"
- 
- #include "ssh-gss.h"
-+#include "monitor_wrap.h"
- 
- 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 +145,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss
- }
- 
- /* Unprivileged */
-+char *
-+ssh_gssapi_server_mechanisms(void) {
-+	gss_OID_set	supported;
-+
-+	ssh_gssapi_supported_oids(&supported);
-+	return (ssh_gssapi_kex_mechs(supported, &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 +177,9 @@ ssh_gssapi_supported_oids(gss_OID_set *o
- 	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 +305,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;
-+		}
-+
-+		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);
-+		}
- 
--	gss_buffer_desc ename;
-+		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 +361,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
- 	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 +385,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
- 		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;
-@@ -320,11 +397,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
- void
- ssh_gssapi_cleanup_creds(void)
- {
--	if (gssapi_client.store.filename != NULL) {
--		/* Unlink probably isn't sufficient */
--		debug("removing gssapi cred file\"%s\"",
--		    gssapi_client.store.filename);
--		unlink(gssapi_client.store.filename);
-+	krb5_ccache ccache = NULL;
-+	krb5_error_code problem;
-+
-+	if (gssapi_client.store.data != NULL) {
-+		if ((problem = krb5_cc_resolve(gssapi_client.store.data, gssapi_client.store.envval, &ccache))) {
-+			debug("%s: krb5_cc_resolve(): %.100s", __func__,
-+				krb5_get_err_text(gssapi_client.store.data, problem));
-+		} else if ((problem = krb5_cc_destroy(gssapi_client.store.data, ccache))) {
-+			debug("%s: krb5_cc_resolve(): %.100s", __func__,
-+				krb5_get_err_text(gssapi_client.store.data, problem));
-+		} else {
-+			krb5_free_context(gssapi_client.store.data);
-+			gssapi_client.store.data = NULL;
-+		}
- 	}
- }
- 
-@@ -357,7 +443,7 @@ ssh_gssapi_do_child(char ***envp, u_int 
- 
- /* Privileged */
- int
--ssh_gssapi_userok(char *user)
-+ssh_gssapi_userok(char *user, struct passwd *pw)
- {
- 	OM_uint32 lmin;
- 
-@@ -367,9 +453,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);
-@@ -383,14 +471,90 @@ 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) {
-+	int ok = 0;
-+
-+	/* Check we've got credentials to store */
-+	if (!gssapi_client.updated)
-+		return 0;
-+
-+	gssapi_client.updated = 0;
-+
-+	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
---- a/kex.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/kex.c	2016-03-01 02:26:25.000000000 +0100
-@@ -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
-@@ -109,6 +113,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)
-@@ -141,6 +153,12 @@ kex_alg_by_name(const char *name)
- 		if (strcmp(k->name, name) == 0)
- 			return k;
- 	}
-+#ifdef GSSAPI
-+	for (k = kexalg_prefixes; k->name != NULL; k++) {
-+		if (strncmp(k->name, name, strlen(k->name)) == 0)
-+			return k;
-+	}
-+#endif
- 	return NULL;
- }
- 
---- a/kex.h	2016-02-26 04:40:04.000000000 +0100
-+++ b/kex.h	2016-03-01 02:26:25.000000000 +0100
-@@ -92,6 +92,11 @@ enum kex_exchange {
- 	KEX_DH_GEX_SHA256,
- 	KEX_ECDH_SHA2,
- 	KEX_C25519_SHA256,
-+#ifdef GSSAPI
-+	KEX_GSS_GRP1_SHA1,
-+	KEX_GSS_GRP14_SHA1,
-+	KEX_GSS_GEX_SHA1,
-+#endif
- 	KEX_MAX
- };
- 
-@@ -140,6 +145,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;
-@@ -190,6 +201,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(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 *);
---- /dev/null	1970-01-01 00:00:00.000000000 +0000
-+++ b/kexgssc.c	2016-03-01 02:26:25.000000000 +0100
-@@ -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 "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) {
-+	struct kex *kex = ssh->kex;
-+	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;
-+	char *lang;
-+	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, kex->name, kex->kex_type)
-+	    == GSS_C_NO_OID)
-+		fatal("Couldn't identify host exchange");
-+
-+	if (ssh_gssapi_import_name(ctxt, kex->gss_host))
-+		fatal("Couldn't import hostname");
-+
-+	if (kex->gss_client &&
-+	    ssh_gssapi_client_identity(ctxt, kex->gss_client))
-+		fatal("Couldn't acquire client credentials");
-+
-+	switch (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(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__, kex->kex_type);
-+	}
-+
-+	/* Step 1 - e is dh->pub_key */
-+	dh_gen_key(dh, 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,
-+		    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);
-+				lang = packet_get_string(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 ((int)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 (kex->kex_type) {
-+	case KEX_GSS_GRP1_SHA1:
-+	case KEX_GSS_GRP14_SHA1:
-+		kex_dh_hash( kex->client_version_string,
-+		    kex->server_version_string,
-+		    buffer_ptr(kex->my), buffer_len(kex->my),
-+		    buffer_ptr(kex->peer), buffer_len(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(
-+		    kex->hash_alg,
-+		    kex->client_version_string,
-+		    kex->server_version_string,
-+		    buffer_ptr(kex->my), buffer_len(kex->my),
-+		    buffer_ptr(kex->peer), buffer_len(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__, 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);
-+	if (serverhostkey)
-+		free(serverhostkey);
-+	BN_clear_free(dh_server_pub);
-+
-+	/* save session id */
-+	if (kex->session_id == NULL) {
-+		kex->session_id_len = hashlen;
-+		kex->session_id = xmalloc(kex->session_id_len);
-+		memcpy(kex->session_id, hash, kex->session_id_len);
-+	}
-+
-+	if (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 */
---- /dev/null	1970-01-01 00:00:00.000000000 +0000
-+++ b/kexgsss.c	2016-03-01 02:26:25.000000000 +0100
-@@ -0,0 +1,300 @@
-+/*
-+ * 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 <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 "ssh-gss.h"
-+#include "digest.h"
-+
-+extern ServerOptions options;
-+
-+int
-+kexgss_server(struct ssh *ssh)
-+{
-+	struct kex *kex = ssh->kex;
-+	int r = 0;
-+
-+	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()) {
-+		if ((mechs = ssh_gssapi_server_mechanisms())) {
-+			free(mechs);
-+		}
-+	}
-+
-+	debug2("%s: Identifying %s", __func__, kex->name);
-+	oid = ssh_gssapi_id_kex(NULL, kex->name, 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 (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();
-+		min = MAX(DH_GRP_MIN, min);
-+		max = MIN(DH_GRP_MAX, max);
-+		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(min, nbits, 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__, kex->kex_type);
-+	}
-+
-+	dh_gen_key(dh, 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 ((int)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 (kex->kex_type) {
-+	case KEX_GSS_GRP1_SHA1:
-+	case KEX_GSS_GRP14_SHA1:
-+		kex_dh_hash(
-+		    kex->client_version_string, kex->server_version_string,
-+		    buffer_ptr(kex->peer), buffer_len(kex->peer),
-+		    buffer_ptr(kex->my), buffer_len(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(
-+		    kex->hash_alg,
-+		    kex->client_version_string, kex->server_version_string,
-+		    buffer_ptr(kex->peer), buffer_len(kex->peer),
-+		    buffer_ptr(kex->my), buffer_len(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__, kex->kex_type);
-+	}
-+
-+	BN_clear_free(dh_client_pub);
-+
-+	if (kex->session_id == NULL) {
-+		kex->session_id_len = hashlen;
-+		kex->session_id = xmalloc(kex->session_id_len);
-+		memcpy(kex->session_id, hash, 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);
-+	r = 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 r;
-+}
-+#endif /* GSSAPI */
---- a/monitor.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/monitor.c	2016-03-01 03:43:58.000000000 +0100
-@@ -156,6 +156,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
-@@ -233,11 +235,18 @@ struct mon_table mon_dispatch_proto20[] 
-     {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
-     {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
-     {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, 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
-@@ -352,6 +361,10 @@ monitor_child_preauth(Authctxt *_authctx
- 		/* 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
- 	} else {
- 		mon_dispatch = mon_dispatch_proto15;
- 
-@@ -460,6 +473,10 @@ monitor_child_postauth(struct monitor *p
- 		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		
- 	} else {
- 		mon_dispatch = mon_dispatch_postauth15;
- 		monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
-@@ -1861,6 +1878,13 @@ monitor_apply_keystate(struct monitor *p
- # 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;
-@@ -1960,6 +1984,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer
- 	OM_uint32 major;
- 	u_int len;
- 
-+	if (!options.gss_authentication && !options.gss_keyex)
-+		fatal("In GSSAPI monitor when GSSAPI is disabled");
-+
- 	goid.elements = buffer_get_string(m, &len);
- 	goid.length = len;
- 
-@@ -1987,6 +2014,9 @@ mm_answer_gss_accept_ctx(int sock, Buffe
- 	OM_uint32 flags = 0; /* GSI needs this */
- 	u_int len;
- 
-+	if (!options.gss_authentication && !options.gss_keyex)
-+		fatal("In GSSAPI monitor when GSSAPI is disabled");
-+
- 	in.value = buffer_get_string(m, &len);
- 	in.length = len;
- 	major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
-@@ -2004,6 +2034,7 @@ mm_answer_gss_accept_ctx(int sock, Buffe
- 		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);
- }
-@@ -2015,6 +2046,9 @@ mm_answer_gss_checkmic(int sock, Buffer 
- 	OM_uint32 ret;
- 	u_int len;
- 
-+	if (!options.gss_authentication && !options.gss_keyex)
-+		fatal("In GSSAPI monitor when GSSAPI is disabled");
-+
- 	gssbuf.value = buffer_get_string(m, &len);
- 	gssbuf.length = len;
- 	mic.value = buffer_get_string(m, &len);
-@@ -2041,7 +2075,11 @@ mm_answer_gss_userok(int sock, Buffer *m
- {
- 	int authenticated;
- 
--	authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
-+	if (!options.gss_authentication && !options.gss_keyex)
-+		fatal("In GSSAPI monitor when GSSAPI is disabled");
-+
-+	authenticated = authctxt->valid && 
-+	    ssh_gssapi_userok(authctxt->user, authctxt->pw);
- 
- 	buffer_clear(m);
- 	buffer_put_int(m, authenticated);
-@@ -2054,5 +2092,73 @@ 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("In GSSAPI monitor when GSSAPI is disabled");
-+
-+	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;
-+
-+	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 */
- 
---- a/monitor.h	2016-02-26 04:40:04.000000000 +0100
-+++ b/monitor.h	2016-03-01 02:26:25.000000000 +0100
-@@ -65,6 +65,9 @@ enum monitor_reqtype {
- 	MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
- 	MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
- 
-+	MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151,
-+	MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153,
-+
- };
- 
- struct mm_master;
---- a/monitor_wrap.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/monitor_wrap.c	2016-03-01 02:26:25.000000000 +0100
-@@ -1068,7 +1068,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss
- }
- 
- int
--mm_ssh_gssapi_userok(char *user)
-+mm_ssh_gssapi_userok(char *user, struct passwd *pw)
- {
- 	Buffer m;
- 	int authenticated = 0;
-@@ -1085,5 +1085,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 */
- 
---- a/monitor_wrap.h	2016-02-26 04:40:04.000000000 +0100
-+++ b/monitor_wrap.h	2016-03-01 02:26:25.000000000 +0100
-@@ -58,8 +58,10 @@ BIGNUM *mm_auth_rsa_generate_challenge(K
- 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
---- a/readconf.c	2016-03-01 02:14:39.000000000 +0100
-+++ b/readconf.c	2016-03-01 02:26:25.000000000 +0100
-@@ -148,6 +148,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,
-@@ -196,10 +198,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 },
-@@ -932,10 +943,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;
-@@ -1660,7 +1691,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;
-@@ -1792,8 +1828,14 @@ fill_default_options(Options * options)
- 		options->challenge_response_authentication = 1;
- 	if (options->gss_authentication == -1)
- 		options->gss_authentication = 0;
-+	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)
---- a/readconf.h	2016-03-01 02:14:39.000000000 +0100
-+++ b/readconf.h	2016-03-01 02:26:25.000000000 +0100
-@@ -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. */
---- a/servconf.c	2016-03-01 02:14:39.000000000 +0100
-+++ b/servconf.c	2016-03-01 03:46:29.000000000 +0100
-@@ -117,8 +117,10 @@ initialize_server_options(ServerOptions 
- 	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;
-@@ -287,10 +289,14 @@ fill_default_server_options(ServerOption
- 		options->kerberos_get_afs_token = 0;
- 	if (options->gss_authentication == -1)
- 		options->gss_authentication = 0;
-+	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 = 0;
- 	if (options->kbd_interactive_authentication == -1)
-@@ -419,6 +425,7 @@ typedef enum {
- 	sHostKeyAlgorithms,
- 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
- 	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
-+	sGssKeyEx, sGssStoreRekey,
- 	sAcceptEnv, sPermitTunnel,
- 	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
- 	sUsePrivilegeSeparation, sAllowAgentForwarding,
-@@ -493,11 +500,17 @@ static struct {
- 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
- 	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
- 	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
-+	{ "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
-+	{ "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
- #else
- 	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
- 	{ "gssapicleanupcredentials", 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 },
-@@ -1242,6 +1255,10 @@ process_server_config_line(ServerOptions
- 		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;
-@@ -1250,6 +1267,10 @@ process_server_config_line(ServerOptions
- 		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;
-@@ -2265,7 +2286,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,
---- a/servconf.h	2016-02-26 04:40:04.000000000 +0100
-+++ b/servconf.h	2016-03-01 02:26:26.000000000 +0100
-@@ -118,8 +118,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 */
---- a/ssh-gss.h	2016-02-26 04:40:04.000000000 +0100
-+++ b/ssh-gss.h	2016-03-01 02:26:26.000000000 +0100
-@@ -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 */
---- a/ssh_config	2016-02-26 04:40:04.000000000 +0100
-+++ b/ssh_config	2016-03-01 02:26:26.000000000 +0100
-@@ -26,6 +26,8 @@
- #   HostbasedAuthentication no
- #   GSSAPIAuthentication no
- #   GSSAPIDelegateCredentials no
-+#   GSSAPIKeyExchange no
-+#   GSSAPITrustDNS no
- #   BatchMode no
- #   CheckHostIP yes
- #   AddressFamily any
---- a/ssh_config.5	2016-02-26 04:40:04.000000000 +0100
-+++ b/ssh_config.5	2016-03-01 02:26:26.000000000 +0100
-@@ -826,10 +826,43 @@ The default is
- Specifies whether user authentication based on GSSAPI is allowed.
- The default is
- .Dq no .
-+.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
-+.Dq no .
-+Note that this option applies to protocol version 2 only.
-+.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
- .Dq no .
-+Note that this option applies to protocol version 2 connections using GSSAPI.
-+.It Cm GSSAPIRenewalForcesRekey
-+If set to 
-+.Dq 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
-+.Dq no .
-+.It Cm GSSAPITrustDns
-+Set to 
-+.Dq yes to indicate that the DNS is trusted to securely canonicalize
-+the name of the host being connected to. If 
-+.Dq no, the hostname entered on the
-+command line will be passed untouched to the GSSAPI library.
-+The default is
-+.Dq no .
-+This option only applies to protocol version 2 connections using GSSAPI.
- .It Cm HashKnownHosts
- Indicates that
- .Xr ssh 1
---- a/sshconnect2.c	2016-03-01 02:24:20.000000000 +0100
-+++ b/sshconnect2.c	2016-03-01 04:15:58.000000000 +0100
-@@ -162,6 +162,11 @@ ssh_kex2(char *host, struct sockaddr *ho
- 	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,33 @@ ssh_kex2(char *host, struct sockaddr *ho
- 		    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_trust_dns)
-+			gss_host = (char *)get_canonical_hostname(1);
-+		else
-+			gss_host = 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);
-+			free(gss);
-+		}
-+	}
-+#endif
-+
- 	if (options.rekey_limit || options.rekey_interval)
- 		packet_set_rekey_limits((u_int32_t)options.rekey_limit,
- 		    (time_t)options.rekey_interval);
-@@ -214,10 +246,30 @@ ssh_kex2(char *host, struct sockaddr *ho
- # 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;
-+		if (options.gss_server_identity) {
-+			kex->gss_host = options.gss_server_identity;
-+		} else {
-+			kex->gss_host = gss_host;
-+		}
-+	}
-+#endif
-+
- 	dispatch_run(DISPATCH_BLOCK, &kex->done, active_state);
- 
- 	/* remove ext-info from the KEX proposals for rekeying */
-@@ -312,6 +364,7 @@ int	input_gssapi_token(int type, u_int32
- 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 *);
-@@ -327,6 +380,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,
-@@ -657,19 +715,31 @@ userauth_gssapi(Authctxt *authctxt)
- 	static u_int mech = 0;
- 	OM_uint32 min;
- 	int ok = 0;
-+	const char *gss_host;
-+
-+	if (options.gss_server_identity)
-+		gss_host = options.gss_server_identity;
-+	else if (options.gss_trust_dns)
-+		gss_host = get_canonical_hostname(1);
-+	else
-+		gss_host = 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;
-+			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++;
-@@ -766,8 +836,8 @@ input_gssapi_response(int type, u_int32_
- {
- 	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");
-@@ -880,6 +950,48 @@ input_gssapi_error(int type, u_int32_t p
- 	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
---- a/sshd.c	2016-03-01 02:14:39.000000000 +0100
-+++ b/sshd.c	2016-03-01 02:26:26.000000000 +0100
-@@ -125,6 +125,10 @@
- #include "version.h"
- #include "ssherr.h"
- 
-+#ifdef USE_SECURITY_SESSION_API
-+#include <Security/AuthSession.h>
-+#endif
-+
- #ifndef O_NOCTTY
- #define O_NOCTTY	0
- #endif
-@@ -974,8 +978,9 @@ notify_hostkeys(struct ssh *ssh)
- 	}
- 	debug3("%s: sent %d hostkeys", __func__, nkeys);
- 	if (nkeys == 0)
--		fatal("%s: no hostkeys", __func__);
--	packet_send();
-+		debug3("%s: no hostkeys", __func__);
-+	else
-+		packet_send();
- 	sshbuf_free(buf);
- }
- 
-@@ -1840,10 +1845,13 @@ main(int ac, char **av)
- 		logit("Disabling protocol version 1. Could not load host key");
- 		options.protocol &= ~SSH_PROTO_1;
- 	}
-+#ifndef GSSAPI
-+	/* The GSSAPI key exchange can run without a host key */
- 	if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
- 		logit("Disabling protocol version 2. Could not load host key");
- 		options.protocol &= ~SSH_PROTO_2;
- 	}
-+#endif
- 	if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
- 		logit("sshd: no hostkeys available -- exiting.");
- 		exit(1);
-@@ -2158,6 +2166,60 @@ main(int ac, char **av)
- 	    remote_ip, remote_port, laddr,  get_local_port());
- 	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
-@@ -2578,6 +2640,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));
-@@ -2592,6 +2696,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;
---- a/sshd_config	2016-03-01 02:14:39.000000000 +0100
-+++ b/sshd_config	2016-03-01 02:26:26.000000000 +0100
-@@ -85,6 +85,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
---- a/sshd_config.5	2016-03-01 02:14:39.000000000 +0100
-+++ b/sshd_config.5	2016-03-01 02:26:26.000000000 +0100
-@@ -623,6 +623,12 @@ The default is
- Specifies whether user authentication based on GSSAPI is allowed.
- The default is
- .Dq no .
-+.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
-+.Dq no .
-+Note that this option applies to protocol version 2 only.
- .It Cm GSSAPICleanupCredentials
- Specifies whether to automatically destroy the user's credentials cache
- on logout.
-@@ -643,6 +649,11 @@ machine's default store.
- This facility is provided to assist with operation on multi homed machines.
- The default is
- .Dq 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
-+.Dq no .
- .It Cm HostbasedAcceptedKeyTypes
- Specifies the key types that will be accepted for hostbased authentication
- as a comma-separated pattern list.
---- a/sshkey.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/sshkey.c	2016-03-01 02:26:26.000000000 +0100
-@@ -115,6 +115,7 @@ static const struct keytype keytypes[] =
- #  endif /* OPENSSL_HAS_NISTP521 */
- # endif /* OPENSSL_HAS_ECC */
- #endif /* WITH_OPENSSL */
-+	{ "null", "null", KEY_NULL, 0, 0, 1 },
- 	{ NULL, NULL, -1, -1, 0, 0 }
- };
- 
---- a/sshkey.h	2016-02-26 04:40:04.000000000 +0100
-+++ b/sshkey.h	2016-03-01 02:26:26.000000000 +0100
-@@ -62,6 +62,7 @@ enum sshkey_types {
- 	KEY_DSA_CERT,
- 	KEY_ECDSA_CERT,
- 	KEY_ED25519_CERT,
-+	KEY_NULL,
- 	KEY_UNSPEC
- };
- 
---- a/auth.c	2016-03-01 02:22:17.000000000 +0100
-+++ b/auth.c	2016-03-01 02:26:26.000000000 +0100
-@@ -354,6 +354,7 @@ auth_root_allowed(const char *method)
- 	case PERMIT_NO_PASSWD:
- 		if (strcmp(method, "publickey") == 0 ||
- 		    strcmp(method, "hostbased") == 0 ||
-+		    strcmp(method, "gssapi-keyex") == 0 ||
- 		    strcmp(method, "gssapi-with-mic") == 0)
- 			return 1;
- 		break;

Deleted: trunk/dports/net/openssh/files/openssh-7.2p1-hpnssh14v5.diff
===================================================================
--- trunk/dports/net/openssh/files/openssh-7.2p1-hpnssh14v5.diff	2016-09-29 13:44:26 UTC (rev 153359)
+++ trunk/dports/net/openssh/files/openssh-7.2p1-hpnssh14v5.diff	2016-09-29 13:49:14 UTC (rev 153360)
@@ -1,1284 +0,0 @@
---- /dev/null	1970-01-01 00:00:00.000000000 +0000
-+++ b/HPN-README	2016-03-01 04:32:19.000000000 +0100
-@@ -0,0 +1,129 @@
-+Notes:
-+
-+MULTI-THREADED CIPHER:
-+The AES cipher in CTR mode has been multithreaded (MTR-AES-CTR). This will allow ssh installations
-+on hosts with multiple cores to use more than one processing core during encryption.
-+Tests have show significant throughput performance increases when using MTR-AES-CTR up
-+to and including a full gigabit per second on quad core systems. It should be possible to
-+achieve full line rate on dual core systems but OS and data management overhead makes this
-+more difficult to achieve. The cipher stream from MTR-AES-CTR is entirely compatible with single
-+thread AES-CTR (ST-AES-CTR) implementations and should be 100% backward compatible. Optimal
-+performance requires the MTR-AES-CTR mode be enabled on both ends of the connection.
-+The MTR-AES-CTR replaces ST-AES-CTR and is used in exactly the same way with the same
-+nomenclature.
-+Use examples:  ssh -caes128-ctr you at host.com
-+               scp -oCipher=aes256-ctr file you at host.com:~/file
-+
-+NONE CIPHER:
-+To use the NONE option you must have the NoneEnabled switch set on the server and
-+you *must* have *both* NoneEnabled and NoneSwitch set to yes on the client. The NONE
-+feature works with ALL ssh subsystems (as far as we can tell) *AS LONG AS* a tty is not
-+spawned. If a user uses the -T switch to prevent a tty being created the NONE cipher will
-+be disabled.
-+
-+The performance increase will only be as good as the network and TCP stack tuning
-+on the receiver side of the connection allows. As a rule of thumb a user will need
-+at least 10Mb/s connection with a 100ms RTT to see a doubling of performance. The
-+HPN-SSH home page describes this in greater detail.
-+
-+http://www.psc.edu/networking/projects/hpn-ssh
-+
-+BUFFER SIZES:
-+
-+If HPN is disabled the receive buffer size will be set to the
-+OpenSSH default of 64K.
-+
-+If an HPN system connects to a nonHPN system the receive buffer will
-+be set to the HPNBufferSize value. The default is 2MB but user adjustable.
-+
-+If an HPN to HPN connection is established a number of different things might
-+happen based on the user options and conditions.
-+
-+Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set
-+HPN Buffer Size = up to 64MB
-+This is the default state. The HPN buffer size will grow to a maximum of 64MB
-+as the TCP receive buffer grows. The maximum HPN Buffer size of 64MB is
-+geared towards 10GigE transcontinental connections.
-+
-+Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set
-+HPN Buffer Size = TCP receive buffer value.
-+Users on non-autotuning systesm should disable TCPRcvBufPoll in the
-+ssh_cofig and sshd_config
-+
-+Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set
-+HPN Buffer Size = minmum of TCP receive buffer and HPNBufferSize.
-+This would be the system defined TCP receive buffer (RWIN).
-+
-+Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf SET
-+HPN Buffer Size = minmum of TCPRcvBuf and HPNBufferSize.
-+Generally there is no need to set both.
-+
-+Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set
-+HPN Buffer Size = grows to HPNBufferSize
-+The buffer will grow up to the maximum size specified here.
-+
-+Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf SET
-+HPN Buffer Size = minmum of TCPRcvBuf and HPNBufferSize.
-+Generally there is no need to set both of these, especially on autotuning
-+systems. However, if the users wishes to override the autotuning this would be
-+one way to do it.
-+
-+Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf SET
-+HPN Buffer Size = TCPRcvBuf.
-+This will override autotuning and set the TCP recieve buffer to the user defined
-+value.
-+
-+
-+HPN Specific Configuration options
-+
-+TcpRcvBuf=[int]KB client
-+      set the TCP socket receive buffer to n Kilobytes. It can be set up to the
-+maximum socket size allowed by the system. This is useful in situations where
-+the tcp receive window is set low but the maximum buffer size is set
-+higher (as is typical). This works on a per TCP connection basis. You can also
-+use this to artifically limit the transfer rate of the connection. In these
-+cases the throughput will be no more than n/RTT. The minimum buffer size is 1KB.
-+Default is the current system wide tcp receive buffer size.
-+
-+TcpRcvBufPoll=[yes/no] client/server
-+      enable of disable the polling of the tcp receive buffer through the life
-+of the connection. You would want to make sure that this option is enabled
-+for systems making use of autotuning kernels (linux 2.4.24+, 2.6, MS Vista)
-+default is yes.
-+
-+NoneEnabled=[yes/no] client/server
-+      enable or disable the use of the None cipher. Care must always be used
-+when enabling this as it will allow users to send data in the clear. However,
-+it is important to note that authentication information remains encrypted
-+even if this option is enabled. Set to no by default.
-+
-+NoneSwitch=[yes/no] client
-+     Switch the encryption cipher being used to the None cipher after
-+authentication takes place. NoneEnabled must be enabled on both the client
-+and server side of the connection. When the connection switches to the NONE
-+cipher a warning is sent to STDERR. The connection attempt will fail with an
-+error if a client requests a NoneSwitch from the server that does not explicitly
-+have NoneEnabled set to yes. Note: The NONE cipher cannot be used in
-+interactive (shell) sessions and it will fail silently. Set to no by default.
-+
-+HPNDisabled=[yes/no] client/server
-+     In some situations, such as transfers on a local area network, the impact
-+of the HPN code produces a net decrease in performance. In these cases it is
-+helpful to disable the HPN functionality. By default HPNDisabled is set to no.
-+
-+HPNBufferSize=[int]KB client/server
-+     This is the default buffer size the HPN functionality uses when interacting
-+with nonHPN SSH installations. Conceptually this is similar to the TcpRcvBuf
-+option as applied to the internal SSH flow control. This value can range from
-+1KB to 64MB (1-65536). Use of oversized or undersized buffers can cause performance
-+problems depending on the length of the network path. The default size of this buffer
-+is 2MB.
-+
-+
-+Credits: This patch was conceived, designed, and led by Chris Rapier (rapier at psc.edu)
-+         The majority of the actual coding for versions up to HPN12v1 was performed
-+         by Michael Stevens (mstevens at andrew.cmu.edu). The MT-AES-CTR cipher was
-+        implemented by Ben Bennet (ben at psc.edu) and improved by Mike Tasota
-+        (tasota at gmail.com) an NSF REU grant recipient for 2013.
-+        This work was financed, in part, by Cisco System, Inc., the National
-+         Library of Medicine, and the National Science Foundation.
---- a/channels.c	2016-03-01 04:32:11.000000000 +0100
-+++ b/channels.c	2016-03-01 04:32:19.000000000 +0100
-@@ -186,6 +186,12 @@ static void port_open_helper(Channel *c,
- static int connect_next(struct channel_connect *);
- static void channel_connect_ctx_free(struct channel_connect *);
- 
-+
-+#ifdef HPN_ENABLED
-+static int hpn_disabled = 0;
-+static int hpn_buffer_size = 2 * 1024 * 1024;
-+#endif
-+
- /* -- channel core */
- 
- Channel *
-@@ -336,6 +342,9 @@ channel_new(char *ctype, int type, int r
- 	c->local_window_max = window;
- 	c->local_consumed = 0;
- 	c->local_maxpacket = maxpack;
-+#ifdef HPN_ENABLED
-+	c->dynamic_window = 0;
-+#endif
- 	c->remote_id = -1;
- 	c->remote_name = xstrdup(remote_name);
- 	c->remote_window = 0;
-@@ -840,11 +849,41 @@ channel_pre_open_13(Channel *c, fd_set *
- 		FD_SET(c->sock, writeset);
- }
- 
-+#ifdef HPN_ENABLED
-+static u_int
-+channel_tcpwinsz(void)
-+{
-+	u_int32_t tcpwinsz = 0;
-+	socklen_t optsz = sizeof(tcpwinsz);
-+	int ret = -1;
-+
-+	/* if we aren't on a socket return 128KB */
-+	if (!packet_connection_is_on_socket())
-+		return (128*1024);
-+	ret = getsockopt(packet_get_connection_in(),
-+	    SOL_SOCKET, SO_RCVBUF, &tcpwinsz, &optsz);
-+	/* return no more than SSHBUF_SIZE_MAX */
-+	if (ret == 0 && tcpwinsz > SSHBUF_SIZE_MAX)
-+		tcpwinsz = SSHBUF_SIZE_MAX;
-+	debug2("tcpwinsz: %d for connection: %d", tcpwinsz,
-+	    packet_get_connection_in());
-+	return (tcpwinsz);
-+}
-+#endif
-+
- static void
- channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
- {
- 	u_int limit = compat20 ? c->remote_window : packet_get_maxsize();
- 
-+#ifdef HPN_ENABLED
-+	/* check buffer limits */
-+	if (!c->tcpwinsz || c->dynamic_window > 0)
-+		c->tcpwinsz = channel_tcpwinsz();
-+
-+	limit = MIN(limit, 2 * c->tcpwinsz);
-+#endif
-+
- 	if (c->istate == CHAN_INPUT_OPEN &&
- 	    limit > 0 &&
- 	    buffer_len(&c->input) < limit &&
-@@ -1862,6 +1901,20 @@ channel_check_window(Channel *c)
- 	    c->local_maxpacket*3) ||
- 	    c->local_window < c->local_window_max/2) &&
- 	    c->local_consumed > 0) {
-+#ifdef HPN_ENABLED
-+		/* adjust max window size if we are in a dynamic environment */
-+		if (c->dynamic_window && (c->tcpwinsz > c->local_window_max)) {
-+			u_int addition = 0;
-+
-+			/*
-+			 * grow the window somewhat aggressively to maintain
-+			 * pressure
-+			 */
-+			addition = 1.5*(c->tcpwinsz - c->local_window_max);
-+			c->local_window_max += addition;
-+			c->local_consumed += addition;
-+		}
-+#endif
- 		packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
- 		packet_put_int(c->remote_id);
- 		packet_put_int(c->local_consumed);
-@@ -2813,6 +2866,17 @@ channel_fwd_bind_addr(const char *listen
- 	return addr;
- }
- 
-+#ifdef HPN_ENABLED
-+void
-+channel_set_hpn(int external_hpn_disabled, int external_hpn_buffer_size)
-+{
-+	hpn_disabled = external_hpn_disabled;
-+	hpn_buffer_size = external_hpn_buffer_size;
-+	debug("HPN Disabled: %d, HPN Buffer Size: %d", hpn_disabled,
-+	    hpn_buffer_size);
-+}
-+#endif
-+
- static int
- channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd,
-     int *allocated_listen_port, struct ForwardOptions *fwd_opts)
-@@ -2941,6 +3005,17 @@ channel_setup_fwd_listener_tcpip(int typ
- 		}
- 
- 		/* Allocate a channel number for the socket. */
-+#ifdef HPN_ENABLED
-+		/*
-+		 * explicitly test for hpn disabled option. if true use smaller
-+		 * window size.
-+		 */
-+		if (!hpn_disabled)
-+			c = channel_new("port listener", type, sock, sock, -1,
-+			    hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT,
-+			    0, "port listener", 1);
-+		else
-+#endif
- 		c = channel_new("port listener", type, sock, sock, -1,
- 		    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
- 		    0, "port listener", 1);
-@@ -3975,6 +4050,14 @@ x11_create_display_inet(int x11_display_
- 	*chanids = xcalloc(num_socks + 1, sizeof(**chanids));
- 	for (n = 0; n < num_socks; n++) {
- 		sock = socks[n];
-+#ifdef HPN_ENABLED
-+		if (!hpn_disabled)
-+			nc = channel_new("x11 listener",
-+			    SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
-+			    hpn_buffer_size, CHAN_X11_PACKET_DEFAULT,
-+			    0, "X11 inet listener", 1);
-+		else
-+#endif
- 		nc = channel_new("x11 listener",
- 		    SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
- 		    CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
---- a/channels.h	2016-02-26 04:40:04.000000000 +0100
-+++ b/channels.h	2016-03-01 04:32:19.000000000 +0100
-@@ -136,6 +136,10 @@ struct Channel {
- 	u_int	local_maxpacket;
- 	int     extended_usage;
- 	int	single_connection;
-+#ifdef HPN_ENABLED
-+	int	dynamic_window;
-+	u_int	tcpwinsz;
-+#endif
- 
- 	char   *ctype;		/* type */
- 
-@@ -312,4 +316,9 @@ void	 chan_rcvd_ieof(Channel *);
- void	 chan_write_failed(Channel *);
- void	 chan_obuf_empty(Channel *);
- 
-+#ifdef HPN_ENABLED
-+/* hpn handler */
-+void     channel_set_hpn(int, int);
-+#endif
-+
- #endif
---- a/cipher.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/cipher.c	2016-03-01 04:32:19.000000000 +0100
-@@ -244,7 +244,13 @@ ciphers_valid(const char *names)
- 	for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
- 	    (p = strsep(&cp, CIPHER_SEP))) {
- 		c = cipher_by_name(p);
--		if (c == NULL || c->number != SSH_CIPHER_SSH2) {
-+		if (c == NULL || (c->number != SSH_CIPHER_SSH2 &&
-+#ifdef NONE_CIPHER_ENABLED
-+				  c->number != SSH_CIPHER_NONE
-+#else
-+				  1
-+#endif
-+				  )) {
- 			free(cipher_list);
- 			return 0;
- 		}
-@@ -544,6 +550,9 @@ cipher_get_keyiv(struct sshcipher_ctx *c
- 
- 	switch (c->number) {
- #ifdef WITH_OPENSSL
-+#ifdef NONE_CIPHER_ENABLED
-+	case SSH_CIPHER_NONE:
-+#endif
- 	case SSH_CIPHER_SSH2:
- 	case SSH_CIPHER_DES:
- 	case SSH_CIPHER_BLOWFISH:
-@@ -592,6 +601,9 @@ cipher_set_keyiv(struct sshcipher_ctx *c
- 
- 	switch (c->number) {
- #ifdef WITH_OPENSSL
-+#ifdef NONE_CIPHER_ENABLED
-+	case SSH_CIPHER_NONE:
-+#endif
- 	case SSH_CIPHER_SSH2:
- 	case SSH_CIPHER_DES:
- 	case SSH_CIPHER_BLOWFISH:
---- a/clientloop.c	2016-03-01 04:32:11.000000000 +0100
-+++ b/clientloop.c	2016-03-01 04:32:19.000000000 +0100
-@@ -1995,6 +1995,15 @@ client_request_x11(const char *request_t
- 	sock = x11_connect_display();
- 	if (sock < 0)
- 		return NULL;
-+#ifdef HPN_ENABLED
-+	/* again is this really necessary for X11? */
-+	if (!options.hpn_disabled)
-+		c = channel_new("x11",
-+		    SSH_CHANNEL_X11_OPEN, sock, sock, -1,
-+		    options.hpn_buffer_size,
-+		    CHAN_X11_PACKET_DEFAULT, 0, "x11", 1);
-+	else
-+#endif
- 	c = channel_new("x11",
- 	    SSH_CHANNEL_X11_OPEN, sock, sock, -1,
- 	    CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1);
-@@ -2020,6 +2029,14 @@ client_request_agent(const char *request
- 			    __func__, ssh_err(r));
- 		return NULL;
- 	}
-+#ifdef HPN_ENABLED
-+	if (!options.hpn_disabled)
-+		c = channel_new("authentication agent connection",
-+		    SSH_CHANNEL_OPEN, sock, sock, -1,
-+		    options.hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, 0,
-+		    "authentication agent connection", 1);
-+	else
-+#endif
- 	c = channel_new("authentication agent connection",
- 	    SSH_CHANNEL_OPEN, sock, sock, -1,
- 	    CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0,
-@@ -2050,6 +2067,12 @@ client_request_tun_fwd(int tun_mode, int
- 		return -1;
- 	}
- 
-+#ifdef HPN_ENABLED
-+	if (!options.hpn_disabled)
-+		c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1,
-+		    options.hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
-+	else
-+#endif
- 	c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1,
- 	    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
- 	c->datagram = 1;
---- a/compat.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/compat.c	2016-03-01 04:32:19.000000000 +0100
-@@ -210,6 +210,14 @@ compat_datafellows(const char *version)
- 			debug("match: %s pat %s compat 0x%08x",
- 			    version, check[i].pat, check[i].bugs);
- 			datafellows = check[i].bugs;	/* XXX for now */
-+#ifdef HPN_ENABLED
-+			/* Check to see if the remote side is OpenSSH and not HPN */
-+			if (strstr(version,"OpenSSH") != NULL &&
-+			    strstr(version,"hpn") == NULL) {
-+				datafellows |= SSH_BUG_LARGEWINDOW;
-+				debug("Remote is NON-HPN aware");
-+			}
-+#endif
- 			return check[i].bugs;
- 		}
- 	}
---- a/compat.h	2016-02-26 04:40:04.000000000 +0100
-+++ b/compat.h	2016-03-01 04:32:19.000000000 +0100
-@@ -62,6 +62,9 @@
- #define SSH_BUG_CURVE25519PAD	0x10000000
- #define SSH_BUG_HOSTKEYS	0x20000000
- #define SSH_BUG_DHGEX_LARGE	0x40000000
-+#ifdef HPN_ENABLED
-+#define SSH_BUG_LARGEWINDOW     0x80000000
-+#endif
- 
- void     enable_compat13(void);
- void     enable_compat20(void);
---- a/configure.ac	2016-02-26 04:40:04.000000000 +0100
-+++ b/configure.ac	2016-03-01 04:32:19.000000000 +0100
-@@ -4321,6 +4321,25 @@ AC_ARG_WITH([maildir],
-     ]
- ) # maildir
- 
-+#check whether user wants HPN support
-+HPN_MSG="no"
-+AC_ARG_WITH(hpn,
-+	[  --with-hpn             Enable HPN support],
-+	[ if test "x$withval" != "xno" ; then
-+		AC_DEFINE(HPN_ENABLED,1,[Define if you want HPN support.])
-+		HPN_MSG="yes"
-+	fi ]
-+)
-+#check whether user wants NONECIPHER support
-+NONECIPHER_MSG="no"
-+AC_ARG_WITH(nonecipher,
-+	[  --with-nonecipher             Enable NONECIPHER support],
-+	[ if test "x$withval" != "xno" ; then
-+		AC_DEFINE(NONE_CIPHER_ENABLED,1,[Define if you want NONECIPHER support.])
-+		NONECIPHER_MSG="yes"
-+	fi ]
-+)
-+
- if test ! -z "$cross_compiling" && test "x$cross_compiling" = "xyes"; then
- 	AC_MSG_WARN([cross compiling: Disabling /dev/ptmx test])
- 	disable_ptmx_check=yes
-@@ -4989,6 +5008,8 @@ echo "           Translate v4 in v6 hack
- echo "                  BSD Auth support: $BSD_AUTH_MSG"
- echo "              Random number source: $RAND_MSG"
- echo "             Privsep sandbox style: $SANDBOX_STYLE"
-+echo "                       HPN support: $HPN_MSG"
-+echo "                NONECIPHER support: $NONECIPHER_MSG"
- 
- echo ""
- 
---- a/kex.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/kex.c	2016-03-01 04:32:19.000000000 +0100
-@@ -822,6 +822,20 @@ kex_choose_conf(struct ssh *ssh)
- 			peer[ncomp] = NULL;
- 			goto out;
- 		}
-+#ifdef NONE_CIPHER_ENABLED
-+		debug("REQUESTED ENC.NAME is '%s'", newkeys->enc.name);
-+		if (strcmp(newkeys->enc.name, "none") == 0) {
-+			int auth_flag;
-+
-+			auth_flag = ssh_packet_authentication_state(ssh);
-+			debug("Requesting NONE. Authflag is %d", auth_flag);
-+			if (auth_flag == 1) {
-+				debug("None requested post authentication.");
-+			} else {
-+				fatal("Pre-authentication none cipher requests are not allowed.");
-+			}
-+		}
-+#endif
- 		debug("kex: %s cipher: %s MAC: %s compression: %s",
- 		    ctos ? "client->server" : "server->client",
- 		    newkeys->enc.name,
---- a/packet.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/packet.c	2016-03-01 04:32:19.000000000 +0100
-@@ -1037,6 +1037,24 @@ ssh_set_newkeys(struct ssh *ssh, int mod
- 	return 0;
- }
- 
-+#ifdef NONE_CIPHER_ENABLED
-+/* this supports the forced rekeying required for the NONE cipher */
-+int rekey_requested = 0;
-+void
-+packet_request_rekeying(void)
-+{
-+	rekey_requested = 1;
-+}
-+
-+int
-+ssh_packet_authentication_state(struct ssh *ssh)
-+{
-+	struct session_state *state = ssh->state;
-+
-+	return(state->after_authentication);
-+}
-+#endif
-+
- #define MAX_PACKETS	(1U<<31)
- static int
- ssh_packet_need_rekeying(struct ssh *ssh, u_int outbound_packet_len)
-@@ -1055,6 +1073,12 @@ ssh_packet_need_rekeying(struct ssh *ssh
- 	/* Peer can't rekey */
- 	if (ssh->compat & SSH_BUG_NOREKEY)
- 		return 0;
-+#ifdef NONE_CIPHER_ENABLED
-+        if (rekey_requested == 1) {
-+               rekey_requested = 0;
-+               return 1;
-+        }
-+#endif
- 
- 	/*
- 	 * Permit one packet in or out per rekey - this allows us to
---- a/packet.h	2016-02-26 04:40:04.000000000 +0100
-+++ b/packet.h	2016-03-01 04:32:19.000000000 +0100
-@@ -185,6 +185,11 @@ int	sshpkt_get_bignum2(struct ssh *ssh, 
- int	sshpkt_get_end(struct ssh *ssh);
- const u_char	*sshpkt_ptr(struct ssh *, size_t *lenp);
- 
-+#ifdef NONE_CIPHER_ENABLED
-+void  packet_request_rekeying(void);
-+int   ssh_packet_authentication_state(struct ssh *ssh);
-+#endif
-+
- /* OLD API */
- extern struct ssh *active_state;
- #include "opacket.h"
---- a/readconf.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/readconf.c	2016-03-01 04:32:19.000000000 +0100
-@@ -154,6 +154,12 @@ typedef enum {
- 	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
- 	oVisualHostKey,
- 	oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
-+#ifdef HPN_ENABLED
-+	oHPNDisabled, oHPNBufferSize, oTcpRcvBufPoll, oTcpRcvBuf,
-+#endif
-+#ifdef NONE_CIPHER_ENABLED
-+	oNoneSwitch, oNoneEnabled,
-+#endif
- 	oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
- 	oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
- 	oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
-@@ -280,6 +286,16 @@ static struct {
- 	{ "updatehostkeys", oUpdateHostkeys },
- 	{ "hostbasedkeytypes", oHostbasedKeyTypes },
- 	{ "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
-+#ifdef NONE_CIPHER_ENABLED
-+	{ "noneenabled", oNoneEnabled },
-+	{ "noneswitch", oNoneSwitch },
-+#endif
-+#ifdef HPN_ENABLED
-+	{ "tcprcvbufpoll", oTcpRcvBufPoll },
-+	{ "tcprcvbuf", oTcpRcvBuf },
-+	{ "hpndisabled", oHPNDisabled },
-+	{ "hpnbuffersize", oHPNBufferSize },
-+#endif
- 	{ "ignoreunknown", oIgnoreUnknown },
- 
- 	{ NULL, oBadOption }
-@@ -938,6 +954,44 @@ parse_time:
- 		intptr = &options->check_host_ip;
- 		goto parse_flag;
- 
-+#ifdef HPN_ENABLED
-+	case oHPNDisabled:
-+		intptr = &options->hpn_disabled;
-+		goto parse_flag;
-+
-+	case oHPNBufferSize:
-+		intptr = &options->hpn_buffer_size;
-+		goto parse_int;
-+
-+	case oTcpRcvBufPoll:
-+		intptr = &options->tcp_rcv_buf_poll;
-+		goto parse_flag;
-+
-+	case oTcpRcvBuf:
-+		intptr = &options->tcp_rcv_buf;
-+		goto parse_int;
-+#endif
-+
-+#ifdef NONE_CIPHER_ENABLED
-+        case oNoneEnabled:
-+                intptr = &options->none_enabled;
-+                goto parse_flag;
-+
-+        /* we check to see if the command comes from the */
-+        /* command line or not. If it does then enable it */
-+        /* otherwise fail. NONE should never be a default configuration */
-+        case oNoneSwitch:
-+                if(strcmp(filename,"command-line") == 0) {
-+                        intptr = &options->none_switch;
-+                        goto parse_flag;
-+                } else {
-+                        error("NoneSwitch is found in %.200s.\nYou may only use this configuration option from the command line", filename);
-+                        error("Continuing...");
-+                        debug("NoneSwitch directive found in %.200s.", filename);
-+                        return 0;
-+                }
-+#endif
-+
- 	case oVerifyHostKeyDNS:
- 		intptr = &options->verify_host_key_dns;
- 		multistate_ptr = multistate_yesnoask;
-@@ -1713,6 +1767,16 @@ initialize_options(Options * options)
- 	options->ip_qos_interactive = -1;
- 	options->ip_qos_bulk = -1;
- 	options->request_tty = -1;
-+#ifdef NONE_CIPHER_ENABLED
-+	options->none_switch = -1;
-+	options->none_enabled = -1;
-+#endif
-+#ifdef HPN_ENABLED
-+	options->hpn_disabled = -1;
-+	options->hpn_buffer_size = -1;
-+	options->tcp_rcv_buf_poll = -1;
-+	options->tcp_rcv_buf = -1;
-+#endif
- 	options->proxy_use_fdpass = -1;
- 	options->ignored_unknown = NULL;
- 	options->num_canonical_domains = 0;
-@@ -1867,6 +1931,35 @@ fill_default_options(Options * options)
- 		options->server_alive_interval = 0;
- 	if (options->server_alive_count_max == -1)
- 		options->server_alive_count_max = 3;
-+#ifdef NONE_CIPHER_ENABLED
-+	if (options->none_switch == -1)
-+		options->none_switch = 0;
-+	if (options->none_enabled == -1)
-+		options->none_enabled = 0;
-+#endif
-+#ifdef HPN_ENABLED
-+	if (options->hpn_disabled == -1)
-+		options->hpn_disabled = 0;
-+	if (options->hpn_buffer_size > -1) {
-+		/* if a user tries to set the size to 0 set it to 1KB */
-+		if (options->hpn_buffer_size == 0)
-+			options->hpn_buffer_size = 1;
-+		/* limit the buffer to 64MB */
-+		if (options->hpn_buffer_size > 64*1024) {
-+			options->hpn_buffer_size = 64*1024*1024;
-+			debug("User requested buffer larger than 64MB. Request"
-+			    " reverted to 64MB");
-+		} else
-+			options->hpn_buffer_size *= 1024;
-+		debug("hpn_buffer_size set to %d", options->hpn_buffer_size);
-+	}
-+	if (options->tcp_rcv_buf == 0)
-+		options->tcp_rcv_buf = 1;
-+	if (options->tcp_rcv_buf > -1)
-+		options->tcp_rcv_buf *=1024;
-+	if (options->tcp_rcv_buf_poll == -1)
-+		options->tcp_rcv_buf_poll = 1;
-+#endif
- 	if (options->control_master == -1)
- 		options->control_master = 0;
- 	if (options->control_persist == -1) {
---- a/readconf.h	2016-02-26 04:40:04.000000000 +0100
-+++ b/readconf.h	2016-03-01 04:32:19.000000000 +0100
-@@ -112,6 +112,16 @@ typedef struct {
- 	int	clear_forwardings;
- 
- 	int	enable_ssh_keysign;
-+#ifdef NONE_CIPHER_ENABLED
-+	int     none_switch;    /* Use none cipher */
-+	int     none_enabled;   /* Allow none to be used */
-+#endif
-+#ifdef HPN_ENABLED
-+	int     tcp_rcv_buf; /* user switch to set tcp recv buffer */
-+	int     tcp_rcv_buf_poll; /* Option to poll recv buf every window transfer */
-+	int     hpn_disabled;    /* Switch to disable HPN buffer management */
-+	int     hpn_buffer_size; /* User definable size for HPN buffer window */
-+#endif
- 	int64_t rekey_limit;
- 	int	rekey_interval;
- 	int	no_host_authentication_for_localhost;
---- a/scp.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/scp.c	2016-03-01 04:32:19.000000000 +0100
-@@ -760,7 +760,7 @@ source(int argc, char **argv)
- 	off_t i, statbytes;
- 	size_t amt, nr;
- 	int fd = -1, haderr, indx;
--	char *last, *name, buf[2048], encname[PATH_MAX];
-+	char *last, *name, buf[16384], encname[PATH_MAX];
- 	int len;
- 
- 	for (indx = 0; indx < argc; ++indx) {
-@@ -929,7 +929,7 @@ sink(int argc, char **argv)
- 	off_t size, statbytes;
- 	unsigned long long ull;
- 	int setimes, targisdir, wrerrno = 0;
--	char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
-+	char ch, *cp, *np, *targ, *why, *vect[1], buf[16384];
- 	struct timeval tv[2];
- 
- #define	atime	tv[0]
---- a/servconf.c	2016-03-01 04:32:13.000000000 +0100
-+++ b/servconf.c	2016-03-01 04:32:19.000000000 +0100
-@@ -165,6 +165,14 @@ initialize_server_options(ServerOptions 
- 	options->authorized_principals_file = NULL;
- 	options->authorized_principals_command = NULL;
- 	options->authorized_principals_command_user = NULL;
-+#ifdef NONE_CIPHER_ENABLED
-+	options->none_enabled = -1;
-+#endif
-+#ifdef HPN_ENABLED
-+	options->tcp_rcv_buf_poll = -1;
-+	options->hpn_disabled = -1;
-+	options->hpn_buffer_size = -1;
-+#endif
- 	options->ip_qos_interactive = -1;
- 	options->ip_qos_bulk = -1;
- 	options->version_addendum = NULL;
-@@ -341,6 +349,57 @@ fill_default_server_options(ServerOption
- 	}
- 	if (options->permit_tun == -1)
- 		options->permit_tun = SSH_TUNMODE_NO;
-+#ifdef NONE_CIPHER_ENABLED
-+	if (options->none_enabled == -1)
-+		options->none_enabled = 0;
-+#endif
-+#ifdef HPN_ENABLED
-+	if (options->hpn_disabled == -1)
-+		options->hpn_disabled = 0;
-+
-+	if (options->hpn_buffer_size == -1) {
-+		/*
-+		 * option not explicitly set. Now we have to figure out
-+		 * what value to use.
-+		 */
-+		if (options->hpn_disabled == 1) {
-+			options->hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT;
-+		} else {
-+			int sock, socksize;
-+			socklen_t socksizelen = sizeof(socksize);
-+
-+			/*
-+			 * get the current RCV size and set it to that
-+			 * create a socket but don't connect it
-+			 * we use that the get the rcv socket size
-+			 */
-+			sock = socket(AF_INET, SOCK_STREAM, 0);
-+			getsockopt(sock, SOL_SOCKET, SO_RCVBUF,
-+			    &socksize, &socksizelen);
-+			close(sock);
-+			options->hpn_buffer_size = socksize;
-+			debug ("HPN Buffer Size: %d", options->hpn_buffer_size);
-+		}
-+	} else {
-+		/*
-+		 * we have to do this incase the user sets both values in a
-+		 * contradictory manner. hpn_disabled overrrides
-+		 * hpn_buffer_size
-+		 */
-+		if (options->hpn_disabled <= 0) {
-+			if (options->hpn_buffer_size == 0)
-+				options->hpn_buffer_size = 1;
-+			/* limit the maximum buffer to 64MB */
-+			if (options->hpn_buffer_size > 64*1024) {
-+				options->hpn_buffer_size = 64*1024*1024;
-+			} else {
-+				options->hpn_buffer_size *= 1024;
-+			}
-+		} else
-+			options->hpn_buffer_size = CHAN_TCP_WINDOW_DEFAULT;
-+	}
-+#endif
-+
- 	if (options->ip_qos_interactive == -1)
- 		options->ip_qos_interactive = IPTOS_LOWDELAY;
- 	if (options->ip_qos_bulk == -1)
-@@ -425,6 +484,12 @@ typedef enum {
- 	sHostCertificate,
- 	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
- 	sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
-+#ifdef NONE_CIPHER_ENABLED
-+	sNoneEnabled,
-+#endif
-+#ifdef HPN_ENABLED
-+	sTcpRcvBufPoll, sHPNDisabled, sHPNBufferSize,
-+#endif
- 	sKexAlgorithms, sIPQoS, sVersionAddendum,
- 	sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
- 	sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
-@@ -560,6 +625,14 @@ static struct {
- 	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
- 	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
- 	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
-+#ifdef NONE_CIPHER_ENABLED
-+	{ "noneenabled", sNoneEnabled, SSHCFG_ALL },
-+#endif
-+#ifdef HPN_ENABLED
-+	{ "hpndisabled", sHPNDisabled, SSHCFG_ALL },
-+	{ "hpnbuffersize", sHPNBufferSize, SSHCFG_ALL },
-+	{ "tcprcvbufpoll", sTcpRcvBufPoll, SSHCFG_ALL },
-+#endif
- 	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
- 	{ "ipqos", sIPQoS, SSHCFG_ALL },
- 	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
-@@ -1180,6 +1253,25 @@ process_server_config_line(ServerOptions
- 		intptr = &options->ignore_user_known_hosts;
- 		goto parse_flag;
- 
-+#ifdef NONE_CIPHER_ENABLED
-+	case sNoneEnabled:
-+		intptr = &options->none_enabled;
-+		goto parse_flag;
-+#endif
-+#ifdef HPN_ENABLED
-+	case sTcpRcvBufPoll:
-+		intptr = &options->tcp_rcv_buf_poll;
-+		goto parse_flag;
-+
-+	case sHPNDisabled:
-+		intptr = &options->hpn_disabled;
-+		goto parse_flag;
-+
-+	case sHPNBufferSize:
-+		intptr = &options->hpn_buffer_size;
-+		goto parse_int;
-+#endif
-+
- 	case sRhostsRSAAuthentication:
- 		intptr = &options->rhosts_rsa_authentication;
- 		goto parse_flag;
---- a/servconf.h	2016-02-26 04:40:04.000000000 +0100
-+++ b/servconf.h	2016-03-01 04:32:19.000000000 +0100
-@@ -173,6 +173,15 @@ typedef struct {
- 
- 	int	use_pam;		/* Enable auth via PAM */
- 
-+#ifdef NONE_CIPHER_ENABLED
-+	int	none_enabled;		/* enable NONE cipher switch */
-+#endif
-+#ifdef HPN_ENABLED
-+	int     tcp_rcv_buf_poll;       /* poll tcp rcv window in autotuning kernels*/
-+	int	hpn_disabled;		/* disable hpn functionality. false by default */
-+	int	hpn_buffer_size;	/* set the hpn buffer size - default 3MB */
-+#endif
-+
- 	int	permit_tun;
- 
- 	int	num_permitted_opens;
---- a/serverloop.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/serverloop.c	2016-03-01 04:32:19.000000000 +0100
-@@ -1041,6 +1041,12 @@ server_request_tun(void)
- 	sock = tun_open(tun, mode);
- 	if (sock < 0)
- 		goto done;
-+#ifdef HPN_ENABLED
-+	if (!options.hpn_disabled)
-+		c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1,
-+		    options.hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
-+	else
-+#endif
- 	c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1,
- 	    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
- 	c->datagram = 1;
-@@ -1078,6 +1084,10 @@ server_request_session(void)
- 	c = channel_new("session", SSH_CHANNEL_LARVAL,
- 	    -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT,
- 	    0, "server-session", 1);
-+#ifdef HPN_ENABLED
-+	if (options.tcp_rcv_buf_poll && !options.hpn_disabled)
-+		c->dynamic_window = 1;
-+#endif
- 	if (session_open(the_authctxt, c->self) != 1) {
- 		debug("session open failed, free channel %d", c->self);
- 		channel_free(c);
---- a/session.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/session.c	2016-03-01 04:32:19.000000000 +0100
-@@ -2326,6 +2326,14 @@ session_set_fds(Session *s, int fdin, in
- 	 */
- 	if (s->chanid == -1)
- 		fatal("no channel for session %d", s->self);
-+#ifdef HPN_ENABLED
-+	if (!options.hpn_disabled)
-+		channel_set_fds(s->chanid,
-+		    fdout, fdin, fderr,
-+		    ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
-+		    1, is_tty, options.hpn_buffer_size);
-+	else
-+#endif
- 	channel_set_fds(s->chanid,
- 	    fdout, fdin, fderr,
- 	    ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
---- a/sftp.1	2016-02-26 04:40:04.000000000 +0100
-+++ b/sftp.1	2016-03-01 04:32:19.000000000 +0100
-@@ -264,7 +264,8 @@ diagnostic messages from
- Specify how many requests may be outstanding at any one time.
- Increasing this may slightly improve file transfer speed
- but will increase memory usage.
--The default is 64 outstanding requests.
-+The default is 256 outstanding requests providing for 8MB
-+of outstanding data with a 32KB buffer.
- .It Fl r
- Recursively copy entire directories when uploading and downloading.
- Note that
---- a/sftp.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/sftp.c	2016-03-01 04:32:19.000000000 +0100
-@@ -71,7 +71,11 @@ typedef void EditLine;
- #include "sftp-client.h"
- 
- #define DEFAULT_COPY_BUFLEN	32768	/* Size of buffer for up/download */
-+#ifdef HPN_ENABLED
-+#define DEFAULT_NUM_REQUESTS	256	/* # concurrent outstanding requests */
-+#else
- #define DEFAULT_NUM_REQUESTS	64	/* # concurrent outstanding requests */
-+#endif
- 
- /* File to read commands from */
- FILE* infile;
---- a/ssh.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/ssh.c	2016-03-01 04:32:19.000000000 +0100
-@@ -898,6 +898,14 @@ main(int ac, char **av)
- 			break;
- 		case 'T':
- 			options.request_tty = REQUEST_TTY_NO;
-+#ifdef NONE_CIPHER_ENABLED
-+			/*
-+			 * ensure that the user doesn't try to backdoor a
-+			 * null cipher switch on an interactive session
-+			 * so explicitly disable it no matter what.
-+			 */
-+			options.none_switch = 0;
-+#endif
- 			break;
- 		case 'o':
- 			line = xstrdup(optarg);
-@@ -1851,9 +1859,85 @@ ssh_session2_open(void)
- 	if (!isatty(err))
- 		set_nonblock(err);
- 
-+#ifdef HPN_ENABLED
-+	/*
-+	 * we need to check to see if what they want to do about buffer
-+	 * sizes here. In a hpn to nonhpn connection we want to limit
-+	 * the window size to something reasonable in case the far side
-+	 * has the large window bug. In hpn to hpn connection we want to
-+	 * use the max window size but allow the user to override it
-+	 * lastly if they disabled hpn then use the ssh std window size
-+
-+	 * so why don't we just do a getsockopt() here and set the
-+	 * ssh window to that? In the case of a autotuning receive
-+	 * window the window would get stuck at the initial buffer
-+	 * size generally less than 96k. Therefore we need to set the
-+	 * maximum ssh window size to the maximum hpn buffer size
-+	 * unless the user has specifically set the tcprcvbufpoll
-+	 * to no. In which case we *can* just set the window to the
-+	 * minimum of the hpn buffer size and tcp receive buffer size
-+	 */
-+
-+	if (tty_flag)
-+		options.hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT;
-+	else
-+		options.hpn_buffer_size = 2*1024*1024;
-+
-+	if (datafellows & SSH_BUG_LARGEWINDOW) {
-+		debug("HPN to Non-HPN Connection");
-+	} else {
-+		int sock, socksize;
-+		socklen_t socksizelen = sizeof(socksize);
-+
-+		if (options.tcp_rcv_buf_poll <= 0) {
-+			sock = socket(AF_INET, SOCK_STREAM, 0);
-+			getsockopt(sock, SOL_SOCKET, SO_RCVBUF,
-+			    &socksize, &socksizelen);
-+			close(sock);
-+			debug("socksize %d", socksize);
-+			options.hpn_buffer_size = socksize;
-+			debug ("HPNBufferSize set to TCP RWIN: %d",
-+			    options.hpn_buffer_size);
-+		} else {
-+			if (options.tcp_rcv_buf > 0) {
-+				/*
-+				 * create a socket but don't connect it.
-+				 * we use that the get the rcv socket size
-+				 */
-+				sock = socket(AF_INET, SOCK_STREAM, 0);
-+				/*
-+				 * if they are using the tcp_rcv_buf option
-+				 * attempt to set the buffer size to that
-+				 */
-+				if (options.tcp_rcv_buf)
-+					setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
-+					    (void *)&options.tcp_rcv_buf,
-+					    sizeof(options.tcp_rcv_buf));
-+				getsockopt(sock, SOL_SOCKET, SO_RCVBUF,
-+				    &socksize, &socksizelen);
-+				close(sock);
-+				debug("socksize %d", socksize);
-+				options.hpn_buffer_size = socksize;
-+				debug ("HPNBufferSize set to user TCPRcvBuf: "
-+				    "%d", options.hpn_buffer_size);
-+			}
-+		}
-+	}
-+
-+	debug("Final hpn_buffer_size = %d", options.hpn_buffer_size);
-+
-+	window = options.hpn_buffer_size;
-+
-+	channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size);
-+#else
- 	window = CHAN_SES_WINDOW_DEFAULT;
-+#endif
-+
- 	packetmax = CHAN_SES_PACKET_DEFAULT;
- 	if (tty_flag) {
-+#ifdef HPN_ENABLED
-+		window = CHAN_SES_WINDOW_DEFAULT;
-+#endif
- 		window >>= 1;
- 		packetmax >>= 1;
- 	}
-@@ -1862,6 +1946,12 @@ ssh_session2_open(void)
- 	    window, packetmax, CHAN_EXTENDED_WRITE,
- 	    "client-session", /*nonblock*/0);
- 
-+#ifdef HPN_ENABLED
-+	if (options.tcp_rcv_buf_poll > 0 && !options.hpn_disabled) {
-+		c->dynamic_window = 1;
-+		debug ("Enabled Dynamic Window Scaling");
-+	}
-+#endif
- 	debug3("ssh_session2_open: channel_new: %d", c->self);
- 
- 	channel_send_open(c->self);
---- a/sshconnect.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/sshconnect.c	2016-03-01 04:32:19.000000000 +0100
-@@ -267,6 +267,31 @@ ssh_kill_proxy_command(void)
- 		kill(proxy_command_pid, SIGHUP);
- }
- 
-+#ifdef HPN_ENABLED
-+/*
-+ * Set TCP receive buffer if requested.
-+ * Note: tuning needs to happen after the socket is
-+ * created but before the connection happens
-+ * so winscale is negotiated properly -cjr
-+ */
-+static void
-+ssh_set_socket_recvbuf(int sock)
-+{
-+	void *buf = (void *)&options.tcp_rcv_buf;
-+	int sz = sizeof(options.tcp_rcv_buf);
-+	int socksize;
-+	socklen_t socksizelen = sizeof(socksize);
-+
-+	debug("setsockopt Attempting to set SO_RCVBUF to %d", options.tcp_rcv_buf);
-+	if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, buf, sz) >= 0) {
-+	  getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &socksize, &socksizelen);
-+	  debug("setsockopt SO_RCVBUF: %.100s %d", strerror(errno), socksize);
-+	} else
-+		error("Couldn't set socket receive buffer to %d: %.100s",
-+		    options.tcp_rcv_buf, strerror(errno));
-+}
-+#endif
-+
- /*
-  * Creates a (possibly privileged) socket for use as the ssh connection.
-  */
-@@ -283,6 +308,11 @@ ssh_create_socket(int privileged, struct
- 	}
- 	fcntl(sock, F_SETFD, FD_CLOEXEC);
- 
-+#ifdef HPN_ENABLED
-+	if (options.tcp_rcv_buf > 0)
-+		ssh_set_socket_recvbuf(sock);
-+#endif
-+
- 	/* Bind the socket to an alternative local IP address */
- 	if (options.bind_address == NULL && !privileged)
- 		return sock;
-@@ -526,11 +556,23 @@ send_client_banner(int connection_out, i
- {
- 	/* Send our own protocol version identification. */
- 	if (compat20) {
--		xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n",
--		    PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION);
-+		xasprintf(&client_version_string, "SSH-%d.%d-%.100s%s\r\n",
-+		    PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION,
-+#ifdef HPN_ENABLED
-+		    options.hpn_disabled ? "" : SSH_HPN
-+#else
-+		    ""
-+#endif
-+		    );
- 	} else {
--		xasprintf(&client_version_string, "SSH-%d.%d-%.100s\n",
--		    PROTOCOL_MAJOR_1, minor1, SSH_VERSION);
-+		xasprintf(&client_version_string, "SSH-%d.%d-%.100s%s\n",
-+		    PROTOCOL_MAJOR_1, minor1, SSH_VERSION,
-+#ifdef HPN_ENABLED
-+		    options.hpn_disabled ? "" : SSH_HPN
-+#else
-+		    ""
-+#endif
-+		    );
- 	}
- 	if (atomicio(vwrite, connection_out, client_version_string,
- 	    strlen(client_version_string)) != strlen(client_version_string))
---- a/sshconnect2.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/sshconnect2.c	2016-03-01 04:32:19.000000000 +0100
-@@ -80,6 +80,14 @@
- extern char *client_version_string;
- extern char *server_version_string;
- extern Options options;
-+#ifdef NONE_CIPHER_ENABLED
-+struct kex *xxx_kex;
-+
-+/* tty_flag is set in ssh.c. use this in ssh_userauth2 */
-+/* if it is set then prevent the switch to the null cipher */
-+
-+extern int tty_flag;
-+#endif
- 
- /*
-  * SSH2 key exchange
-@@ -153,14 +161,17 @@ order_hostkeyalgs(char *host, struct soc
- 	return ret;
- }
- 
-+static char *myproposal[PROPOSAL_MAX];
-+static const char *myproposal_default[PROPOSAL_MAX] = { KEX_CLIENT };
- void
- ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
- {
--	char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
- 	char *s;
- 	struct kex *kex;
- 	int r;
- 
-+	memcpy(&myproposal, &myproposal_default, sizeof(myproposal));
-+
- 	xxx_host = host;
- 	xxx_hostaddr = hostaddr;
- 
-@@ -235,6 +246,9 @@ ssh_kex2(char *host, struct sockaddr *ho
- 	packet_send();
- 	packet_write_wait();
- #endif
-+#ifdef NONE_CIPHER_ENABLED
-+	xxx_kex = kex;
-+#endif
- }
- 
- /*
-@@ -404,6 +418,29 @@ ssh_userauth2(const char *local_user, co
- 	pubkey_cleanup(&authctxt);
- 	ssh_dispatch_range(ssh, SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL);
- 
-+#ifdef NONE_CIPHER_ENABLED
-+	/*
-+	 * if the user wants to use the none cipher do it
-+	 * post authentication and only if the right conditions are met
-+	 * both of the NONE commands must be true and there must be no
-+	 * tty allocated.
-+	 */
-+	if ((options.none_switch == 1) && (options.none_enabled == 1)) {
-+		if (!tty_flag) { /* no null on tty sessions */
-+			debug("Requesting none rekeying...");
-+			myproposal[PROPOSAL_ENC_ALGS_STOC] = "none";
-+			myproposal[PROPOSAL_ENC_ALGS_CTOS] = "none";
-+			kex_prop2buf(xxx_kex->my, myproposal);
-+			packet_request_rekeying();
-+			fprintf(stderr, "WARNING: ENABLED NONE CIPHER\n");
-+		} else {
-+			/* requested NONE cipher when in a tty */
-+			debug("Cannot switch to NONE cipher with tty allocated");
-+			fprintf(stderr, "NONE cipher switch disabled when a TTY is allocated\n");
-+		}
-+	}
-+#endif
-+
- 	debug("Authentication succeeded (%s).", authctxt.method->name);
- }
- 
---- a/sshd.c	2016-03-01 04:32:17.000000000 +0100
-+++ b/sshd.c	2016-03-01 04:32:19.000000000 +0100
-@@ -430,8 +430,13 @@ sshd_exchange_identification(int sock_in
- 		minor = PROTOCOL_MINOR_1;
- 	}
- 
--	xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s",
-+	xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s%s",
- 	    major, minor, SSH_VERSION,
-+#ifdef HPN_ENABLED
-+	    options.hpn_disabled ? "" : SSH_HPN,
-+#else
-+	    "",
-+#endif
- 	    *options.version_addendum == '\0' ? "" : " ",
- 	    options.version_addendum, newline);
- 
-@@ -1167,6 +1172,10 @@ server_listen(void)
- 	int ret, listen_sock, on = 1;
- 	struct addrinfo *ai;
- 	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
-+#ifdef HPN_ENABLED
-+	int socksize;
-+	socklen_t socksizelen = sizeof(socksize);
-+#endif
- 
- 	for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
- 		if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
-@@ -1207,6 +1216,13 @@ server_listen(void)
- 
- 		debug("Bind to port %s on %s.", strport, ntop);
- 
-+#ifdef HPN_ENABLED
-+		getsockopt(listen_sock, SOL_SOCKET, SO_RCVBUF,
-+				   &socksize, &socksizelen);
-+		debug("Server TCP RWIN socket size: %d", socksize);
-+		debug("HPN Buffer Size: %d", options.hpn_buffer_size);
-+#endif
-+
- 		/* Bind the socket to the desired port. */
- 		if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) {
- 			error("Bind to port %s on %s failed: %.200s.",
-@@ -1706,6 +1722,15 @@ main(int ac, char **av)
- 	/* Fill in default values for those options not explicitly set. */
- 	fill_default_server_options(&options);
- 
-+#ifdef NONE_CIPHER_ENABLED
-+	if (options.none_enabled == 1) {
-+		char *old_ciphers = options.ciphers;
-+
-+		xasprintf(&options.ciphers, "%s,none", old_ciphers);
-+		free(old_ciphers);
-+	}
-+#endif
-+
- 	/* challenge-response is implemented via keyboard interactive */
- 	if (options.challenge_response_authentication)
- 		options.kbd_interactive_authentication = 1;
-@@ -2136,6 +2161,11 @@ main(int ac, char **av)
- 		cleanup_exit(255);
- 	}
- 
-+#ifdef HPN_ENABLED
-+	/* set the HPN options for the child */
-+	channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size);
-+#endif
-+
- 	/*
- 	 * We use get_canonical_hostname with usedns = 0 instead of
- 	 * get_remote_ipaddr here so IP options will be checked.
-@@ -2554,6 +2584,12 @@ do_ssh2_kex(void)
- 	struct kex *kex;
- 	int r;
- 
-+#ifdef NONE_CIPHER_ENABLED
-+        if (options.none_enabled == 1) {
-+                debug ("WARNING: None cipher enabled");
-+        }
-+#endif
-+
- 	myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
- 	    options.kex_algorithms);
- 	myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(
---- a/sshd_config	2016-02-26 04:40:04.000000000 +0100
-+++ b/sshd_config	2016-03-01 04:32:19.000000000 +0100
-@@ -125,6 +125,20 @@ AuthorizedKeysFile	.ssh/authorized_keys
- # override default of no subsystems
- Subsystem	sftp	/usr/libexec/sftp-server
- 
-+# the following are HPN related configuration options
-+# tcp receive buffer polling. disable in non autotuning kernels
-+#TcpRcvBufPoll yes
-+
-+# disable hpn performance boosts
-+#HPNDisabled no
-+
-+# buffer size for hpn to non-hpn connections
-+#HPNBufferSize 2048
-+
-+
-+# allow the use of the none cipher
-+#NoneEnabled no
-+
- # Example of overriding settings on a per-user basis
- #Match User anoncvs
- #	X11Forwarding no
---- a/version.h	2016-02-26 04:40:04.000000000 +0100
-+++ b/version.h	2016-03-01 04:32:20.000000000 +0100
-@@ -4,3 +4,4 @@
- 
- #define SSH_PORTABLE	"p1"
- #define SSH_RELEASE	SSH_VERSION SSH_PORTABLE
-+#define SSH_HPN         "-hpn14v5"

Copied: trunk/dports/net/openssh/files/openssh-7.3p1-gsskex-all-20141021-mp-20160929.patch (from rev 153358, trunk/dports/net/openssh/files/openssh-7.2p1-gsskex-all-20141021-mp-20160301.patch)
===================================================================
--- trunk/dports/net/openssh/files/openssh-7.3p1-gsskex-all-20141021-mp-20160929.patch	                        (rev 0)
+++ trunk/dports/net/openssh/files/openssh-7.3p1-gsskex-all-20141021-mp-20160929.patch	2016-09-29 13:49:14 UTC (rev 153360)
@@ -0,0 +1,3267 @@
+From 1c1b6fa17982eb622e2c4e8f4a279f2113f57413 Mon Sep 17 00:00:00 2001
+From: Simon Wilkinson <simon at sxw.org.uk>
+Date: Sun, 9 Feb 2014 16:09:48 +0000
+Subject: GSSAPI key exchange support
+
+This patch has been rejected upstream: "None of the OpenSSH developers are
+in favour of adding this, and this situation has not changed for several
+years.  This is not a slight on Simon's patch, which is of fine quality, but
+just that a) we don't trust GSSAPI implementations that much and b) we don't
+like adding new KEX since they are pre-auth attack surface.  This one is
+particularly scary, since it requires hooks out to typically root-owned
+system resources."
+
+However, quite a lot of people rely on this in Debian, and it's better to
+have it merged into the main openssh package rather than having separate
+-krb5 packages (as we used to have).  It seems to have a generally good
+security history.
+
+Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242
+Last-Updated: 2014-10-07
+
+Patch-Name: gssapi.patch
+
+
+Updated by: Mihai Moldovan <ionic at macports.org>
+Patch-Name: openssh-6.7p1-gsskex-all-20141021-284f364.patch
+Abstract: Updated for OpenSSH 7.3p1 with MacPorts patches for integration
+          with Apple's launchd, pam, sandbox and KeyChain.
+          WARNING: the commit ID does NOT match this patch. It is merely
+                   provided for reference.
+Last-Updated: 2016-09-29
+X-Ref: http://pkgs.fedoraproject.org/cgit/rpms/openssh.git/tree/openssh-7.2p1-gsskex.patch?id=13073f8d9ccec27646453f729aaa2952ae86ad01
+X-Ref: http://sources.debian.net/data/main/o/openssh/1:7.1p2-2/debian/patches/gssapi.patch (N.B.: original patch still references 7.1p2 - no newer version available currently)
+---
+ ChangeLog.gssapi | 113 +++++++++++++++++++
+ Makefile.in      |   3 +-
+ auth-krb5.c      |  17 ++-
+ auth2-gss.c      |  48 +++++++-
+ auth2.c          |   2 +
+ clientloop.c     |  13 +++
+ config.h.in      |   6 +
+ configure        |  57 ++++++++++
+ configure.ac     |  24 ++++
+ gss-genr.c       | 275 ++++++++++++++++++++++++++++++++++++++++++++-
+ gss-serv-krb5.c  |  85 ++++++++++++--
+ gss-serv.c       | 221 +++++++++++++++++++++++++++++++-----
+ kex.c            |  16 +++
+ kex.h            |  14 +++
+ kexgssc.c        | 332 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ kexgsss.c        | 290 ++++++++++++++++++++++++++++++++++++++++++++++++
+ monitor.c        | 108 +++++++++++++++++-
+ monitor.h        |   3 +
+ monitor_wrap.c   |  47 +++++++-
+ monitor_wrap.h   |   4 +-
+ readconf.c       |  42 +++++++
+ readconf.h       |   5 +
+ servconf.c       |  38 ++++++-
+ servconf.h       |   3 +
+ ssh-gss.h        |  41 ++++++-
+ ssh_config       |   2 +
+ ssh_config.5     |  34 +++++-
+ sshconnect2.c    | 124 ++++++++++++++++++++-
+ sshd.c           | 110 ++++++++++++++++++
+ sshd_config      |   2 +
+ sshd_config.5    |  28 +++++
+ sshkey.c         |   3 +-
+ sshkey.h         |   1 +
+ 33 files changed, 2052 insertions(+), 59 deletions(-)
+ create mode 100644 ChangeLog.gssapi
+ create mode 100644 kexgssc.c
+ create mode 100644 kexgsss.c
+
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ b/ChangeLog.gssapi	2016-09-29 14:45:14.000000000 +0200
+@@ -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>
+--- a/Makefile.in	2016-09-29 14:45:14.000000000 +0200
++++ b/Makefile.in	2016-09-29 14:45:14.000000000 +0200
+@@ -93,10 +93,10 @@ 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 \
+-	platform-pledge.o platform-tracing.o
++	platform-pledge.o platform-tracing.o kexgssc.o
+ 
+ SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
+-	sshconnect.o sshconnect1.o sshconnect2.o mux.o
++	sshconnect.o sshconnect1.o sshconnect2.o mux.o auth-compat.o
+ 
+ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
+ 	audit.o audit-bsm.o audit-linux.o platform.o \
+@@ -106,7 +106,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw
+ 	auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \
+ 	auth2-none.o auth2-passwd.o auth2-pubkey.o \
+ 	monitor_mm.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 \
+--- a/auth-krb5.c	2016-07-28 00:54:27.000000000 +0200
++++ b/auth-krb5.c	2016-09-29 14:45:14.000000000 +0200
+@@ -182,8 +182,13 @@ auth_krb5_password(Authctxt *authctxt, c
+ 
+ 	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_c
+ 		return oerrno;
+ 	}
+ 	close(tmpfd);
++#endif
+ 
+ 	return (krb5_cc_resolve(ctx, ccname, ccache));
+ }
+--- a/auth2-gss.c	2016-07-28 00:54:27.000000000 +0200
++++ b/auth2-gss.c	2016-09-29 14:45:14.000000000 +0200
+@@ -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
+@@ -54,6 +54,40 @@ static int input_gssapi_exchange_complet
+ 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,
+ 
+ 	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 ple
+ 	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 ple
+ 	return 0;
+ }
+ 
++Authmethod method_gsskeyex = {
++	"gssapi-keyex",
++	userauth_gsskeyex,
++	&options.gss_authentication
++};
++
+ Authmethod method_gssapi = {
+ 	"gssapi-with-mic",
+ 	userauth_gssapi,
+--- a/auth2.c	2016-07-28 00:54:27.000000000 +0200
++++ b/auth2.c	2016-09-29 14:45:14.000000000 +0200
+@@ -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,
+--- a/clientloop.c	2016-09-29 14:45:14.000000000 +0200
++++ b/clientloop.c	2016-09-29 14:45:14.000000000 +0200
+@@ -114,6 +114,10 @@
+ #include "ssherr.h"
+ #include "hostfile.h"
+ 
++#ifdef GSSAPI
++#include "ssh-gss.h"
++#endif
++
+ /* import options */
+ extern Options options;
+ 
+@@ -1701,9 +1705,18 @@ client_loop(int have_pty, int escape_cha
+ 			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(GSS_C_NO_CONTEXT)) {
++				debug("credentials updated - forcing rekey");
++				need_rekeying = 1;
++			}
++#endif
++		}
++
+ 		/* Buffer input from the connection.  */
+ 		client_process_net_input(readset);
+ 
+--- a/config.h.in	2016-09-29 14:45:14.000000000 +0200
++++ b/config.h.in	2016-09-29 14:45:14.000000000 +0200
+@@ -1680,6 +1680,9 @@
+ /* Use btmp to log bad logins */
+ #undef USE_BTMP
+ 
++/* platform uses an in-memory credentials cache */
++#undef USE_CCAPI
++
+ /* Use libedit for sftp */
+ #undef USE_LIBEDIT
+ 
+@@ -1698,6 +1701,9 @@
+ /* Define if you have Solaris privileges */
+ #undef USE_SOLARIS_PRIVS
+ 
++/* platform has the Security Authorization Session API */
++#undef USE_SECURITY_SESSION_API
++
+ /* Define if you have Solaris process contracts */
+ #undef USE_SOLARIS_PROCESS_CONTRACTS
+ 
+--- a/configure.ac	2016-09-29 14:45:14.000000000 +0200
++++ b/configure.ac	2016-09-29 14:45:14.000000000 +0200
+@@ -632,6 +632,30 @@ main() { if (NSVersionOfRunTimeLibrary("
+ 	    [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])
+--- a/gss-genr.c	2016-07-28 00:54:27.000000000 +0200
++++ b/gss-genr.c	2016-09-29 14:45:14.000000000 +0200
+@@ -1,7 +1,7 @@
+ /* $OpenBSD: gss-genr.c,v 1.23 2015/01/20 23:14:00 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
+@@ -41,12 +41,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)
+@@ -199,7 +354,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int de
+ 	}
+ 
+ 	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);
+ 
+@@ -229,8 +384,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, con
+ }
+ 
+ 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);
+@@ -238,6 +427,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer
+ 	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)
+@@ -251,11 +453,16 @@ ssh_gssapi_buildmic(Buffer *b, const cha
+ }
+ 
+ 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 && 
+@@ -265,6 +472,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx
+ 	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);
+@@ -274,10 +485,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx
+ 			    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 */
+--- a/gss-serv-krb5.c	2016-07-28 00:54:27.000000000 +0200
++++ b/gss-serv-krb5.c	2016-09-29 14:45:14.000000000 +0200
+@@ -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_cl
+ 	krb5_error_code problem;
+ 	krb5_principal princ;
+ 	OM_uint32 maj_status, min_status;
+-	int len;
+ 	const char *errmsg;
++	const char *new_ccname, *new_cctype;
+ 
+ 	if (client->creds == NULL) {
+ 		debug("No credentials stored");
+@@ -181,11 +181,26 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
+ 		return;
+ 	}
+ 
+-	client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache));
++	new_cctype = krb5_cc_get_type(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
++	if (new_ccname[0] == ':')
++		new_ccname++;
++	xasprintf(&client->store.envval, "%s:%s", new_cctype, new_ccname);
++	if (strcmp(new_cctype, "DIR") == 0) {
++		char *p;
++		p = strrchr(client->store.envval, '/');
++		if (p)
++			*p = '\0';
++	}
++	if ((strcmp(new_cctype, "FILE") == 0) || (strcmp(new_cctype, "DIR") == 0))
++		client->store.filename = xstrdup(new_ccname);
++#endif
+ 
+ #ifdef USE_PAM
+ 	if (options.use_pam)
+@@ -194,9 +209,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
+ 
+ 	krb5_cc_close(krb_context, ccache);
+ 
++	client->store.data = krb_context;
++
+ 	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;
++}
++
+ ssh_gssapi_mech gssapi_kerberos_mech = {
+ 	"toWM5Slw5Ew8Mqkay+al2g==",
+ 	"Kerberos",
+@@ -204,7 +286,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = {
+ 	NULL,
+ 	&ssh_gssapi_krb5_userok,
+ 	NULL,
+-	&ssh_gssapi_krb5_storecreds
++	&ssh_gssapi_krb5_storecreds,
++	&ssh_gssapi_krb5_updatecreds
+ };
+ 
+ #endif /* KRB5 */
+--- a/gss-serv.c	2016-07-28 00:54:27.000000000 +0200
++++ b/gss-serv.c	2016-09-29 14:45:14.000000000 +0200
+@@ -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,20 @@
+ #include "session.h"
+ #include "misc.h"
+ #include "servconf.h"
++#include "uidswap.h"
+ 
+ #include "ssh-gss.h"
++#include "monitor_wrap.h"
+ 
+ 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 +145,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss
+ }
+ 
+ /* Unprivileged */
++char *
++ssh_gssapi_server_mechanisms(void) {
++	gss_OID_set	supported;
++
++	ssh_gssapi_supported_oids(&supported);
++	return (ssh_gssapi_kex_mechs(supported, &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 +177,9 @@ ssh_gssapi_supported_oids(gss_OID_set *o
+ 	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 +305,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;
++		}
++
++		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);
++		}
+ 
+-	gss_buffer_desc ename;
++		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 +361,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
+ 	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 +385,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
+ 		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;
+@@ -320,11 +397,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
+ void
+ ssh_gssapi_cleanup_creds(void)
+ {
+-	if (gssapi_client.store.filename != NULL) {
+-		/* Unlink probably isn't sufficient */
+-		debug("removing gssapi cred file\"%s\"",
+-		    gssapi_client.store.filename);
+-		unlink(gssapi_client.store.filename);
++	krb5_ccache ccache = NULL;
++	krb5_error_code problem;
++
++	if (gssapi_client.store.data != NULL) {
++		if ((problem = krb5_cc_resolve(gssapi_client.store.data, gssapi_client.store.envval, &ccache))) {
++			debug("%s: krb5_cc_resolve(): %.100s", __func__,
++				krb5_get_err_text(gssapi_client.store.data, problem));
++		} else if ((problem = krb5_cc_destroy(gssapi_client.store.data, ccache))) {
++			debug("%s: krb5_cc_resolve(): %.100s", __func__,
++				krb5_get_err_text(gssapi_client.store.data, problem));
++		} else {
++			krb5_free_context(gssapi_client.store.data);
++			gssapi_client.store.data = NULL;
++		}
+ 	}
+ }
+ 
+@@ -357,7 +443,7 @@ ssh_gssapi_do_child(char ***envp, u_int 
+ 
+ /* Privileged */
+ int
+-ssh_gssapi_userok(char *user)
++ssh_gssapi_userok(char *user, struct passwd *pw)
+ {
+ 	OM_uint32 lmin;
+ 
+@@ -367,9 +453,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);
+@@ -383,14 +471,90 @@ 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) {
++	int ok = 0;
++
++	/* Check we've got credentials to store */
++	if (!gssapi_client.updated)
++		return 0;
++
++	gssapi_client.updated = 0;
++
++	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
+--- a/kex.c	2016-07-28 00:54:27.000000000 +0200
++++ b/kex.c	2016-09-29 14:45:14.000000000 +0200
+@@ -55,6 +55,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,12 @@ kex_alg_by_name(const char *name)
+ 		if (strcmp(k->name, name) == 0)
+ 			return k;
+ 	}
++#ifdef GSSAPI
++	for (k = kexalg_prefixes; k->name != NULL; k++) {
++		if (strncmp(k->name, name, strlen(k->name)) == 0)
++			return k;
++	}
++#endif
+ 	return NULL;
+ }
+ 
+@@ -587,6 +605,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
+ 	free(kex->client_version_string);
+ 	free(kex->server_version_string);
+ 	free(kex->failed_choice);
+--- a/kex.h	2016-07-28 00:54:27.000000000 +0200
++++ b/kex.h	2016-09-29 14:45:14.000000000 +0200
+@@ -98,6 +98,11 @@ enum kex_exchange {
+ 	KEX_DH_GEX_SHA256,
+ 	KEX_ECDH_SHA2,
+ 	KEX_C25519_SHA256,
++#ifdef GSSAPI
++	KEX_GSS_GRP1_SHA1,
++	KEX_GSS_GRP14_SHA1,
++	KEX_GSS_GEX_SHA1,
++#endif
+ 	KEX_MAX
+ };
+ 
+@@ -146,6 +151,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;
+@@ -196,6 +207,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 *);
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ b/kexgssc.c	2016-09-29 14:45:14.000000000 +0200
+@@ -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 "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) {
++	struct kex *kex = ssh->kex;
++	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;
++	char *lang;
++	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, kex->name, kex->kex_type)
++	    == GSS_C_NO_OID)
++		fatal("Couldn't identify host exchange");
++
++	if (ssh_gssapi_import_name(ctxt, kex->gss_host))
++		fatal("Couldn't import hostname");
++
++	if (kex->gss_client &&
++	    ssh_gssapi_client_identity(ctxt, kex->gss_client))
++		fatal("Couldn't acquire client credentials");
++
++	switch (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(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__, kex->kex_type);
++	}
++
++	/* Step 1 - e is dh->pub_key */
++	dh_gen_key(dh, 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,
++		    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);
++				lang = packet_get_string(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 ((int)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 (kex->kex_type) {
++	case KEX_GSS_GRP1_SHA1:
++	case KEX_GSS_GRP14_SHA1:
++		kex_dh_hash(kex->hash_alg, kex->client_version_string,
++		    kex->server_version_string,
++		    buffer_ptr(kex->my), buffer_len(kex->my),
++		    buffer_ptr(kex->peer), buffer_len(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(
++		    kex->hash_alg,
++		    kex->client_version_string,
++		    kex->server_version_string,
++		    buffer_ptr(kex->my), buffer_len(kex->my),
++		    buffer_ptr(kex->peer), buffer_len(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__, 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);
++	if (serverhostkey)
++		free(serverhostkey);
++	BN_clear_free(dh_server_pub);
++
++	/* save session id */
++	if (kex->session_id == NULL) {
++		kex->session_id_len = hashlen;
++		kex->session_id = xmalloc(kex->session_id_len);
++		memcpy(kex->session_id, hash, kex->session_id_len);
++	}
++
++	if (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 */
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ b/kexgsss.c	2016-09-29 14:45:14.000000000 +0200
+@@ -0,0 +1,302 @@
++/*
++ * 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 <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 "ssh-gss.h"
++#include "digest.h"
++
++extern ServerOptions options;
++
++int
++kexgss_server(struct ssh *ssh)
++{
++	struct kex *kex = ssh->kex;
++	int r = 0;
++
++	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;
++	int cmin = -1, cmax = -1; /* client proposal */
++	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()) {
++		if ((mechs = ssh_gssapi_server_mechanisms())) {
++			free(mechs);
++		}
++	}
++
++	debug2("%s: Identifying %s", __func__, kex->name);
++	oid = ssh_gssapi_id_kex(NULL, kex->name, 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 (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);
++		/* store client proposal to provide valid signature */
++		cmin = packet_get_int();
++		nbits = packet_get_int();
++		cmax = packet_get_int();
++		min = MAX(DH_GRP_MIN, cmin);
++		max = MIN(DH_GRP_MAX, cmax);
++		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(min, nbits, 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__, kex->kex_type);
++	}
++
++	dh_gen_key(dh, 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 ((int)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 (kex->kex_type) {
++	case KEX_GSS_GRP1_SHA1:
++	case KEX_GSS_GRP14_SHA1:
++		kex_dh_hash(kex->hash_alg,
++		    kex->client_version_string, kex->server_version_string,
++		    buffer_ptr(kex->peer), buffer_len(kex->peer),
++		    buffer_ptr(kex->my), buffer_len(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(
++		    kex->hash_alg,
++		    kex->client_version_string, kex->server_version_string,
++		    buffer_ptr(kex->peer), buffer_len(kex->peer),
++		    buffer_ptr(kex->my), buffer_len(kex->my),
++		    NULL, 0,
++		    cmin, nbits, cmax,
++		    dh->p, dh->g,
++		    dh_client_pub,
++		    dh->pub_key,
++		    shared_secret,
++		    hash, &hashlen
++		);
++		break;
++	default:
++		fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
++	}
++
++	BN_clear_free(dh_client_pub);
++
++	if (kex->session_id == NULL) {
++		kex->session_id_len = hashlen;
++		kex->session_id = xmalloc(kex->session_id_len);
++		memcpy(kex->session_id, hash, 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);
++	r = 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 r;
++}
++#endif /* GSSAPI */
+--- a/monitor.c	2016-07-28 00:54:27.000000000 +0200
++++ b/monitor.c	2016-09-29 14:45:14.000000000 +0200
+@@ -158,6 +158,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
+@@ -235,11 +237,18 @@ struct mon_table mon_dispatch_proto20[] 
+     {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
+     {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
+     {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, 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
+@@ -354,6 +363,10 @@ monitor_child_preauth(Authctxt *_authctx
+ 		/* 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
+ 	} else {
+ 		mon_dispatch = mon_dispatch_proto15;
+ 
+@@ -462,6 +475,10 @@ monitor_child_postauth(struct monitor *p
+ 		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		
+ 	} else {
+ 		mon_dispatch = mon_dispatch_postauth15;
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
+@@ -1876,6 +1893,13 @@ monitor_apply_keystate(struct monitor *p
+ # 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;
+@@ -1975,6 +1999,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer
+ 	OM_uint32 major;
+ 	u_int len;
+ 
++	if (!options.gss_authentication && !options.gss_keyex)
++		fatal("In GSSAPI monitor when GSSAPI is disabled");
++
+ 	goid.elements = buffer_get_string(m, &len);
+ 	goid.length = len;
+ 
+@@ -2002,6 +2029,9 @@ mm_answer_gss_accept_ctx(int sock, Buffe
+ 	OM_uint32 flags = 0; /* GSI needs this */
+ 	u_int len;
+ 
++	if (!options.gss_authentication && !options.gss_keyex)
++		fatal("In GSSAPI monitor when GSSAPI is disabled");
++
+ 	in.value = buffer_get_string(m, &len);
+ 	in.length = len;
+ 	major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
+@@ -2019,6 +2049,7 @@ mm_answer_gss_accept_ctx(int sock, Buffe
+ 		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);
+ }
+@@ -2030,6 +2061,9 @@ mm_answer_gss_checkmic(int sock, Buffer 
+ 	OM_uint32 ret;
+ 	u_int len;
+ 
++	if (!options.gss_authentication && !options.gss_keyex)
++		fatal("In GSSAPI monitor when GSSAPI is disabled");
++
+ 	gssbuf.value = buffer_get_string(m, &len);
+ 	gssbuf.length = len;
+ 	mic.value = buffer_get_string(m, &len);
+@@ -2056,7 +2090,11 @@ mm_answer_gss_userok(int sock, Buffer *m
+ {
+ 	int authenticated;
+ 
+-	authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
++	if (!options.gss_authentication && !options.gss_keyex)
++		fatal("In GSSAPI monitor when GSSAPI is disabled");
++
++	authenticated = authctxt->valid && 
++	    ssh_gssapi_userok(authctxt->user, authctxt->pw);
+ 
+ 	buffer_clear(m);
+ 	buffer_put_int(m, authenticated);
+@@ -2069,5 +2107,73 @@ 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("In GSSAPI monitor when GSSAPI is disabled");
++
++	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;
++
++	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 */
+ 
+--- a/monitor.h	2016-07-28 00:54:27.000000000 +0200
++++ b/monitor.h	2016-09-29 14:45:14.000000000 +0200
+@@ -65,6 +65,9 @@ enum monitor_reqtype {
+ 	MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
+ 	MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
+ 
++	MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151,
++	MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153,
++
+ };
+ 
+ struct mm_master;
+--- a/monitor_wrap.c	2016-07-28 00:54:27.000000000 +0200
++++ b/monitor_wrap.c	2016-09-29 14:45:14.000000000 +0200
+@@ -1073,7 +1073,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss
+ }
+ 
+ int
+-mm_ssh_gssapi_userok(char *user)
++mm_ssh_gssapi_userok(char *user, struct passwd *pw)
+ {
+ 	Buffer m;
+ 	int authenticated = 0;
+@@ -1090,5 +1090,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 */
+ 
+--- a/monitor_wrap.h	2016-07-28 00:54:27.000000000 +0200
++++ b/monitor_wrap.h	2016-09-29 14:45:14.000000000 +0200
+@@ -60,8 +60,10 @@ BIGNUM *mm_auth_rsa_generate_challenge(K
+ 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
+--- a/readconf.c	2016-09-29 14:45:14.000000000 +0200
++++ b/readconf.c	2016-09-29 14:45:14.000000000 +0200
+@@ -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 },
+@@ -968,10 +979,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;
+@@ -1789,7 +1820,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;
+@@ -1936,8 +1972,14 @@ fill_default_options(Options * options)
+ 		options->challenge_response_authentication = 1;
+ 	if (options->gss_authentication == -1)
+ 		options->gss_authentication = 0;
++	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)
+--- a/readconf.h	2016-09-29 14:45:14.000000000 +0200
++++ b/readconf.h	2016-09-29 14:45:14.000000000 +0200
+@@ -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. */
+--- a/servconf.c	2016-09-29 14:45:14.000000000 +0200
++++ b/servconf.c	2016-09-29 14:45:14.000000000 +0200
+@@ -117,8 +117,10 @@ initialize_server_options(ServerOptions 
+ 	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;
+@@ -287,10 +289,14 @@ fill_default_server_options(ServerOption
+ 		options->kerberos_get_afs_token = 0;
+ 	if (options->gss_authentication == -1)
+ 		options->gss_authentication = 0;
++	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 = 0;
+ 	if (options->kbd_interactive_authentication == -1)
+@@ -427,6 +433,7 @@ typedef enum {
+ 	sHostKeyAlgorithms,
+ 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
+ 	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
++	sGssKeyEx, sGssStoreRekey,
+ 	sAcceptEnv, sPermitTunnel,
+ 	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
+ 	sUsePrivilegeSeparation, sAllowAgentForwarding,
+@@ -501,11 +508,17 @@ static struct {
+ 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
+ 	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
+ 	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
++	{ "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
++	{ "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
+ #else
+ 	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
+ 	{ "gssapicleanupcredentials", 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 },
+@@ -1251,6 +1264,10 @@ process_server_config_line(ServerOptions
+ 		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;
+@@ -1259,6 +1276,10 @@ process_server_config_line(ServerOptions
+ 		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;
+@@ -2308,7 +2329,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,
+--- a/servconf.h	2016-07-28 00:54:27.000000000 +0200
++++ b/servconf.h	2016-09-29 14:45:14.000000000 +0200
+@@ -118,8 +118,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 */
+--- a/ssh-gss.h	2016-07-28 00:54:27.000000000 +0200
++++ b/ssh-gss.h	2016-09-29 14:45:14.000000000 +0200
+@@ -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 */
+--- a/ssh_config	2016-07-28 00:54:27.000000000 +0200
++++ b/ssh_config	2016-09-29 14:45:14.000000000 +0200
+@@ -26,6 +26,8 @@
+ #   HostbasedAuthentication no
+ #   GSSAPIAuthentication no
+ #   GSSAPIDelegateCredentials no
++#   GSSAPIKeyExchange no
++#   GSSAPITrustDNS no
+ #   BatchMode no
+ #   CheckHostIP yes
+ #   AddressFamily any
+--- a/ssh_config.5	2016-07-28 00:54:27.000000000 +0200
++++ b/ssh_config.5	2016-09-29 14:45:14.000000000 +0200
+@@ -826,10 +826,43 @@ The default is
+ Specifies whether user authentication based on GSSAPI is allowed.
+ The default is
+ .Dq no .
++.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
++.Dq no .
++Note that this option applies to protocol version 2 only.
++.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
+ .Dq no .
++Note that this option applies to protocol version 2 connections using GSSAPI.
++.It Cm GSSAPIRenewalForcesRekey
++If set to 
++.Dq 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
++.Dq no .
++.It Cm GSSAPITrustDns
++Set to 
++.Dq yes to indicate that the DNS is trusted to securely canonicalize
++the name of the host being connected to. If 
++.Dq no, the hostname entered on the
++command line will be passed untouched to the GSSAPI library.
++The default is
++.Dq no .
++This option only applies to protocol version 2 connections using GSSAPI.
+ .It Cm HashKnownHosts
+ Indicates that
+ .Xr ssh 1
+--- a/sshconnect2.c	2016-09-29 14:45:14.000000000 +0200
++++ b/sshconnect2.c	2016-09-29 14:45:14.000000000 +0200
+@@ -73,6 +73,7 @@
+ #include "ssherr.h"
+ #include "utf8.h"
+ #include "keychain.h"
++#include "auth-compat.h"
+ 
+ #ifdef GSSAPI
+ #include "ssh-gss.h"
+@@ -163,6 +164,11 @@ ssh_kex2(char *host, struct sockaddr *ho
+ 	struct kex *kex;
+ 	int r;
+ 
++#ifdef GSSAPI
++	char *orig = NULL, *gss = NULL;
++	char *gss_host = NULL;
++#endif
++
+ 	xxx_host = host;
+ 	xxx_hostaddr = hostaddr;
+ 
+@@ -193,6 +199,35 @@ ssh_kex2(char *host, struct sockaddr *ho
+ 		    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);
++		if (options.gss_trust_dns)
++			gss_host = xstrdup(get_canonical_hostname(active_state, 1));
++		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);
++			free(gss);
++		}
++	}
++#endif
++
+ 	if (options.rekey_limit || options.rekey_interval)
+ 		packet_set_rekey_limits((u_int32_t)options.rekey_limit,
+ 		    (time_t)options.rekey_interval);
+@@ -214,10 +249,26 @@ ssh_kex2(char *host, struct sockaddr *ho
+ # 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 */
+@@ -312,6 +363,7 @@ int	input_gssapi_token(int type, u_int32
+ 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 *);
+@@ -327,6 +379,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,
+@@ -651,25 +708,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 = xstrdup(get_canonical_hostname(active_state, 1));
++	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;
+ 
+@@ -760,8 +832,8 @@ input_gssapi_response(int type, u_int32_
+ {
+ 	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");
+@@ -874,6 +946,48 @@ input_gssapi_error(int type, u_int32_t p
+ 	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
+--- a/sshd.c	2016-09-29 14:45:14.000000000 +0200
++++ b/sshd.c	2016-09-29 14:45:14.000000000 +0200
+@@ -125,6 +125,10 @@
+ #include "version.h"
+ #include "ssherr.h"
+ 
++#ifdef USE_SECURITY_SESSION_API
++#include <Security/AuthSession.h>
++#endif
++
+ #ifndef O_NOCTTY
+ #define O_NOCTTY	0
+ #endif
+@@ -980,8 +984,9 @@ notify_hostkeys(struct ssh *ssh)
+ 	}
+ 	debug3("%s: sent %d hostkeys", __func__, nkeys);
+ 	if (nkeys == 0)
+-		fatal("%s: no hostkeys", __func__);
+-	packet_send();
++		debug3("%s: no hostkeys", __func__);
++	else
++		packet_send();
+ 	sshbuf_free(buf);
+ }
+ 
+@@ -1899,10 +1904,13 @@ main(int ac, char **av)
+ 		logit("Disabling protocol version 1. Could not load host key");
+ 		options.protocol &= ~SSH_PROTO_1;
+ 	}
++#ifndef GSSAPI
++	/* The GSSAPI key exchange can run without a host key */
+ 	if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
+ 		logit("Disabling protocol version 2. Could not load host key");
+ 		options.protocol &= ~SSH_PROTO_2;
+ 	}
++#endif
+ 	if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
+ 		logit("sshd: no hostkeys available -- exiting.");
+ 		exit(1);
+@@ -2214,6 +2222,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
+@@ -2638,6 +2700,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));
+@@ -2655,6 +2759,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;
+--- a/sshd_config	2016-09-29 14:45:14.000000000 +0200
++++ b/sshd_config	2016-09-29 14:45:14.000000000 +0200
+@@ -84,6 +84,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
+--- a/sshd_config.5	2016-09-29 14:45:14.000000000 +0200
++++ b/sshd_config.5	2016-09-29 14:45:14.000000000 +0200
+@@ -632,6 +632,12 @@ The default is
+ Specifies whether user authentication based on GSSAPI is allowed.
+ The default is
+ .Dq no .
++.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
++.Dq no .
++Note that this option applies to protocol version 2 only.
+ .It Cm GSSAPICleanupCredentials
+ Specifies whether to automatically destroy the user's credentials cache
+ on logout.
+@@ -652,6 +658,11 @@ machine's default store.
+ This facility is provided to assist with operation on multi homed machines.
+ The default is
+ .Dq 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
++.Dq no .
+ .It Cm HostbasedAcceptedKeyTypes
+ Specifies the key types that will be accepted for hostbased authentication
+ as a comma-separated pattern list.
+--- a/sshkey.c	2016-07-28 00:54:27.000000000 +0200
++++ b/sshkey.c	2016-09-29 14:45:14.000000000 +0200
+@@ -115,6 +115,7 @@ static const struct keytype keytypes[] =
+ #  endif /* OPENSSL_HAS_NISTP521 */
+ # endif /* OPENSSL_HAS_ECC */
+ #endif /* WITH_OPENSSL */
++	{ "null", "null", KEY_NULL, 0, 0, 1 },
+ 	{ NULL, NULL, -1, -1, 0, 0 }
+ };
+ 
+--- a/sshkey.h	2016-07-28 00:54:27.000000000 +0200
++++ b/sshkey.h	2016-09-29 14:45:14.000000000 +0200
+@@ -62,6 +62,7 @@ enum sshkey_types {
+ 	KEY_DSA_CERT,
+ 	KEY_ECDSA_CERT,
+ 	KEY_ED25519_CERT,
++	KEY_NULL,
+ 	KEY_UNSPEC
+ };
+ 
+--- a/auth.c	2016-09-29 14:45:14.000000000 +0200
++++ b/auth.c	2016-09-29 14:45:14.000000000 +0200
+@@ -363,6 +363,7 @@ auth_root_allowed(const char *method)
+ 	case PERMIT_NO_PASSWD:
+ 		if (strcmp(method, "publickey") == 0 ||
+ 		    strcmp(method, "hostbased") == 0 ||
++		    strcmp(method, "gssapi-keyex") == 0 ||
+ 		    strcmp(method, "gssapi-with-mic") == 0)
+ 			return 1;
+ 		break;
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ b/auth-compat.c	2016-09-29 14:46:41.000000000 +0200
+@@ -0,0 +1,175 @@
++/*
++ * Copyright (c) 2000 Markus Friedl.  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"
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <sys/socket.h>
++
++#include <netinet/in.h>
++
++#include <errno.h>
++#include <fcntl.h>
++#ifdef HAVE_PATHS_H
++# include <paths.h>
++#endif
++#include <pwd.h>
++#ifdef HAVE_LOGIN_H
++#include <login.h>
++#endif
++#ifdef USE_SHADOW
++#include <shadow.h>
++#endif
++#ifdef HAVE_LIBGEN_H
++#include <libgen.h>
++#endif
++#include <stdarg.h>
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++#include <limits.h>
++#include <netdb.h>
++
++#include "auth-compat.h"
++#include "log.h"
++#include "canohost.h"
++#include "misc.h"
++
++/****************  XXX moved from auth.c ****************/
++
++/*
++ * 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 - POSSIBLE BREAK-IN ATTEMPT!", 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 - POSSIBLE BREAK-IN ATTEMPT!",
++		    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.
++ */
++
++const char *
++get_canonical_hostname(struct ssh *ssh, int use_dns)
++{
++	static char *dnsname;
++
++	if (!use_dns)
++		return ssh_remote_ipaddr(ssh);
++	else if (dnsname != NULL)
++		return dnsname;
++	else {
++		dnsname = remote_hostname(ssh);
++		return dnsname;
++	}
++}
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ b/auth-compat.h	2016-09-29 14:46:28.000000000 +0200
+@@ -0,0 +1,34 @@
++/*
++ * Copyright (c) 2000 Markus Friedl.  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.
++ *
++ */
++
++#ifndef AUTH_COMPAT_H
++#define AUTH_COMPAT_H
++
++#include "packet.h"
++
++const char *get_canonical_hostname(struct ssh *, int);
++char *remote_hostname(struct ssh *);
++
++#endif

Added: trunk/dports/net/openssh/files/openssh-7.3p1-hpnssh14v11.diff
===================================================================
--- trunk/dports/net/openssh/files/openssh-7.3p1-hpnssh14v11.diff	                        (rev 0)
+++ trunk/dports/net/openssh/files/openssh-7.3p1-hpnssh14v11.diff	2016-09-29 13:49:14 UTC (rev 153360)
@@ -0,0 +1,2319 @@
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ b/HPN-README	2016-09-29 10:22:26.000000000 +0200
+@@ -0,0 +1,130 @@
++Notes:
++
++MULTI-THREADED CIPHER:
++The AES cipher in CTR mode has been multithreaded (MTR-AES-CTR). This will allow ssh installations
++on hosts with multiple cores to use more than one processing core during encryption.
++Tests have show significant throughput performance increases when using MTR-AES-CTR up
++to and including a full gigabit per second on quad core systems. It should be possible to
++achieve full line rate on dual core systems but OS and data management overhead makes this
++more difficult to achieve. The cipher stream from MTR-AES-CTR is entirely compatible with single
++thread AES-CTR (ST-AES-CTR) implementations and should be 100% backward compatible. Optimal
++performance requires the MTR-AES-CTR mode be enabled on both ends of the connection.
++The MTR-AES-CTR replaces ST-AES-CTR and is used in exactly the same way with the same
++nomenclature.
++Use examples:
++		ssh -caes128-ctr you at host.com
++		scp -oCipher=aes256-ctr file you at host.com:~/file
++
++NONE CIPHER:
++To use the NONE option you must have the NoneEnabled switch set on the server and
++you *must* have *both* NoneEnabled and NoneSwitch set to yes on the client. The NONE
++feature works with ALL ssh subsystems (as far as we can tell) *AS LONG AS* a tty is not
++spawned. If a user uses the -T switch to prevent a tty being created the NONE cipher will
++be disabled.
++
++The performance increase will only be as good as the network and TCP stack tuning
++on the reciever side of the connection allows. As a rule of thumb a user will need
++at least 10Mb/s connection with a 100ms RTT to see a doubling of performance. The
++HPN-SSH home page describes this in greater detail.
++
++http://www.psc.edu/networking/projects/hpn-ssh
++
++BUFFER SIZES:
++
++If HPN is disabled the receive buffer size will be set to the
++OpenSSH default of 64K.
++
++If an HPN system connects to a nonHPN system the receive buffer will
++be set to the HPNBufferSize value. The default is 2MB but user adjustable.
++
++If an HPN to HPN connection is established a number of different things might
++happen based on the user options and conditions.
++
++Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set
++HPN Buffer Size = up to 64MB
++This is the default state. The HPN buffer size will grow to a maximum of 64MB
++as the TCP receive buffer grows. The maximum HPN Buffer size of 64MB is
++geared towards 10GigE transcontinental connections.
++
++Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set
++HPN Buffer Size = TCP receive buffer value.
++Users on non-autotuning systesm should disable TCPRcvBufPoll in the
++ssh_cofig and sshd_config
++
++Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set
++HPN Buffer Size = minmum of TCP receive buffer and HPNBufferSize.
++This would be the system defined TCP receive buffer (RWIN).
++
++Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf SET
++HPN Buffer Size = minmum of TCPRcvBuf and HPNBufferSize.
++Generally there is no need to set both.
++
++Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set
++HPN Buffer Size = grows to HPNBufferSize
++The buffer will grow up to the maximum size specified here.
++
++Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf SET
++HPN Buffer Size = minmum of TCPRcvBuf and HPNBufferSize.
++Generally there is no need to set both of these, especially on autotuning
++systems. However, if the users wishes to override the autotuning this would be
++one way to do it.
++
++Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf SET
++HPN Buffer Size = TCPRcvBuf.
++This will override autotuning and set the TCP recieve buffer to the user defined
++value.
++
++
++HPN Specific Configuration options
++
++TcpRcvBuf=[int]KB client
++      set the TCP socket receive buffer to n Kilobytes. It can be set up to the
++maximum socket size allowed by the system. This is useful in situations where
++the tcp receive window is set low but the maximum buffer size is set
++higher (as is typical). This works on a per TCP connection basis. You can also
++use this to artifically limit the transfer rate of the connection. In these
++cases the throughput will be no more than n/RTT. The minimum buffer size is 1KB.
++Default is the current system wide tcp receive buffer size.
++
++TcpRcvBufPoll=[yes/no] client/server
++      enable of disable the polling of the tcp receive buffer through the life
++of the connection. You would want to make sure that this option is enabled
++for systems making use of autotuning kernels (linux 2.4.24+, 2.6, MS Vista)
++default is yes.
++
++NoneEnabled=[yes/no] client/server
++      enable or disable the use of the None cipher. Care must always be used
++when enabling this as it will allow users to send data in the clear. However,
++it is important to note that authentication information remains encrypted
++even if this option is enabled. Set to no by default.
++
++NoneSwitch=[yes/no] client
++     Switch the encryption cipher being used to the None cipher after
++authentication takes place. NoneEnabled must be enabled on both the client
++and server side of the connection. When the connection switches to the NONE
++cipher a warning is sent to STDERR. The connection attempt will fail with an
++error if a client requests a NoneSwitch from the server that does not explicitly
++have NoneEnabled set to yes. Note: The NONE cipher cannot be used in
++interactive (shell) sessions and it will fail silently. Set to no by default.
++
++HPNDisabled=[yes/no] client/server
++     In some situations, such as transfers on a local area network, the impact
++of the HPN code produces a net decrease in performance. In these cases it is
++helpful to disable the HPN functionality. By default HPNDisabled is set to no.
++
++HPNBufferSize=[int]KB client/server
++     This is the default buffer size the HPN functionality uses when interacting
++with nonHPN SSH installations. Conceptually this is similar to the TcpRcvBuf
++option as applied to the internal SSH flow control. This value can range from
++1KB to 64MB (1-65536). Use of oversized or undersized buffers can cause performance
++problems depending on the length of the network path. The default size of this buffer
++is 2MB.
++
++
++Credits: This patch was conceived, designed, and led by Chris Rapier (rapier at psc.edu)
++         The majority of the actual coding for versions up to HPN12v1 was performed
++         by Michael Stevens (mstevens at andrew.cmu.edu). The MT-AES-CTR cipher was
++         implemented by Ben Bennet (ben at psc.edu) and improved by Mike Tasota
++         (tasota at gmail.com) an NSF REU grant recipient for 2013.
++         This work was financed, in part, by Cisco System, Inc., the National
++         Library of Medicine, and the National Science Foundation.
+--- a/Makefile.in	2016-07-28 00:54:27.000000000 +0200
++++ b/Makefile.in	2016-09-29 10:22:26.000000000 +0200
+@@ -44,7 +44,7 @@ CC=@CC@
+ LD=@LD@
+ CFLAGS=@CFLAGS@
+ CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@
+-LIBS=@LIBS@
++LIBS=@LIBS@ -lpthread
+ K5LIBS=@K5LIBS@
+ GSSLIBS=@GSSLIBS@
+ SSHLIBS=@SSHLIBS@
+@@ -78,7 +78,7 @@ LIBOPENSSH_OBJS=\
+ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
+ 	authfd.o authfile.o bufaux.o bufbn.o bufec.o buffer.o \
+ 	canohost.o channels.o cipher.o cipher-aes.o cipher-aesctr.o \
+-	cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \
++	cipher-bf1.o cipher-ctr.o cipher-ctr-mt.o cipher-3des1.o cleanup.o \
+ 	compat.o crc32.o deattack.o fatal.o hostfile.o \
+ 	log.o match.o md-sha256.o moduli.o nchan.o packet.o opacket.o \
+ 	readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \
+--- a/auth2.c	2016-07-28 00:54:27.000000000 +0200
++++ b/auth2.c	2016-09-29 10:22:26.000000000 +0200
+@@ -50,6 +50,7 @@
+ #include "dispatch.h"
+ #include "pathnames.h"
+ #include "buffer.h"
++#include "canohost.h"
+ 
+ #ifdef GSSAPI
+ #include "ssh-gss.h"
+@@ -73,6 +74,8 @@ extern Authmethod method_hostbased;
+ extern Authmethod method_gssapi;
+ #endif
+ 
++static int log_flag = 0;
++
+ Authmethod *authmethods[] = {
+ 	&method_none,
+ 	&method_pubkey,
+@@ -224,6 +227,11 @@ input_userauth_request(int type, u_int32
+ 	service = packet_get_cstring(NULL);
+ 	method = packet_get_cstring(NULL);
+ 	debug("userauth-request for user %s service %s method %s", user, service, method);
++	if (!log_flag) {
++		logit("SSH: Server;Ltype: Authname;Remote: %s-%d;Name: %s",
++		      ssh_remote_ipaddr(active_state), ssh_remote_port(active_state), user);
++		log_flag = 1;
++	}
+ 	debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
+ 
+ 	if ((style = strchr(user, ':')) != NULL)
+--- a/channels.c	2016-09-29 10:22:25.000000000 +0200
++++ b/channels.c	2016-09-29 10:22:26.000000000 +0200
+@@ -189,6 +189,10 @@ static void port_open_helper(Channel *c,
+ static int connect_next(struct channel_connect *);
+ static void channel_connect_ctx_free(struct channel_connect *);
+ 
++
++static int hpn_disabled = 0;
++static int hpn_buffer_size = 2 * 1024 * 1024;
++
+ /* -- channel core */
+ 
+ Channel *
+@@ -339,6 +343,7 @@ channel_new(char *ctype, int type, int r
+ 	c->local_window_max = window;
+ 	c->local_consumed = 0;
+ 	c->local_maxpacket = maxpack;
++	c->dynamic_window = 0;
+ 	c->remote_id = -1;
+ 	c->remote_name = xstrdup(remote_name);
+ 	c->remote_window = 0;
+@@ -843,11 +848,39 @@ channel_pre_open_13(Channel *c, fd_set *
+ 		FD_SET(c->sock, writeset);
+ }
+ 
++static int
++channel_tcpwinsz(void)
++{
++	u_int32_t tcpwinsz = 0;
++	socklen_t optsz = sizeof(tcpwinsz);
++	int ret = -1;
++
++	/* if we aren't on a socket return 128KB */
++	if (!packet_connection_is_on_socket())
++		return 128 * 1024;
++
++	ret = getsockopt(packet_get_connection_in(),
++			 SOL_SOCKET, SO_RCVBUF, &tcpwinsz, &optsz);
++	/* return no more than SSHBUF_SIZE_MAX (currently 256MB) */
++	if ((ret == 0) && tcpwinsz > SSHBUF_SIZE_MAX)
++		tcpwinsz = SSHBUF_SIZE_MAX;
++
++	debug2("tcpwinsz: %d for connection: %d", tcpwinsz,
++	       packet_get_connection_in());
++	return tcpwinsz;
++}
++
+ static void
+ channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
+ {
+ 	u_int limit = compat20 ? c->remote_window : packet_get_maxsize();
+ 
++	/* check buffer limits */
++	if ((!c->tcpwinsz) || (c->dynamic_window > 0))
++		c->tcpwinsz = channel_tcpwinsz();
++
++	limit = MIN(limit, 2 * c->tcpwinsz);
++
+ 	if (c->istate == CHAN_INPUT_OPEN &&
+ 	    limit > 0 &&
+ 	    buffer_len(&c->input) < limit &&
+@@ -1865,14 +1898,21 @@ channel_check_window(Channel *c)
+ 	    c->local_maxpacket*3) ||
+ 	    c->local_window < c->local_window_max/2) &&
+ 	    c->local_consumed > 0) {
++		u_int addition = 0;
++		/* adjust max window size if we are in a dynamic environment */
++		if (c->dynamic_window && (c->tcpwinsz > c->local_window_max)) {
++			/* grow the window somewhat aggressively to maintain pressure */
++			addition = 1.5 * (c->tcpwinsz - c->local_window_max);
++			c->local_window_max += addition;
++		}
+ 		packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
+ 		packet_put_int(c->remote_id);
+-		packet_put_int(c->local_consumed);
++		packet_put_int(c->local_consumed + addition);
+ 		packet_send();
+ 		debug2("channel %d: window %d sent adjust %d",
+ 		    c->self, c->local_window,
+ 		    c->local_consumed);
+-		c->local_window += c->local_consumed;
++		c->local_window += c->local_consumed + addition;
+ 		c->local_consumed = 0;
+ 	}
+ 	return 1;
+@@ -2236,11 +2276,12 @@ channel_after_select(fd_set *readset, fd
+ 
+ 
+ /* If there is data to send to the connection, enqueue some of it now. */
+-void
++int
+ channel_output_poll(void)
+ {
+ 	Channel *c;
+ 	u_int i, len;
++	int packet_length = 0;
+ 
+ 	for (i = 0; i < channels_alloc; i++) {
+ 		c = channels[i];
+@@ -2288,7 +2329,7 @@ channel_output_poll(void)
+ 					packet_start(SSH2_MSG_CHANNEL_DATA);
+ 					packet_put_int(c->remote_id);
+ 					packet_put_string(data, dlen);
+-					packet_send();
++					packet_length = packet_send();
+ 					c->remote_window -= dlen;
+ 					free(data);
+ 				}
+@@ -2318,7 +2359,7 @@ channel_output_poll(void)
+ 				    SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA);
+ 				packet_put_int(c->remote_id);
+ 				packet_put_string(buffer_ptr(&c->input), len);
+-				packet_send();
++				packet_length = packet_send();
+ 				buffer_consume(&c->input, len);
+ 				c->remote_window -= len;
+ 			}
+@@ -2353,12 +2394,13 @@ channel_output_poll(void)
+ 			packet_put_int(c->remote_id);
+ 			packet_put_int(SSH2_EXTENDED_DATA_STDERR);
+ 			packet_put_string(buffer_ptr(&c->extended), len);
+-			packet_send();
++			packet_length = packet_send();
+ 			buffer_consume(&c->extended, len);
+ 			c->remote_window -= len;
+ 			debug2("channel %d: sent ext data %d", c->self, len);
+ 		}
+ 	}
++	return packet_length;
+ }
+ 
+ 
+@@ -2816,6 +2858,15 @@ channel_fwd_bind_addr(const char *listen
+ 	return addr;
+ }
+ 
++
++void
++channel_set_hpn(int external_hpn_disabled, int external_hpn_buffer_size)
++{
++	hpn_disabled = external_hpn_disabled;
++	hpn_buffer_size = external_hpn_buffer_size;
++	debug("HPN Disabled: %d, HPN Buffer Size: %d", hpn_disabled, hpn_buffer_size);
++}
++
+ static int
+ channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd,
+     int *allocated_listen_port, struct ForwardOptions *fwd_opts)
+@@ -2944,9 +2995,15 @@ channel_setup_fwd_listener_tcpip(int typ
+ 		}
+ 
+ 		/* Allocate a channel number for the socket. */
+-		c = channel_new("port listener", type, sock, sock, -1,
+-		    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
+-		    0, "port listener", 1);
++		/* explicitly test for hpn disabled option. if true use smaller window size */
++		if (hpn_disabled)
++			c = channel_new("port listener", type, sock, sock, -1,
++			    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
++			    0, "port listener", 1);
++		else
++			c = channel_new("port listener", type, sock, sock, -1,
++			    hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT,
++			    0, "port listener", 1);
+ 		c->path = xstrdup(host);
+ 		c->host_port = fwd->connect_port;
+ 		c->listening_addr = addr == NULL ? NULL : xstrdup(addr);
+@@ -3979,10 +4036,17 @@ x11_create_display_inet(int x11_display_
+ 	*chanids = xcalloc(num_socks + 1, sizeof(**chanids));
+ 	for (n = 0; n < num_socks; n++) {
+ 		sock = socks[n];
++		/* Is this really necassary? */
++		if (hpn_disabled)
+ 		nc = channel_new("x11 listener",
+ 		    SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
+ 		    CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
+ 		    0, "X11 inet listener", 1);
++		else
++			nc = channel_new("x11 listener",
++			    SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
++			    hpn_buffer_size, CHAN_X11_PACKET_DEFAULT,
++			    0, "X11 inet listener", 1);
+ 		nc->single_connection = single_connection;
+ 		(*chanids)[n] = nc->self;
+ 	}
+--- a/channels.h	2016-07-28 00:54:27.000000000 +0200
++++ b/channels.h	2016-09-29 10:22:26.000000000 +0200
+@@ -134,8 +134,10 @@ struct Channel {
+ 	u_int	local_window_max;
+ 	u_int	local_consumed;
+ 	u_int	local_maxpacket;
++	int	dynamic_window;
+ 	int     extended_usage;
+ 	int	single_connection;
++	u_int	tcpwinsz;
+ 
+ 	char   *ctype;		/* type */
+ 
+@@ -247,7 +249,7 @@ int	 channel_input_status_confirm(int, u
+ void	 channel_prepare_select(fd_set **, fd_set **, int *, u_int*,
+ 	     time_t*, int);
+ void     channel_after_select(fd_set *, fd_set *);
+-void     channel_output_poll(void);
++int      channel_output_poll(void);
+ 
+ int      channel_not_very_much_buffered_data(void);
+ void     channel_close_all(void);
+@@ -312,4 +314,7 @@ void	 chan_rcvd_ieof(Channel *);
+ void	 chan_write_failed(Channel *);
+ void	 chan_obuf_empty(Channel *);
+ 
++/* hpn handler */
++void     channel_set_hpn(int, int);
++
+ #endif
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ b/cipher-ctr-mt.c	2016-09-29 10:22:26.000000000 +0200
+@@ -0,0 +1,533 @@
++/*
++ * OpenSSH Multi-threaded AES-CTR Cipher
++ *
++ * Author: Benjamin Bennett <ben at psc.edu>
++ * Author: Mike Tasota <tasota at gmail.com>
++ * Author: Chris Rapier <rapier at psc.edu>
++ * Copyright (c) 2008-2013 Pittsburgh Supercomputing Center. All rights reserved.
++ *
++ * Based on original OpenSSH AES-CTR cipher. Small portions remain unchanged,
++ * Copyright (c) 2003 Markus Friedl <markus at openbsd.org>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++#include "includes.h"
++
++#if defined(WITH_OPENSSL)
++#include <sys/types.h>
++
++#include <stdarg.h>
++#include <string.h>
++
++#include <openssl/evp.h>
++
++#include "xmalloc.h"
++#include "log.h"
++
++/* compatibility with old or broken OpenSSL versions */
++#include "openbsd-compat/openssl-compat.h"
++
++#ifndef USE_BUILTIN_RIJNDAEL
++#include <openssl/aes.h>
++#endif
++
++#include <pthread.h>
++
++/*-------------------- TUNABLES --------------------*/
++/* Number of pregen threads to use */
++#define CIPHER_THREADS	2
++
++/* Number of keystream queues */
++#define NUMKQ		(CIPHER_THREADS + 2)
++
++/* Length of a keystream queue */
++#define KQLEN		4096
++
++/* Processor cacheline length */
++#define CACHELINE_LEN	64
++
++/* Collect thread stats and print at cancellation when in debug mode */
++/* #define CIPHER_THREAD_STATS */
++
++/* Can the system do unaligned loads natively? */
++#if defined(__aarch64__) || \
++    defined(__i386__)    || \
++    defined(__powerpc__) || \
++    defined(__x86_64__)
++# define CIPHER_UNALIGNED_OK
++#endif
++#if defined(__SIZEOF_INT128__)
++# define CIPHER_INT128_OK
++#endif
++/*-------------------- END TUNABLES --------------------*/
++
++
++const EVP_CIPHER *evp_aes_ctr_mt(void);
++
++#ifdef CIPHER_THREAD_STATS
++/*
++ * Struct to collect thread stats
++ */
++struct thread_stats {
++	u_int	fills;
++	u_int	skips;
++	u_int	waits;
++	u_int	drains;
++};
++
++/*
++ * Debug print the thread stats
++ * Use with pthread_cleanup_push for displaying at thread cancellation
++ */
++static void
++thread_loop_stats(void *x)
++{
++	struct thread_stats *s = x;
++
++	debug("tid %lu - %u fills, %u skips, %u waits", pthread_self(),
++			s->fills, s->skips, s->waits);
++}
++
++# define STATS_STRUCT(s)	struct thread_stats s
++# define STATS_INIT(s)		{ memset(&s, 0, sizeof(s)); }
++# define STATS_FILL(s)		{ s.fills++; }
++# define STATS_SKIP(s)		{ s.skips++; }
++# define STATS_WAIT(s)		{ s.waits++; }
++# define STATS_DRAIN(s)		{ s.drains++; }
++#else
++# define STATS_STRUCT(s)
++# define STATS_INIT(s)
++# define STATS_FILL(s)
++# define STATS_SKIP(s)
++# define STATS_WAIT(s)
++# define STATS_DRAIN(s)
++#endif
++
++/* Keystream Queue state */
++enum {
++	KQINIT,
++	KQEMPTY,
++	KQFILLING,
++	KQFULL,
++	KQDRAINING
++};
++
++/* Keystream Queue struct */
++struct kq {
++	u_char		keys[KQLEN][AES_BLOCK_SIZE];
++	u_char		ctr[AES_BLOCK_SIZE];
++	u_char		pad0[CACHELINE_LEN];
++	volatile int	qstate;
++	pthread_mutex_t	lock;
++	pthread_cond_t	cond;
++	u_char		pad1[CACHELINE_LEN];
++};
++
++/* Context struct */
++struct ssh_aes_ctr_ctx
++{
++	struct kq	q[NUMKQ];
++	AES_KEY		aes_ctx;
++	STATS_STRUCT(stats);
++	u_char		aes_counter[AES_BLOCK_SIZE];
++	pthread_t	tid[CIPHER_THREADS];
++	int		state;
++	int		qidx;
++	int		ridx;
++};
++
++/* <friedl>
++ * increment counter 'ctr',
++ * the counter is of size 'len' bytes and stored in network-byte-order.
++ * (LSB at ctr[len-1], MSB at ctr[0])
++ */
++static void
++ssh_ctr_inc(u_char *ctr, size_t len)
++{
++	int i;
++
++	for (i = len - 1; i >= 0; i--)
++		if (++ctr[i])	/* continue on overflow */
++			return;
++}
++
++/*
++ * Add num to counter 'ctr'
++ */
++static void
++ssh_ctr_add(u_char *ctr, uint32_t num, u_int len)
++{
++	int i;
++	uint16_t n;
++
++	for (n = 0, i = len - 1; i >= 0 && (num || n); i--) {
++		n = ctr[i] + (num & 0xff) + n;
++		num >>= 8;
++		ctr[i] = n & 0xff;
++		n >>= 8;
++	}
++}
++
++/*
++ * Threads may be cancelled in a pthread_cond_wait, we must free the mutex
++ */
++static void
++thread_loop_cleanup(void *x)
++{
++	pthread_mutex_unlock((pthread_mutex_t *)x);
++}
++
++/*
++ * The life of a pregen thread:
++ *    Find empty keystream queues and fill them using their counter.
++ *    When done, update counter for the next fill.
++ */
++static void *
++thread_loop(void *x)
++{
++	AES_KEY key;
++	STATS_STRUCT(stats);
++	struct ssh_aes_ctr_ctx *c = x;
++	struct kq *q;
++	int i;
++	int qidx;
++
++	/* Threads stats on cancellation */
++	STATS_INIT(stats);
++#ifdef CIPHER_THREAD_STATS
++	pthread_cleanup_push(thread_loop_stats, &stats);
++#endif
++
++	/* Thread local copy of AES key */
++	memcpy(&key, &c->aes_ctx, sizeof(key));
++
++	/*
++	 * Handle the special case of startup, one thread must fill
++	 * the first KQ then mark it as draining. Lock held throughout.
++	 */
++	if (pthread_equal(pthread_self(), c->tid[0])) {
++		q = &c->q[0];
++		pthread_mutex_lock(&q->lock);
++		if (q->qstate == KQINIT) {
++			for (i = 0; i < KQLEN; i++) {
++				AES_encrypt(q->ctr, q->keys[i], &key);
++				ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE);
++			}
++			ssh_ctr_add(q->ctr, KQLEN * (NUMKQ - 1), AES_BLOCK_SIZE);
++			q->qstate = KQDRAINING;
++			STATS_FILL(stats);
++			pthread_cond_broadcast(&q->cond);
++		}
++		pthread_mutex_unlock(&q->lock);
++	} else
++		STATS_SKIP(stats);
++
++	/*
++	 * Normal case is to find empty queues and fill them, skipping over
++	 * queues already filled by other threads and stopping to wait for
++	 * a draining queue to become empty.
++	 *
++	 * Multiple threads may be waiting on a draining queue and awoken
++	 * when empty.  The first thread to wake will mark it as filling,
++	 * others will move on to fill, skip, or wait on the next queue.
++	 */
++	for (qidx = 1;; qidx = (qidx + 1) % NUMKQ) {
++		/* Check if I was cancelled, also checked in cond_wait */
++		pthread_testcancel();
++
++		/* Lock queue and block if its draining */
++		q = &c->q[qidx];
++		pthread_mutex_lock(&q->lock);
++		pthread_cleanup_push(thread_loop_cleanup, &q->lock);
++		while (q->qstate == KQDRAINING || q->qstate == KQINIT) {
++			STATS_WAIT(stats);
++			pthread_cond_wait(&q->cond, &q->lock);
++		}
++		pthread_cleanup_pop(0);
++
++		/* If filling or full, somebody else got it, skip */
++		if (q->qstate != KQEMPTY) {
++			pthread_mutex_unlock(&q->lock);
++			STATS_SKIP(stats);
++			continue;
++		}
++
++		/*
++		 * Empty, let's fill it.
++		 * Queue lock is relinquished while we do this so others
++		 * can see that it's being filled.
++		 */
++		q->qstate = KQFILLING;
++		pthread_mutex_unlock(&q->lock);
++		for (i = 0; i < KQLEN; i++) {
++			AES_encrypt(q->ctr, q->keys[i], &key);
++			ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE);
++		}
++
++		/* Re-lock, mark full and signal consumer */
++		pthread_mutex_lock(&q->lock);
++		ssh_ctr_add(q->ctr, KQLEN * (NUMKQ - 1), AES_BLOCK_SIZE);
++		q->qstate = KQFULL;
++		STATS_FILL(stats);
++		pthread_cond_signal(&q->cond);
++		pthread_mutex_unlock(&q->lock);
++	}
++
++#ifdef CIPHER_THREAD_STATS
++	/* Stats */
++	pthread_cleanup_pop(1);
++#endif
++
++	return NULL;
++}
++
++static int
++ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
++    LIBCRYPTO_EVP_INL_TYPE len)
++{
++	typedef union {
++#ifdef CIPHER_INT128_OK
++		__uint128_t *u128;
++#endif
++		uint64_t *u64;
++		uint32_t *u32;
++		uint8_t *u8;
++		const uint8_t *cu8;
++		uintptr_t u;
++	} ptrs_t;
++	ptrs_t destp, srcp, bufp;
++	uintptr_t align;
++	struct ssh_aes_ctr_ctx *c;
++	struct kq *q, *oldq;
++	int ridx;
++	u_char *buf;
++
++	if (len == 0)
++		return 1;
++	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL)
++		return 0;
++
++	q = &c->q[c->qidx];
++	ridx = c->ridx;
++
++	/* src already padded to block multiple */
++	srcp.cu8 = src;
++	destp.u8 = dest;
++	while (len > 0) {
++		buf = q->keys[ridx];
++		bufp.u8 = buf;
++
++		/* figure out the alignment on the fly */
++#ifdef CIPHER_UNALIGNED_OK
++		align = 0;
++#else
++		align = destp.u | srcp.u | bufp.u;
++#endif
++
++#ifdef CIPHER_INT128_OK
++		if ((align & 0xf) == 0) {
++			destp.u128[0] = srcp.u128[0] ^ bufp.u128[0];
++		} else
++#endif
++		if ((align & 0x7) == 0) {
++			destp.u64[0] = srcp.u64[0] ^ bufp.u64[0];
++			destp.u64[1] = srcp.u64[1] ^ bufp.u64[1];
++		} else if ((align & 0x3) == 0) {
++			destp.u32[0] = srcp.u32[0] ^ bufp.u32[0];
++			destp.u32[1] = srcp.u32[1] ^ bufp.u32[1];
++			destp.u32[2] = srcp.u32[2] ^ bufp.u32[2];
++			destp.u32[3] = srcp.u32[3] ^ bufp.u32[3];
++		} else {
++			size_t i;
++			for (i = 0; i < AES_BLOCK_SIZE; ++i)
++				dest[i] = src[i] ^ buf[i];
++		}
++
++		destp.u += AES_BLOCK_SIZE;
++		srcp.u += AES_BLOCK_SIZE;
++		len -= AES_BLOCK_SIZE;
++		ssh_ctr_inc(ctx->iv, AES_BLOCK_SIZE);
++
++		/* Increment read index, switch queues on rollover */
++		if ((ridx = (ridx + 1) % KQLEN) == 0) {
++			oldq = q;
++
++			/* Mark next queue draining, may need to wait */
++			c->qidx = (c->qidx + 1) % NUMKQ;
++			q = &c->q[c->qidx];
++			pthread_mutex_lock(&q->lock);
++			while (q->qstate != KQFULL) {
++				STATS_WAIT(c->stats);
++				pthread_cond_wait(&q->cond, &q->lock);
++			}
++			q->qstate = KQDRAINING;
++			pthread_mutex_unlock(&q->lock);
++
++			/* Mark consumed queue empty and signal producers */
++			pthread_mutex_lock(&oldq->lock);
++			oldq->qstate = KQEMPTY;
++			STATS_DRAIN(c->stats);
++			pthread_cond_broadcast(&oldq->cond);
++			pthread_mutex_unlock(&oldq->lock);
++		}
++	}
++	c->ridx = ridx;
++	return 1;
++}
++
++#define HAVE_NONE       0
++#define HAVE_KEY        1
++#define HAVE_IV         2
++static int
++ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
++    int enc)
++{
++	struct ssh_aes_ctr_ctx *c;
++	int i;
++
++	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
++		c = xmalloc(sizeof(*c));
++
++		c->state = HAVE_NONE;
++		for (i = 0; i < NUMKQ; i++) {
++			pthread_mutex_init(&c->q[i].lock, NULL);
++			pthread_cond_init(&c->q[i].cond, NULL);
++		}
++
++		STATS_INIT(c->stats);
++		EVP_CIPHER_CTX_set_app_data(ctx, c);
++	}
++
++	if (c->state == (HAVE_KEY | HAVE_IV)) {
++		/* Cancel pregen threads */
++		for (i = 0; i < CIPHER_THREADS; i++)
++			pthread_cancel(c->tid[i]);
++		for (i = 0; i < CIPHER_THREADS; i++)
++			pthread_join(c->tid[i], NULL);
++		/* Start over getting key & iv */
++		c->state = HAVE_NONE;
++	}
++
++	if (key != NULL) {
++		AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++		    &c->aes_ctx);
++		c->state |= HAVE_KEY;
++	}
++
++	if (iv != NULL) {
++		memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
++		c->state |= HAVE_IV;
++	}
++
++	if (c->state == (HAVE_KEY | HAVE_IV)) {
++		/* Clear queues */
++		memcpy(c->q[0].ctr, ctx->iv, AES_BLOCK_SIZE);
++		c->q[0].qstate = KQINIT;
++		for (i = 1; i < NUMKQ; i++) {
++			memcpy(c->q[i].ctr, ctx->iv, AES_BLOCK_SIZE);
++			ssh_ctr_add(c->q[i].ctr, i * KQLEN, AES_BLOCK_SIZE);
++			c->q[i].qstate = KQEMPTY;
++		}
++		c->qidx = 0;
++		c->ridx = 0;
++
++		/* Start threads */
++		for (i = 0; i < CIPHER_THREADS; i++) {
++			debug("spawned a thread");
++			pthread_create(&c->tid[i], NULL, thread_loop, c);
++		}
++		pthread_mutex_lock(&c->q[0].lock);
++		while (c->q[0].qstate != KQDRAINING)
++			pthread_cond_wait(&c->q[0].cond, &c->q[0].lock);
++		pthread_mutex_unlock(&c->q[0].lock);
++	}
++	return 1;
++}
++
++/* this function is no longer used but might prove handy in the future
++ * this comment also applies to ssh_aes_ctr_thread_reconstruction
++ */
++void
++ssh_aes_ctr_thread_destroy(EVP_CIPHER_CTX *ctx)
++{
++	struct ssh_aes_ctr_ctx *c;
++	int i;
++	c = EVP_CIPHER_CTX_get_app_data(ctx);
++	/* destroy threads */
++	for (i = 0; i < CIPHER_THREADS; i++) {
++		pthread_cancel(c->tid[i]);
++	}
++	for (i = 0; i < CIPHER_THREADS; i++) {
++		pthread_join(c->tid[i], NULL);
++	}
++}
++
++void
++ssh_aes_ctr_thread_reconstruction(EVP_CIPHER_CTX *ctx)
++{
++	struct ssh_aes_ctr_ctx *c;
++	int i;
++	c = EVP_CIPHER_CTX_get_app_data(ctx);
++	/* reconstruct threads */
++	for (i = 0; i < CIPHER_THREADS; i++) {
++		debug("spawned a thread");
++		pthread_create(&c->tid[i], NULL, thread_loop, c);
++	}
++}
++
++static int
++ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx)
++{
++	struct ssh_aes_ctr_ctx *c;
++	int i;
++
++	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
++#ifdef CIPHER_THREAD_STATS
++		debug("main thread: %u drains, %u waits", c->stats.drains,
++				c->stats.waits);
++#endif
++		/* Cancel pregen threads */
++		for (i = 0; i < CIPHER_THREADS; i++)
++			pthread_cancel(c->tid[i]);
++		for (i = 0; i < CIPHER_THREADS; i++)
++			pthread_join(c->tid[i], NULL);
++
++		memset(c, 0, sizeof(*c));
++		free(c);
++		EVP_CIPHER_CTX_set_app_data(ctx, NULL);
++	}
++	return 1;
++}
++
++/* <friedl> */
++const EVP_CIPHER *
++evp_aes_ctr_mt(void)
++{
++	static EVP_CIPHER aes_ctr;
++
++	memset(&aes_ctr, 0, sizeof(EVP_CIPHER));
++	aes_ctr.nid = NID_undef;
++	aes_ctr.block_size = AES_BLOCK_SIZE;
++	aes_ctr.iv_len = AES_BLOCK_SIZE;
++	aes_ctr.key_len = 16;
++	aes_ctr.init = ssh_aes_ctr_init;
++	aes_ctr.cleanup = ssh_aes_ctr_cleanup;
++	aes_ctr.do_cipher = ssh_aes_ctr;
++#ifndef SSH_OLD_EVP
++	aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
++	    EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV;
++#endif
++	return &aes_ctr;
++}
++
++#endif /* defined(WITH_OPENSSL) */
+--- a/cipher.c	2016-07-28 00:54:27.000000000 +0200
++++ b/cipher.c	2016-09-29 10:22:26.000000000 +0200
+@@ -57,6 +57,13 @@ extern const EVP_CIPHER *evp_ssh1_3des(v
+ extern int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
+ #endif
+ 
++/* for multi-threaded aes-ctr cipher */
++extern const EVP_CIPHER *evp_aes_ctr_mt(void);
++
++/* no longer needed. replaced by evp pointer swap */
++/* extern void ssh_aes_ctr_thread_destroy(EVP_CIPHER_CTX *ctx); */
++/* extern void ssh_aes_ctr_thread_reconstruction(EVP_CIPHER_CTX *ctx); */
++
+ struct sshcipher {
+ 	char	*name;
+ 	int	number;		/* for ssh1 only */
+@@ -77,7 +84,7 @@ struct sshcipher {
+ #endif
+ };
+ 
+-static const struct sshcipher ciphers[] = {
++static struct sshcipher ciphers[] = {
+ #ifdef WITH_SSH1
+ 	{ "des",	SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc },
+ 	{ "3des",	SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des },
+@@ -156,6 +163,29 @@ cipher_alg_list(char sep, int auth_only)
+ 	return ret;
+ }
+ 
++/* used to get the cipher name so when force rekeying to handle the
++ * single to multithreaded ctr cipher swap we only rekey when appropriate
++ */
++const char *
++cipher_return_name(const struct sshcipher *c)
++{
++	return c->name;
++}
++
++/* in order to get around sandbox and forking issues with a threaded cipher
++ * we set the initial pre-auth aes-ctr cipher to the default OpenSSH cipher
++ * post auth we set them to the new evp as defined by cipher-ctr-mt
++ */
++#ifdef WITH_OPENSSL
++void
++cipher_reset_multithreaded(void)
++{
++	cipher_by_name("aes128-ctr")->evptype = evp_aes_ctr_mt;
++	cipher_by_name("aes192-ctr")->evptype = evp_aes_ctr_mt;
++	cipher_by_name("aes256-ctr")->evptype = evp_aes_ctr_mt;
++}
++#endif
++
+ u_int
+ cipher_blocksize(const struct sshcipher *c)
+ {
+@@ -217,10 +247,10 @@ cipher_mask_ssh1(int client)
+ 	return mask;
+ }
+ 
+-const struct sshcipher *
++struct sshcipher *
+ cipher_by_name(const char *name)
+ {
+-	const struct sshcipher *c;
++	struct sshcipher *c;
+ 	for (c = ciphers; c->name != NULL; c++)
+ 		if (strcmp(c->name, name) == 0)
+ 			return c;
+@@ -252,7 +282,8 @@ ciphers_valid(const char *names)
+ 	for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
+ 	    (p = strsep(&cp, CIPHER_SEP))) {
+ 		c = cipher_by_name(p);
+-		if (c == NULL || c->number != SSH_CIPHER_SSH2) {
++		if (c == NULL || (c->number != SSH_CIPHER_SSH2 &&
++				  c->number != SSH_CIPHER_NONE)) {
+ 			free(cipher_list);
+ 			return 0;
+ 		}
+@@ -552,6 +583,7 @@ cipher_get_keyiv(struct sshcipher_ctx *c
+ 
+ 	switch (c->number) {
+ #ifdef WITH_OPENSSL
++	case SSH_CIPHER_NONE:
+ 	case SSH_CIPHER_SSH2:
+ 	case SSH_CIPHER_DES:
+ 	case SSH_CIPHER_BLOWFISH:
+@@ -600,6 +632,7 @@ cipher_set_keyiv(struct sshcipher_ctx *c
+ 
+ 	switch (c->number) {
+ #ifdef WITH_OPENSSL
++	case SSH_CIPHER_NONE:
+ 	case SSH_CIPHER_SSH2:
+ 	case SSH_CIPHER_DES:
+ 	case SSH_CIPHER_BLOWFISH:
+--- a/cipher.h	2016-07-28 00:54:27.000000000 +0200
++++ b/cipher.h	2016-09-29 10:22:26.000000000 +0200
+@@ -72,8 +72,11 @@ struct sshcipher_ctx {
+ 	const struct sshcipher *cipher;
+ };
+ 
++void ssh_aes_ctr_thread_destroy(EVP_CIPHER_CTX *ctx); // defined in cipher-ctr-mt.c
++void ssh_aes_ctr_thread_reconstruction(EVP_CIPHER_CTX *ctx);
++
+ u_int	 cipher_mask_ssh1(int);
+-const struct sshcipher *cipher_by_name(const char *);
++struct sshcipher *cipher_by_name(const char *);
+ const struct sshcipher *cipher_by_number(int);
+ int	 cipher_number(const char *);
+ char	*cipher_name(int);
+@@ -95,6 +98,8 @@ u_int	 cipher_seclen(const struct sshcip
+ u_int	 cipher_authlen(const struct sshcipher *);
+ u_int	 cipher_ivlen(const struct sshcipher *);
+ u_int	 cipher_is_cbc(const struct sshcipher *);
++void	 cipher_reset_multithreaded(void);
++const char *cipher_return_name(const struct sshcipher *);
+ 
+ u_int	 cipher_get_number(const struct sshcipher *);
+ int	 cipher_get_keyiv(struct sshcipher_ctx *, u_char *, u_int);
+--- a/clientloop.c	2016-09-29 10:22:25.000000000 +0200
++++ b/clientloop.c	2016-09-29 10:22:26.000000000 +0200
+@@ -1999,9 +1999,15 @@ client_request_x11(const char *request_t
+ 	sock = x11_connect_display();
+ 	if (sock < 0)
+ 		return NULL;
++	/* again is this really necessary for X11? */
++	if (options.hpn_disabled)
+ 	c = channel_new("x11",
+ 	    SSH_CHANNEL_X11_OPEN, sock, sock, -1,
+ 	    CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1);
++	else
++		c = channel_new("x11",
++		    SSH_CHANNEL_X11_OPEN, sock, sock, -1,
++		    options.hpn_buffer_size, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1);
+ 	c->force_drain = 1;
+ 	return c;
+ }
+@@ -2024,9 +2030,15 @@ client_request_agent(const char *request
+ 			    __func__, ssh_err(r));
+ 		return NULL;
+ 	}
++	if (options.hpn_disabled)
++	c = channel_new("authentication agent connection",
++	    SSH_CHANNEL_OPEN, sock, sock, -1,
++		    CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0,
++		    "authentication agent connection", 1);
++	else
+ 	c = channel_new("authentication agent connection",
+ 	    SSH_CHANNEL_OPEN, sock, sock, -1,
+-	    CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0,
++	    options.hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, 0,
+ 	    "authentication agent connection", 1);
+ 	c->force_drain = 1;
+ 	return c;
+@@ -2054,10 +2066,18 @@ client_request_tun_fwd(int tun_mode, int
+ 		return -1;
+ 	}
+ 
++	if(options.hpn_disabled)
+ 	c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1,
+-	    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
++				CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
++				0, "tun", 1);
++	else
++	c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1,
++				options.hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT,
++				0, "tun", 1);
+ 	c->datagram = 1;
+ 
++
++
+ #if defined(SSH_TUN_FILTER)
+ 	if (options.tun_open == SSH_TUNMODE_POINTOPOINT)
+ 		channel_register_filter(c->self, sys_tun_infilter,
+--- a/compat.c	2016-07-28 00:54:27.000000000 +0200
++++ b/compat.c	2016-09-29 10:22:26.000000000 +0200
+@@ -210,6 +210,13 @@ compat_datafellows(const char *version)
+ 			debug("match: %s pat %s compat 0x%08x",
+ 			    version, check[i].pat, check[i].bugs);
+ 			datafellows = check[i].bugs;	/* XXX for now */
++			/* Check to see if the remote side is OpenSSH and not HPN */
++			if (strstr(version, "OpenSSH") != NULL) {
++				if (strstr(version, "hpn") == NULL) {
++					datafellows |= SSH_BUG_LARGEWINDOW;
++					debug("Remote is NON-HPN aware");
++				}
++			}
+ 			return check[i].bugs;
+ 		}
+ 	}
+--- a/compat.h	2016-07-28 00:54:27.000000000 +0200
++++ b/compat.h	2016-09-29 10:22:26.000000000 +0200
+@@ -62,6 +62,7 @@
+ #define SSH_BUG_CURVE25519PAD	0x10000000
+ #define SSH_BUG_HOSTKEYS	0x20000000
+ #define SSH_BUG_DHGEX_LARGE	0x40000000
++#define SSH_BUG_LARGEWINDOW	0x80000000
+ 
+ void     enable_compat13(void);
+ void     enable_compat20(void);
+--- a/kex.c	2016-07-28 00:54:27.000000000 +0200
++++ b/kex.c	2016-09-29 10:22:26.000000000 +0200
+@@ -53,6 +53,7 @@
+ 
+ #include "ssherr.h"
+ #include "sshbuf.h"
++#include "canohost.h"
+ #include "digest.h"
+ 
+ #if OPENSSL_VERSION_NUMBER >= 0x00907000L
+@@ -754,6 +755,11 @@ kex_choose_conf(struct ssh *ssh)
+ 	int nenc, nmac, ncomp;
+ 	u_int mode, ctos, need, dh_need, authlen;
+ 	int r, first_kex_follows;
++	int log_flag = 0;
++	int auth_flag;
++
++	auth_flag = packet_authentication_state(ssh);
++	debug("AUTH STATE IS %d", auth_flag);
+ 
+ 	debug2("local %s KEXINIT proposal", kex->server ? "server" : "client");
+ 	if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0)
+@@ -826,11 +832,35 @@ kex_choose_conf(struct ssh *ssh)
+ 			peer[ncomp] = NULL;
+ 			goto out;
+ 		}
++		debug("REQUESTED ENC.NAME is '%s'", newkeys->enc.name);
++		if (strcmp(newkeys->enc.name, "none") == 0) {
++			debug("Requesting NONE. Authflag is %d", auth_flag);
++			if (auth_flag == 1)
++				debug("None requested post authentication.");
++			else
++				fatal("Pre-authentication none cipher requests are not allowed.");
++		}
+ 		debug("kex: %s cipher: %s MAC: %s compression: %s",
+ 		    ctos ? "client->server" : "server->client",
+ 		    newkeys->enc.name,
+ 		    authlen == 0 ? newkeys->mac.name : "<implicit>",
+ 		    newkeys->comp.name);
++		/*
++		 * client starts with ctos = 0 && log flag = 0 and no log.
++		 * 2nd client pass ctos = 1 and flag = 1 so no log.
++		 * server starts with ctos = 1 && log_flag = 0 so log.
++		 * 2nd sever pass ctos = 1 && log flag = 1 so no log.
++		 * -cjr
++		 */
++		if (ctos && !log_flag) {
++			logit("SSH: Server;Ltype: Kex;Remote: %s-%d;Enc: %s;MAC: %s;Comp: %s",
++			    ssh_remote_ipaddr(ssh),
++			    ssh_remote_port(ssh),
++			    newkeys->enc.name,
++			    authlen == 0 ? newkeys->mac.name : "<implicit>",
++			    newkeys->comp.name);
++		}
++		log_flag = 1;
+ 	}
+ 	need = dh_need = 0;
+ 	for (mode = 0; mode < MODE_MAX; mode++) {
+--- a/opacket.c	2016-07-28 00:54:27.000000000 +0200
++++ b/opacket.c	2016-09-29 10:22:26.000000000 +0200
+@@ -108,13 +108,15 @@ ssh_packet_put_ecpoint(struct ssh *ssh, 
+ # endif
+ #endif /* WITH_OPENSSL */
+ 
+-void
++int
+ ssh_packet_send(struct ssh *ssh)
+ {
+ 	int r;
+ 
+ 	if ((r = sshpkt_send(ssh)) != 0)
+ 		fatal("%s: %s", __func__, ssh_err(r));
++
++	return r;
+ }
+ 
+ u_int
+@@ -294,13 +296,15 @@ packet_write_wait(void)
+ 		sshpkt_fatal(active_state, __func__, r);
+ }
+ 
+-void
++int
+ packet_write_poll(void)
+ {
+ 	int r;
+ 
+ 	if ((r = ssh_packet_write_poll(active_state)) != 0)
+ 		sshpkt_fatal(active_state, __func__, r);
++
++	return r;
+ }
+ 
+ void
+--- a/opacket.h	2016-07-28 00:54:27.000000000 +0200
++++ b/opacket.h	2016-09-29 10:22:26.000000000 +0200
+@@ -12,7 +12,7 @@ void     ssh_packet_put_ecpoint(struct s
+ void     ssh_packet_put_string(struct ssh *, const void *buf, u_int len);
+ void     ssh_packet_put_cstring(struct ssh *, const char *str);
+ void     ssh_packet_put_raw(struct ssh *, const void *buf, u_int len);
+-void     ssh_packet_send(struct ssh *);
++int      ssh_packet_send(struct ssh *);
+ 
+ u_int	 ssh_packet_get_char(struct ssh *);
+ u_int	 ssh_packet_get_int(struct ssh *);
+@@ -44,7 +44,7 @@ int	 packet_read_seqnr(u_int32_t *);
+ int	 packet_read_poll_seqnr(u_int32_t *);
+ void	 packet_process_incoming(const char *buf, u_int len);
+ void	 packet_write_wait(void);
+-void	 packet_write_poll(void);
++int	 packet_write_poll(void);
+ void	 packet_read_expect(int expected_type);
+ #define packet_set_timeout(timeout, count) \
+ 	ssh_packet_set_timeout(active_state, (timeout), (count))
+--- a/packet.c	2016-07-28 00:54:27.000000000 +0200
++++ b/packet.c	2016-09-29 10:22:26.000000000 +0200
+@@ -277,7 +277,7 @@ struct ssh *
+ ssh_packet_set_connection(struct ssh *ssh, int fd_in, int fd_out)
+ {
+ 	struct session_state *state;
+-	const struct sshcipher *none = cipher_by_name("none");
++	struct sshcipher *none = cipher_by_name("none");
+ 	int r;
+ 
+ 	if (none == NULL) {
+@@ -1074,6 +1074,24 @@ ssh_set_newkeys(struct ssh *ssh, int mod
+ 	return 0;
+ }
+ 
++/* this supports the forced rekeying required for the NONE cipher */
++int rekey_requested = 0;
++void
++packet_request_rekeying(void)
++{
++	rekey_requested = 1;
++}
++
++/* this determines if authentciation has happened as of yet. Needed for
++ * NONE cipher switching. */
++int
++packet_authentication_state(const struct ssh *ssh)
++{
++	struct session_state *state = ssh->state;
++
++	return state->after_authentication;
++}
++
+ #define MAX_PACKETS	(1U<<31)
+ static int
+ ssh_packet_need_rekeying(struct ssh *ssh, u_int outbound_packet_len)
+@@ -1100,6 +1118,13 @@ ssh_packet_need_rekeying(struct ssh *ssh
+ 	if (state->p_send.packets == 0 && state->p_read.packets == 0)
+ 		return 0;
+ 
++	/* used to force rekeying when called for by the none
++	 * cipher switch methods -cjr */
++	if (rekey_requested == 1) {
++		rekey_requested = 0;
++		return 1;
++	}
++
+ 	/* Time-based rekeying */
+ 	if (state->rekey_interval != 0 &&
+ 	    state->rekey_time + state->rekey_interval <= monotime())
+@@ -3014,3 +3039,10 @@ sshpkt_add_padding(struct ssh *ssh, u_ch
+ 	ssh->state->extra_pad = pad;
+ 	return 0;
+ }
++
++/* need this for the moment for the aes-ctr cipher */
++void *
++ssh_packet_get_send_context(struct ssh *ssh)
++{
++	return (void *)&ssh->state->send_context;
++}
+--- a/packet.h	2016-07-28 00:54:27.000000000 +0200
++++ b/packet.h	2016-09-29 10:22:26.000000000 +0200
+@@ -142,6 +142,10 @@ int	 ssh_packet_inc_alive_timeouts(struc
+ int	 ssh_packet_set_maxsize(struct ssh *, u_int);
+ u_int	 ssh_packet_get_maxsize(struct ssh *);
+ 
++/* for forced packet rekeying post auth */
++void	 packet_request_rekeying(void);
++int	 packet_authentication_state(const struct ssh *);
++
+ int	 ssh_packet_get_state(struct ssh *, struct sshbuf *);
+ int	 ssh_packet_set_state(struct ssh *, struct sshbuf *);
+ 
+@@ -155,6 +159,8 @@ time_t	 ssh_packet_get_rekey_timeout(str
+ 
+ void	*ssh_packet_get_input(struct ssh *);
+ void	*ssh_packet_get_output(struct ssh *);
++void	*ssh_packet_get_receive_context(struct ssh *);
++void	*ssh_packet_get_send_context(struct ssh *);
+ 
+ /* new API */
+ int	sshpkt_start(struct ssh *ssh, u_char type);
+--- a/progressmeter.c	2016-07-28 00:54:27.000000000 +0200
++++ b/progressmeter.c	2016-09-29 10:22:26.000000000 +0200
+@@ -69,6 +69,8 @@ static const char *file;	/* name of the 
+ static off_t start_pos;		/* initial position of transfer */
+ static off_t end_pos;		/* ending position of transfer */
+ static off_t cur_pos;		/* transfer position as of last refresh */
++static off_t last_pos;
++static off_t max_delta_pos = 0;
+ static volatile off_t *counter;	/* progress counter */
+ static long stalled;		/* how long we have been stalled */
+ static int bytes_per_second;	/* current speed in bytes per second */
+@@ -128,12 +130,17 @@ refresh_progress_meter(void)
+ 	int hours, minutes, seconds;
+ 	int i, len;
+ 	int file_len;
++	off_t delta_pos;
+ 
+ 	transferred = *counter - (cur_pos ? cur_pos : start_pos);
+ 	cur_pos = *counter;
+ 	now = monotime_double();
+ 	bytes_left = end_pos - cur_pos;
+ 
++	delta_pos = cur_pos - last_pos;
++	if (delta_pos > max_delta_pos)
++		max_delta_pos = delta_pos;
++
+ 	if (bytes_left > 0)
+ 		elapsed = now - last_update;
+ 	else {
+@@ -158,7 +165,7 @@ refresh_progress_meter(void)
+ 
+ 	/* filename */
+ 	buf[0] = '\0';
+-	file_len = win_size - 35;
++	file_len = win_size - 45;
+ 	if (file_len > 0) {
+ 		len = snprintf(buf, file_len + 1, "\r%s", file);
+ 		if (len < 0)
+@@ -188,6 +195,15 @@ refresh_progress_meter(void)
+ 	    (off_t)bytes_per_second);
+ 	strlcat(buf, "/s ", win_size);
+ 
++	/* instantaneous rate */
++	if (bytes_left > 0)
++		format_rate(buf + strlen(buf), win_size - strlen(buf),
++			    delta_pos);
++	else
++		format_rate(buf + strlen(buf), win_size - strlen(buf),
++			    max_delta_pos);
++	strlcat(buf, "/s ", win_size);
++
+ 	/* ETA */
+ 	if (!transferred)
+ 		stalled += elapsed;
+@@ -224,6 +240,7 @@ refresh_progress_meter(void)
+ 
+ 	atomicio(vwrite, STDOUT_FILENO, buf, win_size - 1);
+ 	last_update = now;
++	last_pos = cur_pos;
+ }
+ 
+ /*ARGSUSED*/
+--- a/readconf.c	2016-07-28 00:54:27.000000000 +0200
++++ b/readconf.c	2016-09-29 10:22:26.000000000 +0200
+@@ -66,6 +66,7 @@
+ #include "uidswap.h"
+ #include "myproposal.h"
+ #include "digest.h"
++#include "sshbuf.h"
+ 
+ /* Format of the configuration file:
+ 
+@@ -164,6 +165,8 @@ typedef enum {
+ 	oSendEnv, oControlPath, oControlMaster, oControlPersist,
+ 	oHashKnownHosts,
+ 	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
++	oNoneEnabled, oNoneSwitch,
++	oTcpRcvBufPoll, oTcpRcvBuf, oHPNDisabled, oHPNBufferSize,
+ 	oVisualHostKey,
+ 	oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
+ 	oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
+@@ -281,6 +284,8 @@ static struct {
+ 	{ "kexalgorithms", oKexAlgorithms },
+ 	{ "ipqos", oIPQoS },
+ 	{ "requesttty", oRequestTTY },
++	{ "noneenabled", oNoneEnabled },
++	{ "noneswitch", oNoneSwitch },
+ 	{ "proxyusefdpass", oProxyUseFdpass },
+ 	{ "canonicaldomains", oCanonicalDomains },
+ 	{ "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
+@@ -297,6 +302,11 @@ static struct {
+ 	{ "ignoreunknown", oIgnoreUnknown },
+ 	{ "proxyjump", oProxyJump },
+ 
++	{ "tcprcvbufpoll", oTcpRcvBufPoll },
++	{ "tcprcvbuf", oTcpRcvBuf },
++	{ "hpndisabled", oHPNDisabled },
++	{ "hpnbuffersize", oHPNBufferSize },
++
+ 	{ NULL, oBadOption }
+ };
+ 
+@@ -974,6 +984,38 @@ parse_time:
+ 		intptr = &options->check_host_ip;
+ 		goto parse_flag;
+ 
++	case oNoneEnabled:
++		intptr = &options->none_enabled;
++		goto parse_flag;
++
++	/*
++	 * We check to see if the command comes from the command
++	 * line or not. If it does then enable it otherwise fail.
++	 *  NONE should never be a default configuration.
++	 */
++	case oNoneSwitch:
++		if (strcmp(filename, "command-line") == 0) {
++			intptr = &options->none_switch;
++			goto parse_flag;
++		} else {
++			error("NoneSwitch is found in %.200s.\nYou may only use this configuration option from the command line", filename);
++			error("Continuing...");
++			debug("NoneSwitch directive found in %.200s.", filename);
++			return 0;
++		}
++
++	case oHPNDisabled:
++		intptr = &options->hpn_disabled;
++		goto parse_flag;
++
++	case oHPNBufferSize:
++		intptr = &options->hpn_buffer_size;
++		goto parse_int;
++
++	case oTcpRcvBufPoll:
++		intptr = &options->tcp_rcv_buf_poll;
++		goto parse_flag;
++
+ 	case oVerifyHostKeyDNS:
+ 		intptr = &options->verify_host_key_dns;
+ 		multistate_ptr = multistate_yesnoask;
+@@ -1166,6 +1208,10 @@ parse_int:
+ 		intptr = &options->connection_attempts;
+ 		goto parse_int;
+ 
++	case oTcpRcvBuf:
++		intptr = &options->tcp_rcv_buf;
++		goto parse_int;
++
+ 	case oCipher:
+ 		intptr = &options->cipher;
+ 		arg = strdelim(&s);
+@@ -1846,6 +1892,12 @@ initialize_options(Options * options)
+ 	options->ip_qos_interactive = -1;
+ 	options->ip_qos_bulk = -1;
+ 	options->request_tty = -1;
++	options->none_switch = -1;
++	options->none_enabled = -1;
++	options->hpn_disabled = -1;
++	options->hpn_buffer_size = -1;
++	options->tcp_rcv_buf_poll = -1;
++	options->tcp_rcv_buf = -1;
+ 	options->proxy_use_fdpass = -1;
+ 	options->ignored_unknown = NULL;
+ 	options->num_canonical_domains = 0;
+@@ -2009,6 +2061,30 @@ fill_default_options(Options * options)
+ 		options->server_alive_interval = 0;
+ 	if (options->server_alive_count_max == -1)
+ 		options->server_alive_count_max = 3;
++	if (options->none_switch == -1)
++		options->none_switch = 0;
++	if (options->none_enabled == -1)
++		options->none_enabled = 0;
++	if (options->hpn_disabled == -1)
++		options->hpn_disabled = 0;
++	if (options->hpn_buffer_size > -1) {
++		/* if a user tries to set the size to 0 set it to 1KB */
++		if (options->hpn_buffer_size == 0)
++			options->hpn_buffer_size = 1;
++		/* limit the buffer to SSHBUF_SIZE_MAX (currently 256MB) */
++		if (options->hpn_buffer_size > (SSHBUF_SIZE_MAX / 1024)) {
++			options->hpn_buffer_size = SSHBUF_SIZE_MAX;
++			debug("User requested buffer larger than 256MB. Request reverted to 256MB");
++		} else
++			options->hpn_buffer_size *= 1024;
++		debug("hpn_buffer_size set to %d", options->hpn_buffer_size);
++	}
++	if (options->tcp_rcv_buf == 0)
++		options->tcp_rcv_buf = 1;
++	if (options->tcp_rcv_buf > -1)
++		options->tcp_rcv_buf *=1024;
++	if (options->tcp_rcv_buf_poll == -1)
++		options->tcp_rcv_buf_poll = 1;
+ 	if (options->control_master == -1)
+ 		options->control_master = 0;
+ 	if (options->control_persist == -1) {
+--- a/readconf.h	2016-07-28 00:54:27.000000000 +0200
++++ b/readconf.h	2016-09-29 10:22:26.000000000 +0200
+@@ -57,6 +57,10 @@ typedef struct {
+ 	int     compression_level;	/* Compression level 1 (fast) to 9
+ 					 * (best). */
+ 	int     tcp_keep_alive;	/* Set SO_KEEPALIVE. */
++	int     tcp_rcv_buf; /* user switch to set tcp recv buffer */
++	int     tcp_rcv_buf_poll; /* Option to poll recv buf every window transfer */
++	int     hpn_disabled;    /* Switch to disable HPN buffer management */
++	int     hpn_buffer_size; /* User definable size for HPN buffer window */
+ 	int	ip_qos_interactive;	/* IP ToS/DSCP/class for interactive */
+ 	int	ip_qos_bulk;		/* IP ToS/DSCP/class for bulk traffic */
+ 	LogLevel log_level;	/* Level for logging. */
+@@ -118,7 +122,10 @@ typedef struct {
+ 
+ 	int	enable_ssh_keysign;
+ 	int64_t rekey_limit;
++	int     none_switch;    /* Use none cipher */
++	int     none_enabled;   /* Allow none to be used */
+ 	int	rekey_interval;
++
+ 	int	no_host_authentication_for_localhost;
+ 	int	identities_only;
+ 	int	server_alive_interval;
+--- a/sandbox-seccomp-filter.c	2016-07-28 00:54:27.000000000 +0200
++++ b/sandbox-seccomp-filter.c	2016-09-29 10:22:26.000000000 +0200
+@@ -147,6 +147,9 @@ static const struct sock_filter preauth_
+ #ifdef __NR_exit_group
+ 	SC_ALLOW(exit_group),
+ #endif
++#ifdef __NR_getpeername /* not defined on archs that go via socketcall(2) */
++	SC_ALLOW(getpeername),
++#endif
+ #ifdef __NR_getpgid
+ 	SC_ALLOW(getpgid),
+ #endif
+@@ -198,6 +201,9 @@ static const struct sock_filter preauth_
+ #ifdef __NR_sigprocmask
+ 	SC_ALLOW(sigprocmask),
+ #endif
++#ifdef __NR_socketcall
++	SC_ALLOW(socketcall),
++#endif
+ #ifdef __NR_time
+ 	SC_ALLOW(time),
+ #endif
+--- a/scp.c	2016-07-28 00:54:27.000000000 +0200
++++ b/scp.c	2016-09-29 10:22:26.000000000 +0200
+@@ -764,7 +764,7 @@ source(int argc, char **argv)
+ 	off_t i, statbytes;
+ 	size_t amt, nr;
+ 	int fd = -1, haderr, indx;
+-	char *last, *name, buf[2048], encname[PATH_MAX];
++	char *last, *name, buf[16384], encname[PATH_MAX];
+ 	int len;
+ 
+ 	for (indx = 0; indx < argc; ++indx) {
+@@ -932,7 +932,7 @@ sink(int argc, char **argv)
+ 	off_t size, statbytes;
+ 	unsigned long long ull;
+ 	int setimes, targisdir, wrerrno = 0;
+-	char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048];
++	char ch, *cp, *np, *targ, *why, *vect[1], buf[16384], visbuf[16384];
+ 	struct timeval tv[2];
+ 
+ #define	atime	tv[0]
+--- a/servconf.c	2016-09-29 10:22:25.000000000 +0200
++++ b/servconf.c	2016-09-29 10:22:26.000000000 +0200
+@@ -57,6 +57,7 @@
+ #include "auth.h"
+ #include "myproposal.h"
+ #include "digest.h"
++#include "sshbuf.h"
+ 
+ static void add_listen_addr(ServerOptions *, char *, int);
+ static void add_one_listen_addr(ServerOptions *, char *, int);
+@@ -165,6 +166,10 @@ initialize_server_options(ServerOptions 
+ 	options->authorized_principals_file = NULL;
+ 	options->authorized_principals_command = NULL;
+ 	options->authorized_principals_command_user = NULL;
++	options->none_enabled = -1;
++	options->tcp_rcv_buf_poll = -1;
++	options->hpn_disabled = -1;
++	options->hpn_buffer_size = -1;
+ 	options->ip_qos_interactive = -1;
+ 	options->ip_qos_bulk = -1;
+ 	options->version_addendum = NULL;
+@@ -196,6 +201,10 @@ void
+ fill_default_server_options(ServerOptions *options)
+ {
+ 	int i;
++	/* needed for hpn socket tests */
++	int sock;
++	int socksize;
++	int socksizelen = sizeof(int);
+ 
+ 	/* Portable-specific options */
+ 	if (options->use_pam == -1)
+@@ -341,6 +350,43 @@ fill_default_server_options(ServerOption
+ 	}
+ 	if (options->permit_tun == -1)
+ 		options->permit_tun = SSH_TUNMODE_NO;
++	if (options->none_enabled == -1)
++		options->none_enabled = 0;
++	if (options->hpn_disabled == -1)
++		options->hpn_disabled = 0;
++
++	if (options->hpn_buffer_size == -1) {
++		/* option not explicitly set. Now we have to figure out */
++		/* what value to use */
++		if (options->hpn_disabled == 1) {
++			options->hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT;
++		} else {
++			/* get the current RCV size and set it to that */
++			/*create a socket but don't connect it */
++			/* we use that the get the rcv socket size */
++			sock = socket(AF_INET, SOCK_STREAM, 0);
++			getsockopt(sock, SOL_SOCKET, SO_RCVBUF,
++				   &socksize, &socksizelen);
++			close(sock);
++			options->hpn_buffer_size = socksize;
++			debug("HPN Buffer Size: %d", options->hpn_buffer_size);
++		}
++	} else {
++		/* we have to do this in case the user sets both values in a contradictory */
++		/* manner. hpn_disabled overrrides hpn_buffer_size*/
++		if (options->hpn_disabled <= 0) {
++			if (options->hpn_buffer_size == 0)
++				options->hpn_buffer_size = 1;
++			/* limit the maximum buffer to SSHBUF_SIZE_MAX (currently 256MB) */
++			if (options->hpn_buffer_size > (SSHBUF_SIZE_MAX / 1024)) {
++				options->hpn_buffer_size = SSHBUF_SIZE_MAX;
++			} else {
++				options->hpn_buffer_size *= 1024;
++			}
++		} else
++			options->hpn_buffer_size = CHAN_TCP_WINDOW_DEFAULT;
++	}
++
+ 	if (options->ip_qos_interactive == -1)
+ 		options->ip_qos_interactive = IPTOS_LOWDELAY;
+ 	if (options->ip_qos_bulk == -1)
+@@ -415,6 +461,8 @@ typedef enum {
+ 	sPasswordAuthentication, sKbdInteractiveAuthentication,
+ 	sListenAddress, sAddressFamily,
+ 	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
++	sNoneEnabled,
++	sTcpRcvBufPoll, sHPNDisabled, sHPNBufferSize,
+ 	sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
+ 	sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive,
+ 	sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
+@@ -568,6 +616,10 @@ static struct {
+ 	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
+ 	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
+ 	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
++	{ "noneenabled", sNoneEnabled, SSHCFG_ALL },
++	{ "hpndisabled", sHPNDisabled, SSHCFG_ALL },
++	{ "hpnbuffersize", sHPNBufferSize, SSHCFG_ALL },
++	{ "tcprcvbufpoll", sTcpRcvBufPoll, SSHCFG_ALL },
+ 	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
+ 	{ "ipqos", sIPQoS, SSHCFG_ALL },
+ 	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
+@@ -606,6 +658,7 @@ parse_token(const char *cp, const char *
+ 
+ 	for (i = 0; keywords[i].name; i++)
+ 		if (strcasecmp(cp, keywords[i].name) == 0) {
++			debug("Config token is %s", keywords[i].name);
+ 			*flags = keywords[i].flags;
+ 			return keywords[i].opcode;
+ 		}
+@@ -1185,10 +1238,27 @@ process_server_config_line(ServerOptions
+ 			*intptr = value;
+ 		break;
+ 
++
++	case sTcpRcvBufPoll:
++		intptr = &options->tcp_rcv_buf_poll;
++		goto parse_flag;
++
++	case sHPNDisabled:
++		intptr = &options->hpn_disabled;
++		goto parse_flag;
++
++	case sHPNBufferSize:
++		intptr = &options->hpn_buffer_size;
++		goto parse_int;
++
+ 	case sIgnoreUserKnownHosts:
+ 		intptr = &options->ignore_user_known_hosts;
+ 		goto parse_flag;
+ 
++	case sNoneEnabled:
++		intptr = &options->none_enabled;
++		goto parse_flag;
++
+ 	case sRhostsRSAAuthentication:
+ 		intptr = &options->rhosts_rsa_authentication;
+ 		goto parse_flag;
+--- a/servconf.h	2016-07-28 00:54:27.000000000 +0200
++++ b/servconf.h	2016-09-29 10:22:26.000000000 +0200
+@@ -172,6 +172,11 @@ typedef struct {
+ 	char   *adm_forced_command;
+ 
+ 	int	use_pam;		/* Enable auth via PAM */
++        int     tcp_rcv_buf_poll;       /* poll tcp rcv window in autotuning kernels*/
++	int	hpn_disabled;		/* disable hpn functionality. false by default */
++	int	hpn_buffer_size;	/* set the hpn buffer size - default 3MB */
++
++	int	none_enabled;		/* Enable NONE cipher switch */
+ 
+ 	int	permit_tun;
+ 
+--- a/serverloop.c	2016-07-28 00:54:27.000000000 +0200
++++ b/serverloop.c	2016-09-29 10:22:26.000000000 +0200
+@@ -93,10 +93,10 @@ static int fdin;		/* Descriptor for stdi
+ static int fdout;		/* Descriptor for stdout (for reading);
+ 				   May be same number as fdin. */
+ static int fderr;		/* Descriptor for stderr.  May be -1. */
+-static long stdin_bytes = 0;	/* Number of bytes written to stdin. */
+-static long stdout_bytes = 0;	/* Number of stdout bytes sent to client. */
+-static long stderr_bytes = 0;	/* Number of stderr bytes sent to client. */
+-static long fdout_bytes = 0;	/* Number of stdout bytes read from program. */
++static u_long stdin_bytes = 0;	/* Number of bytes written to stdin. */
++static u_long stdout_bytes = 0;	/* Number of stdout bytes sent to client. */
++static u_long stderr_bytes = 0;	/* Number of stderr bytes sent to client. */
++static u_long fdout_bytes = 0;	/* Number of stdout bytes read from program. */
+ static int stdin_eof = 0;	/* EOF message received from client. */
+ static int fdout_eof = 0;	/* EOF encountered reading from fdout. */
+ static int fderr_eof = 0;	/* EOF encountered readung from fderr. */
+@@ -121,6 +121,20 @@ static volatile sig_atomic_t received_si
+ static void server_init_dispatch(void);
+ 
+ /*
++ * Returns current time in seconds from Jan 1, 1970 with the maximum
++ * available resolution.
++ */
++
++static double
++get_current_time(void)
++{
++	struct timeval tv;
++	gettimeofday(&tv, NULL);
++	return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
++}
++
++
++/*
+  * we write to this pipe if a SIGCHLD is caught in order to avoid
+  * the race between select() and child_terminated
+  */
+@@ -421,6 +435,7 @@ process_input(fd_set *readset)
+ 		} else {
+ 			/* Buffer any received data. */
+ 			packet_process_incoming(buf, len);
++			fdout_bytes += len;
+ 		}
+ 	}
+ 	if (compat20)
+@@ -443,6 +458,7 @@ process_input(fd_set *readset)
+ 		} else {
+ 			buffer_append(&stdout_buffer, buf, len);
+ 			fdout_bytes += len;
++			debug("FD out now: %ld", fdout_bytes);
+ 		}
+ 	}
+ 	/* Read and buffer any available stderr data from the program. */
+@@ -510,7 +526,7 @@ process_output(fd_set *writeset)
+ 	}
+ 	/* Send any buffered packet data to the client. */
+ 	if (FD_ISSET(connection_out, writeset))
+-		packet_write_poll();
++		stdin_bytes += packet_write_poll();
+ }
+ 
+ /*
+@@ -824,11 +840,13 @@ void
+ server_loop2(Authctxt *authctxt)
+ {
+ 	fd_set *readset = NULL, *writeset = NULL;
++	double start_time, total_time;
+ 	int max_fd;
+ 	u_int nalloc = 0;
+ 	u_int64_t rekey_timeout_ms = 0;
+ 
+ 	debug("Entering interactive session for SSH2.");
++	start_time = get_current_time();
+ 
+ 	mysignal(SIGCHLD, sigchld_handler);
+ 	child_terminated = 0;
+@@ -887,6 +905,11 @@ server_loop2(Authctxt *authctxt)
+ 
+ 	/* free remaining sessions, e.g. remove wtmp entries */
+ 	session_destroy_all(NULL);
++	total_time = get_current_time() - start_time;
++	logit("SSH: Server;LType: Throughput;Remote: %s-%d;IN: %lu;OUT: %lu;Duration: %.1f;tPut_in: %.1f;tPut_out: %.1f",
++	      ssh_remote_ipaddr(active_state), ssh_remote_port(active_state),
++	      stdin_bytes, fdout_bytes, total_time, stdin_bytes / total_time,
++	      fdout_bytes / total_time);
+ }
+ 
+ static int
+@@ -1045,8 +1068,12 @@ server_request_tun(void)
+ 	sock = tun_open(tun, mode);
+ 	if (sock < 0)
+ 		goto done;
++	if (options.hpn_disabled)
+ 	c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1,
+ 	    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
++	else
++		c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1,
++		    options.hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
+ 	c->datagram = 1;
+ #if defined(SSH_TUN_FILTER)
+ 	if (mode == SSH_TUNMODE_POINTOPOINT)
+@@ -1082,6 +1109,8 @@ server_request_session(void)
+ 	c = channel_new("session", SSH_CHANNEL_LARVAL,
+ 	    -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT,
+ 	    0, "server-session", 1);
++	if ((options.tcp_rcv_buf_poll) && (!options.hpn_disabled))
++		c->dynamic_window = 1;
+ 	if (session_open(the_authctxt, c->self) != 1) {
+ 		debug("session open failed, free channel %d", c->self);
+ 		channel_free(c);
+--- a/session.c	2016-07-28 00:54:27.000000000 +0200
++++ b/session.c	2016-09-29 10:22:26.000000000 +0200
+@@ -222,6 +222,7 @@ auth_input_request_forwarding(struct pas
+ 		goto authsock_err;
+ 
+ 	/* Allocate a channel for the authentication agent socket. */
++	/* this shouldn't matter if its hpn or not - cjr */
+ 	nc = channel_new("auth socket",
+ 	    SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
+ 	    CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
+@@ -2361,10 +2362,16 @@ session_set_fds(Session *s, int fdin, in
+ 	 */
+ 	if (s->chanid == -1)
+ 		fatal("no channel for session %d", s->self);
++	if (options.hpn_disabled)
+ 	channel_set_fds(s->chanid,
+ 	    fdout, fdin, fderr,
+ 	    ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
+ 	    1, is_tty, CHAN_SES_WINDOW_DEFAULT);
++	else
++		channel_set_fds(s->chanid,
++		    fdout, fdin, fderr,
++		    ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
++		    1, is_tty, options.hpn_buffer_size);
+ }
+ 
+ /*
+--- a/sftp.1	2016-07-28 00:54:27.000000000 +0200
++++ b/sftp.1	2016-09-29 10:22:26.000000000 +0200
+@@ -266,7 +266,8 @@ diagnostic messages from
+ Specify how many requests may be outstanding at any one time.
+ Increasing this may slightly improve file transfer speed
+ but will increase memory usage.
+-The default is 64 outstanding requests.
++The default is 256 outstanding requests providing for 8MB
++of outstanding data with a 32KB buffer.
+ .It Fl r
+ Recursively copy entire directories when uploading and downloading.
+ Note that
+--- a/sftp.c	2016-07-28 00:54:27.000000000 +0200
++++ b/sftp.c	2016-09-29 10:22:26.000000000 +0200
+@@ -73,7 +73,7 @@ typedef void EditLine;
+ #include "sftp-client.h"
+ 
+ #define DEFAULT_COPY_BUFLEN	32768	/* Size of buffer for up/download */
+-#define DEFAULT_NUM_REQUESTS	64	/* # concurrent outstanding requests */
++#define DEFAULT_NUM_REQUESTS	256	/* # concurrent outstanding requests */
+ 
+ /* File to read commands from */
+ FILE* infile;
+--- a/ssh.c	2016-07-28 00:54:27.000000000 +0200
++++ b/ssh.c	2016-09-29 10:22:26.000000000 +0200
+@@ -910,6 +910,10 @@ main(int ac, char **av)
+ 			break;
+ 		case 'T':
+ 			options.request_tty = REQUEST_TTY_NO;
++			/* ensure that the user doesn't try to backdoor a */
++			/* null cipher switch on an interactive session */
++			/* so explicitly disable it no matter what */
++			options.none_switch=0;
+ 			break;
+ 		case 'o':
+ 			line = xstrdup(optarg);
+@@ -1502,6 +1506,8 @@ control_persist_detach(void)
+ 	setproctitle("%s [mux]", options.control_path);
+ }
+ 
++extern const EVP_CIPHER *evp_aes_ctr_mt(void);
++
+ /* Do fork() after authentication. Used by "ssh -f" */
+ static void
+ fork_postauth(void)
+@@ -1895,6 +1901,78 @@ ssh_session2_setup(int id, int success, 
+ 	    NULL, fileno(stdin), &command, environ);
+ }
+ 
++static void
++hpn_options_init(void)
++{
++	/*
++	 * We need to check to see if what they want to do about buffer
++	 * sizes here. In a hpn to nonhpn connection we want to limit
++	 * the window size to something reasonable in case the far side
++	 * has the large window bug. In hpn to hpn connection we want to
++	 * use the max window size but allow the user to override it
++	 * lastly if they disabled hpn then use the ssh std window size.
++	 *
++	 * So why don't we just do a getsockopt() here and set the
++	 * ssh window to that? In the case of a autotuning receive
++	 * window the window would get stuck at the initial buffer
++	 * size generally less than 96k. Therefore we need to set the
++	 * maximum ssh window size to the maximum hpn buffer size
++	 * unless the user has specifically set the tcprcvbufpoll
++	 * to no. In which case we *can* just set the window to the
++	 * minimum of the hpn buffer size and tcp receive buffer size.
++	 */
++
++	if (tty_flag)
++		options.hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT;
++	else
++		options.hpn_buffer_size = 2 * 1024 * 1024;
++
++	if (datafellows & SSH_BUG_LARGEWINDOW) {
++		debug("HPN to Non-HPN Connection");
++	} else {
++		int sock, socksize;
++		socklen_t socksizelen;
++		if (options.tcp_rcv_buf_poll <= 0) {
++			sock = socket(AF_INET, SOCK_STREAM, 0);
++			socksizelen = sizeof(socksize);
++			getsockopt(sock, SOL_SOCKET, SO_RCVBUF,
++				   &socksize, &socksizelen);
++			close(sock);
++			debug("socksize %d", socksize);
++			options.hpn_buffer_size = socksize;
++			debug("HPNBufferSize set to TCP RWIN: %d", options.hpn_buffer_size);
++		} else {
++			if (options.tcp_rcv_buf > 0) {
++				/*
++				 * Create a socket but don't connect it:
++				 * we use that the get the rcv socket size
++				 */
++				sock = socket(AF_INET, SOCK_STREAM, 0);
++				/*
++				 * If they are using the tcp_rcv_buf option,
++				 * attempt to set the buffer size to that.
++				 */
++				if (options.tcp_rcv_buf) {
++					socksizelen = sizeof(options.tcp_rcv_buf);
++					setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
++						   &options.tcp_rcv_buf, socksizelen);
++				}
++				socksizelen = sizeof(socksize);
++				getsockopt(sock, SOL_SOCKET, SO_RCVBUF,
++					   &socksize, &socksizelen);
++				close(sock);
++				debug("socksize %d", socksize);
++				options.hpn_buffer_size = socksize;
++				debug("HPNBufferSize set to user TCPRcvBuf: %d", options.hpn_buffer_size);
++			}
++		}
++	}
++
++	debug("Final hpn_buffer_size = %d", options.hpn_buffer_size);
++
++	channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size);
++}
++
+ /* open new channel for a session */
+ static int
+ ssh_session2_open(void)
+@@ -1921,9 +1999,11 @@ ssh_session2_open(void)
+ 	if (!isatty(err))
+ 		set_nonblock(err);
+ 
+-	window = CHAN_SES_WINDOW_DEFAULT;
++	window = options.hpn_buffer_size;
++
+ 	packetmax = CHAN_SES_PACKET_DEFAULT;
+ 	if (tty_flag) {
++		window = CHAN_SES_WINDOW_DEFAULT;
+ 		window >>= 1;
+ 		packetmax >>= 1;
+ 	}
+@@ -1932,6 +2012,10 @@ ssh_session2_open(void)
+ 	    window, packetmax, CHAN_EXTENDED_WRITE,
+ 	    "client-session", /*nonblock*/0);
+ 
++	if ((options.tcp_rcv_buf_poll > 0) && (!options.hpn_disabled)) {
++		c->dynamic_window = 1;
++		debug("Enabled Dynamic Window Scaling");
++	}
+ 	debug3("ssh_session2_open: channel_new: %d", c->self);
+ 
+ 	channel_send_open(c->self);
+@@ -1947,6 +2031,13 @@ ssh_session2(void)
+ {
+ 	int id = -1;
+ 
++	/*
++	 * We need to initialize this early because the forwarding logic below
++	 * might open channels that use the hpn buffer sizes.  We can't send a
++	 * window of -1 (the default) to the server as it breaks things.
++	 */
++	hpn_options_init();
++
+ 	/* XXX should be pre-session */
+ 	if (!options.control_persist)
+ 		ssh_init_stdio_forwarding();
+--- a/sshbuf.h	2016-07-28 00:54:27.000000000 +0200
++++ b/sshbuf.h	2016-09-29 10:22:26.000000000 +0200
+@@ -28,7 +28,7 @@
+ # endif /* OPENSSL_HAS_ECC */
+ #endif /* WITH_OPENSSL */
+ 
+-#define SSHBUF_SIZE_MAX		0x8000000	/* Hard maximum size */
++#define SSHBUF_SIZE_MAX		0xF000000	/* Hard maximum size 256MB */
+ #define SSHBUF_REFS_MAX		0x100000	/* Max child buffers */
+ #define SSHBUF_MAX_BIGNUM	(16384 / 8)	/* Max bignum *bytes* */
+ #define SSHBUF_MAX_ECPOINT	((528 * 2 / 8) + 1) /* Max EC point *bytes* */
+--- a/sshconnect.c	2016-07-28 00:54:27.000000000 +0200
++++ b/sshconnect.c	2016-09-29 10:22:26.000000000 +0200
+@@ -268,6 +268,31 @@ ssh_kill_proxy_command(void)
+ }
+ 
+ /*
++ * Set TCP receive buffer if requested.
++ * Note: tuning needs to happen after the socket is
++ * created but before the connection happens
++ * so winscale is negotiated properly -cjr
++ */
++static void
++ssh_set_socket_recvbuf(int sock)
++{
++	void *buf = (void *)&options.tcp_rcv_buf;
++	int sz = sizeof(options.tcp_rcv_buf);
++	int socksize;
++	int socksizelen = sizeof(int);
++
++	debug("setsockopt Attempting to set SO_RCVBUF to %d", options.tcp_rcv_buf);
++	if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, buf, sz) >= 0) {
++	  getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &socksize, &socksizelen);
++	  debug("setsockopt SO_RCVBUF: %.100s %d", strerror(errno), socksize);
++	}
++	else
++		error("Couldn't set socket receive buffer to %d: %.100s",
++		    options.tcp_rcv_buf, strerror(errno));
++}
++
++
++/*
+  * Creates a (possibly privileged) socket for use as the ssh connection.
+  */
+ static int
+@@ -283,6 +308,9 @@ ssh_create_socket(int privileged, struct
+ 	}
+ 	fcntl(sock, F_SETFD, FD_CLOEXEC);
+ 
++	if (options.tcp_rcv_buf > 0)
++		ssh_set_socket_recvbuf(sock);
++
+ 	/* Bind the socket to an alternative local IP address */
+ 	if (options.bind_address == NULL && !privileged)
+ 		return sock;
+@@ -527,10 +555,10 @@ send_client_banner(int connection_out, i
+ 	/* Send our own protocol version identification. */
+ 	if (compat20) {
+ 		xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n",
+-		    PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION);
++		    PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_RELEASE);
+ 	} else {
+ 		xasprintf(&client_version_string, "SSH-%d.%d-%.100s\n",
+-		    PROTOCOL_MAJOR_1, minor1, SSH_VERSION);
++		    PROTOCOL_MAJOR_1, minor1, SSH_RELEASE);
+ 	}
+ 	if (atomicio(vwrite, connection_out, client_version_string,
+ 	    strlen(client_version_string)) != strlen(client_version_string))
+--- a/sshconnect2.c	2016-07-28 00:54:27.000000000 +0200
++++ b/sshconnect2.c	2016-09-29 10:22:26.000000000 +0200
+@@ -83,6 +83,13 @@ extern char *server_version_string;
+ extern Options options;
+ 
+ /*
++ * tty_flag is set in ssh.c. Use this in ssh_userauth2:
++ * if it is set, then prevent the switch to the null cipher.
++ */
++
++extern int tty_flag;
++
++/*
+  * SSH2 key exchange
+  */
+ 
+@@ -154,6 +161,8 @@ order_hostkeyalgs(char *host, struct soc
+ 	return ret;
+ }
+ 
++static char *myproposal[PROPOSAL_MAX];
++static const char *myproposal_default[PROPOSAL_MAX] = { KEX_CLIENT };
+ void
+ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
+ {
+@@ -162,6 +171,8 @@ ssh_kex2(char *host, struct sockaddr *ho
+ 	struct kex *kex;
+ 	int r;
+ 
++	memcpy(&myproposal, &myproposal_default, sizeof(myproposal));
++
+ 	xxx_host = host;
+ 	xxx_hostaddr = hostaddr;
+ 
+@@ -404,6 +415,44 @@ ssh_userauth2(const char *local_user, co
+ 	pubkey_cleanup(&authctxt);
+ 	ssh_dispatch_range(ssh, SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL);
+ 
++	/*
++	 * If the user wants to use the none cipher, do it post authentication
++	 * and only if the right conditions are met -- both of the NONE commands
++	 * must be true and there must be no tty allocated.
++	 */
++	if ((options.none_switch == 1) && (options.none_enabled == 1)) {
++		if (!tty_flag) { /* no null on tty sessions */
++			debug("Requesting none rekeying...");
++			memcpy(&myproposal, &myproposal_default, sizeof(myproposal));
++			myproposal[PROPOSAL_ENC_ALGS_STOC] = "none";
++			myproposal[PROPOSAL_ENC_ALGS_CTOS] = "none";
++			kex_prop2buf(active_state->kex->my, myproposal);
++			packet_request_rekeying();
++			fprintf(stderr, "WARNING: ENABLED NONE CIPHER\n");
++		} else {
++			/* requested NONE cipher when in a tty */
++			debug("Cannot switch to NONE cipher with tty allocated");
++			fprintf(stderr, "NONE cipher switch disabled when a TTY is allocated\n");
++		}
++	}
++
++#ifdef WITH_OPENSSL
++	/* if we are using aes-ctr there can be issues in either a fork or sandbox
++	 * so the initial aes-ctr is defined to point to the original single process
++	 * evp. After authentication we'll be past the fork and the sandboxed privsep
++	 * so we repoint the define to the multithreaded evp. To start the threads we
++	 * then force a rekey
++	 */
++	struct sshcipher_ctx *ccsend = ssh_packet_get_send_context(active_state);
++
++	/* only do this for the ctr cipher. otherwise gcm mode breaks. Don't know why though */
++	if (strstr(cipher_return_name(ccsend->cipher), "ctr")) {
++		debug("Single to Multithread CTR cipher swap - client request");
++		cipher_reset_multithreaded();
++		packet_request_rekeying();
++	}
++#endif
++
+ 	debug("Authentication succeeded (%s).", authctxt.method->name);
+ }
+ 
+--- a/sshd.c	2016-09-29 10:22:25.000000000 +0200
++++ b/sshd.c	2016-09-29 10:24:06.000000000 +0200
+@@ -432,7 +432,7 @@ sshd_exchange_identification(struct ssh 
+ 	}
+ 
+ 	xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s",
+-	    major, minor, SSH_VERSION,
++	    major, minor, SSH_RELEASE,
+ 	    *options.version_addendum == '\0' ? "" : " ",
+ 	    options.version_addendum, newline);
+ 
+@@ -487,6 +487,9 @@ sshd_exchange_identification(struct ssh 
+ 	}
+ 	debug("Client protocol version %d.%d; client software version %.100s",
+ 	    remote_major, remote_minor, remote_version);
++	logit("SSH: Server;Ltype: Version;Remote: %s-%d;Protocol: %d.%d;Client: %.100s",
++	      ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
++	    remote_major, remote_minor, remote_version);
+ 
+ 	ssh->compat = compat_datafellows(remote_version);
+ 
+@@ -1184,6 +1187,8 @@ server_listen(void)
+ 	int ret, listen_sock, on = 1;
+ 	struct addrinfo *ai;
+ 	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
++	int socksize;
++	int socksizelen = sizeof(int);
+ 
+ 	for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
+ 		if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+@@ -1224,6 +1229,11 @@ server_listen(void)
+ 
+ 		debug("Bind to port %s on %s.", strport, ntop);
+ 
++		getsockopt(listen_sock, SOL_SOCKET, SO_RCVBUF,
++				   &socksize, &socksizelen);
++		debug("Server TCP RWIN socket size: %d", socksize);
++		debug("HPN Buffer Size: %d", options.hpn_buffer_size);
++
+ 		/* Bind the socket to the desired port. */
+ 		if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+ 			error("Bind to port %s on %s failed: %.200s.",
+@@ -1765,6 +1775,13 @@ main(int ac, char **av)
+ 	/* Fill in default values for those options not explicitly set. */
+ 	fill_default_server_options(&options);
+ 
++	if (options.none_enabled == 1) {
++		char *old_ciphers = options.ciphers;
++
++		xasprintf(&options.ciphers, "%s,none", old_ciphers);
++		free(old_ciphers);
++	}
++
+ 	/* challenge-response is implemented via keyboard interactive */
+ 	if (options.challenge_response_authentication)
+ 		options.kbd_interactive_authentication = 1;
+@@ -2214,6 +2231,9 @@ main(int ac, char **av)
+ 	    remote_ip, remote_port, laddr,  ssh_local_port(ssh));
+ 	free(laddr);
+ 
++	/* set the HPN options for the child */
++	channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size);
++
+ 	/*
+ 	 * We don't want to listen forever unless the other side
+ 	 * successfully authenticates itself.  So we set up an alarm which is
+@@ -2328,6 +2348,24 @@ main(int ac, char **av)
+ 		notify_hostkeys(active_state);
+ 
+ 	/* Start session. */
++
++#ifdef WITH_OPENSSL
++	/* if we are using aes-ctr there can be issues in either a fork or sandbox
++	 * so the initial aes-ctr is defined to point ot the original single process
++	 * evp. After authentication we'll be past the fork and the sandboxed privsep
++	 * so we repoint the define to the multithreaded evp. To start the threads we
++	 * then force a rekey
++	 */
++	struct sshcipher_ctx *ccsend = ssh_packet_get_send_context(active_state);
++
++	/* only rekey if necessary. If we don't do this gcm mode cipher breaks */
++	if (strstr(cipher_return_name(ccsend->cipher), "ctr")) {
++		debug("Single to Multithreaded CTR cipher swap - server request");
++		cipher_reset_multithreaded();
++		packet_request_rekeying();
++	}
++#endif
++
+ 	do_authenticated(authctxt);
+ 
+ 	/* The connection has been terminated. */
+@@ -2613,6 +2651,9 @@ do_ssh2_kex(void)
+ 	struct kex *kex;
+ 	int r;
+ 
++	if (options.none_enabled == 1)
++		debug("WARNING: None cipher enabled");
++
+ 	myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
+ 	    options.kex_algorithms);
+ 	myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(
+--- a/sshd_config	2016-07-28 00:54:27.000000000 +0200
++++ b/sshd_config	2016-09-29 10:22:26.000000000 +0200
+@@ -124,6 +124,20 @@ AuthorizedKeysFile	.ssh/authorized_keys
+ # override default of no subsystems
+ Subsystem	sftp	/usr/libexec/sftp-server
+ 
++# the following are HPN related configuration options
++# tcp receive buffer polling. disable in non autotuning kernels
++#TcpRcvBufPoll yes
++
++# disable hpn performance boosts
++#HPNDisabled no
++
++# buffer size for hpn to non-hpn connections
++#HPNBufferSize 2048
++
++
++# allow the use of the none cipher
++#NoneEnabled no
++
+ # Example of overriding settings on a per-user basis
+ #Match User anoncvs
+ #	X11Forwarding no
+--- a/version.h	2016-07-28 00:54:27.000000000 +0200
++++ b/version.h	2016-09-29 10:22:26.000000000 +0200
+@@ -3,4 +3,5 @@
+ #define SSH_VERSION	"OpenSSH_7.3"
+ 
+ #define SSH_PORTABLE	"p1"
+-#define SSH_RELEASE	SSH_VERSION SSH_PORTABLE
++#define SSH_HPN		"-hpn14v11"
++#define SSH_RELEASE	SSH_VERSION SSH_PORTABLE SSH_HPN

Modified: trunk/dports/net/openssh/files/pam.patch
===================================================================
--- trunk/dports/net/openssh/files/pam.patch	2016-09-29 13:44:26 UTC (rev 153359)
+++ trunk/dports/net/openssh/files/pam.patch	2016-09-29 13:49:14 UTC (rev 153360)
@@ -1,5 +1,5 @@
---- a/servconf.c	2016-02-26 04:40:04.000000000 +0100
-+++ b/servconf.c	2016-02-29 19:48:25.000000000 +0100
+--- a/servconf.c	2016-07-28 00:54:27.000000000 +0200
++++ b/servconf.c	2016-09-29 06:57:25.000000000 +0200
 @@ -199,7 +199,7 @@ fill_default_server_options(ServerOption
  
  	/* Portable-specific options */

Modified: trunk/dports/net/openssh/files/patch-sandbox-darwin.c-apple-sandbox-named-external.diff
===================================================================
--- trunk/dports/net/openssh/files/patch-sandbox-darwin.c-apple-sandbox-named-external.diff	2016-09-29 13:44:26 UTC (rev 153359)
+++ trunk/dports/net/openssh/files/patch-sandbox-darwin.c-apple-sandbox-named-external.diff	2016-09-29 13:49:14 UTC (rev 153360)
@@ -1,5 +1,5 @@
---- a/sandbox-darwin.c	2015-08-21 06:49:03.000000000 +0200
-+++ b/sandbox-darwin.c	2015-10-24 04:41:19.000000000 +0200
+--- a/sandbox-darwin.c	2016-07-28 00:54:27.000000000 +0200
++++ b/sandbox-darwin.c	2016-09-29 06:57:39.000000000 +0200
 @@ -62,8 +62,16 @@ ssh_sandbox_child(struct ssh_sandbox *bo
  	struct rlimit rl_zero;
  

Modified: trunk/dports/net/openssh/files/patch-sshd.c-apple-sandbox-named-external.diff
===================================================================
--- trunk/dports/net/openssh/files/patch-sshd.c-apple-sandbox-named-external.diff	2016-09-29 13:44:26 UTC (rev 153359)
+++ trunk/dports/net/openssh/files/patch-sshd.c-apple-sandbox-named-external.diff	2016-09-29 13:49:14 UTC (rev 153360)
@@ -1,6 +1,6 @@
---- a/sshd.c	2016-02-29 19:48:45.000000000 +0100
-+++ b/sshd.c	2016-02-29 20:10:32.000000000 +0100
-@@ -713,10 +713,17 @@ privsep_preauth(Authctxt *authctxt)
+--- a/sshd.c	2016-07-28 00:54:27.000000000 +0200
++++ b/sshd.c	2016-09-29 06:57:45.000000000 +0200
+@@ -719,10 +719,17 @@ privsep_preauth(Authctxt *authctxt)
  		/* Arrange for logging to be sent to the monitor */
  		set_log_handler(mm_log_handler, pmonitor);
  

Added: trunk/dports/net/openssh/files/slogin
===================================================================
--- trunk/dports/net/openssh/files/slogin	                        (rev 0)
+++ trunk/dports/net/openssh/files/slogin	2016-09-29 13:49:14 UTC (rev 153360)
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+echo "WARNING: the 'slogin' binary is deprecated, please use the 'ssh' binary instead." >&2
+
+exec "@@PREFIX@@/bin/ssh" "$@"
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/macports-changes/attachments/20160929/a176d4fc/attachment-0001.html>


More information about the macports-changes mailing list