ellert pushed to gsi-openssh (f22). "Based on openssh-6.8p1-4.fc22"

notifications at fedoraproject.org notifications at fedoraproject.org
Tue Apr 14 09:52:01 UTC 2015


>From 04aef646ab7de9bcb4738db00e9d26febd5f0875 Mon Sep 17 00:00:00 2001
From: Mattias Ellert <mattias.ellert at fysast.uu.se>
Date: Tue, 14 Apr 2015 11:49:37 +0200
Subject: Based on openssh-6.8p1-4.fc22


diff --git a/gsi-openssh.spec b/gsi-openssh.spec
index 7e30efa..3a386ed 100644
--- a/gsi-openssh.spec
+++ b/gsi-openssh.spec
@@ -8,6 +8,8 @@
 %global WITH_SELINUX 0
 %endif
 
+%global _hardened_build 1
+
 # OpenSSH privilege separation requires a user & group ID
 %global sshd_uid    74
 %global sshd_gid    74
@@ -28,8 +30,8 @@
 # Do we want LDAP support
 %global ldap 1
 
-%global openssh_ver 6.6.1p1
-%global openssh_rel 5
+%global openssh_ver 6.8p1
+%global openssh_rel 1
 
 Summary: An implementation of the SSH protocol with GSI authentication
 Name: gsi-openssh
@@ -38,8 +40,7 @@ Release: %{openssh_rel}%{?dist}
 Provides: gsissh = %{version}-%{release}
 Obsoletes: gsissh < 5.8p2-2
 URL: http://www.openssh.com/portable.html
-# Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz
-Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-6.6p1.tar.gz
+Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz
 Source2: gsisshd.pam
 Source7: gsisshd.sysconfig
 Source9: gsisshd at .service
@@ -51,9 +52,7 @@ Source14: gsisshd.tmpfiles
 Source99: README.sshd-and-gsisshd
 
 #?
-Patch100: openssh-6.6.1p1-coverity.patch
-#https://bugzilla.mindrot.org/show_bug.cgi?id=1872
-Patch101: openssh-6.6p1-fingerprint.patch
+Patch100: openssh-6.7p1-coverity.patch
 #https://bugzilla.mindrot.org/show_bug.cgi?id=1894
 #https://bugzilla.redhat.com/show_bug.cgi?id=735889
 Patch102: openssh-5.8p1-getaddrinfo.patch
@@ -61,10 +60,9 @@ Patch102: openssh-5.8p1-getaddrinfo.patch
 Patch103: openssh-5.8p1-packet.patch
 
 #https://bugzilla.mindrot.org/show_bug.cgi?id=1402
-Patch200: openssh-6.6p1-audit.patch
 # https://bugzilla.redhat.com/show_bug.cgi?id=1171248
 # record pfs= field in CRYPTO_SESSION audit event
-Patch201: openssh-6.6.1p1-audit-pfs.patch
+Patch200: openssh-6.7p1-audit.patch
 
 #https://bugzilla.mindrot.org/show_bug.cgi?id=1641 (WONTFIX)
 Patch400: openssh-6.6p1-role-mls.patch
@@ -72,7 +70,7 @@ Patch400: openssh-6.6p1-role-mls.patch
 Patch404: openssh-6.6p1-privsep-selinux.patch
 
 #?-- unwanted child :(
-Patch501: openssh-6.6p1-ldap.patch
+Patch501: openssh-6.7p1-ldap.patch
 #?
 Patch502: openssh-6.6p1-keycat.patch
 
@@ -86,21 +84,15 @@ Patch604: openssh-6.6p1-keyperm.patch
 Patch606: openssh-5.9p1-ipv6man.patch
 #?
 Patch607: openssh-5.8p2-sigpipe.patch
-#?
-Patch608: openssh-6.1p1-askpass-ld.patch
 #https://bugzilla.mindrot.org/show_bug.cgi?id=1789
 Patch609: openssh-5.5p1-x11.patch
 
 #?
-Patch700: openssh-6.6p1-fips.patch
-#?
-# drop? Patch701: openssh-5.6p1-exit-deadlock.patch
+Patch700: openssh-6.7p1-fips.patch
 #?
 Patch702: openssh-5.1p1-askpass-progress.patch
 #?
 Patch703: openssh-4.3p2-askpass-grab-info.patch
-# https://bugzilla.redhat.com/show_bug.cgi?id=205842
-# drop? Patch704: openssh-5.9p1-edns.patch
 #?
 Patch706: openssh-6.6.1p1-localdomain.patch
 #https://bugzilla.mindrot.org/show_bug.cgi?id=1635 (WONTFIX)
@@ -115,6 +107,8 @@ Patch711: openssh-6.6p1-log-usepam-no.patch
 Patch712: openssh-6.3p1-ctr-evp-fast.patch
 # add cavs test binary for the aes-ctr
 Patch713: openssh-6.6p1-ctr-cavstest.patch
+# add SSH KDF CAVS test driver
+Patch714: openssh-6.7p1-kdf-cavs.patch
 
 #http://www.sxw.org.uk/computing/patches/openssh.html
 #changed cache storage type - #848228
@@ -133,16 +127,6 @@ Patch902: openssh-6.3p1-krb5-use-default_ccache_name.patch
 Patch905: openssh-6.4p1-legacy-ssh-copy-id.patch
 # Use tty allocation for a remote scp (#985650)
 Patch906: openssh-6.4p1-fromto-remote.patch
-# Try CLOCK_BOOTTIME with fallback (#1091992)
-Patch907: openssh-6.4p1-CLOCK_BOOTTIME.patch
-# Prevents a server from skipping SSHFP lookup and forcing a new-hostkey
-# dialog by offering only certificate keys. (#1081338)
-Patch908: openssh-6.6p1-CVE-2014-2653.patch
-# OpenSSH 6.5 and 6.6 sometimes encode a value used in the curve25519 key exchange incorrectly
-# Disable the curve25519 KEX when speaking to OpenSSH 6.5 or 6.6
-Patch909: openssh-5618210618256bbf5f4f71b2887ff186fd451736.patch
-# standardise on NI_MAXHOST for gethostname() string lengths (#1051490)
-Patch910: openssh-6.6.1p1-NI_MAXHOST.patch
 # set a client's address right after a connection is set
 # http://bugzilla.mindrot.org/show_bug.cgi?id=2257
 Patch911: openssh-6.6p1-set_remote_ipaddr.patch
@@ -150,15 +134,9 @@ Patch911: openssh-6.6p1-set_remote_ipaddr.patch
 # https://bugzilla.mindrot.org/show_bug.cgi?id=2058
 # slightly changed patch from comment 10
 Patch912: openssh-6.6.1p1-utf8-banner.patch
-# don't consider a partial success as a failure
-# https://bugzilla.mindrot.org/show_bug.cgi?id=2270
-Patch913: openssh-6.6.1p1-partial-success.patch
 # fix parsing of empty options in sshd_conf
 # https://bugzilla.mindrot.org/show_bug.cgi?id=2281
 Patch914: openssh-6.6.1p1-servconf-parser.patch
-# Ignore SIGXFSZ in postauth monitor
-# https://bugzilla.mindrot.org/show_bug.cgi?id=2263
-Patch915: openssh-6.6.1p1-ignore-SIGXFSZ-in-postauth.patch
 # privsep_preauth: use SELinux context from selinux-policy (#1008580)
 Patch916: openssh-6.6.1p1-selinux-contexts.patch
 # use different values for DH for Cisco servers (#1026430)
@@ -169,14 +147,25 @@ Patch918: openssh-6.6.1p1-log-in-chroot.patch
 Patch919: openssh-6.6.1p1-scp-non-existing-directory.patch
 # Config parser shouldn't accept ip/port syntax (#1130733)
 Patch920: openssh-6.6.1p1-ip-port-config-parser.patch
+# restore tcp wrappers support, based on Debian patch
+# https://lists.mindrot.org/pipermail/openssh-unix-dev/2014-April/032497.html
+Patch921: openssh-6.7p1-debian-restore-tcp-wrappers.patch
+# apply upstream patch and make sshd -T more consistent (#1187521)
+Patch922: openssh-6.7p1-sshdT-output.patch
 # fix ssh-copy-id on non-sh shells (#1045191)
-Patch921: openssh-6.7p1-fix-ssh-copy-id-on-non-sh-shell.patch
+Patch923: openssh-6.7p1-fix-ssh-copy-id-on-non-sh-shell.patch
+# AArch64 has seccomp support since 3.19 kernel (#1195065)
+Patch924: openssh-6.7p1-seccomp-aarch64.patch
 # Solve issue with ssh-copy-id and keys without trailing newline (#1093168)
-Patch922: openssh-6.7p1-ssh-copy-id-truncated-keys.patch
+Patch925: openssh-6.7p1-ssh-copy-id-truncated-keys.patch
+# Add sftp option to force mode of created files (#1191055)
+Patch926: openssh-6.7p1-sftp-force-permission.patch
+# Upstream bug #1878 reintroduced in openssh6.7p1
+Patch927: openssh-6.8p1-880575.patch
 
 # This is the patch that adds GSI support
-# Based on http://grid.ncsa.illinois.edu/ssh/dl/patch/openssh-6.6p1.patch
-Patch98: openssh-6.6p1-gsissh.patch
+# Based on http://grid.ncsa.illinois.edu/ssh/dl/patch/openssh-6.8p1.patch
+Patch98: openssh-6.8p1-gsissh.patch
 
 License: BSD
 Group: Applications/Internet
@@ -272,9 +261,8 @@ securely connect to your SSH server.
 This version of OpenSSH has been modified to support GSI authentication.
 
 %prep
-%setup -q -n openssh-6.6p1
+%setup -q -n openssh-%{version}
 
-%patch101 -p1 -b .fingerprint
 # investigate %patch102 -p1 -b .getaddrinfo
 %patch103 -p1 -b .packet
 
@@ -293,14 +281,10 @@ This version of OpenSSH has been modified to support GSI authentication.
 %patch604 -p1 -b .keyperm
 %patch606 -p1 -b .ipv6man
 %patch607 -p1 -b .sigpipe
-%patch608 -p1 -b .askpass-ld
 %patch609 -p1 -b .x11
 
-# drop? %patch701 -p1 -b .exit-deadlock
 %patch702 -p1 -b .progress
 %patch703 -p1 -b .grab-info
-# investigate - https://bugzilla.redhat.com/show_bug.cgi?id=205842
-# probably not needed anymore %patch704 -p1 -b .edns
 %patch706 -p1 -b .localdomain
 %patch707 -p1 -b .redhat
 %patch708 -p1 -b .entropy
@@ -308,6 +292,7 @@ This version of OpenSSH has been modified to support GSI authentication.
 %patch711 -p1 -b .log-usepam-no
 %patch712 -p1 -b .evp-ctr
 %patch713 -p1 -b .ctr-cavs
+%patch714 -p1 -b .kdf-cavs
 
 %patch800 -p1 -b .gsskex
 %patch801 -p1 -b .force_krb
@@ -317,26 +302,24 @@ This version of OpenSSH has been modified to support GSI authentication.
 %patch902 -p1 -b .ccache_name
 %patch905 -p1 -b .legacy-ssh-copy-id
 %patch906 -p1 -b .fromto-remote
-%patch907 -p1 -b .CLOCK_BOOTTIME
-%patch908 -p1 -b .CVE-2014-2653
-%patch909 -p1 -b .6.6.1
-%patch910 -p1 -b .NI_MAXHOST
 %patch911 -p1 -b .set_remote_ipaddr
 %patch912 -p1 -b .utf8-banner
-%patch913 -p1 -b .partial-success
 %patch914 -p1 -b .servconf
-%patch915 -p1 -b .SIGXFSZ
 %patch916 -p1 -b .contexts
 %patch917 -p1 -b .cisco-dh
 %patch918 -p1 -b .log-in-chroot
 %patch919 -p1 -b .scp
 %patch920 -p1 -b .config
 %patch802 -p1 -b .GSSAPIEnablek5users
-%patch921 -p1 -b .ssh-copy-id
-%patch922 -p1 -b .newline
+%patch921 -p1 -b .tcp_wrappers
+%patch922 -p1 -b .sshdt
+%patch923 -p1 -b .ssh-copy-id
+%patch924 -p1 -b .seccomp
+%patch925 -p1 -b .newline
+%patch926 -p1 -b .sftp-force-mode
+%patch927 -p1 -b .bz880575
 
 %patch200 -p1 -b .audit
-%patch201 -p1 -b .audit-fps
 %patch700 -p1 -b .fips
 
 %patch100 -p1 -b .coverity
@@ -393,14 +376,14 @@ fi
 	--without-zlib-version-check \
 	--with-ssl-engine \
 	--with-ipaddr-display \
+	--with-pie=no \
 %if %{ldap}
 	--with-ldap \
 %endif
 	--with-pam \
 %if %{WITH_SELINUX}
 	--with-selinux --with-audit=linux \
-%if 0
-	#seccomp_filter cannot be build right now
+%ifarch %{ix86} x86_64 %{arm} aarch64
 	--with-sandbox=seccomp_filter \
 %else
 	--with-sandbox=rlimit \
@@ -458,6 +441,9 @@ install -m644 -D %{SOURCE14} $RPM_BUILD_ROOT%{_tmpfilesdir}/gsissh.conf
 rm $RPM_BUILD_ROOT%{_bindir}/ssh-add
 rm $RPM_BUILD_ROOT%{_bindir}/ssh-agent
 rm $RPM_BUILD_ROOT%{_bindir}/ssh-keyscan
+rm $RPM_BUILD_ROOT%{_libexecdir}/gsissh/ctr-cavstest
+rm $RPM_BUILD_ROOT%{_libexecdir}/gsissh/ssh-cavs
+rm $RPM_BUILD_ROOT%{_libexecdir}/gsissh/ssh-cavs_driver.pl
 rm $RPM_BUILD_ROOT%{_libexecdir}/gsissh/ssh-ldap-helper
 rm $RPM_BUILD_ROOT%{_libexecdir}/gsissh/ssh-ldap-wrapper
 rm $RPM_BUILD_ROOT%{_libexecdir}/gsissh/ssh-keycat
@@ -519,7 +505,6 @@ getent passwd sshd >/dev/null || \
 %attr(0644,root,root) %{_mandir}/man1/gsissh-keygen.1*
 %attr(0755,root,root) %dir %{_libexecdir}/gsissh
 %attr(2755,root,ssh_keys) %{_libexecdir}/gsissh/ssh-keysign
-%attr(0755,root,root) %{_libexecdir}/gsissh/ctr-cavstest
 %attr(0644,root,root) %{_mandir}/man8/gsissh-keysign.8*
 
 %files clients
@@ -557,6 +542,9 @@ getent passwd sshd >/dev/null || \
 %attr(0644,root,root) %{_tmpfilesdir}/gsissh.conf
 
 %changelog
+* Mon Apr 13 2015 Mattias Ellert <mattias.ellert at fysast.uu.se> - 6.8p1-1
+- Based on openssh-6.8p1-4.fc22
+
 * Mon Apr 13 2015 Mattias Ellert <mattias.ellert at fysast.uu.se> - 6.6.1p1-5
 - Based on openssh-6.6.1p1-12.fc21
 
diff --git a/gsisshd.pam b/gsisshd.pam
index 766aa93..eae0ba6 100644
--- a/gsisshd.pam
+++ b/gsisshd.pam
@@ -12,6 +12,7 @@ session    required     pam_selinux.so close
 session    required     pam_loginuid.so
 # pam_selinux.so open should only be followed by sessions to be executed in the user context
 session    required     pam_selinux.so open env_params
+session    required     pam_namespace.so
 session    optional     pam_keyinit.so force revoke
 session    include      password-auth
 session    include      postlogin
diff --git a/openssh-5.6p1-exit-deadlock.patch b/openssh-5.6p1-exit-deadlock.patch
deleted file mode 100644
index 278dfa1..0000000
--- a/openssh-5.6p1-exit-deadlock.patch
+++ /dev/null
@@ -1,14 +0,0 @@
-diff -up openssh-5.6p1/channels.c.exit-deadlock openssh-5.6p1/channels.c
---- openssh-5.6p1/channels.c.exit-deadlock	2010-08-05 15:09:48.000000000 +0200
-+++ openssh-5.6p1/channels.c	2010-08-23 12:41:43.000000000 +0200
-@@ -1647,6 +1647,10 @@ channel_handle_wfd(Channel *c, fd_set *r
- 	u_int dlen, olen = 0;
- 	int len;
- 
-+	if(c->wfd != -1 && buffer_len(&c->output) > 0 && c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
-+		debug("channel %d: forcing write", c->self);
-+		FD_SET(c->wfd, writeset);
-+	}
- 	/* Send buffered output data to the socket. */
- 	if (c->wfd != -1 &&
- 	    FD_ISSET(c->wfd, writeset) &&
diff --git a/openssh-5.8p1-packet.patch b/openssh-5.8p1-packet.patch
index 4951af6..baccb53 100644
--- a/openssh-5.8p1-packet.patch
+++ b/openssh-5.8p1-packet.patch
@@ -1,12 +1,12 @@
-diff -up openssh-5.8p1/packet.c.packet openssh-5.8p1/packet.c
---- openssh-5.8p1/packet.c.packet	2011-04-05 13:29:06.998648899 +0200
-+++ openssh-5.8p1/packet.c	2011-04-05 13:30:32.967648596 +0200
-@@ -294,6 +294,8 @@ packet_connection_is_on_socket(void)
+diff -up openssh-6.8p1/packet.c.packet openssh-6.8p1/packet.c
+--- openssh-6.8p1/packet.c.packet	2015-03-18 10:56:32.286930601 +0100
++++ openssh-6.8p1/packet.c	2015-03-18 10:58:38.535629739 +0100
+@@ -371,6 +371,8 @@ ssh_packet_connection_is_on_socket(struc
  	struct sockaddr_storage from, to;
  	socklen_t fromlen, tolen;
  
-+	if (!active_state)
++	if (!state)
 +		return 0;
  	/* filedescriptors in and out are the same, so it's a socket */
- 	if (active_state->connection_in == active_state->connection_out)
+ 	if (state->connection_in == state->connection_out)
  		return 1;
diff --git a/openssh-5.9p1-edns.patch b/openssh-5.9p1-edns.patch
deleted file mode 100644
index 34f3851..0000000
--- a/openssh-5.9p1-edns.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-diff -up openssh-5.9p1/dns.c.edns openssh-5.9p1/dns.c
---- openssh-5.9p1/dns.c.edns	2010-08-31 14:41:14.000000000 +0200
-+++ openssh-5.9p1/dns.c	2011-09-09 08:05:27.782440497 +0200
-@@ -177,6 +177,7 @@ verify_host_key_dns(const char *hostname
- {
- 	u_int counter;
- 	int result;
-+	unsigned int rrset_flags = 0;
- 	struct rrsetinfo *fingerprints = NULL;
- 
- 	u_int8_t hostkey_algorithm;
-@@ -200,8 +201,19 @@ verify_host_key_dns(const char *hostname
- 		return -1;
- 	}
- 
-+	/*
-+	 * Original getrrsetbyname function, found on OpenBSD for example,
-+	 * doesn't accept any flag and prerequisite for obtaining AD bit in
-+	 * DNS response is set by "options edns0" in resolv.conf.
-+	 *
-+	 * Our version is more clever and use RRSET_FORCE_EDNS0 flag.
-+	 */
-+#ifndef HAVE_GETRRSETBYNAME
-+	rrset_flags |= RRSET_FORCE_EDNS0;
-+#endif
- 	result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
--	    DNS_RDATATYPE_SSHFP, 0, &fingerprints);
-+	    DNS_RDATATYPE_SSHFP, rrset_flags, &fingerprints);
-+
- 	if (result) {
- 		verbose("DNS lookup error: %s", dns_result_totext(result));
- 		return -1;
-diff -up openssh-5.9p1/openbsd-compat/getrrsetbyname.c.edns openssh-5.9p1/openbsd-compat/getrrsetbyname.c
---- openssh-5.9p1/openbsd-compat/getrrsetbyname.c.edns	2009-07-13 03:38:23.000000000 +0200
-+++ openssh-5.9p1/openbsd-compat/getrrsetbyname.c	2011-09-09 15:03:39.930500801 +0200
-@@ -209,8 +209,8 @@ getrrsetbyname(const char *hostname, uns
- 		goto fail;
- 	}
- 
--	/* don't allow flags yet, unimplemented */
--	if (flags) {
-+	/* Allow RRSET_FORCE_EDNS0 flag only. */
-+	if ((flags & ~RRSET_FORCE_EDNS0) != 0) {
- 		result = ERRSET_INVAL;
- 		goto fail;
- 	}
-@@ -226,9 +226,9 @@ getrrsetbyname(const char *hostname, uns
- #endif /* DEBUG */
- 
- #ifdef RES_USE_DNSSEC
--	/* turn on DNSSEC if EDNS0 is configured */
--	if (_resp->options & RES_USE_EDNS0)
--		_resp->options |= RES_USE_DNSSEC;
-+	/* turn on DNSSEC if required  */
-+	if (flags & RRSET_FORCE_EDNS0)
-+		_resp->options |= (RES_USE_EDNS0|RES_USE_DNSSEC);
- #endif /* RES_USE_DNSEC */
- 
- 	/* make query */
-diff -up openssh-5.9p1/openbsd-compat/getrrsetbyname.h.edns openssh-5.9p1/openbsd-compat/getrrsetbyname.h
---- openssh-5.9p1/openbsd-compat/getrrsetbyname.h.edns	2007-10-26 08:26:50.000000000 +0200
-+++ openssh-5.9p1/openbsd-compat/getrrsetbyname.h	2011-09-09 08:05:27.965438689 +0200
-@@ -72,6 +72,9 @@
- #ifndef RRSET_VALIDATED
- # define RRSET_VALIDATED	1
- #endif
-+#ifndef RRSET_FORCE_EDNS0
-+# define RRSET_FORCE_EDNS0	0x0001
-+#endif
- 
- /*
-  * Return codes for getrrsetbyname()
diff --git a/openssh-5618210618256bbf5f4f71b2887ff186fd451736.patch b/openssh-5618210618256bbf5f4f71b2887ff186fd451736.patch
deleted file mode 100644
index 44da114..0000000
--- a/openssh-5618210618256bbf5f4f71b2887ff186fd451736.patch
+++ /dev/null
@@ -1,177 +0,0 @@
-From 5618210618256bbf5f4f71b2887ff186fd451736 Mon Sep 17 00:00:00 2001
-From: Damien Miller <djm at mindrot.org>
-Date: Sun, 20 Apr 2014 13:44:47 +1000
-Subject: [PATCH]  - (djm) [bufaux.c compat.c compat.h sshconnect2.c sshd.c
- version.h]    OpenSSH 6.5 and 6.6 sometimes encode a value used in the
- curve25519    key exchange incorrectly, causing connection failures about
- 0.2% of    the time when this method is used against a peer that implements  
-  the method properly.
-
-   Fix the problem and disable the curve25519 KEX when speaking to
-   OpenSSH 6.5 or 6.6. This version will identify itself as 6.6.1
-   to enable the compatability code.
----
- ChangeLog     | 11 +++++++++++
- bufaux.c      |  5 ++++-
- compat.c      | 17 ++++++++++++++++-
- compat.h      |  2 ++
- sshconnect2.c |  2 ++
- sshd.c        |  3 +++
- version.h     |  2 +-
- 7 files changed, 39 insertions(+), 3 deletions(-)
-
-diff --git a/ChangeLog b/ChangeLog
-index 1603a07..928999d 100644
---- a/ChangeLog
-+++ b/ChangeLog
-@@ -1,13 +1,23 @@
- 20140420
--   - djm at cvs.openbsd.org 2014/04/01 03:34:10
--     [sshconnect.c]
--     When using VerifyHostKeyDNS with a DNSSEC resolver, down-convert any
--     certificate keys to plain keys and attempt SSHFP resolution.
--     
--     Prevents a server from skipping SSHFP lookup and forcing a new-hostkey
--     dialog by offering only certificate keys.
--     
--     Reported by mcv21 AT cam.ac.uk
-+ - (djm) [bufaux.c compat.c compat.h sshconnect2.c sshd.c version.h]
-+   OpenSSH 6.5 and 6.6 sometimes encode a value used in the curve25519
-+   key exchange incorrectly, causing connection failures about 0.2% of
-+   the time when this method is used against a peer that implements
-+   the method properly.
-+
-+   Fix the problem and disable the curve25519 KEX when speaking to
-+   OpenSSH 6.5 or 6.6. This version will identify itself as 6.6.1
-+   to enable the compatability code.
-+
-+ - djm at cvs.openbsd.org 2014/04/01 03:34:10
-+   [sshconnect.c]
-+   When using VerifyHostKeyDNS with a DNSSEC resolver, down-convert any
-+   certificate keys to plain keys and attempt SSHFP resolution.
-+   
-+   Prevents a server from skipping SSHFP lookup and forcing a new-hostkey
-+   dialog by offering only certificate keys.
-+   
-+   Reported by mcv21 AT cam.ac.uk
- 
- 20140313
-  - (djm) Release OpenSSH 6.6
-diff --git a/bufaux.c b/bufaux.c
-index e24b5fc..f6a6f2a 100644
---- a/bufaux.c
-+++ b/bufaux.c
-@@ -1,4 +1,4 @@
--/* $OpenBSD: bufaux.c,v 1.56 2014/02/02 03:44:31 djm Exp $ */
-+/* $OpenBSD: bufaux.c,v 1.57 2014/04/16 23:22:45 djm Exp $ */
- /*
-  * Author: Tatu Ylonen <ylo at cs.hut.fi>
-  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
-@@ -372,6 +372,9 @@ buffer_put_bignum2_from_string(Buffer *buffer, const u_char *s, u_int l)
- 
- 	if (l > 8 * 1024)
- 		fatal("%s: length %u too long", __func__, l);
-+	/* Skip leading zero bytes */
-+	for (; l > 0 && *s == 0; l--, s++)
-+		;
- 	p = buf = xmalloc(l + 1);
- 	/*
- 	 * If most significant bit is set then prepend a zero byte to
-diff --git a/compat.c b/compat.c
-index 9d9fabe..2709dc5 100644
---- a/compat.c
-+++ b/compat.c
-@@ -95,6 +95,9 @@ compat_datafellows(const char *version)
- 		{ "Sun_SSH_1.0*",	SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
- 		{ "OpenSSH_4*",		0 },
- 		{ "OpenSSH_5*",		SSH_NEW_OPENSSH|SSH_BUG_DYNAMIC_RPORT},
-+		{ "OpenSSH_6.6.1*",	SSH_NEW_OPENSSH},
-+		{ "OpenSSH_6.5*,"
-+		  "OpenSSH_6.6*",	SSH_NEW_OPENSSH|SSH_BUG_CURVE25519PAD},
- 		{ "OpenSSH*",		SSH_NEW_OPENSSH },
- 		{ "*MindTerm*",		0 },
- 		{ "2.1.0*",		SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
-@@ -251,7 +254,6 @@ compat_cipher_proposal(char *cipher_prop)
- 	return cipher_prop;
- }
- 
--
- char *
- compat_pkalg_proposal(char *pkalg_prop)
- {
-@@ -265,3 +267,16 @@ compat_pkalg_proposal(char *pkalg_prop)
- 	return pkalg_prop;
- }
- 
-+char *
-+compat_kex_proposal(char *kex_prop)
-+{
-+	if (!(datafellows & SSH_BUG_CURVE25519PAD))
-+		return kex_prop;
-+	debug2("%s: original KEX proposal: %s", __func__, kex_prop);
-+	kex_prop = filter_proposal(kex_prop, "curve25519-sha256 at libssh.org");
-+	debug2("%s: compat KEX proposal: %s", __func__, kex_prop);
-+	if (*kex_prop == '\0')
-+		fatal("No supported key exchange algorithms found");
-+	return kex_prop;
-+}
-+
-diff --git a/compat.h b/compat.h
-index b174fa1..a6c3f3d 100644
---- a/compat.h
-+++ b/compat.h
-@@ -59,6 +59,7 @@
- #define SSH_BUG_RFWD_ADDR	0x02000000
- #define SSH_NEW_OPENSSH		0x04000000
- #define SSH_BUG_DYNAMIC_RPORT	0x08000000
-+#define SSH_BUG_CURVE25519PAD	0x10000000
- 
- void     enable_compat13(void);
- void     enable_compat20(void);
-@@ -66,6 +67,7 @@ void     compat_datafellows(const char *);
- int	 proto_spec(const char *);
- char	*compat_cipher_proposal(char *);
- char	*compat_pkalg_proposal(char *);
-+char	*compat_kex_proposal(char *);
- 
- extern int compat13;
- extern int compat20;
-diff --git a/sshconnect2.c b/sshconnect2.c
-index bb9292f..b00658b 100644
---- a/sshconnect2.c
-+++ b/sshconnect2.c
-@@ -220,6 +220,8 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
- 	}
- 	if (options.kex_algorithms != NULL)
- 		myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
-+	myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
-+	    myproposal[PROPOSAL_KEX_ALGS]);
- 
- #ifdef GSSAPI
- 	/* If we've got GSSAPI algorithms, then we also support the
-diff --git a/sshd.c b/sshd.c
-index e4e406e..512c7ed 100644
---- a/sshd.c
-+++ b/sshd.c
-@@ -2488,6 +2488,9 @@ do_ssh2_kex(void)
- 	if (options.kex_algorithms != NULL)
- 		myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
- 
-+	myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
-+	    myproposal[PROPOSAL_KEX_ALGS]);
-+
- 	if (options.rekey_limit || options.rekey_interval)
- 		packet_set_rekey_limits((u_int32_t)options.rekey_limit,
- 		    (time_t)options.rekey_interval);
-diff --git a/version.h b/version.h
-index a1579ac..a33e77c 100644
---- a/version.h
-+++ b/version.h
-@@ -1,6 +1,6 @@
- /* $OpenBSD: version.h,v 1.70 2014/02/27 22:57:40 djm Exp $ */
- 
--#define SSH_VERSION	"OpenSSH_6.6"
-+#define SSH_VERSION	"OpenSSH_6.6.1"
- 
- #define SSH_PORTABLE	"p1"
- #define SSH_RELEASE	SSH_VERSION SSH_PORTABLE
diff --git a/openssh-6.1p1-askpass-ld.patch b/openssh-6.1p1-askpass-ld.patch
deleted file mode 100644
index f7a7fac..0000000
--- a/openssh-6.1p1-askpass-ld.patch
+++ /dev/null
@@ -1,18 +0,0 @@
-diff -up openssh-6.1p1/contrib/Makefile.askpass-ld openssh-6.1p1/contrib/Makefile
---- openssh-6.1p1/contrib/Makefile.askpass-ld	2012-05-19 07:24:37.000000000 +0200
-+++ openssh-6.1p1/contrib/Makefile	2012-09-14 20:35:47.565704718 +0200
-@@ -4,12 +4,12 @@ all:
- 	@echo "Valid targets: gnome-ssh-askpass1 gnome-ssh-askpass2"
- 
- gnome-ssh-askpass1: gnome-ssh-askpass1.c
--	$(CC) `gnome-config --cflags gnome gnomeui` \
-+	$(CC) ${CFLAGS} `gnome-config --cflags gnome gnomeui` \
- 		gnome-ssh-askpass1.c -o gnome-ssh-askpass1 \
- 		`gnome-config --libs gnome gnomeui`
- 
- gnome-ssh-askpass2: gnome-ssh-askpass2.c
--	$(CC) `$(PKG_CONFIG) --cflags gtk+-2.0` \
-+	$(CC) ${CFLAGS} `$(PKG_CONFIG) --cflags gtk+-2.0` \
- 		gnome-ssh-askpass2.c -o gnome-ssh-askpass2 \
- 		`$(PKG_CONFIG) --libs gtk+-2.0 x11`
- 
diff --git a/openssh-6.2p1-vendor.patch b/openssh-6.2p1-vendor.patch
index ddccd2c..67769f0 100644
--- a/openssh-6.2p1-vendor.patch
+++ b/openssh-6.2p1-vendor.patch
@@ -1,7 +1,7 @@
-diff -up openssh-6.2p1/configure.ac.vendor openssh-6.2p1/configure.ac
---- openssh-6.2p1/configure.ac.vendor	2013-03-25 19:34:01.277495179 +0100
-+++ openssh-6.2p1/configure.ac	2013-03-25 19:34:01.377495818 +0100
-@@ -4420,6 +4420,12 @@ AC_ARG_WITH([lastlog],
+diff -up openssh-6.8p1/configure.ac.vendor openssh-6.8p1/configure.ac
+--- openssh-6.8p1/configure.ac.vendor	2015-03-18 11:17:56.670880303 +0100
++++ openssh-6.8p1/configure.ac	2015-03-18 11:17:56.695880243 +0100
+@@ -4743,6 +4743,12 @@ AC_ARG_WITH([lastlog],
  		fi
  	]
  )
@@ -14,7 +14,7 @@ diff -up openssh-6.2p1/configure.ac.vendor openssh-6.2p1/configure.ac
  
  dnl lastlog, [uw]tmpx? detection
  dnl  NOTE: set the paths in the platform section to avoid the
-@@ -4681,6 +4687,7 @@ echo "           Translate v4 in v6 hack
+@@ -5005,6 +5011,7 @@ 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"
@@ -22,10 +22,10 @@ diff -up openssh-6.2p1/configure.ac.vendor openssh-6.2p1/configure.ac
  
  echo ""
  
-diff -up openssh-6.2p1/servconf.c.vendor openssh-6.2p1/servconf.c
---- openssh-6.2p1/servconf.c.vendor	2013-03-25 19:34:01.197494668 +0100
-+++ openssh-6.2p1/servconf.c	2013-03-25 19:34:01.379495831 +0100
-@@ -128,6 +128,7 @@ initialize_server_options(ServerOptions
+diff -up openssh-6.8p1/servconf.c.vendor openssh-6.8p1/servconf.c
+--- openssh-6.8p1/servconf.c.vendor	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/servconf.c	2015-03-18 11:19:16.279691126 +0100
+@@ -145,6 +145,7 @@ initialize_server_options(ServerOptions
  	options->max_authtries = -1;
  	options->max_sessions = -1;
  	options->banner = NULL;
@@ -33,26 +33,25 @@ diff -up openssh-6.2p1/servconf.c.vendor openssh-6.2p1/servconf.c
  	options->use_dns = -1;
  	options->client_alive_interval = -1;
  	options->client_alive_count_max = -1;
-@@ -287,6 +288,9 @@ fill_default_server_options(ServerOption
+@@ -327,6 +328,8 @@ fill_default_server_options(ServerOption
  		options->ip_qos_bulk = IPTOS_THROUGHPUT;
  	if (options->version_addendum == NULL)
  		options->version_addendum = xstrdup("");
 +	if (options->show_patchlevel == -1)
 +		options->show_patchlevel = 0;
-+
- 	/* Turn privilege separation on by default */
- 	if (use_privsep == -1)
- 		use_privsep = PRIVSEP_NOSANDBOX;
-@@ -324,7 +328,7 @@ typedef enum {
+ 	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
+ 		options->fwd_opts.streamlocal_bind_mask = 0177;
+ 	if (options->fwd_opts.streamlocal_bind_unlink == -1)
+@@ -388,7 +391,7 @@ typedef enum {
  	sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
- 	sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
- 	sMaxStartups, sMaxAuthTries, sMaxSessions,
+ 	sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedKeyTypes,
+ 	sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions,
 -	sBanner, sUseDNS, sHostbasedAuthentication,
 +	sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication,
- 	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
- 	sClientAliveCountMax, sAuthorizedKeysFile,
+ 	sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes,
+ 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
  	sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
-@@ -439,6 +443,7 @@ static struct {
+@@ -504,6 +507,7 @@ static struct {
  	{ "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
  	{ "maxsessions", sMaxSessions, SSHCFG_ALL },
  	{ "banner", sBanner, SSHCFG_ALL },
@@ -60,7 +59,7 @@ diff -up openssh-6.2p1/servconf.c.vendor openssh-6.2p1/servconf.c
  	{ "usedns", sUseDNS, SSHCFG_GLOBAL },
  	{ "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
  	{ "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
-@@ -1163,6 +1168,10 @@ process_server_config_line(ServerOptions
+@@ -1320,6 +1324,10 @@ process_server_config_line(ServerOptions
  		multistate_ptr = multistate_privsep;
  		goto parse_multistate;
  
@@ -71,18 +70,18 @@ diff -up openssh-6.2p1/servconf.c.vendor openssh-6.2p1/servconf.c
  	case sAllowUsers:
  		while ((arg = strdelim(&cp)) && *arg != '\0') {
  			if (options->num_allow_users >= MAX_ALLOW_USERS)
-@@ -1950,6 +1959,7 @@ dump_config(ServerOptions *o)
+@@ -2145,6 +2153,7 @@ dump_config(ServerOptions *o)
  	dump_cfg_fmtint(sUseLogin, o->use_login);
  	dump_cfg_fmtint(sCompression, o->compression);
- 	dump_cfg_fmtint(sGatewayPorts, o->gateway_ports);
+ 	dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports);
 +	dump_cfg_fmtint(sShowPatchLevel, o->show_patchlevel);
  	dump_cfg_fmtint(sUseDNS, o->use_dns);
  	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
- 	dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
-diff -up openssh-6.2p1/servconf.h.vendor openssh-6.2p1/servconf.h
---- openssh-6.2p1/servconf.h.vendor	2013-01-09 05:56:45.000000000 +0100
-+++ openssh-6.2p1/servconf.h	2013-03-25 19:34:01.379495831 +0100
-@@ -147,6 +147,7 @@ typedef struct {
+ 	dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
+diff -up openssh-6.8p1/servconf.h.vendor openssh-6.8p1/servconf.h
+--- openssh-6.8p1/servconf.h.vendor	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/servconf.h	2015-03-18 11:17:56.696880241 +0100
+@@ -151,6 +151,7 @@ typedef struct {
  	int	max_authtries;
  	int	max_sessions;
  	char   *banner;			/* SSH-2 banner message */
@@ -90,21 +89,43 @@ diff -up openssh-6.2p1/servconf.h.vendor openssh-6.2p1/servconf.h
  	int	use_dns;
  	int	client_alive_interval;	/*
  					 * poke the client this often to
-diff -up openssh-6.2p1/sshd_config.vendor openssh-6.2p1/sshd_config
---- openssh-6.2p1/sshd_config.vendor	2013-03-25 19:34:01.380495837 +0100
-+++ openssh-6.2p1/sshd_config	2013-03-25 19:44:43.471296362 +0100
-@@ -118,6 +118,7 @@ UsePrivilegeSeparation sandbox		# Defaul
+diff -up openssh-6.8p1/sshd.c.vendor openssh-6.8p1/sshd.c
+--- openssh-6.8p1/sshd.c.vendor	2015-03-18 11:17:56.669880305 +0100
++++ openssh-6.8p1/sshd.c	2015-03-18 11:17:56.697880239 +0100
+@@ -431,7 +431,7 @@ sshd_exchange_identification(int sock_in
+ 	}
+ 
+ 	xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s",
+-	    major, minor, SSH_VERSION,
++	    major, minor, (options.show_patchlevel == 1) ? SSH_VENDOR_PATCHLEVEL : SSH_VERSION,
+ 	    *options.version_addendum == '\0' ? "" : " ",
+ 	    options.version_addendum, newline);
+ 
+@@ -1737,7 +1737,8 @@ main(int ac, char **av)
+ 		exit(1);
+ 	}
+ 
+-	debug("sshd version %s, %s", SSH_VERSION,
++	debug("sshd version %s, %s", 
++		(options.show_patchlevel == 1) ? SSH_VENDOR_PATCHLEVEL : SSH_VERSION,
+ #ifdef WITH_OPENSSL
+ 	    SSLeay_version(SSLEAY_VERSION)
+ #else
+diff -up openssh-6.8p1/sshd_config.vendor openssh-6.8p1/sshd_config
+--- openssh-6.8p1/sshd_config.vendor	2015-03-18 11:17:56.697880239 +0100
++++ openssh-6.8p1/sshd_config	2015-03-18 11:20:15.552550274 +0100
+@@ -119,6 +119,7 @@ UsePrivilegeSeparation sandbox		# Defaul
  #Compression delayed
  #ClientAliveInterval 0
  #ClientAliveCountMax 3
 +#ShowPatchLevel no
- #UseDNS yes
+ #UseDNS no
  #PidFile /var/run/sshd.pid
  #MaxStartups 10:30:100
-diff -up openssh-6.2p1/sshd_config.0.vendor openssh-6.2p1/sshd_config.0
---- openssh-6.2p1/sshd_config.0.vendor	2013-03-25 19:34:01.361495716 +0100
-+++ openssh-6.2p1/sshd_config.0	2013-03-25 19:34:01.381495844 +0100
-@@ -595,6 +595,11 @@ DESCRIPTION
+diff -up openssh-6.8p1/sshd_config.0.vendor openssh-6.8p1/sshd_config.0
+--- openssh-6.8p1/sshd_config.0.vendor	2015-03-18 11:17:56.691880253 +0100
++++ openssh-6.8p1/sshd_config.0	2015-03-18 11:17:56.697880239 +0100
+@@ -740,6 +740,11 @@ DESCRIPTION
               Defines the number of bits in the ephemeral protocol version 1
               server key.  The minimum value is 512, and the default is 1024.
  
@@ -113,13 +134,13 @@ diff -up openssh-6.2p1/sshd_config.0.vendor openssh-6.2p1/sshd_config.0
 +	     the binary in the server identification string.  The patch level
 +	     is set at compile-time.  The default is M-bM-^@M-^\noM-bM-^@M-^].
 +
-      StrictModes
-              Specifies whether sshd(8) should check file modes and ownership
-              of the user's files and home directory before accepting login.
-diff -up openssh-6.2p1/sshd_config.5.vendor openssh-6.2p1/sshd_config.5
---- openssh-6.2p1/sshd_config.5.vendor	2013-03-25 19:34:01.362495722 +0100
-+++ openssh-6.2p1/sshd_config.5	2013-03-25 19:34:01.382495850 +0100
-@@ -1019,6 +1019,14 @@ This option applies to protocol version
+      StreamLocalBindMask
+              Sets the octal file creation mode mask (umask) used when creating
+              a Unix-domain socket file for local or remote port forwarding.
+diff -up openssh-6.8p1/sshd_config.5.vendor openssh-6.8p1/sshd_config.5
+--- openssh-6.8p1/sshd_config.5.vendor	2015-03-18 11:17:56.691880253 +0100
++++ openssh-6.8p1/sshd_config.5	2015-03-18 11:17:56.697880239 +0100
+@@ -1276,6 +1276,13 @@ This option applies to protocol version
  .It Cm ServerKeyBits
  Defines the number of bits in the ephemeral protocol version 1 server key.
  The minimum value is 512, and the default is 1024.
@@ -130,29 +151,6 @@ diff -up openssh-6.2p1/sshd_config.5.vendor openssh-6.2p1/sshd_config.5
 +The patch level is set at compile-time. 
 +The default is 
 +.Dq no . 
-+This option applies to protocol version 1 only. 
- .It Cm StrictModes
- Specifies whether
- .Xr sshd 8
-diff -up openssh-6.2p1/sshd.c.vendor openssh-6.2p1/sshd.c
---- openssh-6.2p1/sshd.c.vendor	2013-03-25 19:34:01.332495531 +0100
-+++ openssh-6.2p1/sshd.c	2013-03-25 19:44:11.864112092 +0100
-@@ -442,7 +442,7 @@ sshd_exchange_identification(int sock_in
- 	}
- 
- 	xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s",
--	    major, minor, SSH_VERSION,
-+	    major, minor, (options.show_patchlevel == 1) ? SSH_VENDOR_PATCHLEVEL : SSH_VERSION,
- 	    *options.version_addendum == '\0' ? "" : " ",
- 	    options.version_addendum, newline);
- 
-@@ -1675,7 +1675,8 @@ main(int ac, char **av)
- 		exit(1);
- 	}
- 
--	debug("sshd version %s, %s", SSH_VERSION,
-+	debug("sshd version %s, %s",
-+	    (options.show_patchlevel == 1) ? SSH_VENDOR_PATCHLEVEL : SSH_VERSION,
- 	    SSLeay_version(SSLEAY_VERSION));
- 
- 	/* Store privilege separation user for later use if required. */
+ .It Cm StreamLocalBindMask
+ Sets the octal file creation mode mask
+ .Pq umask
diff --git a/openssh-6.4p1-CLOCK_BOOTTIME.patch b/openssh-6.4p1-CLOCK_BOOTTIME.patch
deleted file mode 100644
index 1073a77..0000000
--- a/openssh-6.4p1-CLOCK_BOOTTIME.patch
+++ /dev/null
@@ -1,29 +0,0 @@
---- a/misc.c
-+++ b/misc.c
-@@ -865,17 +865,24 @@ ms_to_timeval(struct timeval *tv, int ms
- time_t
- monotime(void)
- {
--#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
-+#if defined(HAVE_CLOCK_GETTIME) && \
-+    (defined(CLOCK_MONOTONIC) || defined(CLOCK_BOOTTIME))
- 	struct timespec ts;
- 	static int gettime_failed = 0;
- 
- 	if (!gettime_failed) {
-+#if defined(CLOCK_BOOTTIME)
-+		if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0)
-+			return (ts.tv_sec);
-+#endif
-+#if defined(CLOCK_MONOTONIC)
- 		if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
- 			return (ts.tv_sec);
-+#endif
- 		debug3("clock_gettime: %s", strerror(errno));
- 		gettime_failed = 1;
- 	}
--#endif
-+#endif /* HAVE_CLOCK_GETTIME && (CLOCK_MONOTONIC || CLOCK_BOOTTIME */
- 
- 	return time(NULL);
- }
diff --git a/openssh-6.6.1p1-NI_MAXHOST.patch b/openssh-6.6.1p1-NI_MAXHOST.patch
deleted file mode 100644
index 7eeee50..0000000
--- a/openssh-6.6.1p1-NI_MAXHOST.patch
+++ /dev/null
@@ -1,76 +0,0 @@
-diff --git a/ChangeLog b/ChangeLog
-index 928999d..3887495 100644
---- a/ChangeLog
-+++ b/ChangeLog
-@@ -1,3 +1,10 @@
-+20140703
-+ - OpenBSD CVS Sync
-+   - djm at cvs.openbsd.org 2014/07/03 03:34:09
-+     [gss-serv.c session.c ssh-keygen.c]
-+     standardise on NI_MAXHOST for gethostname() string lengths; about
-+     1/2 the cases were using it already. Fixes bz#2239 en passant
-+
- 20140420
-  - (djm) [bufaux.c compat.c compat.h sshconnect2.c sshd.c version.h]
-    OpenSSH 6.5 and 6.6 sometimes encode a value used in the curve25519
-diff --git a/gss-serv.c b/gss-serv.c
-index 14f540e..29916d3 100644
---- a/gss-serv.c
-+++ b/gss-serv.c
-@@ -1,4 +1,4 @@
--/* $OpenBSD: gss-serv.c,v 1.26 2014/02/26 20:28:44 djm Exp $ */
-+/* $OpenBSD: gss-serv.c,v 1.27 2014/07/03 03:34:09 djm Exp $ */
- 
- /*
-  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
-@@ -102,14 +102,14 @@ static OM_uint32
- ssh_gssapi_acquire_cred(Gssctxt *ctx)
- {
- 	OM_uint32 status;
--	char lname[MAXHOSTNAMELEN];
-+	char lname[NI_MAXHOST];
- 	gss_OID_set oidset;
- 
- 	if (options.gss_strict_acceptor) {
- 		gss_create_empty_oid_set(&status, &oidset);
- 		gss_add_oid_set_member(&status, ctx->oid, &oidset);
- 
--		if (gethostname(lname, MAXHOSTNAMELEN)) {
-+		if (gethostname(lname, sizeof(lname))) {
- 			gss_release_oid_set(&status, &oidset);
- 			return (-1);
- 		}
-diff --git a/session.c b/session.c
-index ba4589b..e4add93 100644
---- a/session.c
-+++ b/session.c
-@@ -49,6 +49,7 @@
- #include <errno.h>
- #include <fcntl.h>
- #include <grp.h>
-+#include <netdb.h>
- #ifdef HAVE_PATHS_H
- #include <paths.h>
- #endif
-@@ -2669,7 +2670,7 @@ session_setup_x11fwd(Session *s)
- {
- 	struct stat st;
- 	char display[512], auth_display[512];
--	char hostname[MAXHOSTNAMELEN];
-+	char hostname[NI_MAXHOST];
- 	u_int i;
- 
- 	if (no_x11_forwarding_flag) {
-diff --git a/ssh-keygen.c b/ssh-keygen.c
-index 482dc1c..66198e6 100644
---- a/ssh-keygen.c
-+++ b/ssh-keygen.c
-@@ -165,7 +165,7 @@ int rounds = 0;
- /* argv0 */
- extern char *__progname;
- 
--char hostname[MAXHOSTNAMELEN];
-+char hostname[NI_MAXHOST];
- 
- /* moduli.c */
- int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *);
diff --git a/openssh-6.6.1p1-audit-pfs.patch b/openssh-6.6.1p1-audit-pfs.patch
deleted file mode 100644
index a2b6d75..0000000
--- a/openssh-6.6.1p1-audit-pfs.patch
+++ /dev/null
@@ -1,212 +0,0 @@
-diff --git a/audit-bsm.c b/audit-bsm.c
-index 5160869..c7a1b47 100644
---- a/audit-bsm.c
-+++ b/audit-bsm.c
-@@ -481,7 +481,7 @@ audit_unsupported_body(int what)
- }
- 
- void
--audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, uid_t uid)
-+audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, uid_t uid)
- {
- 	/* not implemented */
- }
-diff --git a/audit-linux.c b/audit-linux.c
-index 6954fc1..6686f6a 100644
---- a/audit-linux.c
-+++ b/audit-linux.c
-@@ -297,7 +297,7 @@ audit_unsupported_body(int what)
- const static char *direction[] = { "from-server", "from-client", "both" };
- 
- void
--audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid,
-+audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid,
- 	       uid_t uid)
- {
- #ifdef AUDIT_CRYPTO_SESSION
-@@ -306,8 +306,8 @@ audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid,
- 	Cipher *cipher = cipher_by_name(enc);
- 	char *s;
- 
--	snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ",
--		direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac,
-+	snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s pfs=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ",
-+		direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac, pfs,
- 		(intmax_t)pid, (intmax_t)uid,
- 		get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), get_local_port());
- 	free(s);
-diff --git a/audit.c b/audit.c
-index 13c6849..5b49434 100644
---- a/audit.c
-+++ b/audit.c
-@@ -135,9 +135,9 @@ audit_unsupported(int what)
- }
- 
- void
--audit_kex(int ctos, char *enc, char *mac, char *comp)
-+audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs)
- {
--	PRIVSEP(audit_kex_body(ctos, enc, mac, comp, getpid(), getuid()));
-+	PRIVSEP(audit_kex_body(ctos, enc, mac, comp, pfs, getpid(), getuid()));
- }
- 
- void
-@@ -270,11 +270,11 @@ audit_unsupported_body(int what)
-  * This will be called on succesfull protocol negotiation.
-  */
- void
--audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid,
-+audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid,
- 	       uid_t uid)
- {
--	debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s from pid %ld uid %u",
--		(unsigned)geteuid(), ctos, enc, mac, compress, (long)pid,
-+	debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s pfs %s from pid %ld uid %u",
-+		(unsigned)geteuid(), ctos, enc, mac, compress, pfs, (long)pid,
- 	        (unsigned)uid);
- }
- 
-diff --git a/audit.h b/audit.h
-index a2dc3ff..903df66 100644
---- a/audit.h
-+++ b/audit.h
-@@ -61,9 +61,9 @@ ssh_audit_event_t audit_classify_auth(const char *);
- int	audit_keyusage(int, const char *, unsigned, char *, int);
- void	audit_key(int, int *, const Key *);
- void	audit_unsupported(int);
--void	audit_kex(int, char *, char *, char *);
-+void	audit_kex(int, char *, char *, char *, char *);
- void	audit_unsupported_body(int);
--void	audit_kex_body(int, char *, char *, char *, pid_t, uid_t);
-+void	audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t);
- void	audit_session_key_free(int ctos);
- void	audit_session_key_free_body(int ctos, pid_t, uid_t);
- void	audit_destroy_sensitive_data(const char *, pid_t, uid_t);
-diff --git a/auditstub.c b/auditstub.c
-index 45817e0..116f460 100644
---- a/auditstub.c
-+++ b/auditstub.c
-@@ -35,7 +35,7 @@ audit_unsupported(int n)
- }
- 
- void
--audit_kex(int ctos, char *enc, char *mac, char *comp)
-+audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs)
- {
- }
- 
-diff --git a/kex.c b/kex.c
-index ede7b67..eb5f333 100644
---- a/kex.c
-+++ b/kex.c
-@@ -553,13 +553,12 @@ kex_choose_conf(Kex *kex)
- 		    newkeys->enc.name,
- 		    authlen == 0 ? newkeys->mac.name : "<implicit>",
- 		    newkeys->comp.name);
--#ifdef SSH_AUDIT_EVENTS
--		audit_kex(ctos, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name);
--#endif
- 	}
-+
- 	choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
- 	choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
- 	    sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
-+
- 	need = dh_need = 0;
- 	for (mode = 0; mode < MODE_MAX; mode++) {
- 		newkeys = kex->newkeys[mode];
-@@ -571,11 +570,16 @@ kex_choose_conf(Kex *kex)
- 		dh_need = MAX(dh_need, newkeys->enc.block_size);
- 		dh_need = MAX(dh_need, newkeys->enc.iv_len);
- 		dh_need = MAX(dh_need, newkeys->mac.key_len);
-+		debug("kex: %s need=%d dh_need=%d", kex->name, need, dh_need);
-+#ifdef SSH_AUDIT_EVENTS
-+		audit_kex(ctos, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name, kex->name);
-+#endif
- 	}
- 	/* XXX need runden? */
- 	kex->we_need = need;
- 	kex->dh_need = dh_need;
- 
-+
- 	/* ignore the next message if the proposals do not match */
- 	if (first_kex_follows && !proposals_match(my, peer) &&
- 	    !(datafellows & SSH_BUG_FIRSTKEX)) {
-diff --git a/monitor.c b/monitor.c
-index 70b9b4c..81bc9c1 100644
---- a/monitor.c
-+++ b/monitor.c
-@@ -2396,7 +2396,7 @@ int
- mm_answer_audit_kex_body(int sock, Buffer *m)
- {
- 	int ctos, len;
--	char *cipher, *mac, *compress;
-+	char *cipher, *mac, *compress, *pfs;
- 	pid_t pid;
- 	uid_t uid;
- 
-@@ -2404,14 +2404,16 @@ mm_answer_audit_kex_body(int sock, Buffer *m)
- 	cipher = buffer_get_string(m, &len);
- 	mac = buffer_get_string(m, &len);
- 	compress = buffer_get_string(m, &len);
-+	pfs = buffer_get_string(m, &len);
- 	pid = buffer_get_int64(m);
- 	uid = buffer_get_int64(m);
- 
--	audit_kex_body(ctos, cipher, mac, compress, pid, uid);
-+	audit_kex_body(ctos, cipher, mac, compress, pfs, pid, uid);
- 
- 	free(cipher);
- 	free(mac);
- 	free(compress);
-+	free(pfs);
- 	buffer_clear(m);
- 
- 	mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m);
-diff --git a/monitor_wrap.c b/monitor_wrap.c
-index 93f6535..69b29d8 100644
---- a/monitor_wrap.c
-+++ b/monitor_wrap.c
-@@ -1408,7 +1408,7 @@ mm_audit_unsupported_body(int what)
- }
- 
- void
--mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, pid_t pid,
-+mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, char *fps, pid_t pid,
- 		  uid_t uid)
- {
- 	Buffer m;
-@@ -1418,6 +1418,7 @@ mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, pid_t pid,
- 	buffer_put_cstring(&m, cipher);
- 	buffer_put_cstring(&m, (mac ? mac : ""));
- 	buffer_put_cstring(&m, compress);
-+	buffer_put_cstring(&m, fps);
- 	buffer_put_int64(&m, pid);
- 	buffer_put_int64(&m, uid);
- 
-diff --git a/monitor_wrap.h b/monitor_wrap.h
-index 4cf0c78..e43109f 100644
---- a/monitor_wrap.h
-+++ b/monitor_wrap.h
-@@ -83,7 +83,7 @@ void mm_audit_event(ssh_audit_event_t);
- int mm_audit_run_command(const char *);
- void mm_audit_end_command(int, const char *);
- void mm_audit_unsupported_body(int);
--void mm_audit_kex_body(int, char *, char *, char *, pid_t, uid_t);
-+void mm_audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t);
- void mm_audit_session_key_free_body(int, pid_t, uid_t);
- void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t);
- #endif
-diff --git a/sshd.c b/sshd.c
-index ee94825..41a94a7 100644
---- a/sshd.c
-+++ b/sshd.c
-@@ -2430,7 +2430,7 @@ do_ssh1_kex(void)
- 			packet_disconnect("IP Spoofing check bytes do not match.");
- 
- #ifdef SSH_AUDIT_EVENTS
--	audit_kex(2, cipher_name(cipher_type), "crc", "none");
-+	audit_kex(2, cipher_name(cipher_type), "crc", "none", "none");
- #endif
- 
- 	debug("Encryption type: %.200s", cipher_name(cipher_type));
diff --git a/openssh-6.6.1p1-cisco-dh-keys.patch b/openssh-6.6.1p1-cisco-dh-keys.patch
index 0763b10..6890c05 100644
--- a/openssh-6.6.1p1-cisco-dh-keys.patch
+++ b/openssh-6.6.1p1-cisco-dh-keys.patch
@@ -1,7 +1,6 @@
-diff --git a/compat.c b/compat.c
-index 2709dc5..7412a54 100644
---- a/compat.c
-+++ b/compat.c
+diff -up openssh-6.8p1/compat.c.cisco-dh openssh-6.8p1/compat.c
+--- openssh-6.8p1/compat.c.cisco-dh	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/compat.c	2015-03-19 12:57:58.862606969 +0100
 @@ -167,6 +167,7 @@ compat_datafellows(const char *version)
  					SSH_BUG_SCANNER },
  		{ "Probe-*",
@@ -10,10 +9,9 @@ index 2709dc5..7412a54 100644
  		{ NULL,			0 }
  	};
  
-diff --git a/compat.h b/compat.h
-index a6c3f3d..d8def7d 100644
---- a/compat.h
-+++ b/compat.h
+diff -up openssh-6.8p1/compat.h.cisco-dh openssh-6.8p1/compat.h
+--- openssh-6.8p1/compat.h.cisco-dh	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/compat.h	2015-03-19 12:57:58.862606969 +0100
 @@ -60,6 +60,7 @@
  #define SSH_NEW_OPENSSH		0x04000000
  #define SSH_BUG_DYNAMIC_RPORT	0x08000000
@@ -22,49 +20,35 @@ index a6c3f3d..d8def7d 100644
  
  void     enable_compat13(void);
  void     enable_compat20(void);
-diff --git a/kexgexc.c b/kexgexc.c
-index 355b7ba..0a91bdd 100644
---- a/kexgexc.c
-+++ b/kexgexc.c
-@@ -58,20 +58,37 @@ kexgex_client(Kex *kex)
- 	int min, max, nbits;
- 	DH *dh;
+diff -up openssh-6.8p1/kexgexc.c.cisco-dh openssh-6.8p1/kexgexc.c
+--- openssh-6.8p1/kexgexc.c.cisco-dh	2015-03-19 12:57:58.862606969 +0100
++++ openssh-6.8p1/kexgexc.c	2015-03-19 13:11:52.320519969 +0100
+@@ -64,8 +64,27 @@ kexgex_client(struct ssh *ssh)
  
-+	min = DH_GRP_MIN;
-+	max = DH_GRP_MAX;
+ 	kex->min = DH_GRP_MIN;
+ 	kex->max = DH_GRP_MAX;
 +
 +	/* Servers with MAX4096DH need a preferred size (nbits) <= 4096.
 + 	 * We need to also ensure that min < nbits < max */
 +
 +	if (datafellows & SSH_BUG_MAX4096DH) {
 +		/* The largest min for these servers is 4096 */
-+		min = MIN(min, 4096);
++		kex->min = MIN(kex->min, 4096);
 +	}
 +
- 	nbits = dh_estimate(kex->dh_need * 8);
-+	nbits = MIN(nbits, max);
-+	nbits = MAX(nbits, min);
+ 	kex->nbits = nbits;
+-	if (ssh->compat & SSH_OLD_DHGEX) {
++	kex->nbits = MIN(nbits, kex->max);
++	kex->nbits = MAX(nbits, kex->min);
 +
-+	if (datafellows & SSH_BUG_MAX4096DH) {
++	if (ssh->compat & SSH_BUG_MAX4096DH) {
 +		/* Cannot have a nbits > 4096 for these servers */
-+		nbits = MIN(nbits, 4096);
++		kex->nbits = MIN(kex->nbits, 4096);
 +		/* nbits has to be powers of two */
-+		if (nbits == 3072)
-+			nbits = 4096;
++		if (kex->nbits == 3072)
++			kex->nbits = 4096;
 +	}
- 
- 	if (datafellows & SSH_OLD_DHGEX) {
++	if (ssh->compat & SSH_OLD_DHGEX) {	/* Old GEX request */
  		/* Old GEX request */
- 		packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
- 		packet_put_int(nbits);
--		min = DH_GRP_MIN;
--		max = DH_GRP_MAX;
- 
- 		debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD(%u) sent", nbits);
- 	} else {
- 		/* New GEX request */
--		min = DH_GRP_MIN;
--		max = DH_GRP_MAX;
- 		packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
- 		packet_put_int(min);
- 		packet_put_int(nbits);
+ 		if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST_OLD))
+ 		    != 0 ||
diff --git a/openssh-6.6.1p1-coverity.patch b/openssh-6.6.1p1-coverity.patch
deleted file mode 100644
index 9f71f9c..0000000
--- a/openssh-6.6.1p1-coverity.patch
+++ /dev/null
@@ -1,844 +0,0 @@
-diff --git a/auth-pam.c b/auth-pam.c
-index cd1a775..690711e 100644
---- a/auth-pam.c
-+++ b/auth-pam.c
-@@ -216,7 +216,12 @@ pthread_join(sp_pthread_t thread, void **value)
- 	if (sshpam_thread_status != -1)
- 		return (sshpam_thread_status);
- 	signal(SIGCHLD, sshpam_oldsig);
--	waitpid(thread, &status, 0);
-+	while (waitpid(thread, &status, 0) < 0) {                     
-+		if (errno == EINTR)                                
-+			continue;
-+		fatal("%s: waitpid: %s", __func__,         
-+				strerror(errno));                      
-+	}
- 	return (status);
- }
- #endif
-diff --git a/channels.c b/channels.c
-index af3fdc2..39c9f89 100644
---- a/channels.c
-+++ b/channels.c
-@@ -233,11 +233,11 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd,
- 	channel_max_fd = MAX(channel_max_fd, wfd);
- 	channel_max_fd = MAX(channel_max_fd, efd);
- 
--	if (rfd != -1)
-+	if (rfd >= 0)
- 		fcntl(rfd, F_SETFD, FD_CLOEXEC);
--	if (wfd != -1 && wfd != rfd)
-+	if (wfd >= 0 && wfd != rfd)
- 		fcntl(wfd, F_SETFD, FD_CLOEXEC);
--	if (efd != -1 && efd != rfd && efd != wfd)
-+	if (efd >= 0 && efd != rfd && efd != wfd)
- 		fcntl(efd, F_SETFD, FD_CLOEXEC);
- 
- 	c->rfd = rfd;
-@@ -255,11 +255,11 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd,
- 
- 	/* enable nonblocking mode */
- 	if (nonblock) {
--		if (rfd != -1)
-+		if (rfd >= 0)
- 			set_nonblock(rfd);
--		if (wfd != -1)
-+		if (wfd >= 0)
- 			set_nonblock(wfd);
--		if (efd != -1)
-+		if (efd >= 0)
- 			set_nonblock(efd);
- 	}
- }
-diff --git a/clientloop.c b/clientloop.c
-index 9c60108..d372b53 100644
---- a/clientloop.c
-+++ b/clientloop.c
-@@ -2081,14 +2081,15 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt)
- 	char *rtype;
- 	int want_reply;
- 	int success = 0;
-+/* success is still 0 the packet is allways SSH2_MSG_REQUEST_FAILURE, isn't it? */
- 
- 	rtype = packet_get_string(NULL);
- 	want_reply = packet_get_char();
- 	debug("client_input_global_request: rtype %s want_reply %d",
- 	    rtype, want_reply);
- 	if (want_reply) {
--		packet_start(success ?
--		    SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
-+		packet_start(/*success ?
-+		    SSH2_MSG_REQUEST_SUCCESS :*/ SSH2_MSG_REQUEST_FAILURE);
- 		packet_send();
- 		packet_write_wait();
- 	}
-diff --git a/key.c b/key.c
-index a2050f6..6487d81 100644
---- a/key.c
-+++ b/key.c
-@@ -880,8 +880,10 @@ key_read(Key *ret, char **cpp)
- 		success = 1;
- /*XXXX*/
- 		key_free(k);
-+/*XXXX
- 		if (success != 1)
- 			break;
-+XXXX*/
- 		/* advance cp: skip whitespace and data */
- 		while (*cp == ' ' || *cp == '\t')
- 			cp++;
-diff --git a/monitor.c b/monitor.c
-index 3ff62b0..70b9b4c 100644
---- a/monitor.c
-+++ b/monitor.c
-@@ -472,7 +472,7 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
- 	mm_get_keystate(pmonitor);
- 
- 	/* Drain any buffered messages from the child */
--	while (pmonitor->m_log_recvfd != -1 && monitor_read_log(pmonitor) == 0)
-+	while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0)
- 		;
- 
- 	close(pmonitor->m_sendfd);
-@@ -1254,6 +1254,10 @@ mm_answer_keyallowed(int sock, Buffer *m)
- 			break;
- 		}
- 	}
-+
-+	debug3("%s: key %p is %s",
-+	    __func__, key, allowed ? "allowed" : "not allowed");
-+
- 	if (key != NULL)
- 		key_free(key);
- 
-@@ -1275,9 +1279,6 @@ mm_answer_keyallowed(int sock, Buffer *m)
- 		free(chost);
- 	}
- 
--	debug3("%s: key %p is %s",
--	    __func__, key, allowed ? "allowed" : "not allowed");
--
- 	buffer_clear(m);
- 	buffer_put_int(m, allowed);
- 	buffer_put_int(m, forced_command != NULL);
-diff --git a/monitor_wrap.c b/monitor_wrap.c
-index 6df236a..93f6535 100644
---- a/monitor_wrap.c
-+++ b/monitor_wrap.c
-@@ -743,10 +743,10 @@ mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
- 	if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 ||
- 	    (tmp2 = dup(pmonitor->m_recvfd)) == -1) {
- 		error("%s: cannot allocate fds for pty", __func__);
--		if (tmp1 > 0)
-+		if (tmp1 >= 0)
- 			close(tmp1);
--		if (tmp2 > 0)
--			close(tmp2);
-+		/*DEAD CODE if (tmp2 >= 0)
-+			close(tmp2);*/
- 		return 0;
- 	}
- 	close(tmp1);
-diff --git a/openbsd-compat/bindresvport.c b/openbsd-compat/bindresvport.c
-index c89f214..80115c2 100644
---- a/openbsd-compat/bindresvport.c
-+++ b/openbsd-compat/bindresvport.c
-@@ -58,7 +58,7 @@ bindresvport_sa(int sd, struct sockaddr *sa)
- 	struct sockaddr_in6 *in6;
- 	u_int16_t *portp;
- 	u_int16_t port;
--	socklen_t salen;
-+	socklen_t salen = sizeof(struct sockaddr_storage);
- 	int i;
- 
- 	if (sa == NULL) {
-diff --git a/packet.c b/packet.c
-index f5b122b..1305e87 100644
---- a/packet.c
-+++ b/packet.c
-@@ -1234,6 +1234,7 @@ packet_read_poll1(void)
- 		case DEATTACK_DETECTED:
- 			packet_disconnect("crc32 compensation attack: "
- 			    "network attack detected");
-+			break;
- 		case DEATTACK_DOS_DETECTED:
- 			packet_disconnect("deattack denial of "
- 			    "service detected");
-diff --git a/progressmeter.c b/progressmeter.c
-index bbbc706..ae6d1aa 100644
---- a/progressmeter.c
-+++ b/progressmeter.c
-@@ -65,7 +65,7 @@ static void update_progress_meter(int);
- 
- static time_t start;		/* start progress */
- static time_t last_update;	/* last progress update */
--static char *file;		/* name of the file being transferred */
-+static const char *file;	/* name of the file being transferred */
- 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 */
-@@ -248,7 +248,7 @@ update_progress_meter(int ignore)
- }
- 
- void
--start_progress_meter(char *f, off_t filesize, off_t *ctr)
-+start_progress_meter(const char *f, off_t filesize, off_t *ctr)
- {
- 	start = last_update = monotime();
- 	file = f;
-diff --git a/progressmeter.h b/progressmeter.h
-index 10bab99..e9ca8f0 100644
---- a/progressmeter.h
-+++ b/progressmeter.h
-@@ -23,5 +23,5 @@
-  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-  */
- 
--void	start_progress_meter(char *, off_t, off_t *);
-+void	start_progress_meter(const char *, off_t, off_t *);
- void	stop_progress_meter(void);
-diff --git a/scp.c b/scp.c
-index 1178a07..d9bc016 100644
---- a/scp.c
-+++ b/scp.c
-@@ -155,7 +155,7 @@ killchild(int signo)
- {
- 	if (do_cmd_pid > 1) {
- 		kill(do_cmd_pid, signo ? signo : SIGTERM);
--		waitpid(do_cmd_pid, NULL, 0);
-+		(void) waitpid(do_cmd_pid, NULL, 0);
- 	}
- 
- 	if (signo)
-diff --git a/servconf.c b/servconf.c
-index 3839928..d482e79 100644
---- a/servconf.c
-+++ b/servconf.c
-@@ -1382,7 +1382,7 @@ process_server_config_line(ServerOptions *options, char *line,
- 			fatal("%s line %d: Missing subsystem name.",
- 			    filename, linenum);
- 		if (!*activep) {
--			arg = strdelim(&cp);
-+			/*arg =*/ (void) strdelim(&cp);
- 			break;
- 		}
- 		for (i = 0; i < options->num_subsystems; i++)
-@@ -1473,8 +1473,9 @@ process_server_config_line(ServerOptions *options, char *line,
- 		if (*activep && *charptr == NULL) {
- 			*charptr = tilde_expand_filename(arg, getuid());
- 			/* increase optional counter */
--			if (intptr != NULL)
--				*intptr = *intptr + 1;
-+			/* DEAD CODE intptr is still NULL ;)
-+  			 if (intptr != NULL)
-+				*intptr = *intptr + 1; */
- 		}
- 		break;
- 
-diff --git a/serverloop.c b/serverloop.c
-index 2f8e3a0..e03bc6c 100644
---- a/serverloop.c
-+++ b/serverloop.c
-@@ -147,13 +147,13 @@ notify_setup(void)
- static void
- notify_parent(void)
- {
--	if (notify_pipe[1] != -1)
-+	if (notify_pipe[1] >= 0)
- 		(void)write(notify_pipe[1], "", 1);
- }
- static void
- notify_prepare(fd_set *readset)
- {
--	if (notify_pipe[0] != -1)
-+	if (notify_pipe[0] >= 0)
- 		FD_SET(notify_pipe[0], readset);
- }
- static void
-@@ -161,8 +161,8 @@ notify_done(fd_set *readset)
- {
- 	char c;
- 
--	if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset))
--		while (read(notify_pipe[0], &c, 1) != -1)
-+	if (notify_pipe[0] >= 0 && FD_ISSET(notify_pipe[0], readset))
-+		while (read(notify_pipe[0], &c, 1) >= 0)
- 			debug2("notify_done: reading");
- }
- 
-@@ -337,7 +337,7 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
- 		 * If we have buffered data, try to write some of that data
- 		 * to the program.
- 		 */
--		if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
-+		if (fdin >= 0 && buffer_len(&stdin_buffer) > 0)
- 			FD_SET(fdin, *writesetp);
- 	}
- 	notify_prepare(*readsetp);
-@@ -477,7 +477,7 @@ process_output(fd_set *writeset)
- 	int len;
- 
- 	/* Write buffered data to program stdin. */
--	if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) {
-+	if (!compat20 && fdin >= 0 && FD_ISSET(fdin, writeset)) {
- 		data = buffer_ptr(&stdin_buffer);
- 		dlen = buffer_len(&stdin_buffer);
- 		len = write(fdin, data, dlen);
-@@ -590,7 +590,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
- 	set_nonblock(fdin);
- 	set_nonblock(fdout);
- 	/* we don't have stderr for interactive terminal sessions, see below */
--	if (fderr != -1)
-+	if (fderr >= 0)
- 		set_nonblock(fderr);
- 
- 	if (!(datafellows & SSH_BUG_IGNOREMSG) && isatty(fdin))
-@@ -614,7 +614,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
- 	max_fd = MAX(connection_in, connection_out);
- 	max_fd = MAX(max_fd, fdin);
- 	max_fd = MAX(max_fd, fdout);
--	if (fderr != -1)
-+	if (fderr >= 0)
- 		max_fd = MAX(max_fd, fderr);
- #endif
- 
-@@ -644,7 +644,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
- 		 * If we have received eof, and there is no more pending
- 		 * input data, cause a real eof by closing fdin.
- 		 */
--		if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) {
-+		if (stdin_eof && fdin >= 0 && buffer_len(&stdin_buffer) == 0) {
- 			if (fdin != fdout)
- 				close(fdin);
- 			else
-@@ -740,15 +740,15 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
- 	buffer_free(&stderr_buffer);
- 
- 	/* Close the file descriptors. */
--	if (fdout != -1)
-+	if (fdout >= 0)
- 		close(fdout);
- 	fdout = -1;
- 	fdout_eof = 1;
--	if (fderr != -1)
-+	if (fderr >= 0)
- 		close(fderr);
- 	fderr = -1;
- 	fderr_eof = 1;
--	if (fdin != -1)
-+	if (fdin >= 0)
- 		close(fdin);
- 	fdin = -1;
- 
-@@ -947,7 +947,7 @@ server_input_window_size(int type, u_int32_t seq, void *ctxt)
- 
- 	debug("Window change received.");
- 	packet_check_eom();
--	if (fdin != -1)
-+	if (fdin >= 0)
- 		pty_change_window_size(fdin, row, col, xpixel, ypixel);
- }
- 
-@@ -1007,7 +1007,7 @@ server_request_tun(void)
- 	}
- 
- 	tun = packet_get_int();
--	if (forced_tun_device != -1) {
-+	if (forced_tun_device >= 0) {
- 		if (tun != SSH_TUNID_ANY && forced_tun_device != tun)
- 			goto done;
- 		tun = forced_tun_device;
-diff --git a/sftp-client.c b/sftp-client.c
-index 2f5907c..3a2affd 100644
---- a/sftp-client.c
-+++ b/sftp-client.c
-@@ -151,7 +151,7 @@ get_msg(struct sftp_conn *conn, Buffer *m)
- }
- 
- static void
--send_string_request(struct sftp_conn *conn, u_int id, u_int code, char *s,
-+send_string_request(struct sftp_conn *conn, u_int id, u_int code, const char *s,
-     u_int len)
- {
- 	Buffer msg;
-@@ -167,7 +167,7 @@ send_string_request(struct sftp_conn *conn, u_int id, u_int code, char *s,
- 
- static void
- send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code,
--    char *s, u_int len, Attrib *a)
-+    const char *s, u_int len, Attrib *a)
- {
- 	Buffer msg;
- 
-@@ -429,7 +429,7 @@ sftp_proto_version(struct sftp_conn *conn)
- }
- 
- int
--do_close(struct sftp_conn *conn, char *handle, u_int handle_len)
-+do_close(struct sftp_conn *conn, const char *handle, u_int handle_len)
- {
- 	u_int id, status;
- 	Buffer msg;
-@@ -454,7 +454,7 @@ do_close(struct sftp_conn *conn, char *handle, u_int handle_len)
- 
- 
- static int
--do_lsreaddir(struct sftp_conn *conn, char *path, int print_flag,
-+do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag,
-     SFTP_DIRENT ***dir)
- {
- 	Buffer msg;
-@@ -577,7 +577,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int print_flag,
- }
- 
- int
--do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir)
-+do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir)
- {
- 	return(do_lsreaddir(conn, path, 0, dir));
- }
-@@ -597,7 +597,7 @@ void free_sftp_dirents(SFTP_DIRENT **s)
- }
- 
- int
--do_rm(struct sftp_conn *conn, char *path)
-+do_rm(struct sftp_conn *conn, const char *path)
- {
- 	u_int status, id;
- 
-@@ -612,7 +612,7 @@ do_rm(struct sftp_conn *conn, char *path)
- }
- 
- int
--do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int print_flag)
-+do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag)
- {
- 	u_int status, id;
- 
-@@ -628,7 +628,7 @@ do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int print_flag)
- }
- 
- int
--do_rmdir(struct sftp_conn *conn, char *path)
-+do_rmdir(struct sftp_conn *conn, const char *path)
- {
- 	u_int status, id;
- 
-@@ -644,7 +644,7 @@ do_rmdir(struct sftp_conn *conn, char *path)
- }
- 
- Attrib *
--do_stat(struct sftp_conn *conn, char *path, int quiet)
-+do_stat(struct sftp_conn *conn, const char *path, int quiet)
- {
- 	u_int id;
- 
-@@ -658,7 +658,7 @@ do_stat(struct sftp_conn *conn, char *path, int quiet)
- }
- 
- Attrib *
--do_lstat(struct sftp_conn *conn, char *path, int quiet)
-+do_lstat(struct sftp_conn *conn, const char *path, int quiet)
- {
- 	u_int id;
- 
-@@ -679,7 +679,7 @@ do_lstat(struct sftp_conn *conn, char *path, int quiet)
- 
- #ifdef notyet
- Attrib *
--do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet)
-+do_fstat(struct sftp_conn *conn, const char *handle, u_int handle_len, int quiet)
- {
- 	u_int id;
- 
-@@ -692,7 +692,7 @@ do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet)
- #endif
- 
- int
--do_setstat(struct sftp_conn *conn, char *path, Attrib *a)
-+do_setstat(struct sftp_conn *conn, const char *path, Attrib *a)
- {
- 	u_int status, id;
- 
-@@ -709,7 +709,7 @@ do_setstat(struct sftp_conn *conn, char *path, Attrib *a)
- }
- 
- int
--do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len,
-+do_fsetstat(struct sftp_conn *conn, const char *handle, u_int handle_len,
-     Attrib *a)
- {
- 	u_int status, id;
-@@ -726,7 +726,7 @@ do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len,
- }
- 
- char *
--do_realpath(struct sftp_conn *conn, char *path)
-+do_realpath(struct sftp_conn *conn, const char *path)
- {
- 	Buffer msg;
- 	u_int type, expected_id, count, id;
-@@ -775,7 +775,7 @@ do_realpath(struct sftp_conn *conn, char *path)
- }
- 
- int
--do_rename(struct sftp_conn *conn, char *oldpath, char *newpath,
-+do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath,
-     int force_legacy)
- {
- 	Buffer msg;
-@@ -811,7 +811,7 @@ do_rename(struct sftp_conn *conn, char *oldpath, char *newpath,
- }
- 
- int
--do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath)
-+do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
- {
- 	Buffer msg;
- 	u_int status, id;
-@@ -844,7 +844,7 @@ do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath)
- }
- 
- int
--do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
-+do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
- {
- 	Buffer msg;
- 	u_int status, id;
-@@ -876,7 +876,7 @@ do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
- }
- 
- int
--do_fsync(struct sftp_conn *conn, char *handle, u_int handle_len)
-+do_fsync(struct sftp_conn *conn, const char *handle, u_int handle_len)
- {
- 	Buffer msg;
- 	u_int status, id;
-@@ -907,7 +907,7 @@ do_fsync(struct sftp_conn *conn, char *handle, u_int handle_len)
- 
- #ifdef notyet
- char *
--do_readlink(struct sftp_conn *conn, char *path)
-+do_readlink(struct sftp_conn *conn, const char *path)
- {
- 	Buffer msg;
- 	u_int type, expected_id, count, id;
-@@ -1010,7 +1010,7 @@ do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len,
- 
- static void
- send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
--    u_int len, char *handle, u_int handle_len)
-+    u_int len, const char *handle, u_int handle_len)
- {
- 	Buffer msg;
- 
-@@ -1026,7 +1026,7 @@ send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
- }
- 
- int
--do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
-+do_download(struct sftp_conn *conn, const char *remote_path, const char *local_path,
-     Attrib *a, int preserve_flag, int resume_flag, int fsync_flag)
- {
- 	Attrib junk;
-@@ -1308,7 +1308,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
- }
- 
- static int
--download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
-+download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, int depth,
-     Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,
-     int fsync_flag)
- {
-@@ -1400,7 +1400,7 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
- }
- 
- int
--download_dir(struct sftp_conn *conn, char *src, char *dst,
-+download_dir(struct sftp_conn *conn, const char *src, const char *dst,
-     Attrib *dirattrib, int preserve_flag, int print_flag,
-     int resume_flag, int fsync_flag)
- {
-@@ -1419,7 +1419,7 @@ download_dir(struct sftp_conn *conn, char *src, char *dst,
- }
- 
- int
--do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
-+do_upload(struct sftp_conn *conn, const char *local_path, const char *remote_path,
-     int preserve_flag, int fsync_flag)
- {
- 	int local_fd;
-@@ -1607,7 +1607,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
- }
- 
- static int
--upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
-+upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, int depth,
-     int preserve_flag, int print_flag, int fsync_flag)
- {
- 	int ret = 0, status;
-@@ -1700,7 +1700,7 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
- }
- 
- int
--upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag,
-+upload_dir(struct sftp_conn *conn, const char *src, const char *dst, int preserve_flag,
-     int print_flag, int fsync_flag)
- {
- 	char *dst_canon;
-@@ -1719,7 +1719,7 @@ upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag,
- }
- 
- char *
--path_append(char *p1, char *p2)
-+path_append(const char *p1, const char *p2)
- {
- 	char *ret;
- 	size_t len = strlen(p1) + strlen(p2) + 2;
-diff --git a/sftp-client.h b/sftp-client.h
-index ba92ad0..c085423 100644
---- a/sftp-client.h
-+++ b/sftp-client.h
-@@ -56,79 +56,79 @@ struct sftp_conn *do_init(int, int, u_int, u_int, u_int64_t);
- u_int sftp_proto_version(struct sftp_conn *);
- 
- /* Close file referred to by 'handle' */
--int do_close(struct sftp_conn *, char *, u_int);
-+int do_close(struct sftp_conn *, const char *, u_int);
- 
- /* Read contents of 'path' to NULL-terminated array 'dir' */
--int do_readdir(struct sftp_conn *, char *, SFTP_DIRENT ***);
-+int do_readdir(struct sftp_conn *, const char *, SFTP_DIRENT ***);
- 
- /* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from do_readdir) */
- void free_sftp_dirents(SFTP_DIRENT **);
- 
- /* Delete file 'path' */
--int do_rm(struct sftp_conn *, char *);
-+int do_rm(struct sftp_conn *, const char *);
- 
- /* Create directory 'path' */
--int do_mkdir(struct sftp_conn *, char *, Attrib *, int);
-+int do_mkdir(struct sftp_conn *, const char *, Attrib *, int);
- 
- /* Remove directory 'path' */
--int do_rmdir(struct sftp_conn *, char *);
-+int do_rmdir(struct sftp_conn *, const char *);
- 
- /* Get file attributes of 'path' (follows symlinks) */
--Attrib *do_stat(struct sftp_conn *, char *, int);
-+Attrib *do_stat(struct sftp_conn *, const char *, int);
- 
- /* Get file attributes of 'path' (does not follow symlinks) */
--Attrib *do_lstat(struct sftp_conn *, char *, int);
-+Attrib *do_lstat(struct sftp_conn *, const char *, int);
- 
- /* Set file attributes of 'path' */
--int do_setstat(struct sftp_conn *, char *, Attrib *);
-+int do_setstat(struct sftp_conn *, const char *, Attrib *);
- 
- /* Set file attributes of open file 'handle' */
--int do_fsetstat(struct sftp_conn *, char *, u_int, Attrib *);
-+int do_fsetstat(struct sftp_conn *, const char *, u_int, Attrib *);
- 
- /* Canonicalise 'path' - caller must free result */
--char *do_realpath(struct sftp_conn *, char *);
-+char *do_realpath(struct sftp_conn *, const char *);
- 
- /* Get statistics for filesystem hosting file at "path" */
- int do_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int);
- 
- /* Rename 'oldpath' to 'newpath' */
--int do_rename(struct sftp_conn *, char *, char *m, int force_legacy);
-+int do_rename(struct sftp_conn *, const char *, const char *m, int force_legacy);
- 
- /* Link 'oldpath' to 'newpath' */
--int do_hardlink(struct sftp_conn *, char *, char *);
-+int do_hardlink(struct sftp_conn *, const char *, const char *);
- 
- /* Rename 'oldpath' to 'newpath' */
--int do_symlink(struct sftp_conn *, char *, char *);
-+int do_symlink(struct sftp_conn *, const char *, const char *);
- 
- /* Call fsync() on open file 'handle' */
--int do_fsync(struct sftp_conn *conn, char *, u_int);
-+int do_fsync(struct sftp_conn *conn, const char *, u_int);
- 
- /*
-  * Download 'remote_path' to 'local_path'. Preserve permissions and times
-  * if 'pflag' is set
-  */
--int do_download(struct sftp_conn *, char *, char *, Attrib *, int, int, int);
-+int do_download(struct sftp_conn *, const char *, const char *, Attrib *, int, int, int);
- 
- /*
-  * Recursively download 'remote_directory' to 'local_directory'. Preserve 
-  * times if 'pflag' is set
-  */
--int download_dir(struct sftp_conn *, char *, char *, Attrib *, int,
-+int download_dir(struct sftp_conn *, const char *, const char *, Attrib *, int,
-     int, int, int);
- 
- /*
-  * Upload 'local_path' to 'remote_path'. Preserve permissions and times
-  * if 'pflag' is set
-  */
--int do_upload(struct sftp_conn *, char *, char *, int, int);
-+int do_upload(struct sftp_conn *, const char *, const char *, int, int);
- 
- /*
-  * Recursively upload 'local_directory' to 'remote_directory'. Preserve 
-  * times if 'pflag' is set
-  */
--int upload_dir(struct sftp_conn *, char *, char *, int, int, int);
-+int upload_dir(struct sftp_conn *, const char *, const char *, int, int, int);
- 
- /* Concatenate paths, taking care of slashes. Caller must free result. */
--char *path_append(char *, char *);
-+char *path_append(const char *, const char *);
- 
- #endif
-diff --git a/sftp.c b/sftp.c
-index ad1f8c8..3987117 100644
---- a/sftp.c
-+++ b/sftp.c
-@@ -218,7 +218,7 @@ killchild(int signo)
- {
- 	if (sshpid > 1) {
- 		kill(sshpid, SIGTERM);
--		waitpid(sshpid, NULL, 0);
-+		(void) waitpid(sshpid, NULL, 0);
- 	}
- 
- 	_exit(1);
-@@ -329,7 +329,7 @@ local_do_ls(const char *args)
- 
- /* Strip one path (usually the pwd) from the start of another */
- static char *
--path_strip(char *path, char *strip)
-+path_strip(const char *path, const char *strip)
- {
- 	size_t len;
- 
-@@ -347,7 +347,7 @@ path_strip(char *path, char *strip)
- }
- 
- static char *
--make_absolute(char *p, char *pwd)
-+make_absolute(char *p, const char *pwd)
- {
- 	char *abs_str;
- 
-@@ -545,7 +545,7 @@ parse_no_flags(const char *cmd, char **argv, int argc)
- }
- 
- static int
--is_dir(char *path)
-+is_dir(const char *path)
- {
- 	struct stat sb;
- 
-@@ -557,7 +557,7 @@ is_dir(char *path)
- }
- 
- static int
--remote_is_dir(struct sftp_conn *conn, char *path)
-+remote_is_dir(struct sftp_conn *conn, const char *path)
- {
- 	Attrib *a;
- 
-@@ -571,7 +571,7 @@ remote_is_dir(struct sftp_conn *conn, char *path)
- 
- /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
- static int
--pathname_is_dir(char *pathname)
-+pathname_is_dir(const char *pathname)
- {
- 	size_t l = strlen(pathname);
- 
-@@ -579,7 +579,7 @@ pathname_is_dir(char *pathname)
- }
- 
- static int
--process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd,
-+process_get(struct sftp_conn *conn, const char *src, const char *dst, const char *pwd,
-     int pflag, int rflag, int resume, int fflag)
- {
- 	char *abs_src = NULL;
-@@ -659,7 +659,7 @@ out:
- }
- 
- static int
--process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd,
-+process_put(struct sftp_conn *conn, const char *src, const char *dst, const char *pwd,
-     int pflag, int rflag, int fflag)
- {
- 	char *tmp_dst = NULL;
-@@ -765,7 +765,7 @@ sdirent_comp(const void *aa, const void *bb)
- 
- /* sftp ls.1 replacement for directories */
- static int
--do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)
-+do_ls_dir(struct sftp_conn *conn, const char *path, const char *strip_path, int lflag)
- {
- 	int n;
- 	u_int c = 1, colspace = 0, columns = 1;
-@@ -850,7 +850,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)
- 
- /* sftp ls.1 replacement which handles path globs */
- static int
--do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
-+do_globbed_ls(struct sftp_conn *conn, const char *path, const char *strip_path,
-     int lflag)
- {
- 	char *fname, *lname;
-@@ -931,7 +931,7 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
- }
- 
- static int
--do_df(struct sftp_conn *conn, char *path, int hflag, int iflag)
-+do_df(struct sftp_conn *conn, const char *path, int hflag, int iflag)
- {
- 	struct sftp_statvfs st;
- 	char s_used[FMT_SCALED_STRSIZE];
-diff --git a/ssh-agent.c b/ssh-agent.c
-index 117fdde..2b50132 100644
---- a/ssh-agent.c
-+++ b/ssh-agent.c
-@@ -1037,8 +1037,8 @@ main(int ac, char **av)
- 	sanitise_stdfd();
- 
- 	/* drop */
--	setegid(getgid());
--	setgid(getgid());
-+	(void) setegid(getgid());
-+	(void) setgid(getgid());
- 
- #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
- 	/* Disable ptrace on Linux without sgid bit */
-diff --git a/sshd.c b/sshd.c
-index 773bb02..1eaa9f7 100644
---- a/sshd.c
-+++ b/sshd.c
-@@ -771,8 +771,10 @@ privsep_preauth(Authctxt *authctxt)
- 		if (getuid() == 0 || geteuid() == 0)
- 			privsep_preauth_child();
- 		setproctitle("%s", "[net]");
--		if (box != NULL)
-+		if (box != NULL) {
- 			ssh_sandbox_child(box);
-+			free(box);
-+		}
- 
- 		return 0;
- 	}
-@@ -1439,6 +1441,9 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
- 		if (num_listen_socks < 0)
- 			break;
- 	}
-+
-+	if (fdset != NULL)
-+		free(fdset);
- }
- 
- 
diff --git a/openssh-6.6.1p1-ignore-SIGXFSZ-in-postauth.patch b/openssh-6.6.1p1-ignore-SIGXFSZ-in-postauth.patch
deleted file mode 100644
index 87434ce..0000000
--- a/openssh-6.6.1p1-ignore-SIGXFSZ-in-postauth.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-diff --git a/ChangeLog b/ChangeLog
-index 3887495..a4dc72f 100644
---- a/ChangeLog
-+++ b/ChangeLog
-@@ -1,3 +1,9 @@
-+20140823
-+ - (djm) [sshd.c] Ignore SIGXFSZ in preauth monitor child; can explode on
-+   lastlog writing on platforms with high UIDs; bz#2263
-+ - (djm) [monitor.c sshd.c] SIGXFSZ needs to be ignored in postauth
-+   monitor, not preauth; bz#2263
-+
- 20140703
-  - OpenBSD CVS Sync
-    - djm at cvs.openbsd.org 2014/07/03 03:34:09
-diff --git a/monitor.c b/monitor.c
-index bdabe21..5a65114 100644
---- a/monitor.c
-+++ b/monitor.c
-@@ -501,6 +501,9 @@ monitor_child_postauth(struct monitor *pmonitor)
- 	signal(SIGHUP, &monitor_child_handler);
- 	signal(SIGTERM, &monitor_child_handler);
- 	signal(SIGINT, &monitor_child_handler);
-+#ifdef SIGXFSZ
-+	signal(SIGXFSZ, SIG_IGN);
-+#endif
- 
- 	if (compat20) {
- 		mon_dispatch = mon_dispatch_postauth20;
diff --git a/openssh-6.6.1p1-log-in-chroot.patch b/openssh-6.6.1p1-log-in-chroot.patch
index bccf39b..7590812 100644
--- a/openssh-6.6.1p1-log-in-chroot.patch
+++ b/openssh-6.6.1p1-log-in-chroot.patch
@@ -1,7 +1,6 @@
-diff --git a/log.c b/log.c
-index 32e1d2e..d4caeb5 100644
---- a/log.c
-+++ b/log.c
+diff -up openssh-6.8p1/log.c.log-in-chroot openssh-6.8p1/log.c
+--- openssh-6.8p1/log.c.log-in-chroot	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/log.c	2015-03-18 12:59:29.694022313 +0100
 @@ -241,6 +241,11 @@ debug3(const char *fmt,...)
  void
  log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
@@ -14,7 +13,7 @@ index 32e1d2e..d4caeb5 100644
  #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
  	struct syslog_data sdata = SYSLOG_DATA_INIT;
  #endif
-@@ -264,8 +269,10 @@ log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
+@@ -264,8 +269,10 @@ log_init(char *av0, LogLevel level, Sysl
  		exit(1);
  	}
  
@@ -27,10 +26,9 @@ index 32e1d2e..d4caeb5 100644
  
  	log_on_stderr = on_stderr;
  	if (on_stderr)
-diff --git a/log.h b/log.h
-index ae7df25..30c3310 100644
---- a/log.h
-+++ b/log.h
+diff -up openssh-6.8p1/log.h.log-in-chroot openssh-6.8p1/log.h
+--- openssh-6.8p1/log.h.log-in-chroot	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/log.h	2015-03-18 12:59:29.694022313 +0100
 @@ -49,6 +49,7 @@ typedef enum {
  typedef void (log_handler_fn)(LogLevel, const char *, void *);
  
@@ -39,11 +37,10 @@ index ae7df25..30c3310 100644
  void     log_change_level(LogLevel);
  int      log_is_on_stderr(void);
  void     log_redirect_stderr_to(const char *);
-diff --git a/monitor.c b/monitor.c
-index 7461fae..da2f766 100644
---- a/monitor.c
-+++ b/monitor.c
-@@ -364,6 +364,8 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
+diff -up openssh-6.8p1/monitor.c.log-in-chroot openssh-6.8p1/monitor.c
+--- openssh-6.8p1/monitor.c.log-in-chroot	2015-03-18 12:59:29.669022374 +0100
++++ openssh-6.8p1/monitor.c	2015-03-18 13:01:52.894671198 +0100
+@@ -357,6 +357,8 @@ monitor_child_preauth(Authctxt *_authctx
  	close(pmonitor->m_log_sendfd);
  	pmonitor->m_log_sendfd = pmonitor->m_recvfd = -1;
  
@@ -52,7 +49,7 @@ index 7461fae..da2f766 100644
  	authctxt = _authctxt;
  	memset(authctxt, 0, sizeof(*authctxt));
  
-@@ -472,6 +474,8 @@ monitor_child_postauth(struct monitor *pmonitor)
+@@ -465,6 +467,8 @@ monitor_child_postauth(struct monitor *p
  	close(pmonitor->m_recvfd);
  	pmonitor->m_recvfd = -1;
  
@@ -61,7 +58,7 @@ index 7461fae..da2f766 100644
  	monitor_set_child_handler(pmonitor->m_pid);
  	signal(SIGHUP, &monitor_child_handler);
  	signal(SIGTERM, &monitor_child_handler);
-@@ -552,7 +556,7 @@ monitor_read_log(struct monitor *pmonitor)
+@@ -566,7 +570,7 @@ monitor_read_log(struct monitor *pmonito
  	if (log_level_name(level) == NULL)
  		fatal("%s: invalid log level %u (corrupted message?)",
  		    __func__, level);
@@ -70,8 +67,8 @@ index 7461fae..da2f766 100644
  
  	buffer_free(&logmsg);
  	free(msg);
-@@ -2083,13 +2087,28 @@ monitor_init(void)
- 		mm_init_compression(mon->m_zlib);
+@@ -1998,13 +2002,28 @@ monitor_init(void)
+ 		    (ssh_packet_comp_free_func *)mm_zfree);
  	}
  
 +	mon->m_state = "";
@@ -101,13 +98,12 @@ index 7461fae..da2f766 100644
  }
  
  #ifdef GSSAPI
-diff --git a/monitor.h b/monitor.h
-index ff79fbb..00c2028 100644
---- a/monitor.h
-+++ b/monitor.h
+diff -up openssh-6.8p1/monitor.h.log-in-chroot openssh-6.8p1/monitor.h
+--- openssh-6.8p1/monitor.h.log-in-chroot	2015-03-18 12:59:29.695022310 +0100
++++ openssh-6.8p1/monitor.h	2015-03-18 13:02:56.926514197 +0100
 @@ -83,10 +83,11 @@ struct monitor {
  	struct mm_master	*m_zlib;
- 	struct Kex		**m_pkex;
+ 	struct kex		**m_pkex;
  	pid_t			 m_pid;
 +	char		*m_state;
  };
@@ -118,11 +114,10 @@ index ff79fbb..00c2028 100644
  void monitor_sync(struct monitor *);
  
  struct Authctxt;
-diff --git a/session.c b/session.c
-index e4add93..bc4a8dd 100644
---- a/session.c
-+++ b/session.c
-@@ -160,6 +160,8 @@ login_cap_t *lc;
+diff -up openssh-6.8p1/session.c.log-in-chroot openssh-6.8p1/session.c
+--- openssh-6.8p1/session.c.log-in-chroot	2015-03-18 12:59:29.675022359 +0100
++++ openssh-6.8p1/session.c	2015-03-18 12:59:29.696022308 +0100
+@@ -161,6 +161,8 @@ login_cap_t *lc;
  
  static int is_child = 0;
  
@@ -131,7 +126,7 @@ index e4add93..bc4a8dd 100644
  /* Name and directory of socket for authentication agent forwarding. */
  static char *auth_sock_name = NULL;
  static char *auth_sock_dir = NULL;
-@@ -523,8 +525,8 @@ do_exec_no_pty(Session *s, const char *command)
+@@ -506,8 +508,8 @@ do_exec_no_pty(Session *s, const char *c
  		is_child = 1;
  
  		/* Child.  Reinitialize the log since the pid has changed. */
@@ -142,7 +137,7 @@ index e4add93..bc4a8dd 100644
  
  		/*
  		 * Create a new session and process group since the 4.4BSD
-@@ -692,8 +694,8 @@ do_exec_pty(Session *s, const char *command)
+@@ -675,8 +677,8 @@ do_exec_pty(Session *s, const char *comm
  		close(ptymaster);
  
  		/* Child.  Reinitialize the log because the pid has changed. */
@@ -153,7 +148,7 @@ index e4add93..bc4a8dd 100644
  		/* Close the master side of the pseudo tty. */
  		close(ptyfd);
  
-@@ -797,6 +799,7 @@ do_exec(Session *s, const char *command)
+@@ -780,6 +782,7 @@ do_exec(Session *s, const char *command)
  	int ret;
  	const char *forced = NULL;
  	char session_type[1024], *tty = NULL;
@@ -161,7 +156,7 @@ index e4add93..bc4a8dd 100644
  
  	if (options.adm_forced_command) {
  		original_command = command;
-@@ -854,6 +857,10 @@ do_exec(Session *s, const char *command)
+@@ -837,6 +840,10 @@ do_exec(Session *s, const char *command)
  			tty += 5;
  	}
  
@@ -172,7 +167,7 @@ index e4add93..bc4a8dd 100644
  	verbose("Starting session: %s%s%s for %s from %.200s port %d",
  	    session_type,
  	    tty == NULL ? "" : " on ",
-@@ -1681,14 +1688,6 @@ child_close_fds(void)
+@@ -1678,14 +1685,6 @@ child_close_fds(void)
  	 * descriptors left by system functions.  They will be closed later.
  	 */
  	endpwent();
@@ -187,7 +182,7 @@ index e4add93..bc4a8dd 100644
  }
  
  /*
-@@ -1834,8 +1833,6 @@ do_child(Session *s, const char *command)
+@@ -1831,8 +1830,6 @@ do_child(Session *s, const char *command
  			exit(1);
  	}
  
@@ -196,7 +191,7 @@ index e4add93..bc4a8dd 100644
  	if (!options.use_login)
  		do_rc_files(s, shell);
  
-@@ -1859,9 +1856,17 @@ do_child(Session *s, const char *command)
+@@ -1856,9 +1853,17 @@ do_child(Session *s, const char *command
  		argv[i] = NULL;
  		optind = optreset = 1;
  		__progname = argv[0];
@@ -215,10 +210,9 @@ index e4add93..bc4a8dd 100644
  	fflush(NULL);
  
  	if (options.use_login) {
-diff --git a/sftp-server-main.c b/sftp-server-main.c
-index 7e644ab..e162b7a 100644
---- a/sftp-server-main.c
-+++ b/sftp-server-main.c
+diff -up openssh-6.8p1/sftp-server-main.c.log-in-chroot openssh-6.8p1/sftp-server-main.c
+--- openssh-6.8p1/sftp-server-main.c.log-in-chroot	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/sftp-server-main.c	2015-03-18 12:59:29.696022308 +0100
 @@ -47,5 +47,5 @@ main(int argc, char **argv)
  		return 1;
  	}
@@ -226,11 +220,10 @@ index 7e644ab..e162b7a 100644
 -	return (sftp_server_main(argc, argv, user_pw));
 +	return (sftp_server_main(argc, argv, user_pw, 0));
  }
-diff --git a/sftp-server.c b/sftp-server.c
-index b8eb59c..a0e644c 100644
---- a/sftp-server.c
-+++ b/sftp-server.c
-@@ -1437,7 +1437,7 @@ sftp_server_usage(void)
+diff -up openssh-6.8p1/sftp-server.c.log-in-chroot openssh-6.8p1/sftp-server.c
+--- openssh-6.8p1/sftp-server.c.log-in-chroot	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/sftp-server.c	2015-03-18 13:03:52.510377911 +0100
+@@ -1502,7 +1502,7 @@ sftp_server_usage(void)
  }
  
  int
@@ -238,8 +231,8 @@ index b8eb59c..a0e644c 100644
 +sftp_server_main(int argc, char **argv, struct passwd *user_pw, int reset_handler)
  {
  	fd_set *rset, *wset;
- 	int i, in, out, max, ch, skipargs = 0, log_stderr = 0;
-@@ -1450,7 +1450,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
+ 	int i, r, in, out, max, ch, skipargs = 0, log_stderr = 0;
+@@ -1515,7 +1515,7 @@ sftp_server_main(int argc, char **argv,
  	extern char *__progname;
  
  	__progname = ssh_get_progname(argv[0]);
@@ -248,19 +241,18 @@ index b8eb59c..a0e644c 100644
  
  	pw = pwcopy(user_pw);
  
-@@ -1521,7 +1521,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
+@@ -1586,7 +1586,7 @@ sftp_server_main(int argc, char **argv,
  		}
  	}
  
 -	log_init(__progname, log_level, log_facility, log_stderr);
 +	log_init_handler(__progname, log_level, log_facility, log_stderr, reset_handler);
  
- 	if ((cp = getenv("SSH_CONNECTION")) != NULL) {
- 		client_addr = xstrdup(cp);
-diff --git a/sftp.h b/sftp.h
-index 2bde8bb..ddf1a39 100644
---- a/sftp.h
-+++ b/sftp.h
+ #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
+ 	/*
+diff -up openssh-6.8p1/sftp.h.log-in-chroot openssh-6.8p1/sftp.h
+--- openssh-6.8p1/sftp.h.log-in-chroot	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/sftp.h	2015-03-18 12:59:29.696022308 +0100
 @@ -97,5 +97,5 @@
  
  struct passwd;
@@ -268,11 +260,10 @@ index 2bde8bb..ddf1a39 100644
 -int	sftp_server_main(int, char **, struct passwd *);
 +int	sftp_server_main(int, char **, struct passwd *, int);
  void	sftp_server_cleanup_exit(int) __attribute__((noreturn));
-diff --git a/sshd.c b/sshd.c
-index 3eee75a..9c00bcb 100644
---- a/sshd.c
-+++ b/sshd.c
-@@ -745,7 +745,7 @@ privsep_postauth(Authctxt *authctxt)
+diff -up openssh-6.8p1/sshd.c.log-in-chroot openssh-6.8p1/sshd.c
+--- openssh-6.8p1/sshd.c.log-in-chroot	2015-03-18 12:59:29.691022320 +0100
++++ openssh-6.8p1/sshd.c	2015-03-18 12:59:29.697022305 +0100
+@@ -744,7 +744,7 @@ privsep_postauth(Authctxt *authctxt)
  	}
  
  	/* New socket pair */
@@ -281,7 +272,7 @@ index 3eee75a..9c00bcb 100644
  
  	pmonitor->m_pid = fork();
  	if (pmonitor->m_pid == -1)
-@@ -763,6 +763,11 @@ privsep_postauth(Authctxt *authctxt)
+@@ -762,6 +762,11 @@ privsep_postauth(Authctxt *authctxt)
  
  	close(pmonitor->m_sendfd);
  	pmonitor->m_sendfd = -1;
diff --git a/openssh-6.6.1p1-partial-success.patch b/openssh-6.6.1p1-partial-success.patch
deleted file mode 100644
index b5c61cf..0000000
--- a/openssh-6.6.1p1-partial-success.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-diff --git a/auth2.c b/auth2.c
-index d9b440a..ec0bf12 100644
---- a/auth2.c
-+++ b/auth2.c
-@@ -355,8 +355,9 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
- 		authctxt->success = 1;
- 	} else {
- 
--		/* Allow initial try of "none" auth without failure penalty */
--		if (!authctxt->server_caused_failure &&
-+		/* Allow initial try of "none" auth without failure penalty
-+		 * Partial succes is not failure */
-+		if (!authctxt->server_caused_failure && !partial &&
- 		    (authctxt->attempt > 1 || strcmp(method, "none") != 0))
- 			authctxt->failures++;
- 		if (authctxt->failures >= options.max_authtries) {
diff --git a/openssh-6.6.1p1-selinux-contexts.patch b/openssh-6.6.1p1-selinux-contexts.patch
index a831a15..425ffda 100644
--- a/openssh-6.6.1p1-selinux-contexts.patch
+++ b/openssh-6.6.1p1-selinux-contexts.patch
@@ -1,16 +1,16 @@
 diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c
-index 0077dd7..e3f2ced 100644
+index 8f32464..18a2ca4 100644
 --- a/openbsd-compat/port-linux-sshd.c
 +++ b/openbsd-compat/port-linux-sshd.c
-@@ -31,6 +31,7 @@
- #include "xmalloc.h"
+@@ -32,6 +32,7 @@
+ #include "misc.h"      /* servconf.h needs misc.h for struct ForwardOptions */
  #include "servconf.h"
  #include "port-linux.h"
 +#include "misc.h"
  #include "key.h"
  #include "hostfile.h"
  #include "auth.h"
-@@ -444,7 +445,7 @@ sshd_selinux_setup_exec_context(char *pwname)
+@@ -445,7 +446,7 @@ sshd_selinux_setup_exec_context(char *pwname)
  void
  sshd_selinux_copy_context(void)
  {
@@ -19,7 +19,7 @@ index 0077dd7..e3f2ced 100644
  
  	if (!sshd_selinux_enabled())
  		return;
-@@ -460,6 +461,58 @@ sshd_selinux_copy_context(void)
+@@ -461,6 +462,58 @@ sshd_selinux_copy_context(void)
  	}
  }
  
@@ -104,10 +104,10 @@ index cb51f99..8b7cda2 100644
  
  #ifdef LINUX_OOM_ADJUST
 diff --git a/sshd.c b/sshd.c
-index 512c7ed..3eee75a 100644
+index 2871fe9..39b9c08 100644
 --- a/sshd.c
 +++ b/sshd.c
-@@ -637,7 +637,7 @@ privsep_preauth_child(void)
+@@ -629,7 +629,7 @@ privsep_preauth_child(void)
  	demote_sensitive_data();
  
  #ifdef WITH_SELINUX
diff --git a/openssh-6.6.1p1-utf8-banner.patch b/openssh-6.6.1p1-utf8-banner.patch
index 1ab8ade..1513b6f 100644
--- a/openssh-6.6.1p1-utf8-banner.patch
+++ b/openssh-6.6.1p1-utf8-banner.patch
@@ -1,21 +1,19 @@
-diff --git a/Makefile.in b/Makefile.in
-index 2ad26ff..0f0d39f 100644
---- a/Makefile.in
-+++ b/Makefile.in
-@@ -81,7 +81,7 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \
+diff -up openssh-6.8p1/Makefile.in.utf8-banner openssh-6.8p1/Makefile.in
+--- openssh-6.8p1/Makefile.in.utf8-banner	2015-03-18 12:41:28.174713188 +0100
++++ openssh-6.8p1/Makefile.in	2015-03-18 12:45:52.723048114 +0100
+@@ -94,7 +94,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
  	msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
- 	ssh-pkcs11.o krl.o smult_curve25519_ref.o \
- 	kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \
--	ssh-ed25519.o digest-openssl.o hmac.o \
-+	ssh-ed25519.o digest-openssl.o hmac.o utf8_stringprep.o \
- 	sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o
- 
- SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
-diff --git a/misc.h b/misc.h
-index d4df619..d98b83d 100644
---- a/misc.h
-+++ b/misc.h
-@@ -106,4 +106,7 @@ char	*read_passphrase(const char *, int);
+ 	ssh-pkcs11.o smult_curve25519_ref.o \
+ 	poly1305.o chacha.o cipher-chachapoly.o \
+-	ssh-ed25519.o digest-openssl.o digest-libc.o hmac.o \
++	ssh-ed25519.o digest-openssl.o digest-libc.o hmac.o utf8_stringprep.o \
+ 	sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \
+ 	kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
+ 	kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \
+diff -up openssh-6.8p1/misc.h.utf8-banner openssh-6.8p1/misc.h
+--- openssh-6.8p1/misc.h.utf8-banner	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/misc.h	2015-03-18 12:41:28.175713185 +0100
+@@ -135,4 +135,7 @@ char	*read_passphrase(const char *, int)
  int	 ask_permission(const char *, ...) __attribute__((format(printf, 1, 2)));
  int	 read_keyfile_line(FILE *, const char *, char *, size_t, u_long *);
  
@@ -23,10 +21,9 @@ index d4df619..d98b83d 100644
 +int utf8_stringprep(const char *, char *, size_t);
 +
  #endif /* _MISC_H */
-diff --git a/sshconnect2.c b/sshconnect2.c
-index b00658b..08064f4 100644
---- a/sshconnect2.c
-+++ b/sshconnect2.c
+diff -up openssh-6.8p1/sshconnect2.c.utf8-banner openssh-6.8p1/sshconnect2.c
+--- openssh-6.8p1/sshconnect2.c.utf8-banner	2015-03-18 12:41:28.161713220 +0100
++++ openssh-6.8p1/sshconnect2.c	2015-03-18 12:44:05.483317714 +0100
 @@ -33,6 +33,8 @@
  
  #include <errno.h>
@@ -36,8 +33,8 @@ index b00658b..08064f4 100644
  #include <netdb.h>
  #include <pwd.h>
  #include <signal.h>
-@@ -519,21 +521,51 @@ input_userauth_error(int type, u_int32_t seq, void *ctxt)
- 	    "type %d", type);
+@@ -532,21 +534,51 @@ input_userauth_error(int type, u_int32_t
+ 	return 0;
  }
  
 +/* Check whether we can display UTF-8 safely */
@@ -56,7 +53,7 @@ index b00658b..08064f4 100644
 +}
 +
  /* ARGSUSED */
- void
+ int
  input_userauth_banner(int type, u_int32_t seq, void *ctxt)
  {
  	char *msg, *raw, *lang;
@@ -90,11 +87,9 @@ index b00658b..08064f4 100644
  		fprintf(stderr, "%s", msg);
  		free(msg);
  	}
-diff --git a/stringprep-tables.c b/stringprep-tables.c
-new file mode 100644
-index 0000000..49f4d9d
---- /dev/null
-+++ b/stringprep-tables.c
+diff -up openssh-6.8p1/stringprep-tables.c.utf8-banner openssh-6.8p1/stringprep-tables.c
+--- openssh-6.8p1/stringprep-tables.c.utf8-banner	2015-03-18 12:41:28.175713185 +0100
++++ openssh-6.8p1/stringprep-tables.c	2015-03-18 12:41:28.175713185 +0100
 @@ -0,0 +1,661 @@
 +/* Public domain.  */
 +
@@ -757,11 +752,9 @@ index 0000000..49f4d9d
 +	{ 0xE0020, 0xE007F },
 +};
 +
-diff --git a/utf8_stringprep.c b/utf8_stringprep.c
-new file mode 100644
-index 0000000..bcafae7
---- /dev/null
-+++ b/utf8_stringprep.c
+diff -up openssh-6.8p1/utf8_stringprep.c.utf8-banner openssh-6.8p1/utf8_stringprep.c
+--- openssh-6.8p1/utf8_stringprep.c.utf8-banner	2015-03-18 12:41:28.175713185 +0100
++++ openssh-6.8p1/utf8_stringprep.c	2015-03-18 12:41:28.175713185 +0100
 @@ -0,0 +1,229 @@
 +/*
 + * Copyright (c) 2013 Damien Miller <djm at mindrot.org>
diff --git a/openssh-6.6p1-CVE-2014-2653.patch b/openssh-6.6p1-CVE-2014-2653.patch
deleted file mode 100644
index c3bd0a1..0000000
--- a/openssh-6.6p1-CVE-2014-2653.patch
+++ /dev/null
@@ -1,80 +0,0 @@
-diff --git a/ChangeLog b/ChangeLog
-index 38de846..1603a07 100644
---- a/ChangeLog
-+++ b/ChangeLog
-@@ -1,3 +1,14 @@
-+20140420
-+   - djm at cvs.openbsd.org 2014/04/01 03:34:10
-+     [sshconnect.c]
-+     When using VerifyHostKeyDNS with a DNSSEC resolver, down-convert any
-+     certificate keys to plain keys and attempt SSHFP resolution.
-+     
-+     Prevents a server from skipping SSHFP lookup and forcing a new-hostkey
-+     dialog by offering only certificate keys.
-+     
-+     Reported by mcv21 AT cam.ac.uk
-+
- 20140313
-  - (djm) Release OpenSSH 6.6
- 
-diff --git a/sshconnect.c b/sshconnect.c
-index 394cca8..e636f33 100644
---- a/sshconnect.c
-+++ b/sshconnect.c
-@@ -1219,30 +1219,40 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
- {
- 	int flags = 0;
- 	char *fp;
-+	Key *plain = NULL;
- 
- 	fp = key_selected_fingerprint(host_key, SSH_FP_HEX);
- 	debug("Server host key: %s %s%s", key_type(host_key),
- 	    key_fingerprint_prefix(), fp);
- 	free(fp);
- 
--	/* XXX certs are not yet supported for DNS */
--	if (!key_is_cert(host_key) && options.verify_host_key_dns &&
--	    verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) {
--		if (flags & DNS_VERIFY_FOUND) {
--
--			if (options.verify_host_key_dns == 1 &&
--			    flags & DNS_VERIFY_MATCH &&
--			    flags & DNS_VERIFY_SECURE)
--				return 0;
--
--			if (flags & DNS_VERIFY_MATCH) {
--				matching_host_key_dns = 1;
--			} else {
--				warn_changed_key(host_key);
--				error("Update the SSHFP RR in DNS with the new "
--				    "host key to get rid of this message.");
-+	if (options.verify_host_key_dns) {
-+		/*
-+		 * XXX certs are not yet supported for DNS, so downgrade
-+		 * them and try the plain key.
-+		 */
-+		plain = key_from_private(host_key);
-+		if (key_is_cert(plain))
-+			key_drop_cert(plain);
-+		if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) {
-+			if (flags & DNS_VERIFY_FOUND) {
-+				if (options.verify_host_key_dns == 1 &&
-+				    flags & DNS_VERIFY_MATCH &&
-+				    flags & DNS_VERIFY_SECURE) {
-+					key_free(plain);
-+					return 0;
-+				}
-+				if (flags & DNS_VERIFY_MATCH) {
-+					matching_host_key_dns = 1;
-+				} else {
-+					warn_changed_key(plain);
-+					error("Update the SSHFP RR in DNS "
-+					    "with the new host key to get rid "
-+					    "of this message.");
-+				}
- 			}
- 		}
-+		key_free(plain);
- 	}
- 
- 	return check_host_key(host, hostaddr, options.port, host_key, RDRW,
diff --git a/openssh-6.6p1-GSSAPIEnablek5users.patch b/openssh-6.6p1-GSSAPIEnablek5users.patch
index a60d608..cf01dd5 100644
--- a/openssh-6.6p1-GSSAPIEnablek5users.patch
+++ b/openssh-6.6p1-GSSAPIEnablek5users.patch
@@ -1,16 +1,15 @@
-diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
-index 0a4930e..a7c0c5f 100644
---- a/gss-serv-krb5.c
-+++ b/gss-serv-krb5.c
-@@ -260,7 +260,6 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name,
+diff -up openssh-6.8p1/gss-serv-krb5.c.GSSAPIEnablek5users openssh-6.8p1/gss-serv-krb5.c
+--- openssh-6.8p1/gss-serv-krb5.c.GSSAPIEnablek5users	2015-03-18 13:04:21.505306818 +0100
++++ openssh-6.8p1/gss-serv-krb5.c	2015-03-18 13:04:21.527306764 +0100
+@@ -260,7 +260,6 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri
  	FILE *fp;
  	char file[MAXPATHLEN];
- 	char line[BUFSIZ];
+ 	char line[BUFSIZ] = "";
 -	char kuser[65]; /* match krb5_kuserok() */
  	struct stat st;
  	struct passwd *pw = the_authctxt->pw;
  	int found_principal = 0;
-@@ -269,7 +268,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name,
+@@ -269,7 +268,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri
  
  	snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir);
  	/* If both .k5login and .k5users DNE, self-login is ok. */
@@ -19,37 +18,36 @@ index 0a4930e..a7c0c5f 100644
                  return ssh_krb5_kuserok(krb_context, principal, luser,
                                          k5login_exists);
  	}
-diff --git a/servconf.c b/servconf.c
-index d482e79..ad5869b 100644
---- a/servconf.c
-+++ b/servconf.c
-@@ -158,6 +158,7 @@ initialize_server_options(ServerOptions *options)
- 	options->ip_qos_bulk = -1;
+diff -up openssh-6.8p1/servconf.c.GSSAPIEnablek5users openssh-6.8p1/servconf.c
+--- openssh-6.8p1/servconf.c.GSSAPIEnablek5users	2015-03-18 13:04:21.516306791 +0100
++++ openssh-6.8p1/servconf.c	2015-03-18 13:05:26.846146608 +0100
+@@ -168,6 +168,7 @@ initialize_server_options(ServerOptions
  	options->version_addendum = NULL;
+ 	options->fingerprint_hash = -1;
  	options->use_kuserok = -1;
 +	options->enable_k5users = -1;
  }
  
- void
-@@ -315,6 +316,8 @@ fill_default_server_options(ServerOptions *options)
- 		options->show_patchlevel = 0;
+ /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
+@@ -348,6 +349,8 @@ fill_default_server_options(ServerOption
+ 		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
  	if (options->use_kuserok == -1)
  		options->use_kuserok = 1;
 +	if (options->enable_k5users == -1)
 +		options->enable_k5users = 0;
- 
  	/* Turn privilege separation on by default */
  	if (use_privsep == -1)
-@@ -356,7 +359,7 @@ typedef enum {
+ 		use_privsep = PRIVSEP_NOSANDBOX;
+@@ -406,7 +409,7 @@ typedef enum {
  	sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication,
- 	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
- 	sClientAliveCountMax, sAuthorizedKeysFile,
+ 	sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes,
+ 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
 -	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
 +	sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor,
  	sGssKeyEx, sGssStoreRekey, sAcceptEnv, sPermitTunnel,
  	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
  	sUsePrivilegeSeparation, sAllowAgentForwarding,
-@@ -430,6 +433,7 @@ static struct {
+@@ -484,6 +487,7 @@ static struct {
  	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
  	{ "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
  	{ "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
@@ -57,7 +55,7 @@ index d482e79..ad5869b 100644
  #else
  	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
  	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
-@@ -437,6 +441,7 @@ static struct {
+@@ -491,6 +495,7 @@ static struct {
  	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
  	{ "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
  	{ "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
@@ -65,7 +63,7 @@ index d482e79..ad5869b 100644
  #endif
  	{ "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
  	{ "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
-@@ -1536,6 +1541,10 @@ process_server_config_line(ServerOptions *options, char *line,
+@@ -1623,6 +1628,10 @@ process_server_config_line(ServerOptions
  		intptr = &options->use_kuserok;
  		goto parse_flag;
  
@@ -76,7 +74,7 @@ index d482e79..ad5869b 100644
  	case sPermitOpen:
  		arg = strdelim(&cp);
  		if (!arg || *arg == '\0')
-@@ -1824,6 +1833,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
+@@ -1947,6 +1956,7 @@ copy_set_server_options(ServerOptions *d
  	M_CP_INTOPT(ip_qos_interactive);
  	M_CP_INTOPT(ip_qos_bulk);
  	M_CP_INTOPT(use_kuserok);
@@ -84,19 +82,18 @@ index d482e79..ad5869b 100644
  	M_CP_INTOPT(rekey_limit);
  	M_CP_INTOPT(rekey_interval);
  
-@@ -2076,6 +2086,7 @@ dump_config(ServerOptions *o)
- 	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
+@@ -2207,6 +2217,7 @@ dump_config(ServerOptions *o)
  	dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
+ 	dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
  	dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok);
 +	dump_cfg_fmtint(sGssEnablek5users, o->enable_k5users);
  
  	/* string arguments */
  	dump_cfg_string(sPidFile, o->pid_file);
-diff --git a/servconf.h b/servconf.h
-index 5117dfa..d63cb71 100644
---- a/servconf.h
-+++ b/servconf.h
-@@ -173,7 +173,8 @@ typedef struct {
+diff -up openssh-6.8p1/servconf.h.GSSAPIEnablek5users openssh-6.8p1/servconf.h
+--- openssh-6.8p1/servconf.h.GSSAPIEnablek5users	2015-03-18 13:04:21.506306815 +0100
++++ openssh-6.8p1/servconf.h	2015-03-18 13:04:21.528306762 +0100
+@@ -177,7 +177,8 @@ typedef struct {
  
  	int	num_permitted_opens;
  
@@ -106,10 +103,9 @@ index 5117dfa..d63cb71 100644
  	char   *chroot_directory;
  	char   *revoked_keys_file;
  	char   *trusted_user_ca_keys;
-diff --git a/sshd_config b/sshd_config
-index 43671f6..6ab00ed 100644
---- a/sshd_config
-+++ b/sshd_config
+diff -up openssh-6.8p1/sshd_config.GSSAPIEnablek5users openssh-6.8p1/sshd_config
+--- openssh-6.8p1/sshd_config.GSSAPIEnablek5users	2015-03-18 13:04:21.506306815 +0100
++++ openssh-6.8p1/sshd_config	2015-03-18 13:04:21.528306762 +0100
 @@ -94,6 +94,7 @@ GSSAPIAuthentication yes
  GSSAPICleanupCredentials no
  #GSSAPIStrictAcceptorCheck yes
@@ -118,11 +114,10 @@ index 43671f6..6ab00ed 100644
  
  # Set this to 'yes' to enable PAM authentication, account processing,
  # and session processing. If this is enabled, PAM authentication will
-diff --git a/sshd_config.5 b/sshd_config.5
-index e0e5fff..aa9525d 100644
---- a/sshd_config.5
-+++ b/sshd_config.5
-@@ -505,6 +505,12 @@ on logout.
+diff -up openssh-6.8p1/sshd_config.5.GSSAPIEnablek5users openssh-6.8p1/sshd_config.5
+--- openssh-6.8p1/sshd_config.5.GSSAPIEnablek5users	2015-03-18 13:04:21.506306815 +0100
++++ openssh-6.8p1/sshd_config.5	2015-03-18 13:04:21.528306762 +0100
+@@ -576,6 +576,12 @@ on logout.
  The default is
  .Dq yes .
  Note that this option applies to protocol version 2 only.
diff --git a/openssh-6.6p1-audit.patch b/openssh-6.6p1-audit.patch
deleted file mode 100644
index 2ee2012..0000000
--- a/openssh-6.6p1-audit.patch
+++ /dev/null
@@ -1,2312 +0,0 @@
-diff --git a/Makefile.in b/Makefile.in
-index 0f0d39f..9d8c2eb 100644
---- a/Makefile.in
-+++ b/Makefile.in
-@@ -82,7 +82,8 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \
- 	ssh-pkcs11.o krl.o smult_curve25519_ref.o \
- 	kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \
- 	ssh-ed25519.o digest-openssl.o hmac.o utf8_stringprep.o \
--	sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o
-+	sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \
-+	auditstub.o
- 
- SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
- 	sshconnect.o sshconnect1.o sshconnect2.o mux.o \
-diff --git a/audit-bsm.c b/audit-bsm.c
-index 6135591..5160869 100644
---- a/audit-bsm.c
-+++ b/audit-bsm.c
-@@ -375,10 +375,23 @@ audit_connection_from(const char *host, int port)
- #endif
- }
- 
--void
-+int
- audit_run_command(const char *command)
- {
- 	/* not implemented */
-+	return 0;
-+}
-+
-+void
-+audit_end_command(int handle, const char *command)
-+{
-+	/* not implemented */
-+}
-+
-+void
-+audit_count_session_open(void)
-+{
-+	/* not necessary */
- }
- 
- void
-@@ -393,6 +406,12 @@ audit_session_close(struct logininfo *li)
- 	/* not implemented */
- }
- 
-+int
-+audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv)
-+{
-+	/* not implemented */
-+}
-+
- void
- audit_event(ssh_audit_event_t event)
- {
-@@ -454,4 +473,40 @@ audit_event(ssh_audit_event_t event)
- 		debug("%s: unhandled event %d", __func__, event);
- 	}
- }
-+
-+void
-+audit_unsupported_body(int what)
-+{
-+	/* not implemented */
-+}
-+
-+void
-+audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, uid_t uid)
-+{
-+	/* not implemented */
-+}
-+
-+void
-+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
-+{
-+	/* not implemented */
-+}
-+
-+void
-+audit_destroy_sensitive_data(const char *fp)
-+{
-+	/* not implemented */
-+}
-+
-+void
-+audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid)
-+{
-+	/* not implemented */
-+}
-+
-+void
-+audit_generate_ephemeral_server_key(const char *fp)
-+{
-+	/* not implemented */
-+}
- #endif /* BSM */
-diff --git a/audit-linux.c b/audit-linux.c
-index b3ee2f4..946f7fa 100644
---- a/audit-linux.c
-+++ b/audit-linux.c
-@@ -35,13 +35,24 @@
- 
- #include "log.h"
- #include "audit.h"
-+#include "key.h"
-+#include "hostfile.h"
-+#include "auth.h"
-+#include "servconf.h"
- #include "canohost.h"
-+#include "packet.h"
-+#include "cipher.h"
- 
-+#define AUDIT_LOG_SIZE 256
-+
-+extern ServerOptions options;
-+extern Authctxt *the_authctxt;
-+extern u_int utmp_len;
- const char* audit_username(void);
- 
--int
--linux_audit_record_event(int uid, const char *username,
--    const char *hostname, const char *ip, const char *ttyn, int success)
-+static void
-+linux_audit_user_logxxx(int uid, const char *username,
-+    const char *hostname, const char *ip, const char *ttyn, int success, int event)
- {
- 	int audit_fd, rc, saved_errno;
- 
-@@ -49,11 +60,11 @@ linux_audit_record_event(int uid, const char *username,
- 	if (audit_fd < 0) {
- 		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
- 		    errno == EAFNOSUPPORT)
--			return 1; /* No audit support in kernel */
-+			return; /* No audit support in kernel */
- 		else
--			return 0; /* Must prevent login */
-+			goto fatal_report; /* Must prevent login */
- 	}
--	rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN,
-+	rc = audit_log_acct_message(audit_fd, event,
- 	    NULL, "login", username ? username : "(unknown)",
- 	    username == NULL ? uid : -1, hostname, ip, ttyn, success);
- 	saved_errno = errno;
-@@ -65,35 +76,150 @@ linux_audit_record_event(int uid, const char *username,
- 	if ((rc == -EPERM) && (geteuid() != 0))
- 		rc = 0;
- 	errno = saved_errno;
--	return (rc >= 0);
-+	if (rc < 0) {
-+fatal_report:
-+		fatal("linux_audit_write_entry failed: %s", strerror(errno));
-+	}
- }
- 
-+static void
-+linux_audit_user_auth(int uid, const char *username,
-+    const char *hostname, const char *ip, const char *ttyn, int success, int event)
-+{
-+	int audit_fd, rc, saved_errno;
-+	static const char *event_name[] = {
-+		"maxtries exceeded",
-+		"root denied",
-+		"success",
-+		"none",
-+		"password",
-+		"challenge-response",
-+		"pubkey",
-+		"hostbased",
-+		"gssapi",
-+		"invalid user",
-+		"nologin",
-+		"connection closed",
-+		"connection abandoned",
-+		"unknown"
-+	};
-+
-+	audit_fd = audit_open();
-+	if (audit_fd < 0) {
-+		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
-+		    errno == EAFNOSUPPORT)
-+			return; /* No audit support in kernel */
-+		else
-+			goto fatal_report; /* Must prevent login */
-+	}
-+	
-+	if ((event < 0) || (event > SSH_AUDIT_UNKNOWN))
-+		event = SSH_AUDIT_UNKNOWN;
-+
-+	rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH,
-+	    NULL, event_name[event], username ? username : "(unknown)",
-+	    username == NULL ? uid : -1, hostname, ip, ttyn, success);
-+	saved_errno = errno;
-+	close(audit_fd);
-+	/*
-+	 * Do not report error if the error is EPERM and sshd is run as non
-+	 * root user.
-+	 */
-+	if ((rc == -EPERM) && (geteuid() != 0))
-+		rc = 0;
-+	errno = saved_errno;
-+	if (rc < 0) {
-+fatal_report:
-+		fatal("linux_audit_write_entry failed: %s", strerror(errno));
-+	}
-+}
-+
-+int
-+audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv)
-+{
-+	char buf[AUDIT_LOG_SIZE];
-+	int audit_fd, rc, saved_errno;
-+
-+	audit_fd = audit_open();
-+	if (audit_fd < 0) {
-+		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
-+					 errno == EAFNOSUPPORT)
-+			return 1; /* No audit support in kernel */
-+		else                                                                                                                                       
-+			return 0; /* Must prevent login */
-+	}
-+	snprintf(buf, sizeof(buf), "%s_auth rport=%d", host_user ? "pubkey" : "hostbased", get_remote_port());
-+	rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
-+		buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv);
-+	if ((rc < 0) && ((rc != -1) || (getuid() == 0)))
-+		goto out;
-+	snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s%s rport=%d",
-+			type, bits, key_fingerprint_prefix(), fp, get_remote_port());
-+	rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
-+		buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv);
-+out:
-+	saved_errno = errno;
-+	audit_close(audit_fd);
-+	errno = saved_errno;
-+	/* do not report error if the error is EPERM and sshd is run as non root user */
-+	return (rc >= 0) || ((rc == -EPERM) && (getuid() != 0));
-+}
-+
-+static int user_login_count = 0;
-+
- /* Below is the sshd audit API code */
- 
- void
- audit_connection_from(const char *host, int port)
- {
--}
- 	/* not implemented */
-+}
- 
--void
-+int
- audit_run_command(const char *command)
- {
--	/* not implemented */
-+	if (!user_login_count++) 
-+		linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
-+		    NULL, "ssh", 1, AUDIT_USER_LOGIN);
-+	linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
-+	    NULL, "ssh", 1, AUDIT_USER_START);
-+	return 0;
-+}
-+
-+void
-+audit_end_command(int handle, const char *command)
-+{
-+	linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
-+	    NULL, "ssh", 1, AUDIT_USER_END);
-+	if (user_login_count && !--user_login_count) 
-+		linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
-+		    NULL, "ssh", 1, AUDIT_USER_LOGOUT);
-+}
-+
-+void
-+audit_count_session_open(void)
-+{
-+	user_login_count++;
- }
- 
- void
- audit_session_open(struct logininfo *li)
- {
--	if (linux_audit_record_event(li->uid, NULL, li->hostname,
--	    NULL, li->line, 1) == 0)
--		fatal("linux_audit_write_entry failed: %s", strerror(errno));
-+	if (!user_login_count++) 
-+		linux_audit_user_logxxx(li->uid, NULL, li->hostname,
-+		    NULL, li->line, 1, AUDIT_USER_LOGIN);
-+	linux_audit_user_logxxx(li->uid, NULL, li->hostname,
-+	    NULL, li->line, 1, AUDIT_USER_START);
- }
- 
- void
- audit_session_close(struct logininfo *li)
- {
--	/* not implemented */
-+	linux_audit_user_logxxx(li->uid, NULL, li->hostname,
-+	    NULL, li->line, 1, AUDIT_USER_END);
-+	if (user_login_count && !--user_login_count) 
-+		linux_audit_user_logxxx(li->uid, NULL, li->hostname,
-+		    NULL, li->line, 1, AUDIT_USER_LOGOUT);
- }
- 
- void
-@@ -101,21 +227,43 @@ audit_event(ssh_audit_event_t event)
- {
- 	switch(event) {
- 	case SSH_AUTH_SUCCESS:
--	case SSH_CONNECTION_CLOSE:
-+		linux_audit_user_auth(-1, audit_username(), NULL,
-+			get_remote_ipaddr(), "ssh", 1, event);
-+		break;
-+
- 	case SSH_NOLOGIN:
--	case SSH_LOGIN_EXCEED_MAXTRIES:
- 	case SSH_LOGIN_ROOT_DENIED:
-+		linux_audit_user_auth(-1, audit_username(), NULL,
-+			get_remote_ipaddr(), "ssh", 0, event);
-+		linux_audit_user_logxxx(-1, audit_username(), NULL,
-+			get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN);
- 		break;
- 
-+	case SSH_LOGIN_EXCEED_MAXTRIES:
- 	case SSH_AUTH_FAIL_NONE:
- 	case SSH_AUTH_FAIL_PASSWD:
- 	case SSH_AUTH_FAIL_KBDINT:
- 	case SSH_AUTH_FAIL_PUBKEY:
- 	case SSH_AUTH_FAIL_HOSTBASED:
- 	case SSH_AUTH_FAIL_GSSAPI:
-+		linux_audit_user_auth(-1, audit_username(), NULL,
-+			get_remote_ipaddr(), "ssh", 0, event);
-+		break;
-+
-+	case SSH_CONNECTION_CLOSE:
-+		if (user_login_count) {
-+			while (user_login_count--)
-+				linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
-+				    NULL, "ssh", 1, AUDIT_USER_END);
-+			linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
-+			    NULL, "ssh", 1, AUDIT_USER_LOGOUT);
-+		}
-+		break;
-+
-+	case SSH_CONNECTION_ABANDON:
- 	case SSH_INVALID_USER:
--		linux_audit_record_event(-1, audit_username(), NULL,
--			get_remote_ipaddr(), "sshd", 0);
-+		linux_audit_user_logxxx(-1, audit_username(), NULL,
-+			get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN);
- 		break;
- 
- 	default:
-@@ -123,4 +271,135 @@ audit_event(ssh_audit_event_t event)
- 	}
- }
- 
-+void
-+audit_unsupported_body(int what)
-+{
-+#ifdef AUDIT_CRYPTO_SESSION
-+	char buf[AUDIT_LOG_SIZE];
-+	const static char *name[] = { "cipher", "mac", "comp" };
-+	char *s;
-+	int audit_fd;
-+
-+	snprintf(buf, sizeof(buf), "op=unsupported-%s direction=? cipher=? ksize=? rport=%d laddr=%s lport=%d ",
-+		name[what], get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())),
-+		get_local_port());
-+	free(s);
-+	audit_fd = audit_open();
-+	if (audit_fd < 0)
-+		/* no problem, the next instruction will be fatal() */
-+		return;
-+	audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION,
-+			buf, NULL, get_remote_ipaddr(), NULL, 0);
-+	audit_close(audit_fd);
-+#endif
-+}
-+
-+const static char *direction[] = { "from-server", "from-client", "both" };
-+
-+void
-+audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid,
-+	       uid_t uid)
-+{
-+#ifdef AUDIT_CRYPTO_SESSION
-+	char buf[AUDIT_LOG_SIZE];
-+	int audit_fd, audit_ok;
-+	Cipher *cipher = cipher_by_name(enc);
-+	char *s;
-+
-+	snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ",
-+		direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac,
-+		(intmax_t)pid, (intmax_t)uid,
-+		get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), get_local_port());
-+	free(s);
-+	audit_fd = audit_open();
-+	if (audit_fd < 0) {
-+		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
-+					 errno == EAFNOSUPPORT)
-+			return; /* No audit support in kernel */
-+		else                                                                                                                                       
-+			fatal("cannot open audit"); /* Must prevent login */
-+	}
-+	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION,
-+			buf, NULL, get_remote_ipaddr(), NULL, 1);
-+	audit_close(audit_fd);
-+	/* do not abort if the error is EPERM and sshd is run as non root user */
-+	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
-+		fatal("cannot write into audit"); /* Must prevent login */
-+#endif
-+}
-+
-+void
-+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
-+{
-+	char buf[AUDIT_LOG_SIZE];
-+	int audit_fd, audit_ok;
-+	char *s;
-+
-+	snprintf(buf, sizeof(buf), "op=destroy kind=session fp=? direction=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ",
-+		 direction[ctos], (intmax_t)pid, (intmax_t)uid,
-+		 get_remote_port(),
-+		 (s = get_local_ipaddr(packet_get_connection_in())),
-+		 get_local_port());
-+	free(s);
-+	audit_fd = audit_open();
-+	if (audit_fd < 0) {
-+		if (errno != EINVAL && errno != EPROTONOSUPPORT &&
-+					 errno != EAFNOSUPPORT)
-+			error("cannot open audit");
-+		return;
-+	}
-+	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER,
-+			buf, NULL, get_remote_ipaddr(), NULL, 1);
-+	audit_close(audit_fd);
-+	/* do not abort if the error is EPERM and sshd is run as non root user */
-+	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
-+		error("cannot write into audit");
-+}
-+
-+void
-+audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid)
-+{
-+	char buf[AUDIT_LOG_SIZE];
-+	int audit_fd, audit_ok;
-+
-+	snprintf(buf, sizeof(buf), "op=destroy kind=server fp=%s direction=? spid=%jd suid=%jd ",
-+		fp, (intmax_t)pid, (intmax_t)uid);
-+	audit_fd = audit_open();
-+	if (audit_fd < 0) {
-+		if (errno != EINVAL && errno != EPROTONOSUPPORT &&
-+					 errno != EAFNOSUPPORT)
-+			error("cannot open audit");
-+		return;
-+	}
-+	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER,
-+			buf, NULL,
-+			listening_for_clients() ? NULL : get_remote_ipaddr(),
-+			NULL, 1);
-+	audit_close(audit_fd);
-+	/* do not abort if the error is EPERM and sshd is run as non root user */
-+	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
-+		error("cannot write into audit");
-+}
-+
-+void
-+audit_generate_ephemeral_server_key(const char *fp)
-+{
-+	char buf[AUDIT_LOG_SIZE];
-+	int audit_fd, audit_ok;
-+
-+	snprintf(buf, sizeof(buf), "op=create kind=server fp=%s direction=? ", fp);
-+	audit_fd = audit_open();
-+	if (audit_fd < 0) {
-+		if (errno != EINVAL && errno != EPROTONOSUPPORT &&
-+					 errno != EAFNOSUPPORT)
-+			error("cannot open audit");
-+		return;
-+	}
-+	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER,
-+			buf, NULL, 0, NULL, 1);
-+	audit_close(audit_fd);
-+	/* do not abort if the error is EPERM and sshd is run as non root user */
-+	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
-+		error("cannot write into audit");
-+}
- #endif /* USE_LINUX_AUDIT */
-diff --git a/audit.c b/audit.c
-index ced57fa..ab9fb82 100644
---- a/audit.c
-+++ b/audit.c
-@@ -28,6 +28,7 @@
- 
- #include <stdarg.h>
- #include <string.h>
-+#include <unistd.h>
- 
- #ifdef SSH_AUDIT_EVENTS
- 
-@@ -36,6 +37,9 @@
- #include "key.h"
- #include "hostfile.h"
- #include "auth.h"
-+#include "ssh-gss.h"
-+#include "monitor_wrap.h"
-+#include "xmalloc.h"
- 
- /*
-  * Care must be taken when using this since it WILL NOT be initialized when
-@@ -71,13 +75,10 @@ audit_classify_auth(const char *method)
- const char *
- audit_username(void)
- {
--	static const char unknownuser[] = "(unknown user)";
--	static const char invaliduser[] = "(invalid user)";
-+	static const char unknownuser[] = "(unknown)";
- 
--	if (the_authctxt == NULL || the_authctxt->user == NULL)
-+	if (the_authctxt == NULL || the_authctxt->user == NULL || !the_authctxt->valid)
- 		return (unknownuser);
--	if (!the_authctxt->valid)
--		return (invaliduser);
- 	return (the_authctxt->user);
- }
- 
-@@ -111,6 +112,40 @@ audit_event_lookup(ssh_audit_event_t ev)
- 	return(event_lookup[i].name);
- }
- 
-+void
-+audit_key(int host_user, int *rv, const Key *key)
-+{
-+	char *fp;
-+	const char *crypto_name;
-+
-+	fp = key_selected_fingerprint(key, SSH_FP_HEX);
-+	if (key->type == KEY_RSA1)
-+		crypto_name = "ssh-rsa1";
-+	else
-+		crypto_name = key_ssh_name(key);
-+	if (audit_keyusage(host_user, crypto_name, key_size(key), fp, *rv) == 0)
-+		*rv = 0;
-+	free(fp);
-+}
-+
-+void
-+audit_unsupported(int what)
-+{
-+	PRIVSEP(audit_unsupported_body(what));
-+}
-+
-+void
-+audit_kex(int ctos, char *enc, char *mac, char *comp)
-+{
-+	PRIVSEP(audit_kex_body(ctos, enc, mac, comp, getpid(), getuid()));
-+}
-+
-+void
-+audit_session_key_free(int ctos)
-+{
-+	PRIVSEP(audit_session_key_free_body(ctos, getpid(), getuid()));
-+}
-+
- # ifndef CUSTOM_SSH_AUDIT_EVENTS
- /*
-  * Null implementations of audit functions.
-@@ -140,6 +175,17 @@ audit_event(ssh_audit_event_t event)
- }
- 
- /*
-+ * Called when a child process has called, or will soon call,
-+ * audit_session_open.
-+ */
-+void
-+audit_count_session_open(void)
-+{
-+	debug("audit count session open euid %d user %s", geteuid(),
-+	      audit_username());
-+}
-+
-+/*
-  * Called when a user session is started.  Argument is the tty allocated to
-  * the session, or NULL if no tty was allocated.
-  *
-@@ -174,13 +220,91 @@ audit_session_close(struct logininfo *li)
- /*
-  * This will be called when a user runs a non-interactive command.  Note that
-  * it may be called multiple times for a single connection since SSH2 allows
-- * multiple sessions within a single connection.
-+ * multiple sessions within a single connection.  Returns a "handle" for
-+ * audit_end_command.
-  */
--void
-+int
- audit_run_command(const char *command)
- {
- 	debug("audit run command euid %d user %s command '%.200s'", geteuid(),
- 	    audit_username(), command);
-+	return 0;
-+}
-+
-+/*
-+ * This will be called when the non-interactive command finishes.  Note that
-+ * it may be called multiple times for a single connection since SSH2 allows
-+ * multiple sessions within a single connection.  "handle" should come from
-+ * the corresponding audit_run_command.
-+ */
-+void
-+audit_end_command(int handle, const char *command)
-+{
-+	debug("audit end nopty exec  euid %d user %s command '%.200s'", geteuid(),
-+	    audit_username(), command);
-+}
-+
-+/*
-+ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key.
-+ *
-+ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key.
-+ */
-+int
-+audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv)
-+{
-+	debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s%s, result %d", 
-+		host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), type, bits,
-+		key_fingerprint_prefix(), fp, rv);
-+}
-+
-+/*
-+ * This will be called when the protocol negotiation fails.
-+ */
-+void
-+audit_unsupported_body(int what)
-+{
-+	debug("audit unsupported protocol euid %d type %d", geteuid(), what);
-+}
-+
-+/*
-+ * This will be called on succesfull protocol negotiation.
-+ */
-+void
-+audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid,
-+	       uid_t uid)
-+{
-+	debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s from pid %ld uid %u",
-+		(unsigned)geteuid(), ctos, enc, mac, compress, (long)pid,
-+	        (unsigned)uid);
-+}
-+
-+/*
-+ * This will be called on succesfull session key discard
-+ */
-+void
-+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
-+{
-+	debug("audit session key discard euid %u direction %d from pid %ld uid %u",
-+		(unsigned)geteuid(), ctos, (long)pid, (unsigned)uid);
-+}
-+
-+/*
-+ * This will be called on destroy private part of the server key
-+ */
-+void
-+audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid)
-+{
-+	debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u",
-+		geteuid(), fp, (long)pid, (unsigned)uid);
-+}
-+
-+/*
-+ * This will be called on generation of the ephemeral server key
-+ */
-+void
-+audit_generate_ephemeral_server_key(const char *)
-+{
-+	debug("audit create ephemeral server key euid %d fingerprint %s", geteuid(), fp);
- }
- # endif  /* !defined CUSTOM_SSH_AUDIT_EVENTS */
- #endif /* SSH_AUDIT_EVENTS */
-diff --git a/audit.h b/audit.h
-index 92ede5b..a2dc3ff 100644
---- a/audit.h
-+++ b/audit.h
-@@ -28,6 +28,7 @@
- # define _SSH_AUDIT_H
- 
- #include "loginrec.h"
-+#include "key.h"
- 
- enum ssh_audit_event_type {
- 	SSH_LOGIN_EXCEED_MAXTRIES,
-@@ -47,11 +48,25 @@ enum ssh_audit_event_type {
- };
- typedef enum ssh_audit_event_type ssh_audit_event_t;
- 
-+int	listening_for_clients(void);
-+
- void	audit_connection_from(const char *, int);
- void	audit_event(ssh_audit_event_t);
-+void	audit_count_session_open(void);
- void	audit_session_open(struct logininfo *);
- void	audit_session_close(struct logininfo *);
--void	audit_run_command(const char *);
-+int	audit_run_command(const char *);
-+void 	audit_end_command(int, const char *);
- ssh_audit_event_t audit_classify_auth(const char *);
-+int	audit_keyusage(int, const char *, unsigned, char *, int);
-+void	audit_key(int, int *, const Key *);
-+void	audit_unsupported(int);
-+void	audit_kex(int, char *, char *, char *);
-+void	audit_unsupported_body(int);
-+void	audit_kex_body(int, char *, char *, char *, pid_t, uid_t);
-+void	audit_session_key_free(int ctos);
-+void	audit_session_key_free_body(int ctos, pid_t, uid_t);
-+void	audit_destroy_sensitive_data(const char *, pid_t, uid_t);
-+void	audit_generate_ephemeral_server_key(const char *);
- 
- #endif /* _SSH_AUDIT_H */
-diff --git a/auditstub.c b/auditstub.c
-new file mode 100644
-index 0000000..45817e0
---- /dev/null
-+++ b/auditstub.c
-@@ -0,0 +1,50 @@
-+/* $Id: auditstub.c,v 1.1 jfch Exp $ */
-+
-+/*
-+ * Copyright 2010 Red Hat, Inc.  All rights reserved.
-+ * Use is subject to license terms.
-+ *
-+ * 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.
-+ *
-+ * Red Hat author: Jan F. Chadima <jchadima at redhat.com>
-+ */
-+
-+#include <sys/types.h>
-+
-+void
-+audit_unsupported(int n)
-+{
-+}
-+
-+void
-+audit_kex(int ctos, char *enc, char *mac, char *comp)
-+{
-+}
-+
-+void
-+audit_session_key_free(int ctos)
-+{
-+}
-+
-+void
-+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
-+{
-+}
-diff --git a/auth-rsa.c b/auth-rsa.c
-index 5dad6c3..f225b0b 100644
---- a/auth-rsa.c
-+++ b/auth-rsa.c
-@@ -93,7 +93,10 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16])
- {
- 	u_char buf[32], mdbuf[16];
- 	struct ssh_digest_ctx *md;
--	int len;
-+	int len, rv;
-+#ifdef SSH_AUDIT_EVENTS
-+	char *fp;
-+#endif
- 
- 	/* don't allow short keys */
- 	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
-@@ -117,12 +120,18 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16])
- 	ssh_digest_free(md);
- 
- 	/* Verify that the response is the original challenge. */
--	if (timingsafe_bcmp(response, mdbuf, 16) != 0) {
--		/* Wrong answer. */
--		return (0);
-+	rv = timingsafe_bcmp(response, mdbuf, 16) == 0;
-+
-+#ifdef SSH_AUDIT_EVENTS
-+	fp = key_selected_fingerprint(key, SSH_FP_HEX);
-+	if (audit_keyusage(1, "ssh-rsa1", RSA_size(key->rsa) * 8, fp, rv) == 0) {
-+		debug("unsuccessful audit");
-+		rv = 0;
- 	}
--	/* Correct answer. */
--	return (1);
-+	free(fp);
-+#endif
-+
-+	return rv;
- }
- 
- /*
-diff --git a/auth.c b/auth.c
-index 420a85b..d613f8c 100644
---- a/auth.c
-+++ b/auth.c
-@@ -628,9 +628,6 @@ getpwnamallow(const char *user)
- 		record_failed_login(user,
- 		    get_canonical_hostname(options.use_dns), "ssh");
- #endif
--#ifdef SSH_AUDIT_EVENTS
--		audit_event(SSH_INVALID_USER);
--#endif /* SSH_AUDIT_EVENTS */
- 		return (NULL);
- 	}
- 	if (!allowed_user(pw))
-diff --git a/auth.h b/auth.h
-index 4605588..f9d191c 100644
---- a/auth.h
-+++ b/auth.h
-@@ -186,6 +186,7 @@ void	abandon_challenge_response(Authctxt *);
- 
- char	*expand_authorized_keys(const char *, struct passwd *pw);
- char	*authorized_principals_file(struct passwd *);
-+int	 user_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
- 
- FILE	*auth_openkeyfile(const char *, struct passwd *, int);
- FILE	*auth_openprincipals(const char *, struct passwd *, int);
-@@ -203,6 +204,7 @@ Key	*get_hostkey_private_by_type(int);
- int	 get_hostkey_index(Key *);
- int	 ssh1_session_key(BIGNUM *);
- void	 sshd_hostkey_sign(Key *, Key *, u_char **, u_int *, u_char *, u_int);
-+int	 hostbased_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
- 
- /* debug messages during authentication */
- void	 auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2)));
-diff --git a/auth2-hostbased.c b/auth2-hostbased.c
-index 95d678e..48aede4 100644
---- a/auth2-hostbased.c
-+++ b/auth2-hostbased.c
-@@ -137,7 +137,7 @@ userauth_hostbased(Authctxt *authctxt)
- 	/* test for allowed key and correct signature */
- 	authenticated = 0;
- 	if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) &&
--	    PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
-+	    PRIVSEP(hostbased_key_verify(key, sig, slen, buffer_ptr(&b),
- 			buffer_len(&b))) == 1)
- 		authenticated = 1;
- 
-@@ -154,6 +154,18 @@ done:
- 	return authenticated;
- }
- 
-+int
-+hostbased_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen)
-+{
-+	int rv;
-+
-+	rv = key_verify(key, sig, slen, data, datalen);
-+#ifdef SSH_AUDIT_EVENTS
-+	audit_key(0, &rv, key);
-+#endif
-+	return rv;
-+}
-+
- /* return 1 if given hostkey is allowed */
- int
- hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
-diff --git a/auth2-pubkey.c b/auth2-pubkey.c
-index cb0f931..6d1c872 100644
---- a/auth2-pubkey.c
-+++ b/auth2-pubkey.c
-@@ -160,7 +160,7 @@ userauth_pubkey(Authctxt *authctxt)
- 		/* test for correct signature */
- 		authenticated = 0;
- 		if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
--		    PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
-+		    PRIVSEP(user_key_verify(key, sig, slen, buffer_ptr(&b),
- 		    buffer_len(&b))) == 1)
- 			authenticated = 1;
- 		buffer_free(&b);
-@@ -231,6 +231,18 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
- 	free(extra);
- }
- 
-+int
-+user_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen)
-+{
-+	int rv;
-+
-+	rv = key_verify(key, sig, slen, data, datalen);
-+#ifdef SSH_AUDIT_EVENTS
-+	audit_key(1, &rv, key);
-+#endif
-+	return rv;
-+}
-+
- static int
- match_principals_option(const char *principal_list, struct KeyCert *cert)
- {
-diff --git a/auth2.c b/auth2.c
-index 426dcd6..436cd60 100644
---- a/auth2.c
-+++ b/auth2.c
-@@ -249,9 +249,6 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
- 		} else {
- 			logit("input_userauth_request: invalid user %s", user);
- 			authctxt->pw = fakepw();
--#ifdef SSH_AUDIT_EVENTS
--			PRIVSEP(audit_event(SSH_INVALID_USER));
--#endif
- 		}
- #ifdef USE_PAM
- 		if (options.use_pam)
-diff --git a/cipher.c b/cipher.c
-index 53d9b4f..226e56d 100644
---- a/cipher.c
-+++ b/cipher.c
-@@ -57,20 +57,6 @@ extern const EVP_CIPHER *evp_ssh1_bf(void);
- extern const EVP_CIPHER *evp_ssh1_3des(void);
- extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
- 
--struct Cipher {
--	char	*name;
--	int	number;		/* for ssh1 only */
--	u_int	block_size;
--	u_int	key_len;
--	u_int	iv_len;		/* defaults to block_size */
--	u_int	auth_len;
--	u_int	discard_len;
--	u_int	flags;
--#define CFLAG_CBC		(1<<0)
--#define CFLAG_CHACHAPOLY	(1<<1)
--	const EVP_CIPHER	*(*evptype)(void);
--};
--
- static const struct Cipher ciphers[] = {
- 	{ "none",	SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null },
- 	{ "des",	SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc },
-diff --git a/cipher.h b/cipher.h
-index 133d2e7..d41758e 100644
---- a/cipher.h
-+++ b/cipher.h
-@@ -63,7 +63,20 @@
- typedef struct Cipher Cipher;
- typedef struct CipherContext CipherContext;
- 
--struct Cipher;
-+struct Cipher {
-+	char	*name;
-+	int	number;		/* for ssh1 only */
-+	u_int	block_size;
-+	u_int	key_len;
-+	u_int	iv_len;		/* defaults to block_size */
-+	u_int	auth_len;
-+	u_int	discard_len;
-+	u_int	flags;
-+#define CFLAG_CBC		(1<<0)
-+#define CFLAG_CHACHAPOLY	(1<<1)
-+	const EVP_CIPHER	*(*evptype)(void);
-+};
-+
- struct CipherContext {
- 	int	plaintext;
- 	int	encrypt;
-diff --git a/kex.c b/kex.c
-index bce2ab8..bc3e53e 100644
---- a/kex.c
-+++ b/kex.c
-@@ -50,6 +50,7 @@
- #include "monitor.h"
- #include "roaming.h"
- #include "digest.h"
-+#include "audit.h"
- 
- #ifdef GSSAPI
- #include "ssh-gss.h"
-@@ -366,9 +367,13 @@ static void
- choose_enc(Enc *enc, char *client, char *server)
- {
- 	char *name = match_list(client, server, NULL);
--	if (name == NULL)
-+	if (name == NULL) {
-+#ifdef SSH_AUDIT_EVENTS
-+		audit_unsupported(0);
-+#endif
- 		fatal("no matching cipher found: client %s server %s",
- 		    client, server);
-+	}
- 	if ((enc->cipher = cipher_by_name(name)) == NULL)
- 		fatal("matching cipher is not supported: %s", name);
- 	enc->name = name;
-@@ -384,9 +389,13 @@ static void
- choose_mac(Mac *mac, char *client, char *server)
- {
- 	char *name = match_list(client, server, NULL);
--	if (name == NULL)
-+	if (name == NULL) {
-+#ifdef SSH_AUDIT_EVENTS
-+		audit_unsupported(1);
-+#endif
- 		fatal("no matching mac found: client %s server %s",
- 		    client, server);
-+	}
- 	if (mac_setup(mac, name) < 0)
- 		fatal("unsupported mac %s", name);
- 	/* truncate the key */
-@@ -401,8 +410,12 @@ static void
- choose_comp(Comp *comp, char *client, char *server)
- {
- 	char *name = match_list(client, server, NULL);
--	if (name == NULL)
-+	if (name == NULL) {
-+#ifdef SSH_AUDIT_EVENTS
-+		audit_unsupported(2);
-+#endif
- 		fatal("no matching comp found: client %s server %s", client, server);
-+	}
- 	if (strcmp(name, "zlib at openssh.com") == 0) {
- 		comp->type = COMP_DELAYED;
- 	} else if (strcmp(name, "zlib") == 0) {
-@@ -517,6 +530,9 @@ kex_choose_conf(Kex *kex)
- 		    newkeys->enc.name,
- 		    authlen == 0 ? newkeys->mac.name : "<implicit>",
- 		    newkeys->comp.name);
-+#ifdef SSH_AUDIT_EVENTS
-+		audit_kex(ctos, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name);
-+#endif
- 	}
- 	choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
- 	choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
-@@ -702,3 +718,34 @@ dump_digest(char *msg, u_char *digest, int len)
- 	fprintf(stderr, "\n");
- }
- #endif
-+
-+static void
-+enc_destroy(Enc *enc)
-+{
-+	if (enc == NULL)
-+		return;
-+
-+	if (enc->key) {
-+		memset(enc->key, 0, enc->key_len);
-+		free(enc->key);
-+	}
-+
-+	if (enc->iv) {
-+		memset(enc->iv,  0, enc->block_size);
-+		free(enc->iv);
-+	}
-+
-+	memset(enc, 0, sizeof(*enc));
-+}
-+
-+void
-+newkeys_destroy(Newkeys *newkeys)
-+{
-+	if (newkeys == NULL)
-+		return;
-+
-+	enc_destroy(&newkeys->enc);
-+	mac_destroy(&newkeys->mac);
-+	memset(&newkeys->comp, 0, sizeof(newkeys->comp));
-+}
-+
-diff --git a/kex.h b/kex.h
-index 313bb51..c643250 100644
---- a/kex.h
-+++ b/kex.h
-@@ -182,6 +182,8 @@ void	 kexgss_client(Kex *);
- void	 kexgss_server(Kex *);
- #endif
- 
-+void	newkeys_destroy(Newkeys *newkeys);
-+
- void
- kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
-     BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *);
-diff --git a/key.c b/key.c
-index 900b9e3..62f3edb 100644
---- a/key.c
-+++ b/key.c
-@@ -1925,6 +1925,33 @@ key_demote(const Key *k)
- }
- 
- int
-+key_is_private(const Key *k)
-+{
-+	switch (k->type) {
-+	case KEY_RSA_CERT_V00:
-+	case KEY_RSA_CERT:
-+	case KEY_RSA1:
-+	case KEY_RSA:
-+		return k->rsa->d != NULL;
-+	case KEY_DSA_CERT_V00:
-+	case KEY_DSA_CERT:
-+	case KEY_DSA:
-+		return k->dsa->priv_key != NULL;
-+#ifdef OPENSSL_HAS_ECC
-+	case KEY_ECDSA_CERT:
-+	case KEY_ECDSA:
-+		return EC_KEY_get0_private_key(k->ecdsa) != NULL;
-+#endif
-+	case KEY_ED25519_CERT:
-+	case KEY_ED25519:
-+		return (k->ed25519_pk != NULL);
-+	default:
-+		fatal("key_is_private: bad key type %d", k->type);
-+		return 1;
-+	}
-+}
-+
-+int
- key_is_cert(const Key *k)
- {
- 	if (k == NULL)
-diff --git a/key.h b/key.h
-index d51ed81..8f61605 100644
---- a/key.h
-+++ b/key.h
-@@ -118,6 +118,7 @@ Key	*key_generate(int, u_int);
- Key	*key_from_private(const Key *);
- int	 key_type_from_name(char *);
- int	 key_is_cert(const Key *);
-+int	 key_is_private(const Key *k);
- int	 key_type_is_cert(int);
- int	 key_type_plain(int);
- int	 key_to_certified(Key *, int);
-diff --git a/mac.c b/mac.c
-index 0977572..9388af4 100644
---- a/mac.c
-+++ b/mac.c
-@@ -222,6 +222,20 @@ mac_clear(Mac *mac)
- 	mac->umac_ctx = NULL;
- }
- 
-+void
-+mac_destroy(Mac *mac)
-+{
-+	if (mac == NULL)
-+		return;
-+
-+	if (mac->key) {
-+		memset(mac->key, 0, mac->key_len);
-+		free(mac->key);
-+	}
-+
-+	memset(mac, 0, sizeof(*mac));
-+}
-+
- /* XXX copied from ciphers_valid */
- #define	MAC_SEP	","
- int
-diff --git a/mac.h b/mac.h
-index fbe18c4..7dc7f43 100644
---- a/mac.h
-+++ b/mac.h
-@@ -29,3 +29,4 @@ int	 mac_setup(Mac *, char *);
- int	 mac_init(Mac *);
- u_char	*mac_compute(Mac *, u_int32_t, u_char *, int);
- void	 mac_clear(Mac *);
-+void	 mac_destroy(Mac *);
-diff --git a/monitor.c b/monitor.c
-index 8b18086..5a65114 100644
---- a/monitor.c
-+++ b/monitor.c
-@@ -97,6 +97,7 @@
- #include "ssh2.h"
- #include "roaming.h"
- #include "authfd.h"
-+#include "audit.h"
- 
- #ifdef GSSAPI
- static Gssctxt *gsscontext = NULL;
-@@ -113,6 +114,8 @@ extern Buffer auth_debug;
- extern int auth_debug_init;
- extern Buffer loginmsg;
- 
-+extern void destroy_sensitive_data(int);
-+
- /* State exported from the child */
- 
- struct {
-@@ -185,6 +188,11 @@ int mm_answer_gss_updatecreds(int, Buffer *);
- #ifdef SSH_AUDIT_EVENTS
- int mm_answer_audit_event(int, Buffer *);
- int mm_answer_audit_command(int, Buffer *);
-+int mm_answer_audit_end_command(int, Buffer *);
-+int mm_answer_audit_unsupported_body(int, Buffer *);
-+int mm_answer_audit_kex_body(int, Buffer *);
-+int mm_answer_audit_session_key_free_body(int, Buffer *);
-+int mm_answer_audit_server_key_free(int, Buffer *);
- #endif
- 
- static int monitor_read_log(struct monitor *);
-@@ -239,6 +247,10 @@ struct mon_table mon_dispatch_proto20[] = {
- #endif
- #ifdef SSH_AUDIT_EVENTS
-     {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
-+    {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body},
-+    {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body},
-+    {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body},
-+    {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free},
- #endif
- #ifdef BSD_AUTH
-     {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
-@@ -274,6 +286,11 @@ struct mon_table mon_dispatch_postauth20[] = {
- #ifdef SSH_AUDIT_EVENTS
-     {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
-     {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command},
-+    {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command},
-+    {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body},
-+    {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body},
-+    {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body},
-+    {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free},
- #endif
-     {0, 0, NULL}
- };
-@@ -305,6 +322,10 @@ struct mon_table mon_dispatch_proto15[] = {
- #endif
- #ifdef SSH_AUDIT_EVENTS
-     {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
-+    {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body},
-+    {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body},
-+    {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body},
-+    {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free},
- #endif
-     {0, 0, NULL}
- };
-@@ -316,6 +337,11 @@ struct mon_table mon_dispatch_postauth15[] = {
- #ifdef SSH_AUDIT_EVENTS
-     {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
-     {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command},
-+    {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command},
-+    {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body},
-+    {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body},
-+    {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body},
-+    {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free},
- #endif
-     {0, 0, NULL}
- };
-@@ -1393,9 +1419,11 @@ mm_answer_keyverify(int sock, Buffer *m)
- 	Key *key;
- 	u_char *signature, *data, *blob;
- 	u_int signaturelen, datalen, bloblen;
-+	int type = 0;
- 	int verified = 0;
- 	int valid_data = 0;
- 
-+	type = buffer_get_int(m);
- 	blob = buffer_get_string(m, &bloblen);
- 	signature = buffer_get_string(m, &signaturelen);
- 	data = buffer_get_string(m, &datalen);
-@@ -1403,6 +1431,8 @@ mm_answer_keyverify(int sock, Buffer *m)
- 	if (hostbased_cuser == NULL || hostbased_chost == NULL ||
- 	  !monitor_allowed_key(blob, bloblen))
- 		fatal("%s: bad key, not previously allowed", __func__);
-+	if (type != key_blobtype)
-+		fatal("%s: bad key type", __func__);
- 
- 	key = key_from_blob(blob, bloblen);
- 	if (key == NULL)
-@@ -1423,7 +1453,17 @@ mm_answer_keyverify(int sock, Buffer *m)
- 	if (!valid_data)
- 		fatal("%s: bad signature data blob", __func__);
- 
--	verified = key_verify(key, signature, signaturelen, data, datalen);
-+	switch (key_blobtype) {
-+	case MM_USERKEY:
-+		verified = user_key_verify(key, signature, signaturelen, data, datalen);
-+		break;
-+	case MM_HOSTKEY:
-+		verified = hostbased_key_verify(key, signature, signaturelen, data, datalen);
-+		break;
-+	default:
-+		verified = 0;
-+		break;
-+	}
- 	debug3("%s: key %p signature %s",
- 	    __func__, key, (verified == 1) ? "verified" : "unverified");
- 
-@@ -1476,6 +1516,12 @@ mm_session_close(Session *s)
- 		debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd);
- 		session_pty_cleanup2(s);
- 	}
-+#ifdef SSH_AUDIT_EVENTS
-+	if (s->command != NULL) {
-+		debug3("%s: command %d", __func__, s->command_handle);
-+		session_end_command2(s);
-+	}
-+#endif
- 	session_unused(s->self);
- }
- 
-@@ -1756,6 +1802,8 @@ mm_answer_term(int sock, Buffer *req)
- 		sshpam_cleanup();
- #endif
- 
-+	destroy_sensitive_data(0);
-+
- 	while (waitpid(pmonitor->m_pid, &status, 0) == -1)
- 		if (errno != EINTR)
- 			exit(1);
-@@ -1798,11 +1846,43 @@ mm_answer_audit_command(int socket, Buffer *m)
- {
- 	u_int len;
- 	char *cmd;
-+	Session *s;
- 
- 	debug3("%s entering", __func__);
- 	cmd = buffer_get_string(m, &len);
-+
- 	/* sanity check command, if so how? */
--	audit_run_command(cmd);
-+	s = session_new();
-+	if (s == NULL)
-+		fatal("%s: error allocating a session", __func__);
-+	s->command = cmd;
-+	s->command_handle = audit_run_command(cmd);
-+
-+	buffer_clear(m);
-+	buffer_put_int(m, s->self);
-+
-+	mm_request_send(socket, MONITOR_ANS_AUDIT_COMMAND, m);
-+
-+	return (0);
-+}
-+
-+int
-+mm_answer_audit_end_command(int socket, Buffer *m)
-+{
-+	int handle;
-+	u_int len;
-+	char *cmd;
-+	Session *s;
-+
-+	debug3("%s entering", __func__);
-+	handle = buffer_get_int(m);
-+	cmd = buffer_get_string(m, &len);
-+
-+	s = session_by_id(handle);
-+	if (s == NULL || s->ttyfd != -1 || s->command == NULL ||
-+	    strcmp(s->command, cmd) != 0)
-+		fatal("%s: invalid handle", __func__);
-+	mm_session_close(s);
- 	free(cmd);
- 	return (0);
- }
-@@ -1946,11 +2026,13 @@ mm_get_keystate(struct monitor *pmonitor)
- 
- 	blob = buffer_get_string(&m, &bloblen);
- 	current_keys[MODE_OUT] = mm_newkeys_from_blob(blob, bloblen);
-+	memset(blob, 0, bloblen);
- 	free(blob);
- 
- 	debug3("%s: Waiting for second key", __func__);
- 	blob = buffer_get_string(&m, &bloblen);
- 	current_keys[MODE_IN] = mm_newkeys_from_blob(blob, bloblen);
-+	memset(blob, 0, bloblen);
- 	free(blob);
- 
- 	/* Now get sequence numbers for the packets */
-@@ -1996,6 +2078,21 @@ mm_get_keystate(struct monitor *pmonitor)
- 	}
- 
- 	buffer_free(&m);
-+
-+#ifdef SSH_AUDIT_EVENTS
-+	if (compat20) {
-+		buffer_init(&m);
-+		mm_request_receive_expect(pmonitor->m_sendfd,
-+					  MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m);
-+		mm_answer_audit_session_key_free_body(pmonitor->m_sendfd, &m);
-+		buffer_free(&m);
-+	}
-+#endif
-+
-+	/* Drain any buffered messages from the child */
-+	while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0)
-+		;
-+
- }
- 
- 
-@@ -2277,3 +2374,85 @@ mm_answer_gss_updatecreds(int socket, Buffer *m) {
- 
- #endif /* GSSAPI */
- 
-+#ifdef SSH_AUDIT_EVENTS
-+int
-+mm_answer_audit_unsupported_body(int sock, Buffer *m)
-+{
-+	int what;
-+
-+	what = buffer_get_int(m);
-+
-+	audit_unsupported_body(what);
-+
-+	buffer_clear(m);
-+
-+	mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m);
-+	return 0;
-+}
-+
-+int
-+mm_answer_audit_kex_body(int sock, Buffer *m)
-+{
-+	int ctos, len;
-+	char *cipher, *mac, *compress;
-+	pid_t pid;
-+	uid_t uid;
-+
-+	ctos = buffer_get_int(m);
-+	cipher = buffer_get_string(m, &len);
-+	mac = buffer_get_string(m, &len);
-+	compress = buffer_get_string(m, &len);
-+	pid = buffer_get_int64(m);
-+	uid = buffer_get_int64(m);
-+
-+	audit_kex_body(ctos, cipher, mac, compress, pid, uid);
-+
-+	free(cipher);
-+	free(mac);
-+	free(compress);
-+	buffer_clear(m);
-+
-+	mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m);
-+	return 0;
-+}
-+
-+int
-+mm_answer_audit_session_key_free_body(int sock, Buffer *m)
-+{
-+	int ctos;
-+	pid_t pid;
-+	uid_t uid;
-+
-+	ctos = buffer_get_int(m);
-+	pid = buffer_get_int64(m);
-+	uid = buffer_get_int64(m);
-+
-+	audit_session_key_free_body(ctos, pid, uid);
-+
-+	buffer_clear(m);
-+
-+	mm_request_send(sock, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, m);
-+	return 0;
-+}
-+
-+int
-+mm_answer_audit_server_key_free(int sock, Buffer *m)
-+{
-+	int len;
-+	char *fp;
-+	pid_t pid;
-+	uid_t uid;
-+
-+	fp = buffer_get_string(m, &len);
-+	pid = buffer_get_int64(m);
-+	uid = buffer_get_int64(m);
-+
-+	audit_destroy_sensitive_data(fp, pid, uid);
-+
-+	free(fp);
-+	buffer_clear(m);
-+
-+	mm_request_send(sock, MONITOR_ANS_AUDIT_SERVER_KEY_FREE, m);
-+	return 0;
-+}
-+#endif /* SSH_AUDIT_EVENTS */
-diff --git a/monitor.h b/monitor.h
-index ff79fbb..6dfb234 100644
---- a/monitor.h
-+++ b/monitor.h
-@@ -69,7 +69,13 @@ enum monitor_reqtype {
- 	MONITOR_REQ_PAM_QUERY = 106, MONITOR_ANS_PAM_QUERY = 107,
- 	MONITOR_REQ_PAM_RESPOND = 108, MONITOR_ANS_PAM_RESPOND = 109,
- 	MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
--	MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
-+	MONITOR_REQ_AUDIT_EVENT = 112,
-+	MONITOR_REQ_AUDIT_COMMAND = 114, MONITOR_ANS_AUDIT_COMMAND = 115,
-+	MONITOR_REQ_AUDIT_END_COMMAND = 116,
-+	MONITOR_REQ_AUDIT_UNSUPPORTED = 118, MONITOR_ANS_AUDIT_UNSUPPORTED = 119,
-+	MONITOR_REQ_AUDIT_KEX = 120, MONITOR_ANS_AUDIT_KEX = 121,
-+	MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 122, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 123,
-+	MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124, MONITOR_ANS_AUDIT_SERVER_KEY_FREE = 125
- 
- };
- 
-diff --git a/monitor_wrap.c b/monitor_wrap.c
-index d1e1caa..6df236a 100644
---- a/monitor_wrap.c
-+++ b/monitor_wrap.c
-@@ -450,7 +450,7 @@ mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key)
-  */
- 
- int
--mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
-+mm_key_verify(enum mm_keytype type, Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
- {
- 	Buffer m;
- 	u_char *blob;
-@@ -464,6 +464,7 @@ mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
- 		return (0);
- 
- 	buffer_init(&m);
-+	buffer_put_int(&m, type);
- 	buffer_put_string(&m, blob, len);
- 	buffer_put_string(&m, sig, siglen);
- 	buffer_put_string(&m, data, datalen);
-@@ -481,6 +482,19 @@ mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
- 	return (verified);
- }
- 
-+int
-+mm_hostbased_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
-+{
-+	return mm_key_verify(MM_HOSTKEY, key, sig, siglen, data, datalen);
-+}
-+
-+int
-+mm_user_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
-+{
-+	return mm_key_verify(MM_USERKEY, key, sig, siglen, data, datalen);
-+}
-+
-+
- /* Export key state after authentication */
- Newkeys *
- mm_newkeys_from_blob(u_char *blob, int blen)
-@@ -659,12 +673,14 @@ mm_send_keystate(struct monitor *monitor)
- 		fatal("%s: conversion of newkeys failed", __func__);
- 
- 	buffer_put_string(&m, blob, bloblen);
-+	memset(blob, 0, bloblen);
- 	free(blob);
- 
- 	if (!mm_newkeys_to_blob(MODE_IN, &blob, &bloblen))
- 		fatal("%s: conversion of newkeys failed", __func__);
- 
- 	buffer_put_string(&m, blob, bloblen);
-+	memset(blob, 0, bloblen);
- 	free(blob);
- 
- 	packet_get_state(MODE_OUT, &seqnr, &blocks, &packets, &bytes);
-@@ -1208,10 +1224,11 @@ mm_audit_event(ssh_audit_event_t event)
- 	buffer_free(&m);
- }
- 
--void
-+int
- mm_audit_run_command(const char *command)
- {
- 	Buffer m;
-+	int handle;
- 
- 	debug3("%s entering command %s", __func__, command);
- 
-@@ -1219,6 +1236,26 @@ mm_audit_run_command(const char *command)
- 	buffer_put_cstring(&m, command);
- 
- 	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, &m);
-+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, &m);
-+
-+	handle = buffer_get_int(&m);
-+	buffer_free(&m);
-+
-+	return (handle);
-+}
-+
-+void
-+mm_audit_end_command(int handle, const char *command)
-+{
-+	Buffer m;
-+
-+	debug3("%s entering command %s", __func__, command);
-+
-+	buffer_init(&m);
-+	buffer_put_int(&m, handle);
-+	buffer_put_cstring(&m, command);
-+
-+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, &m);
- 	buffer_free(&m);
- }
- #endif /* SSH_AUDIT_EVENTS */
-@@ -1354,3 +1391,71 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store)
- 
- #endif /* GSSAPI */
- 
-+#ifdef SSH_AUDIT_EVENTS
-+void
-+mm_audit_unsupported_body(int what)
-+{
-+	Buffer m;
-+
-+	buffer_init(&m);
-+	buffer_put_int(&m, what);
-+
-+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, &m);
-+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED,
-+				  &m);
-+
-+	buffer_free(&m);
-+}
-+
-+void
-+mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, pid_t pid,
-+		  uid_t uid)
-+{
-+	Buffer m;
-+
-+	buffer_init(&m);
-+	buffer_put_int(&m, ctos);
-+	buffer_put_cstring(&m, cipher);
-+	buffer_put_cstring(&m, (mac ? mac : ""));
-+	buffer_put_cstring(&m, compress);
-+	buffer_put_int64(&m, pid);
-+	buffer_put_int64(&m, uid);
-+
-+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, &m);
-+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX,
-+				  &m);
-+
-+	buffer_free(&m);
-+}
-+
-+void
-+mm_audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
-+{
-+	Buffer m;
-+
-+	buffer_init(&m);
-+	buffer_put_int(&m, ctos);
-+	buffer_put_int64(&m, pid);
-+	buffer_put_int64(&m, uid);
-+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m);
-+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE,
-+				  &m);
-+	buffer_free(&m);
-+}
-+
-+void
-+mm_audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid)
-+{
-+	Buffer m;
-+
-+	buffer_init(&m);
-+	buffer_put_cstring(&m, fp);
-+	buffer_put_int64(&m, pid);
-+	buffer_put_int64(&m, uid);
-+
-+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, &m);
-+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SERVER_KEY_FREE,
-+				  &m);
-+	buffer_free(&m);
-+}
-+#endif /* SSH_AUDIT_EVENTS */
-diff --git a/monitor_wrap.h b/monitor_wrap.h
-index 93929e0..4cf0c78 100644
---- a/monitor_wrap.h
-+++ b/monitor_wrap.h
-@@ -52,7 +52,8 @@ int mm_key_allowed(enum mm_keytype, char *, char *, Key *);
- int mm_user_key_allowed(struct passwd *, Key *);
- int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *);
- int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *);
--int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int);
-+int mm_hostbased_key_verify(Key *, u_char *, u_int, u_char *, u_int);
-+int mm_user_key_verify(Key *, u_char *, u_int, u_char *, u_int);
- int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **);
- int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *);
- BIGNUM *mm_auth_rsa_generate_challenge(Key *);
-@@ -79,7 +80,12 @@ void mm_sshpam_free_ctx(void *);
- #ifdef SSH_AUDIT_EVENTS
- #include "audit.h"
- void mm_audit_event(ssh_audit_event_t);
--void mm_audit_run_command(const char *);
-+int mm_audit_run_command(const char *);
-+void mm_audit_end_command(int, const char *);
-+void mm_audit_unsupported_body(int);
-+void mm_audit_kex_body(int, char *, char *, char *, pid_t, uid_t);
-+void mm_audit_session_key_free_body(int, pid_t, uid_t);
-+void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t);
- #endif
- 
- struct Session;
-diff --git a/packet.c b/packet.c
-index 660a9fc..f5b122b 100644
---- a/packet.c
-+++ b/packet.c
-@@ -61,6 +61,7 @@
- #include <time.h>
- 
- #include "xmalloc.h"
-+#include "audit.h"
- #include "buffer.h"
- #include "packet.h"
- #include "crc32.h"
-@@ -476,6 +477,13 @@ packet_get_connection_out(void)
- 	return active_state->connection_out;
- }
- 
-+static int
-+packet_state_has_keys (const struct session_state *state)
-+{
-+	return state != NULL &&
-+		(state->newkeys[MODE_IN] != NULL || state->newkeys[MODE_OUT] != NULL);
-+}
-+
- /* Closes the connection and clears and frees internal data structures. */
- 
- void
-@@ -484,13 +492,6 @@ packet_close(void)
- 	if (!active_state->initialized)
- 		return;
- 	active_state->initialized = 0;
--	if (active_state->connection_in == active_state->connection_out) {
--		shutdown(active_state->connection_out, SHUT_RDWR);
--		close(active_state->connection_out);
--	} else {
--		close(active_state->connection_in);
--		close(active_state->connection_out);
--	}
- 	buffer_free(&active_state->input);
- 	buffer_free(&active_state->output);
- 	buffer_free(&active_state->outgoing_packet);
-@@ -499,8 +500,18 @@ packet_close(void)
- 		buffer_free(&active_state->compression_buffer);
- 		buffer_compress_uninit();
- 	}
--	cipher_cleanup(&active_state->send_context);
--	cipher_cleanup(&active_state->receive_context);
-+	if (packet_state_has_keys(active_state)) {
-+		cipher_cleanup(&active_state->send_context);
-+		cipher_cleanup(&active_state->receive_context);
-+		audit_session_key_free(2);
-+	}
-+	if (active_state->connection_in == active_state->connection_out) {
-+		shutdown(active_state->connection_out, SHUT_RDWR);
-+		close(active_state->connection_out);
-+	} else {
-+		close(active_state->connection_in);
-+		close(active_state->connection_out);
-+	}
- }
- 
- /* Sets remote side protocol flags. */
-@@ -736,6 +747,25 @@ packet_send1(void)
- 	 */
- }
- 
-+static void
-+newkeys_destroy_and_free(Newkeys *newkeys)
-+{
-+	if (newkeys == NULL)
-+		return;
-+
-+	free(newkeys->enc.name);
-+
-+	if (newkeys->mac.enabled) {
-+		mac_clear(&newkeys->mac);
-+		free(newkeys->mac.name);
-+	}
-+
-+	free(newkeys->comp.name);
-+
-+	newkeys_destroy(newkeys);
-+	free(newkeys);
-+}
-+
- void
- set_newkeys(int mode)
- {
-@@ -761,6 +791,7 @@ set_newkeys(int mode)
- 	}
- 	if (active_state->newkeys[mode] != NULL) {
- 		debug("set_newkeys: rekeying");
-+		audit_session_key_free(mode);
- 		cipher_cleanup(cc);
- 		enc  = &active_state->newkeys[mode]->enc;
- 		mac  = &active_state->newkeys[mode]->mac;
-@@ -2011,6 +2042,47 @@ packet_get_newkeys(int mode)
- 	return (void *)active_state->newkeys[mode];
- }
- 
-+static void
-+packet_destroy_state(struct session_state *state)
-+{
-+	if (state == NULL)
-+		return;
-+
-+	cipher_cleanup(&state->receive_context);
-+	cipher_cleanup(&state->send_context);
-+
-+	buffer_free(&state->input);
-+	buffer_free(&state->output);
-+	buffer_free(&state->outgoing_packet);
-+	buffer_free(&state->incoming_packet);
-+	buffer_free(&state->compression_buffer);
-+	newkeys_destroy_and_free(state->newkeys[MODE_IN]);
-+	state->newkeys[MODE_IN] = NULL;
-+	newkeys_destroy_and_free(state->newkeys[MODE_OUT]);
-+	state->newkeys[MODE_OUT] = NULL;
-+	mac_destroy(state->packet_discard_mac);
-+//	TAILQ_HEAD(, packet) outgoing;
-+//	memset(state, 0, sizeof(state));
-+}
-+
-+void
-+packet_destroy_all(int audit_it, int privsep)
-+{
-+	if (audit_it)
-+		audit_it = packet_state_has_keys (active_state) ||
-+			packet_state_has_keys (backup_state);
-+	packet_destroy_state(active_state);
-+	packet_destroy_state(backup_state);
-+	if (audit_it) {
-+#ifdef SSH_AUDIT_EVENTS
-+		if (privsep)
-+			audit_session_key_free(2);
-+		else
-+			audit_session_key_free_body(2, getpid(), getuid());
-+#endif
-+	}
-+}
-+
- /*
-  * Save the state for the real connection, and use a separate state when
-  * resuming a suspended connection.
-@@ -2018,18 +2090,12 @@ packet_get_newkeys(int mode)
- void
- packet_backup_state(void)
- {
--	struct session_state *tmp;
--
- 	close(active_state->connection_in);
- 	active_state->connection_in = -1;
- 	close(active_state->connection_out);
- 	active_state->connection_out = -1;
--	if (backup_state)
--		tmp = backup_state;
--	else
--		tmp = alloc_session_state();
- 	backup_state = active_state;
--	active_state = tmp;
-+	active_state = alloc_session_state();
- }
- 
- /*
-@@ -2046,9 +2112,7 @@ packet_restore_state(void)
- 	backup_state = active_state;
- 	active_state = tmp;
- 	active_state->connection_in = backup_state->connection_in;
--	backup_state->connection_in = -1;
- 	active_state->connection_out = backup_state->connection_out;
--	backup_state->connection_out = -1;
- 	len = buffer_len(&backup_state->input);
- 	if (len > 0) {
- 		buf = buffer_ptr(&backup_state->input);
-@@ -2056,4 +2120,10 @@ packet_restore_state(void)
- 		buffer_clear(&backup_state->input);
- 		add_recv_bytes(len);
- 	}
-+	backup_state->connection_in = -1;
-+	backup_state->connection_out = -1;
-+	packet_destroy_state(backup_state);
-+	free(backup_state);
-+	backup_state = NULL;
- }
-+
-diff --git a/packet.h b/packet.h
-index f8edf85..c36c812 100644
---- a/packet.h
-+++ b/packet.h
-@@ -124,4 +124,5 @@ void	 packet_restore_state(void);
- void	*packet_get_input(void);
- void	*packet_get_output(void);
- 
-+void	 packet_destroy_all(int, int);
- #endif				/* PACKET_H */
-diff --git a/session.c b/session.c
-index df43592..b186ca1 100644
---- a/session.c
-+++ b/session.c
-@@ -138,7 +138,7 @@ extern int log_stderr;
- extern int debug_flag;
- extern u_int utmp_len;
- extern int startup_pipe;
--extern void destroy_sensitive_data(void);
-+extern void destroy_sensitive_data(int);
- extern Buffer loginmsg;
- 
- /* original command from peer. */
-@@ -746,6 +746,14 @@ do_exec_pty(Session *s, const char *command)
- 	/* Parent.  Close the slave side of the pseudo tty. */
- 	close(ttyfd);
- 
-+#ifndef HAVE_OSF_SIA
-+	/* do_login in the child did not affect state in this process,
-+	   compensate.  From an architectural standpoint, this is extremely
-+	   ugly. */
-+	if (!(options.use_login && command == NULL))
-+		audit_count_session_open();
-+#endif
-+
- 	/* Enter interactive session. */
- 	s->ptymaster = ptymaster;
- 	packet_set_interactive(1, 
-@@ -863,15 +871,19 @@ do_exec(Session *s, const char *command)
- 	    get_remote_port());
- 
- #ifdef SSH_AUDIT_EVENTS
-+	if (s->command != NULL || s->command_handle != -1)
-+		fatal("do_exec: command already set");
- 	if (command != NULL)
--		PRIVSEP(audit_run_command(command));
-+		s->command = xstrdup(command);
- 	else if (s->ttyfd == -1) {
- 		char *shell = s->pw->pw_shell;
- 
- 		if (shell[0] == '\0')	/* empty shell means /bin/sh */
- 			shell =_PATH_BSHELL;
--		PRIVSEP(audit_run_command(shell));
-+		s->command = xstrdup(shell);
- 	}
-+	if (s->command != NULL)
-+		s->command_handle = PRIVSEP(audit_run_command(s->command));
- #endif
- 	if (s->ttyfd != -1)
- 		ret = do_exec_pty(s, command);
-@@ -1708,7 +1720,10 @@ do_child(Session *s, const char *command)
- 	int r = 0;
- 
- 	/* remove hostkey from the child's memory */
--	destroy_sensitive_data();
-+	destroy_sensitive_data(1);
-+	/* Don't audit this - both us and the parent would be talking to the
-+	   monitor over a single socket, with no synchronization. */
-+	packet_destroy_all(0, 1);
- 
- 	/* Force a password change */
- 	if (s->authctxt->force_pwchange) {
-@@ -1933,6 +1948,7 @@ session_unused(int id)
- 	sessions[id].ttyfd = -1;
- 	sessions[id].ptymaster = -1;
- 	sessions[id].x11_chanids = NULL;
-+	sessions[id].command_handle = -1;
- 	sessions[id].next_unused = sessions_first_unused;
- 	sessions_first_unused = id;
- }
-@@ -2015,6 +2031,19 @@ session_open(Authctxt *authctxt, int chanid)
- }
- 
- Session *
-+session_by_id(int id)
-+{
-+	if (id >= 0 && id < sessions_nalloc) {
-+		Session *s = &sessions[id];
-+		if (s->used)
-+			return s;
-+	}
-+	debug("session_by_id: unknown id %d", id);
-+	session_dump();
-+	return NULL;
-+}
-+
-+Session *
- session_by_tty(char *tty)
- {
- 	int i;
-@@ -2531,6 +2560,30 @@ session_exit_message(Session *s, int status)
- 		chan_write_failed(c);
- }
- 
-+#ifdef SSH_AUDIT_EVENTS
-+void
-+session_end_command2(Session *s)
-+{
-+	if (s->command != NULL) {
-+		audit_end_command(s->command_handle, s->command);
-+		free(s->command);
-+		s->command = NULL;
-+		s->command_handle = -1;
-+	}
-+}
-+
-+static void
-+session_end_command(Session *s)
-+{
-+	if (s->command != NULL) {
-+		PRIVSEP(audit_end_command(s->command_handle, s->command));
-+		free(s->command);
-+		s->command = NULL;
-+		s->command_handle = -1;
-+	}
-+}
-+#endif
-+
- void
- session_close(Session *s)
- {
-@@ -2539,6 +2592,10 @@ session_close(Session *s)
- 	debug("session_close: session %d pid %ld", s->self, (long)s->pid);
- 	if (s->ttyfd != -1)
- 		session_pty_cleanup(s);
-+#ifdef SSH_AUDIT_EVENTS
-+	if (s->command)
-+		session_end_command(s);
-+#endif
- 	free(s->term);
- 	free(s->display);
- 	free(s->x11_chanids);
-@@ -2753,6 +2810,15 @@ do_authenticated2(Authctxt *authctxt)
- 	server_loop2(authctxt);
- }
- 
-+static void
-+do_cleanup_one_session(Session *s)
-+{
-+	session_pty_cleanup2(s);
-+#ifdef SSH_AUDIT_EVENTS
-+	session_end_command2(s);
-+#endif
-+}
-+
- void
- do_cleanup(Authctxt *authctxt)
- {
-@@ -2801,5 +2867,5 @@ do_cleanup(Authctxt *authctxt)
- 	 * or if running in monitor.
- 	 */
- 	if (!use_privsep || mm_is_monitor())
--		session_destroy_all(session_pty_cleanup2);
-+		session_destroy_all(do_cleanup_one_session);
- }
-diff --git a/session.h b/session.h
-index 6a2f35e..e9b312e 100644
---- a/session.h
-+++ b/session.h
-@@ -61,6 +61,12 @@ struct Session {
- 		char	*name;
- 		char	*val;
- 	} *env;
-+
-+	/* exec */
-+#ifdef SSH_AUDIT_EVENTS
-+	int	command_handle;
-+	char	*command;
-+#endif
- };
- 
- void	 do_authenticated(Authctxt *);
-@@ -73,8 +79,10 @@ void	 session_close_by_pid(pid_t, int);
- void	 session_close_by_channel(int, void *);
- void	 session_destroy_all(void (*)(Session *));
- void	 session_pty_cleanup2(Session *);
-+void	 session_end_command2(Session *);
- 
- Session	*session_new(void);
-+Session *session_by_id(int);
- Session	*session_by_tty(char *);
- void	 session_close(Session *);
- void	 do_setusercontext(struct passwd *);
-diff --git a/sshd.c b/sshd.c
-index 8a0740a..2813aa2 100644
---- a/sshd.c
-+++ b/sshd.c
-@@ -119,6 +119,7 @@
- #endif
- #include "monitor_wrap.h"
- #include "roaming.h"
-+#include "audit.h"
- #include "ssh-sandbox.h"
- #include "version.h"
- 
-@@ -264,7 +265,7 @@ Buffer loginmsg;
- struct passwd *privsep_pw = NULL;
- 
- /* Prototypes for various functions defined later in this file. */
--void destroy_sensitive_data(void);
-+void destroy_sensitive_data(int);
- void demote_sensitive_data(void);
- 
- static void do_ssh1_kex(void);
-@@ -283,6 +284,15 @@ close_listen_socks(void)
- 	num_listen_socks = -1;
- }
- 
-+/*
-+ * Is this process listening for clients (i.e. not specific to any specific
-+ * client connection?)
-+ */
-+int listening_for_clients(void)
-+{
-+	return num_listen_socks > 0;
-+}
-+
- static void
- close_startup_pipes(void)
- {
-@@ -562,22 +572,45 @@ sshd_exchange_identification(int sock_in, int sock_out)
- 	}
- }
- 
--/* Destroy the host and server keys.  They will no longer be needed. */
-+/*
-+ * Destroy the host and server keys.  They will no longer be needed.  Careful,
-+ * this can be called from cleanup_exit() - i.e. from just about anywhere.
-+ */
- void
--destroy_sensitive_data(void)
-+destroy_sensitive_data(int privsep)
- {
- 	int i;
-+	pid_t pid;
-+	uid_t uid;
- 
- 	if (sensitive_data.server_key) {
- 		key_free(sensitive_data.server_key);
- 		sensitive_data.server_key = NULL;
- 	}
-+	pid = getpid();
-+	uid = getuid();
- 	for (i = 0; i < options.num_host_key_files; i++) {
- 		if (sensitive_data.host_keys[i]) {
-+			char *fp;
-+
-+			if (key_is_private(sensitive_data.host_keys[i]))
-+				fp = key_selected_fingerprint(sensitive_data.host_keys[i], SSH_FP_HEX);
-+			else
-+				fp = NULL;
- 			key_free(sensitive_data.host_keys[i]);
- 			sensitive_data.host_keys[i] = NULL;
-+			if (fp != NULL) {
-+				if (privsep)
-+					PRIVSEP(audit_destroy_sensitive_data(fp,
-+						pid, uid));
-+				else
-+					audit_destroy_sensitive_data(fp,
-+						pid, uid);
-+				free(fp);
-+			}
- 		}
--		if (sensitive_data.host_certificates[i]) {
-+		if (sensitive_data.host_certificates
-+		    && sensitive_data.host_certificates[i]) {
- 			key_free(sensitive_data.host_certificates[i]);
- 			sensitive_data.host_certificates[i] = NULL;
- 		}
-@@ -591,6 +624,8 @@ void
- demote_sensitive_data(void)
- {
- 	Key *tmp;
-+	pid_t pid;
-+	uid_t uid;
- 	int i;
- 
- 	if (sensitive_data.server_key) {
-@@ -599,13 +634,25 @@ demote_sensitive_data(void)
- 		sensitive_data.server_key = tmp;
- 	}
- 
-+	pid = getpid();
-+	uid = getuid();
- 	for (i = 0; i < options.num_host_key_files; i++) {
- 		if (sensitive_data.host_keys[i]) {
-+			char *fp;
-+
-+			if (key_is_private(sensitive_data.host_keys[i]))
-+				fp = key_selected_fingerprint(sensitive_data.host_keys[i], SSH_FP_HEX);
-+			else
-+				fp = NULL;
- 			tmp = key_demote(sensitive_data.host_keys[i]);
- 			key_free(sensitive_data.host_keys[i]);
- 			sensitive_data.host_keys[i] = tmp;
- 			if (tmp->type == KEY_RSA1)
- 				sensitive_data.ssh1_host_key = tmp;
-+			if (fp != NULL) {
-+				audit_destroy_sensitive_data(fp, pid, uid);
-+				free(fp);
-+			}
- 		}
- 		/* Certs do not need demotion */
- 	}
-@@ -675,7 +722,7 @@ privsep_preauth(Authctxt *authctxt)
- 
- 	if (use_privsep == PRIVSEP_ON)
- 		box = ssh_sandbox_init(pmonitor);
--	pid = fork();
-+	pmonitor->m_pid = pid = fork();
- 	if (pid == -1) {
- 		fatal("fork of unprivileged child failed");
- 	} else if (pid != 0) {
-@@ -729,6 +776,8 @@ privsep_preauth(Authctxt *authctxt)
- 	}
- }
- 
-+extern Newkeys *current_keys[];
-+
- static void
- privsep_postauth(Authctxt *authctxt)
- {
-@@ -753,6 +802,10 @@ privsep_postauth(Authctxt *authctxt)
- 	else if (pmonitor->m_pid != 0) {
- 		verbose("User child is on pid %ld", (long)pmonitor->m_pid);
- 		buffer_clear(&loginmsg);
-+ 		newkeys_destroy(current_keys[MODE_OUT]);
-+		newkeys_destroy(current_keys[MODE_IN]);
-+		audit_session_key_free_body(2, getpid(), getuid());
-+		packet_destroy_all(0, 0);
- 		monitor_child_postauth(pmonitor);
- 
- 		/* NEVERREACHED */
-@@ -1211,6 +1264,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
- 		if (received_sigterm) {
- 			logit("Received signal %d; terminating.",
- 			    (int) received_sigterm);
-+			destroy_sensitive_data(0);
- 			close_listen_socks();
- 			unlink(options.pid_file);
- 			exit(received_sigterm == SIGTERM ? 0 : 255);
-@@ -2134,6 +2188,7 @@ main(int ac, char **av)
- 	 */
- 	if (use_privsep) {
- 		mm_send_keystate(pmonitor);
-+		packet_destroy_all(1, 1);
- 		exit(0);
- 	}
- 
-@@ -2179,7 +2234,7 @@ main(int ac, char **av)
- 		privsep_postauth(authctxt);
- 		/* the monitor process [priv] will not return */
- 		if (!compat20)
--			destroy_sensitive_data();
-+			destroy_sensitive_data(0);
- 	}
- 
- 	packet_set_timeout(options.client_alive_interval,
-@@ -2189,6 +2244,9 @@ main(int ac, char **av)
- 	do_authenticated(authctxt);
- 
- 	/* The connection has been terminated. */
-+	packet_destroy_all(1, 1);
-+	destroy_sensitive_data(1);
-+
- 	packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes);
- 	packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes);
- 	verbose("Transferred: sent %llu, received %llu bytes",
-@@ -2346,6 +2404,10 @@ do_ssh1_kex(void)
- 		if (cookie[i] != packet_get_char())
- 			packet_disconnect("IP Spoofing check bytes do not match.");
- 
-+#ifdef SSH_AUDIT_EVENTS
-+	audit_kex(2, cipher_name(cipher_type), "crc", "none");
-+#endif
-+
- 	debug("Encryption type: %.200s", cipher_name(cipher_type));
- 
- 	/* Get the encrypted integer. */
-@@ -2418,7 +2480,7 @@ do_ssh1_kex(void)
- 			session_id[i] = session_key[i] ^ session_key[i + 16];
- 	}
- 	/* Destroy the private and public keys. No longer. */
--	destroy_sensitive_data();
-+	destroy_sensitive_data(0);
- 
- 	if (use_privsep)
- 		mm_ssh1_session_id(session_id);
-@@ -2584,6 +2646,16 @@ do_ssh2_kex(void)
- void
- cleanup_exit(int i)
- {
-+	static int in_cleanup = 0;
-+	int is_privsep_child;
-+
-+	/* cleanup_exit can be called at the very least from the privsep
-+	   wrappers used for auditing.  Make sure we don't recurse
-+	   indefinitely. */
-+	if (in_cleanup)
-+		_exit(i);
-+	in_cleanup = 1;
-+
- 	if (the_authctxt) {
- 		do_cleanup(the_authctxt);
- 		if (use_privsep && privsep_is_preauth && pmonitor->m_pid > 1) {
-@@ -2594,9 +2666,14 @@ cleanup_exit(int i)
- 				    pmonitor->m_pid, strerror(errno));
- 		}
- 	}
-+	is_privsep_child = use_privsep && pmonitor != NULL && pmonitor->m_pid == 0;
-+	if (sensitive_data.host_keys != NULL)
-+		destroy_sensitive_data(is_privsep_child);
-+	packet_destroy_all(1, is_privsep_child);
- #ifdef SSH_AUDIT_EVENTS
- 	/* done after do_cleanup so it can cancel the PAM auth 'thread' */
--	if (!use_privsep || mm_is_monitor())
-+	if ((the_authctxt == NULL || !the_authctxt->authenticated) &&
-+	    (!use_privsep || mm_is_monitor()))
- 		audit_event(SSH_CONNECTION_ABANDON);
- #endif
- 	_exit(i);
diff --git a/openssh-6.6p1-ctr-cavstest.patch b/openssh-6.6p1-ctr-cavstest.patch
index 1997fa6..6f4f1e8 100644
--- a/openssh-6.6p1-ctr-cavstest.patch
+++ b/openssh-6.6p1-ctr-cavstest.patch
@@ -1,7 +1,6 @@
-diff --git a/Makefile.in b/Makefile.in
-index 4ab6717..581b121 100644
---- a/Makefile.in
-+++ b/Makefile.in
+diff -up openssh-6.8p1/Makefile.in.ctr-cavs openssh-6.8p1/Makefile.in
+--- openssh-6.8p1/Makefile.in.ctr-cavs	2015-03-18 11:22:05.493289018 +0100
++++ openssh-6.8p1/Makefile.in	2015-03-18 11:22:44.504196316 +0100
 @@ -28,6 +28,7 @@ SSH_KEYSIGN=$(libexecdir)/ssh-keysign
  SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper
  SSH_LDAP_WRAPPER=$(libexecdir)/ssh-ldap-wrapper
@@ -10,16 +9,16 @@ index 4ab6717..581b121 100644
  SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
  PRIVSEP_PATH=@PRIVSEP_PATH@
  SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
-@@ -65,7 +66,7 @@ EXEEXT=@EXEEXT@
+@@ -66,7 +67,7 @@ EXEEXT=@EXEEXT@
  MANFMT=@MANFMT@
  INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@
  
 -TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT)
 +TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT) ctr-cavstest$(EXEEXT)
  
- LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \
- 	canohost.o channels.o cipher.o cipher-aes.o \
-@@ -180,6 +181,9 @@ ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o
+ LIBOPENSSH_OBJS=\
+ 	ssh_api.o \
+@@ -194,6 +195,9 @@ ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) l
  ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHDOBJS) libssh.a ssh-keycat.o
  	$(LD) -o $@ ssh-keycat.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHDLIBS) $(SSHLIBS)
  
@@ -29,7 +28,7 @@ index 4ab6717..581b121 100644
  ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o
  	$(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
  
-@@ -288,6 +292,7 @@ install-files:
+@@ -326,6 +330,7 @@ install-files:
  		$(INSTALL) -m 0700 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \
  	fi
  	$(INSTALL) -m 0755 $(STRIP_OPT) ssh-keycat$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-keycat$(EXEEXT)
@@ -37,11 +36,9 @@ index 4ab6717..581b121 100644
  	$(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT)
  	$(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
  	$(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
-diff --git a/ctr-cavstest.c b/ctr-cavstest.c
-new file mode 100644
-index 0000000..bbcbe8a
---- /dev/null
-+++ b/ctr-cavstest.c
+diff -up openssh-6.8p1/ctr-cavstest.c.ctr-cavs openssh-6.8p1/ctr-cavstest.c
+--- openssh-6.8p1/ctr-cavstest.c.ctr-cavs	2015-03-18 11:22:05.521288952 +0100
++++ openssh-6.8p1/ctr-cavstest.c	2015-03-18 11:22:05.521288952 +0100
 @@ -0,0 +1,208 @@
 +/*
 + *
diff --git a/openssh-6.6p1-entropy.patch b/openssh-6.6p1-entropy.patch
index 67bd30f..6076165 100644
--- a/openssh-6.6p1-entropy.patch
+++ b/openssh-6.6p1-entropy.patch
@@ -1,8 +1,8 @@
 diff --git a/entropy.c b/entropy.c
-index 2d483b3..b361a04 100644
+index 1e9d52a..d24e724 100644
 --- a/entropy.c
 +++ b/entropy.c
-@@ -234,6 +234,9 @@ seed_rng(void)
+@@ -227,6 +227,9 @@ seed_rng(void)
  	memset(buf, '\0', sizeof(buf));
  
  #endif /* OPENSSL_PRNG_ONLY */
@@ -13,12 +13,12 @@ index 2d483b3..b361a04 100644
  		fatal("PRNG is not seeded");
  }
 diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in
-index b912dbe..9206337 100644
+index 843225d..041bbab 100644
 --- a/openbsd-compat/Makefile.in
 +++ b/openbsd-compat/Makefile.in
 @@ -20,7 +20,7 @@ OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o di
  
- COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o
+ COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o kludge-fd_set.o
  
 -PORTS=port-aix.o port-irix.o port-linux.o port-linux-sshd.o port-solaris.o port-tun.o port-uw.o
 +PORTS=port-aix.o port-irix.o port-linux.o port-linux-sshd.o port-linux-prng.o port-solaris.o port-tun.o port-uw.o
@@ -27,7 +27,7 @@ index b912dbe..9206337 100644
  	$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
 diff --git a/openbsd-compat/port-linux-prng.c b/openbsd-compat/port-linux-prng.c
 new file mode 100644
-index 0000000..92a617c
+index 0000000..da84bf2
 --- /dev/null
 +++ b/openbsd-compat/port-linux-prng.c
 @@ -0,0 +1,59 @@
@@ -63,6 +63,7 @@ index 0000000..92a617c
 +
 +#include "log.h"
 +#include "xmalloc.h"
++#include "misc.h"      /* servconf.h needs misc.h for struct ForwardOptions */
 +#include "servconf.h"
 +#include "port-linux.h"
 +#include "key.h"
@@ -72,10 +73,9 @@ index 0000000..92a617c
 +void
 +linux_seed(void)
 +{
-+	int len;
 +	char *env = getenv("SSH_USE_STRONG_RNG");
 +	char *random = "/dev/random";
-+	size_t ienv, randlen = 14;
++	size_t len, ienv, randlen = 14;
 +
 +	if (!env || !strcmp(env, "0"))
 +		random = "/dev/urandom";
@@ -91,7 +91,7 @@ index 0000000..92a617c
 +	}
 +}
 diff --git a/ssh-add.0 b/ssh-add.0
-index ba43fee..0b2629a 100644
+index f16165a..17d22cf 100644
 --- a/ssh-add.0
 +++ b/ssh-add.0
 @@ -82,6 +82,16 @@ ENVIRONMENT
@@ -112,10 +112,10 @@ index ba43fee..0b2629a 100644
       ~/.ssh/identity
               Contains the protocol version 1 RSA authentication identity of
 diff --git a/ssh-add.1 b/ssh-add.1
-index 4812448..16305bf 100644
+index 04d1840..db883a4 100644
 --- a/ssh-add.1
 +++ b/ssh-add.1
-@@ -161,6 +161,20 @@ to make this work.)
+@@ -170,6 +170,20 @@ to make this work.)
  Identifies the path of a
  .Ux Ns -domain
  socket used to communicate with the agent.
@@ -137,10 +137,10 @@ index 4812448..16305bf 100644
  .Sh FILES
  .Bl -tag -width Ds
 diff --git a/ssh-agent.1 b/ssh-agent.1
-index 281ecbd..1a9a635 100644
+index d7e791b..7332f0d 100644
 --- a/ssh-agent.1
 +++ b/ssh-agent.1
-@@ -201,6 +201,24 @@ sockets used to contain the connection to the authentication agent.
+@@ -189,6 +189,24 @@ sockets used to contain the connection to the authentication agent.
  These sockets should only be readable by the owner.
  The sockets should get automatically removed when the agent exits.
  .El
@@ -166,10 +166,10 @@ index 281ecbd..1a9a635 100644
  .Xr ssh 1 ,
  .Xr ssh-add 1 ,
 diff --git a/ssh-keygen.1 b/ssh-keygen.1
-index 12e00d4..1b51a4a 100644
+index 276dacc..a09d9b1 100644
 --- a/ssh-keygen.1
 +++ b/ssh-keygen.1
-@@ -832,6 +832,24 @@ Contains Diffie-Hellman groups used for DH-GEX.
+@@ -841,6 +841,24 @@ Contains Diffie-Hellman groups used for DH-GEX.
  The file format is described in
  .Xr moduli 5 .
  .El
@@ -224,10 +224,10 @@ index 69d0829..02d79f8 100644
  .Xr ssh 1 ,
  .Xr ssh-keygen 1 ,
 diff --git a/ssh.1 b/ssh.1
-index 929904b..f65e42f 100644
+index 4a476c2..410a04a 100644
 --- a/ssh.1
 +++ b/ssh.1
-@@ -1309,6 +1309,23 @@ For more information, see the
+@@ -1299,6 +1299,23 @@ For more information, see the
  .Cm PermitUserEnvironment
  option in
  .Xr sshd_config 5 .
@@ -252,10 +252,10 @@ index 929904b..f65e42f 100644
  .Bl -tag -width Ds -compact
  .It Pa ~/.rhosts
 diff --git a/sshd.8 b/sshd.8
-index c2c237f..058d37a 100644
+index cb866b5..adcaaf9 100644
 --- a/sshd.8
 +++ b/sshd.8
-@@ -951,6 +951,24 @@ concurrently for different ports, this contains the process ID of the one
+@@ -945,6 +945,24 @@ concurrently for different ports, this contains the process ID of the one
  started last).
  The content of this file is not sensitive; it can be world-readable.
  .El
diff --git a/openssh-6.6p1-fingerprint.patch b/openssh-6.6p1-fingerprint.patch
deleted file mode 100644
index c5332fb..0000000
--- a/openssh-6.6p1-fingerprint.patch
+++ /dev/null
@@ -1,415 +0,0 @@
-diff --git a/auth.c b/auth.c
-index 9a36f1d..420a85b 100644
---- a/auth.c
-+++ b/auth.c
-@@ -685,9 +685,10 @@ auth_key_is_revoked(Key *key)
- 	case 1:
-  revoked:
- 		/* Key revoked */
--		key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
-+		key_fp = key_selected_fingerprint(key, SSH_FP_HEX);
- 		error("WARNING: authentication attempt with a revoked "
--		    "%s key %s ", key_type(key), key_fp);
-+		    "%s key %s%s ", key_type(key),
-+		    key_fingerprint_prefix(), key_fp);
- 		free(key_fp);
- 		return 1;
- 	}
-diff --git a/auth2-hostbased.c b/auth2-hostbased.c
-index 488008f..eca0069 100644
---- a/auth2-hostbased.c
-+++ b/auth2-hostbased.c
-@@ -206,16 +206,18 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
- 
- 	if (host_status == HOST_OK) {
- 		if (key_is_cert(key)) {
--			fp = key_fingerprint(key->cert->signature_key,
--			    SSH_FP_MD5, SSH_FP_HEX);
-+			fp = key_selected_fingerprint(key->cert->signature_key,
-+			    SSH_FP_HEX);		
- 			verbose("Accepted certificate ID \"%s\" signed by "
--			    "%s CA %s from %s@%s", key->cert->key_id,
--			    key_type(key->cert->signature_key), fp,
-+			    "%s CA %s%s from %s@%s", key->cert->key_id,
-+			    key_type(key->cert->signature_key),
-+			    key_fingerprint_prefix(), fp,
- 			    cuser, lookup);
- 		} else {
--			fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
--			verbose("Accepted %s public key %s from %s@%s",
--			    key_type(key), fp, cuser, lookup);
-+			fp = key_selected_fingerprint(key, SSH_FP_HEX);
-+			verbose("Accepted %s public key %s%s from %s@%s",
-+			    key_type(key), key_fingerprint_prefix(),
-+			    fp, cuser, lookup);
- 		}
- 		free(fp);
- 	}
-diff --git a/auth2-pubkey.c b/auth2-pubkey.c
-index 0fd27bb..749b11a 100644
---- a/auth2-pubkey.c
-+++ b/auth2-pubkey.c
-@@ -365,10 +365,10 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
- 				continue;
- 			if (!key_is_cert_authority)
- 				continue;
--			fp = key_fingerprint(found, SSH_FP_MD5,
--			    SSH_FP_HEX);
--			debug("matching CA found: file %s, line %lu, %s %s",
--			    file, linenum, key_type(found), fp);
-+			fp = key_selected_fingerprint(found, SSH_FP_HEX);
-+			debug("matching CA found: file %s, line %lu, %s %s%s",
-+			    file, linenum, key_type(found),
-+			    key_fingerprint_prefix(), fp);
- 			/*
- 			 * If the user has specified a list of principals as
- 			 * a key option, then prefer that list to matching
-@@ -406,9 +406,9 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
- 			if (key_is_cert_authority)
- 				continue;
- 			found_key = 1;
--			fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
--			debug("matching key found: file %s, line %lu %s %s",
--			    file, linenum, key_type(found), fp);
-+			fp = key_selected_fingerprint(found, SSH_FP_HEX);
-+			verbose("Found matching %s key: %s%s",
-+			    key_type(found), key_fingerprint_prefix(), fp);
- 			free(fp);
- 			break;
- 		}
-@@ -431,13 +431,13 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
- 	if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL)
- 		return 0;
- 
--	ca_fp = key_fingerprint(key->cert->signature_key,
--	    SSH_FP_MD5, SSH_FP_HEX);
-+	ca_fp = key_selected_fingerprint(key->cert->signature_key, SSH_FP_HEX);
- 
- 	if (key_in_file(key->cert->signature_key,
- 	    options.trusted_user_ca_keys, 1) != 1) {
--		debug2("%s: CA %s %s is not listed in %s", __func__,
--		    key_type(key->cert->signature_key), ca_fp,
-+		debug2("%s: CA %s%s %s is not listed in %s", __func__,
-+		    key_type(key->cert->signature_key),
-+		    key_fingerprint_prefix(), ca_fp,
- 		    options.trusted_user_ca_keys);
- 		goto out;
- 	}
-diff --git a/key.c b/key.c
-index 168e1b7..eb98ea8 100644
---- a/key.c
-+++ b/key.c
-@@ -628,6 +628,34 @@ key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep)
- 	return retval;
- }
- 
-+enum fp_type
-+key_fingerprint_selection(void)
-+{
-+	static enum fp_type rv;
-+	static char rv_defined = 0;
-+	char *env;
-+
-+	if (!rv_defined) {
-+		env = getenv("SSH_FINGERPRINT_TYPE");
-+		rv = (env && !strcmp (env, "sha")) ?
-+			SSH_FP_SHA1 : SSH_FP_MD5;
-+		rv_defined = 1;
-+	}
-+	return rv;
-+}
-+
-+char *
-+key_selected_fingerprint(Key *k, enum fp_rep dgst_rep)
-+{
-+	return key_fingerprint(k, key_fingerprint_selection(), dgst_rep);
-+}
-+
-+char *
-+key_fingerprint_prefix(void)
-+{
-+	return key_fingerprint_selection() == SSH_FP_SHA1 ? "sha1:" : "";
-+}
-+
- /*
-  * Reads a multiple-precision integer in decimal from the buffer, and advances
-  * the pointer.  The integer must already be initialized.  This function is
-diff --git a/key.h b/key.h
-index d8ad13d..0e3eea5 100644
---- a/key.h
-+++ b/key.h
-@@ -104,6 +104,9 @@ int		 key_equal_public(const Key *, const Key *);
- int		 key_equal(const Key *, const Key *);
- char		*key_fingerprint(const Key *, enum fp_type, enum fp_rep);
- u_char		*key_fingerprint_raw(const Key *, enum fp_type, u_int *);
-+enum fp_type	 key_fingerprint_selection(void);
-+char		*key_selected_fingerprint(Key *, enum fp_rep);
-+char		*key_fingerprint_prefix(void);
- const char	*key_type(const Key *);
- const char	*key_cert_type(const Key *);
- int		 key_write(const Key *, FILE *);
-diff --git a/ssh-add.c b/ssh-add.c
-index 3421452..691949f 100644
---- a/ssh-add.c
-+++ b/ssh-add.c
-@@ -330,10 +330,10 @@ list_identities(AuthenticationConnection *ac, int do_fp)
- 		    key = ssh_get_next_identity(ac, &comment, version)) {
- 			had_identities = 1;
- 			if (do_fp) {
--				fp = key_fingerprint(key, SSH_FP_MD5,
--				    SSH_FP_HEX);
--				printf("%d %s %s (%s)\n",
--				    key_size(key), fp, comment, key_type(key));
-+				fp = key_selected_fingerprint(key, SSH_FP_HEX);
-+				printf("%d %s%s %s (%s)\n",
-+				    key_size(key), key_fingerprint_prefix(),
-+				    fp, comment, key_type(key));
- 				free(fp);
- 			} else {
- 				if (!key_write(key, stdout))
-diff --git a/ssh-agent.c b/ssh-agent.c
-index ba24612..117fdde 100644
---- a/ssh-agent.c
-+++ b/ssh-agent.c
-@@ -198,9 +198,9 @@ confirm_key(Identity *id)
- 	char *p;
- 	int ret = -1;
- 
--	p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
--	if (ask_permission("Allow use of key %s?\nKey fingerprint %s.",
--	    id->comment, p))
-+	p = key_selected_fingerprint(id->key, SSH_FP_HEX);
-+	if (ask_permission("Allow use of key %s?\nKey fingerprint %s%s.",
-+	    id->comment, key_fingerprint_prefix(), p))
- 		ret = 0;
- 	free(p);
- 
-diff --git a/ssh-keygen.c b/ssh-keygen.c
-index 2a316bc..482dc1c 100644
---- a/ssh-keygen.c
-+++ b/ssh-keygen.c
-@@ -783,13 +783,14 @@ do_fingerprint(struct passwd *pw)
- {
- 	FILE *f;
- 	Key *public;
--	char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra;
-+	char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra, *pfx;
- 	int i, skip = 0, num = 0, invalid = 1;
- 	enum fp_rep rep;
- 	enum fp_type fptype;
- 	struct stat st;
- 
--	fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
-+	fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_selection();
-+	pfx =	 print_bubblebabble ? "" : key_fingerprint_prefix();
- 	rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
- 
- 	if (!have_identity)
-@@ -801,8 +802,8 @@ do_fingerprint(struct passwd *pw)
- 	public = key_load_public(identity_file, &comment);
- 	if (public != NULL) {
- 		fp = key_fingerprint(public, fptype, rep);
--		ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
--		printf("%u %s %s (%s)\n", key_size(public), fp, comment,
-+		ra = key_selected_fingerprint(public, SSH_FP_RANDOMART);
-+		printf("%u %s%s %s (%s)\n", key_size(public), pfx, fp, comment,
- 		    key_type(public));
- 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
- 			printf("%s\n", ra);
-@@ -867,8 +868,8 @@ do_fingerprint(struct passwd *pw)
- 		}
- 		comment = *cp ? cp : comment;
- 		fp = key_fingerprint(public, fptype, rep);
--		ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
--		printf("%u %s %s (%s)\n", key_size(public), fp,
-+		ra = key_selected_fingerprint(public, SSH_FP_RANDOMART);
-+		printf("%u %s%s %s (%s)\n", key_size(public), pfx, fp,
- 		    comment ? comment : "no comment", key_type(public));
- 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
- 			printf("%s\n", ra);
-@@ -986,13 +987,15 @@ printhost(FILE *f, const char *name, Key *public, int ca, int hash)
- 	if (print_fingerprint) {
- 		enum fp_rep rep;
- 		enum fp_type fptype;
--		char *fp, *ra;
-+		char *fp, *ra, *pfx;
- 
--		fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
-+		fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_selection();
-+		pfx =	 print_bubblebabble ? "" : key_fingerprint_prefix();
- 		rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
-+
- 		fp = key_fingerprint(public, fptype, rep);
--		ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
--		printf("%u %s %s (%s)\n", key_size(public), fp, name,
-+		ra = key_selected_fingerprint(public, SSH_FP_RANDOMART);
-+		printf("%u %s%s %s (%s)\n", key_size(public), pfx, fp, name,
- 		    key_type(public));
- 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
- 			printf("%s\n", ra);
-@@ -1878,16 +1881,17 @@ do_show_cert(struct passwd *pw)
- 		fatal("%s is not a certificate", identity_file);
- 	v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00;
- 
--	key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
--	ca_fp = key_fingerprint(key->cert->signature_key,
--	    SSH_FP_MD5, SSH_FP_HEX);
-+	key_fp = key_selected_fingerprint(key, SSH_FP_HEX);
-+	ca_fp = key_selected_fingerprint(key->cert->signature_key, SSH_FP_HEX);
- 
- 	printf("%s:\n", identity_file);
- 	printf("        Type: %s %s certificate\n", key_ssh_name(key),
- 	    key_cert_type(key));
--	printf("        Public key: %s %s\n", key_type(key), key_fp);
--	printf("        Signing CA: %s %s\n",
--	    key_type(key->cert->signature_key), ca_fp);
-+	printf("        Public key: %s %s%s\n", key_type(key),
-+	    key_fingerprint_prefix(), key_fp);
-+	printf("        Signing CA: %s %s%s\n",
-+	    key_type(key->cert->signature_key),
-+	    key_fingerprint_prefix(), ca_fp);
- 	printf("        Key ID: \"%s\"\n", key->cert->key_id);
- 	if (!v00) {
- 		printf("        Serial: %llu\n",
-@@ -2686,13 +2690,12 @@ passphrase_again:
- 	fclose(f);
- 
- 	if (!quiet) {
--		char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
--		char *ra = key_fingerprint(public, SSH_FP_MD5,
--		    SSH_FP_RANDOMART);
-+		char *fp = key_selected_fingerprint(public, SSH_FP_HEX);
-+		char *ra = key_selected_fingerprint(public, SSH_FP_RANDOMART);
- 		printf("Your public key has been saved in %s.\n",
- 		    identity_file);
- 		printf("The key fingerprint is:\n");
--		printf("%s %s\n", fp, comment);
-+		printf("%s%s %s\n", key_fingerprint_prefix(), fp, comment);
- 		printf("The key's randomart image is:\n");
- 		printf("%s\n", ra);
- 		free(ra);
-diff --git a/sshconnect.c b/sshconnect.c
-index 573d7a8..394cca8 100644
---- a/sshconnect.c
-+++ b/sshconnect.c
-@@ -914,10 +914,10 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
- 				    "key for IP address '%.128s' to the list "
- 				    "of known hosts.", type, ip);
- 		} else if (options.visual_host_key) {
--			fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
--			ra = key_fingerprint(host_key, SSH_FP_MD5,
--			    SSH_FP_RANDOMART);
--			logit("Host key fingerprint is %s\n%s\n", fp, ra);
-+			fp = key_selected_fingerprint(host_key, SSH_FP_HEX);
-+			ra = key_selected_fingerprint(host_key, SSH_FP_RANDOMART);
-+			logit("Host key fingerprint is %s%s\n%s\n",
-+			    key_fingerprint_prefix(), fp, ra);
- 			free(ra);
- 			free(fp);
- 		}
-@@ -955,9 +955,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
- 			else
- 				snprintf(msg1, sizeof(msg1), ".");
- 			/* The default */
--			fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
--			ra = key_fingerprint(host_key, SSH_FP_MD5,
--			    SSH_FP_RANDOMART);
-+			fp = key_selected_fingerprint(host_key, SSH_FP_HEX);
-+			ra = key_selected_fingerprint(host_key, SSH_FP_RANDOMART);
- 			msg2[0] = '\0';
- 			if (options.verify_host_key_dns) {
- 				if (matching_host_key_dns)
-@@ -972,10 +971,11 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
- 			snprintf(msg, sizeof(msg),
- 			    "The authenticity of host '%.200s (%s)' can't be "
- 			    "established%s\n"
--			    "%s key fingerprint is %s.%s%s\n%s"
-+			    "%s key fingerprint is %s%s.%s%s\n%s"
- 			    "Are you sure you want to continue connecting "
- 			    "(yes/no)? ",
--			    host, ip, msg1, type, fp,
-+			    host, ip, msg1, type,
-+			    key_fingerprint_prefix(), fp,
- 			    options.visual_host_key ? "\n" : "",
- 			    options.visual_host_key ? ra : "",
- 			    msg2);
-@@ -1220,8 +1220,9 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
- 	int flags = 0;
- 	char *fp;
- 
--	fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
--	debug("Server host key: %s %s", key_type(host_key), fp);
-+	fp = key_selected_fingerprint(host_key, SSH_FP_HEX);
-+	debug("Server host key: %s %s%s", key_type(host_key),
-+	    key_fingerprint_prefix(), fp);
- 	free(fp);
- 
- 	/* XXX certs are not yet supported for DNS */
-@@ -1327,14 +1328,15 @@ show_other_keys(struct hostkeys *hostkeys, Key *key)
- 			continue;
- 		if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found))
- 			continue;
--		fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX);
--		ra = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_RANDOMART);
-+		fp = key_selected_fingerprint(found->key, SSH_FP_HEX);
-+		ra = key_selected_fingerprint(found->key, SSH_FP_RANDOMART);
- 		logit("WARNING: %s key found for host %s\n"
- 		    "in %s:%lu\n"
--		    "%s key fingerprint %s.",
-+		    "%s key fingerprint %s%s.",
- 		    key_type(found->key),
- 		    found->host, found->file, found->line,
--		    key_type(found->key), fp);
-+		    key_type(found->key),
-+		    key_fingerprint_prefix(), fp);
- 		if (options.visual_host_key)
- 			logit("%s", ra);
- 		free(ra);
-@@ -1349,7 +1351,7 @@ warn_changed_key(Key *host_key)
- {
- 	char *fp;
- 
--	fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
-+	fp = key_selected_fingerprint(host_key, SSH_FP_HEX);
- 
- 	error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
- 	error("@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @");
-@@ -1357,8 +1359,8 @@ warn_changed_key(Key *host_key)
- 	error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
- 	error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
- 	error("It is also possible that a host key has just been changed.");
--	error("The fingerprint for the %s key sent by the remote host is\n%s.",
--	    key_type(host_key), fp);
-+	error("The fingerprint for the %s key sent by the remote host is\n%s%s.",
-+	    key_type(host_key),key_fingerprint_prefix(),  fp);
- 	error("Please contact your system administrator.");
- 
- 	free(fp);
-diff --git a/sshconnect2.c b/sshconnect2.c
-index 7f4ff41..adbbfc7 100644
---- a/sshconnect2.c
-+++ b/sshconnect2.c
-@@ -577,8 +577,9 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
- 		    key->type, pktype);
- 		goto done;
- 	}
--	fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
--	debug2("input_userauth_pk_ok: fp %s", fp);
-+	fp = key_selected_fingerprint(key, SSH_FP_HEX);
-+	debug2("input_userauth_pk_ok: fp %s%s",
-+	    key_fingerprint_prefix(), fp);
- 	free(fp);
- 
- 	/*
-@@ -986,8 +987,9 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
- 	int have_sig = 1;
- 	char *fp;
- 
--	fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
--	debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp);
-+	fp = key_selected_fingerprint(id->key, SSH_FP_HEX);
-+	debug3("sign_and_send_pubkey: %s %s%s", key_type(id->key),
-+	    key_fingerprint_prefix(), fp);
- 	free(fp);
- 
- 	if (key_to_blob(id->key, &blob, &bloblen) == 0) {
diff --git a/openssh-6.6p1-fips.patch b/openssh-6.6p1-fips.patch
deleted file mode 100644
index f97e2ba..0000000
--- a/openssh-6.6p1-fips.patch
+++ /dev/null
@@ -1,812 +0,0 @@
-diff --git a/Makefile.in b/Makefile.in
-index 3bb7f00..294bef5 100644
---- a/Makefile.in
-+++ b/Makefile.in
-@@ -154,25 +154,25 @@ libssh.a: $(LIBSSH_OBJS)
- 	$(RANLIB) $@
- 
- ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS)
--	$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS) $(GSSLIBS)
-+	$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHLIBS) $(LIBS) $(GSSLIBS)
- 
- sshd$(EXEEXT): libssh.a	$(LIBCOMPAT) $(SSHDOBJS)
--	$(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS)
-+	$(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS)
- 
- scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o
- 	$(LD) -o $@ scp.o progressmeter.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
- 
- ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o
--	$(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
-+	$(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
- 
- ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o
--	$(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
-+	$(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
- 
- ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o
--	$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
-+	$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
- 
- ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o readconf.o
--	$(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
-+	$(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
- 
- ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o
- 	$(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
-@@ -187,7 +187,7 @@ ctr-cavstest$(EXEEXT): $(LIBCOMPAT) libssh.a ctr-cavstest.o
- 	$(LD) -o $@ ctr-cavstest.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS)
- 
- ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o
--	$(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
-+	$(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS)
- 
- sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o
- 	$(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
-diff --git a/auth-rsa.c b/auth-rsa.c
-index f225b0b..8bafcd6 100644
---- a/auth-rsa.c
-+++ b/auth-rsa.c
-@@ -244,7 +244,7 @@ rsa_key_allowed_in_file(struct passwd *pw, char *file,
- 			    "actual %d vs. announced %d.",
- 			    file, linenum, BN_num_bits(key->rsa->n), bits);
- 
--		fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
-+		fp = key_selected_fingerprint(key, SSH_FP_HEX);
- 		debug("matching key found: file %s, line %lu %s %s",
- 		    file, linenum, key_type(key), fp);
- 		free(fp);
-diff --git a/auth2-pubkey.c b/auth2-pubkey.c
-index 6d1c872..3808ec8 100644
---- a/auth2-pubkey.c
-+++ b/auth2-pubkey.c
-@@ -214,8 +214,7 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
- 	}
- 
- 	if (key_is_cert(key)) {
--		fp = key_fingerprint(key->cert->signature_key,
--		    SSH_FP_MD5, SSH_FP_HEX);
-+		fp = key_selected_fingerprint(key->cert->signature_key, SSH_FP_HEX);
- 		auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", 
- 		    key_type(key), key->cert->key_id,
- 		    (unsigned long long)key->cert->serial,
-@@ -223,7 +222,7 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
- 		    extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
- 		free(fp);
- 	} else {
--		fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
-+		fp = key_selected_fingerprint(key, SSH_FP_HEX);
- 		auth_info(authctxt, "%s %s%s%s", key_type(key), fp,
- 		    extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
- 		free(fp);
-diff --git a/authfile.c b/authfile.c
-index ec4f4ff..2b3d650 100644
---- a/authfile.c
-+++ b/authfile.c
-@@ -46,6 +46,7 @@
- #include <openssl/err.h>
- #include <openssl/evp.h>
- #include <openssl/pem.h>
-+#include <openssl/fips.h>
- 
- /* compatibility with old or broken OpenSSL versions */
- #include "openbsd-compat/openssl-compat.h"
-@@ -1068,7 +1069,7 @@ Key *
- key_parse_private(Buffer *buffer, const char *filename,
-     const char *passphrase, char **commentp)
- {
--	Key *pub, *prv;
-+	Key *pub, *prv = NULL;
- 
- 	/* it's a SSH v1 key if the public key part is readable */
- 	pub = key_parse_public_rsa1(buffer, commentp);
-@@ -1080,9 +1081,10 @@ key_parse_private(Buffer *buffer, const char *filename,
- 			*commentp = xstrdup(filename);
- 	} else {
- 		key_free(pub);
--		/* key_parse_public_rsa1() has already loaded the comment */
--		prv = key_parse_private_type(buffer, KEY_RSA1, passphrase,
--		    NULL);
-+		if (! FIPS_mode())
-+			/* key_parse_public_rsa1() has already loaded the comment */
-+			prv = key_parse_private_type(buffer, KEY_RSA1, passphrase,
-+			    NULL);
- 	}
- 	return prv;
- }
-diff --git a/cipher-ctr.c b/cipher-ctr.c
-index 73e9c7c..40ee395 100644
---- a/cipher-ctr.c
-+++ b/cipher-ctr.c
-@@ -179,7 +179,8 @@ evp_aes_128_ctr(void)
- 	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;
-+	    EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV |
-+	    EVP_CIPH_FLAG_FIPS;
- #endif
- 	return (&aes_ctr);
- }
-diff --git a/cipher.c b/cipher.c
-index 226e56d..b19443c 100644
---- a/cipher.c
-+++ b/cipher.c
-@@ -39,6 +39,8 @@
- 
- #include <sys/types.h>
- 
-+#include <openssl/fips.h>
-+
- #include <string.h>
- #include <stdarg.h>
- #include <stdio.h>
-@@ -90,6 +92,25 @@ static const struct Cipher ciphers[] = {
- 	{ NULL,		SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL }
- };
- 
-+static const struct Cipher fips_ciphers[] = {
-+	{ "none",	SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null },
-+	{ "3des-cbc",	SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc },
-+	{ "aes128-cbc",	SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 1, EVP_aes_128_cbc },
-+	{ "aes192-cbc",	SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 1, EVP_aes_192_cbc },
-+	{ "aes256-cbc",	SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc },
-+	{ "rijndael-cbc at lysator.liu.se",
-+			SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc },
-+	{ "aes128-ctr",	SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr },
-+	{ "aes192-ctr",	SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr },
-+	{ "aes256-ctr",	SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr },
-+#ifdef OPENSSL_HAVE_EVPGCM
-+	{ "aes128-gcm at openssh.com",
-+			SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm },
-+	{ "aes256-gcm at openssh.com",
-+			SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm },
-+#endif
-+	{ NULL,		SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL }
-+};
- /*--*/
- 
- /* Returns a list of supported ciphers separated by the specified char. */
-@@ -100,7 +121,7 @@ cipher_alg_list(char sep, int auth_only)
- 	size_t nlen, rlen = 0;
- 	const Cipher *c;
- 
--	for (c = ciphers; c->name != NULL; c++) {
-+	for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) {
- 		if (c->number != SSH_CIPHER_SSH2)
- 			continue;
- 		if (auth_only && c->auth_len == 0)
-@@ -180,7 +201,7 @@ const Cipher *
- cipher_by_name(const char *name)
- {
- 	const Cipher *c;
--	for (c = ciphers; c->name != NULL; c++)
-+	for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++)
- 		if (strcmp(c->name, name) == 0)
- 			return c;
- 	return NULL;
-@@ -190,7 +211,7 @@ const Cipher *
- cipher_by_number(int id)
- {
- 	const Cipher *c;
--	for (c = ciphers; c->name != NULL; c++)
-+	for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++)
- 		if (c->number == id)
- 			return c;
- 	return NULL;
-@@ -232,7 +253,7 @@ cipher_number(const char *name)
- 	const Cipher *c;
- 	if (name == NULL)
- 		return -1;
--	for (c = ciphers; c->name != NULL; c++)
-+	for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++)
- 		if (strcasecmp(c->name, name) == 0)
- 			return c->number;
- 	return -1;
-diff --git a/dh.h b/dh.h
-index 48f7b68..9ff39f4 100644
---- a/dh.h
-+++ b/dh.h
-@@ -45,6 +45,7 @@ int	 dh_estimate(int);
- 
- /* Min and max values from RFC4419. */
- #define DH_GRP_MIN	1024
-+#define DH_GRP_MIN_FIPS	2048
- #define DH_GRP_MAX	8192
- 
- /*
-diff --git a/entropy.c b/entropy.c
-index b361a04..5616643 100644
---- a/entropy.c
-+++ b/entropy.c
-@@ -222,6 +222,9 @@ seed_rng(void)
- 		fatal("OpenSSL version mismatch. Built against %lx, you "
- 		    "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay());
- 
-+	/* clean the PRNG status when exiting the program */
-+	atexit(RAND_cleanup);
-+
- #ifndef OPENSSL_PRNG_ONLY
- 	if (RAND_status() == 1) {
- 		debug3("RNG is ready, skipping seeding");
-diff --git a/kex.c b/kex.c
-index bc3e53e..ede7b67 100644
---- a/kex.c
-+++ b/kex.c
-@@ -34,6 +34,7 @@
- #include <string.h>
- 
- #include <openssl/crypto.h>
-+#include <openssl/fips.h>
- 
- #include "xmalloc.h"
- #include "ssh2.h"
-@@ -103,6 +104,25 @@ static const struct kexalg kexalgs[] = {
- 	{ NULL, -1, -1, -1},
- };
- 
-+static const struct kexalg kexalgs_fips[] = {
-+	{ KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
-+	{ KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
-+#ifdef HAVE_EVP_SHA256
-+	{ KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
-+#endif
-+#ifdef OPENSSL_HAS_ECC
-+	{ KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2,
-+	    NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
-+	{ KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1,
-+	    SSH_DIGEST_SHA384 },
-+# ifdef OPENSSL_HAS_NISTP521
-+	{ KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
-+	    SSH_DIGEST_SHA512 },
-+# endif
-+#endif
-+	{ NULL, -1, -1, NULL},
-+};
-+
- char *
- kex_alg_list(char sep)
- {
-@@ -126,7 +146,7 @@ kex_alg_by_name(const char *name)
- {
- 	const struct kexalg *k;
- 
--	for (k = kexalgs; k->name != NULL; k++) {
-+	for (k = (FIPS_mode() ? kexalgs_fips : kexalgs); k->name != NULL; k++) {
- 		if (strcmp(k->name, name) == 0)
- 			return k;
- #ifdef GSSAPI
-@@ -151,7 +171,10 @@ kex_names_valid(const char *names)
- 	for ((p = strsep(&cp, ",")); p && *p != '\0';
- 	    (p = strsep(&cp, ","))) {
- 		if (kex_alg_by_name(p) == NULL) {
--			error("Unsupported KEX algorithm \"%.100s\"", p);
-+			if (FIPS_mode())
-+				error("\"%.100s\" is not allowed in FIPS mode", p);
-+			else
-+				error("Unsupported KEX algorithm \"%.100s\"", p);
- 			free(s);
- 			return 0;
- 		}
-diff --git a/kexecdhc.c b/kexecdhc.c
-index 2f7629c..20c9946 100644
---- a/kexecdhc.c
-+++ b/kexecdhc.c
-@@ -154,6 +154,7 @@ kexecdh_client(Kex *kex)
- 
- 	kex_derive_keys_bn(kex, hash, hashlen, shared_secret);
- 	BN_clear_free(shared_secret);
-+	memset(hash, 0, hashlen);
- 	kex_finish(kex);
- }
- #else /* OPENSSL_HAS_ECC */
-diff --git a/kexecdhs.c b/kexecdhs.c
-index 2700b72..0820894 100644
---- a/kexecdhs.c
-+++ b/kexecdhs.c
-@@ -150,6 +150,7 @@ kexecdh_server(Kex *kex)
- 
- 	kex_derive_keys_bn(kex, hash, hashlen, shared_secret);
- 	BN_clear_free(shared_secret);
-+	memset(hash, 0, hashlen);
- 	kex_finish(kex);
- }
- #else /* OPENSSL_HAS_ECC */
-diff --git a/kexgexc.c b/kexgexc.c
-index 355b7ba..427e11f 100644
---- a/kexgexc.c
-+++ b/kexgexc.c
-@@ -26,6 +26,8 @@
- 
- #include "includes.h"
- 
-+#include <openssl/fips.h>
-+
- #include <sys/types.h>
- 
- #include <openssl/dh.h>
-@@ -58,7 +60,7 @@ kexgex_client(Kex *kex)
- 	int min, max, nbits;
- 	DH *dh;
- 
--	min = DH_GRP_MIN;
-+	min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN;
- 	max = DH_GRP_MAX;
- 
- 	/* Servers with MAX4096DH need a preferred size (nbits) <= 4096.
-diff --git a/kexgexs.c b/kexgexs.c
-index 770ad28..9d4fc6d 100644
---- a/kexgexs.c
-+++ b/kexgexs.c
-@@ -76,16 +76,16 @@ kexgex_server(Kex *kex)
- 		omin = min = packet_get_int();
- 		onbits = nbits = packet_get_int();
- 		omax = max = packet_get_int();
--		min = MAX(DH_GRP_MIN, min);
-+		min = MAX(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, min);
- 		max = MIN(DH_GRP_MAX, max);
--		nbits = MAX(DH_GRP_MIN, nbits);
-+		nbits = MAX(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, nbits);
- 		nbits = MIN(DH_GRP_MAX, nbits);
- 		break;
- 	case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
- 		debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
- 		onbits = nbits = packet_get_int();
- 		/* unused for old GEX */
--		omin = min = DH_GRP_MIN;
-+		omin = min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN;
- 		omax = max = DH_GRP_MAX;
- 		break;
- 	default:
-diff --git a/key.c b/key.c
-index 62f3edb..a2050f6 100644
---- a/key.c
-+++ b/key.c
-@@ -42,6 +42,7 @@
- #include "crypto_api.h"
- 
- #include <openssl/evp.h>
-+#include <openssl/fips.h>
- #include <openbsd-compat/openssl-compat.h>
- 
- #include <stdarg.h>
-@@ -636,9 +637,13 @@ key_fingerprint_selection(void)
- 	char *env;
- 
- 	if (!rv_defined) {
--		env = getenv("SSH_FINGERPRINT_TYPE");
--		rv = (env && !strcmp (env, "sha")) ?
--			SSH_FP_SHA1 : SSH_FP_MD5;
-+		if (FIPS_mode())
-+			rv = SSH_FP_SHA1;
-+		else {
-+			env = getenv("SSH_FINGERPRINT_TYPE");
-+			rv = (env && !strcmp (env, "sha")) ?
-+				SSH_FP_SHA1 : SSH_FP_MD5;
-+		}
- 		rv_defined = 1;
- 	}
- 	return rv;
-@@ -1168,8 +1173,11 @@ rsa_generate_private_key(u_int bits)
- 		fatal("%s: BN_new failed", __func__);
- 	if (!BN_set_word(f4, RSA_F4))
- 		fatal("%s: BN_new failed", __func__);
--	if (!RSA_generate_key_ex(private, bits, f4, NULL))
-+	if (!RSA_generate_key_ex(private, bits, f4, NULL)) {
-+		if (FIPS_mode())
-+			logit("%s: the key length might be unsupported by FIPS mode approved key generation method", __func__);
- 		fatal("%s: key generation failed.", __func__);
-+	}
- 	BN_free(f4);
- 	return private;
- }
-diff --git a/mac.c b/mac.c
-index 9388af4..cd7b034 100644
---- a/mac.c
-+++ b/mac.c
-@@ -27,6 +27,8 @@
- 
- #include <sys/types.h>
- 
-+#include <openssl/fips.h>
-+
- #include <stdarg.h>
- #include <string.h>
- #include <signal.h>
-@@ -60,7 +62,7 @@ struct macalg {
- 	int		etm;		/* Encrypt-then-MAC */
- };
- 
--static const struct macalg macs[] = {
-+static const struct macalg all_macs[] = {
- 	/* Encrypt-and-MAC (encrypt-and-authenticate) variants */
- 	{ "hmac-sha1",				SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 },
- 	{ "hmac-sha1-96",			SSH_DIGEST, SSH_DIGEST_SHA1, 96, 0, 0, 0 },
-@@ -91,6 +93,24 @@ static const struct macalg macs[] = {
- 	{ NULL,					0, 0, 0, 0, 0, 0 }
- };
- 
-+static const struct macalg fips_macs[] = {
-+	/* Encrypt-and-MAC (encrypt-and-authenticate) variants */
-+	{ "hmac-sha1",				SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 },
-+#ifdef HAVE_EVP_SHA256
-+	{ "hmac-sha2-256",			SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 0 },
-+	{ "hmac-sha2-512",			SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 0 },
-+#endif
-+
-+	/* Encrypt-then-MAC variants */
-+	{ "hmac-sha1-etm at openssh.com",		SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 1 },
-+#ifdef HAVE_EVP_SHA256
-+	{ "hmac-sha2-256-etm at openssh.com",	SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 1 },
-+	{ "hmac-sha2-512-etm at openssh.com",	SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 1 },
-+#endif
-+
-+	{ NULL,					0, 0, 0, 0, 0, 0 }
-+};
-+
- /* Returns a list of supported MACs separated by the specified char. */
- char *
- mac_alg_list(char sep)
-@@ -99,7 +119,7 @@ mac_alg_list(char sep)
- 	size_t nlen, rlen = 0;
- 	const struct macalg *m;
- 
--	for (m = macs; m->name != NULL; m++) {
-+	for (m = FIPS_mode() ? fips_macs : all_macs; m->name != NULL; m++) {
- 		if (ret != NULL)
- 			ret[rlen++] = sep;
- 		nlen = strlen(m->name);
-@@ -133,7 +153,7 @@ mac_setup(Mac *mac, char *name)
- {
- 	const struct macalg *m;
- 
--	for (m = macs; m->name != NULL; m++) {
-+	for (m = FIPS_mode() ? fips_macs : all_macs; m->name != NULL; m++) {
- 		if (strcmp(name, m->name) != 0)
- 			continue;
- 		if (mac != NULL) {
-diff --git a/myproposal.h b/myproposal.h
-index 3a0f5ae..4f35a44 100644
---- a/myproposal.h
-+++ b/myproposal.h
-@@ -88,6 +88,12 @@
- 	"diffie-hellman-group14-sha1," \
- 	"diffie-hellman-group1-sha1"
- 
-+#define KEX_DEFAULT_KEX_FIPS		\
-+	KEX_ECDH_METHODS \
-+	KEX_SHA256_METHODS \
-+	"diffie-hellman-group-exchange-sha1," \
-+	"diffie-hellman-group14-sha1"
-+
- #define	KEX_DEFAULT_PK_ALG	\
- 	HOSTKEY_ECDSA_CERT_METHODS \
- 	"ssh-ed25519-cert-v01 at openssh.com," \
-@@ -133,6 +139,22 @@
- #define	KEX_DEFAULT_COMP	"none,zlib at openssh.com,zlib"
- #define	KEX_DEFAULT_LANG	""
- 
-+#define	KEX_FIPS_ENCRYPT \
-+	"aes128-ctr,aes192-ctr,aes256-ctr," \
-+	"aes128-cbc,3des-cbc," \
-+	"aes192-cbc,aes256-cbc,rijndael-cbc at lysator.liu.se"
-+#ifdef HAVE_EVP_SHA256
-+#define	KEX_FIPS_MAC \
-+	"hmac-sha1," \
-+	"hmac-sha2-256," \
-+	"hmac-sha2-512," \
-+	"hmac-sha1-etm at openssh.com," \
-+	"hmac-sha2-256-etm at openssh.com," \
-+	"hmac-sha2-512-etm at openssh.com"
-+#else
-+#define        KEX_FIPS_MAC \
-+       "hmac-sha1"
-+#endif
- 
- static char *myproposal[PROPOSAL_MAX] = {
- 	KEX_DEFAULT_KEX,
-diff --git a/ssh-keygen.c b/ssh-keygen.c
-index 66198e6..ccf22c8 100644
---- a/ssh-keygen.c
-+++ b/ssh-keygen.c
-@@ -195,6 +195,12 @@ type_bits_valid(int type, u_int32_t *bitsp)
- 		fprintf(stderr, "key bits exceeds maximum %d\n", maxbits);
- 		exit(1);
- 	}
-+	if (FIPS_mode()) {
-+		if (type == KEY_DSA)
-+			fatal("DSA keys are not allowed in FIPS mode");
-+		if (type == KEY_ED25519)
-+			fatal("ED25519 keys are not allowed in FIPS mode");
-+	}
- 	if (type == KEY_DSA && *bitsp != 1024)
- 		fatal("DSA keys must be 1024 bits");
- 	else if (type != KEY_ECDSA && type != KEY_ED25519 && *bitsp < 768)
-@@ -746,7 +752,7 @@ do_download(struct passwd *pw)
- 	enum fp_type fptype;
- 	char *fp, *ra;
- 
--	fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
-+	fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_selection();
- 	rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
- 
- 	pkcs11_init(0);
-@@ -756,8 +762,7 @@ do_download(struct passwd *pw)
- 	for (i = 0; i < nkeys; i++) {
- 		if (print_fingerprint) {
- 			fp = key_fingerprint(keys[i], fptype, rep);
--			ra = key_fingerprint(keys[i], SSH_FP_MD5,
--			    SSH_FP_RANDOMART);
-+			ra = key_selected_fingerprint(keys[i], SSH_FP_RANDOMART);
- 			printf("%u %s %s (PKCS11 key)\n", key_size(keys[i]),
- 			    fp, key_type(keys[i]));
- 			if (log_level >= SYSLOG_LEVEL_VERBOSE)
-diff --git a/ssh.c b/ssh.c
-index 1e6cb90..ea9193f 100644
---- a/ssh.c
-+++ b/ssh.c
-@@ -73,6 +73,8 @@
- 
- #include <openssl/evp.h>
- #include <openssl/err.h>
-+#include <openssl/fips.h>
-+#include <fipscheck.h>
- #include "openbsd-compat/openssl-compat.h"
- #include "openbsd-compat/sys-queue.h"
- 
-@@ -427,6 +429,13 @@ main(int ac, char **av)
- 	sanitise_stdfd();
- 
- 	__progname = ssh_get_progname(av[0]);
-+        SSLeay_add_all_algorithms();
-+	if (access("/etc/system-fips", F_OK) == 0)
-+		if (! FIPSCHECK_verify(NULL, NULL))
-+			if (FIPS_mode())
-+				fatal("FIPS integrity verification test failed.");
-+			else
-+				logit("FIPS integrity verification test failed.");
- 
- #ifndef HAVE_SETPROCTITLE
- 	/* Prepare for later setproctitle emulation */
-@@ -504,6 +513,9 @@ main(int ac, char **av)
- 	    "ACD:E:F:I:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
- 		switch (opt) {
- 		case '1':
-+			if (FIPS_mode()) {
-+				fatal("Protocol 1 not allowed in the FIPS mode.");
-+			}
- 			options.protocol = SSH_PROTO_1;
- 			break;
- 		case '2':
-@@ -828,7 +840,6 @@ main(int ac, char **av)
- 
- 	host_arg = xstrdup(host);
- 
--	OpenSSL_add_all_algorithms();
- 	ERR_load_crypto_strings();
- 
- 	/* Initialize the command to execute on remote host. */
-@@ -973,6 +984,10 @@ main(int ac, char **av)
- 
- 	seed_rng();
- 
-+	if (FIPS_mode()) {
-+		logit("FIPS mode initialized");
-+	}
-+
- 	if (options.user == NULL)
- 		options.user = xstrdup(pw->pw_name);
- 
-@@ -1020,6 +1035,12 @@ main(int ac, char **av)
- 
- 	timeout_ms = options.connection_timeout * 1000;
- 
-+	if (FIPS_mode()) {
-+		options.protocol &= SSH_PROTO_2;
-+		if (options.protocol == 0)
-+			fatal("Protocol 2 disabled by configuration but required in the FIPS mode.");
-+	}
-+
- 	/* Open a connection to the remote host. */
- 	if (ssh_connect(host, addrs, &hostaddr, options.port,
- 	    options.address_family, options.connection_attempts,
-diff --git a/sshconnect2.c b/sshconnect2.c
-index b00658b..6a1562c 100644
---- a/sshconnect2.c
-+++ b/sshconnect2.c
-@@ -44,6 +44,8 @@
- #include <vis.h>
- #endif
- 
-+#include <openssl/fips.h>
-+
- #include "openbsd-compat/sys-queue.h"
- 
- #include "xmalloc.h"
-@@ -168,20 +170,25 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short 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 (FIPS_mode()) {
-+			logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode");
-+			options.gss_keyex = 0;
-+		} else {
-+			/* 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);
-+			}
- 		}
- 	}
- #endif
-@@ -193,6 +200,10 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
- 	if (options.ciphers != NULL) {
- 		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
- 		myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
-+	} else if (FIPS_mode()) {
-+		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
-+		myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT;
-+
- 	}
- 	myproposal[PROPOSAL_ENC_ALGS_CTOS] =
- 	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
-@@ -208,7 +219,11 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
- 	if (options.macs != NULL) {
- 		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
- 		myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
-+	} else if (FIPS_mode()) {
-+		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
-+		myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC;
- 	}
-+
- 	if (options.hostkeyalgorithms != NULL)
- 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
- 		    compat_pkalg_proposal(options.hostkeyalgorithms);
-@@ -220,9 +235,11 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
- 	}
- 	if (options.kex_algorithms != NULL)
- 		myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
-+	else if (FIPS_mode())
-+		myproposal[PROPOSAL_KEX_ALGS] = KEX_DEFAULT_KEX_FIPS;
-+
- 	myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
- 	    myproposal[PROPOSAL_KEX_ALGS]);
--
- #ifdef GSSAPI
- 	/* If we've got GSSAPI algorithms, then we also support the
- 	 * 'null' hostkey, as a last resort */
-diff --git a/sshd.c b/sshd.c
-index b561ec8..e977de3 100644
---- a/sshd.c
-+++ b/sshd.c
-@@ -75,6 +75,8 @@
- #include <openssl/dh.h>
- #include <openssl/bn.h>
- #include <openssl/rand.h>
-+#include <openssl/fips.h>
-+#include <fipscheck.h>
- #include "openbsd-compat/openssl-compat.h"
- 
- #ifdef HAVE_SECUREWARE
-@@ -1468,6 +1470,18 @@ main(int ac, char **av)
- #endif
- 	__progname = ssh_get_progname(av[0]);
- 
-+        SSLeay_add_all_algorithms();
-+	if (access("/etc/system-fips", F_OK) == 0)
-+		if (! FIPSCHECK_verify(NULL, NULL)) {
-+			openlog(__progname, LOG_PID, LOG_AUTHPRIV);
-+			if (FIPS_mode()) {
-+				syslog(LOG_CRIT, "FIPS integrity verification test failed.");
-+				cleanup_exit(255);
-+			}
-+			else
-+				syslog(LOG_INFO, "FIPS integrity verification test failed.");
-+			closelog();
-+		}
- 	/* Save argv. Duplicate so setproctitle emulation doesn't clobber it */
- 	saved_argc = ac;
- 	rexec_argc = ac;
-@@ -1619,8 +1633,6 @@ main(int ac, char **av)
- 	else
- 		closefrom(REEXEC_DEVCRYPTO_RESERVED_FD);
- 
--	OpenSSL_add_all_algorithms();
--
- 	/* If requested, redirect the logs to the specified logfile. */
- 	if (logfile != NULL) {
- 		log_redirect_stderr_to(logfile);
-@@ -1798,6 +1810,10 @@ main(int ac, char **av)
- 		debug("private host key: #%d type %d %s", i, keytype,
- 		    key_type(key ? key : pubkey));
- 	}
-+	if ((options.protocol & SSH_PROTO_1) && FIPS_mode()) {
-+		logit("Disabling protocol version 1. Not allowed in the FIPS mode.");
-+		options.protocol &= ~SSH_PROTO_1;
-+	}
- 	if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) {
- 		logit("Disabling protocol version 1. Could not load host key");
- 		options.protocol &= ~SSH_PROTO_1;
-@@ -1961,6 +1977,10 @@ main(int ac, char **av)
- 	/* Reinitialize the log (because of the fork above). */
- 	log_init(__progname, options.log_level, options.log_facility, log_stderr);
- 
-+	if (FIPS_mode()) {
-+		logit("FIPS mode initialized");
-+	}
-+
- 	/* Chdir to the root directory so that the current disk can be
- 	   unmounted if desired. */
- 	if (chdir("/") == -1)
-@@ -2530,6 +2550,9 @@ do_ssh2_kex(void)
- 	if (options.ciphers != NULL) {
- 		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
- 		myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
-+	} else if (FIPS_mode()) {
-+		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
-+		myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT;
- 	}
- 	myproposal[PROPOSAL_ENC_ALGS_CTOS] =
- 	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
-@@ -2539,6 +2562,9 @@ do_ssh2_kex(void)
- 	if (options.macs != NULL) {
- 		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
- 		myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
-+	} else if (FIPS_mode()) {
-+		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
-+		myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC;
- 	}
- 	if (options.compression == COMP_NONE) {
- 		myproposal[PROPOSAL_COMP_ALGS_CTOS] =
-@@ -2549,6 +2575,8 @@ do_ssh2_kex(void)
- 	}
- 	if (options.kex_algorithms != NULL)
- 		myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
-+	else if (FIPS_mode())
-+		myproposal[PROPOSAL_KEX_ALGS] = KEX_DEFAULT_KEX_FIPS;
- 
- 	myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
- 	    myproposal[PROPOSAL_KEX_ALGS]);
-@@ -2575,10 +2603,14 @@ do_ssh2_kex(void)
- 	if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
- 		orig = NULL;
- 
--	if (options.gss_keyex)
--		gss = ssh_gssapi_server_mechanisms();
--	else
--		gss = NULL;
-+	if (options.gss_keyex) {
-+		if (FIPS_mode()) {
-+			logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode");
-+			options.gss_keyex = 0;
-+		} else {
-+			gss = ssh_gssapi_server_mechanisms();
-+		}
-+	}
- 
- 	if (gss && orig)
- 		xasprintf(&newstr, "%s,%s", gss, orig);
diff --git a/openssh-6.6p1-force_krb.patch b/openssh-6.6p1-force_krb.patch
index a242394..6703c15 100644
--- a/openssh-6.6p1-force_krb.patch
+++ b/openssh-6.6p1-force_krb.patch
@@ -1,5 +1,5 @@
 diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
-index 42de994..60de320 100644
+index 413b845..54dd383 100644
 --- a/gss-serv-krb5.c
 +++ b/gss-serv-krb5.c
 @@ -32,7 +32,9 @@
@@ -12,12 +12,7 @@ index 42de994..60de320 100644
  
  #include "xmalloc.h"
  #include "key.h"
-@@ -40,10 +42,12 @@
- #include "auth.h"
- #include "log.h"
- #include "servconf.h"
-+#include "misc.h"
- 
+@@ -45,6 +47,7 @@
  #include "buffer.h"
  #include "ssh-gss.h"
  
@@ -25,7 +20,7 @@ index 42de994..60de320 100644
  extern ServerOptions options;
  
  #ifdef HEIMDAL
-@@ -55,6 +59,13 @@ extern ServerOptions options;
+@@ -56,6 +59,13 @@ extern ServerOptions options;
  # include <gssapi/gssapi_krb5.h>
  #endif
  
@@ -39,7 +34,7 @@ index 42de994..60de320 100644
  static krb5_context krb_context = NULL;
  
  /* Initialise the krb5 library, for the stuff that GSSAPI won't do */
-@@ -87,6 +98,7 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
+@@ -88,6 +98,7 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
  	krb5_principal princ;
  	int retval;
  	const char *errmsg;
@@ -47,7 +42,7 @@ index 42de994..60de320 100644
  
  	if (ssh_gssapi_krb5_init() == 0)
  		return 0;
-@@ -98,10 +110,22 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
+@@ -99,10 +110,22 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
  		krb5_free_error_message(krb_context, errmsg);
  		return 0;
  	}
@@ -71,7 +66,7 @@ index 42de994..60de320 100644
  	} else
  		retval = 0;
  
-@@ -109,6 +133,135 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
+@@ -110,6 +133,135 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
  	return retval;
  }
  
@@ -102,7 +97,7 @@ index 42de994..60de320 100644
 +{
 +	FILE *fp;
 +	char file[MAXPATHLEN];
-+	char line[BUFSIZ];
++	char line[BUFSIZ] = "";
 +	char kuser[65]; /* match krb5_kuserok() */
 +	struct stat st;
 +	struct passwd *pw = the_authctxt->pw;
@@ -208,10 +203,10 @@ index 42de994..60de320 100644
  /* This writes out any forwarded credentials from the structure populated
   * during userauth. Called after we have setuid to the user */
 diff --git a/session.c b/session.c
-index b5dc144..ba4589b 100644
+index 28659ec..9c94d8e 100644
 --- a/session.c
 +++ b/session.c
-@@ -806,6 +806,29 @@ do_exec(Session *s, const char *command)
+@@ -789,6 +789,29 @@ do_exec(Session *s, const char *command)
  		command = forced_command;
  		forced = "(key-option)";
  	}
@@ -257,10 +252,10 @@ index 0374c88..509109a 100644
  
  /* draft-ietf-secsh-gsskeyex-06 */
 diff --git a/sshd.8 b/sshd.8
-index 058d37a..5c4f15b 100644
+index adcaaf9..824163b 100644
 --- a/sshd.8
 +++ b/sshd.8
-@@ -327,6 +327,7 @@ Finally, the server and the client enter an authentication dialog.
+@@ -324,6 +324,7 @@ Finally, the server and the client enter an authentication dialog.
  The client tries to authenticate itself using
  host-based authentication,
  public key authentication,
diff --git a/openssh-6.6p1-gsissh.patch b/openssh-6.6p1-gsissh.patch
deleted file mode 100644
index 5bf7cc9..0000000
--- a/openssh-6.6p1-gsissh.patch
+++ /dev/null
@@ -1,3010 +0,0 @@
-diff -Nur openssh-6.6p1.orig/auth2.c openssh-6.6p1/auth2.c
---- openssh-6.6p1.orig/auth2.c	2015-01-15 20:08:13.117214971 +0100
-+++ openssh-6.6p1/auth2.c	2015-01-15 20:08:56.673616238 +0100
-@@ -49,6 +49,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_gssapi;
- #endif
- 
-+static int log_flag = 0;
-+
- Authmethod *authmethods[] = {
- 	&method_none,
- 	&method_pubkey,
-@@ -228,7 +231,33 @@
- 	user = packet_get_cstring(NULL);
- 	service = packet_get_cstring(NULL);
- 	method = packet_get_cstring(NULL);
--	debug("userauth-request for user %s service %s method %s", user, service, method);
-+
-+#ifdef GSSAPI
-+	if (user[0] == '\0') {
-+		debug("received empty username for %s", method);
-+		if (strcmp(method, "gssapi-keyex") == 0) {
-+			char *lname = NULL;
-+			PRIVSEP(ssh_gssapi_localname(&lname));
-+			if (lname && lname[0] != '\0') {
-+				free(user);
-+				user = lname;
-+				debug("set username to %s from gssapi context", user);
-+			} else {
-+				debug("failed to set username from gssapi context");
-+				packet_send_debug("failed to set username from gssapi context");
-+			}
-+		}
-+	}
-+#endif
-+
-+	debug("userauth-request for user %s service %s method %s",
-+	    user[0] ? user : "<implicit>", service, method);
-+	if (!log_flag) {
-+		logit("SSH: Server;Ltype: Authname;Remote: %s-%d;Name: %s", 
-+		      get_remote_ipaddr(), get_remote_port(),
-+		      user[0] ? user : "<implicit>");
-+		log_flag = 1;
-+	}
- 	debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
- 
- #ifdef WITH_SELINUX
-@@ -239,23 +268,48 @@
- 	if ((style = strchr(user, ':')) != NULL)
- 		*style++ = 0;
- 
--	if (authctxt->attempt++ == 0) {
--		/* setup auth context */
--		authctxt->pw = PRIVSEP(getpwnamallow(user));
-+	/* If first time or username changed or empty username,
-+	   setup/reset authentication context. */
-+	if ((authctxt->attempt++ == 0) ||
-+	    (strcmp(user, authctxt->user) != 0) ||
-+	    (strcmp(user, "") == 0)) {
-+		if (authctxt->user) {
-+			free(authctxt->user);
-+			authctxt->user = NULL;
-+		}
-+		authctxt->valid = 0;
- 		authctxt->user = xstrdup(user);
--		if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
-+		if (strcmp(service, "ssh-connection") != 0) {
-+			packet_disconnect("Unsupported service %s", service);
-+		}
-+#ifdef GSSAPI
-+		/* If we're going to set the username based on the
-+		   GSSAPI context later, then wait until then to
-+		   verify it. Just put in placeholders for now. */
-+		if ((strcmp(user, "") == 0) &&
-+		    ((strcmp(method, "gssapi") == 0) ||
-+		     (strcmp(method, "gssapi-with-mic") == 0))) {
-+			authctxt->pw = fakepw();
-+		} else {
-+#endif
-+		authctxt->pw = PRIVSEP(getpwnamallow(user));
-+		if (authctxt->pw) {
- 			authctxt->valid = 1;
- 			debug2("input_userauth_request: setting up authctxt for %s", user);
- 		} else {
- 			logit("input_userauth_request: invalid user %s", user);
- 			authctxt->pw = fakepw();
- 		}
-+#ifdef GSSAPI
-+		} /* endif for setting username based on GSSAPI context */
-+#endif
- #ifdef USE_PAM
- 		if (options.use_pam)
- 			PRIVSEP(start_pam(authctxt));
- #endif
- 		setproctitle("%s%s", authctxt->valid ? user : "unknown",
- 		    use_privsep ? " [net]" : "");
-+		if (authctxt->attempt == 1) {
- 		authctxt->service = xstrdup(service);
- 		authctxt->style = style ? xstrdup(style) : NULL;
- #ifdef WITH_SELINUX
-@@ -270,9 +324,10 @@
- 		userauth_banner();
- 		if (auth2_setup_methods_lists(authctxt) != 0)
- 			packet_disconnect("no authentication methods enabled");
--	} else if (strcmp(user, authctxt->user) != 0 ||
--	    strcmp(service, authctxt->service) != 0) {
--		packet_disconnect("Change of username or service not allowed: "
-+		}
-+	}
-+	if (strcmp(service, authctxt->service) != 0) {
-+		packet_disconnect("Change of service not allowed: "
- 		    "(%s,%s) -> (%s,%s)",
- 		    authctxt->user, authctxt->service, user, service);
- 	}
-diff -Nur openssh-6.6p1.orig/auth2-gss.c openssh-6.6p1/auth2-gss.c
---- openssh-6.6p1.orig/auth2-gss.c	2015-01-15 20:08:13.020214078 +0100
-+++ openssh-6.6p1/auth2-gss.c	2015-01-15 20:08:56.674616247 +0100
-@@ -47,6 +47,7 @@
- 
- extern ServerOptions options;
- 
-+static void ssh_gssapi_userauth_error(Gssctxt *ctxt);
- static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
- static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
- static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
-@@ -59,8 +60,8 @@
- userauth_gsskeyex(Authctxt *authctxt)
- {
- 	int authenticated = 0;
--	Buffer b;
--	gss_buffer_desc mic, gssbuf;
-+	Buffer b, b2;
-+	gss_buffer_desc mic, gssbuf, gssbuf2;
- 	u_int len;
- 
- 	mic.value = packet_get_string(&len);
-@@ -74,13 +75,27 @@
- 	gssbuf.value = buffer_ptr(&b);
- 	gssbuf.length = buffer_len(&b);
- 
-+	/* client may have used empty username to determine target
-+	   name from GSSAPI context */
-+	ssh_gssapi_buildmic(&b2, "", authctxt->service, "gssapi-keyex");
-+
-+	gssbuf2.value = buffer_ptr(&b2);
-+	gssbuf2.length = buffer_len(&b2);
-+
- 	/* 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));
-+						   &gssbuf, &mic))) ||
-+	    !GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, 
-+						   &gssbuf2, &mic)))) {
-+		if (authctxt->valid && authctxt->user && authctxt->user[0]) {
-+			authenticated =
-+			    PRIVSEP(ssh_gssapi_userok(authctxt->user,
-+				    authctxt->pw, 1 /* gssapi-keyex */));
-+		}
-+	}
- 	
- 	buffer_free(&b);
-+	buffer_free(&b2);
- 	free(mic.value);
- 
- 	return (authenticated);
-@@ -101,7 +116,10 @@
- 	u_int len;
- 	u_char *doid = NULL;
- 
--	if (!authctxt->valid || authctxt->user == NULL)
-+	/* authctxt->valid may be 0 if we haven't yet determined
-+	   username from gssapi context. */
-+
-+	if (authctxt->user == NULL)
- 		return (0);
- 
- 	mechs = packet_get_int();
-@@ -166,7 +184,7 @@
- 	Gssctxt *gssctxt;
- 	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
- 	gss_buffer_desc recv_tok;
--	OM_uint32 maj_status, min_status, flags;
-+	OM_uint32 maj_status, min_status, flags = 0;
- 	u_int len;
- 
- 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
-@@ -184,6 +202,7 @@
- 	free(recv_tok.value);
- 
- 	if (GSS_ERROR(maj_status)) {
-+		ssh_gssapi_userauth_error(gssctxt);
- 		if (send_tok.length != 0) {
- 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
- 			packet_put_string(send_tok.value, send_tok.length);
-@@ -247,6 +266,32 @@
- 	gss_release_buffer(&maj_status, &send_tok);
- }
- 
-+static void
-+gssapi_set_username(Authctxt *authctxt)
-+{
-+	char *lname = NULL;
-+
-+	if ((authctxt->user == NULL) || (authctxt->user[0] == '\0')) {
-+		PRIVSEP(ssh_gssapi_localname(&lname));
-+		if (lname && lname[0] != '\0') {
-+			if (authctxt->user) free(authctxt->user);
-+			authctxt->user = lname;
-+			debug("set username to %s from gssapi context", lname);
-+			authctxt->pw = PRIVSEP(getpwnamallow(authctxt->user));
-+			if (authctxt->pw) {
-+				authctxt->valid = 1;
-+#ifdef USE_PAM
-+				if (options.use_pam)
-+					PRIVSEP(start_pam(authctxt));
-+#endif
-+			}
-+		} else {
-+			debug("failed to set username from gssapi context");
-+			packet_send_debug("failed to set username from gssapi context");
-+		}
-+	}
-+}
-+
- /*
-  * This is called when the client thinks we've completed authentication.
-  * It should only be enabled in the dispatch handler by the function above,
-@@ -262,6 +307,8 @@
- 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
- 		fatal("No authentication or GSSAPI context");
- 
-+	gssapi_set_username(authctxt);
-+
- 	/*
- 	 * We don't need to check the status, because we're only enabled in
- 	 * the dispatcher once the exchange is complete
-@@ -269,8 +316,13 @@
- 
- 	packet_check_eom();
- 
--	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
--	    authctxt->pw));
-+	/* user should be set if valid but we double-check here */
-+	if (authctxt->valid && authctxt->user && authctxt->user[0]) {
-+		authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
-+					authctxt->pw, 0 /* !gssapi-keyex */));
-+	} else {
-+		authenticated = 0;
-+	}
- 
- 	authctxt->postponed = 0;
- 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
-@@ -311,9 +363,16 @@
- 	gssbuf.value = buffer_ptr(&b);
- 	gssbuf.length = buffer_len(&b);
- 
-+	gssapi_set_username(authctxt);
-+
- 	if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
--		authenticated = 
--		    PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
-+		if (authctxt->valid && authctxt->user && authctxt->user[0]) {
-+			authenticated =
-+			    PRIVSEP(ssh_gssapi_userok(authctxt->user,
-+				    authctxt->pw, 0 /* !gssapi-keyex */));
-+		} else {
-+			authenticated = 0;
-+		}
- 	else
- 		logit("GSSAPI MIC check failed");
- 
-@@ -330,6 +389,23 @@
- 	userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
- }
- 
-+static void ssh_gssapi_userauth_error(Gssctxt *ctxt) {
-+	char *errstr;
-+	OM_uint32 maj,min;
-+	
-+	errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
-+	if (errstr) {
-+		packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR);
-+		packet_put_int(maj);
-+		packet_put_int(min);
-+		packet_put_cstring(errstr);
-+		packet_put_cstring("");
-+		packet_send();
-+		packet_write_wait();
-+		free(errstr);
-+	}
-+}
-+
- Authmethod method_gsskeyex = {
- 	"gssapi-keyex",
- 	userauth_gsskeyex,
-diff -Nur openssh-6.6p1.orig/auth.c openssh-6.6p1/auth.c
---- openssh-6.6p1.orig/auth.c	2015-01-15 20:08:13.116214962 +0100
-+++ openssh-6.6p1/auth.c	2015-01-15 20:08:56.675616256 +0100
-@@ -74,6 +74,9 @@
- #include "krl.h"
- #include "compat.h"
- 
-+#include "version.h"
-+#include "ssh-globus-usage.h"
-+
- /* import */
- extern ServerOptions options;
- extern int use_privsep;
-@@ -298,7 +301,8 @@
- 	    method,
- 	    submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
- 	    authctxt->valid ? "" : "invalid user ",
--	    authctxt->user,
-+	    (authctxt->user && authctxt->user[0]) ?
-+		authctxt->user : "unknown",
- 	    get_remote_ipaddr(),
- 	    get_remote_port(),
- 	    compat20 ? "ssh2" : "ssh1",
-@@ -324,6 +328,23 @@
- 	if (authenticated == 0 && !authctxt->postponed)
- 		audit_event(audit_classify_auth(method));
- #endif
-+	if (authenticated) {
-+		char *userdn = NULL;
-+		char *mech_name = NULL;
-+#ifdef GSSAPI
-+		ssh_gssapi_get_client_info(&userdn, &mech_name);
-+#endif
-+		debug("REPORTING (%s) (%s) (%s) (%s) (%s) (%s) (%s)",
-+			 SSH_RELEASE, SSLeay_version(SSLEAY_VERSION),
-+			 method, mech_name?mech_name:"NULL", get_remote_ipaddr(),
-+			 (authctxt->user && authctxt->user[0])?
-+				authctxt->user : "unknown",
-+			userdn?userdn:"NULL");
-+		ssh_globus_send_usage_metrics(SSH_RELEASE,
-+					SSLeay_version(SSLEAY_VERSION),
-+					method, mech_name, get_remote_ipaddr(),
-+					authctxt->user, userdn);
-+	}
- }
- 
- /*
-@@ -604,6 +625,10 @@
- #endif
- 
- 	pw = getpwnam(user);
-+#ifdef USE_PAM
-+	if (options.use_pam && options.permit_pam_user_change && pw == NULL)
-+		pw = sshpam_getpw(user);
-+#endif
- 
- #if defined(_AIX) && defined(HAVE_SETAUTHDB)
- 	aix_restoreauthdb();
-@@ -623,7 +648,8 @@
- #endif
- 	if (pw == NULL) {
- 		logit("Invalid user %.100s from %.100s",
--		    user, get_remote_ipaddr());
-+		      (user && user[0]) ? user : "unknown",
-+		      get_remote_ipaddr());
- #ifdef CUSTOM_FAILED_LOGIN
- 		record_failed_login(user,
- 		    get_canonical_hostname(options.use_dns), "ssh");
-diff -Nur openssh-6.6p1.orig/auth-pam.c openssh-6.6p1/auth-pam.c
---- openssh-6.6p1.orig/auth-pam.c	2015-01-15 20:08:13.146215238 +0100
-+++ openssh-6.6p1/auth-pam.c	2015-01-15 20:08:56.676616265 +0100
-@@ -122,6 +122,10 @@
-  */
- typedef pthread_t sp_pthread_t;
- #else
-+#define pthread_create openssh_pthread_create
-+#define pthread_exit openssh_pthread_exit
-+#define pthread_cancel openssh_pthread_cancel
-+#define pthread_join openssh_pthread_join
- typedef pid_t sp_pthread_t;
- #endif
- 
-@@ -277,6 +281,55 @@
- # define pam_chauthtok(a,b)	(sshpam_chauthtok_ruid((a), (b)))
- #endif
- 
-+struct passwd *
-+sshpam_getpw(const char *user)
-+{
-+	struct passwd *pw;
-+
-+	if ((pw = getpwnam(user)) != NULL)
-+		return(pw);
-+
-+	debug("PAM: faking passwd struct for user '%.100s'", user);
-+	if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL)
-+		return NULL;
-+	pw->pw_name = xstrdup(user);	/* XXX leak */
-+	pw->pw_shell = "/bin/true";
-+	pw->pw_gecos = "sshd fake PAM user";
-+	return (pw);
-+}
-+
-+void
-+sshpam_check_userchanged(void)
-+{
-+	int sshpam_err;
-+	struct passwd *pw;
-+	const char *user;
-+
-+	debug("sshpam_check_userchanged");
-+	sshpam_err = pam_get_item(sshpam_handle, PAM_USER, &user);
-+	if (sshpam_err != PAM_SUCCESS)
-+		fatal("PAM: could not get PAM_USER: %s",
-+		    pam_strerror(sshpam_handle, sshpam_err));
-+	debug("sshpam_check_userchanged: user was '%.100s'",
-+	      sshpam_authctxt->pw->pw_name);
-+	if (strcmp(user, sshpam_authctxt->pw->pw_name) != 0) {
-+		debug("PAM: user mapped from '%.100s' to '%.100s'",
-+		    sshpam_authctxt->pw->pw_name, user);
-+		if ((pw = getpwnam(user)) == NULL)
-+			fatal("PAM: could not get passwd entry for user "
-+			    "'%.100s' provided by PAM_USER", user);
-+		pwfree(sshpam_authctxt->pw);
-+		sshpam_authctxt->pw = pwcopy(pw);
-+		sshpam_authctxt->valid = allowed_user(pw);
-+		free(sshpam_authctxt->user);
-+		sshpam_authctxt->user = xstrdup(user);
-+		debug("PAM: user '%.100s' now %svalid", user,
-+		    sshpam_authctxt->valid ? "" : "in");
-+	}
-+	debug("sshpam_check_userchanged: user is '%.100s'",
-+	      sshpam_authctxt->pw->pw_name);
-+}
-+
- void
- sshpam_password_change_required(int reqd)
- {
-@@ -299,7 +352,7 @@
- static void
- import_environments(Buffer *b)
- {
--	char *env;
-+	char *env, *user;
- 	u_int i, num_env;
- 	int err;
- 
-@@ -309,6 +362,17 @@
- 	/* Import variables set by do_pam_account */
- 	sshpam_account_status = buffer_get_int(b);
- 	sshpam_password_change_required(buffer_get_int(b));
-+	if (options.permit_pam_user_change) {
-+		user = buffer_get_string(b, NULL);
-+		debug("PAM: user is '%.100s'",
-+		      sshpam_authctxt->pw->pw_name);
-+		debug("PAM: got username '%.100s' from thread", user);
-+		if ((err = pam_set_item(sshpam_handle, PAM_USER, user)) != PAM_SUCCESS)
-+			fatal("PAM: failed to set PAM_USER: %s",
-+			      pam_strerror(sshpam_handle, err));
-+		pwfree(sshpam_authctxt->pw);
-+		sshpam_authctxt->pw = pwcopy(sshpam_getpw(user));
-+	}
- 
- 	/* Import environment from subprocess */
- 	num_env = buffer_get_int(b);
-@@ -475,6 +539,13 @@
- 	if (sshpam_err != PAM_SUCCESS)
- 		goto auth_fail;
- 
-+	if (options.permit_pam_user_change) {
-+	debug("sshpam_thread: user is '%.100s'",
-+	      sshpam_authctxt->pw->pw_name);
-+		sshpam_check_userchanged();
-+	debug("sshpam_thread: user is '%.100s'",
-+	      sshpam_authctxt->pw->pw_name);
-+	}
- 	if (compat20) {
- 		if (!do_pam_account()) {
- 			sshpam_err = PAM_ACCT_EXPIRED;
-@@ -495,6 +566,11 @@
- 	/* Export variables set by do_pam_account */
- 	buffer_put_int(&buffer, sshpam_account_status);
- 	buffer_put_int(&buffer, sshpam_authctxt->force_pwchange);
-+	if (options.permit_pam_user_change) {
-+		debug("sshpam_thread: user is '%.100s'",
-+		      sshpam_authctxt->pw->pw_name);
-+		buffer_put_cstring(&buffer, sshpam_authctxt->pw->pw_name);
-+	}
- 
- 	/* Export any environment strings set in child */
- 	for(i = 0; environ[i] != NULL; i++)
-@@ -912,6 +988,18 @@
- 	debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
- 	    pam_strerror(sshpam_handle, sshpam_err));
- 
-+	if (options.permit_pam_user_change) {
-+		debug("do_pam_account: user is '%.100s'",
-+		      sshpam_authctxt->pw->pw_name);
-+		sshpam_check_userchanged();
-+		debug("do_pam_account: user is '%.100s'",
-+		      sshpam_authctxt->pw->pw_name);
-+		if (getpwnam(sshpam_authctxt->pw->pw_name) == NULL)
-+		    fatal("PAM: completed authentication but PAM account invalid");
-+		debug("do_pam_account: user is '%.100s'",
-+		      sshpam_authctxt->pw->pw_name);
-+	}
-+
- 	if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) {
- 		sshpam_account_status = 0;
- 		return (sshpam_account_status);
-@@ -1209,6 +1297,9 @@
- 		    pam_strerror(sshpam_handle, sshpam_err));
- 
- 	sshpam_err = pam_authenticate(sshpam_handle, flags);
-+	if (options.permit_pam_user_change) {
-+		sshpam_check_userchanged();
-+	}
- 	sshpam_password = NULL;
- 	if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
- 		debug("PAM: password authentication accepted for %.100s",
-diff -Nur openssh-6.6p1.orig/auth-pam.h openssh-6.6p1/auth-pam.h
---- openssh-6.6p1.orig/auth-pam.h	2015-01-15 20:08:12.937213313 +0100
-+++ openssh-6.6p1/auth-pam.h	2015-01-15 20:08:56.677616275 +0100
-@@ -46,5 +46,6 @@
- void sshpam_cleanup(void);
- int sshpam_auth_passwd(Authctxt *, const char *);
- int is_pam_session_open(void);
-+struct passwd *sshpam_getpw(const char *);
- 
- #endif /* USE_PAM */
-diff -Nur openssh-6.6p1.orig/canohost.c openssh-6.6p1/canohost.c
---- openssh-6.6p1.orig/canohost.c	2015-01-15 20:08:13.072214556 +0100
-+++ openssh-6.6p1/canohost.c	2015-01-15 20:08:56.678616284 +0100
-@@ -16,6 +16,7 @@
- 
- #include <sys/types.h>
- #include <sys/socket.h>
-+#include <sys/param.h>          /* for MAXHOSTNAMELEN */
- 
- #include <netinet/in.h>
- #include <arpa/inet.h>
-@@ -453,3 +454,33 @@
- {
- 	return get_port(1);
- }
-+
-+void
-+resolve_localhost(char **host)
-+{
-+	struct hostent *hostinfo;
-+
-+	hostinfo = gethostbyname(*host);
-+	if (hostinfo == NULL || hostinfo->h_name == NULL) {
-+		debug("gethostbyname(%s) failed", *host);
-+		return;
-+	}
-+	if (hostinfo->h_addrtype == AF_INET) {
-+		struct in_addr addr;
-+		addr = *(struct in_addr *)(hostinfo->h_addr);
-+		if (ntohl(addr.s_addr) == INADDR_LOOPBACK) {
-+			char buf[MAXHOSTNAMELEN];
-+			if (gethostname(buf, sizeof(buf)) < 0) {
-+				debug("gethostname() failed");
-+				return;
-+			}
-+			hostinfo = gethostbyname(buf);
-+			free(*host);
-+			if (hostinfo == NULL || hostinfo->h_name == NULL) {
-+				*host = xstrdup(buf);
-+			} else {
-+				*host = xstrdup(hostinfo->h_name);
-+			}
-+		}
-+	}
-+}
-diff -Nur openssh-6.6p1.orig/canohost.h openssh-6.6p1/canohost.h
---- openssh-6.6p1.orig/canohost.h	2015-01-15 20:08:13.073214566 +0100
-+++ openssh-6.6p1/canohost.h	2015-01-15 20:08:56.679616293 +0100
-@@ -27,4 +27,6 @@
- int		 get_sock_port(int, int);
- void		 clear_cached_addr(void);
- 
-+void		 resolve_localhost(char **host);
-+
- void		 ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *);
-diff -Nur openssh-6.6p1.orig/configure.ac openssh-6.6p1/configure.ac
---- openssh-6.6p1.orig/configure.ac	2015-01-15 20:08:13.022214096 +0100
-+++ openssh-6.6p1/configure.ac	2015-01-15 20:08:56.681616311 +0100
-@@ -4133,6 +4133,14 @@
- 			AC_CHECK_HEADER([gssapi_krb5.h], ,
- 					[ CPPFLAGS="$oldCPP" ])
- 
-+			# If we're using some other GSSAPI
-+			if test -n "$GSSAPI" ; then
-+				AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Kerberos GSI.])
-+			fi
-+
-+			if test -z "$GSSAPI"; then
-+				GSSAPI="KRB5";
-+			fi
- 		fi
- 		if test ! -z "$need_dash_r" ; then
- 			LDFLAGS="$LDFLAGS -R${KRB5ROOT}/lib"
-@@ -4172,6 +4180,50 @@
- AC_SUBST([GSSLIBS])
- AC_SUBST([K5LIBS])
- 
-+# Check whether the user wants GSI (Globus) support
-+gsi="no"
-+AC_ARG_WITH(gsi,
-+	[  --with-gsi              Enable Globus GSI authentication support],
-+	[
-+		gsi="$withval"
-+	]
-+)
-+
-+if test "x$gsi" != "xno" ; then
-+	# Globus GSSAPI configuration
-+	AC_MSG_CHECKING(for Globus GSI)
-+	AC_DEFINE(GSI, 1, [Define if you want GSI/Globus authentication support.])
-+
-+	if test -n "$GSSAPI" ; then
-+		AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Globus GSI.])
-+	fi
-+
-+	if test -z "$GSSAPI" ; then	
-+		GSSAPI="GSI"
-+	fi
-+
-+	LIBS="$LIBS `pkg-config --libs globus-gss-assist globus-gssapi-gsi globus-common`"
-+	CPPFLAGS="$CPPFLAGS `pkg-config --cflags globus-gss-assist globus-gssapi-gsi globus-common`"
-+
-+	AC_DEFINE(GSSAPI)
-+	AC_DEFINE(HAVE_GSSAPI_H)
-+
-+	AC_CHECK_FUNCS(globus_gss_assist_map_and_authorize)
-+
-+	dnl
-+	dnl Check for globus_usage_stats_send
-+	dnl
-+	AC_SEARCH_LIBS(globus_usage_stats_send,
-+	               globus_usage,
-+	               AC_DEFINE([HAVE_GLOBUS_USAGE], 1, [Have Globus Usage]))
-+	dnl
-+	dnl Check for globus_usage_stats_send_array
-+	dnl
-+	AC_SEARCH_LIBS(globus_usage_stats_send_array,
-+		       globus_usage,
-+	               AC_DEFINE([HAVE_GLOBUS_USAGE_SEND_ARRAY], 1, [Have Globus Usage send_array]))
-+fi
-+
- # Looking for programs, paths and files
- 
- PRIVSEP_PATH=/var/empty
-diff -Nur openssh-6.6p1.orig/gss-genr.c openssh-6.6p1/gss-genr.c
---- openssh-6.6p1.orig/gss-genr.c	2015-01-15 20:08:13.023214105 +0100
-+++ openssh-6.6p1/gss-genr.c	2015-01-15 20:08:56.681616311 +0100
-@@ -38,6 +38,7 @@
- #include "xmalloc.h"
- #include "buffer.h"
- #include "log.h"
-+#include "canohost.h"
- #include "ssh2.h"
- #include "cipher.h"
- #include "key.h"
-@@ -367,9 +368,18 @@
- ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
- {
- 	gss_buffer_desc gssbuf;
-+	char *xhost;
- 	char *val;
- 
--	xasprintf(&val, "host@%s", host);
-+	/* Make a copy of the host name, in case it was returned by a
-+	 * previous call to gethostbyname(). */	
-+	xhost = xstrdup(host);
-+
-+	/* Make sure we have the FQDN. Some GSSAPI implementations don't do
-+	 * this for us themselves */
-+	resolve_localhost(&xhost);
-+	
-+	xasprintf(&val, "host@%s", xhost);
- 	gssbuf.value = val;
- 	gssbuf.length = strlen(gssbuf.value);
- 
-@@ -377,6 +387,7 @@
- 	    &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name)))
- 		ssh_gssapi_error(ctx);
- 
-+	free(xhost);
- 	free(gssbuf.value);
- 	return (ctx->major);
- }
-diff -Nur openssh-6.6p1.orig/gss-serv.c openssh-6.6p1/gss-serv.c
---- openssh-6.6p1.orig/gss-serv.c	2015-01-15 20:08:13.068214520 +0100
-+++ openssh-6.6p1/gss-serv.c	2015-01-15 20:08:56.682616321 +0100
-@@ -48,14 +48,17 @@
- #include "servconf.h"
- #include "uidswap.h"
- 
-+#include "xmalloc.h"
- #include "ssh-gss.h"
- #include "monitor_wrap.h"
- 
- extern ServerOptions options;
-+extern Authctxt *the_authctxt;
- 
- static ssh_gssapi_client gssapi_client =
-     { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
--    GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME,  NULL, {NULL, NULL, NULL}, 0, 0};
-+      GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL},
-+      GSS_C_NO_CONTEXT, 0, 0};
- 
- ssh_gssapi_mech gssapi_null_mech =
-     { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
-@@ -63,14 +66,24 @@
- #ifdef KRB5
- extern ssh_gssapi_mech gssapi_kerberos_mech;
- #endif
-+#ifdef GSI
-+extern ssh_gssapi_mech gssapi_gsi_mech;
-+#endif
- 
- ssh_gssapi_mech* supported_mechs[]= {
- #ifdef KRB5
- 	&gssapi_kerberos_mech,
- #endif
-+#ifdef GSI
-+	&gssapi_gsi_mech,
-+#endif
- 	&gssapi_null_mech,
- };
- 
-+#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
-+static int limited = 0;
-+#endif
-+
- /*
-  * ssh_gssapi_supported_oids() can cause sandbox violations, so prepare the
-  * list of supported mechanisms before privsep is set up.
-@@ -231,6 +244,10 @@
- 	    (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) {
- 		if (ssh_gssapi_getclient(ctx, &gssapi_client))
- 			fatal("Couldn't convert client name");
-+#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
-+		if (flags && (*flags & GSS_C_GLOBUS_LIMITED_PROXY_FLAG))
-+			limited=1;
-+#endif
- 	}
- 
- 	return (status);
-@@ -250,6 +267,17 @@
- 
- 	tok = ename->value;
- 
-+#ifdef GSI /* GSI gss_export_name() is broken. */
-+	if ((ctx->oid->length == gssapi_gsi_mech.oid.length) &&
-+	    (memcmp(ctx->oid->elements, gssapi_gsi_mech.oid.elements,
-+		    gssapi_gsi_mech.oid.length) == 0)) {
-+		name->length = ename->length;
-+		name->value = xmalloc(ename->length+1);
-+		memcpy(name->value, ename->value, ename->length);
-+		return GSS_S_COMPLETE;
-+	}
-+#endif
-+
- 	/*
- 	 * Check that ename is long enough for all of the fixed length
- 	 * header, and that the initial ID bytes are correct
-@@ -317,8 +345,11 @@
- 			return GSS_S_COMPLETE;
- 		}
- 
--		if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, 
--		    ctx->client_creds, ctx->oid, &new_name, 
-+		/* Call gss_inquire_cred rather than gss_inquire_cred_by_mech
-+		   because GSI doesn't support the latter. -jbasney */
-+
-+		if ((ctx->major = gss_inquire_cred(&ctx->minor, 
-+		    ctx->client_creds, &new_name, 
- 		    NULL, NULL, NULL))) {
- 			ssh_gssapi_error(ctx);
- 			return (ctx->major);
-@@ -361,9 +392,12 @@
- 	if (client->mech == NULL)
- 		return GSS_S_FAILURE;
- 
-+	/* Call gss_inquire_cred rather than gss_inquire_cred_by_mech
-+	   because GSI doesn't support the latter. -jbasney */
-+
- 	if (ctx->client_creds &&
--	    (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
--	     ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
-+	    (ctx->major = gss_inquire_cred(&ctx->minor,
-+	     ctx->client_creds, &client->name, NULL, NULL, NULL))) {
- 		ssh_gssapi_error(ctx);
- 		return (ctx->major);
- 	}
-@@ -390,6 +424,10 @@
- 	/* 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;
-+
-+	/* needed for globus_gss_assist_map_and_authorize() */
-+	client->context = ctx->context;
-+
- 	return (ctx->major);
- }
- 
-@@ -397,6 +435,7 @@
- void
- ssh_gssapi_cleanup_creds(void)
- {
-+#ifdef KRB5
- 	krb5_ccache ccache = NULL;
- 	krb5_error_code problem;
- 
-@@ -412,6 +451,14 @@
- 			gssapi_client.store.data = NULL;
- 		}
- 	}
-+#else
-+	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);
-+	}
-+#endif
- }
- 
- /* As user */
-@@ -419,6 +466,11 @@
- ssh_gssapi_storecreds(void)
- {
- 	if (gssapi_client.mech && gssapi_client.mech->storecreds) {
-+		if (options.gss_creds_path) {
-+			gssapi_client.store.filename =
-+				expand_authorized_keys(options.gss_creds_path,
-+						       the_authctxt->pw);
-+		}
- 		(*gssapi_client.mech->storecreds)(&gssapi_client);
- 	} else
- 		debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
-@@ -442,8 +494,9 @@
- }
- 
- /* Privileged */
-+/* gssapi_keyex arg added for Globus usage */
- int
--ssh_gssapi_userok(char *user, struct passwd *pw)
-+ssh_gssapi_userok(char *user, struct passwd *pw, int gssapi_keyex)
- {
- 	OM_uint32 lmin;
- 
-@@ -452,6 +505,12 @@
- 		debug("No suitable client data");
- 		return 0;
- 	}
-+#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
-+	if (limited && options.gsi_allow_limited_proxy != 1) {
-+		debug("limited proxy not acceptable for remote login");
-+		return 0;
-+	}
-+#endif
- 	if (gssapi_client.mech && gssapi_client.mech->userok)
- 		if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
- 			gssapi_client.used = 1;
-@@ -471,6 +530,24 @@
- 	return (0);
- }
- 
-+/* Priviledged */
-+int
-+ssh_gssapi_localname(char **user)
-+{
-+    	*user = NULL;
-+	if (gssapi_client.displayname.length == 0 || 
-+	    gssapi_client.displayname.value == NULL) {
-+		debug("No suitable client data");
-+		return(0);
-+	}
-+	if (gssapi_client.mech && gssapi_client.mech->localname) {
-+		return((*gssapi_client.mech->localname)(&gssapi_client,user));
-+	} else {
-+		debug("Unknown client authentication type");
-+	}
-+	return(0);
-+}
-+
- /* These bits are only used for rekeying. The unpriviledged child is running 
-  * as the user, the monitor is root.
-  *
-@@ -497,6 +574,7 @@
- 	pam_handle_t *pamh = NULL;
- 	struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
- 	char *envstr;
-+	char **p; char **pw;
- #endif
- 
- 	if (gssapi_client.store.filename == NULL && 
-@@ -526,6 +604,18 @@
- 	if (ret)
- 		return;
- 
-+	/* Put ssh pam stack env variables in this new pam stack env 
-+	 * Using pam-pkinit, KRB5CCNAME is set during do_pam_session
-+	 * this addition enables pam-pkinit to access KRB5CCNAME if used 
-+	 * in sshd-rekey stack too
-+	 */
-+	pw = p = fetch_pam_environment();
-+	while ( *pw != NULL ) {
-+	        pam_putenv(pamh, *pw);
-+		pw++;
-+	}
-+	free_pam_environment(p);
-+
- 	xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, 
- 	    gssapi_client.store.envval);
- 
-@@ -557,4 +647,13 @@
- 	return ok;
- }
- 
-+/* added for Globus usage */
-+void
-+ssh_gssapi_get_client_info(char **userdn, char **mech) {
-+	*userdn = gssapi_client.displayname.value;
-+
-+	if (gssapi_client.mech)
-+		*mech = gssapi_client.mech->name;
-+}
-+
- #endif
-diff -Nur openssh-6.6p1.orig/gss-serv-gsi.c openssh-6.6p1/gss-serv-gsi.c
---- openssh-6.6p1.orig/gss-serv-gsi.c	1970-01-01 01:00:00.000000000 +0100
-+++ openssh-6.6p1/gss-serv-gsi.c	2015-01-15 20:08:56.682616321 +0100
-@@ -0,0 +1,238 @@
-+/*
-+ * Copyright (c) 2001-2003 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
-+#ifdef GSI
-+
-+#include <sys/types.h>
-+
-+#include <stdarg.h>
-+#include <string.h>
-+
-+#include "xmalloc.h"
-+#include "key.h"
-+#include "hostfile.h"
-+#include "auth.h"
-+#include "log.h"
-+#include "servconf.h"
-+
-+#include "buffer.h"
-+#include "ssh-gss.h"
-+
-+extern ServerOptions options;
-+
-+#include <globus_gss_assist.h>
-+
-+static int ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name);
-+static int ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user);
-+static void ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client);
-+static int ssh_gssapi_gsi_updatecreds(ssh_gssapi_ccache *store,
-+				       ssh_gssapi_client *client);
-+
-+ssh_gssapi_mech gssapi_gsi_mech = {
-+	"dZuIebMjgUqaxvbF7hDbAw==",
-+	"GSI",
-+	{9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"},
-+	NULL,
-+	&ssh_gssapi_gsi_userok,
-+	&ssh_gssapi_gsi_localname,
-+	&ssh_gssapi_gsi_storecreds,
-+	&ssh_gssapi_gsi_updatecreds
-+};
-+
-+/*
-+ * Check if this user is OK to login under GSI. User has been authenticated
-+ * as identity in global 'client_name.value' and is trying to log in as passed
-+ * username in 'name'.
-+ *
-+ * Returns non-zero if user is authorized, 0 otherwise.
-+ */
-+static int
-+ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name)
-+{
-+    int authorized = 0;
-+    globus_result_t res;
-+#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
-+    char lname[256] = "";
-+#endif
-+    
-+#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
-+    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
-+	return 0;
-+    }
-+#endif
-+
-+/* use new globus_gss_assist_map_and_authorize() interface if available */
-+#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
-+    debug("calling globus_gss_assist_map_and_authorize()");
-+    if (GLOBUS_SUCCESS !=
-+        (res = globus_gss_assist_map_and_authorize(client->context, "ssh",
-+                                                   name, lname, 256))) {
-+        debug("%s", globus_error_print_chain(globus_error_get(res)));
-+    } else if (lname[0] && strcmp(name, lname) != 0) {
-+        debug("GSI user maps to %s, not %s", lname, name);
-+    } else {
-+        authorized = 1;
-+    }
-+#else
-+    debug("calling globus_gss_assist_userok()");
-+    if (GLOBUS_SUCCESS !=
-+        (res = (globus_gss_assist_userok(client->displayname.value,
-+                                         name)))) {
-+        debug("%s", globus_error_print_chain(globus_error_get(res)));
-+    } else {
-+        authorized = 1;
-+    }
-+#endif
-+    
-+    logit("GSI user %s is%s authorized as target user %s",
-+	(char *) client->displayname.value, (authorized ? "" : " not"), name);
-+    
-+    return authorized;
-+}
-+
-+/*
-+ * Return the local username associated with the GSI credentials.
-+ */
-+int
-+ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user)
-+{
-+    globus_result_t res;
-+#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
-+    char lname[256] = "";
-+#endif
-+
-+#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
-+    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
-+	return 0;
-+    }
-+#endif
-+
-+/* use new globus_gss_assist_map_and_authorize() interface if available */
-+#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
-+    debug("calling globus_gss_assist_map_and_authorize()");
-+    if (GLOBUS_SUCCESS !=
-+        (res = globus_gss_assist_map_and_authorize(client->context, "ssh",
-+                                                   NULL, lname, 256))) {
-+        debug("%s", globus_error_print_chain(globus_error_get(res)));
-+        logit("failed to map GSI user %s", (char *)client->displayname.value);
-+        return 0;
-+    }
-+    *user = strdup(lname);
-+#else
-+    debug("calling globus_gss_assist_gridmap()");
-+    if (GLOBUS_SUCCESS !=
-+        (res = globus_gss_assist_gridmap(client->displayname.value, user))) {
-+        debug("%s", globus_error_print_chain(globus_error_get(res)));
-+        logit("failed to map GSI user %s", (char *)client->displayname.value);
-+        return 0;
-+    }
-+#endif
-+
-+    logit("GSI user %s mapped to target user %s",
-+          (char *) client->displayname.value, *user);
-+
-+    return 1;
-+}
-+
-+/*
-+ * Export GSI credentials to disk.
-+ */
-+static void
-+ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client)
-+{
-+	OM_uint32	major_status;
-+	OM_uint32	minor_status;
-+	gss_buffer_desc	export_cred = GSS_C_EMPTY_BUFFER;
-+	char *		p;
-+	
-+	if (!client || !client->creds) {
-+	    return;
-+	}
-+
-+	major_status = gss_export_cred(&minor_status,
-+				       client->creds,
-+				       GSS_C_NO_OID,
-+				       1,
-+				       &export_cred);
-+	if (GSS_ERROR(major_status) && major_status != GSS_S_UNAVAILABLE) {
-+	    Gssctxt *ctx;
-+	    ssh_gssapi_build_ctx(&ctx);
-+	    ctx->major = major_status;
-+	    ctx->minor = minor_status;
-+	    ssh_gssapi_set_oid(ctx, &gssapi_gsi_mech.oid);
-+	    ssh_gssapi_error(ctx);
-+	    ssh_gssapi_delete_ctx(&ctx);
-+	    return;
-+	}
-+	
-+	p = strchr((char *) export_cred.value, '=');
-+	if (p == NULL) {
-+	    logit("Failed to parse exported credentials string '%.100s'",
-+		(char *)export_cred.value);
-+	    gss_release_buffer(&minor_status, &export_cred);
-+	    return;
-+	}
-+	*p++ = '\0';
-+	if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0) {
-+	    client->store.envvar = strdup("X509_USER_PROXY");
-+	} else {
-+	    client->store.envvar = strdup((char *)export_cred.value);
-+	}
-+	if (access(p, R_OK) == 0) {
-+        if (client->store.filename) {
-+            if (rename(p, client->store.filename) < 0) {
-+                logit("Failed to rename %s to %s: %s", p,
-+                      client->store.filename, strerror(errno));
-+                free(client->store.filename);
-+                client->store.filename = strdup(p);
-+            } else {
-+                p = client->store.filename;
-+            }
-+        } else {
-+            client->store.filename = strdup(p);
-+        }
-+	}
-+	client->store.envval = strdup(p);
-+#ifdef USE_PAM
-+	if (options.use_pam)
-+	    do_pam_putenv(client->store.envvar, client->store.envval);
-+#endif
-+	gss_release_buffer(&minor_status, &export_cred);
-+}
-+
-+/*
-+ * Export updated GSI credentials to disk.
-+ */
-+static int
-+ssh_gssapi_gsi_updatecreds(ssh_gssapi_ccache *store,ssh_gssapi_client *client)
-+{
-+	ssh_gssapi_gsi_storecreds(client);
-+	return 1;
-+}
-+
-+#endif /* GSI */
-+#endif /* GSSAPI */
-diff -Nur openssh-6.6p1.orig/gss-serv-krb5.c openssh-6.6p1/gss-serv-krb5.c
---- openssh-6.6p1.orig/gss-serv-krb5.c	2015-01-15 20:08:13.108214888 +0100
-+++ openssh-6.6p1/gss-serv-krb5.c	2015-01-15 20:08:56.683616330 +0100
-@@ -359,6 +359,34 @@
- 	return found_principal;
- }
-  
-+/* Retrieve the local username associated with a set of Kerberos 
-+ * credentials. Hopefully we can use this for the 'empty' username
-+ * logins discussed in the draft  */
-+static int
-+ssh_gssapi_krb5_localname(ssh_gssapi_client *client, char **user) {
-+	krb5_principal princ;
-+	int retval;
-+
-+	if (ssh_gssapi_krb5_init() == 0)
-+		return 0;
-+
-+	if ((retval=krb5_parse_name(krb_context, client->displayname.value, 
-+				    &princ))) {
-+		logit("krb5_parse_name(): %.100s", 
-+			krb5_get_err_text(krb_context,retval));
-+		return 0;
-+	}
-+
-+	/* We've got to return a malloc'd string */
-+	*user = (char *)xmalloc(256);
-+	if (krb5_aname_to_localname(krb_context, princ, 256, *user)) {
-+		free(*user);
-+		*user = NULL;
-+		return(0);
-+	}
-+
-+	return(1);
-+}
- 
- /* This writes out any forwarded credentials from the structure populated
-  * during userauth. Called after we have setuid to the user */
-@@ -463,7 +491,7 @@
- 	return;
- }
- 
--int
-+static int
- ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, 
-     ssh_gssapi_client *client)
- {
-@@ -534,7 +562,7 @@
- 	{9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"},
- 	NULL,
- 	&ssh_gssapi_krb5_userok,
--	NULL,
-+	&ssh_gssapi_krb5_localname,
- 	&ssh_gssapi_krb5_storecreds,
- 	&ssh_gssapi_krb5_updatecreds
- };
-diff -Nur openssh-6.6p1.orig/kexgsss.c openssh-6.6p1/kexgsss.c
---- openssh-6.6p1.orig/kexgsss.c	2015-01-15 20:08:13.025214124 +0100
-+++ openssh-6.6p1/kexgsss.c	2015-01-15 20:08:56.683616330 +0100
-@@ -44,6 +44,7 @@
- #include "monitor_wrap.h"
- #include "servconf.h"
- 
-+static void kex_gss_send_error(Gssctxt *ctxt);
- extern ServerOptions options;
- 
- void
-@@ -89,8 +90,10 @@
- 
- 	debug2("%s: Acquiring credentials", __func__);
- 
--	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
-+	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) {
-+		kex_gss_send_error(ctxt);
- 		fatal("Unable to acquire credentials for the server");
-+	}
- 
- 	switch (kex->kex_type) {
- 	case KEX_GSS_GRP1_SHA1:
-@@ -176,12 +179,13 @@
- 	} while (maj_status & GSS_S_CONTINUE_NEEDED);
- 
- 	if (GSS_ERROR(maj_status)) {
-+		kex_gss_send_error(ctxt);
- 		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");
-+		packet_disconnect("GSSAPI Key Exchange handshake failed");
- 	}
- 
- 	if (!(ret_flags & GSS_C_MUTUAL_FLAG))
-@@ -285,4 +289,23 @@
- 	if (options.gss_store_rekey)
- 		ssh_gssapi_rekey_creds();
- }
-+
-+static void 
-+kex_gss_send_error(Gssctxt *ctxt) {
-+	char *errstr;
-+	OM_uint32 maj,min;
-+		
-+	errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
-+	if (errstr) {
-+		packet_start(SSH2_MSG_KEXGSS_ERROR);
-+		packet_put_int(maj);
-+		packet_put_int(min);
-+		packet_put_cstring(errstr);
-+		packet_put_cstring("");
-+		packet_send();
-+		packet_write_wait();
-+		/* XXX - We should probably log the error locally here */
-+		free(errstr);
-+	}
-+}
- #endif /* GSSAPI */
-diff -Nur openssh-6.6p1.orig/LICENSE.globus_usage openssh-6.6p1/LICENSE.globus_usage
---- openssh-6.6p1.orig/LICENSE.globus_usage	1970-01-01 01:00:00.000000000 +0100
-+++ openssh-6.6p1/LICENSE.globus_usage	2015-01-15 20:08:56.684616339 +0100
-@@ -0,0 +1,18 @@
-+/*
-+ * Portions of the Usage Metrics suport code are derived from the
-+ * Globus project's GridFTP subject to the following license.
-+ *
-+ * Copyright 2010 University of Chicago
-+ *
-+ * Licensed under the Apache License, Version 2.0 (the "License");
-+ * you may not use this file except in compliance with the License.
-+ * You may obtain a copy of the License at
-+ *
-+ * http://www.apache.org/licenses/LICENSE-2.0
-+ *
-+ * Unless required by applicable law or agreed to in writing, software
-+ * distributed under the License is distributed on an "AS IS" BASIS,
-+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+ * See the License for the specific language governing permissions and
-+ * limitations under the License.
-+ */
-diff -Nur openssh-6.6p1.orig/Makefile.in openssh-6.6p1/Makefile.in
---- openssh-6.6p1.orig/Makefile.in	2015-01-15 20:08:13.135215137 +0100
-+++ openssh-6.6p1/Makefile.in	2015-01-15 20:08:56.684616339 +0100
-@@ -99,8 +99,10 @@
- 	monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \
- 	kexc25519s.o auth-krb5.o \
- 	auth2-gss.o gss-serv.o gss-serv-krb5.o  kexgsss.o \
-+	gss-serv-gsi.o \
- 	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
- 	sftp-server.o sftp-common.o \
-+	ssh-globus-usage.o \
- 	roaming_common.o roaming_serv.o \
- 	sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
- 	sandbox-seccomp-filter.o sandbox-capsicum.o
-diff -Nur openssh-6.6p1.orig/misc.c openssh-6.6p1/misc.c
---- openssh-6.6p1.orig/misc.c	2015-01-15 20:08:13.106214870 +0100
-+++ openssh-6.6p1/misc.c	2015-01-15 20:08:56.685616348 +0100
-@@ -159,11 +159,14 @@
- #define WHITESPACE " \t\r\n"
- #define QUOTE	"\""
- 
-+/* Characters considered as quotations. */
-+#define QUOTES "'\""
-+
- /* return next token in configuration line */
- char *
- strdelim(char **s)
- {
--	char *old;
-+	char *old, *p, *q;
- 	int wspace = 0;
- 
- 	if (*s == NULL)
-@@ -171,6 +174,21 @@
- 
- 	old = *s;
- 
-+	if ((q=strchr(QUOTES, (int) *old)) && *q)
-+	{
-+		/* find next quote character, point old to start of quoted
-+		 * string */
-+		for (p = ++old; *p && *p != *q; p++)
-+			;
-+
-+		/* find start of next token */
-+		*s = (*p) ? p + strspn(p + 1, WHITESPACE) + 1 : NULL;
-+
-+		/* terminate 'old' token */
-+		*p = '\0';
-+		return (old);
-+	}
-+
- 	*s = strpbrk(*s, WHITESPACE QUOTE "=");
- 	if (*s == NULL)
- 		return (old);
-@@ -226,6 +244,20 @@
- 	return copy;
- }
- 
-+void
-+pwfree(struct passwd *pw)
-+{
-+	free(pw->pw_name);
-+	free(pw->pw_passwd);
-+	free(pw->pw_gecos);
-+#ifdef HAVE_PW_CLASS_IN_PASSWD
-+	free(pw->pw_class);
-+#endif
-+	free(pw->pw_dir);
-+	free(pw->pw_shell);
-+	free(pw);
-+}
-+
- /*
-  * Convert ASCII string to TCP/IP port number.
-  * Port must be >=0 and <=65535.
-diff -Nur openssh-6.6p1.orig/misc.h openssh-6.6p1/misc.h
---- openssh-6.6p1.orig/misc.h	2015-01-15 20:08:13.076214593 +0100
-+++ openssh-6.6p1/misc.h	2015-01-15 20:08:56.685616348 +0100
-@@ -41,6 +41,7 @@
- void	 sock_set_v6only(int);
- 
- struct passwd *pwcopy(struct passwd *);
-+void pwfree(struct passwd *);
- const char *ssh_gai_strerror(int);
- 
- typedef struct arglist arglist;
-diff -Nur openssh-6.6p1.orig/monitor.c openssh-6.6p1/monitor.c
---- openssh-6.6p1.orig/monitor.c	2015-01-15 20:08:13.150215275 +0100
-+++ openssh-6.6p1/monitor.c	2015-01-15 20:08:56.686616358 +0100
-@@ -182,6 +182,9 @@
- 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_error(int, Buffer *);
-+int mm_answer_gss_indicate_mechs(int, Buffer *);
-+int mm_answer_gss_localname(int, Buffer *);
- int mm_answer_gss_updatecreds(int, Buffer *);
- #endif
- 
-@@ -230,7 +233,7 @@
- struct mon_table mon_dispatch_proto20[] = {
-     {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli},
-     {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
--    {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
-+    {MONITOR_REQ_PWNAM, MON_AUTH, mm_answer_pwnamallow},
-     {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
- #ifdef WITH_SELINUX
-     {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole},
-@@ -238,7 +241,7 @@
-     {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
-     {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
- #ifdef USE_PAM
--    {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
-+    {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start},
-     {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
-     {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
-     {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
-@@ -268,6 +271,9 @@
-     {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},
-+    {MONITOR_REQ_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error},
-+    {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs},
-+    {MONITOR_REQ_GSSLOCALNAME, MON_ISAUTH, mm_answer_gss_localname},
- #endif
-     {0, 0, NULL}
- };
-@@ -277,6 +283,8 @@
-     {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_GSSERR, 0, mm_answer_gss_error},
-+    {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs},
-     {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
- #endif
-     {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
-@@ -314,7 +322,7 @@
-     {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond},
- #endif
- #ifdef USE_PAM
--    {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
-+    {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start},
-     {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
-     {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
-     {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
-@@ -406,6 +414,8 @@
- #ifdef GSSAPI
- 		/* and for the GSSAPI key exchange */
- 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
-+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
-+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1);
- #endif
- 	} else {
- 		mon_dispatch = mon_dispatch_proto15;
-@@ -520,6 +530,8 @@
- #ifdef GSSAPI
- 		/* and for the GSSAPI key exchange */
- 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
-+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
-+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1);
- #endif		
- 	} else {
- 		mon_dispatch = mon_dispatch_postauth15;
-@@ -790,14 +802,17 @@
- 
- 	debug3("%s", __func__);
- 
--	if (authctxt->attempt++ != 0)
--		fatal("%s: multiple attempts for getpwnam", __func__);
--
- 	username = buffer_get_string(m, NULL);
- 
- 	pwent = getpwnamallow(username);
- 
-+	if (authctxt->user) free(authctxt->user);
- 	authctxt->user = xstrdup(username);
-+#ifdef USE_PAM
-+	if (options.permit_pam_user_change)
-+		setproctitle("%s [priv]", pwent ? "[pam]" : "unknown");
-+	else
-+#endif
- 	setproctitle("%s [priv]", pwent ? username : "unknown");
- 	free(username);
- 
-@@ -2307,12 +2322,15 @@
- mm_answer_gss_userok(int sock, Buffer *m)
- {
- 	int authenticated;
-+	int gssapi_keyex;
- 
- 	if (!options.gss_authentication && !options.gss_keyex)
- 		fatal("In GSSAPI monitor when GSSAPI is disabled");
- 
-+	gssapi_keyex = buffer_get_int(m);
-+
- 	authenticated = authctxt->valid && 
--	    ssh_gssapi_userok(authctxt->user, authctxt->pw);
-+	    ssh_gssapi_userok(authctxt->user, authctxt->pw, gssapi_keyex);
- 
- 	buffer_clear(m);
- 	buffer_put_int(m, authenticated);
-@@ -2320,12 +2338,77 @@
- 	debug3("%s: sending result %d", __func__, authenticated);
- 	mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m);
- 
--	auth_method = "gssapi-with-mic";
-+	if (gssapi_keyex)
-+		auth_method = "gssapi-keyex";
-+	else
-+		auth_method = "gssapi-with-mic";
- 
- 	/* Monitor loop will terminate if authenticated */
- 	return (authenticated);
- }
- 
-+int
-+mm_answer_gss_error(int socket, Buffer *m) {
-+	OM_uint32 major, minor;
-+	char *msg;
-+
-+	msg=ssh_gssapi_last_error(gsscontext, &major, &minor);
-+	buffer_clear(m);
-+	buffer_put_int(m, major);
-+	buffer_put_int(m, minor);
-+	buffer_put_cstring(m, msg);
-+
-+	mm_request_send(socket, MONITOR_ANS_GSSERR, m);
-+
-+	free(msg);
-+
-+	return(0);
-+}
-+
-+int
-+mm_answer_gss_indicate_mechs(int socket, Buffer *m) {
-+	OM_uint32 major, minor;
-+	gss_OID_set mech_set;
-+	size_t i;
-+
-+	major=gss_indicate_mechs(&minor, &mech_set);
-+
-+	buffer_clear(m);
-+	buffer_put_int(m, major);
-+	buffer_put_int(m, mech_set->count);
-+	for (i = 0; i < mech_set->count; i++) {
-+		buffer_put_string(m, mech_set->elements[i].elements,
-+				  mech_set->elements[i].length);
-+	}
-+
-+	gss_release_oid_set(&minor, &mech_set);
-+
-+	mm_request_send(socket, MONITOR_ANS_GSSMECHS, m);
-+
-+	return(0);
-+}
-+
-+int
-+mm_answer_gss_localname(int socket, Buffer *m) {
-+	char *name;
-+
-+	ssh_gssapi_localname(&name);
-+
-+	buffer_clear(m);
-+	if (name) {
-+		buffer_put_cstring(m, name);
-+		debug3("%s: sending result %s", __func__, name);
-+		free(name);
-+	} else {
-+		buffer_put_cstring(m, "");
-+		debug3("%s: sending result \"\"", __func__);
-+	}
-+
-+	mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m);
-+
-+	return(0);
-+}
-+
- int 
- mm_answer_gss_sign(int socket, Buffer *m)
- {
-diff -Nur openssh-6.6p1.orig/monitor.h openssh-6.6p1/monitor.h
---- openssh-6.6p1.orig/monitor.h	2015-01-15 20:08:13.121215008 +0100
-+++ openssh-6.6p1/monitor.h	2015-01-15 20:08:56.686616358 +0100
-@@ -75,8 +75,10 @@
- 	MONITOR_REQ_AUDIT_UNSUPPORTED = 118, MONITOR_ANS_AUDIT_UNSUPPORTED = 119,
- 	MONITOR_REQ_AUDIT_KEX = 120, MONITOR_ANS_AUDIT_KEX = 121,
- 	MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 122, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 123,
--	MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124, MONITOR_ANS_AUDIT_SERVER_KEY_FREE = 125
--
-+	MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124, MONITOR_ANS_AUDIT_SERVER_KEY_FREE = 125,
-+	MONITOR_REQ_GSSMECHS = 200, MONITOR_ANS_GSSMECHS = 201,
-+	MONITOR_REQ_GSSLOCALNAME = 202, MONITOR_ANS_GSSLOCALNAME = 203,
-+	MONITOR_REQ_GSSERR = 204, MONITOR_ANS_GSSERR = 205,
- };
- 
- struct mm_master;
-diff -Nur openssh-6.6p1.orig/monitor_wrap.c openssh-6.6p1/monitor_wrap.c
---- openssh-6.6p1.orig/monitor_wrap.c	2015-01-15 20:08:13.151215284 +0100
-+++ openssh-6.6p1/monitor_wrap.c	2015-01-15 20:08:56.687616367 +0100
-@@ -1327,12 +1327,13 @@
- }
- 
- int
--mm_ssh_gssapi_userok(char *user, struct passwd *pw)
-+mm_ssh_gssapi_userok(char *user, struct passwd *pw, int gssapi_keyex)
- {
- 	Buffer m;
- 	int authenticated = 0;
- 
- 	buffer_init(&m);
-+	buffer_put_int(&m, gssapi_keyex);
- 
- 	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m);
- 	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK,
-@@ -1345,6 +1346,83 @@
- 	return (authenticated);
- }
- 
-+char *
-+mm_ssh_gssapi_last_error(Gssctxt *ctx, OM_uint32 *major, OM_uint32 *minor) {
-+	Buffer m;
-+	OM_uint32 maj,min;
-+	char *errstr;
-+
-+	buffer_init(&m);
-+
-+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSERR, &m);
-+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSERR, &m);
-+
-+	maj = buffer_get_int(&m);
-+	min = buffer_get_int(&m);
-+
-+	if (major) *major=maj;
-+	if (minor) *minor=min;
-+
-+	errstr=buffer_get_string(&m,NULL);
-+
-+	buffer_free(&m);
-+
-+	return(errstr);
-+}
-+
-+OM_uint32
-+mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set)
-+{
-+	Buffer m;
-+	OM_uint32 major,minor;
-+	int count;
-+	gss_OID_desc oid;
-+	u_int length;
-+
-+	buffer_init(&m);
-+
-+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSMECHS, &m);
-+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSMECHS,
-+				  &m);
-+	major=buffer_get_int(&m);
-+	count=buffer_get_int(&m);
-+	
-+	gss_create_empty_oid_set(&minor,mech_set);
-+	while(count-->0) {
-+	    oid.elements=buffer_get_string(&m,&length);
-+	    oid.length=length;
-+	    gss_add_oid_set_member(&minor,&oid,mech_set);
-+	}
-+
-+	buffer_free(&m);
-+	
-+	return(major);
-+}
-+
-+int
-+mm_ssh_gssapi_localname(char **lname)
-+{
-+	Buffer m;
-+
-+	buffer_init(&m);
-+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, &m);
-+
-+	debug3("%s: waiting for MONITOR_ANS_GSSLOCALNAME", __func__);
-+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME,
-+				  &m);
-+
-+	*lname = buffer_get_string(&m, NULL);
-+
-+	buffer_free(&m);
-+	if (lname[0] == '\0') {
-+	    debug3("%s: gssapi identity mapping failed", __func__);
-+	} else {
-+	    debug3("%s: gssapi identity mapped to %s", __func__, *lname);
-+	}
-+
-+	return(0);
-+}
-+
- OM_uint32
- mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
- {
-diff -Nur openssh-6.6p1.orig/monitor_wrap.h openssh-6.6p1/monitor_wrap.h
---- openssh-6.6p1.orig/monitor_wrap.h	2015-01-15 20:08:13.131215100 +0100
-+++ openssh-6.6p1/monitor_wrap.h	2015-01-15 20:08:56.687616367 +0100
-@@ -62,9 +62,13 @@
- 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, struct passwd *);
-+int mm_ssh_gssapi_userok(char *user, struct passwd *, int gssapi_keyex);
- 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_localname(char **user);
-+OM_uint32 mm_gss_indicate_mechs(OM_uint32 *minor_status,
-+				gss_OID_set *mech_set);
-+char *mm_ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min);
- int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
- #endif
- 
-diff -Nur openssh-6.6p1.orig/readconf.c openssh-6.6p1/readconf.c
---- openssh-6.6p1.orig/readconf.c	2015-01-15 20:08:13.028214151 +0100
-+++ openssh-6.6p1/readconf.c	2015-01-15 20:08:56.688616376 +0100
-@@ -1651,13 +1651,13 @@
- 	if (options->challenge_response_authentication == -1)
- 		options->challenge_response_authentication = 1;
- 	if (options->gss_authentication == -1)
--		options->gss_authentication = 0;
-+		options->gss_authentication = 1;
- 	if (options->gss_keyex == -1)
--		options->gss_keyex = 0;
-+		options->gss_keyex = 1;
- 	if (options->gss_deleg_creds == -1)
--		options->gss_deleg_creds = 0;
-+		options->gss_deleg_creds = 1;
- 	if (options->gss_trust_dns == -1)
--		options->gss_trust_dns = 0;
-+		options->gss_trust_dns = 1;
- 	if (options->gss_renewal_rekey == -1)
- 		options->gss_renewal_rekey = 0;
- 	if (options->password_authentication == -1)
-diff -Nur openssh-6.6p1.orig/readconf.h openssh-6.6p1/readconf.h
---- openssh-6.6p1.orig/readconf.h	2015-01-15 20:08:13.028214151 +0100
-+++ openssh-6.6p1/readconf.h	2015-01-15 20:08:56.688616376 +0100
-@@ -93,6 +93,8 @@
- 	char   *host_key_alias;	/* hostname alias for .ssh/known_hosts */
- 	char   *proxy_command;	/* Proxy command for connecting the host. */
- 	char   *user;		/* User to log in as. */
-+	int     implicit;	/* Login user was not specified.
-+				   Server may choose based on authctxt. */
- 	int     escape_char;	/* Escape character; -2 = none */
- 
- 	u_int	num_system_hostfiles;	/* Paths for /etc/ssh/ssh_known_hosts */
-diff -Nur openssh-6.6p1.orig/servconf.c openssh-6.6p1/servconf.c
---- openssh-6.6p1.orig/servconf.c	2015-01-15 20:08:13.152215293 +0100
-+++ openssh-6.6p1/servconf.c	2015-01-15 20:16:24.463735405 +0100
-@@ -71,6 +71,7 @@
- 
- 	/* Portable-specific options */
- 	options->use_pam = -1;
-+	options->permit_pam_user_change = -1;
- 
- 	/* Standard Options */
- 	options->num_ports = 0;
-@@ -108,9 +109,11 @@
- 	options->kerberos_ticket_cleanup = -1;
- 	options->kerberos_get_afs_token = -1;
- 	options->gss_authentication=-1;
-+	options->gss_deleg_creds = -1;
- 	options->gss_keyex = -1;
- 	options->gss_cleanup_creds = -1;
- 	options->gss_strict_acceptor = -1;
-+	options->gsi_allow_limited_proxy = -1;
- 	options->gss_store_rekey = -1;
- 	options->password_authentication = -1;
- 	options->kbd_interactive_authentication = -1;
-@@ -151,6 +154,8 @@
- 	options->chroot_directory = NULL;
- 	options->authorized_keys_command = NULL;
- 	options->authorized_keys_command_user = NULL;
-+	options->disable_usage_stats = 0;
-+	options->usage_stats_targets = NULL;
- 	options->revoked_keys_file = NULL;
- 	options->trusted_user_ca_keys = NULL;
- 	options->authorized_principals_file = NULL;
-@@ -167,6 +172,8 @@
- 	/* Portable-specific options */
- 	if (options->use_pam == -1)
- 		options->use_pam = 0;
-+	if (options->permit_pam_user_change == -1)
-+		options->permit_pam_user_change = 0;
- 
- 	/* Standard Options */
- 	if (options->protocol == SSH_PROTO_UNKNOWN)
-@@ -249,13 +256,17 @@
- 	if (options->kerberos_get_afs_token == -1)
- 		options->kerberos_get_afs_token = 0;
- 	if (options->gss_authentication == -1)
--		options->gss_authentication = 0;
-+		options->gss_authentication = 1;
-+	if (options->gss_deleg_creds == -1)
-+		options->gss_deleg_creds = 1;
- 	if (options->gss_keyex == -1)
--		options->gss_keyex = 0;
-+		options->gss_keyex = 1;
- 	if (options->gss_cleanup_creds == -1)
- 		options->gss_cleanup_creds = 1;
- 	if (options->gss_strict_acceptor == -1)
- 		options->gss_strict_acceptor = 1;
-+	if (options->gsi_allow_limited_proxy == -1)
-+		options->gsi_allow_limited_proxy = 0;
- 	if (options->gss_store_rekey == -1)
- 		options->gss_store_rekey = 0;
- 	if (options->password_authentication == -1)
-@@ -338,7 +349,7 @@
- typedef enum {
- 	sBadOption,		/* == unknown option */
- 	/* Portable-specific options */
--	sUsePAM,
-+	sUsePAM, sPermitPAMUserChange,
- 	/* Standard Options */
- 	sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
- 	sPermitRootLogin, sLogFacility, sLogLevel,
-@@ -359,10 +370,14 @@
- 	sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication,
- 	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
- 	sClientAliveCountMax, sAuthorizedKeysFile,
-+	sGssDelegateCreds,
-+	sGssCredsPath,
-+	sGsiAllowLimitedProxy,
- 	sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor,
- 	sGssKeyEx, sGssStoreRekey, sAcceptEnv, sPermitTunnel,
- 	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
- 	sUsePrivilegeSeparation, sAllowAgentForwarding,
-+	sDisUsageStats, sUsageStatsTarg,
- 	sHostCertificate,
- 	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
- 	sKexAlgorithms, sIPQoS, sVersionAddendum,
-@@ -384,8 +399,10 @@
- 	/* Portable-specific options */
- #ifdef USE_PAM
- 	{ "usepam", sUsePAM, SSHCFG_GLOBAL },
-+	{ "permitpamuserchange", sPermitPAMUserChange, SSHCFG_GLOBAL },
- #else
- 	{ "usepam", sUnsupported, SSHCFG_GLOBAL },
-+	{ "permitpamuserchange", sUnsupported, SSHCFG_GLOBAL },
- #endif
- 	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
- 	/* Standard Options */
-@@ -428,16 +445,26 @@
- 	{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
- #ifdef GSSAPI
- 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
-+	{ "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_ALL },
- 	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
- 	{ "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
-+	{ "gssapicredentialspath", sGssCredsPath, SSHCFG_GLOBAL },
-+#ifdef GSI
-+	{ "gsiallowlimitedproxy", sGsiAllowLimitedProxy, SSHCFG_GLOBAL },
-+#else
-+	{ "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL },
-+#endif
- 	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
- 	{ "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
- 	{ "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
- 	{ "gssapienablek5users", sGssEnablek5users, SSHCFG_ALL },
- #else
- 	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
-+	{ "gssapidelegatecredentials", sUnsupported, SSHCFG_ALL },
- 	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
- 	{ "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
-+	{ "gssapicredentialspath", sUnsupported, SSHCFG_GLOBAL },
-+	{ "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL },
- 	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
- 	{ "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
- 	{ "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
-@@ -499,6 +526,8 @@
- 	{ "permitopen", sPermitOpen, SSHCFG_ALL },
- 	{ "forcecommand", sForceCommand, SSHCFG_ALL },
- 	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
-+	{ "disableusagestats", sDisUsageStats, SSHCFG_GLOBAL},
-+	{ "usagestatstargets", sUsageStatsTarg, SSHCFG_GLOBAL},
- 	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
- 	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
- 	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
-@@ -906,6 +935,10 @@
- 		intptr = &options->use_pam;
- 		goto parse_flag;
- 
-+	case sPermitPAMUserChange:
-+		intptr = &options->permit_pam_user_change;
-+		goto parse_flag;
-+
- 	/* Standard Options */
- 	case sBadOption:
- 		return -1;
-@@ -1121,6 +1154,10 @@
- 		intptr = &options->gss_authentication;
- 		goto parse_flag;
- 
-+	case sGssDelegateCreds:
-+		intptr = &options->gss_deleg_creds;
-+		goto parse_flag;
-+
- 	case sGssKeyEx:
- 		intptr = &options->gss_keyex;
- 		goto parse_flag;
-@@ -1129,6 +1166,10 @@
- 		intptr = &options->gss_cleanup_creds;
- 		goto parse_flag;
- 
-+	case sGssCredsPath:
-+		charptr = &options->gss_creds_path;
-+		goto parse_filename;
-+
- 	case sGssStrictAcceptor:
- 		intptr = &options->gss_strict_acceptor;
- 		goto parse_flag;
-@@ -1137,6 +1178,12 @@
- 		intptr = &options->gss_store_rekey;
- 		goto parse_flag;
- 
-+#ifdef GSI
-+	case sGsiAllowLimitedProxy:
-+		intptr = &options->gsi_allow_limited_proxy;
-+		goto parse_flag;
-+#endif
-+
- 	case sPasswordAuthentication:
- 		intptr = &options->password_authentication;
- 		goto parse_flag;
-@@ -1602,6 +1649,18 @@
- 			*charptr = xstrdup(arg);
- 		break;
- 
-+	case sDisUsageStats:
-+		intptr = &options->disable_usage_stats;
-+		goto parse_flag;
-+
-+	case sUsageStatsTarg:
-+		arg = strdelim(&cp);
-+		if (!arg || *arg == '\0')
-+			fatal("%s line %d: missing value.",
-+			    filename, linenum);
-+		options->usage_stats_targets = xstrdup(arg);
-+		break;
-+
- 	case sTrustedUserCAKeys:
- 		charptr = &options->trusted_user_ca_keys;
- 		goto parse_filename;
-@@ -1811,6 +1870,7 @@
- 
- 	M_CP_INTOPT(password_authentication);
- 	M_CP_INTOPT(gss_authentication);
-+	M_CP_INTOPT(gss_deleg_creds);
- 	M_CP_INTOPT(rsa_authentication);
- 	M_CP_INTOPT(pubkey_authentication);
- 	M_CP_INTOPT(kerberos_authentication);
-diff -Nur openssh-6.6p1.orig/servconf.h openssh-6.6p1/servconf.h
---- openssh-6.6p1.orig/servconf.h	2015-01-15 20:08:13.109214897 +0100
-+++ openssh-6.6p1/servconf.h	2015-01-15 20:08:56.690616394 +0100
-@@ -111,9 +111,12 @@
- 						 * file on logout. */
- 	int     kerberos_get_afs_token;		/* If true, try to get AFS token if
- 						 * authenticated with Kerberos. */
-+	int     gsi_allow_limited_proxy;	/* If true, accept limited proxies */
- 	int     gss_authentication;	/* If true, permit GSSAPI authentication */
-+	int     gss_deleg_creds;	/* If true, store delegated GSSAPI credentials*/
- 	int     gss_keyex;		/* If true, permit GSSAPI key exchange */
- 	int     gss_cleanup_creds;	/* If true, destroy cred cache on logout */
-+	char   *gss_creds_path;		/* Use non-default credentials path */
- 	int 	gss_strict_acceptor;	/* If true, restrict the GSSAPI acceptor name */
- 	int 	gss_store_rekey;
- 	int     password_authentication;	/* If true, permit password
-@@ -168,6 +171,7 @@
- 	char   *adm_forced_command;
- 
- 	int	use_pam;		/* Enable auth via PAM */
-+	int	permit_pam_user_change;	/* Allow PAM to change user name */
- 
- 	int	permit_tun;
- 
-@@ -176,6 +180,10 @@
- 	int		use_kuserok;
- 	int		enable_k5users;
- 	char   *chroot_directory;
-+
-+	int	disable_usage_stats;
-+	char   *usage_stats_targets;
-+
- 	char   *revoked_keys_file;
- 	char   *trusted_user_ca_keys;
- 	char   *authorized_principals_file;
-diff -Nur openssh-6.6p1.orig/ssh.1 openssh-6.6p1/ssh.1
---- openssh-6.6p1.orig/ssh.1	2015-01-15 20:08:12.997213865 +0100
-+++ openssh-6.6p1/ssh.1	2015-01-15 20:08:56.690616394 +0100
-@@ -1295,6 +1295,18 @@
- on to new connections).
- .It Ev USER
- Set to the name of the user logging in.
-+.It Ev X509_CERT_DIR
-+Used for GSI authentication. Specifies a non-standard location for the
-+CA certificates directory.
-+.It Ev X509_USER_CERT
-+Used for GSI authentication. Specifies a non-standard location for the
-+certificate to be used for authentication to the server.
-+.It Ev X509_USER_KEY
-+Used for GSI authentication. Specifies a non-standard location for the
-+private key to be used for authentication to the server.
-+.It Ev X509_USER_PROXY
-+Used for GSI authentication. Specifies a non-standard location for the
-+proxy credential to be used for authentication to the server.
- .El
- .Pp
- Additionally,
-diff -Nur openssh-6.6p1.orig/ssh.c openssh-6.6p1/ssh.c
---- openssh-6.6p1.orig/ssh.c	2015-01-15 20:08:13.141215192 +0100
-+++ openssh-6.6p1/ssh.c	2015-01-15 20:08:56.691616404 +0100
-@@ -395,6 +395,32 @@
- 			fatal("Can't open user config file %.100s: "
- 			    "%.100s", config, strerror(errno));
- 	} else {
-+	    /*
-+	     * Since the config file parsing code aborts if it sees
-+	     * options it doesn't recognize, allow users to put
-+	     * options specific to compile-time add-ons in alternate
-+	     * config files so their primary config file will
-+	     * interoperate SSH versions that don't support those
-+	     * options.
-+	     */
-+#ifdef GSSAPI
-+		r = snprintf(buf, sizeof buf, "%s/%s.gssapi", pw->pw_dir,
-+		    _PATH_SSH_USER_CONFFILE);
-+		if (r > 0 && (size_t)r < sizeof(buf))
-+			(void)read_config_file(buf, pw, host, &options, 1);
-+#ifdef GSI
-+		r = snprintf(buf, sizeof buf, "%s/%s.gsi", pw->pw_dir,
-+		    _PATH_SSH_USER_CONFFILE);
-+		if (r > 0 && (size_t)r < sizeof(buf))
-+			(void)read_config_file(buf, pw, host, &options, 1);
-+#endif
-+#if defined(KRB5)
-+		r = snprintf(buf, sizeof buf, "%s/%s.krb", pw->pw_dir,
-+		    _PATH_SSH_USER_CONFFILE);
-+		if (r > 0 && (size_t)r < sizeof(buf))
-+			(void)read_config_file(buf, pw, host, &options, 1);
-+#endif
-+#endif
- 		r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
- 		    _PATH_SSH_USER_CONFFILE);
- 		if (r > 0 && (size_t)r < sizeof(buf))
-@@ -988,8 +1014,12 @@
- 		logit("FIPS mode initialized");
- 	}
- 
--	if (options.user == NULL)
-+	if (options.user == NULL) {
- 		options.user = xstrdup(pw->pw_name);
-+		options.implicit = 1;
-+	} else {
-+		options.implicit = 0;
-+	}
- 
- 	if (gethostname(thishost, sizeof(thishost)) == -1)
- 		fatal("gethostname: %s", strerror(errno));
-diff -Nur openssh-6.6p1.orig/ssh_config openssh-6.6p1/ssh_config
---- openssh-6.6p1.orig/ssh_config	2015-01-15 20:08:13.031214179 +0100
-+++ openssh-6.6p1/ssh_config	2015-01-15 20:08:56.691616404 +0100
-@@ -24,10 +24,10 @@
- #   RSAAuthentication yes
- #   PasswordAuthentication yes
- #   HostbasedAuthentication no
--#   GSSAPIAuthentication no
--#   GSSAPIDelegateCredentials no
--#   GSSAPIKeyExchange no
--#   GSSAPITrustDNS no
-+#   GSSAPIAuthentication yes
-+#   GSSAPIDelegateCredentials yes
-+#   GSSAPIKeyExchange yes
-+#   GSSAPITrustDNS yes
- #   BatchMode no
- #   CheckHostIP yes
- #   AddressFamily any
-diff -Nur openssh-6.6p1.orig/ssh_config.5 openssh-6.6p1/ssh_config.5
---- openssh-6.6p1.orig/ssh_config.5	2015-01-15 20:08:13.031214179 +0100
-+++ openssh-6.6p1/ssh_config.5	2015-01-15 20:08:56.692616413 +0100
-@@ -55,6 +55,12 @@
- user's configuration file
- .Pq Pa ~/.ssh/config
- .It
-+GSSAPI configuration file
-+.Pq Pa $HOME/.ssh/config.gssapi
-+.It
-+Kerberos configuration file
-+.Pq Pa $HOME/.ssh/config.krb
-+.It
- system-wide configuration file
- .Pq Pa /etc/ssh/ssh_config
- .El
-diff -Nur openssh-6.6p1.orig/sshconnect2.c openssh-6.6p1/sshconnect2.c
---- openssh-6.6p1.orig/sshconnect2.c	2015-01-15 20:08:13.142215201 +0100
-+++ openssh-6.6p1/sshconnect2.c	2015-01-15 20:08:56.692616413 +0100
-@@ -728,6 +728,11 @@
- 	int ok = 0;
- 	const char *gss_host = NULL;
- 
-+	if (!options.gss_authentication) {
-+		verbose("GSSAPI authentication disabled.");
-+		return 0;
-+	}
-+
- 	if (options.gss_server_identity)
- 		gss_host = options.gss_server_identity;
- 	else if (options.gss_trust_dns) {
-@@ -961,6 +966,15 @@
- 	free(lang);
- }
- 
-+#ifdef GSI
-+extern
-+const gss_OID_desc * const gss_mech_globus_gssapi_openssl;
-+#define is_gsi_oid(oid) \
-+  (oid->length == gss_mech_globus_gssapi_openssl->length && \
-+   (memcmp(oid->elements, gss_mech_globus_gssapi_openssl->elements, \
-+	   oid->length) == 0))
-+#endif
-+
- int
- userauth_gsskeyex(Authctxt *authctxt)
- {
-@@ -978,8 +992,16 @@
- 		return (0);
- 	}
- 
-+#ifdef GSI
-+	if (options.implicit && is_gsi_oid(gss_kex_context->oid)) {
-+		ssh_gssapi_buildmic(&b, "", authctxt->service, "gssapi-keyex");
-+	} else {
-+#endif
- 	ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
- 	    "gssapi-keyex");
-+#ifdef GSI
-+	}
-+#endif
- 
- 	gssbuf.value = buffer_ptr(&b);
- 	gssbuf.length = buffer_len(&b);
-@@ -990,7 +1012,15 @@
- 	}
- 
- 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
-+#ifdef GSI
-+	if (options.implicit && is_gsi_oid(gss_kex_context->oid)) {
-+		packet_put_cstring("");
-+	} else {
-+#endif
- 	packet_put_cstring(authctxt->server_user);
-+#ifdef GSI
-+	}
-+#endif
- 	packet_put_cstring(authctxt->service);
- 	packet_put_cstring(authctxt->method->name);
- 	packet_put_string(mic.value, mic.length);
-diff -Nur openssh-6.6p1.orig/sshd.8 openssh-6.6p1/sshd.8
---- openssh-6.6p1.orig/sshd.8	2015-01-15 20:08:13.036214225 +0100
-+++ openssh-6.6p1/sshd.8	2015-01-15 20:08:56.693616422 +0100
-@@ -766,6 +766,44 @@
- # A CA key, accepted for any host in *.mydomain.com or *.mydomain.org
- @cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W...
- .Ed
-+.Sh ENVIRONMENT
-+.Nm
-+will normally set the following environment variables:
-+.Bl -tag -width "SSH_ORIGINAL_COMMAND"
-+.It Ev GLOBUS_USAGE_OPTOUT
-+Setting this environment variable to "1" will disable the reporting
-+of usage metrics. Usage metrics can also be disabled using the
-+.Cm DisableUsageStats
-+setting in
-+.Xr sshd_config 5 .
-+.It Ev GLOBUS_USAGE_TARGETS
-+If
-+.Cm UsageStatsTargets
-+is not specified in
-+.Xr sshd_config 5 ,
-+a comma-separated list of targets (without any tags specified) if
-+specified in the environment variable
-+.Ev GLOBUS_USAGE_TARGETS
-+will be used.
-+.It Ev GRIDMAP
-+Applies to GSI authentication/authorization. Specifies the location of the
-+gridmapfile. If not specified, the gridmap file is assumed to be available at
-+/etc/grid-security/grid-mapfile for services running as root and at
-+HOME/.gridmap for services running as non-root where HOME is the home directory
-+of the effective user from the password file entry.
-+.It Ev X509_CERT_DIR
-+Used for GSI authentication. Specifies a non-standard location for the
-+CA certificates directory.
-+.It Ev X509_USER_CERT
-+Used for GSI authentication. Specifies a non-standard location for the
-+certificate to be used for authentication to the client.
-+.It Ev X509_USER_KEY
-+Used for GSI authentication. Specifies a non-standard location for the
-+private key to be used for authentication to the client.
-+.It Ev X509_USER_PROXY
-+Used for GSI authentication. Specifies a non-standard location for the
-+proxy credential to be used for authentication to the client.
-+.El
- .Sh FILES
- .Bl -tag -width Ds -compact
- .It Pa ~/.hushlogin
-diff -Nur openssh-6.6p1.orig/sshd.c openssh-6.6p1/sshd.c
---- openssh-6.6p1.orig/sshd.c	2015-01-15 20:08:13.154215312 +0100
-+++ openssh-6.6p1/sshd.c	2015-01-15 20:08:56.693616422 +0100
-@@ -124,6 +124,7 @@
- #include "audit.h"
- #include "ssh-sandbox.h"
- #include "version.h"
-+#include "ssh-globus-usage.h"
- 
- #ifdef USE_SECURITY_SESSION_API
- #include <Security/AuthSession.h>
-@@ -1709,6 +1710,13 @@
- 	/* Fill in default values for those options not explicitly set. */
- 	fill_default_server_options(&options);
- 
-+#ifdef HAVE_GLOBUS_USAGE
-+	if (ssh_usage_stats_init(options.disable_usage_stats,
-+			options.usage_stats_targets) != GLOBUS_SUCCESS) {
-+		error("Error initializing Globus Usage Metrics, but continuing ...");
-+	}
-+#endif /* HAVE_GLOBUS_USAGE */
-+
- 	/* challenge-response is implemented via keyboard interactive */
- 	if (options.challenge_response_authentication)
- 		options.kbd_interactive_authentication = 1;
-@@ -2240,7 +2248,7 @@
- #endif
- 
- #ifdef GSSAPI
--	if (options.gss_authentication) {
-+	if (options.gss_authentication && options.gss_deleg_creds) {
- 		temporarily_use_uid(authctxt->pw);
- 		ssh_gssapi_storecreds();
- 		restore_uid();
-diff -Nur openssh-6.6p1.orig/sshd_config openssh-6.6p1/sshd_config
---- openssh-6.6p1.orig/sshd_config	2015-01-15 20:08:13.110214907 +0100
-+++ openssh-6.6p1/sshd_config	2015-01-15 20:12:27.743560736 +0100
-@@ -90,10 +90,11 @@
- #KerberosUseKuserok yes
- 
- # GSSAPI options
--GSSAPIAuthentication yes
-+#GSSAPIAuthentication yes
-+#GSSAPIDelegateCredentials yes
- GSSAPICleanupCredentials no
- #GSSAPIStrictAcceptorCheck yes
--#GSSAPIKeyExchange no
-+#GSSAPIKeyExchange yes
- #GSSAPIEnablek5users no
- 
- # Set this to 'yes' to enable PAM authentication, account processing,
-@@ -109,6 +110,10 @@
- # problems.
- UsePAM yes
- 
-+# Set to 'yes' to allow the PAM stack to change the user name during
-+# calls to authentication
-+#PermitPAMUserChange no
-+
- #AllowAgentForwarding yes
- #AllowTcpForwarding yes
- #GatewayPorts no
-@@ -151,3 +156,7 @@
- #	AllowTcpForwarding no
- #	PermitTTY no
- #	ForceCommand cvs server
-+
-+# Usage Metrics
-+#UsageStatsTargets usage-stats.cilogon.org:4810
-+#DisableUsageStats no
-diff -Nur openssh-6.6p1.orig/sshd_config.5 openssh-6.6p1/sshd_config.5
---- openssh-6.6p1.orig/sshd_config.5	2015-01-15 20:08:13.110214907 +0100
-+++ openssh-6.6p1/sshd_config.5	2015-01-15 20:10:59.416747018 +0100
-@@ -449,6 +449,15 @@
- See PATTERNS in
- .Xr ssh_config 5
- for more information on patterns.
-+.It Cm DisableUsageStats
-+This keyword can be followed by "yes" to disable reporting of usage metrics.
-+Or it can be set to "no" to enable reporting of usage metrics, which is the
-+default. Setting the
-+.Cm GLOBUS_USAGE_OPTOUT
-+environment variable to "1" will also disable the reporting of usage metrics.
-+Disabling reporting of usage metrics will cause the
-+.Cm UsageStatsTargets
-+setting to be ignored.
- .It Cm ForceCommand
- Forces the execution of the command specified by
- .Cm ForceCommand ,
-@@ -493,6 +502,10 @@
- The default is
- .Dq no .
- Note that this option applies to protocol version 2 only.
-+.It Cm GSSAPIDelegateCredentials
-+Specifies whether delegated credentials are stored in the user's environment.
-+The default is
-+.Dq yes .
- .It Cm GSSAPIKeyExchange
- Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
- doesn't rely on ssh keys to verify host identity.
-@@ -511,6 +524,22 @@
- .Xr ksu 1 .
- The default is
- .Dq no .
-+.It Cm GSSAPICredentialsPath
-+If specified, the delegated GSSAPI credential is stored in the
-+given path, overwriting any existing credentials.  
-+Paths can be specified with syntax similar to the AuthorizedKeysFile 
-+option (i.e., accepting %h and %u tokens).  
-+When using this option,
-+setting 'GssapiCleanupCredentials no' is recommended,
-+so logging out of one session
-+doesn't remove the credentials in use by another session of
-+the same user.
-+Currently only implemented for the GSI mechanism.
-+.It Cm GSIAllowLimitedProxy
-+Specifies whether to accept limited proxy credentials for
-+authentication.
-+The default is
-+.Dq no .
- .It Cm GSSAPIStrictAcceptorCheck
- Determines whether to be strict about the identity of the GSSAPI acceptor 
- a client authenticates against. If
-@@ -1202,6 +1231,121 @@
- .Pp
- To disable TCP keepalive messages, the value should be set to
- .Dq no .
-+.It Cm UsageStatsTargets
-+This option can be used to specify the target collector hosts to which usage
-+metrics should be reported. This setting will be ignored if
-+.Cm DisableUsageStats
-+is enabled. Multiple targets can be specified separated by comma(s), but no
-+space(s). Each target specification is of the format
-+.Pa host:port[!tags].
-+Tags control what data elements are reported. The following list specifies
-+the tags for the corresponding data elements.
-+.Pp
-+.Bl -item -offset indent -compact
-+.It
-+.Cm V
-+.Sm off
-+- OpenSSH version, reported by default.
-+.Sm on
-+.It
-+.Cm v
-+.Sm off
-+- SSL version, reported by default.
-+.Sm on
-+.It
-+.Cm M
-+.Sm off
-+- User authentication method used such as "gssapi-keyex", "gssapi-with-mic", etc. Reported by default.
-+.Sm on
-+.It
-+.Cm m
-+.Sm off
-+- User authentication mechanism used such as "GSI", "Kerberos", etc. Reported by default.
-+.Sm on
-+.It
-+.Cm I
-+.Sm off
-+- Client IP address. Not reported by default.
-+.Sm on
-+.It
-+.Cm u
-+.Sm off
-+- User name. Not reported by default.
-+.Sm on
-+.It
-+.Cm U
-+.Sm off
-+- User DN. Not reported by default.
-+.Sm on
-+.Pp
-+In addition to the above selected information, the following data are
-+reported to ALL the specified/default target collectors. There's no way to
-+exclude these from being reported other than by disabling the reporting of
-+usage metrics altogether:
-+.Pp
-+.It
-+.Cm Component code
-+.Sm off
-+- 12 for GSI OpenSSH
-+.Sm on
-+.It
-+.Cm Component Data Format version
-+.Sm off
-+- 0 currently
-+.Sm on
-+.It
-+.Cm IP Address
-+.Sm off
-+- IP address of reporting server
-+.Sm on
-+.It
-+.Cm Timestamp
-+.It
-+.Cm Hostname
-+.Sm off
-+- Host name of reporting server
-+.Sm on
-+.Pp
-+If no tags are specified in a host spec, or the special string
-+.Dq default
-+is specified, the tags
-+.Dq VvMm
-+are assumed. A site could choose to allow a
-+different set of data to be reported by specifying a different tag set. The
-+last 3 tags
-+.Dq I ,
-+.Dq u
-+and
-+.Dq U
-+above are more meant for a local collector that a
-+site might like to deploy since they could be construed as private information.
-+The special string
-+.Dq all
-+denotes all tags.
-+.El
-+.Pp
-+By default, Usage Metrics reporting is sent to
-+.Dq usage-stats.cilogon.org:4810 .
-+This can be made explicit by specifying
-+.Dq default
-+(all by itself) for the
-+target specification as in:
-+.Pp
-+.Bl -item -offset indent -compact
-+.It
-+.Cm UsageStatsTargets
-+.Sm off
-+default
-+.Sm on
-+.El
-+.Pp
-+If
-+.Cm UsageStatsTargets
-+is not specified, a comma-separated list of targets
-+(without any tags specified) if specified in the environment variable
-+.Cm GLOBUS_USAGE_TARGETS
-+will be used.
-+.Pp
- .It Cm TrustedUserCAKeys
- Specifies a file containing public keys of certificate authorities that are
- trusted to sign user certificates for authentication.
-@@ -1267,6 +1411,12 @@
- as a non-root user.
- The default is
- .Dq no .
-+.It Cm PermitPAMUserChange
-+If set to
-+.Dq yes
-+this will enable PAM authentication to change the name of the user being
-+authenticated.  The default is
-+.Dq no .
- .It Cm UsePrivilegeSeparation
- Specifies whether
- .Xr sshd 8
-diff -Nur openssh-6.6p1.orig/ssh-globus-usage.c openssh-6.6p1/ssh-globus-usage.c
---- openssh-6.6p1.orig/ssh-globus-usage.c	1970-01-01 01:00:00.000000000 +0100
-+++ openssh-6.6p1/ssh-globus-usage.c	2015-01-15 20:08:56.696616450 +0100
-@@ -0,0 +1,396 @@
-+/*
-+ * Copyright 2009 The Board of Trustees of the University
-+ * of Illinois.  See the LICENSE file for detailed license information.
-+ *
-+ * Portions, specifically log_usage_stats(), ssh_usage_stats_init(),
-+ * ssh_usage_stats_close(), ssh_usage_ent_s, ssh_usage_tag_e and
-+ * TAG #defines were based on those from Usage Metrics portions of:
-+ * gridftp/server/source/globus_i_gfs_log.c
-+ *
-+ * Copyright 1999-2006 University of Chicago
-+ *
-+ * Licensed under the Apache License, Version 2.0 (the "License");
-+ * you may not use this file except in compliance with the License.
-+ * You may obtain a copy of the License at
-+ *
-+ * http://www.apache.org/licenses/LICENSE-2.0
-+ *
-+ * Unless required by applicable law or agreed to in writing, software
-+ * distributed under the License is distributed on an "AS IS" BASIS,
-+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+ * See the License for the specific language governing permissions and
-+ * limitations under the License.
-+ */
-+
-+#include "includes.h"
-+
-+#ifdef HAVE_GLOBUS_USAGE
-+
-+#include <stdarg.h>
-+#include <unistd.h> 
-+
-+#include "log.h"
-+#include "ssh-globus-usage.h"
-+
-+static globus_list_t *usage_handle_list = NULL;
-+
-+#define SSH_GLOBUS_USAGE_ID 12
-+#define SSH_GLOBUS_USAGE_VER 0
-+
-+#define SSH_GLOBUS_DEFAULT_TAGLIST "VvMm"
-+#define SSH_GLOBUS_ALL_TAGLIST     "VvMmIuU"
-+#define SSH_GLOBUS_TAGCOUNT 25
-+
-+typedef enum ssh_usage_tag_e
-+{
-+    SSH_GLOBUS_USAGE_SSH_VER        = 'V',
-+    SSH_GLOBUS_USAGE_SSL_VER        = 'v',
-+    SSH_GLOBUS_USAGE_METHOD         = 'M',
-+    SSH_GLOBUS_USAGE_MECHANISM      = 'm',
-+    SSH_GLOBUS_USAGE_CLIENTIP       = 'I',
-+    SSH_GLOBUS_USAGE_USERNAME       = 'u',
-+    SSH_GLOBUS_USAGE_USERDN         = 'U'
-+    /* !! ADD to ALL_TAGLIST above and to globus_usage_stats_send()
-+          invocation below when adding here */
-+} ssh_usage_tag_t;
-+
-+typedef struct ssh_usage_ent_s
-+{
-+    globus_usage_stats_handle_t         handle;
-+    char *                              target;
-+    char *                              taglist;
-+} ssh_usage_ent_t;
-+
-+
-+globus_result_t
-+ssh_usage_stats_init(int disable_usage_stats, char *usage_stats_targets)
-+{
-+    globus_result_t                     result;
-+    char *                              target_str = NULL;
-+    char *                              ptr = ptr;
-+    char *                              target = NULL;
-+    char *                              entry = NULL;
-+    globus_list_t *                     list = NULL;
-+    ssh_usage_ent_t *               usage_ent = NULL;
-+
-+    if (disable_usage_stats)
-+	return GLOBUS_SUCCESS;
-+
-+    result = globus_module_activate(GLOBUS_USAGE_MODULE);
-+    if (result != GLOBUS_SUCCESS)
-+    {
-+        error("ERROR: couldn't activate USAGE STATS module");
-+        return result;
-+    }
-+
-+    if (!usage_stats_targets ||
-+        !strcasecmp(usage_stats_targets, "default"))
-+        target_str = strdup(CILOGON_COLLECTOR);
-+    else
-+        target_str = strdup(usage_stats_targets);
-+
-+    if (target_str == NULL)
-+    {
-+        error("ERROR: strdup failure for target_str");
-+        goto error;
-+    }
-+    debug("Processing usage_stats_target (%s)\n", target_str);
-+
-+    if(target_str && (strchr(target_str, ',') || strchr(target_str, '!')))
-+    {
-+        target = target_str;
-+
-+        do {
-+            usage_ent = (ssh_usage_ent_t *) malloc(sizeof(ssh_usage_ent_t));
-+            if (usage_ent == NULL)
-+            {
-+                error("ERROR: couldn't allocate for ssh_usage_ent_t");
-+                goto error;
-+            }
-+
-+            if ((ptr = strchr(target, ',')) != NULL)
-+                *ptr = '\0';
-+
-+            entry = strdup(target);
-+            if (entry == NULL)
-+            {
-+                error("ERROR: strdup failure for target");
-+                goto error;
-+            }
-+
-+            if (ptr)
-+                target = ptr + 1;
-+            else
-+                target = NULL;
-+
-+            if((ptr = strchr(entry, '!')) != NULL)
-+            {
-+                *ptr = '\0';
-+                usage_ent->taglist = strdup(ptr + 1);
-+                if (usage_ent->taglist == NULL)
-+                {
-+                    error("ERROR: strdup failure for taglist");
-+                    goto error;
-+                }
-+                if(strlen(usage_ent->taglist) > SSH_GLOBUS_TAGCOUNT)
-+                {
-+                    usage_ent->taglist[SSH_GLOBUS_TAGCOUNT + 1] = '\0';
-+                }
-+            }
-+            else
-+            {
-+                usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST);
-+                if (usage_ent->taglist == NULL)
-+                {
-+                    error("ERROR: couldn't allocate for taglist");
-+                    goto error;
-+                }
-+            }
-+            
-+            if(strcasecmp(usage_ent->taglist, "default") == 0)
-+            {
-+                free(usage_ent->taglist);
-+                usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST);
-+                if (usage_ent->taglist == NULL)
-+                {
-+                    error("ERROR: couldn't allocate for taglist");
-+                    goto error;
-+                }
-+            }                
-+            else if(strcasecmp(usage_ent->taglist, "all") == 0)
-+            {
-+                free(usage_ent->taglist);
-+                usage_ent->taglist = strdup(SSH_GLOBUS_ALL_TAGLIST);
-+                if (usage_ent->taglist == NULL)
-+                {
-+                    error("ERROR: couldn't allocate for taglist");
-+                    goto error;
-+                }
-+            }
-+            
-+            usage_ent->target = entry;
-+
-+            globus_list_insert(&usage_handle_list, usage_ent);
-+        }
-+        while(target != NULL);
-+
-+        free(target_str);
-+    }
-+    else
-+    {
-+        usage_ent = (ssh_usage_ent_t *) malloc(sizeof(ssh_usage_ent_t));
-+        if (usage_ent == NULL)
-+        {
-+             error("ERROR: couldn't allocate for usage_ent");
-+             goto error;
-+        }
-+
-+        usage_ent->target = target_str;
-+        usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST);
-+        if (usage_ent->taglist == NULL)
-+        {
-+             error("ERROR: couldn't allocate for taglist");
-+             goto error;
-+        }
-+
-+        globus_list_insert(&usage_handle_list, usage_ent);
-+    }
-+
-+    result = GLOBUS_SUCCESS;
-+    for(list = usage_handle_list;
-+        !globus_list_empty(list);
-+        list = globus_list_rest(list))
-+    {
-+        usage_ent = (ssh_usage_ent_t *) globus_list_first(list);
-+
-+        usage_ent->handle = NULL;
-+        if (globus_usage_stats_handle_init(
-+            &usage_ent->handle,
-+            SSH_GLOBUS_USAGE_ID,
-+            SSH_GLOBUS_USAGE_VER,
-+            usage_ent->target) != GLOBUS_SUCCESS)
-+        {
-+            error("USAGE-STATS: Error initializing (%s) (%s)",
-+                     usage_ent->target?:"NULL",
-+                     usage_ent->taglist?:"NULL");
-+            result = GLOBUS_FAILURE;
-+        } else
-+            debug("USAGE-STATS: Initialized (%s) (%s)", usage_ent->target?:"NULL",
-+                     usage_ent->taglist?:"NULL");
-+
-+    }
-+
-+    return result;
-+
-+error:
-+    if (target_str)
-+    {
-+        free(target_str); 
-+        target_str = NULL;
-+    }
-+    if (entry)
-+    {
-+        free(target_str); 
-+        target_str = NULL;
-+    }
-+    return GLOBUS_FAILURE;
-+}
-+
-+void
-+ssh_usage_stats_close(int disable_usage_stats)
-+{
-+    globus_list_t *list;
-+
-+    if (disable_usage_stats)
-+	return;
-+
-+    list = usage_handle_list;
-+    
-+    while(!globus_list_empty(list))
-+    {
-+        ssh_usage_ent_t *usage_ent;
-+        
-+        usage_ent = (ssh_usage_ent_t *) 
-+            globus_list_remove(&list, list);
-+    
-+        if(usage_ent)
-+        {
-+            if(usage_ent->handle)
-+            {
-+                globus_usage_stats_handle_destroy(usage_ent->handle);
-+            }
-+            if(usage_ent->target)
-+            {
-+                free(usage_ent->target);
-+            }
-+            if(usage_ent->taglist)
-+            {
-+                free(usage_ent->taglist);
-+            }
-+            free(usage_ent);
-+        }
-+    }
-+    usage_handle_list = NULL;
-+}
-+
-+static void
-+log_usage_stats(char *ssh_release, const char *ssl_release,
-+                char *method, char *mechanism, const char *clientip,
-+                char *username, char *userdn)
-+{
-+    globus_result_t                     result;
-+    globus_list_t *                     list;
-+    ssh_usage_ent_t *                   usage_ent;
-+    char *                              keys[SSH_GLOBUS_TAGCOUNT];
-+    char *                              values[SSH_GLOBUS_TAGCOUNT];
-+    char *                              ptr;
-+    char *                              key;
-+    char *                              value;
-+    int                                 i = 0;
-+    char *                              save_taglist = NULL;
-+
-+    for(list = usage_handle_list;
-+        !globus_list_empty(list);
-+        list = globus_list_rest(list))
-+    {
-+        usage_ent = (ssh_usage_ent_t *) globus_list_first(list);
-+
-+        if(!usage_ent || usage_ent->handle == NULL)
-+            continue;
-+        
-+        if(save_taglist == NULL || 
-+            strcmp(save_taglist, usage_ent->taglist) != 0)
-+        {
-+            save_taglist = usage_ent->taglist;
-+            
-+            ptr = usage_ent->taglist;
-+            i = 0;
-+            while(ptr && *ptr)
-+            {
-+                switch(*ptr)
-+                {
-+                  case SSH_GLOBUS_USAGE_SSH_VER:
-+                    key = "SSH_VER";
-+                    value = ssh_release;
-+                    break;
-+    
-+                  case SSH_GLOBUS_USAGE_SSL_VER:
-+                    key = "SSL_VER";
-+                    value = (char *) ssl_release;
-+                    break;
-+    
-+                  case SSH_GLOBUS_USAGE_METHOD:
-+                    key = "METHOD";
-+                    value = method;
-+                    break;
-+    
-+                  case SSH_GLOBUS_USAGE_MECHANISM:
-+                    key = "MECH";
-+                    value = mechanism?:"";
-+                    break;
-+    
-+                  case SSH_GLOBUS_USAGE_CLIENTIP:
-+                    key = "CLIENTIP";
-+                    value = (char *) clientip?:"";
-+                    break;
-+    
-+                  case SSH_GLOBUS_USAGE_USERNAME:
-+                    key = "USER";
-+                    value = username?:"";
-+                    break;
-+    
-+                  case SSH_GLOBUS_USAGE_USERDN:
-+                    key = "USERDN";
-+                    value = userdn?:"";
-+                    break;
-+    
-+                  default:
-+                    key = NULL;
-+                    value = NULL;
-+                    break;
-+                }
-+                
-+                if(key != NULL && value != NULL)
-+                {
-+                    keys[i] = key;
-+                    values[i] = value;
-+                    i++;
-+                }
-+                
-+                ptr++;
-+            }
-+        }
-+
-+#ifdef HAVE_GLOBUS_USAGE_SEND_ARRAY
-+        result = globus_usage_stats_send_array(
-+            usage_ent->handle, i, keys, values);
-+#else
-+        if (i)
-+            result = globus_usage_stats_send(
-+                usage_ent->handle, i,
-+                i>0?keys[0]:NULL, i>0?values[0]:NULL,
-+                i>1?keys[1]:NULL, i>1?values[1]:NULL,
-+                i>2?keys[2]:NULL, i>2?values[2]:NULL,
-+                i>3?keys[3]:NULL, i>3?values[3]:NULL,
-+                i>4?keys[4]:NULL, i>4?values[4]:NULL,
-+                i>5?keys[5]:NULL, i>5?values[5]:NULL,
-+                i>6?keys[6]:NULL, i>6?values[6]:NULL);
-+#endif /* HAVE_GLOBUS_USAGE_SEND_ARRAY */
-+    }
-+    
-+    return;
-+}
-+#endif /* HAVE_GLOBUS_USAGE */
-+
-+void
-+ssh_globus_send_usage_metrics(char *ssh_release, const char *ssl_release,
-+                              char *method, char *mechanism, const char *client_ip,
-+                              char *username, char *userdn)
-+{
-+#ifdef HAVE_GLOBUS_USAGE
-+
-+    log_usage_stats(ssh_release, ssl_release, method, mechanism,
-+                    client_ip, username, userdn);
-+
-+#endif /* HAVE_GLOBUS_USAGE */
-+}
-diff -Nur openssh-6.6p1.orig/ssh-globus-usage.h openssh-6.6p1/ssh-globus-usage.h
---- openssh-6.6p1.orig/ssh-globus-usage.h	1970-01-01 01:00:00.000000000 +0100
-+++ openssh-6.6p1/ssh-globus-usage.h	2015-01-15 20:08:56.696616450 +0100
-@@ -0,0 +1,46 @@
-+/*
-+ * Copyright 2009 The Board of Trustees of the University
-+ * of Illinois.  See the LICENSE file for detailed license information.
-+ *
-+ * Portions, specifically ssh_usage_stats_init(), ssh_usage_stats_close()
-+ * were based on those from: gridftp/server/source/globus_i_gfs_log.h
-+ * Copyright 1999-2006 University of Chicago
-+ * 
-+ * Licensed under the Apache License, Version 2.0 (the "License");
-+ * you may not use this file except in compliance with the License.
-+ * You may obtain a copy of the License at
-+ * 
-+ * http://www.apache.org/licenses/LICENSE-2.0
-+ * 
-+ * Unless required by applicable law or agreed to in writing, software
-+ * distributed under the License is distributed on an "AS IS" BASIS,
-+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+ * See the License for the specific language governing permissions and
-+ * limitations under the License.
-+ */
-+
-+#ifndef __SSH_GLOBUS_USAGE_H
-+#define __SSH_GLOBUS_USAGE_H
-+
-+#include "includes.h"
-+
-+#ifdef HAVE_GLOBUS_USAGE
-+
-+#include "globus_usage.h"
-+
-+#define CILOGON_COLLECTOR "usage-stats.cilogon.org:4810"
-+
-+globus_result_t
-+ssh_usage_stats_init(int disable_usage_stats, char *usage_stats_targets);
-+
-+void
-+ssh_usage_stats_close(int disable_usage_stats);
-+
-+#endif /* HAVE_GLOBUS_USAGE */
-+
-+void
-+ssh_globus_send_usage_metrics(char *ssh_release, const char *ssl_release,
-+                           char *method, char *mechanism, const char *client_ip,
-+                           char *username, char *userdn);
-+
-+#endif /* __SSH_GLOBUS_USAGE_H */
-diff -Nur openssh-6.6p1.orig/ssh-gss.h openssh-6.6p1/ssh-gss.h
---- openssh-6.6p1.orig/ssh-gss.h	2015-01-15 20:08:13.036214225 +0100
-+++ openssh-6.6p1/ssh-gss.h	2015-01-15 20:08:56.696616450 +0100
-@@ -91,6 +91,7 @@
- 	gss_name_t name;
- 	struct ssh_gssapi_mech_struct *mech;
- 	ssh_gssapi_ccache store;
-+	gss_ctx_id_t context; /* needed for globus_gss_assist_map_and_authorize() */
- 	int used;
- 	int updated;
- } ssh_gssapi_client;
-@@ -111,7 +112,7 @@
- 	OM_uint32	minor; /* both */
- 	gss_ctx_id_t	context; /* both */
- 	gss_name_t	name; /* both */
--	gss_OID		oid; /* client */
-+	gss_OID		oid; /* both */
- 	gss_cred_id_t	creds; /* server */
- 	gss_name_t	client; /* server */
- 	gss_cred_id_t	client_creds; /* both */
-@@ -144,6 +145,9 @@
- OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
- int ssh_gssapi_credentials_updated(Gssctxt *);
- 
-+int ssh_gssapi_localname(char **name);
-+void ssh_gssapi_rekey_creds();
-+
- /* In the server */
- typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, 
-     const char *);
-@@ -154,7 +158,7 @@
- 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, struct passwd *);
-+int ssh_gssapi_userok(char *name, struct passwd *, int gssapi_keyex);
- 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);
-@@ -164,6 +168,7 @@
- int ssh_gssapi_oid_table_ok();
- 
- int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
-+void ssh_gssapi_get_client_info(char **userdn, char **mech);
- #endif /* GSSAPI */
- 
- #endif /* _SSH_GSS_H */
-diff -Nur openssh-6.6p1.orig/version.h openssh-6.6p1/version.h
---- openssh-6.6p1.orig/version.h	2015-01-15 20:08:13.065214492 +0100
-+++ openssh-6.6p1/version.h	2015-01-15 20:08:56.696616450 +0100
-@@ -1,6 +1,21 @@
- /* $OpenBSD: version.h,v 1.70 2014/02/27 22:57:40 djm Exp $ */
- 
-+#ifdef GSI
-+#define GSI_VERSION	" GSI"
-+#else
-+#define GSI_VERSION	""
-+#endif
-+
-+#ifdef KRB5
-+#define KRB5_VERSION	" KRB5"
-+#else
-+#define KRB5_VERSION	""
-+#endif
-+
-+#define NCSA_VERSION	" GSI_GSSAPI_20140522"
-+
- #define SSH_VERSION	"OpenSSH_6.6.1"
- 
- #define SSH_PORTABLE	"p1"
--#define SSH_RELEASE	SSH_VERSION SSH_PORTABLE
-+#define SSH_RELEASE	SSH_VERSION SSH_PORTABLE \
-+				    NCSA_VERSION GSI_VERSION KRB5_VERSION
diff --git a/openssh-6.6p1-gsskex.patch b/openssh-6.6p1-gsskex.patch
index 826acd4..42b6a10 100644
--- a/openssh-6.6p1-gsskex.patch
+++ b/openssh-6.6p1-gsskex.patch
@@ -1,31 +1,37 @@
-diff --git a/Makefile.in b/Makefile.in
-index 581b121..2ad26ff 100644
---- a/Makefile.in
-+++ b/Makefile.in
-@@ -77,6 +77,7 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \
- 	atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
+diff -up openssh-6.8p1/Makefile.in.gsskex openssh-6.8p1/Makefile.in
+--- openssh-6.8p1/Makefile.in.gsskex	2015-03-18 11:24:48.875900767 +0100
++++ openssh-6.8p1/Makefile.in	2015-03-18 12:34:36.468748216 +0100
+@@ -90,6 +90,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
+ 	readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \
+ 	atomicio.o key.o dispatch.o mac.o uidswap.o uuencode.o misc.o \
  	monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
- 	kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \
 +	kexgssc.o \
  	msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
- 	ssh-pkcs11.o krl.o smult_curve25519_ref.o \
- 	kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \
-@@ -96,7 +97,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
+ 	ssh-pkcs11.o smult_curve25519_ref.o \
+ 	poly1305.o chacha.o cipher-chachapoly.o \
+@@ -111,7 +112,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 kexdhs.o kexgexs.o kexecdhs.o \
- 	kexc25519s.o auth-krb5.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 \
  	roaming_common.o roaming_serv.o \
-diff --git a/auth2-gss.c b/auth2-gss.c
-index 4756dd7..ad65059 100644
---- a/auth2-gss.c
-+++ b/auth2-gss.c
-@@ -52,6 +52,40 @@ static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
- static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
- static void input_gssapi_errtok(int, u_int32_t, void *);
+diff -up openssh-6.8p1/auth2-gss.c.gsskex openssh-6.8p1/auth2-gss.c
+--- openssh-6.8p1/auth2-gss.c.gsskex	2015-03-18 11:24:48.832900869 +0100
++++ openssh-6.8p1/auth2-gss.c	2015-03-18 12:32:50.584011552 +0100
+@@ -31,6 +31,7 @@
+ #include <sys/types.h>
+ 
+ #include <stdarg.h>
++#include <string.h>
+ 
+ #include "xmalloc.h"
+ #include "key.h"
+@@ -53,6 +54,40 @@ static int input_gssapi_mic(int type, u_
+ static int input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
+ static int input_gssapi_errtok(int, u_int32_t, void *);
  
 +/* 
 + * The 'gssapi_keyex' userauth mechanism.
@@ -64,7 +70,7 @@ index 4756dd7..ad65059 100644
  /*
   * We only support those mechanisms that we know about (ie ones that we know
   * how to check local user kuserok and the like)
-@@ -235,7 +269,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
+@@ -238,7 +273,8 @@ input_gssapi_exchange_complete(int type,
  
  	packet_check_eom();
  
@@ -74,7 +80,7 @@ index 4756dd7..ad65059 100644
  
  	authctxt->postponed = 0;
  	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
-@@ -277,7 +312,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
+@@ -281,7 +317,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))))
@@ -84,8 +90,8 @@ index 4756dd7..ad65059 100644
  	else
  		logit("GSSAPI MIC check failed");
  
-@@ -294,6 +330,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
- 	userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
+@@ -299,6 +336,12 @@ input_gssapi_mic(int type, u_int32_t ple
+ 	return 0;
  }
  
 +Authmethod method_gsskeyex = {
@@ -97,11 +103,10 @@ index 4756dd7..ad65059 100644
  Authmethod method_gssapi = {
  	"gssapi-with-mic",
  	userauth_gssapi,
-diff --git a/auth2.c b/auth2.c
-index 5f4f26f..0f52b68 100644
---- a/auth2.c
-+++ b/auth2.c
-@@ -69,6 +69,7 @@ extern Authmethod method_passwd;
+diff -up openssh-6.8p1/auth2.c.gsskex openssh-6.8p1/auth2.c
+--- openssh-6.8p1/auth2.c.gsskex	2015-03-18 11:24:48.832900869 +0100
++++ openssh-6.8p1/auth2.c	2015-03-18 11:24:48.875900767 +0100
+@@ -70,6 +70,7 @@ extern Authmethod method_passwd;
  extern Authmethod method_kbdint;
  extern Authmethod method_hostbased;
  #ifdef GSSAPI
@@ -109,7 +114,7 @@ index 5f4f26f..0f52b68 100644
  extern Authmethod method_gssapi;
  #endif
  
-@@ -76,6 +77,7 @@ Authmethod *authmethods[] = {
+@@ -77,6 +78,7 @@ Authmethod *authmethods[] = {
  	&method_none,
  	&method_pubkey,
  #ifdef GSSAPI
@@ -117,13 +122,12 @@ index 5f4f26f..0f52b68 100644
  	&method_gssapi,
  #endif
  	&method_passwd,
-diff --git a/clientloop.c b/clientloop.c
-index 59ad3a2..9c60108 100644
---- a/clientloop.c
-+++ b/clientloop.c
-@@ -111,6 +111,10 @@
- #include "msg.h"
- #include "roaming.h"
+diff -up openssh-6.8p1/clientloop.c.gsskex openssh-6.8p1/clientloop.c
+--- openssh-6.8p1/clientloop.c.gsskex	2015-03-18 11:24:48.875900767 +0100
++++ openssh-6.8p1/clientloop.c	2015-03-18 12:30:42.647329654 +0100
+@@ -114,6 +114,10 @@
+ #include "ssherr.h"
+ #include "hostfile.h"
  
 +#ifdef GSSAPI
 +#include "ssh-gss.h"
@@ -132,7 +136,7 @@ index 59ad3a2..9c60108 100644
  /* import options */
  extern Options options;
  
-@@ -1608,6 +1612,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
+@@ -1596,6 +1600,15 @@ client_loop(int have_pty, int escape_cha
  		/* Do channel operations unless rekeying in progress. */
  		if (!rekeying) {
  			channel_after_select(readset, writeset);
@@ -147,12 +151,11 @@ index 59ad3a2..9c60108 100644
 +
  			if (need_rekeying || packet_need_rekeying()) {
  				debug("need rekeying");
- 				xxx_kex->done = 0;
-diff --git a/configure.ac b/configure.ac
-index 74e77db..9bde04e 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -584,6 +584,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
+ 				active_state->kex->done = 0;
+diff -up openssh-6.8p1/configure.ac.gsskex openssh-6.8p1/configure.ac
+--- openssh-6.8p1/configure.ac.gsskex	2015-03-18 11:24:48.866900788 +0100
++++ openssh-6.8p1/configure.ac	2015-03-18 11:24:48.876900765 +0100
+@@ -620,6 +620,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])
@@ -183,11 +186,10 @@ index 74e77db..9bde04e 100644
  	m4_pattern_allow([AU_IPv])
  	AC_CHECK_DECL([AU_IPv4], [], 
  	    AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records])
-diff --git a/gss-genr.c b/gss-genr.c
-index b39281b..a3a2289 100644
---- a/gss-genr.c
-+++ b/gss-genr.c
-@@ -39,12 +39,167 @@
+diff -up openssh-6.8p1/gss-genr.c.gsskex openssh-6.8p1/gss-genr.c
+--- openssh-6.8p1/gss-genr.c.gsskex	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/gss-genr.c	2015-03-18 11:24:48.876900765 +0100
+@@ -40,12 +40,167 @@
  #include "buffer.h"
  #include "log.h"
  #include "ssh2.h"
@@ -355,7 +357,7 @@ index b39281b..a3a2289 100644
  /* 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)
-@@ -197,7 +352,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
+@@ -198,7 +353,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int de
  	}
  
  	ctx->major = gss_init_sec_context(&ctx->minor,
@@ -364,7 +366,7 @@ index b39281b..a3a2289 100644
  	    GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
  	    0, NULL, recv_tok, NULL, send_tok, flags, NULL);
  
-@@ -227,8 +382,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
+@@ -228,8 +383,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, con
  }
  
  OM_uint32
@@ -407,7 +409,7 @@ index b39281b..a3a2289 100644
  	if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
  	    GSS_C_QOP_DEFAULT, buffer, hash)))
  		ssh_gssapi_error(ctx);
-@@ -236,6 +425,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
+@@ -237,6 +426,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer
  	return (ctx->major);
  }
  
@@ -427,7 +429,7 @@ index b39281b..a3a2289 100644
  void
  ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
      const char *context)
-@@ -249,11 +451,16 @@ ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
+@@ -250,11 +452,16 @@ ssh_gssapi_buildmic(Buffer *b, const cha
  }
  
  int
@@ -445,7 +447,7 @@ index b39281b..a3a2289 100644
  
  	/* RFC 4462 says we MUST NOT do SPNEGO */
  	if (oid->length == spnego_oid.length && 
-@@ -263,6 +470,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
+@@ -264,6 +471,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);
@@ -456,7 +458,7 @@ index b39281b..a3a2289 100644
  	if (!GSS_ERROR(major)) {
  		major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, 
  		    NULL);
-@@ -272,10 +483,67 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
+@@ -273,10 +484,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx
  			    GSS_C_NO_BUFFER);
  	}
  
@@ -476,7 +478,6 @@ index b39281b..a3a2289 100644
 +	static OM_uint32 last_call = 0;
 +	OM_uint32 lifetime, now, major, minor;
 +	int equal;
-+	gss_cred_usage_t usage = GSS_C_INITIATE;
 +	
 +	now = time(NULL);
 +
@@ -525,11 +526,10 @@ index b39281b..a3a2289 100644
 +}
 +
  #endif /* GSSAPI */
-diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
-index 759fa10..42de994 100644
---- a/gss-serv-krb5.c
-+++ b/gss-serv-krb5.c
-@@ -120,7 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
+diff -up openssh-6.8p1/gss-serv-krb5.c.gsskex openssh-6.8p1/gss-serv-krb5.c
+--- openssh-6.8p1/gss-serv-krb5.c.gsskex	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/gss-serv-krb5.c	2015-03-18 11:24:48.876900765 +0100
+@@ -121,7 +121,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
  	krb5_error_code problem;
  	krb5_principal princ;
  	OM_uint32 maj_status, min_status;
@@ -538,7 +538,7 @@ index 759fa10..42de994 100644
  	const char *errmsg;
  
  	if (client->creds == NULL) {
-@@ -180,11 +180,26 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
+@@ -181,11 +181,26 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
  		return;
  	}
  
@@ -569,7 +569,7 @@ index 759fa10..42de994 100644
  
  #ifdef USE_PAM
  	if (options.use_pam)
-@@ -193,9 +208,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
+@@ -194,9 +209,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
  
  	krb5_cc_close(krb_context, ccache);
  
@@ -646,7 +646,7 @@ index 759fa10..42de994 100644
  ssh_gssapi_mech gssapi_kerberos_mech = {
  	"toWM5Slw5Ew8Mqkay+al2g==",
  	"Kerberos",
-@@ -203,7 +285,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = {
+@@ -204,7 +286,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = {
  	NULL,
  	&ssh_gssapi_krb5_userok,
  	NULL,
@@ -656,11 +656,10 @@ index 759fa10..42de994 100644
  };
  
  #endif /* KRB5 */
-diff --git a/gss-serv.c b/gss-serv.c
-index e61b37b..14f540e 100644
---- a/gss-serv.c
-+++ b/gss-serv.c
-@@ -45,15 +45,20 @@
+diff -up openssh-6.8p1/gss-serv.c.gsskex openssh-6.8p1/gss-serv.c
+--- openssh-6.8p1/gss-serv.c.gsskex	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/gss-serv.c	2015-03-18 11:24:48.877900762 +0100
+@@ -44,15 +44,20 @@
  #include "channels.h"
  #include "session.h"
  #include "misc.h"
@@ -683,54 +682,55 @@ index e61b37b..14f540e 100644
  
  #ifdef KRB5
  extern ssh_gssapi_mech gssapi_kerberos_mech;
-@@ -100,25 +105,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx)
- 	char lname[MAXHOSTNAMELEN];
+@@ -99,25 +104,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx)
+ 	char lname[NI_MAXHOST];
  	gss_OID_set oidset;
  
 -	gss_create_empty_oid_set(&status, &oidset);
 -	gss_add_oid_set_member(&status, ctx->oid, &oidset);
-+	if (options.gss_strict_acceptor) {
-+		gss_create_empty_oid_set(&status, &oidset);
-+		gss_add_oid_set_member(&status, ctx->oid, &oidset);
- 
--	if (gethostname(lname, MAXHOSTNAMELEN)) {
+-
+-	if (gethostname(lname, sizeof(lname))) {
 -		gss_release_oid_set(&status, &oidset);
 -		return (-1);
 -	}
-+		if (gethostname(lname, MAXHOSTNAMELEN)) {
++	if (options.gss_strict_acceptor) {
++		gss_create_empty_oid_set(&status, &oidset);
++		gss_add_oid_set_member(&status, ctx->oid, &oidset);
++
++		if (gethostname(lname, sizeof(lname))) {
 +			gss_release_oid_set(&status, &oidset);
 +			return (-1);
 +		}
-+
++	
 +		if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
 +			gss_release_oid_set(&status, &oidset);
 +			return (ctx->major);
 +		}
-+
++	
 +		if ((ctx->major = gss_acquire_cred(&ctx->minor,
-+		    ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, 
-+		    NULL, NULL)))
++		    ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
 +			ssh_gssapi_error(ctx);
  
 -	if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
  		gss_release_oid_set(&status, &oidset);
  		return (ctx->major);
+-	}
 +	} else {
 +		ctx->name = GSS_C_NO_NAME;
 +		ctx->creds = GSS_C_NO_CREDENTIAL;
- 	}
--
++		return GSS_S_COMPLETE;
++ 	}
+ 
 -	if ((ctx->major = gss_acquire_cred(&ctx->minor,
 -	    ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
 -		ssh_gssapi_error(ctx);
 -
 -	gss_release_oid_set(&status, &oidset);
 -	return (ctx->major);
-+	return GSS_S_COMPLETE;
  }
  
  /* Privileged */
-@@ -133,6 +145,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
+@@ -132,6 +144,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss
  }
  
  /* Unprivileged */
@@ -760,7 +760,7 @@ index e61b37b..14f540e 100644
  void
  ssh_gssapi_supported_oids(gss_OID_set *oidset)
  {
-@@ -142,7 +177,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset)
+@@ -141,7 +176,9 @@ ssh_gssapi_supported_oids(gss_OID_set *o
  	gss_OID_set supported;
  
  	gss_create_empty_oid_set(&min_status, oidset);
@@ -771,7 +771,7 @@ index e61b37b..14f540e 100644
  
  	while (supported_mechs[i]->name != NULL) {
  		if (GSS_ERROR(gss_test_oid_set_member(&min_status,
-@@ -268,8 +305,48 @@ OM_uint32
+@@ -267,8 +304,48 @@ OM_uint32
  ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
  {
  	int i = 0;
@@ -793,11 +793,11 @@ index e61b37b..14f540e 100644
 +			ssh_gssapi_error(ctx);
 +			return (ctx->major);
 +		}
-+
-+		ctx->major = gss_compare_name(&ctx->minor, client->name, 
-+		    new_name, &equal);
  
 -	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);
@@ -821,7 +821,7 @@ index e61b37b..14f540e 100644
  
  	client->mech = NULL;
  
-@@ -284,6 +361,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
+@@ -283,6 +360,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
  	if (client->mech == NULL)
  		return GSS_S_FAILURE;
  
@@ -835,7 +835,7 @@ index e61b37b..14f540e 100644
  	if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
  	    &client->displayname, NULL))) {
  		ssh_gssapi_error(ctx);
-@@ -301,6 +385,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
+@@ -300,6 +384,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
  		return (ctx->major);
  	}
  
@@ -844,7 +844,7 @@ index e61b37b..14f540e 100644
  	/* 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;
-@@ -311,11 +397,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
+@@ -310,11 +396,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
  void
  ssh_gssapi_cleanup_creds(void)
  {
@@ -870,7 +870,7 @@ index e61b37b..14f540e 100644
  	}
  }
  
-@@ -348,7 +443,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep)
+@@ -347,7 +442,7 @@ ssh_gssapi_do_child(char ***envp, u_int
  
  /* Privileged */
  int
@@ -879,7 +879,7 @@ index e61b37b..14f540e 100644
  {
  	OM_uint32 lmin;
  
-@@ -358,9 +453,11 @@ ssh_gssapi_userok(char *user)
+@@ -357,9 +452,11 @@ ssh_gssapi_userok(char *user)
  		return 0;
  	}
  	if (gssapi_client.mech && gssapi_client.mech->userok)
@@ -893,7 +893,7 @@ index e61b37b..14f540e 100644
  			/* Destroy delegated credentials if userok fails */
  			gss_release_buffer(&lmin, &gssapi_client.displayname);
  			gss_release_buffer(&lmin, &gssapi_client.exportedname);
-@@ -374,14 +471,90 @@ ssh_gssapi_userok(char *user)
+@@ -373,14 +470,90 @@ ssh_gssapi_userok(char *user)
  	return (0);
  }
  
@@ -990,12 +990,11 @@ index e61b37b..14f540e 100644
  }
  
  #endif
-diff --git a/kex.c b/kex.c
-index 74e2b86..bce2ab8 100644
---- a/kex.c
-+++ b/kex.c
-@@ -51,6 +51,10 @@
- #include "roaming.h"
+diff -up openssh-6.8p1/kex.c.gsskex openssh-6.8p1/kex.c
+--- openssh-6.8p1/kex.c.gsskex	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/kex.c	2015-03-18 12:29:33.452501699 +0100
+@@ -55,6 +55,10 @@
+ #include "sshbuf.h"
  #include "digest.h"
  
 +#ifdef GSSAPI
@@ -1005,10 +1004,10 @@ index 74e2b86..bce2ab8 100644
  #if OPENSSL_VERSION_NUMBER >= 0x00907000L
  # if defined(HAVE_EVP_SHA256)
  # define evp_ssh_sha256 EVP_sha256
-@@ -90,6 +94,11 @@ static const struct kexalg kexalgs[] = {
- #ifdef HAVE_EVP_SHA256
+@@ -95,6 +99,11 @@ static const struct kexalg kexalgs[] = {
+ #if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL)
  	{ KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
- #endif
+ #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
 +#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 },
@@ -1017,7 +1016,7 @@ index 74e2b86..bce2ab8 100644
  	{ NULL, -1, -1, -1},
  };
  
-@@ -119,6 +128,12 @@ kex_alg_by_name(const char *name)
+@@ -128,6 +137,12 @@ kex_alg_by_name(const char *name)
  	for (k = kexalgs; k->name != NULL; k++) {
  		if (strcmp(k->name, name) == 0)
  			return k;
@@ -1030,11 +1029,10 @@ index 74e2b86..bce2ab8 100644
  	}
  	return NULL;
  }
-diff --git a/kex.h b/kex.h
-index c85680e..313bb51 100644
---- a/kex.h
-+++ b/kex.h
-@@ -76,6 +76,11 @@ enum kex_exchange {
+diff -up openssh-6.8p1/kex.h.gsskex openssh-6.8p1/kex.h
+--- openssh-6.8p1/kex.h.gsskex	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/kex.h	2015-03-18 12:28:17.600690296 +0100
+@@ -93,6 +93,11 @@ enum kex_exchange {
  	KEX_DH_GEX_SHA256,
  	KEX_ECDH_SHA2,
  	KEX_C25519_SHA256,
@@ -1046,8 +1044,8 @@ index c85680e..313bb51 100644
  	KEX_MAX
  };
  
-@@ -135,6 +140,12 @@ struct Kex {
- 	int	flags;
+@@ -139,6 +144,12 @@ struct kex {
+ 	u_int	flags;
  	int	hash_alg;
  	int	ec_nid;
 +#ifdef GSSAPI
@@ -1058,24 +1056,22 @@ index c85680e..313bb51 100644
 +#endif
  	char	*client_version_string;
  	char	*server_version_string;
- 	int	(*verify_host_key)(Key *);
-@@ -166,6 +177,10 @@ void	 kexecdh_client(Kex *);
- void	 kexecdh_server(Kex *);
- void	 kexc25519_client(Kex *);
- void	 kexc25519_server(Kex *);
+ 	int	(*verify_host_key)(struct sshkey *, struct ssh *);
+@@ -183,6 +194,10 @@ int	 kexecdh_client(struct ssh *);
+ int	 kexecdh_server(struct ssh *);
+ int	 kexc25519_client(struct ssh *);
+ int	 kexc25519_server(struct ssh *);
 +#ifdef GSSAPI
-+void	 kexgss_client(Kex *);
-+void	 kexgss_server(Kex *);
++int	 kexgss_client(struct ssh *);
++int	 kexgss_server(struct ssh *);
 +#endif
  
- void
- kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
-diff --git a/kexgssc.c b/kexgssc.c
-new file mode 100644
-index 0000000..e90b567
---- /dev/null
-+++ b/kexgssc.c
-@@ -0,0 +1,334 @@
+ int	 kex_dh_hash(const char *, const char *,
+     const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
+diff -up openssh-6.8p1/kexgssc.c.gsskex openssh-6.8p1/kexgssc.c
+--- openssh-6.8p1/kexgssc.c.gsskex	2015-03-18 11:24:48.877900762 +0100
++++ openssh-6.8p1/kexgssc.c	2015-03-18 11:24:48.877900762 +0100
+@@ -0,0 +1,338 @@
 +/*
 + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
 + *
@@ -1120,22 +1116,23 @@ index 0000000..e90b567
 +#include "log.h"
 +#include "packet.h"
 +#include "dh.h"
++#include "digest.h"
 +
 +#include "ssh-gss.h"
 +
-+void
-+kexgss_client(Kex *kex) {
++int
++kexgss_client(struct ssh *ssh) {
 +	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
 +	gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
 +	Gssctxt *ctxt;
 +	OM_uint32 maj_status, min_status, ret_flags;
-+	u_int klen, kout, slen = 0, hashlen, strlen;
++	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, *hash;
++	u_char *kbuf;
 +	u_char *serverhostkey = NULL;
 +	u_char *empty = "";
 +	char *msg;
@@ -1143,21 +1140,23 @@ index 0000000..e90b567
 +	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) 
++	if (ssh_gssapi_id_kex(ctxt, ssh->kex->name, ssh->kex->kex_type) 
 +	    == GSS_C_NO_OID)
 +		fatal("Couldn't identify host exchange");
 +
-+	if (ssh_gssapi_import_name(ctxt, kex->gss_host))
++	if (ssh_gssapi_import_name(ctxt, ssh->kex->gss_host))
 +		fatal("Couldn't import hostname");
 +
-+	if (kex->gss_client && 
-+	    ssh_gssapi_client_identity(ctxt, kex->gss_client))
++	if (ssh->kex->gss_client && 
++	    ssh_gssapi_client_identity(ctxt, ssh->kex->gss_client))
 +		fatal("Couldn't acquire client credentials");
 +
-+	switch (kex->kex_type) {
++	switch (ssh->kex->kex_type) {
 +	case KEX_GSS_GRP1_SHA1:
 +		dh = dh_new_group1();
 +		break;
@@ -1166,7 +1165,7 @@ index 0000000..e90b567
 +		break;
 +	case KEX_GSS_GEX_SHA1:
 +		debug("Doing group exchange\n");
-+		nbits = dh_estimate(kex->we_need * 8);
++		nbits = dh_estimate(ssh->kex->we_need * 8);
 +		packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
 +		packet_put_int(min);
 +		packet_put_int(nbits);
@@ -1191,11 +1190,11 @@ index 0000000..e90b567
 +		dh = dh_new_group(g, p);
 +		break;
 +	default:
-+		fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
++		fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type);
 +	}
 +	
 +	/* Step 1 - e is dh->pub_key */
-+	dh_gen_key(dh, kex->we_need * 8);
++	dh_gen_key(dh, ssh->kex->we_need * 8);
 +
 +	/* This is f, we initialise it now to make life easier */
 +	dh_server_pub = BN_new();
@@ -1208,7 +1207,7 @@ index 0000000..e90b567
 +		debug("Calling gss_init_sec_context");
 +		
 +		maj_status = ssh_gssapi_init_ctx(ctxt,
-+		    kex->gss_deleg_creds, token_ptr, &send_tok,
++		    ssh->kex->gss_deleg_creds, token_ptr, &send_tok,
 +		    &ret_flags);
 +
 +		if (GSS_ERROR(maj_status)) {
@@ -1341,38 +1340,39 @@ index 0000000..e90b567
 +	memset(kbuf, 0, klen);
 +	free(kbuf);
 +
-+	switch (kex->kex_type) {
++	hashlen = sizeof(hash);
++	switch (ssh->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),
++		kex_dh_hash( ssh->kex->client_version_string, 
++		    ssh->kex->server_version_string,
++		    buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my),
++		    buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer),
 +		    (serverhostkey ? serverhostkey : empty), slen,
 +		    dh->pub_key,	/* e */
 +		    dh_server_pub,	/* f */
 +		    shared_secret,	/* K */
-+		    &hash, &hashlen
++		    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),
++		    ssh->kex->hash_alg,
++		    ssh->kex->client_version_string,
++		    ssh->kex->server_version_string,
++		    buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my),
++		    buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer),
 +		    (serverhostkey ? serverhostkey : empty), slen,
 + 		    min, nbits, max,
 +		    dh->p, dh->g,
 +		    dh->pub_key,
 +		    dh_server_pub,
 +		    shared_secret,
-+		    &hash, &hashlen
++		    hash, &hashlen
 +		);
 +		break;
 +	default:
-+		fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
++		fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type);
 +	}
 +
 +	gssbuf.value = hash;
@@ -1390,13 +1390,13 @@ index 0000000..e90b567
 +	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 (ssh->kex->session_id == NULL) {
++		ssh->kex->session_id_len = hashlen;
++		ssh->kex->session_id = xmalloc(ssh->kex->session_id_len);
++		memcpy(ssh->kex->session_id, hash, ssh->kex->session_id_len);
 +	}
 +
-+	if (kex->gss_deleg_creds)
++	if (ssh->kex->gss_deleg_creds)
 +		ssh_gssapi_credentials_updated(ctxt);
 +
 +	if (gss_kex_context == NULL)
@@ -1404,18 +1404,16 @@ index 0000000..e90b567
 +	else
 +		ssh_gssapi_delete_ctx(&ctxt);
 +
-+	kex_derive_keys_bn(kex, hash, hashlen, shared_secret);
++	kex_derive_keys_bn(ssh, hash, hashlen, shared_secret);
 +	BN_clear_free(shared_secret);
-+	kex_finish(kex);
++	return kex_send_newkeys(ssh);
 +}
 +
 +#endif /* GSSAPI */
-diff --git a/kexgsss.c b/kexgsss.c
-new file mode 100644
-index 0000000..6d7518c
---- /dev/null
-+++ b/kexgsss.c
-@@ -0,0 +1,288 @@
+diff -up openssh-6.8p1/kexgsss.c.gsskex openssh-6.8p1/kexgsss.c
+--- openssh-6.8p1/kexgsss.c.gsskex	2015-03-18 11:24:48.878900760 +0100
++++ openssh-6.8p1/kexgsss.c	2015-03-18 11:24:48.878900760 +0100
+@@ -0,0 +1,295 @@
 +/*
 + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
 + *
@@ -1460,12 +1458,15 @@ index 0000000..6d7518c
 +#include "dh.h"
 +#include "ssh-gss.h"
 +#include "monitor_wrap.h"
++#include "misc.h"      /* servconf.h needs misc.h for struct ForwardOptions */
 +#include "servconf.h"
++#include "ssh-gss.h"
++#include "digest.h"
 +
 +extern ServerOptions options;
 +
-+void
-+kexgss_server(Kex *kex)
++int
++kexgss_server(struct ssh *ssh)
 +{
 +	OM_uint32 maj_status, min_status;
 +	
@@ -1480,8 +1481,8 @@ index 0000000..6d7518c
 +	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, hashlen;
-+	u_char *kbuf, *hash;
++	u_int slen, klen, kout;
++	u_char *kbuf;
 +	DH *dh;
 +	int min = -1, max = -1, nbits = -1;
 +	BIGNUM *shared_secret = NULL;
@@ -1489,6 +1490,8 @@ index 0000000..6d7518c
 +	int type = 0;
 +	gss_OID oid;
 +	char *mechs;
++	u_char hash[SSH_DIGEST_MAX_LENGTH];
++	size_t hashlen;
 +
 +	/* Initialise GSSAPI */
 +
@@ -1500,8 +1503,8 @@ index 0000000..6d7518c
 +		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);
++	debug2("%s: Identifying %s", __func__, ssh->kex->name);
++	oid = ssh_gssapi_id_kex(NULL, ssh->kex->name, ssh->kex->kex_type);
 +	if (oid == GSS_C_NO_OID)
 +	   fatal("Unknown gssapi mechanism");
 +
@@ -1510,7 +1513,7 @@ index 0000000..6d7518c
 +	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
 +		fatal("Unable to acquire credentials for the server");
 +
-+	switch (kex->kex_type) {
++	switch (ssh->kex->kex_type) {
 +	case KEX_GSS_GRP1_SHA1:
 +		dh = dh_new_group1();
 +		break;
@@ -1541,10 +1544,10 @@ index 0000000..6d7518c
 +		packet_write_wait();
 +		break;
 +	default:
-+		fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
++		fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type);
 +	}
 +
-+	dh_gen_key(dh, kex->we_need * 8);
++	dh_gen_key(dh, ssh->kex->we_need * 8);
 +
 +	do {
 +		debug("Wait SSH2_MSG_GSSAPI_INIT");
@@ -1627,43 +1630,44 @@ index 0000000..6d7518c
 +	memset(kbuf, 0, klen);
 +	free(kbuf);
 +
-+	switch (kex->kex_type) {
++	hashlen = sizeof(hash);
++	switch (ssh->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),
++		    ssh->kex->client_version_string, ssh->kex->server_version_string,
++		    buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer),
++		    buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my),
 +		    NULL, 0, /* Change this if we start sending host keys */
 +		    dh_client_pub, dh->pub_key, shared_secret,
-+		    &hash, &hashlen
++		    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),
++		    ssh->kex->hash_alg,
++		    ssh->kex->client_version_string, ssh->kex->server_version_string,
++		    buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer),
++		    buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my),
 +		    NULL, 0,
 +		    min, nbits, max,
 +		    dh->p, dh->g,
 +		    dh_client_pub,
 +		    dh->pub_key,
 +		    shared_secret,
-+		    &hash, &hashlen
++		    hash, &hashlen
 +		);
 +		break;
 +	default:
-+		fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
++		fatal("%s: Unexpected KEX type %d", __func__, ssh->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);
++	if (ssh->kex->session_id == NULL) {
++		ssh->kex->session_id_len = hashlen;
++		ssh->kex->session_id = xmalloc(ssh->kex->session_id_len);
++		memcpy(ssh->kex->session_id, hash, ssh->kex->session_id_len);
 +	}
 +
 +	gssbuf.value = hash;
@@ -1694,45 +1698,21 @@ index 0000000..6d7518c
 +
 +	DH_free(dh);
 +
-+	kex_derive_keys_bn(kex, hash, hashlen, shared_secret);
++	kex_derive_keys_bn(ssh, hash, hashlen, shared_secret);
 +	BN_clear_free(shared_secret);
-+	kex_finish(kex);
++	kex_send_newkeys(ssh);
 +
 +	/* If this was a rekey, then save out any delegated credentials we
 +	 * just exchanged.  */
 +	if (options.gss_store_rekey)
 +		ssh_gssapi_rekey_creds();
++	return 0;
 +}
 +#endif /* GSSAPI */
-diff --git a/key.c b/key.c
-index eb98ea8..900b9e3 100644
---- a/key.c
-+++ b/key.c
-@@ -1013,6 +1013,7 @@ static const struct keytype keytypes[] = {
- 	    KEY_DSA_CERT_V00, 0, 1 },
- 	{ "ssh-ed25519-cert-v01 at openssh.com", "ED25519-CERT",
- 	    KEY_ED25519_CERT, 0, 1 },
-+	{ "null", "null", KEY_NULL, 0, 0 },
- 	{ NULL, NULL, -1, -1, 0 }
- };
- 
-diff --git a/key.h b/key.h
-index 0e3eea5..d51ed81 100644
---- a/key.h
-+++ b/key.h
-@@ -46,6 +46,7 @@ enum types {
- 	KEY_ED25519_CERT,
- 	KEY_RSA_CERT_V00,
- 	KEY_DSA_CERT_V00,
-+	KEY_NULL,
- 	KEY_UNSPEC
- };
- enum fp_type {
-diff --git a/monitor.c b/monitor.c
-index 229fada..aa70945 100644
---- a/monitor.c
-+++ b/monitor.c
-@@ -178,6 +178,8 @@ int mm_answer_gss_setup_ctx(int, Buffer *);
+diff -up openssh-6.8p1/monitor.c.gsskex openssh-6.8p1/monitor.c
+--- openssh-6.8p1/monitor.c.gsskex	2015-03-18 11:24:48.834900865 +0100
++++ openssh-6.8p1/monitor.c	2015-03-18 12:24:38.971233895 +0100
+@@ -160,6 +160,8 @@ int mm_answer_gss_setup_ctx(int, Buffer
  int mm_answer_gss_accept_ctx(int, Buffer *);
  int mm_answer_gss_userok(int, Buffer *);
  int mm_answer_gss_checkmic(int, Buffer *);
@@ -1741,7 +1721,7 @@ index 229fada..aa70945 100644
  #endif
  
  #ifdef SSH_AUDIT_EVENTS
-@@ -253,11 +255,18 @@ struct mon_table mon_dispatch_proto20[] = {
+@@ -240,11 +242,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},
@@ -1757,10 +1737,10 @@ index 229fada..aa70945 100644
 +    {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},
-     {MONITOR_REQ_SIGN, 0, mm_answer_sign},
-     {MONITOR_REQ_PTY, 0, mm_answer_pty},
-@@ -366,6 +375,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
+ #endif
+@@ -359,6 +368,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);
@@ -1771,7 +1751,7 @@ index 229fada..aa70945 100644
  	} else {
  		mon_dispatch = mon_dispatch_proto15;
  
-@@ -471,6 +484,10 @@ monitor_child_postauth(struct monitor *pmonitor)
+@@ -467,6 +480,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);
@@ -1782,10 +1762,10 @@ index 229fada..aa70945 100644
  	} else {
  		mon_dispatch = mon_dispatch_postauth15;
  		monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
-@@ -1866,6 +1883,13 @@ mm_get_kex(Buffer *m)
- 	kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
- 	kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
- 	kex->kex[KEX_C25519_SHA256] = kexc25519_server;
+@@ -1892,6 +1909,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;
@@ -1793,10 +1773,10 @@ index 229fada..aa70945 100644
 +		kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
 +	}
 +#endif
- 	kex->server = 1;
- 	kex->hostkey_type = buffer_get_int(m);
- 	kex->kex_type = buffer_get_int(m);
-@@ -2073,6 +2097,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer *m)
+ 		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;
+@@ -1991,6 +2015,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer
  	OM_uint32 major;
  	u_int len;
  
@@ -1806,7 +1786,7 @@ index 229fada..aa70945 100644
  	goid.elements = buffer_get_string(m, &len);
  	goid.length = len;
  
-@@ -2100,6 +2127,9 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
+@@ -2018,6 +2045,9 @@ mm_answer_gss_accept_ctx(int sock, Buffe
  	OM_uint32 flags = 0; /* GSI needs this */
  	u_int len;
  
@@ -1816,7 +1796,7 @@ index 229fada..aa70945 100644
  	in.value = buffer_get_string(m, &len);
  	in.length = len;
  	major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
-@@ -2117,6 +2147,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
+@@ -2035,6 +2065,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);
@@ -1824,7 +1804,7 @@ index 229fada..aa70945 100644
  	}
  	return (0);
  }
-@@ -2128,6 +2159,9 @@ mm_answer_gss_checkmic(int sock, Buffer *m)
+@@ -2046,6 +2077,9 @@ mm_answer_gss_checkmic(int sock, Buffer
  	OM_uint32 ret;
  	u_int len;
  
@@ -1834,7 +1814,7 @@ index 229fada..aa70945 100644
  	gssbuf.value = buffer_get_string(m, &len);
  	gssbuf.length = len;
  	mic.value = buffer_get_string(m, &len);
-@@ -2154,7 +2188,11 @@ mm_answer_gss_userok(int sock, Buffer *m)
+@@ -2072,7 +2106,11 @@ mm_answer_gss_userok(int sock, Buffer *m
  {
  	int authenticated;
  
@@ -1847,7 +1827,7 @@ index 229fada..aa70945 100644
  
  	buffer_clear(m);
  	buffer_put_int(m, authenticated);
-@@ -2167,5 +2205,73 @@ mm_answer_gss_userok(int sock, Buffer *m)
+@@ -2085,5 +2123,73 @@ mm_answer_gss_userok(int sock, Buffer *m
  	/* Monitor loop will terminate if authenticated */
  	return (authenticated);
  }
@@ -1921,10 +1901,9 @@ index 229fada..aa70945 100644
 +
  #endif /* GSSAPI */
  
-diff --git a/monitor.h b/monitor.h
-index 20e2b4a..ff79fbb 100644
---- a/monitor.h
-+++ b/monitor.h
+diff -up openssh-6.8p1/monitor.h.gsskex openssh-6.8p1/monitor.h
+--- openssh-6.8p1/monitor.h.gsskex	2015-03-18 11:24:48.834900865 +0100
++++ openssh-6.8p1/monitor.h	2015-03-18 11:24:48.878900760 +0100
 @@ -60,6 +60,8 @@ enum monitor_reqtype {
  #ifdef WITH_SELINUX
  	MONITOR_REQ_AUTHROLE = 80,
@@ -1934,11 +1913,10 @@ index 20e2b4a..ff79fbb 100644
  
  	MONITOR_REQ_PAM_START = 100,
  	MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103,
-diff --git a/monitor_wrap.c b/monitor_wrap.c
-index d1b6d99..d1e1caa 100644
---- a/monitor_wrap.c
-+++ b/monitor_wrap.c
-@@ -1290,7 +1290,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
+diff -up openssh-6.8p1/monitor_wrap.c.gsskex openssh-6.8p1/monitor_wrap.c
+--- openssh-6.8p1/monitor_wrap.c.gsskex	2015-03-18 11:24:48.834900865 +0100
++++ openssh-6.8p1/monitor_wrap.c	2015-03-18 11:24:48.878900760 +0100
+@@ -1087,7 +1087,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss
  }
  
  int
@@ -1947,7 +1925,7 @@ index d1b6d99..d1e1caa 100644
  {
  	Buffer m;
  	int authenticated = 0;
-@@ -1307,5 +1307,50 @@ mm_ssh_gssapi_userok(char *user)
+@@ -1104,5 +1104,50 @@ mm_ssh_gssapi_userok(char *user)
  	debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
  	return (authenticated);
  }
@@ -1998,11 +1976,10 @@ index d1b6d99..d1e1caa 100644
 +
  #endif /* GSSAPI */
  
-diff --git a/monitor_wrap.h b/monitor_wrap.h
-index 9d5e5ba..93929e0 100644
---- a/monitor_wrap.h
-+++ b/monitor_wrap.h
-@@ -61,8 +61,10 @@ BIGNUM *mm_auth_rsa_generate_challenge(Key *);
+diff -up openssh-6.8p1/monitor_wrap.h.gsskex openssh-6.8p1/monitor_wrap.h
+--- openssh-6.8p1/monitor_wrap.h.gsskex	2015-03-18 11:24:48.834900865 +0100
++++ openssh-6.8p1/monitor_wrap.h	2015-03-18 11:24:48.878900760 +0100
+@@ -61,8 +61,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 *);
@@ -2014,11 +1991,10 @@ index 9d5e5ba..93929e0 100644
  #endif
  
  #ifdef USE_PAM
-diff --git a/readconf.c b/readconf.c
-index dc884c9..7613ff2 100644
---- a/readconf.c
-+++ b/readconf.c
-@@ -141,6 +141,8 @@ typedef enum {
+diff -up openssh-6.8p1/readconf.c.gsskex openssh-6.8p1/readconf.c
+--- openssh-6.8p1/readconf.c.gsskex	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/readconf.c	2015-03-18 11:24:48.879900758 +0100
+@@ -147,6 +147,8 @@ typedef enum {
  	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
  	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
  	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
@@ -2027,7 +2003,7 @@ index dc884c9..7613ff2 100644
  	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
  	oSendEnv, oControlPath, oControlMaster, oControlPersist,
  	oHashKnownHosts,
-@@ -183,10 +185,19 @@ static struct {
+@@ -191,10 +193,19 @@ static struct {
  	{ "afstokenpassing", oUnsupported },
  #if defined(GSSAPI)
  	{ "gssapiauthentication", oGssAuthentication },
@@ -2047,7 +2023,7 @@ index dc884c9..7613ff2 100644
  #endif
  	{ "fallbacktorsh", oDeprecated },
  	{ "usersh", oDeprecated },
-@@ -841,10 +852,30 @@ parse_time:
+@@ -892,10 +903,30 @@ parse_time:
  		intptr = &options->gss_authentication;
  		goto parse_flag;
  
@@ -2078,7 +2054,7 @@ index dc884c9..7613ff2 100644
  	case oBatchMode:
  		intptr = &options->batch_mode;
  		goto parse_flag;
-@@ -1497,7 +1528,12 @@ initialize_options(Options * options)
+@@ -1601,7 +1632,12 @@ initialize_options(Options * options)
  	options->pubkey_authentication = -1;
  	options->challenge_response_authentication = -1;
  	options->gss_authentication = -1;
@@ -2091,7 +2067,7 @@ index dc884c9..7613ff2 100644
  	options->password_authentication = -1;
  	options->kbd_interactive_authentication = -1;
  	options->kbd_interactive_devices = NULL;
-@@ -1616,8 +1652,14 @@ fill_default_options(Options * options)
+@@ -1728,8 +1764,14 @@ fill_default_options(Options * options)
  		options->challenge_response_authentication = 1;
  	if (options->gss_authentication == -1)
  		options->gss_authentication = 0;
@@ -2106,11 +2082,10 @@ index dc884c9..7613ff2 100644
  	if (options->password_authentication == -1)
  		options->password_authentication = 1;
  	if (options->kbd_interactive_authentication == -1)
-diff --git a/readconf.h b/readconf.h
-index 75e3f8f..5cc97f0 100644
---- a/readconf.h
-+++ b/readconf.h
-@@ -54,7 +54,12 @@ typedef struct {
+diff -up openssh-6.8p1/readconf.h.gsskex openssh-6.8p1/readconf.h
+--- openssh-6.8p1/readconf.h.gsskex	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/readconf.h	2015-03-18 11:24:48.879900758 +0100
+@@ -45,7 +45,12 @@ typedef struct {
  	int     challenge_response_authentication;
  					/* Try S/Key or TIS, authentication. */
  	int     gss_authentication;	/* Try GSS authentication */
@@ -2123,23 +2098,21 @@ index 75e3f8f..5cc97f0 100644
  	int     password_authentication;	/* Try password
  						 * authentication. */
  	int     kbd_interactive_authentication; /* Try keyboard-interactive auth. */
-diff --git a/regress/cert-hostkey.sh b/regress/cert-hostkey.sh
-index 1d9e0ed..1277409 100644
---- a/regress/cert-hostkey.sh
-+++ b/regress/cert-hostkey.sh
-@@ -17,7 +17,7 @@ ${SSHKEYGEN} -q -N '' -t rsa  -f $OBJ/host_ca_key ||\
- 	cat $OBJ/host_ca_key.pub
- ) > $OBJ/known_hosts-cert
+diff -up openssh-6.8p1/regress/cert-hostkey.sh.gsskex openssh-6.8p1/regress/cert-hostkey.sh
+--- openssh-6.8p1/regress/cert-hostkey.sh.gsskex	2015-03-18 11:24:48.879900758 +0100
++++ openssh-6.8p1/regress/cert-hostkey.sh	2015-03-18 12:15:49.556546478 +0100
+@@ -25,7 +25,7 @@ touch $OBJ/host_revoked_plain
+ touch $OBJ/host_revoked_cert
+ cp $OBJ/host_ca_key.pub $OBJ/host_revoked_ca
  
 -PLAIN_TYPES=`$SSH -Q key-plain | sed 's/^ssh-dss/ssh-dsa/g;s/^ssh-//'`
 +PLAIN_TYPES=`$SSH -Q key-plain | grep -v null | sed 's/^ssh-dss/ssh-dsa/g;s/^ssh-//'`
  
  type_has_legacy() {
  	case $1 in
-diff --git a/regress/cert-userkey.sh b/regress/cert-userkey.sh
-index b093a91..4c8da00 100644
---- a/regress/cert-userkey.sh
-+++ b/regress/cert-userkey.sh
+diff -up openssh-6.8p1/regress/cert-userkey.sh.gsskex openssh-6.8p1/regress/cert-userkey.sh
+--- openssh-6.8p1/regress/cert-userkey.sh.gsskex	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/regress/cert-userkey.sh	2015-03-18 11:24:48.879900758 +0100
 @@ -6,7 +6,7 @@ tid="certified user keys"
  rm -f $OBJ/authorized_keys_$USER $OBJ/user_ca_key* $OBJ/cert_user_key*
  cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
@@ -2149,11 +2122,10 @@ index b093a91..4c8da00 100644
  
  type_has_legacy() {
  	case $1 in
-diff --git a/regress/kextype.sh b/regress/kextype.sh
-index 8c2ac09..a2a87ca 100644
---- a/regress/kextype.sh
-+++ b/regress/kextype.sh
-@@ -9,6 +9,9 @@ cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak
+diff -up openssh-6.8p1/regress/kextype.sh.gsskex openssh-6.8p1/regress/kextype.sh
+--- openssh-6.8p1/regress/kextype.sh.gsskex	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/regress/kextype.sh	2015-03-18 11:24:48.879900758 +0100
+@@ -14,6 +14,9 @@ echo "KexAlgorithms=$KEXOPT" >> $OBJ/ssh
  
  tries="1 2 3 4"
  for k in `${SSH} -Q kex`; do
@@ -2163,11 +2135,10 @@ index 8c2ac09..a2a87ca 100644
  	verbose "kex $k"
  	for i in $tries; do
  		${SSH} -F $OBJ/ssh_proxy -o KexAlgorithms=$k x true
-diff --git a/regress/rekey.sh b/regress/rekey.sh
-index cf9401e..31fb0f7 100644
---- a/regress/rekey.sh
-+++ b/regress/rekey.sh
-@@ -30,6 +30,9 @@ increase_datafile_size 300
+diff -up openssh-6.8p1/regress/rekey.sh.gsskex openssh-6.8p1/regress/rekey.sh
+--- openssh-6.8p1/regress/rekey.sh.gsskex	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/regress/rekey.sh	2015-03-18 11:24:48.879900758 +0100
+@@ -38,6 +38,9 @@ increase_datafile_size 300
  
  opts=""
  for i in `${SSH} -Q kex`; do
@@ -2177,7 +2148,7 @@ index cf9401e..31fb0f7 100644
  	opts="$opts KexAlgorithms=$i"
  done
  for i in `${SSH} -Q cipher`; do
-@@ -48,6 +51,9 @@ done
+@@ -56,6 +59,9 @@ done
  if ${SSH} -Q cipher-auth | grep '^.*$' >/dev/null 2>&1 ; then
    for c in `${SSH} -Q cipher-auth`; do
      for kex in `${SSH} -Q kex`; do
@@ -2185,13 +2156,12 @@ index cf9401e..31fb0f7 100644
 +		continue
 +	fi
  	verbose "client rekey $c $kex"
- 	ssh_data_rekeying -oRekeyLimit=256k -oCiphers=$c -oKexAlgorithms=$kex
+ 	ssh_data_rekeying "KexAlgorithms=$kex" -oRekeyLimit=256k -oCiphers=$c
      done
-diff --git a/servconf.c b/servconf.c
-index f763317..68fb9ef 100644
---- a/servconf.c
-+++ b/servconf.c
-@@ -108,7 +108,10 @@ initialize_server_options(ServerOptions *options)
+diff -up openssh-6.8p1/servconf.c.gsskex openssh-6.8p1/servconf.c
+--- openssh-6.8p1/servconf.c.gsskex	2015-03-18 11:24:48.866900788 +0100
++++ openssh-6.8p1/servconf.c	2015-03-18 12:14:37.967721387 +0100
+@@ -114,7 +114,10 @@ initialize_server_options(ServerOptions
  	options->kerberos_ticket_cleanup = -1;
  	options->kerberos_get_afs_token = -1;
  	options->gss_authentication=-1;
@@ -2202,7 +2172,7 @@ index f763317..68fb9ef 100644
  	options->password_authentication = -1;
  	options->kbd_interactive_authentication = -1;
  	options->challenge_response_authentication = -1;
-@@ -245,8 +248,14 @@ fill_default_server_options(ServerOptions *options)
+@@ -270,8 +273,14 @@ fill_default_server_options(ServerOption
  		options->kerberos_get_afs_token = 0;
  	if (options->gss_authentication == -1)
  		options->gss_authentication = 0;
@@ -2217,17 +2187,17 @@ index f763317..68fb9ef 100644
  	if (options->password_authentication == -1)
  		options->password_authentication = 1;
  	if (options->kbd_interactive_authentication == -1)
-@@ -344,7 +353,8 @@ typedef enum {
+@@ -394,7 +403,8 @@ typedef enum {
  	sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication,
- 	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
- 	sClientAliveCountMax, sAuthorizedKeysFile,
+ 	sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes,
+ 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
 -	sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
 +	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
 +	sGssKeyEx, sGssStoreRekey, sAcceptEnv, sPermitTunnel,
  	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
  	sUsePrivilegeSeparation, sAllowAgentForwarding,
  	sHostCertificate,
-@@ -411,10 +421,20 @@ static struct {
+@@ -465,10 +475,20 @@ static struct {
  #ifdef GSSAPI
  	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
  	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
@@ -2248,7 +2218,7 @@ index f763317..68fb9ef 100644
  	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
  	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
  	{ "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
-@@ -1091,10 +1111,22 @@ process_server_config_line(ServerOptions *options, char *line,
+@@ -1170,10 +1190,22 @@ process_server_config_line(ServerOptions
  		intptr = &options->gss_authentication;
  		goto parse_flag;
  
@@ -2271,7 +2241,7 @@ index f763317..68fb9ef 100644
  	case sPasswordAuthentication:
  		intptr = &options->password_authentication;
  		goto parse_flag;
-@@ -2005,6 +2037,9 @@ dump_config(ServerOptions *o)
+@@ -2134,6 +2166,9 @@ dump_config(ServerOptions *o)
  #ifdef GSSAPI
  	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
  	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
@@ -2281,11 +2251,10 @@ index f763317..68fb9ef 100644
  #endif
  	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
  	dump_cfg_fmtint(sKbdInteractiveAuthentication,
-diff --git a/servconf.h b/servconf.h
-index 4572066..37cfa9b 100644
---- a/servconf.h
-+++ b/servconf.h
-@@ -112,7 +112,10 @@ typedef struct {
+diff -up openssh-6.8p1/servconf.h.gsskex openssh-6.8p1/servconf.h
+--- openssh-6.8p1/servconf.h.gsskex	2015-03-18 11:24:48.866900788 +0100
++++ openssh-6.8p1/servconf.h	2015-03-18 11:24:48.880900755 +0100
+@@ -115,7 +115,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 */
@@ -2296,10 +2265,9 @@ index 4572066..37cfa9b 100644
  	int     password_authentication;	/* If true, permit password
  						 * authentication. */
  	int     kbd_interactive_authentication;	/* If true, permit */
-diff --git a/ssh-gss.h b/ssh-gss.h
-index a99d7f0..0374c88 100644
---- a/ssh-gss.h
-+++ b/ssh-gss.h
+diff -up openssh-6.8p1/ssh-gss.h.gsskex openssh-6.8p1/ssh-gss.h
+--- openssh-6.8p1/ssh-gss.h.gsskex	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/ssh-gss.h	2015-03-18 11:24:48.880900755 +0100
 @@ -1,6 +1,6 @@
  /* $OpenBSD: ssh-gss.h,v 1.11 2014/02/26 20:28:44 djm Exp $ */
  /*
@@ -2364,7 +2332,7 @@ index a99d7f0..0374c88 100644
  
  int  ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
  void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
-@@ -119,16 +136,30 @@ void ssh_gssapi_build_ctx(Gssctxt **);
+@@ -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 *);
@@ -2394,13 +2362,14 @@ index a99d7f0..0374c88 100644
 +int ssh_gssapi_oid_table_ok();
 +
 +int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
++
++void ssh_gssapi_rekey_creds(void);
  #endif /* GSSAPI */
  
  #endif /* _SSH_GSS_H */
-diff --git a/ssh_config b/ssh_config
-index 6d1abaf..b0d343b 100644
---- a/ssh_config
-+++ b/ssh_config
+diff -up openssh-6.8p1/ssh_config.gsskex openssh-6.8p1/ssh_config
+--- openssh-6.8p1/ssh_config.gsskex	2015-03-18 11:24:48.861900800 +0100
++++ openssh-6.8p1/ssh_config	2015-03-18 11:24:48.880900755 +0100
 @@ -26,6 +26,8 @@
  #   HostbasedAuthentication no
  #   GSSAPIAuthentication no
@@ -2410,11 +2379,10 @@ index 6d1abaf..b0d343b 100644
  #   BatchMode no
  #   CheckHostIP yes
  #   AddressFamily any
-diff --git a/ssh_config.5 b/ssh_config.5
-index b580392..e7accd6 100644
---- a/ssh_config.5
-+++ b/ssh_config.5
-@@ -682,11 +682,43 @@ Specifies whether user authentication based on GSSAPI is allowed.
+diff -up openssh-6.8p1/ssh_config.5.gsskex openssh-6.8p1/ssh_config.5
+--- openssh-6.8p1/ssh_config.5.gsskex	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/ssh_config.5	2015-03-18 11:24:48.881900753 +0100
+@@ -743,11 +743,43 @@ Specifies whether user authentication ba
  The default is
  .Dq no .
  Note that this option applies to protocol version 2 only.
@@ -2459,13 +2427,12 @@ index b580392..e7accd6 100644
  .It Cm HashKnownHosts
  Indicates that
  .Xr ssh 1
-diff --git a/sshconnect2.c b/sshconnect2.c
-index adbbfc7..cadf234 100644
---- a/sshconnect2.c
-+++ b/sshconnect2.c
-@@ -158,9 +158,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
- {
- 	Kex *kex;
+diff -up openssh-6.8p1/sshconnect2.c.gsskex openssh-6.8p1/sshconnect2.c
+--- openssh-6.8p1/sshconnect2.c.gsskex	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/sshconnect2.c	2015-03-18 11:32:36.879784546 +0100
+@@ -160,9 +160,34 @@ ssh_kex2(char *host, struct sockaddr *ho
+ 	struct kex *kex;
+ 	int r;
  
 +#ifdef GSSAPI
 +	char *orig = NULL, *gss = NULL;
@@ -2498,9 +2465,9 @@ index adbbfc7..cadf234 100644
  	if (options.ciphers == (char *)-1) {
  		logit("No valid ciphers for protocol version 2 given, using defaults.");
  		options.ciphers = NULL;
-@@ -196,6 +221,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
- 	if (options.kex_algorithms != NULL)
- 		myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
+@@ -200,6 +225,17 @@ ssh_kex2(char *host, struct sockaddr *ho
+ 	myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
+ 	    myproposal[PROPOSAL_KEX_ALGS]);
  
 +#ifdef GSSAPI
 +	/* If we've got GSSAPI algorithms, then we also support the
@@ -2516,10 +2483,10 @@ index adbbfc7..cadf234 100644
  	if (options.rekey_limit || options.rekey_interval)
  		packet_set_rekey_limits((u_int32_t)options.rekey_limit,
  		    (time_t)options.rekey_interval);
-@@ -208,10 +244,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
- 	kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
+@@ -217,11 +253,31 @@ ssh_kex2(char *host, struct sockaddr *ho
  	kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
- 	kex->kex[KEX_C25519_SHA256] = kexc25519_client;
+ # endif
+ #endif
 +#ifdef GSSAPI
 +	if (options.gss_keyex) {
 +		kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
@@ -2527,6 +2494,7 @@ index adbbfc7..cadf234 100644
 +		kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
 +	}
 +#endif
+ 	kex->kex[KEX_C25519_SHA256] = kexc25519_client;
  	kex->client_version_string=client_version_string;
  	kex->server_version_string=server_version_string;
  	kex->verify_host_key=&verify_host_key_callback;
@@ -2544,18 +2512,18 @@ index adbbfc7..cadf234 100644
 +	}
 +#endif
 +
- 	xxx_kex = kex;
+ 	dispatch_run(DISPATCH_BLOCK, &kex->done, active_state);
  
- 	dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
-@@ -301,6 +357,7 @@ void	input_gssapi_token(int type, u_int32_t, void *);
- void	input_gssapi_hash(int type, u_int32_t, void *);
- void	input_gssapi_error(int, u_int32_t, void *);
- void	input_gssapi_errtok(int, u_int32_t, void *);
+ 	if (options.use_roaming && !kex->roaming) {
+@@ -313,6 +369,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 *);
-@@ -316,6 +373,11 @@ static char *authmethods_get(void);
+@@ -328,6 +385,11 @@ static char *authmethods_get(void);
  
  Authmethod authmethods[] = {
  #ifdef GSSAPI
@@ -2567,7 +2535,7 @@ index adbbfc7..cadf234 100644
  	{"gssapi-with-mic",
  		userauth_gssapi,
  		NULL,
-@@ -613,19 +675,31 @@ userauth_gssapi(Authctxt *authctxt)
+@@ -634,19 +696,31 @@ userauth_gssapi(Authctxt *authctxt)
  	static u_int mech = 0;
  	OM_uint32 min;
  	int ok = 0;
@@ -2601,7 +2569,7 @@ index adbbfc7..cadf234 100644
  			ok = 1; /* Mechanism works */
  		} else {
  			mech++;
-@@ -722,8 +796,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
+@@ -743,8 +817,8 @@ input_gssapi_response(int type, u_int32_
  {
  	Authctxt *authctxt = ctxt;
  	Gssctxt *gssctxt;
@@ -2612,9 +2580,9 @@ index adbbfc7..cadf234 100644
  
  	if (authctxt == NULL)
  		fatal("input_gssapi_response: no authentication context");
-@@ -832,6 +906,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
- 	free(msg);
+@@ -857,6 +931,48 @@ input_gssapi_error(int type, u_int32_t p
  	free(lang);
+ 	return 0;
  }
 +
 +int
@@ -2661,22 +2629,10 @@ index adbbfc7..cadf234 100644
  #endif /* GSSAPI */
  
  int
-diff --git a/sshd.c b/sshd.c
-index 24ab272..e4e406e 100644
---- a/sshd.c
-+++ b/sshd.c
-@@ -122,6 +122,10 @@
- #include "ssh-sandbox.h"
- #include "version.h"
- 
-+#ifdef USE_SECURITY_SESSION_API
-+#include <Security/AuthSession.h>
-+#endif
-+
- #ifdef LIBWRAP
- #include <tcpd.h>
- #include <syslog.h>
-@@ -1744,10 +1748,13 @@ main(int ac, char **av)
+diff -up openssh-6.8p1/sshd.c.gsskex openssh-6.8p1/sshd.c
+--- openssh-6.8p1/sshd.c.gsskex	2015-03-18 11:24:48.869900781 +0100
++++ openssh-6.8p1/sshd.c	2015-03-18 11:35:53.260315986 +0100
+@@ -1831,10 +1831,13 @@ main(int ac, char **av)
  		logit("Disabling protocol version 1. Could not load host key");
  		options.protocol &= ~SSH_PROTO_1;
  	}
@@ -2690,7 +2646,7 @@ index 24ab272..e4e406e 100644
  	if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
  		logit("sshd: no hostkeys available -- exiting.");
  		exit(1);
-@@ -2488,6 +2495,48 @@ do_ssh2_kex(void)
+@@ -2580,6 +2583,48 @@ do_ssh2_kex(void)
  	myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal(
  	    list_hostkey_types());
  
@@ -2737,11 +2693,11 @@ index 24ab272..e4e406e 100644
 +#endif
 +
  	/* start key exchange */
- 	kex = kex_setup(myproposal);
- 	kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
-@@ -2496,6 +2545,13 @@ do_ssh2_kex(void)
- 	kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
- 	kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
+ 	if ((r = kex_setup(active_state, myproposal)) != 0)
+ 		fatal("kex_setup: %s", ssh_err(r));
+@@ -2594,6 +2639,13 @@ do_ssh2_kex(void)
+ # endif
+ #endif
  	kex->kex[KEX_C25519_SHA256] = kexc25519_server;
 +#ifdef GSSAPI
 +	if (options.gss_keyex) {
@@ -2753,10 +2709,9 @@ index 24ab272..e4e406e 100644
  	kex->server = 1;
  	kex->client_version_string=client_version_string;
  	kex->server_version_string=server_version_string;
-diff --git a/sshd_config b/sshd_config
-index c1b7c03..adfd7b1 100644
---- a/sshd_config
-+++ b/sshd_config
+diff -up openssh-6.8p1/sshd_config.gsskex openssh-6.8p1/sshd_config
+--- openssh-6.8p1/sshd_config.gsskex	2015-03-18 11:24:48.869900781 +0100
++++ openssh-6.8p1/sshd_config	2015-03-18 11:24:48.882900750 +0100
 @@ -91,6 +91,8 @@ ChallengeResponseAuthentication no
  # GSSAPI options
  GSSAPIAuthentication yes
@@ -2766,11 +2721,10 @@ index c1b7c03..adfd7b1 100644
  
  # Set this to 'yes' to enable PAM authentication, account processing,
  # and session processing. If this is enabled, PAM authentication will
-diff --git a/sshd_config.5 b/sshd_config.5
-index 95b5f8c..1fb002d 100644
---- a/sshd_config.5
-+++ b/sshd_config.5
-@@ -493,12 +493,40 @@ Specifies whether user authentication based on GSSAPI is allowed.
+diff -up openssh-6.8p1/sshd_config.5.gsskex openssh-6.8p1/sshd_config.5
+--- openssh-6.8p1/sshd_config.5.gsskex	2015-03-18 11:24:48.882900750 +0100
++++ openssh-6.8p1/sshd_config.5	2015-03-18 12:12:57.914965842 +0100
+@@ -564,12 +564,40 @@ Specifies whether user authentication ba
  The default is
  .Dq no .
  Note that this option applies to protocol version 2 only.
@@ -2808,6 +2762,6 @@ index 95b5f8c..1fb002d 100644
 +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 HostbasedAuthentication
- Specifies whether rhosts or /etc/hosts.equiv authentication together
- with successful public key client host authentication is allowed
+ .It Cm HostbasedAcceptedKeyTypes
+ Specifies the key types that will be accepted for hostbased authentication
+ as a comma-separated pattern list.
diff --git a/openssh-6.6p1-keycat.patch b/openssh-6.6p1-keycat.patch
index d30dedb..be79371 100644
--- a/openssh-6.6p1-keycat.patch
+++ b/openssh-6.6p1-keycat.patch
@@ -1,8 +1,6 @@
-diff --git a/HOWTO.ssh-keycat b/HOWTO.ssh-keycat
-new file mode 100644
-index 0000000..630ec62
---- /dev/null
-+++ b/HOWTO.ssh-keycat
+diff -up openssh-6.8p1/HOWTO.ssh-keycat.keycat openssh-6.8p1/HOWTO.ssh-keycat
+--- openssh-6.8p1/HOWTO.ssh-keycat.keycat	2015-03-18 11:13:43.063482958 +0100
++++ openssh-6.8p1/HOWTO.ssh-keycat	2015-03-18 11:13:43.063482958 +0100
 @@ -0,0 +1,12 @@
 +The ssh-keycat retrieves the content of the ~/.ssh/authorized_keys
 +of an user in any environment. This includes environments with
@@ -16,10 +14,9 @@ index 0000000..630ec62
 +        PubkeyAuthentication yes
 +
 +
-diff --git a/Makefile.in b/Makefile.in
-index 411eadb..4ab6717 100644
---- a/Makefile.in
-+++ b/Makefile.in
+diff -up openssh-6.8p1/Makefile.in.keycat openssh-6.8p1/Makefile.in
+--- openssh-6.8p1/Makefile.in.keycat	2015-03-18 11:13:43.061482963 +0100
++++ openssh-6.8p1/Makefile.in	2015-03-18 11:14:22.480389291 +0100
 @@ -27,6 +27,7 @@ SFTP_SERVER=$(libexecdir)/sftp-server
  SSH_KEYSIGN=$(libexecdir)/ssh-keysign
  SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper
@@ -28,18 +25,18 @@ index 411eadb..4ab6717 100644
  SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
  PRIVSEP_PATH=@PRIVSEP_PATH@
  SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
-@@ -64,7 +65,7 @@ EXEEXT=@EXEEXT@
+@@ -65,7 +66,7 @@ EXEEXT=@EXEEXT@
  MANFMT=@MANFMT@
  INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@
  
 -TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT)
 +TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT)
  
- LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \
- 	canohost.o channels.o cipher.o cipher-aes.o \
-@@ -176,6 +177,9 @@ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11
- ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o
- 	$(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
+ LIBOPENSSH_OBJS=\
+ 	ssh_api.o \
+@@ -190,6 +191,9 @@ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT)
+ ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o sshbuf-getput-basic.o ssherr.o
+ 	$(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o sshbuf-getput-basic.o ssherr.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
  
 +ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHDOBJS) libssh.a ssh-keycat.o
 +	$(LD) -o $@ ssh-keycat.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHDLIBS) $(SSHLIBS)
@@ -47,7 +44,7 @@ index 411eadb..4ab6717 100644
  ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o
  	$(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
  
-@@ -283,6 +287,7 @@ install-files:
+@@ -321,6 +325,7 @@ install-files:
  		$(INSTALL) -m 0700 $(STRIP_OPT) ssh-ldap-helper $(DESTDIR)$(SSH_LDAP_HELPER) ; \
  		$(INSTALL) -m 0700 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \
  	fi
@@ -55,11 +52,10 @@ index 411eadb..4ab6717 100644
  	$(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT)
  	$(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
  	$(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
-diff --git a/auth2-pubkey.c b/auth2-pubkey.c
-index c0ae0d4..cb0f931 100644
---- a/auth2-pubkey.c
-+++ b/auth2-pubkey.c
-@@ -600,6 +600,14 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
+diff -up openssh-6.8p1/auth2-pubkey.c.keycat openssh-6.8p1/auth2-pubkey.c
+--- openssh-6.8p1/auth2-pubkey.c.keycat	2015-03-18 11:13:43.053482982 +0100
++++ openssh-6.8p1/auth2-pubkey.c	2015-03-18 11:13:43.063482958 +0100
+@@ -623,6 +623,14 @@ user_key_command_allowed2(struct passwd
  			_exit(1);
  		}
  
@@ -74,11 +70,10 @@ index c0ae0d4..cb0f931 100644
  		execl(options.authorized_keys_command,
  		    options.authorized_keys_command, user_pw->pw_name, NULL);
  
-diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c
-index d04f4ed..0077dd7 100644
---- a/openbsd-compat/port-linux-sshd.c
-+++ b/openbsd-compat/port-linux-sshd.c
-@@ -53,6 +53,20 @@ extern Authctxt *the_authctxt;
+diff -up openssh-6.8p1/openbsd-compat/port-linux-sshd.c.keycat openssh-6.8p1/openbsd-compat/port-linux-sshd.c
+--- openssh-6.8p1/openbsd-compat/port-linux-sshd.c.keycat	2015-03-18 11:13:43.057482972 +0100
++++ openssh-6.8p1/openbsd-compat/port-linux-sshd.c	2015-03-18 11:13:43.063482958 +0100
+@@ -54,6 +54,20 @@ extern Authctxt *the_authctxt;
  extern int inetd_flag;
  extern int rexeced_flag;
  
@@ -99,7 +94,7 @@ index d04f4ed..0077dd7 100644
  /* Send audit message */
  static int
  sshd_selinux_send_audit_message(int success, security_context_t default_context,
-@@ -307,7 +321,7 @@ sshd_selinux_getctxbyname(char *pwname,
+@@ -308,7 +322,7 @@ sshd_selinux_getctxbyname(char *pwname,
  
  /* Setup environment variables for pam_selinux */
  static int
@@ -108,7 +103,7 @@ index d04f4ed..0077dd7 100644
  {
  	const char *reqlvl;
  	char *role;
-@@ -318,16 +332,16 @@ sshd_selinux_setup_pam_variables(void)
+@@ -319,16 +333,16 @@ sshd_selinux_setup_pam_variables(void)
  
  	ssh_selinux_get_role_level(&role, &reqlvl);
  
@@ -128,7 +123,7 @@ index d04f4ed..0077dd7 100644
  
  	if (role != NULL)
  		free(role);
-@@ -335,6 +349,24 @@ sshd_selinux_setup_pam_variables(void)
+@@ -336,6 +350,24 @@ sshd_selinux_setup_pam_variables(void)
  	return rv;
  }
  
@@ -153,7 +148,7 @@ index d04f4ed..0077dd7 100644
  /* Set the execution context to the default for the specified user */
  void
  sshd_selinux_setup_exec_context(char *pwname)
-@@ -343,7 +375,7 @@ sshd_selinux_setup_exec_context(char *pwname)
+@@ -344,7 +376,7 @@ sshd_selinux_setup_exec_context(char *pw
  	int r = 0;
  	security_context_t default_ctx = NULL;
  
@@ -162,7 +157,7 @@ index d04f4ed..0077dd7 100644
  		return;
  
  	if (options.use_pam) {
-@@ -414,7 +446,7 @@ sshd_selinux_copy_context(void)
+@@ -415,7 +447,7 @@ sshd_selinux_copy_context(void)
  {
  	security_context_t *ctx;
  
@@ -171,11 +166,10 @@ index d04f4ed..0077dd7 100644
  		return;
  
  	if (getexeccon((security_context_t *)&ctx) != 0) {
-diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h
-index b18893c..cb51f99 100644
---- a/openbsd-compat/port-linux.h
-+++ b/openbsd-compat/port-linux.h
-@@ -25,8 +25,10 @@ void ssh_selinux_setup_pty(char *, const char *);
+diff -up openssh-6.8p1/openbsd-compat/port-linux.h.keycat openssh-6.8p1/openbsd-compat/port-linux.h
+--- openssh-6.8p1/openbsd-compat/port-linux.h.keycat	2015-03-18 11:13:43.057482972 +0100
++++ openssh-6.8p1/openbsd-compat/port-linux.h	2015-03-18 11:13:43.063482958 +0100
+@@ -25,8 +25,10 @@ void ssh_selinux_setup_pty(char *, const
  void ssh_selinux_change_context(const char *);
  void ssh_selinux_setfscreatecon(const char *);
  
@@ -186,11 +180,10 @@ index b18893c..cb51f99 100644
  #endif
  
  #ifdef LINUX_OOM_ADJUST
-diff --git a/platform.c b/platform.c
-index 0d39ab2..0dae387 100644
---- a/platform.c
-+++ b/platform.c
-@@ -102,7 +102,7 @@ platform_setusercontext(struct passwd *pw)
+diff -up openssh-6.8p1/platform.c.keycat openssh-6.8p1/platform.c
+--- openssh-6.8p1/platform.c.keycat	2015-03-18 11:13:43.055482977 +0100
++++ openssh-6.8p1/platform.c	2015-03-18 11:13:43.063482958 +0100
+@@ -103,7 +103,7 @@ platform_setusercontext(struct passwd *p
  {
  #ifdef WITH_SELINUX
  	/* Cache selinux status for later use */
@@ -199,11 +192,9 @@ index 0d39ab2..0dae387 100644
  #endif
  
  #ifdef USE_SOLARIS_PROJECTS
-diff --git a/ssh-keycat.c b/ssh-keycat.c
-new file mode 100644
-index 0000000..f8ed7af
---- /dev/null
-+++ b/ssh-keycat.c
+diff -up openssh-6.8p1/ssh-keycat.c.keycat openssh-6.8p1/ssh-keycat.c
+--- openssh-6.8p1/ssh-keycat.c.keycat	2015-03-18 11:13:43.064482956 +0100
++++ openssh-6.8p1/ssh-keycat.c	2015-03-18 11:13:43.064482956 +0100
 @@ -0,0 +1,238 @@
 +/*
 + * Redistribution and use in source and binary forms, with or without
diff --git a/openssh-6.6p1-keyperm.patch b/openssh-6.6p1-keyperm.patch
index fccb328..fbe33b0 100644
--- a/openssh-6.6p1-keyperm.patch
+++ b/openssh-6.6p1-keyperm.patch
@@ -1,15 +1,16 @@
-diff -up openssh-6.6p1/authfile.c.keyperm openssh-6.6p1/authfile.c
---- openssh-6.6p1/authfile.c.keyperm	2014-02-04 01:20:15.000000000 +0100
-+++ openssh-6.6p1/authfile.c	2014-05-05 15:20:43.075246776 +0200
-@@ -54,6 +54,7 @@
+diff --git a/authfile.c b/authfile.c
+index e93d867..4fc5b3d 100644
+--- a/authfile.c
++++ b/authfile.c
+@@ -32,6 +32,7 @@
  
  #include <errno.h>
  #include <fcntl.h>
 +#include <grp.h>
- #include <stdarg.h>
  #include <stdio.h>
+ #include <stdarg.h>
  #include <stdlib.h>
-@@ -979,6 +980,13 @@ key_perm_ok(int fd, const char *filename
+@@ -207,6 +208,13 @@ sshkey_perm_ok(int fd, const char *filename)
  #ifdef HAVE_CYGWIN
  	if (check_ntsec(filename))
  #endif
diff --git a/openssh-6.6p1-kuserok.patch b/openssh-6.6p1-kuserok.patch
index f7c5a1c..9e93051 100644
--- a/openssh-6.6p1-kuserok.patch
+++ b/openssh-6.6p1-kuserok.patch
@@ -1,8 +1,7 @@
-diff --git a/auth-krb5.c b/auth-krb5.c
-index 6c62bdf..11c8562 100644
---- a/auth-krb5.c
-+++ b/auth-krb5.c
-@@ -54,6 +54,21 @@
+diff -up openssh-6.8p1/auth-krb5.c.kuserok openssh-6.8p1/auth-krb5.c
+--- openssh-6.8p1/auth-krb5.c.kuserok	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/auth-krb5.c	2015-03-18 12:37:14.349351304 +0100
+@@ -55,6 +55,21 @@
  
  extern ServerOptions	 options;
  
@@ -24,7 +23,7 @@ index 6c62bdf..11c8562 100644
  static int
  krb5_init(void *context)
  {
-@@ -157,8 +172,9 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
+@@ -158,8 +173,9 @@ auth_krb5_password(Authctxt *authctxt, c
  	if (problem)
  		goto out;
  
@@ -36,11 +35,10 @@ index 6c62bdf..11c8562 100644
  		problem = -1;
  		goto out;
  	}
-diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
-index 60de320..0a4930e 100644
---- a/gss-serv-krb5.c
-+++ b/gss-serv-krb5.c
-@@ -67,6 +67,7 @@ static int ssh_gssapi_krb5_cmdok(krb5_principal, const char *, const char *,
+diff -up openssh-6.8p1/gss-serv-krb5.c.kuserok openssh-6.8p1/gss-serv-krb5.c
+--- openssh-6.8p1/gss-serv-krb5.c.kuserok	2015-03-18 12:37:14.346351312 +0100
++++ openssh-6.8p1/gss-serv-krb5.c	2015-03-18 12:37:14.349351304 +0100
+@@ -67,6 +67,7 @@ static int ssh_gssapi_krb5_cmdok(krb5_pr
      int);
  
  static krb5_context krb_context = NULL;
@@ -152,7 +150,7 @@ index 60de320..0a4930e 100644
  static int
  ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
  {
-@@ -116,7 +214,8 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
+@@ -116,7 +214,8 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client
  	/* NOTE: .k5login and .k5users must opened as root, not the user,
  	 * because if they are on a krb5-protected filesystem, user credentials
  	 * to access these files aren't available yet. */
@@ -162,7 +160,7 @@ index 60de320..0a4930e 100644
  		retval = 1;
  		logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
  		    name, (char *)client->displayname.value);
-@@ -171,9 +270,8 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name,
+@@ -171,9 +270,8 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri
  	snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir);
  	/* If both .k5login and .k5users DNE, self-login is ok. */
  	if (!k5login_exists && (access(file, F_OK) == -1)) {
@@ -174,29 +172,28 @@ index 60de320..0a4930e 100644
  	}
  	if ((fp = fopen(file, "r")) == NULL) {
  		int saved_errno = errno;
-diff --git a/servconf.c b/servconf.c
-index 68fb9ef..904c869 100644
---- a/servconf.c
-+++ b/servconf.c
-@@ -157,6 +157,7 @@ initialize_server_options(ServerOptions *options)
- 	options->ip_qos_interactive = -1;
+diff -up openssh-6.8p1/servconf.c.kuserok openssh-6.8p1/servconf.c
+--- openssh-6.8p1/servconf.c.kuserok	2015-03-18 12:37:14.342351322 +0100
++++ openssh-6.8p1/servconf.c	2015-03-18 12:38:36.133145700 +0100
+@@ -167,6 +167,7 @@ initialize_server_options(ServerOptions
  	options->ip_qos_bulk = -1;
  	options->version_addendum = NULL;
+ 	options->fingerprint_hash = -1;
 +	options->use_kuserok = -1;
  }
  
- void
-@@ -312,6 +313,8 @@ fill_default_server_options(ServerOptions *options)
- 		options->version_addendum = xstrdup("");
- 	if (options->show_patchlevel == -1)
- 		options->show_patchlevel = 0;
+ /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
+@@ -345,6 +346,8 @@ fill_default_server_options(ServerOption
+ 		options->fwd_opts.streamlocal_bind_unlink = 0;
+ 	if (options->fingerprint_hash == -1)
+ 		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
 +	if (options->use_kuserok == -1)
 +		options->use_kuserok = 1;
- 
  	/* Turn privilege separation on by default */
  	if (use_privsep == -1)
-@@ -338,7 +341,7 @@ typedef enum {
- 	sPermitRootLogin, sLogFacility, sLogLevel,
+ 		use_privsep = PRIVSEP_NOSANDBOX;
+@@ -388,7 +391,7 @@ typedef enum {
+ 	sKeyRegenerationTime, sPermitRootLogin, sLogFacility, sLogLevel,
  	sRhostsRSAAuthentication, sRSAAuthentication,
  	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
 -	sKerberosGetAFSToken,
@@ -204,7 +201,7 @@ index 68fb9ef..904c869 100644
  	sKerberosTgtPassing, sChallengeResponseAuthentication,
  	sPasswordAuthentication, sKbdInteractiveAuthentication,
  	sListenAddress, sAddressFamily,
-@@ -410,11 +413,13 @@ static struct {
+@@ -464,11 +467,13 @@ static struct {
  #else
  	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
  #endif
@@ -218,7 +215,7 @@ index 68fb9ef..904c869 100644
  #endif
  	{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
  	{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
-@@ -1526,6 +1531,10 @@ process_server_config_line(ServerOptions *options, char *line,
+@@ -1614,6 +1619,10 @@ process_server_config_line(ServerOptions
  		*activep = value;
  		break;
  
@@ -229,7 +226,7 @@ index 68fb9ef..904c869 100644
  	case sPermitOpen:
  		arg = strdelim(&cp);
  		if (!arg || *arg == '\0')
-@@ -1811,6 +1820,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
+@@ -1935,6 +1944,7 @@ copy_set_server_options(ServerOptions *d
  	M_CP_INTOPT(max_authtries);
  	M_CP_INTOPT(ip_qos_interactive);
  	M_CP_INTOPT(ip_qos_bulk);
@@ -237,19 +234,18 @@ index 68fb9ef..904c869 100644
  	M_CP_INTOPT(rekey_limit);
  	M_CP_INTOPT(rekey_interval);
  
-@@ -2062,6 +2072,7 @@ dump_config(ServerOptions *o)
- 	dump_cfg_fmtint(sUseDNS, o->use_dns);
- 	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
+@@ -2194,6 +2204,7 @@ dump_config(ServerOptions *o)
+ 	dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
  	dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
+ 	dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
 +	dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok);
  
  	/* string arguments */
  	dump_cfg_string(sPidFile, o->pid_file);
-diff --git a/servconf.h b/servconf.h
-index 37cfa9b..5117dfa 100644
---- a/servconf.h
-+++ b/servconf.h
-@@ -173,6 +173,7 @@ typedef struct {
+diff -up openssh-6.8p1/servconf.h.kuserok openssh-6.8p1/servconf.h
+--- openssh-6.8p1/servconf.h.kuserok	2015-03-18 12:37:14.342351322 +0100
++++ openssh-6.8p1/servconf.h	2015-03-18 12:37:14.350351302 +0100
+@@ -177,6 +177,7 @@ typedef struct {
  
  	int	num_permitted_opens;
  
@@ -257,10 +253,9 @@ index 37cfa9b..5117dfa 100644
  	char   *chroot_directory;
  	char   *revoked_keys_file;
  	char   *trusted_user_ca_keys;
-diff --git a/sshd_config b/sshd_config
-index adfd7b1..e772ed5 100644
---- a/sshd_config
-+++ b/sshd_config
+diff -up openssh-6.8p1/sshd_config.kuserok openssh-6.8p1/sshd_config
+--- openssh-6.8p1/sshd_config.kuserok	2015-03-18 12:37:14.344351317 +0100
++++ openssh-6.8p1/sshd_config	2015-03-18 12:37:14.350351302 +0100
 @@ -87,6 +87,7 @@ ChallengeResponseAuthentication no
  #KerberosOrLocalPasswd yes
  #KerberosTicketCleanup yes
@@ -269,11 +264,10 @@ index adfd7b1..e772ed5 100644
  
  # GSSAPI options
  GSSAPIAuthentication yes
-diff --git a/sshd_config.5 b/sshd_config.5
-index 1fb002d..e0e5fff 100644
---- a/sshd_config.5
-+++ b/sshd_config.5
-@@ -697,6 +697,10 @@ Specifies whether to automatically destroy the user's ticket cache
+diff -up openssh-6.8p1/sshd_config.5.kuserok openssh-6.8p1/sshd_config.5
+--- openssh-6.8p1/sshd_config.5.kuserok	2015-03-18 12:37:14.343351319 +0100
++++ openssh-6.8p1/sshd_config.5	2015-03-18 12:39:23.373026939 +0100
+@@ -779,6 +779,10 @@ Specifies whether to automatically destr
  file on logout.
  The default is
  .Dq yes .
@@ -284,8 +278,8 @@ index 1fb002d..e0e5fff 100644
  .It Cm KexAlgorithms
  Specifies the available KEX (Key Exchange) algorithms.
  Multiple algorithms must be comma-separated.
-@@ -862,6 +866,7 @@ Available keywords are
- .Cm HostbasedUsesNameFromPacketOnly ,
+@@ -1017,6 +1021,7 @@ Available keywords are
+ .Cm IPQoS ,
  .Cm KbdInteractiveAuthentication ,
  .Cm KerberosAuthentication ,
 +.Cm KerberosUseKuserok ,
diff --git a/openssh-6.6p1-ldap.patch b/openssh-6.6p1-ldap.patch
deleted file mode 100644
index ae3e7cd..0000000
--- a/openssh-6.6p1-ldap.patch
+++ /dev/null
@@ -1,2674 +0,0 @@
-diff --git a/HOWTO.ldap-keys b/HOWTO.ldap-keys
-new file mode 100644
-index 0000000..dd5f5cc
---- /dev/null
-+++ b/HOWTO.ldap-keys
-@@ -0,0 +1,108 @@
-+
-+HOW TO START
-+
-+1) configure LDAP server
-+  * Use LDAP server documentation
-+2) add appropriate LDAP schema
-+  * For OpenLDAP or SunONE Use attached schema, otherwise you have to create it. 
-+  * LDAP user entry
-+        User entry:
-+	- attached to the 'ldapPublicKey' objectclass
-+	- attached to the 'posixAccount' objectclass
-+	- with a filled 'sshPublicKey' attribute 
-+3) insert users into LDAP
-+  * Use LDAP Tree management tool as useful
-+  * Entry in the LDAP server must respect 'posixAccount' and 'ldapPublicKey' which are defined in core.schema and the additionnal lpk.schema.
-+  * Example:
-+	dn: uid=captain,ou=commanders,dc=enterprise,dc=universe
-+	objectclass: top
-+	objectclass: person
-+	objectclass: organizationalPerson
-+	objectclass: posixAccount
-+	objectclass: ldapPublicKey
-+	description: Jonathan Archer
-+	userPassword: Porthos
-+	cn: onathan Archer
-+	sn: onathan Archer
-+	uid: captain
-+	uidNumber: 1001
-+	gidNumber: 1001
-+	homeDirectory: /home/captain
-+	sshPublicKey: ssh-rss AAAAB3.... =captain at universe
-+	sshPublicKey: command="kill -9 1" ssh-rss AAAAM5...
-+4) on the ssh side set in sshd_config
-+  * Set up the backend
-+	AuthorizedKeysCommand /usr/libexec/openssh/ssh-ldap-wrapper
-+	AuthorizedKeysCommandUser <appropriate user to run LDAP>
-+  * Do not forget to set
-+	PubkeyAuthentication yes
-+  * Swith off unnecessary auth methods
-+5) confugure ldap.conf
-+  * Default ldap.conf is placed in /etc/ssh
-+  * The configuration style is the same as other ldap based aplications
-+6) if necessary edit ssh-ldap-wrapper
-+  * There is a possibility to change ldap.conf location
-+  * There are some debug options
-+  * Example
-+	/usr/libexec/openssh -s -f /etc/ldap.conf -w -d >> /tmp/ldapdebuglog.txt
-+
-+HOW TO MIGRATE FROM LPK
-+
-+1) goto HOW TO START 4) .... the ldap schema is the same
-+
-+2) convert the group requests to the appropriate LDAP requests
-+
-+HOW TO SOLVE PROBLEMS
-+
-+1) use debug in sshd
-+  * /usr/sbin/sshd -d -d -d -d
-+2) use debug in ssh-ldap-helper
-+  * ssh-ldap-helper -d -d -d -d -s <username>
-+3) use tcpdump ... other ldap client etc.
-+
-+ADVANTAGES
-+
-+1) Blocking an user account can be done directly from LDAP (if sshd is using PubkeyAuthentication + AuthorizedKeysCommand with ldap only).
-+
-+DISADVANTAGES
-+
-+1)  LDAP must be well configured, getting the public key of some user is not a problem, but if anonymous LDAP 
-+  allows write to users dn, somebody could replace some user's public key by his own and impersonate some 
-+  of your users in all your server farm -- be VERY CAREFUL.
-+2) With incomplete PKI the MITM attack when sshd is requesting the public key, could lead to a compromise of your servers allowing login 
-+  as the impersonated user.
-+3) If LDAP server is down there may be no fallback on passwd auth.
-+  
-+MISC.
-+  
-+1) todo
-+  * Possibility to reuse the ssh-ldap-helper.
-+  * Tune the LDAP part to accept  all possible LDAP configurations.
-+
-+2) differences from original lpk
-+  * No LDAP code in sshd.
-+  * Support for various LDAP platforms and configurations.
-+  * LDAP is configured in separate ldap.conf file.
-+
-+3) docs/link 
-+  * http://pacsec.jp/core05/psj05-barisani-en.pdf
-+  * http://fritz.potsdam.edu/projects/openssh-lpk/
-+  * http://fritz.potsdam.edu/projects/sshgate/
-+  * http://dev.inversepath.com/trac/openssh-lpk
-+  * http://lam.sf.net/ ( http://lam.sourceforge.net/documentation/supportedSchemas.htm )
-+
-+4) contributors/ideas/greets
-+  - Eric AUGE <eau at phear.org>
-+  - Andrea Barisani <andrea at inversepath.com>
-+  - Falk Siemonsmeier.
-+  - Jacob Rief.
-+  - Michael Durchgraf.
-+  - frederic peters.
-+  - Finlay dobbie.
-+  - Stefan Fisher.
-+  - Robin H. Johnson.
-+  - Adrian Bridgett.
-+
-+5) Author
-+    Jan F. Chadima <jchadima at redhat.com>
-+
-diff --git a/Makefile.in b/Makefile.in
-index 28a8ec4..411eadb 100644
---- a/Makefile.in
-+++ b/Makefile.in
-@@ -25,6 +25,8 @@ SSH_PROGRAM=@bindir@/ssh
- ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass
- SFTP_SERVER=$(libexecdir)/sftp-server
- SSH_KEYSIGN=$(libexecdir)/ssh-keysign
-+SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper
-+SSH_LDAP_WRAPPER=$(libexecdir)/ssh-ldap-wrapper
- SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
- PRIVSEP_PATH=@PRIVSEP_PATH@
- SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
-@@ -60,8 +62,9 @@ XAUTH_PATH=@XAUTH_PATH@
- LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@
- EXEEXT=@EXEEXT@
- MANFMT=@MANFMT@
-+INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@
- 
--TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT)
-+TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT)
- 
- LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \
- 	canohost.o channels.o cipher.o cipher-aes.o \
-@@ -98,8 +101,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
- 	sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
- 	sandbox-seccomp-filter.o sandbox-capsicum.o
- 
--MANPAGES	= moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out
--MANPAGES_IN	= moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5
-+MANPAGES	= moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out ssh-ldap-helper.8.out ssh-ldap.conf.5.out
-+MANPAGES_IN	= moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5 ssh-ldap-helper.8 ssh-ldap.conf.5
- MANTYPE		= @MANTYPE@
- 
- CONFIGFILES=sshd_config.out ssh_config.out moduli.out
-@@ -170,6 +173,9 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o readco
- ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o
- 	$(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
- 
-+ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o
-+	$(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
-+
- ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o
- 	$(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
- 
-@@ -273,6 +279,10 @@ install-files:
- 	$(INSTALL) -m 0755 $(STRIP_OPT) sshd$(EXEEXT) $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
- 	$(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
- 	$(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
-+	if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \
-+		$(INSTALL) -m 0700 $(STRIP_OPT) ssh-ldap-helper $(DESTDIR)$(SSH_LDAP_HELPER) ; \
-+		$(INSTALL) -m 0700 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \
-+	fi
- 	$(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT)
- 	$(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
- 	$(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
-@@ -289,6 +299,10 @@ install-files:
- 	$(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
- 	$(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
- 	$(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
-+	if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \
-+		$(INSTALL) -m 644 ssh-ldap-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-ldap-helper.8 ; \
-+		$(INSTALL) -m 644 ssh-ldap.conf.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/ssh-ldap.conf.5 ; \
-+	fi
- 	-rm -f $(DESTDIR)$(bindir)/slogin
- 	ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
- 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
-@@ -318,6 +332,13 @@ install-sysconf:
- 	else \
- 		echo "$(DESTDIR)$(sysconfdir)/moduli already exists, install will not overwrite"; \
- 	fi
-+	if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \
-+		if [ ! -f $(DESTDIR)$(sysconfdir)/ldap.conf ]; then \
-+			$(INSTALL) -m 644 ldap.conf $(DESTDIR)$(sysconfdir)/ldap.conf; \
-+		else \
-+			echo "$(DESTDIR)$(sysconfdir)/ldap.conf already exists, install will not overwrite"; \
-+		fi ; \
-+	fi
- 
- host-key: ssh-keygen$(EXEEXT)
- 	@if [ -z "$(DESTDIR)" ] ; then \
-@@ -381,6 +402,8 @@ uninstall:
- 	-rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
- 	-rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
- 	-rm -f $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
-+	-rm -f $(DESTDIR)$(SSH_LDAP_HELPER)$(EXEEXT)
-+	-rm -f $(DESTDIR)$(SSH_LDAP_WRAPPER)$(EXEEXT)
- 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
- 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
- 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
-@@ -392,6 +415,7 @@ uninstall:
- 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
- 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
- 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
-+	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-ldap-helper.8
- 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
- 
- regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c
-diff --git a/configure.ac b/configure.ac
-index 7c6ce08..722a19e 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1625,6 +1625,106 @@ if test "x$use_pie" != "xno"; then
- 	fi
- fi
- 
-+# Check whether user wants LDAP support
-+LDAP_MSG="no"
-+INSTALL_SSH_LDAP_HELPER=""
-+AC_ARG_WITH(ldap,
-+	[  --with-ldap[[=PATH]]      Enable LDAP pubkey support (optionally in PATH)],
-+	[
-+		if test "x$withval" != "xno" ; then
-+
-+			INSTALL_SSH_LDAP_HELPER="yes"
-+			CPPFLAGS="$CPPFLAGS -DLDAP_DEPRECATED"
-+
-+			if test "x$withval" != "xyes" ; then
-+				CPPFLAGS="$CPPFLAGS -I${withval}/include"
-+				LDFLAGS="$LDFLAGS -L${withval}/lib"
-+			fi
-+
-+			AC_DEFINE([WITH_LDAP_PUBKEY], 1, [Enable LDAP pubkey support])
-+			LDAP_MSG="yes"
-+
-+			AC_CHECK_HEADERS(lber.h)
-+			AC_CHECK_HEADERS(ldap.h, , AC_MSG_ERROR(could not locate <ldap.h>))
-+			AC_CHECK_HEADERS(ldap_ssl.h)
-+
-+			AC_ARG_WITH(ldap-lib,
-+				[  --with-ldap-lib=type    select ldap library [auto|netscape5|netscape4|netscape3|umich|openldap]])
-+
-+			if test -z "$with_ldap_lib"; then
-+				with_ldap_lib=auto
-+			fi
-+
-+			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = umich -o $with_ldap_lib = openldap \); then
-+				AC_CHECK_LIB(lber, main, LIBS="-llber $LIBS" found_ldap_lib=yes)
-+				AC_CHECK_LIB(ldap, main, LIBS="-lldap $LIBS" found_ldap_lib=yes)
-+			fi
-+
-+			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape5 \); then
-+				AC_CHECK_LIB(ldap50, main, LIBS="-lldap50 -lssldap50 -lssl3 -lnss3 -lnspr4 -lprldap50 -lplc4 -lplds4 $LIBS" found_ldap_lib=yes)
-+			fi
-+
-+			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape4 \); then
-+				AC_CHECK_LIB(ldapssl41, main, LIBS="-lldapssl41 -lplc3 -lplds3 -lnspr3 $LIBS" found_ldap_lib=yes)
-+				if test -z "$found_ldap_lib"; then
-+					AC_CHECK_LIB(ldapssl40, main, LIBS="-lldapssl40 $LIBS" found_ldap_lib=yes)
-+				fi
-+				if test -z "$found_ldap_lib"; then
-+					AC_CHECK_LIB(ldap41, main, LIBS="-lldap41 $LIBS" found_ldap_lib=yes)
-+				fi
-+				if test -z "$found_ldap_lib"; then
-+					AC_CHECK_LIB(ldap40, main, LIBS="-lldap40 $LIBS" found_ldap_lib=yes)
-+				fi
-+			fi
-+
-+			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape3 \); then
-+				AC_CHECK_LIB(ldapssl30, main, LIBS="-lldapssl30 $LIBS" found_ldap_lib=yes)
-+			fi
-+
-+			if test -z "$found_ldap_lib"; then
-+				AC_MSG_ERROR(could not locate a valid LDAP library)
-+			fi
-+
-+			AC_MSG_CHECKING([for working LDAP support])
-+			AC_TRY_COMPILE(
-+				[#include <sys/types.h>
-+				 #include <ldap.h>],
-+				[(void)ldap_init(0, 0);],
-+				[AC_MSG_RESULT(yes)],
-+				[
-+				    AC_MSG_RESULT(no) 
-+					AC_MSG_ERROR([** Incomplete or missing ldap libraries **])
-+				])
-+			AC_CHECK_FUNCS( \
-+				ldap_init \
-+				ldap_get_lderrno \
-+				ldap_set_lderrno \
-+				ldap_parse_result \
-+				ldap_memfree \
-+				ldap_controls_free \
-+				ldap_set_option \
-+				ldap_get_option \
-+				ldapssl_init \
-+				ldap_start_tls_s \
-+				ldap_pvt_tls_set_option \
-+				ldap_initialize \
-+			)
-+			AC_CHECK_FUNCS(ldap_set_rebind_proc,
-+				AC_MSG_CHECKING([number arguments of ldap_set_rebind_proc])
-+				AC_TRY_COMPILE(
-+					[#include <lber.h>
-+					#include <ldap.h>],
-+					[ldap_set_rebind_proc(0, 0, 0);],
-+					[ac_cv_ldap_set_rebind_proc=3],
-+					[ac_cv_ldap_set_rebind_proc=2])
-+				AC_MSG_RESULT($ac_cv_ldap_set_rebind_proc)
-+				AC_DEFINE(LDAP_SET_REBIND_PROC_ARGS, $ac_cv_ldap_set_rebind_proc, [number arguments of ldap_set_rebind_proc])
-+			)
-+		fi
-+	]
-+)
-+AC_SUBST(INSTALL_SSH_LDAP_HELPER)
-+
- dnl    Checks for library functions. Please keep in alphabetical order
- AC_CHECK_FUNCS([ \
- 	Blowfish_initstate \
-diff --git a/ldap-helper.c b/ldap-helper.c
-new file mode 100644
-index 0000000..e95a94a
---- /dev/null
-+++ b/ldap-helper.c
-@@ -0,0 +1,155 @@
-+/* $OpenBSD: ssh-pka-ldap.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
-+/*
-+ * Copyright (c) 2009 Jan F. Chadima.  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 "ldapincludes.h"
-+#include "log.h"
-+#include "misc.h"
-+#include "xmalloc.h"
-+#include "ldapconf.h"
-+#include "ldapbody.h"
-+#include <string.h>
-+#include <unistd.h>
-+
-+static int config_debug = 0;
-+int config_exclusive_config_file = 0;
-+static char *config_file_name = "/etc/ssh/ldap.conf";
-+static char *config_single_user = NULL;
-+static int config_verbose = SYSLOG_LEVEL_VERBOSE;
-+int config_warning_config_file = 0;
-+extern char *__progname;
-+
-+static void
-+usage(void)
-+{
-+	fprintf(stderr, "usage: %s [options]\n",
-+	    __progname);
-+	fprintf(stderr, "Options:\n");
-+	fprintf(stderr, "  -d          Output the log messages to stderr.\n");
-+	fprintf(stderr, "  -e          Check the config file for unknown commands.\n");
-+	fprintf(stderr, "  -f file     Use alternate config file (default is /etc/ssh/ldap.conf).\n");
-+	fprintf(stderr, "  -s user     Do not demonize, send the user's key to stdout.\n");
-+	fprintf(stderr, "  -v          Increase verbosity of the debug output (implies -d).\n");
-+	fprintf(stderr, "  -w          Warn on unknown commands in the config file.\n");
-+	exit(1);
-+}
-+
-+/*
-+ * Main program for the ssh pka ldap agent.
-+ */
-+
-+int
-+main(int ac, char **av)
-+{
-+	int opt;
-+	FILE *outfile = NULL;
-+
-+	__progname = ssh_get_progname(av[0]);
-+
-+	log_init(__progname, SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0);
-+
-+	/*
-+	 * Initialize option structure to indicate that no values have been
-+	 * set.
-+	 */
-+	initialize_options();
-+
-+	/* Parse command-line arguments. */
-+	while ((opt = getopt(ac, av, "def:s:vw")) != -1) {
-+		switch (opt) {
-+		case 'd':
-+			config_debug = 1;
-+			break;
-+
-+		case 'e':
-+			config_exclusive_config_file = 1;
-+			config_warning_config_file = 1;
-+			break;
-+
-+		case 'f':
-+			config_file_name = optarg;
-+			break;
-+
-+		case 's':
-+			config_single_user = optarg;
-+			outfile = fdopen (dup (fileno (stdout)), "w");
-+			break;
-+
-+		case 'v':
-+			config_debug = 1;
-+			if (config_verbose < SYSLOG_LEVEL_DEBUG3)
-+			    config_verbose++;
-+			break;
-+
-+		case 'w':
-+			config_warning_config_file = 1;
-+			break;
-+
-+		case '?':
-+		default:
-+			usage();
-+			break;
-+		}
-+	}
-+
-+	/* Initialize loging */
-+	log_init(__progname, config_verbose, SYSLOG_FACILITY_AUTH, config_debug);
-+
-+	if (ac != optind)
-+	    fatal ("illegal extra parameter %s", av[1]);
-+
-+	/* Ensure that fds 0 and 2 are open or directed to /dev/null */
-+	if (config_debug == 0)
-+	    sanitise_stdfd();
-+
-+	/* Read config file */
-+	read_config_file(config_file_name);
-+	fill_default_options();
-+	if (config_verbose == SYSLOG_LEVEL_DEBUG3) {
-+		debug3 ("=== Configuration ===");
-+		dump_config();
-+		debug3 ("=== *** ===");
-+	}
-+
-+	ldap_checkconfig();
-+	ldap_do_connect();
-+
-+	if (config_single_user) {
-+		process_user (config_single_user, outfile);
-+	} else {
-+		usage();
-+		fatal ("Not yet implemented");
-+/* TODO
-+ * open unix socket a run the loop on it
-+ */
-+	}
-+
-+	ldap_do_close();
-+	return 0;
-+}
-+
-+/* Ugly hack */
-+void   *buffer_get_string(Buffer *b, u_int *l) { return NULL; }
-+void    buffer_put_string(Buffer *b, const void *f, u_int l) {}
-+
-diff --git a/ldap-helper.h b/ldap-helper.h
-new file mode 100644
-index 0000000..14cb29a
---- /dev/null
-+++ b/ldap-helper.h
-@@ -0,0 +1,32 @@
-+/* $OpenBSD: ldap-helper.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
-+/*
-+ * Copyright (c) 2009 Jan F. Chadima.  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 LDAP_HELPER_H
-+#define LDAP_HELPER_H
-+
-+extern int config_exclusive_config_file;
-+extern int config_warning_config_file;
-+
-+#endif /* LDAP_HELPER_H */
-diff --git a/ldap.conf b/ldap.conf
-new file mode 100644
-index 0000000..42e38d3
---- /dev/null
-+++ b/ldap.conf
-@@ -0,0 +1,88 @@
-+# $Id: openssh-5.5p1-ldap.patch,v 1.3 2010/07/07 13:48:36 jfch2222 Exp $
-+#
-+# This is the example configuration file for the OpenSSH
-+# LDAP backend
-+# 
-+# see ssh-ldap.conf(5)
-+#
-+
-+# URI with your LDAP server name. This allows to use
-+# Unix Domain Sockets to connect to a local LDAP Server.
-+#uri ldap://127.0.0.1/
-+#uri ldaps://127.0.0.1/   
-+#uri ldapi://%2fvar%2frun%2fldapi_sock/
-+# Note: %2f encodes the '/' used as directory separator
-+
-+# Another way to specify your LDAP server is to provide an
-+# host name and the port of our LDAP server. Host name
-+# must be resolvable without using LDAP.
-+# Multiple hosts may be specified, each separated by a 
-+# space. How long nss_ldap takes to failover depends on
-+# whether your LDAP client library supports configurable
-+# network or connect timeouts (see bind_timelimit).
-+#host 127.0.0.1
-+
-+# The port.
-+# Optional: default is 389.
-+#port 389
-+
-+# The distinguished name to bind to the server with.
-+# Optional: default is to bind anonymously.
-+#binddn cn=openssh_keys,dc=example,dc=org
-+
-+# The credentials to bind with. 
-+# Optional: default is no credential.
-+#bindpw TopSecret
-+
-+# The distinguished name of the search base.
-+#base dc=example,dc=org
-+
-+# The LDAP version to use (defaults to 3
-+# if supported by client library)
-+#ldap_version 3
-+
-+# The search scope.
-+#scope sub
-+#scope one
-+#scope base
-+
-+# Search timelimit
-+#timelimit 30
-+
-+# Bind/connect timelimit
-+#bind_timelimit 30
-+
-+# Reconnect policy: hard (default) will retry connecting to
-+# the software with exponential backoff, soft will fail
-+# immediately.
-+#bind_policy hard
-+
-+# SSL setup, may be implied by URI also.
-+#ssl no
-+#ssl on
-+#ssl start_tls
-+
-+# OpenLDAP SSL options
-+# Require and verify server certificate (yes/no)
-+# Default is to use libldap's default behavior, which can be configured in
-+# /etc/openldap/ldap.conf using the TLS_REQCERT setting.  The default for
-+# OpenLDAP 2.0 and earlier is "no", for 2.1 and later is "yes".
-+#tls_checkpeer hard
-+
-+# CA certificates for server certificate verification
-+# At least one of these are required if tls_checkpeer is "yes"
-+#tls_cacertfile /etc/ssl/ca.cert
-+#tls_cacertdir /etc/pki/tls/certs
-+
-+# Seed the PRNG if /dev/urandom is not provided
-+#tls_randfile /var/run/egd-pool
-+
-+# SSL cipher suite
-+# See man ciphers for syntax
-+#tls_ciphers TLSv1
-+
-+# Client certificate and key
-+# Use these, if your server requires client authentication.
-+#tls_cert
-+#tls_key
-+
-diff --git a/ldapbody.c b/ldapbody.c
-new file mode 100644
-index 0000000..3029108
---- /dev/null
-+++ b/ldapbody.c
-@@ -0,0 +1,494 @@
-+/* $OpenBSD: ldapbody.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
-+/*
-+ * Copyright (c) 2009 Jan F. Chadima.  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 "ldapincludes.h"
-+#include "log.h"
-+#include "xmalloc.h"
-+#include "ldapconf.h"
-+#include "ldapmisc.h"
-+#include "ldapbody.h"
-+#include <stdio.h>
-+#include <unistd.h>
-+
-+#define LDAPSEARCH_FORMAT "(&(objectclass=%s)(objectclass=ldapPublicKey)(uid=%s)%s)"
-+#define PUBKEYATTR "sshPublicKey"
-+#define LDAP_LOGFILE	"%s/ldap.%d"
-+
-+static FILE *logfile = NULL;
-+static LDAP *ld;
-+
-+static char *attrs[] = {
-+    PUBKEYATTR,
-+    NULL
-+};
-+
-+void
-+ldap_checkconfig (void)
-+{
-+#ifdef HAVE_LDAP_INITIALIZE
-+		if (options.host == NULL && options.uri == NULL)
-+#else
-+		if (options.host == NULL)
-+#endif
-+		    fatal ("missing  \"host\" in config file");
-+}
-+
-+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-+static int
-+_rebind_proc (LDAP * ld, LDAP_CONST char *url, int request, ber_int_t msgid)
-+{
-+	struct timeval timeout;
-+	int rc;
-+#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE)
-+	LDAPMessage *result;
-+#endif /* HAVE_LDAP_PARSE_RESULT && HAVE_LDAP_CONTROLS_FREE */
-+
-+	debug2 ("Doing LDAP rebind to %s", options.binddn);
-+	if (options.ssl == SSL_START_TLS) {
-+		if ((rc = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS) {
-+			error ("ldap_starttls_s: %s", ldap_err2string (rc));
-+			return LDAP_OPERATIONS_ERROR;
-+		}
-+	}
-+
-+#if !defined(HAVE_LDAP_PARSE_RESULT) || !defined(HAVE_LDAP_CONTROLS_FREE)
-+	return ldap_simple_bind_s (ld, options.binddn, options.bindpw);
-+#else
-+	if (ldap_simple_bind(ld, options.binddn, options.bindpw) < 0)
-+	    fatal ("ldap_simple_bind %s", ldap_err2string (ldap_get_lderrno (ld, 0, 0)));
-+
-+	timeout.tv_sec = options.bind_timelimit;
-+	timeout.tv_usec = 0;
-+	result = NULL;
-+	if ((rc = ldap_result (ld, msgid, FALSE, &timeout, &result)) < 1) {
-+		error ("ldap_result %s", ldap_err2string (ldap_get_lderrno (ld, 0, 0)));
-+		ldap_msgfree (result);
-+		return LDAP_OPERATIONS_ERROR;
-+	}
-+	debug3 ("LDAP rebind to %s succesfull", options.binddn);
-+	return rc;
-+#endif
-+}
-+#else
-+
-+static int
-+_rebind_proc (LDAP * ld, char **whop, char **credp, int *methodp, int freeit)
-+{
-+	if (freeit)
-+	    return LDAP_SUCCESS;
-+
-+	*whop = strdup (options.binddn);
-+	*credp = strdup (options.bindpw);
-+	*methodp = LDAP_AUTH_SIMPLE;
-+	debug2 ("Doing LDAP rebind for %s", *whop);
-+	return LDAP_SUCCESS;
-+}
-+#endif
-+
-+void
-+ldap_do_connect(void)
-+{
-+	int rc, msgid, ld_errno = 0;
-+	struct timeval timeout;
-+#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE)
-+	int parserc;
-+	LDAPMessage *result;
-+	LDAPControl **controls;
-+	int reconnect = 0;
-+#endif /* HAVE_LDAP_PARSE_RESULT && HAVE_LDAP_CONTROLS_FREE */
-+
-+	debug ("LDAP do connect");
-+
-+retry:
-+	if (reconnect) {
-+		debug3 ("Reconnecting with ld_errno %d", ld_errno);
-+		if (options.bind_policy == 0 ||
-+		    (ld_errno != LDAP_SERVER_DOWN && ld_errno != LDAP_TIMEOUT) ||
-+			reconnect > 5)
-+			    fatal ("Cannot connect to LDAP server");
-+	
-+		if (reconnect > 1)
-+			sleep (reconnect - 1);
-+
-+		if (ld != NULL) {
-+			ldap_unbind (ld);
-+			ld = NULL;
-+		}
-+		logit("reconnecting to LDAP server...");
-+	}
-+
-+	if (ld == NULL) {
-+		int rc;
-+		struct timeval tv;
-+
-+#ifdef HAVE_LDAP_SET_OPTION
-+		if (options.debug > 0) {
-+#ifdef LBER_OPT_LOG_PRINT_FILE
-+			if (options.logdir) {
-+				char *logfilename;
-+				int logfilenamelen;
-+
-+				logfilenamelen = strlen (LDAP_LOGFILE) + strlen ("000000") + strlen (options.logdir);
-+				logfilename = xmalloc (logfilenamelen);
-+				snprintf (logfilename, logfilenamelen, LDAP_LOGFILE, options.logdir, (int) getpid ());
-+				logfilename[logfilenamelen - 1] = 0;
-+				if ((logfile = fopen (logfilename, "a")) == NULL)
-+				    fatal ("cannot append to %s: %s", logfilename, strerror (errno));
-+				debug3 ("LDAP debug into %s", logfilename);
-+				free (logfilename);
-+				ber_set_option (NULL, LBER_OPT_LOG_PRINT_FILE, logfile);
-+			}
-+#endif
-+			if (options.debug) {
-+#ifdef LBER_OPT_DEBUG_LEVEL
-+				ber_set_option (NULL, LBER_OPT_DEBUG_LEVEL, &options.debug);
-+#endif /* LBER_OPT_DEBUG_LEVEL */
-+#ifdef LDAP_OPT_DEBUG_LEVEL
-+				(void) ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &options.debug);
-+#endif /* LDAP_OPT_DEBUG_LEVEL */
-+				debug3 ("Set LDAP debug to %d", options.debug);
-+			}
-+		}
-+#endif /* HAVE_LDAP_SET_OPTION */
-+
-+		ld = NULL;
-+#ifdef HAVE_LDAPSSL_INIT
-+		if (options.host != NULL) {
-+			if (options.ssl_on == SSL_LDAPS) {
-+				if ((rc = ldapssl_client_init (options.sslpath, NULL)) != LDAP_SUCCESS)
-+				    fatal ("ldapssl_client_init %s", ldap_err2string (rc));
-+				debug3 ("LDAPssl client init");
-+			}
-+
-+			if (options.ssl_on != SSL_OFF) {
-+				if ((ld = ldapssl_init (options.host, options.port, TRUE)) == NULL)
-+				    fatal ("ldapssl_init failed");
-+				debug3 ("LDAPssl init");
-+			}
-+		}
-+#endif /* HAVE_LDAPSSL_INIT */
-+
-+		/* continue with opening */
-+		if (ld == NULL) {
-+#if defined (HAVE_LDAP_START_TLS_S) || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS))
-+			/* Some global TLS-specific options need to be set before we create our
-+			 * session context, so we set them here. */
-+
-+#ifdef LDAP_OPT_X_TLS_RANDOM_FILE
-+			/* rand file */
-+			if (options.tls_randfile != NULL) {
-+				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
-+				    options.tls_randfile)) != LDAP_SUCCESS)
-+					fatal ("ldap_set_option(LDAP_OPT_X_TLS_RANDOM_FILE): %s",
-+					    ldap_err2string (rc));
-+				debug3 ("Set TLS random file %s", options.tls_randfile);
-+			}
-+#endif /* LDAP_OPT_X_TLS_RANDOM_FILE */
-+
-+			/* ca cert file */
-+			if (options.tls_cacertfile != NULL) {
-+				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE,
-+				    options.tls_cacertfile)) != LDAP_SUCCESS)
-+					error ("ldap_set_option(LDAP_OPT_X_TLS_CACERTFILE): %s",
-+					    ldap_err2string (rc));
-+				debug3 ("Set TLS CA cert file %s ", options.tls_cacertfile);
-+			}
-+
-+			/* ca cert directory */
-+			if (options.tls_cacertdir != NULL) {
-+				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR,
-+				    options.tls_cacertdir)) != LDAP_SUCCESS)
-+					fatal ("ldap_set_option(LDAP_OPT_X_TLS_CACERTDIR): %s",
-+					    ldap_err2string (rc));
-+				debug3 ("Set TLS CA cert dir %s ", options.tls_cacertdir);
-+			}
-+
-+			/* require cert? */
-+			if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
-+			    &options.tls_checkpeer)) != LDAP_SUCCESS)
-+				fatal ("ldap_set_option(LDAP_OPT_X_TLS_REQUIRE_CERT): %s",
-+				    ldap_err2string (rc));
-+			debug3 ("Set TLS check peer to %d ", options.tls_checkpeer);
-+
-+			/* set cipher suite, certificate and private key: */
-+			if (options.tls_ciphers != NULL) {
-+				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
-+				    options.tls_ciphers)) != LDAP_SUCCESS)
-+					fatal ("ldap_set_option(LDAP_OPT_X_TLS_CIPHER_SUITE): %s",
-+					    ldap_err2string (rc));
-+				debug3 ("Set TLS ciphers to %s ", options.tls_ciphers);
-+			}
-+
-+			/* cert file */
-+			if (options.tls_cert != NULL) {
-+				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE,
-+				    options.tls_cert)) != LDAP_SUCCESS)
-+					fatal ("ldap_set_option(LDAP_OPT_X_TLS_CERTFILE): %s",
-+					    ldap_err2string (rc));
-+				debug3 ("Set TLS cert file %s ", options.tls_cert);
-+			}
-+
-+			/* key file */
-+			if (options.tls_key != NULL) {
-+				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE,
-+				    options.tls_key)) != LDAP_SUCCESS)
-+					fatal ("ldap_set_option(LDAP_OPT_X_TLS_KEYFILE): %s",
-+					    ldap_err2string (rc));
-+				debug3 ("Set TLS key file %s ", options.tls_key);
-+			}
-+#endif
-+#ifdef HAVE_LDAP_INITIALIZE
-+			if (options.uri != NULL) {
-+				if ((rc = ldap_initialize (&ld, options.uri)) != LDAP_SUCCESS)
-+					fatal ("ldap_initialize %s", ldap_err2string (rc));
-+				debug3 ("LDAP initialize %s", options.uri);
-+			}
-+	}
-+#endif /* HAVE_LDAP_INTITIALIZE */
-+
-+		/* continue with opening */
-+		if ((ld == NULL) && (options.host != NULL)) {
-+#ifdef HAVE_LDAP_INIT
-+			if ((ld = ldap_init (options.host, options.port)) == NULL)
-+			    fatal ("ldap_init failed");
-+			debug3 ("LDAP init %s:%d", options.host, options.port);
-+#else
-+			if ((ld = ldap_open (options.host, options.port)) == NULL)
-+			    fatal ("ldap_open failed");
-+			debug3 ("LDAP open %s:%d", options.host, options.port);
-+#endif /* HAVE_LDAP_INIT */
-+		}
-+
-+		if (ld == NULL)
-+			fatal ("no way to open ldap");
-+
-+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
-+		if (options.ssl == SSL_LDAPS) {
-+			if ((rc = ldap_set_option (ld, LDAP_OPT_X_TLS, &options.tls_checkpeer)) != LDAP_SUCCESS)
-+				fatal ("ldap_set_option(LDAP_OPT_X_TLS) %s", ldap_err2string (rc));
-+			debug3 ("LDAP set LDAP_OPT_X_TLS_%d", options.tls_checkpeer);
-+		}
-+#endif /* LDAP_OPT_X_TLS */
-+
-+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_PROTOCOL_VERSION)
-+		(void) ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION,
-+		    &options.ldap_version);
-+#else
-+		ld->ld_version = options.ldap_version;
-+#endif
-+		debug3 ("LDAP set version to %d", options.ldap_version);
-+
-+#if LDAP_SET_REBIND_PROC_ARGS == 3
-+		ldap_set_rebind_proc (ld, _rebind_proc, NULL);
-+#elif LDAP_SET_REBIND_PROC_ARGS == 2
-+		ldap_set_rebind_proc (ld, _rebind_proc);
-+#else
-+#warning unknown LDAP_SET_REBIND_PROC_ARGS
-+#endif
-+		debug3 ("LDAP set rebind proc");
-+
-+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_DEREF)
-+		(void) ldap_set_option (ld, LDAP_OPT_DEREF, &options.deref);
-+#else
-+		ld->ld_deref = options.deref;
-+#endif
-+		debug3 ("LDAP set deref to %d", options.deref);
-+
-+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_TIMELIMIT)
-+		(void) ldap_set_option (ld, LDAP_OPT_TIMELIMIT,
-+		    &options.timelimit);
-+#else
-+		ld->ld_timelimit = options.timelimit;
-+#endif
-+		debug3 ("LDAP set timelimit to %d", options.timelimit);
-+
-+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_X_OPT_CONNECT_TIMEOUT)
-+		/*
-+		 * This is a new option in the Netscape SDK which sets 
-+		 * the TCP connect timeout. For want of a better value,
-+		 * we use the bind_timelimit to control this.
-+		 */
-+		timeout = options.bind_timelimit * 1000;
-+		(void) ldap_set_option (ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout);
-+		debug3 ("LDAP set opt connect timeout to %d", timeout);
-+#endif
-+
-+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_NETWORK_TIMEOUT)
-+		tv.tv_sec = options.bind_timelimit;
-+		tv.tv_usec = 0;
-+		(void) ldap_set_option (ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
-+		debug3 ("LDAP set opt network timeout to %ld.0", tv.tv_sec);
-+#endif
-+
-+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_REFERRALS)
-+		(void) ldap_set_option (ld, LDAP_OPT_REFERRALS,
-+		    options.referrals ? LDAP_OPT_ON : LDAP_OPT_OFF);
-+		debug3 ("LDAP set referrals to %d", options.referrals);
-+#endif
-+
-+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_RESTART)
-+		(void) ldap_set_option (ld, LDAP_OPT_RESTART,
-+		    options.restart ? LDAP_OPT_ON : LDAP_OPT_OFF);
-+		debug3 ("LDAP set restart to %d", options.restart);
-+#endif
-+
-+#ifdef HAVE_LDAP_START_TLS_S
-+		if (options.ssl == SSL_START_TLS) {
-+			int version;
-+
-+			if (ldap_get_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version)
-+			    == LDAP_SUCCESS) {
-+				if (version < LDAP_VERSION3) {
-+					version = LDAP_VERSION3;
-+					(void) ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION,
-+					    &version);
-+					debug3 ("LDAP set version to %d", version);
-+				}
-+			}
-+
-+			if ((rc = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS)
-+			    fatal ("ldap_starttls_s: %s", ldap_err2string (rc));
-+			debug3 ("LDAP start TLS");
-+		}
-+#endif /* HAVE_LDAP_START_TLS_S */
-+	}
-+
-+	if ((msgid = ldap_simple_bind (ld, options.binddn,
-+	    options.bindpw)) == -1) {
-+		ld_errno = ldap_get_lderrno (ld, 0, 0);
-+
-+		error ("ldap_simple_bind %s", ldap_err2string (ld_errno));
-+		reconnect++;
-+		goto retry;
-+	}
-+	debug3 ("LDAP simple bind (%s)", options.binddn);
-+
-+	timeout.tv_sec = options.bind_timelimit;
-+	timeout.tv_usec = 0;
-+	if ((rc = ldap_result (ld, msgid, FALSE, &timeout, &result)) < 1) {
-+		ld_errno = ldap_get_lderrno (ld, 0, 0);
-+
-+		error ("ldap_result %s", ldap_err2string (ld_errno));
-+		reconnect++;
-+		goto retry;
-+	}
-+	debug3 ("LDAP result in time");
-+
-+#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE)
-+	controls = NULL;
-+	if ((parserc = ldap_parse_result (ld, result, &rc, 0, 0, 0, &controls, TRUE)) != LDAP_SUCCESS)
-+	    fatal ("ldap_parse_result %s", ldap_err2string (parserc));
-+	debug3 ("LDAP parse result OK");
-+
-+	if (controls != NULL) {
-+		ldap_controls_free (controls);
-+	}
-+#else
-+	rc = ldap_result2error (session->ld, result, TRUE);
-+#endif
-+	if (rc != LDAP_SUCCESS)
-+	    fatal ("error trying to bind as user \"%s\" (%s)",
-+		options.binddn, ldap_err2string (rc));
-+
-+	debug2 ("LDAP do connect OK");
-+}
-+
-+void
-+process_user (const char *user, FILE *output)
-+{
-+	LDAPMessage *res, *e;
-+	char *buffer;
-+	int bufflen, rc, i;
-+	struct timeval timeout;
-+
-+	debug ("LDAP process user");
-+
-+	/* quick check for attempts to be evil */
-+	if ((strchr(user, '(') != NULL) || (strchr(user, ')') != NULL) ||
-+	    (strchr(user, '*') != NULL) || (strchr(user, '\\') != NULL)) {
-+		logit ("illegal user name %s not processed", user);
-+		return;
-+	}
-+
-+	/* build  filter for LDAP request */
-+	bufflen = strlen (LDAPSEARCH_FORMAT) + strlen(options.account_class) + strlen (user);
-+	if (options.ssh_filter != NULL)
-+	    bufflen += strlen (options.ssh_filter);
-+	buffer = xmalloc (bufflen);
-+	snprintf(buffer, bufflen, LDAPSEARCH_FORMAT, options.account_class, user, (options.ssh_filter != NULL) ? options.ssh_filter : NULL);
-+	buffer[bufflen - 1] = 0;
-+
-+	debug3 ("LDAP search scope = %d %s", options.scope, buffer);
-+
-+	timeout.tv_sec = options.timelimit;
-+	timeout.tv_usec = 0;
-+	if ((rc = ldap_search_st(ld, options.base, options.scope, buffer, attrs, 0, &timeout, &res)) != LDAP_SUCCESS) {
-+		error ("ldap_search_st(): %s", ldap_err2string (rc));
-+		free (buffer);
-+		return;
-+	}
-+
-+	/* free */
-+	free (buffer);
-+
-+	for (e = ldap_first_entry(ld, res); e != NULL; e = ldap_next_entry(ld, e)) {
-+		int num;
-+		struct berval **keys;
-+
-+		keys = ldap_get_values_len(ld, e, PUBKEYATTR);
-+		num = ldap_count_values_len(keys);
-+		for (i = 0 ; i < num ; i++) {
-+			char *cp; //, *options = NULL;
-+
-+			for (cp = keys[i]->bv_val; *cp == ' ' || *cp == '\t'; cp++);
-+			if (!*cp || *cp == '\n' || *cp == '#')
-+			    continue;
-+
-+			/* We have found the desired key. */
-+			fprintf (output, "%s\n", keys[i]->bv_val);
-+		}
-+
-+		ldap_value_free_len(keys);
-+	}
-+
-+	ldap_msgfree(res);
-+	debug2 ("LDAP process user finished");
-+}
-+
-+void
-+ldap_do_close(void)
-+{
-+	int rc;
-+
-+	debug ("LDAP do close");
-+	if ((rc = ldap_unbind_ext(ld, NULL, NULL)) != LDAP_SUCCESS)
-+	    fatal ("ldap_unbind_ext: %s",
-+                                    ldap_err2string (rc));
-+
-+	ld = NULL;
-+	debug2 ("LDAP do close OK");
-+	return;
-+}
-+
-diff --git a/ldapbody.h b/ldapbody.h
-new file mode 100644
-index 0000000..665dca2
---- /dev/null
-+++ b/ldapbody.h
-@@ -0,0 +1,37 @@
-+/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
-+/*
-+ * Copyright (c) 2009 Jan F. Chadima.  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 LDAPBODY_H
-+#define LDAPBODY_H
-+
-+#include <stdio.h>
-+
-+void ldap_checkconfig(void);
-+void ldap_do_connect(void);
-+void process_user(const char *, FILE *);
-+void ldap_do_close(void);
-+
-+#endif /* LDAPBODY_H */
-+
-diff --git a/ldapconf.c b/ldapconf.c
-new file mode 100644
-index 0000000..525060a
---- /dev/null
-+++ b/ldapconf.c
-@@ -0,0 +1,722 @@
-+/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
-+/*
-+ * Copyright (c) 2009 Jan F. Chadima.  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 "ldapincludes.h"
-+#include "ldap-helper.h"
-+#include "log.h"
-+#include "misc.h"
-+#include "xmalloc.h"
-+#include "ldapconf.h"
-+#include <unistd.h>
-+#include <string.h>
-+
-+/* Keyword tokens. */
-+
-+typedef enum {
-+	lBadOption,
-+	lHost, lURI, lBase, lBindDN, lBindPW, lRootBindDN,
-+	lScope, lDeref, lPort, lTimeLimit, lBind_TimeLimit,
-+	lLdap_Version, lBind_Policy, lSSLPath, lSSL, lReferrals,
-+	lRestart, lTLS_CheckPeer, lTLS_CaCertFile,
-+	lTLS_CaCertDir, lTLS_Ciphers, lTLS_Cert, lTLS_Key,
-+	lTLS_RandFile, lLogDir, lDebug, lSSH_Filter,
-+	lAccountClass, lDeprecated, lUnsupported
-+} OpCodes;
-+
-+/* Textual representations of the tokens. */
-+
-+static struct {
-+	const char *name;
-+	OpCodes opcode;
-+} keywords[] = {
-+	{ "URI", lURI },
-+	{ "Base", lBase },
-+	{ "BindDN", lBindDN },
-+	{ "BindPW", lBindPW },
-+	{ "RootBindDN", lRootBindDN },
-+	{ "Host", lHost },
-+	{ "Port", lPort },
-+	{ "Scope", lScope },
-+	{ "Deref", lDeref },
-+	{ "TimeLimit", lTimeLimit },
-+	{ "TimeOut", lTimeLimit },
-+	{ "Bind_Timelimit", lBind_TimeLimit },
-+	{ "Network_TimeOut", lBind_TimeLimit },
-+/*
-+ * Todo
-+ * SIZELIMIT
-+ */
-+	{ "Ldap_Version", lLdap_Version },
-+	{ "Version", lLdap_Version },
-+	{ "Bind_Policy", lBind_Policy },
-+	{ "SSLPath", lSSLPath },
-+	{ "SSL", lSSL },
-+	{ "Referrals", lReferrals },
-+	{ "Restart", lRestart },
-+	{ "TLS_CheckPeer", lTLS_CheckPeer },
-+	{ "TLS_ReqCert", lTLS_CheckPeer },
-+	{ "TLS_CaCertFile", lTLS_CaCertFile },
-+	{ "TLS_CaCert", lTLS_CaCertFile },
-+	{ "TLS_CaCertDir", lTLS_CaCertDir },
-+	{ "TLS_Ciphers", lTLS_Ciphers },
-+	{ "TLS_Cipher_Suite", lTLS_Ciphers },
-+	{ "TLS_Cert", lTLS_Cert },
-+	{ "TLS_Certificate", lTLS_Cert },
-+	{ "TLS_Key", lTLS_Key },
-+	{ "TLS_RandFile", lTLS_RandFile },
-+/*
-+ * Todo
-+ * TLS_CRLCHECK
-+ * TLS_CRLFILE
-+ */
-+	{ "LogDir", lLogDir },
-+	{ "Debug", lDebug },
-+	{ "SSH_Filter", lSSH_Filter },
-+	{ "AccountClass", lAccountClass },
-+	{ NULL, lBadOption }
-+};
-+
-+/* Configuration ptions. */
-+
-+Options options;
-+
-+/*
-+ * Returns the number of the token pointed to by cp or oBadOption.
-+ */
-+
-+static OpCodes
-+parse_token(const char *cp, const char *filename, int linenum)
-+{
-+	u_int i;
-+
-+	for (i = 0; keywords[i].name; i++)
-+		if (strcasecmp(cp, keywords[i].name) == 0)
-+			return keywords[i].opcode;
-+
-+	if (config_warning_config_file) 
-+	    logit("%s: line %d: Bad configuration option: %s",
-+		filename, linenum, cp);
-+	return lBadOption;
-+}
-+
-+/* Characters considered whitespace in strsep calls. */
-+#define WHITESPACE " \t\r\n"
-+
-+/* return next token in configuration line */
-+static char *
-+ldap_strdelim(char **s)
-+{
-+      char *old;
-+      int wspace = 0;
-+
-+      if (*s == NULL)
-+              return NULL;
-+
-+      old = *s;
-+
-+      *s = strpbrk(*s, WHITESPACE);
-+      if (*s == NULL)
-+              return (old);
-+
-+      *s[0] = '\0';
-+
-+      /* Skip any extra whitespace after first token */
-+      *s += strspn(*s + 1, WHITESPACE) + 1;
-+      if (*s[0] == '=' && !wspace)
-+              *s += strspn(*s + 1, WHITESPACE) + 1;
-+
-+      return (old);
-+}
-+
-+/*
-+ * Processes a single option line as used in the configuration files. This
-+ * only sets those values that have not already been set.
-+ */
-+#define WHITESPACE " \t\r\n"
-+
-+static int
-+process_config_line(char *line, const char *filename, int linenum)
-+{
-+	char *s, **charptr, **xstringptr, *endofnumber, *keyword, *arg;
-+	char *rootbinddn = NULL;
-+	int opcode, *intptr, value;
-+	size_t len;
-+
-+	/* Strip trailing whitespace */
-+	for (len = strlen(line) - 1; len > 0; len--) {
-+		if (strchr(WHITESPACE, line[len]) == NULL)
-+			break;
-+		line[len] = '\0';
-+	}
-+
-+	s = line;
-+	/* Get the keyword. (Each line is supposed to begin with a keyword). */
-+	if ((keyword = ldap_strdelim(&s)) == NULL)
-+		return 0;
-+	/* Ignore leading whitespace. */
-+	if (*keyword == '\0')
-+		keyword = ldap_strdelim(&s);
-+	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
-+		return 0;
-+
-+	opcode = parse_token(keyword, filename, linenum);
-+
-+	switch (opcode) {
-+	case lBadOption:
-+		/* don't panic, but count bad options */
-+		return -1;
-+		/* NOTREACHED */
-+
-+	case lHost:
-+		xstringptr = &options.host;
-+parse_xstring:
-+		if (!s || *s == '\0')
-+		    fatal("%s line %d: missing dn",filename,linenum);
-+		if (*xstringptr == NULL)
-+		    *xstringptr = xstrdup(s);
-+		return 0;
-+
-+	case lURI:
-+		xstringptr = &options.uri;
-+		goto parse_xstring;
-+
-+	case lBase:
-+		xstringptr = &options.base;
-+		goto parse_xstring;
-+
-+	case lBindDN:
-+		xstringptr = &options.binddn;
-+		goto parse_xstring;
-+
-+	case lBindPW:
-+		charptr = &options.bindpw;
-+parse_string:
-+		arg = ldap_strdelim(&s);
-+		if (!arg || *arg == '\0')
-+			fatal("%.200s line %d: Missing argument.", filename, linenum);
-+		if (*charptr == NULL)
-+			*charptr = xstrdup(arg);
-+		break;
-+
-+	case lRootBindDN:
-+		xstringptr = &rootbinddn;
-+		goto parse_xstring;
-+
-+	case lScope:
-+		intptr = &options.scope;
-+		arg = ldap_strdelim(&s);
-+		if (!arg || *arg == '\0')
-+			fatal("%.200s line %d: Missing sub/one/base argument.", filename, linenum);
-+		value = 0;	/* To avoid compiler warning... */
-+		if (strcasecmp (arg, "sub") == 0 || strcasecmp (arg, "subtree") == 0)
-+			value = LDAP_SCOPE_SUBTREE;
-+		else if (strcasecmp (arg, "one") == 0)
-+			value = LDAP_SCOPE_ONELEVEL;
-+		else if (strcasecmp (arg, "base") == 0)
-+			value = LDAP_SCOPE_BASE;
-+		else
-+			fatal("%.200s line %d: Bad sub/one/base argument.", filename, linenum);
-+		if (*intptr == -1)
-+			*intptr = value;
-+		break;
-+
-+	case lDeref:
-+		intptr = &options.scope;
-+		arg = ldap_strdelim(&s);
-+		if (!arg || *arg == '\0')
-+			fatal("%.200s line %d: Missing never/searching/finding/always argument.", filename, linenum);
-+		value = 0;	/* To avoid compiler warning... */
-+		if (!strcasecmp (arg, "never"))
-+			value = LDAP_DEREF_NEVER;
-+		else if (!strcasecmp (arg, "searching"))
-+			value = LDAP_DEREF_SEARCHING;
-+		else if (!strcasecmp (arg, "finding"))
-+			value = LDAP_DEREF_FINDING;
-+		else if (!strcasecmp (arg, "always"))
-+			value = LDAP_DEREF_ALWAYS;
-+		else
-+			fatal("%.200s line %d: Bad never/searching/finding/always argument.", filename, linenum);
-+		if (*intptr == -1)
-+			*intptr = value;
-+		break;
-+
-+	case lPort:
-+		intptr = &options.port;
-+parse_int:
-+		arg = ldap_strdelim(&s);
-+		if (!arg || *arg == '\0')
-+			fatal("%.200s line %d: Missing argument.", filename, linenum);
-+		if (arg[0] < '0' || arg[0] > '9')
-+			fatal("%.200s line %d: Bad number.", filename, linenum);
-+
-+		/* Octal, decimal, or hex format? */
-+		value = strtol(arg, &endofnumber, 0);
-+		if (arg == endofnumber)
-+			fatal("%.200s line %d: Bad number.", filename, linenum);
-+		if (*intptr == -1)
-+			*intptr = value;
-+		break;
-+
-+	case lTimeLimit:
-+		intptr = &options.timelimit;
-+parse_time:
-+		arg = ldap_strdelim(&s);
-+		if (!arg || *arg == '\0')
-+			fatal("%s line %d: missing time value.",
-+			    filename, linenum);
-+		if ((value = convtime(arg)) == -1)
-+			fatal("%s line %d: invalid time value.",
-+			    filename, linenum);
-+		if (*intptr == -1)
-+			*intptr = value;
-+		break;
-+
-+	case lBind_TimeLimit:
-+		intptr = &options.bind_timelimit;
-+		goto parse_time;
-+
-+	case lLdap_Version:
-+		intptr = &options.ldap_version;
-+		goto parse_int;
-+
-+	case lBind_Policy:
-+		intptr = &options.bind_policy;
-+		arg = ldap_strdelim(&s);
-+		if (!arg || *arg == '\0')
-+			fatal("%.200s line %d: Missing soft/hard argument.", filename, linenum);
-+		value = 0;	/* To avoid compiler warning... */
-+		if (strcasecmp(arg, "hard") == 0 || strcasecmp(arg, "hard_open") == 0 || strcasecmp(arg, "hard_init") == 0)
-+			value = 1;
-+		else if (strcasecmp(arg, "soft") == 0)
-+			value = 0;
-+		else
-+			fatal("%.200s line %d: Bad soft/hard argument.", filename, linenum);
-+		if (*intptr == -1)
-+			*intptr = value;
-+		break;
-+
-+	case lSSLPath:
-+		charptr = &options.sslpath;
-+		goto parse_string;
-+
-+	case lSSL:
-+		intptr = &options.ssl;
-+		arg = ldap_strdelim(&s);
-+		if (!arg || *arg == '\0')
-+			fatal("%.200s line %d: Missing yes/no/start_tls argument.", filename, linenum);
-+		value = 0;	/* To avoid compiler warning... */
-+		if (strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0 || strcasecmp(arg, "on") == 0)
-+			value = SSL_LDAPS;
-+		else if (strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0 || strcasecmp(arg, "off") == 0)
-+			value = SSL_OFF;
-+		else if (!strcasecmp (arg, "start_tls"))
-+			value = SSL_START_TLS;
-+		else
-+			fatal("%.200s line %d: Bad yes/no/start_tls argument.", filename, linenum);
-+		if (*intptr == -1)
-+			*intptr = value;
-+		break;
-+
-+	case lReferrals:
-+		intptr = &options.referrals;
-+parse_flag:
-+		arg = ldap_strdelim(&s);
-+		if (!arg || *arg == '\0')
-+			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
-+		value = 0;	/* To avoid compiler warning... */
-+		if (strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0 || strcasecmp(arg, "on") == 0)
-+			value = 1;
-+		else if (strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0 || strcasecmp(arg, "off") == 0)
-+			value = 0;
-+		else
-+			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
-+		if (*intptr == -1)
-+			*intptr = value;
-+		break;
-+
-+	case lRestart:
-+		intptr = &options.restart;
-+		goto parse_flag;
-+
-+	case lTLS_CheckPeer:
-+		intptr = &options.tls_checkpeer;
-+		arg = ldap_strdelim(&s);
-+		if (!arg || *arg == '\0')
-+			fatal("%.200s line %d: Missing never/hard/demand/alow/try argument.", filename, linenum);
-+		value = 0;	/* To avoid compiler warning... */
-+		if (strcasecmp(arg, "never") == 0 || strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0 || strcasecmp(arg, "off") == 0)
-+			value = LDAP_OPT_X_TLS_NEVER;
-+		else if (strcasecmp(arg, "hard") == 0 || strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0 || strcasecmp(arg, "on") == 0)
-+			value = LDAP_OPT_X_TLS_HARD;
-+		else if (strcasecmp(arg, "demand") == 0)
-+			value = LDAP_OPT_X_TLS_DEMAND;
-+		else if (strcasecmp(arg, "allow") == 0)
-+			value = LDAP_OPT_X_TLS_ALLOW;
-+		else if (strcasecmp(arg, "try") == 0)
-+			value = LDAP_OPT_X_TLS_TRY;
-+		else
-+			fatal("%.200s line %d: Bad never/hard/demand/alow/try argument.", filename, linenum);
-+		if (*intptr == -1)
-+			*intptr = value;
-+		break;
-+
-+	case lTLS_CaCertFile:
-+		charptr = &options.tls_cacertfile;
-+		goto parse_string;
-+
-+	case lTLS_CaCertDir:
-+		charptr = &options.tls_cacertdir;
-+		goto parse_string;
-+
-+	case lTLS_Ciphers:
-+		xstringptr = &options.tls_ciphers;
-+		goto parse_xstring;
-+
-+	case lTLS_Cert:
-+		charptr = &options.tls_cert;
-+		goto parse_string;
-+
-+	case lTLS_Key:
-+		charptr = &options.tls_key;
-+		goto parse_string;
-+
-+	case lTLS_RandFile:
-+		charptr = &options.tls_randfile;
-+		goto parse_string;
-+
-+	case lLogDir:
-+		charptr = &options.logdir;
-+		goto parse_string;
-+
-+	case lDebug:
-+		intptr = &options.debug;
-+		goto parse_int;
-+
-+	case lSSH_Filter:
-+		xstringptr = &options.ssh_filter;
-+		goto parse_xstring;
-+
-+	case lAccountClass:
-+		charptr = &options.account_class;
-+		goto parse_string;
-+
-+	case lDeprecated:
-+		debug("%s line %d: Deprecated option \"%s\"",
-+		    filename, linenum, keyword);
-+		return 0;
-+
-+	case lUnsupported:
-+		error("%s line %d: Unsupported option \"%s\"",
-+		    filename, linenum, keyword);
-+		return 0;
-+
-+	default:
-+		fatal("process_config_line: Unimplemented opcode %d", opcode);
-+	}
-+
-+	/* Check that there is no garbage at end of line. */
-+	if ((arg = ldap_strdelim(&s)) != NULL && *arg != '\0') {
-+		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
-+		    filename, linenum, arg);
-+	}
-+	return 0;
-+}
-+
-+/*
-+ * Reads the config file and modifies the options accordingly.  Options
-+ * should already be initialized before this call.  This never returns if
-+ * there is an error.  If the file does not exist, this returns 0.
-+ */
-+
-+void
-+read_config_file(const char *filename)
-+{
-+	FILE *f;
-+	char line[1024];
-+	int active, linenum;
-+	int bad_options = 0;
-+	struct stat sb;
-+
-+	if ((f = fopen(filename, "r")) == NULL)
-+		fatal("fopen %s: %s", filename, strerror(errno));
-+
-+	if (fstat(fileno(f), &sb) == -1)
-+		fatal("fstat %s: %s", filename, strerror(errno));
-+	if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
-+	    (sb.st_mode & 022) != 0))
-+		fatal("Bad owner or permissions on %s", filename);
-+
-+	debug("Reading configuration data %.200s", filename);
-+
-+	/*
-+	 * Mark that we are now processing the options.  This flag is turned
-+	 * on/off by Host specifications.
-+	 */
-+	active = 1;
-+	linenum = 0;
-+	while (fgets(line, sizeof(line), f)) {
-+		/* Update line number counter. */
-+		linenum++;
-+		if (process_config_line(line, filename, linenum) != 0)
-+			bad_options++;
-+	}
-+	fclose(f);
-+	if ((bad_options > 0) && config_exclusive_config_file) 
-+		fatal("%s: terminating, %d bad configuration options",
-+		    filename, bad_options);
-+}
-+
-+/*
-+ * Initializes options to special values that indicate that they have not yet
-+ * been set.  Read_config_file will only set options with this value. Options
-+ * are processed in the following order: command line, user config file,
-+ * system config file.  Last, fill_default_options is called.
-+ */
-+
-+void
-+initialize_options(void)
-+{
-+	memset(&options, 'X', sizeof(options));
-+	options.host = NULL;
-+	options.uri = NULL;
-+	options.base = NULL;
-+	options.binddn = NULL;
-+	options.bindpw = NULL;
-+	options.scope = -1;
-+	options.deref = -1;
-+	options.port = -1;
-+	options.timelimit = -1;
-+	options.bind_timelimit = -1;
-+	options.ldap_version = -1;
-+	options.bind_policy = -1;
-+	options.sslpath = NULL;
-+	options.ssl = -1;
-+	options.referrals = -1;
-+	options.restart = -1;
-+	options.tls_checkpeer = -1;
-+	options.tls_cacertfile = NULL;
-+	options.tls_cacertdir = NULL;
-+	options.tls_ciphers = NULL;
-+	options.tls_cert = NULL;
-+	options.tls_key = NULL;
-+	options.tls_randfile = NULL;
-+	options.logdir = NULL;
-+	options.debug = -1;
-+	options.ssh_filter = NULL;
-+	options.account_class = NULL;
-+}
-+
-+/*
-+ * Called after processing other sources of option data, this fills those
-+ * options for which no value has been specified with their default values.
-+ */
-+
-+void
-+fill_default_options(void)
-+{
-+	if (options.uri != NULL) {
-+		LDAPURLDesc *ludp;
-+
-+		if (ldap_url_parse(options.uri, &ludp) == LDAP_SUCCESS) {
-+			if (options.ssl == -1) {
-+				if (strcmp (ludp->lud_scheme, "ldap") == 0)
-+				    options.ssl = 2;
-+				if (strcmp (ludp->lud_scheme, "ldapi") == 0)
-+				    options.ssl = 0;
-+				else if (strcmp (ludp->lud_scheme, "ldaps") == 0)
-+				    options.ssl = 1;
-+			}
-+			if (options.host == NULL)
-+			    options.host = xstrdup (ludp->lud_host);
-+			if (options.port == -1)
-+			    options.port = ludp->lud_port;
-+
-+			ldap_free_urldesc (ludp);
-+		}
-+	} 
-+	if (options.ssl == -1)
-+	    options.ssl = SSL_START_TLS;
-+	if (options.port == -1)
-+	    options.port = (options.ssl == 0) ? 389 : 636;
-+	if (options.uri == NULL) {
-+		int len;
-+#define MAXURILEN 4096
-+
-+		options.uri = xmalloc (MAXURILEN);
-+		len = snprintf (options.uri, MAXURILEN, "ldap%s://%s:%d",
-+		    (options.ssl == 0) ? "" : "s", options.host, options.port);
-+		options.uri[MAXURILEN - 1] = 0;
-+		options.uri = xrealloc (options.uri, len + 1, 1);
-+	}
-+	if (options.binddn == NULL)
-+	    options.binddn = "";
-+	if (options.bindpw == NULL)
-+	    options.bindpw = "";
-+	if (options.scope == -1)
-+	    options.scope = LDAP_SCOPE_SUBTREE;
-+	if (options.deref == -1)
-+	    options.deref = LDAP_DEREF_NEVER;
-+	if (options.timelimit == -1)
-+	    options.timelimit = 10;
-+	if (options.bind_timelimit == -1)
-+	    options.bind_timelimit = 10;
-+	if (options.ldap_version == -1)
-+	    options.ldap_version = 3;
-+	if (options.bind_policy == -1)
-+	    options.bind_policy = 1;
-+	if (options.referrals == -1)
-+	    options.referrals = 1;
-+	if (options.restart == -1)
-+	    options.restart = 1;
-+	if (options.tls_checkpeer == -1)
-+	    options.tls_checkpeer = LDAP_OPT_X_TLS_HARD;
-+	if (options.debug == -1)
-+	    options.debug = 0;
-+	if (options.ssh_filter == NULL)
-+	    options.ssh_filter = "";
-+	if (options.account_class == NULL)
-+	    options.account_class = "posixAccount";
-+}
-+
-+static const char *
-+lookup_opcode_name(OpCodes code)
-+{
-+	u_int i;
-+
-+	for (i = 0; keywords[i].name != NULL; i++)
-+	    if (keywords[i].opcode == code)
-+		return(keywords[i].name);
-+	return "UNKNOWN";
-+}
-+
-+static void
-+dump_cfg_string(OpCodes code, const char *val)
-+{
-+	if (val == NULL)
-+	    debug3("%s <UNDEFINED>", lookup_opcode_name(code));
-+	else
-+	    debug3("%s %s", lookup_opcode_name(code), val);
-+}
-+
-+static void
-+dump_cfg_int(OpCodes code, int val)
-+{
-+	if (val == -1)
-+	    debug3("%s <UNDEFINED>", lookup_opcode_name(code));
-+	else
-+	    debug3("%s %d", lookup_opcode_name(code), val);
-+}
-+
-+struct names {
-+	int value;
-+	char *name;
-+};
-+
-+static void
-+dump_cfg_namedint(OpCodes code, int val, struct names *names)
-+{
-+	u_int i;
-+
-+	if (val == -1)
-+	    debug3("%s <UNDEFINED>", lookup_opcode_name(code));
-+	else {
-+		for (i = 0; names[i].value != -1; i++)
-+	 	    if (names[i].value == val) {
-+	    		debug3("%s %s", lookup_opcode_name(code), names[i].name);
-+			    return;
-+		}
-+		debug3("%s unknown: %d", lookup_opcode_name(code), val);
-+	}
-+}
-+
-+static struct names _yesnotls[] = {
-+	{ 0, "No" },
-+	{ 1, "Yes" },
-+	{ 2, "Start_TLS" },
-+	{ -1, NULL }};
-+
-+static struct names _scope[] = {
-+	{ LDAP_SCOPE_BASE, "Base" },
-+	{ LDAP_SCOPE_ONELEVEL, "One" },
-+	{ LDAP_SCOPE_SUBTREE, "Sub"},
-+	{ -1, NULL }};
-+
-+static struct names _deref[] = {
-+	{ LDAP_DEREF_NEVER, "Never" },
-+	{ LDAP_DEREF_SEARCHING, "Searching" },
-+	{ LDAP_DEREF_FINDING, "Finding" },
-+	{ LDAP_DEREF_ALWAYS, "Always" },
-+	{ -1, NULL }};
-+
-+static struct names _yesno[] = {
-+	{ 0, "No" },
-+	{ 1, "Yes" },
-+	{ -1, NULL }};
-+
-+static struct names _bindpolicy[] = {
-+	{ 0, "Soft" },
-+	{ 1, "Hard" },
-+	{ -1, NULL }};
-+
-+static struct names _checkpeer[] = {
-+	{ LDAP_OPT_X_TLS_NEVER, "Never" },
-+	{ LDAP_OPT_X_TLS_HARD, "Hard" },
-+	{ LDAP_OPT_X_TLS_DEMAND, "Demand" },
-+	{ LDAP_OPT_X_TLS_ALLOW, "Allow" },
-+	{ LDAP_OPT_X_TLS_TRY, "TRY" },
-+	{ -1, NULL }};
-+
-+void
-+dump_config(void)
-+{
-+	dump_cfg_string(lURI, options.uri);
-+	dump_cfg_string(lHost, options.host);
-+	dump_cfg_int(lPort, options.port);
-+	dump_cfg_namedint(lSSL, options.ssl, _yesnotls);
-+	dump_cfg_int(lLdap_Version, options.ldap_version);
-+	dump_cfg_int(lTimeLimit, options.timelimit);
-+	dump_cfg_int(lBind_TimeLimit, options.bind_timelimit);
-+	dump_cfg_string(lBase, options.base);
-+	dump_cfg_string(lBindDN, options.binddn);
-+	dump_cfg_string(lBindPW, options.bindpw);
-+	dump_cfg_namedint(lScope, options.scope, _scope);
-+	dump_cfg_namedint(lDeref, options.deref, _deref);
-+	dump_cfg_namedint(lReferrals, options.referrals, _yesno);
-+	dump_cfg_namedint(lRestart, options.restart, _yesno);
-+	dump_cfg_namedint(lBind_Policy, options.bind_policy, _bindpolicy);
-+	dump_cfg_string(lSSLPath, options.sslpath);
-+	dump_cfg_namedint(lTLS_CheckPeer, options.tls_checkpeer, _checkpeer);
-+	dump_cfg_string(lTLS_CaCertFile, options.tls_cacertfile);
-+	dump_cfg_string(lTLS_CaCertDir, options.tls_cacertdir);
-+	dump_cfg_string(lTLS_Ciphers, options.tls_ciphers);
-+	dump_cfg_string(lTLS_Cert, options.tls_cert);
-+	dump_cfg_string(lTLS_Key, options.tls_key);
-+	dump_cfg_string(lTLS_RandFile, options.tls_randfile);
-+	dump_cfg_string(lLogDir, options.logdir);
-+	dump_cfg_int(lDebug, options.debug);
-+	dump_cfg_string(lSSH_Filter, options.ssh_filter);
-+	dump_cfg_string(lAccountClass, options.logdir);
-+}
-+
-diff --git a/ldapconf.h b/ldapconf.h
-new file mode 100644
-index 0000000..2cb550c
---- /dev/null
-+++ b/ldapconf.h
-@@ -0,0 +1,72 @@
-+/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
-+/*
-+ * Copyright (c) 2009 Jan F. Chadima.  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 LDAPCONF_H
-+#define LDAPCONF_H
-+
-+#define SSL_OFF          0
-+#define SSL_LDAPS        1
-+#define SSL_START_TLS    2
-+
-+/* Data structure for representing option data. */
-+
-+typedef struct {
-+	char *host;
-+	char *uri;
-+	char *base;
-+	char *binddn;
-+	char *bindpw;
-+	int scope;
-+	int deref;
-+	int port;
-+	int timelimit;
-+	int bind_timelimit;
-+	int ldap_version;
-+	int bind_policy;
-+	char *sslpath;
-+	int ssl;
-+	int referrals;
-+	int restart;
-+	int tls_checkpeer;
-+	char *tls_cacertfile;
-+	char *tls_cacertdir;
-+	char *tls_ciphers;
-+	char *tls_cert;
-+	char *tls_key;
-+	char *tls_randfile;
-+	char *logdir;
-+	int debug;
-+	char *ssh_filter;
-+	char *account_class;
-+}       Options;
-+
-+extern Options options;
-+
-+void read_config_file(const char *);
-+void initialize_options(void);
-+void fill_default_options(void);
-+void dump_config(void);
-+
-+#endif /* LDAPCONF_H */
-diff --git a/ldapincludes.h b/ldapincludes.h
-new file mode 100644
-index 0000000..8539bdc
---- /dev/null
-+++ b/ldapincludes.h
-@@ -0,0 +1,41 @@
-+/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
-+/*
-+ * Copyright (c) 2009 Jan F. Chadima.  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 LDAPINCLUDES_H
-+#define LDAPINCLUDES_H
-+
-+#include "includes.h"
-+
-+#ifdef HAVE_LBER_H
-+#include <lber.h>
-+#endif
-+#ifdef HAVE_LDAP_H
-+#include <ldap.h>
-+#endif
-+#ifdef HAVE_LDAP_SSL_H
-+#include <ldap_ssl.h>
-+#endif
-+
-+#endif /* LDAPINCLUDES_H */
-diff --git a/ldapmisc.c b/ldapmisc.c
-new file mode 100644
-index 0000000..de23c0c
---- /dev/null
-+++ b/ldapmisc.c
-@@ -0,0 +1,79 @@
-+
-+#include "ldapincludes.h"
-+#include "ldapmisc.h"
-+
-+#ifndef HAVE_LDAP_GET_LDERRNO
-+int
-+ldap_get_lderrno (LDAP * ld, char **m, char **s)
-+{
-+#ifdef HAVE_LDAP_GET_OPTION
-+	int rc;
-+#endif
-+	int lderrno;
-+
-+#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
-+	if ((rc = ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, &lderrno)) != LDAP_SUCCESS)
-+	    return rc;
-+#else
-+	lderrno = ld->ld_errno;
-+#endif
-+
-+	if (s != NULL) {
-+#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_STRING)
-+		if ((rc = ldap_get_option (ld, LDAP_OPT_ERROR_STRING, s)) != LDAP_SUCCESS)
-+		    return rc;
-+#else
-+		*s = ld->ld_error;
-+#endif
-+	}
-+
-+	if (m != NULL) {
-+#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_MATCHED_DN)
-+		if ((rc = ldap_get_option (ld, LDAP_OPT_MATCHED_DN, m)) != LDAP_SUCCESS)
-+		    return rc;
-+#else
-+		*m = ld->ld_matched;
-+#endif
-+	}
-+
-+	return lderrno;
-+}
-+#endif
-+
-+#ifndef HAVE_LDAP_SET_LDERRNO
-+int
-+ldap_set_lderrno (LDAP * ld, int lderrno, const char *m, const char *s)
-+{
-+#ifdef HAVE_LDAP_SET_OPTION
-+	int rc;
-+#endif
-+
-+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
-+	if ((rc = ldap_set_option (ld, LDAP_OPT_ERROR_NUMBER, &lderrno)) != LDAP_SUCCESS)
-+	    return rc;
-+#else
-+	ld->ld_errno = lderrno;
-+#endif
-+
-+	if (s != NULL) {
-+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_ERROR_STRING)
-+		if ((rc = ldap_set_option (ld, LDAP_OPT_ERROR_STRING, s)) != LDAP_SUCCESS)
-+		    return rc;
-+#else
-+		ld->ld_error = s;
-+#endif
-+	}
-+
-+	if (m != NULL) {
-+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_MATCHED_DN)
-+		if ((rc = ldap_set_option (ld, LDAP_OPT_MATCHED_DN, m)) != LDAP_SUCCESS)
-+		    return rc;
-+#else
-+		ld->ld_matched = m;
-+#endif
-+	}
-+
-+	return LDAP_SUCCESS;
-+}
-+#endif
-+
-diff --git a/ldapmisc.h b/ldapmisc.h
-new file mode 100644
-index 0000000..4c271df
---- /dev/null
-+++ b/ldapmisc.h
-@@ -0,0 +1,35 @@
-+/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
-+/*
-+ * Copyright (c) 2009 Jan F. Chadima.  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 LDAPMISC_H
-+#define LDAPMISC_H
-+
-+#include "ldapincludes.h"
-+
-+int ldap_get_lderrno (LDAP *, char **, char **);
-+int ldap_set_lderrno (LDAP *, int, const char *, const char *);
-+
-+#endif /* LDAPMISC_H */
-+
-diff --git a/openssh-lpk-openldap.schema b/openssh-lpk-openldap.schema
-new file mode 100644
-index 0000000..c84f90f
---- /dev/null
-+++ b/openssh-lpk-openldap.schema
-@@ -0,0 +1,21 @@
-+#
-+# LDAP Public Key Patch schema for use with openssh-ldappubkey
-+#                              useful with PKA-LDAP also
-+#
-+# Author: Eric AUGE <eau at phear.org>
-+# 
-+# Based on the proposal of : Mark Ruijter
-+#
-+
-+
-+# octetString SYNTAX
-+attributetype ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' 
-+	DESC 'MANDATORY: OpenSSH Public key' 
-+	EQUALITY octetStringMatch
-+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
-+
-+# printableString SYNTAX yes|no
-+objectclass ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
-+	DESC 'MANDATORY: OpenSSH LPK objectclass'
-+	MUST ( sshPublicKey $ uid ) 
-+	)
-diff --git a/openssh-lpk-sun.schema b/openssh-lpk-sun.schema
-new file mode 100644
-index 0000000..3136673
---- /dev/null
-+++ b/openssh-lpk-sun.schema
-@@ -0,0 +1,23 @@
-+#
-+# LDAP Public Key Patch schema for use with openssh-ldappubkey
-+#                              useful with PKA-LDAP also
-+#
-+# Author: Eric AUGE <eau at phear.org>
-+# 
-+# Schema for Sun Directory Server.
-+# Based on the original schema, modified by Stefan Fischer.
-+#
-+
-+dn: cn=schema
-+
-+# octetString SYNTAX
-+attributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' 
-+	DESC 'MANDATORY: OpenSSH Public key' 
-+	EQUALITY octetStringMatch
-+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
-+
-+# printableString SYNTAX yes|no
-+objectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
-+	DESC 'MANDATORY: OpenSSH LPK objectclass'
-+	MUST ( sshPublicKey $ uid ) 
-+	)
-diff --git a/ssh-ldap-helper.8 b/ssh-ldap-helper.8
-new file mode 100644
-index 0000000..5d2d7be
---- /dev/null
-+++ b/ssh-ldap-helper.8
-@@ -0,0 +1,79 @@
-+.\" $OpenBSD: ssh-ldap-helper.8,v 1.1 2010/02/10 23:20:38 markus Exp $
-+.\"
-+.\" Copyright (c) 2010 Jan F. Chadima.  All rights reserved.
-+.\"
-+.\" 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.
-+.\"
-+.Dd $Mdocdate: April 29 2010 $
-+.Dt SSH-LDAP-HELPER 8
-+.Os
-+.Sh NAME
-+.Nm ssh-ldap-helper
-+.Nd sshd helper program for ldap support
-+.Sh SYNOPSIS
-+.Nm ssh-ldap-helper
-+.Op Fl devw
-+.Op Fl f Ar file
-+.Op Fl s Ar user
-+.Sh DESCRIPTION
-+.Nm
-+is used by
-+.Xr sshd 1
-+to access keys provided by an LDAP.
-+.Nm
-+is disabled by default and can only be enabled in the
-+sshd configuration file
-+.Pa /etc/ssh/sshd_config
-+by setting
-+.Cm AuthorizedKeysCommand
-+to
-+.Dq /usr/libexec/ssh-ldap-wrapper .
-+.Pp
-+.Nm
-+is not intended to be invoked by the user, but from
-+.Xr sshd 8 via
-+.Xr ssh-ldap-wrapper .
-+.Pp
-+The options are as follows:
-+.Bl -tag -width Ds
-+.It Fl d
-+Set the debug mode; 
-+.Nm
-+prints all logs to stderr instead of syslog.
-+.It Fl e
-+Implies \-w;
-+.Nm
-+halts if it encounters an unknown item in the ldap.conf file.
-+.It Fl f
-+.Nm
-+uses this file as the ldap configuration file instead of /etc/ssh/ldap.conf (default).
-+.It Fl s
-+.Nm
-+prints out the user's keys to stdout and exits.
-+.It Fl v
-+Implies \-d;
-+increases verbosity.
-+.It Fl w
-+.Nm
-+writes warnings about unknown items in the ldap.conf configuration file.
-+.El
-+.Sh SEE ALSO
-+.Xr sshd 8 ,
-+.Xr sshd_config 5 ,
-+.Xr ssh-ldap.conf 5 ,
-+.Sh HISTORY
-+.Nm
-+first appeared in
-+OpenSSH 5.5 + PKA-LDAP .
-+.Sh AUTHORS
-+.An Jan F. Chadima Aq jchadima at redhat.com
-diff --git a/ssh-ldap-wrapper b/ssh-ldap-wrapper
-new file mode 100644
-index 0000000..cb500aa
---- /dev/null
-+++ b/ssh-ldap-wrapper
-@@ -0,0 +1,4 @@
-+#!/bin/sh
-+
-+exec /usr/libexec/openssh/ssh-ldap-helper -s "$1"
-+
-diff --git a/ssh-ldap.conf.5 b/ssh-ldap.conf.5
-new file mode 100644
-index 0000000..f7081b8
---- /dev/null
-+++ b/ssh-ldap.conf.5
-@@ -0,0 +1,379 @@
-+.\" $OpenBSD: ssh-ldap.conf.5,v 1.1 2010/02/10 23:20:38 markus Exp $
-+.\"
-+.\" Copyright (c) 2010 Jan F. Chadima.  All rights reserved.
-+.\"
-+.\" 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.
-+.\"
-+.Dd $Mdocdate: may 12 2010 $
-+.Dt SSH-LDAP.CONF 5
-+.Os
-+.Sh NAME
-+.Nm ssh-ldap.conf
-+.Nd configuration file for ssh-ldap-helper
-+.Sh SYNOPSIS
-+.Nm /etc/ssh/ldap.conf
-+.Sh DESCRIPTION
-+.Xr ssh-ldap-helper 8
-+reads configuration data from
-+.Pa /etc/ssh/ldap.conf
-+(or the file specified with
-+.Fl f
-+on the command line).
-+The file contains keyword-argument pairs, one per line.
-+Lines starting with
-+.Ql #
-+and empty lines are interpreted as comments.
-+.Pp
-+The value starts with the first non-blank character after 
-+the keyword's name, and terminates at the end of the line, 
-+or at the last sequence of blanks before the end of the line.
-+Quoting values that contain blanks 
-+may be incorrect, as the quotes would become part of the value.
-+The possible keywords and their meanings are as follows (note that
-+keywords are case-insensitive, and arguments, on a case by case basis, may be case-sensitive).
-+.Bl -tag -width Ds
-+.It Cm URI
-+The argument(s) are in the form
-+.Pa ldap[si]://[name[:port]]
-+and specify the URI(s) of an LDAP server(s) to which the
-+.Xr ssh-ldap-helper 8 
-+should connect. The URI scheme may be any of
-+.Dq ldap ,
-+.Dq ldaps 
-+or
-+.Dq ldapi ,
-+which refer to LDAP over TCP, LDAP over SSL (TLS) and LDAP
-+over IPC (UNIX domain sockets), respectively.
-+Each server's name can be specified as a
-+domain-style name or an IP address literal.  Optionally, the
-+server's name can followed by a ':' and the port number the LDAP
-+server is listening on.  If no port number is provided, the default
-+port for the scheme is used (389 for ldap://, 636 for ldaps://).
-+For LDAP over IPC, name is the name of the socket, and no port
-+is required, nor allowed; note that directory separators must be 
-+URL-encoded, like any other characters that are special to URLs; 
-+A space separated list of URIs may be provided.
-+There is no default.
-+.It Cm Base
-+Specifies the default base Distinguished Name (DN) to use when performing ldap operations.
-+The base must be specified as a DN in LDAP format.
-+There is no default.
-+.It Cm BindDN
-+Specifies the default BIND DN to use when connecting to the ldap server.
-+The bind DN must be specified as a Distinguished Name in LDAP format.
-+There is no default.
-+.It Cm BindPW
-+Specifies the default password to use when connecting to the ldap server via
-+.Cm BindDN .
-+There is no default.
-+.It Cm RootBindDN
-+Intentionaly does nothing. Recognized for compatibility reasons.
-+.It Cm Host
-+The argument(s) specifies the name(s) of an LDAP server(s) to which the
-+.Xr ssh-ldap-helper 8
-+should connect.  Each server's name can be specified as a
-+domain-style name or an IP address and optionally followed by a ':' and
-+the port number the ldap server is listening on.  A space-separated
-+list of hosts may be provided.
-+There is no default.
-+.Cm Host
-+is deprecated in favor of
-+.Cm URI .
-+.It Cm Port
-+Specifies the default port used when connecting to LDAP servers(s).
-+The port may be specified as a number.
-+The default port is 389 for ldap:// or 636 for ldaps:// respectively.
-+.Cm Port
-+is deprecated in favor of
-+.Cm URI .
-+.It Cm Scope
-+Specifies the starting point of an LDAP search and the depth from the base DN to which the search should descend.
-+There are three options (values) that can be assigned to the
-+.Cm Scope parameter:
-+.Dq base ,
-+.Dq one
-+and
-+.Dq subtree .
-+Alias for the subtree is
-+.Dq sub .
-+The value
-+.Dq base
-+is used to indicate searching only the entry at the base DN, resulting in only that entry being returned (keeping in mind that it also has to meet the search filter criteria!).
-+The value
-+.Dq one
-+is used to indicate searching all entries one level under the base DN, but not including the base DN and not including any entries under that one level under the base DN.
-+The value
-+.Dq subtree
-+is used to indicate searching of all entries at all levels under and including the specified base DN.
-+The default is
-+.Dq subtree .
-+.It Cm Deref
-+Specifies how alias dereferencing is done when performing a search. There are four
-+possible values that can be assigned to the
-+.Cm Deref
-+parameter:
-+.Dq never ,
-+.Dq searching ,
-+.Dq finding ,
-+and
-+.Dq always .
-+The value
-+.Dq never
-+means that the aliases are never dereferenced.
-+The value
-+.Dq searching
-+means that the aliases are dereferenced in subordinates of the base object, but
-+not in locating the base object of the search.
-+The value
-+.Dq finding
-+means that the aliases are only dereferenced when locating the base object of the search.
-+The value
-+.Dq always
-+means that the aliases are dereferenced both in searching and in locating the base object
-+of the search.
-+The default is
-+.Dq never .
-+.It Cm TimeLimit
-+Specifies a time limit (in seconds) to use when performing searches.
-+The number should be a non-negative integer. A
-+.Cm TimeLimit
-+of zero (0) specifies that the search time is unlimited. Please note that the server
-+may still apply any server-side limit on the duration of a search operation.
-+The default value is 10.
-+.It Cm TimeOut
-+Is an aliast to
-+.Cm TimeLimit .
-+.It Cm Bind_TimeLimit
-+Specifies the timeout (in seconds) after which the poll(2)/select(2)
-+following a connect(2) returns in case of no activity.
-+The default value is 10.
-+.It Cm Network_TimeOut
-+Is an alias to
-+.Cm Bind_TimeLimit .
-+.It Cm Ldap_Version
-+Specifies what version of the LDAP protocol should be used.
-+The allowed values are 2 or 3. The default is 3.
-+.It Cm Version
-+Is an alias to
-+.Cm Ldap_Version .
-+.It Cm Bind_Policy
-+Specifies the policy to use for reconnecting to an unavailable LDAP server. There are 2 available values:
-+.Dq hard
-+and
-+.Dq soft.
-+.Dq hard has 2 aliases
-+.Dq hard_open
-+and
-+.Dq hard_init .
-+The value
-+.Dq hard
-+means that reconects that the
-+.Xr ssh-ldap-helper 8
-+tries to reconnect to the LDAP server 5 times before failure. There is exponential backoff before retrying.
-+The value
-+.Dq soft
-+means that
-+.Xr ssh-ldap-helper 8
-+fails immediately when it cannot connect to the LDAP seerver.
-+The deault is
-+.Dq hard .
-+.It Cm SSLPath
-+Specifies the path to the X.509 certificate database.
-+There is no default.
-+.It Cm SSL
-+Specifies whether to use SSL/TLS or not.
-+There are three allowed values:
-+.Dq yes ,
-+.Dq no
-+and
-+.Dq start_tls
-+Both
-+.Dq true
-+and
-+.Dq on
-+are the aliases for
-+.Dq yes .
-+.Dq false
-+and
-+.Dq off
-+are the aliases for
-+.Dq no .
-+If
-+.Dq start_tls
-+is specified then StartTLS is used rather than raw LDAP over SSL.
-+The default for ldap:// is
-+.Dq start_tls ,
-+for ldaps://
-+.Dq yes
-+and
-+.Dq no
-+for the ldapi:// .
-+In case of host based configuration the default is
-+.Dq start_tls .
-+.It Cm Referrals
-+Specifies if the client should automatically follow referrals returned
-+by LDAP servers.
-+The value can be or
-+.Dq yes
-+or
-+.Dq no .
-+.Dq true
-+and
-+.Dq on
-+are the aliases for
-+.Dq yes .
-+.Dq false
-+and
-+.Dq off
-+are the aliases for
-+.Dq no .
-+The default is yes.
-+.It Cm Restart
-+Specifies whether the LDAP client library should restart the select(2) system call when interrupted.
-+The value can be or
-+.Dq yes
-+or
-+.Dq no .
-+.Dq true
-+and
-+.Dq on
-+are the aliases for
-+.Dq yes .
-+.Dq false
-+and
-+.Dq off
-+are the aliases for
-+.Dq no .
-+The default is yes.
-+.It Cm TLS_CheckPeer
-+Specifies what checks to perform on server certificates in a TLS session,
-+if any. The value
-+can be specified as one of the following keywords:
-+.Dq never ,
-+.Dq hard ,
-+.Dq demand ,
-+.Dq allow
-+and
-+.Dq try .
-+.Dq true ,
-+.Dq on
-+and
-+.Dq yes
-+are aliases for
-+.Dq hard .
-+.Dq false ,
-+.Dq off
-+and
-+.Dq no
-+are the aliases for
-+.Dq never .
-+The value
-+.Dq never
-+means that the client will not request or check any server certificate.
-+The value
-+.Dq allow
-+means that the server certificate is requested. If no certificate is provided,
-+the session proceeds normally. If a bad certificate is provided, it will
-+be ignored and the session proceeds normally.
-+The value
-+.Dq try
-+means that the server certificate is requested. If no certificate is provided,
-+the session proceeds normally. If a bad certificate is provided,
-+the session is immediately terminated.
-+The value
-+.Dq demand
-+means that the server certificate is requested. If no
-+certificate is provided, or a bad certificate is provided, the session
-+is immediately terminated.
-+The value
-+.Dq hard
-+is the same as
-+.Dq demand .
-+It requires an SSL connection. In the case of the plain conection the
-+session is immediately terminated.
-+The default is
-+.Dq hard .
-+.It Cm TLS_ReqCert
-+Is an alias for 
-+.Cm TLS_CheckPeer .
-+.It Cm TLS_CACertFile
-+Specifies the file that contains certificates for all of the Certificate
-+Authorities the client will recognize.
-+There is no default.
-+.It Cm TLS_CACert
-+Is an alias for
-+.Cm TLS_CACertFile .
-+.It Cm TLS_CACertDIR
-+Specifies the path of a directory that contains Certificate Authority
-+certificates in separate individual files. The
-+.Cm TLS_CACert
-+is always used before
-+.Cm TLS_CACertDir .
-+The specified directory must be managed with the OpenSSL c_rehash utility.
-+There is no default.
-+.It Cm TLS_Ciphers
-+Specifies acceptable cipher suite and preference order.
-+The value should be a cipher specification for OpenSSL,
-+e.g.,
-+.Dq HIGH:MEDIUM:+SSLv2 .
-+The default is
-+.Dq ALL .
-+.It Cm TLS_Cipher_Suite
-+Is an alias for
-+.Cm TLS_Ciphers .
-+.It Cm TLS_Cert
-+Specifies the file that contains the client certificate.
-+There is no default.
-+.It Cm TLS_Certificate
-+Is an alias for
-+.Cm TLS_Cert .
-+.It Cm TLS_Key
-+Specifies the file that contains the private key that matches the certificate
-+stored in the
-+.Cm TLS_Cert
-+file. Currently, the private key must not be protected with a password, so
-+it is of critical importance that the key file is protected carefully.
-+There is no default.
-+.It Cm TLS_RandFile
-+Specifies the file to obtain random bits from when /dev/[u]random is
-+not available. Generally set to the name of the EGD/PRNGD socket.
-+The environment variable RANDFILE can also be used to specify the filename.
-+There is no default.
-+.It Cm LogDir
-+Specifies the directory used for logging by the LDAP client library.
-+There is no default.
-+.It Cm Debug
-+Specifies the debug level used for logging by the LDAP client library.
-+There is no default.
-+.It Cm SSH_Filter
-+Specifies the user filter applied on the LDAP serch.
-+The default is no filter.
-+.It Cm AccountClass
-+Specifies the LDAP class used to find user accounts.
-+The default is posixAccount.
-+.El
-+.Sh FILES
-+.Bl -tag -width Ds
-+.It Pa  /etc/ssh/ldap.conf
-+Ldap configuration file for
-+.Xr ssh-ldap-helper 8 .
-+.El
-+.Sh "SEE ALSO"
-+.Xr ldap.conf 5 ,
-+.Xr ssh-ldap-helper 8
-+.Sh HISTORY
-+.Nm
-+first appeared in
-+OpenSSH 5.5 + PKA-LDAP .
-+.Sh AUTHORS
-+.An Jan F. Chadima Aq jchadima at redhat.com
diff --git a/openssh-6.6p1-role-mls.patch b/openssh-6.6p1-role-mls.patch
index 4740c99..da164d3 100644
--- a/openssh-6.6p1-role-mls.patch
+++ b/openssh-6.6p1-role-mls.patch
@@ -1,7 +1,6 @@
-diff --git a/auth-pam.c b/auth-pam.c
-index d789bad..cd1a775 100644
---- a/auth-pam.c
-+++ b/auth-pam.c
+diff -up openssh-6.8p1/auth-pam.c.role-mls openssh-6.8p1/auth-pam.c
+--- openssh-6.8p1/auth-pam.c.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/auth-pam.c	2015-03-18 11:04:21.045817122 +0100
 @@ -1068,7 +1068,7 @@ is_pam_session_open(void)
   * during the ssh authentication process.
   */
@@ -11,10 +10,9 @@ index d789bad..cd1a775 100644
  {
  	int ret = 1;
  #ifdef HAVE_PAM_PUTENV
-diff --git a/auth-pam.h b/auth-pam.h
-index a1a2b52..b109a5a 100644
---- a/auth-pam.h
-+++ b/auth-pam.h
+diff -up openssh-6.8p1/auth-pam.h.role-mls openssh-6.8p1/auth-pam.h
+--- openssh-6.8p1/auth-pam.h.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/auth-pam.h	2015-03-18 11:04:21.045817122 +0100
 @@ -38,7 +38,7 @@ void do_pam_session(void);
  void do_pam_set_tty(const char *);
  void do_pam_setcred(int );
@@ -24,11 +22,10 @@ index a1a2b52..b109a5a 100644
  char ** fetch_pam_environment(void);
  char ** fetch_pam_child_environment(void);
  void free_pam_environment(char **);
-diff --git a/auth.h b/auth.h
-index 124e597..4605588 100644
---- a/auth.h
-+++ b/auth.h
-@@ -59,6 +59,9 @@ struct Authctxt {
+diff -up openssh-6.8p1/auth.h.role-mls openssh-6.8p1/auth.h
+--- openssh-6.8p1/auth.h.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/auth.h	2015-03-18 11:04:21.045817122 +0100
+@@ -62,6 +62,9 @@ struct Authctxt {
  	char		*service;
  	struct passwd	*pw;		/* set if 'valid' */
  	char		*style;
@@ -38,11 +35,10 @@ index 124e597..4605588 100644
  	void		*kbdintctxt;
  	char		*info;		/* Extra info for next auth_log */
  #ifdef BSD_AUTH
-diff --git a/auth1.c b/auth1.c
-index 0f870b3..df040bb 100644
---- a/auth1.c
-+++ b/auth1.c
-@@ -381,6 +381,9 @@ do_authentication(Authctxt *authctxt)
+diff -up openssh-6.8p1/auth1.c.role-mls openssh-6.8p1/auth1.c
+--- openssh-6.8p1/auth1.c.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/auth1.c	2015-03-18 11:04:21.046817119 +0100
+@@ -384,6 +384,9 @@ do_authentication(Authctxt *authctxt)
  {
  	u_int ulen;
  	char *user, *style = NULL;
@@ -52,7 +48,7 @@ index 0f870b3..df040bb 100644
  
  	/* Get the name of the user that we wish to log in as. */
  	packet_read_expect(SSH_CMSG_USER);
-@@ -389,11 +392,24 @@ do_authentication(Authctxt *authctxt)
+@@ -392,11 +395,24 @@ do_authentication(Authctxt *authctxt)
  	user = packet_get_cstring(&ulen);
  	packet_check_eom();
  
@@ -77,11 +73,10 @@ index 0f870b3..df040bb 100644
  
  	/* Verify that the user is a valid user. */
  	if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
-diff --git a/auth2-gss.c b/auth2-gss.c
-index c28a705..4756dd7 100644
---- a/auth2-gss.c
-+++ b/auth2-gss.c
-@@ -251,6 +251,7 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
+diff -up openssh-6.8p1/auth2-gss.c.role-mls openssh-6.8p1/auth2-gss.c
+--- openssh-6.8p1/auth2-gss.c.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/auth2-gss.c	2015-03-18 11:04:21.046817119 +0100
+@@ -255,6 +255,7 @@ input_gssapi_mic(int type, u_int32_t ple
  	Authctxt *authctxt = ctxt;
  	Gssctxt *gssctxt;
  	int authenticated = 0;
@@ -89,7 +84,7 @@ index c28a705..4756dd7 100644
  	Buffer b;
  	gss_buffer_desc mic, gssbuf;
  	u_int len;
-@@ -263,7 +264,13 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
+@@ -267,7 +268,13 @@ input_gssapi_mic(int type, u_int32_t ple
  	mic.value = packet_get_string(&len);
  	mic.length = len;
  
@@ -104,7 +99,7 @@ index c28a705..4756dd7 100644
  	    "gssapi-with-mic");
  
  	gssbuf.value = buffer_ptr(&b);
-@@ -275,6 +282,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
+@@ -279,6 +286,8 @@ input_gssapi_mic(int type, u_int32_t ple
  		logit("GSSAPI MIC check failed");
  
  	buffer_free(&b);
@@ -113,11 +108,10 @@ index c28a705..4756dd7 100644
  	free(mic.value);
  
  	authctxt->postponed = 0;
-diff --git a/auth2-hostbased.c b/auth2-hostbased.c
-index eca0069..95d678e 100644
---- a/auth2-hostbased.c
-+++ b/auth2-hostbased.c
-@@ -112,7 +112,15 @@ userauth_hostbased(Authctxt *authctxt)
+diff -up openssh-6.8p1/auth2-hostbased.c.role-mls openssh-6.8p1/auth2-hostbased.c
+--- openssh-6.8p1/auth2-hostbased.c.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/auth2-hostbased.c	2015-03-18 11:04:21.046817119 +0100
+@@ -122,7 +122,15 @@ userauth_hostbased(Authctxt *authctxt)
  	buffer_put_string(&b, session_id2, session_id2_len);
  	/* reconstruct packet */
  	buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
@@ -134,11 +128,10 @@ index eca0069..95d678e 100644
  	buffer_put_cstring(&b, service);
  	buffer_put_cstring(&b, "hostbased");
  	buffer_put_string(&b, pkalg, alen);
-diff --git a/auth2-pubkey.c b/auth2-pubkey.c
-index 749b11a..c0ae0d4 100644
---- a/auth2-pubkey.c
-+++ b/auth2-pubkey.c
-@@ -133,9 +133,11 @@ userauth_pubkey(Authctxt *authctxt)
+diff -up openssh-6.8p1/auth2-pubkey.c.role-mls openssh-6.8p1/auth2-pubkey.c
+--- openssh-6.8p1/auth2-pubkey.c.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/auth2-pubkey.c	2015-03-18 11:04:21.046817119 +0100
+@@ -145,9 +145,11 @@ userauth_pubkey(Authctxt *authctxt)
  		}
  		/* reconstruct packet */
  		buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
@@ -152,11 +145,10 @@ index 749b11a..c0ae0d4 100644
  		buffer_put_cstring(&b, userstyle);
  		free(userstyle);
  		buffer_put_cstring(&b,
-diff --git a/auth2.c b/auth2.c
-index a5490c0..5f4f26f 100644
---- a/auth2.c
-+++ b/auth2.c
-@@ -215,6 +215,9 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
+diff -up openssh-6.8p1/auth2.c.role-mls openssh-6.8p1/auth2.c
+--- openssh-6.8p1/auth2.c.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/auth2.c	2015-03-18 11:04:21.046817119 +0100
+@@ -215,6 +215,9 @@ input_userauth_request(int type, u_int32
  	Authctxt *authctxt = ctxt;
  	Authmethod *m = NULL;
  	char *user, *service, *method, *style = NULL;
@@ -166,7 +158,7 @@ index a5490c0..5f4f26f 100644
  	int authenticated = 0;
  
  	if (authctxt == NULL)
-@@ -226,6 +229,11 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
+@@ -226,6 +229,11 @@ input_userauth_request(int type, u_int32
  	debug("userauth-request for user %s service %s method %s", user, service, method);
  	debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
  
@@ -178,7 +170,7 @@ index a5490c0..5f4f26f 100644
  	if ((style = strchr(user, ':')) != NULL)
  		*style++ = 0;
  
-@@ -251,8 +259,15 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
+@@ -251,8 +259,15 @@ input_userauth_request(int type, u_int32
  		    use_privsep ? " [net]" : "");
  		authctxt->service = xstrdup(service);
  		authctxt->style = style ? xstrdup(style) : NULL;
@@ -195,11 +187,10 @@ index a5490c0..5f4f26f 100644
  		userauth_banner();
  		if (auth2_setup_methods_lists(authctxt) != 0)
  			packet_disconnect("no authentication methods enabled");
-diff --git a/misc.c b/misc.c
-index e4c8c32..f31cd91 100644
---- a/misc.c
-+++ b/misc.c
-@@ -430,6 +430,7 @@ char *
+diff -up openssh-6.8p1/misc.c.role-mls openssh-6.8p1/misc.c
+--- openssh-6.8p1/misc.c.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/misc.c	2015-03-18 11:04:21.046817119 +0100
+@@ -431,6 +431,7 @@ char *
  colon(char *cp)
  {
  	int flag = 0;
@@ -207,7 +198,7 @@ index e4c8c32..f31cd91 100644
  
  	if (*cp == ':')		/* Leading colon is part of file name. */
  		return NULL;
-@@ -445,6 +446,13 @@ colon(char *cp)
+@@ -446,6 +447,13 @@ colon(char *cp)
  			return (cp);
  		if (*cp == '/')
  			return NULL;
@@ -221,11 +212,10 @@ index e4c8c32..f31cd91 100644
  	}
  	return NULL;
  }
-diff --git a/monitor.c b/monitor.c
-index 531c4f9..229fada 100644
---- a/monitor.c
-+++ b/monitor.c
-@@ -145,6 +145,9 @@ int mm_answer_sign(int, Buffer *);
+diff -up openssh-6.8p1/monitor.c.role-mls openssh-6.8p1/monitor.c
+--- openssh-6.8p1/monitor.c.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/monitor.c	2015-03-18 11:04:21.047817117 +0100
+@@ -127,6 +127,9 @@ int mm_answer_sign(int, Buffer *);
  int mm_answer_pwnamallow(int, Buffer *);
  int mm_answer_auth2_read_banner(int, Buffer *);
  int mm_answer_authserv(int, Buffer *);
@@ -235,7 +225,7 @@ index 531c4f9..229fada 100644
  int mm_answer_authpassword(int, Buffer *);
  int mm_answer_bsdauthquery(int, Buffer *);
  int mm_answer_bsdauthrespond(int, Buffer *);
-@@ -219,6 +222,9 @@ struct mon_table mon_dispatch_proto20[] = {
+@@ -206,6 +209,9 @@ struct mon_table mon_dispatch_proto20[]
      {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
      {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
      {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
@@ -245,7 +235,7 @@ index 531c4f9..229fada 100644
      {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
      {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
  #ifdef USE_PAM
-@@ -805,6 +811,9 @@ mm_answer_pwnamallow(int sock, Buffer *m)
+@@ -862,6 +868,9 @@ mm_answer_pwnamallow(int sock, Buffer *m
  	else {
  		/* Allow service/style information on the auth context */
  		monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
@@ -255,7 +245,7 @@ index 531c4f9..229fada 100644
  		monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1);
  	}
  #ifdef USE_PAM
-@@ -846,6 +855,25 @@ mm_answer_authserv(int sock, Buffer *m)
+@@ -903,6 +912,25 @@ mm_answer_authserv(int sock, Buffer *m)
  	return (0);
  }
  
@@ -281,7 +271,7 @@ index 531c4f9..229fada 100644
  int
  mm_answer_authpassword(int sock, Buffer *m)
  {
-@@ -1220,7 +1248,7 @@ static int
+@@ -1291,7 +1319,7 @@ static int
  monitor_valid_userblob(u_char *data, u_int datalen)
  {
  	Buffer b;
@@ -290,7 +280,7 @@ index 531c4f9..229fada 100644
  	u_int len;
  	int fail = 0;
  
-@@ -1246,6 +1274,8 @@ monitor_valid_userblob(u_char *data, u_int datalen)
+@@ -1317,6 +1345,8 @@ monitor_valid_userblob(u_char *data, u_i
  	if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
  		fail++;
  	p = buffer_get_cstring(&b, NULL);
@@ -299,7 +289,7 @@ index 531c4f9..229fada 100644
  	xasprintf(&userstyle, "%s%s%s", authctxt->user,
  	    authctxt->style ? ":" : "",
  	    authctxt->style ? authctxt->style : "");
-@@ -1281,7 +1311,7 @@ monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser,
+@@ -1352,7 +1382,7 @@ monitor_valid_hostbasedblob(u_char *data
      char *chost)
  {
  	Buffer b;
@@ -308,7 +298,7 @@ index 531c4f9..229fada 100644
  	u_int len;
  	int fail = 0;
  
-@@ -1298,6 +1328,8 @@ monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser,
+@@ -1369,6 +1399,8 @@ monitor_valid_hostbasedblob(u_char *data
  	if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
  		fail++;
  	p = buffer_get_cstring(&b, NULL);
@@ -317,10 +307,9 @@ index 531c4f9..229fada 100644
  	xasprintf(&userstyle, "%s%s%s", authctxt->user,
  	    authctxt->style ? ":" : "",
  	    authctxt->style ? authctxt->style : "");
-diff --git a/monitor.h b/monitor.h
-index 5bc41b5..20e2b4a 100644
---- a/monitor.h
-+++ b/monitor.h
+diff -up openssh-6.8p1/monitor.h.role-mls openssh-6.8p1/monitor.h
+--- openssh-6.8p1/monitor.h.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/monitor.h	2015-03-18 11:04:21.047817117 +0100
 @@ -57,6 +57,10 @@ enum monitor_reqtype {
  	MONITOR_REQ_GSSCHECKMIC = 48, MONITOR_ANS_GSSCHECKMIC = 49,
  	MONITOR_REQ_TERM = 50,
@@ -332,11 +321,10 @@ index 5bc41b5..20e2b4a 100644
  	MONITOR_REQ_PAM_START = 100,
  	MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103,
  	MONITOR_REQ_PAM_INIT_CTX = 104, MONITOR_ANS_PAM_INIT_CTX = 105,
-diff --git a/monitor_wrap.c b/monitor_wrap.c
-index 1a47e41..d1b6d99 100644
---- a/monitor_wrap.c
-+++ b/monitor_wrap.c
-@@ -336,6 +336,25 @@ mm_inform_authserv(char *service, char *style)
+diff -up openssh-6.8p1/monitor_wrap.c.role-mls openssh-6.8p1/monitor_wrap.c
+--- openssh-6.8p1/monitor_wrap.c.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/monitor_wrap.c	2015-03-18 11:04:21.047817117 +0100
+@@ -347,6 +347,25 @@ mm_inform_authserv(char *service, char *
  	buffer_free(&m);
  }
  
@@ -362,13 +350,12 @@ index 1a47e41..d1b6d99 100644
  /* Do the password authentication */
  int
  mm_auth_password(Authctxt *authctxt, char *password)
-diff --git a/monitor_wrap.h b/monitor_wrap.h
-index 18c2501..9d5e5ba 100644
---- a/monitor_wrap.h
-+++ b/monitor_wrap.h
+diff -up openssh-6.8p1/monitor_wrap.h.role-mls openssh-6.8p1/monitor_wrap.h
+--- openssh-6.8p1/monitor_wrap.h.role-mls	2015-03-18 11:04:21.047817117 +0100
++++ openssh-6.8p1/monitor_wrap.h	2015-03-18 11:10:32.343936171 +0100
 @@ -42,6 +42,9 @@ int mm_is_monitor(void);
  DH *mm_choose_dh(int, int, int);
- int mm_key_sign(Key *, u_char **, u_int *, u_char *, u_int);
+ int mm_key_sign(Key *, u_char **, u_int *, const u_char *, u_int);
  void mm_inform_authserv(char *, char *);
 +#ifdef WITH_SELINUX
 +void mm_inform_authrole(char *);
@@ -376,25 +363,22 @@ index 18c2501..9d5e5ba 100644
  struct passwd *mm_getpwnamallow(const char *);
  char *mm_auth2_read_banner(void);
  int mm_auth_password(struct Authctxt *, char *);
-diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in
-index 6ecfb93..b912dbe 100644
---- a/openbsd-compat/Makefile.in
-+++ b/openbsd-compat/Makefile.in
-@@ -20,7 +20,7 @@ OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o di
+diff -up openssh-6.8p1/openbsd-compat/Makefile.in.role-mls openssh-6.8p1/openbsd-compat/Makefile.in
+--- openssh-6.8p1/openbsd-compat/Makefile.in.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/openbsd-compat/Makefile.in	2015-03-18 11:04:21.047817117 +0100
+@@ -20,7 +20,7 @@ OPENBSD=base64.o basename.o bcrypt_pbkdf
  
- COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o
+ COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o kludge-fd_set.o
  
 -PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o
 +PORTS=port-aix.o port-irix.o port-linux.o port-linux-sshd.o port-solaris.o port-tun.o port-uw.o
  
  .c.o:
  	$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
-diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c
-new file mode 100644
-index 0000000..c18524e
---- /dev/null
-+++ b/openbsd-compat/port-linux-sshd.c
-@@ -0,0 +1,414 @@
+diff -up openssh-6.8p1/openbsd-compat/port-linux-sshd.c.role-mls openssh-6.8p1/openbsd-compat/port-linux-sshd.c
+--- openssh-6.8p1/openbsd-compat/port-linux-sshd.c.role-mls	2015-03-18 11:04:21.048817114 +0100
++++ openssh-6.8p1/openbsd-compat/port-linux-sshd.c	2015-03-18 11:04:21.048817114 +0100
+@@ -0,0 +1,415 @@
 +/*
 + * Copyright (c) 2005 Daniel Walsh <dwalsh at redhat.com>
 + * Copyright (c) 2014 Petr Lautrbach <plautrba at redhat.com>
@@ -426,6 +410,7 @@ index 0000000..c18524e
 +
 +#include "log.h"
 +#include "xmalloc.h"
++#include "misc.h"      /* servconf.h needs misc.h for struct ForwardOptions */
 +#include "servconf.h"
 +#include "port-linux.h"
 +#include "key.h"
@@ -809,10 +794,9 @@ index 0000000..c18524e
 +#endif
 +#endif
 +
-diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c
-index 4637a7a..22ea8ef 100644
---- a/openbsd-compat/port-linux.c
-+++ b/openbsd-compat/port-linux.c
+diff -up openssh-6.8p1/openbsd-compat/port-linux.c.role-mls openssh-6.8p1/openbsd-compat/port-linux.c
+--- openssh-6.8p1/openbsd-compat/port-linux.c.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/openbsd-compat/port-linux.c	2015-03-18 11:04:21.048817114 +0100
 @@ -103,37 +103,6 @@ ssh_selinux_getctxbyname(char *pwname)
  	return sc;
  }
@@ -851,10 +835,9 @@ index 4637a7a..22ea8ef 100644
  /* Set the TTY context for the specified user */
  void
  ssh_selinux_setup_pty(char *pwname, const char *tty)
-diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h
-index e3d1004..8ef6cc4 100644
---- a/openbsd-compat/port-linux.h
-+++ b/openbsd-compat/port-linux.h
+diff -up openssh-6.8p1/openbsd-compat/port-linux.h.role-mls openssh-6.8p1/openbsd-compat/port-linux.h
+--- openssh-6.8p1/openbsd-compat/port-linux.h.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/openbsd-compat/port-linux.h	2015-03-18 11:04:21.048817114 +0100
 @@ -22,9 +22,10 @@
  #ifdef WITH_SELINUX
  int ssh_selinux_enabled(void);
@@ -867,11 +850,10 @@ index e3d1004..8ef6cc4 100644
  #endif
  
  #ifdef LINUX_OOM_ADJUST
-diff --git a/platform.c b/platform.c
-index 30fc609..0d39ab2 100644
---- a/platform.c
-+++ b/platform.c
-@@ -183,7 +183,7 @@ platform_setusercontext_post_groups(struct passwd *pw)
+diff -up openssh-6.8p1/platform.c.role-mls openssh-6.8p1/platform.c
+--- openssh-6.8p1/platform.c.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/platform.c	2015-03-18 11:04:21.048817114 +0100
+@@ -184,7 +184,7 @@ platform_setusercontext_post_groups(stru
  	}
  #endif /* HAVE_SETPCRED */
  #ifdef WITH_SELINUX
@@ -880,11 +862,10 @@ index 30fc609..0d39ab2 100644
  #endif
  }
  
-diff --git a/sshd.c b/sshd.c
-index 7523de9..07f9926 100644
---- a/sshd.c
-+++ b/sshd.c
-@@ -2138,6 +2138,9 @@ main(int ac, char **av)
+diff -up openssh-6.8p1/sshd.c.role-mls openssh-6.8p1/sshd.c
+--- openssh-6.8p1/sshd.c.role-mls	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/sshd.c	2015-03-18 11:04:21.048817114 +0100
+@@ -2220,6 +2220,9 @@ main(int ac, char **av)
  		restore_uid();
  	}
  #endif
@@ -894,3 +875,20 @@ index 7523de9..07f9926 100644
  #ifdef USE_PAM
  	if (options.use_pam) {
  		do_pam_setcred(1);
+diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c
+index 22ea8ef..2660085 100644
+--- a/openbsd-compat/port-linux.c
++++ b/openbsd-compat/port-linux.c
+@@ -116,7 +116,11 @@ ssh_selinux_setup_pty(char *pwname, const char *tty)
+ 
+ 	debug3("%s: setting TTY context on %s", __func__, tty);
+ 
+-	user_ctx = ssh_selinux_getctxbyname(pwname);
++	if (getexeccon(&user_ctx) != 0) {
++		error("%s: getexeccon: %s", __func__, strerror(errno));
++		goto out;
++	}
++
+ 
+ 	/* XXX: should these calls fatal() upon failure in enforcing mode? */
+ 
diff --git a/openssh-6.6p1-set_remote_ipaddr.patch b/openssh-6.6p1-set_remote_ipaddr.patch
index 166e569..ec4e416 100644
--- a/openssh-6.6p1-set_remote_ipaddr.patch
+++ b/openssh-6.6p1-set_remote_ipaddr.patch
@@ -1,8 +1,7 @@
-diff --git a/canohost.c b/canohost.c
-index 97ce58c..1f9320a 100644
---- a/canohost.c
-+++ b/canohost.c
-@@ -338,6 +338,21 @@ clear_cached_addr(void)
+diff -up openssh-6.8p1/canohost.c.set_remote_ipaddr openssh-6.8p1/canohost.c
+--- openssh-6.8p1/canohost.c.set_remote_ipaddr	2015-03-18 12:40:03.702925550 +0100
++++ openssh-6.8p1/canohost.c	2015-03-18 12:40:03.749925432 +0100
+@@ -349,6 +349,21 @@ clear_cached_addr(void)
  	cached_port = -1;
  }
  
@@ -24,7 +23,7 @@ index 97ce58c..1f9320a 100644
  /*
   * Returns the IP-address of the remote host as a string.  The returned
   * string must not be freed.
-@@ -347,17 +362,9 @@ const char *
+@@ -358,17 +373,9 @@ const char *
  get_remote_ipaddr(void)
  {
  	/* Check whether we have cached the ipaddr. */
@@ -45,10 +44,9 @@ index 97ce58c..1f9320a 100644
  	return canonical_host_ip;
  }
  
-diff --git a/canohost.h b/canohost.h
-index 4c8636f..4079953 100644
---- a/canohost.h
-+++ b/canohost.h
+diff -up openssh-6.8p1/canohost.h.set_remote_ipaddr openssh-6.8p1/canohost.h
+--- openssh-6.8p1/canohost.h.set_remote_ipaddr	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/canohost.h	2015-03-18 12:40:03.749925432 +0100
 @@ -13,6 +13,7 @@
   */
  
@@ -57,19 +55,18 @@ index 4c8636f..4079953 100644
  const char	*get_remote_ipaddr(void);
  const char	*get_remote_name_or_ip(u_int, int);
  
-diff --git a/sshconnect.c b/sshconnect.c
-index e636f33..451a58b 100644
---- a/sshconnect.c
-+++ b/sshconnect.c
-@@ -62,6 +62,7 @@
- #include "monitor_fdpass.h"
- #include "ssh2.h"
+diff -up openssh-6.8p1/sshconnect.c.set_remote_ipaddr openssh-6.8p1/sshconnect.c
+--- openssh-6.8p1/sshconnect.c.set_remote_ipaddr	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/sshconnect.c	2015-03-18 12:40:58.096788804 +0100
+@@ -65,6 +65,7 @@
  #include "version.h"
+ #include "authfile.h"
+ #include "ssherr.h"
 +#include "canohost.h"
  
  char *client_version_string = NULL;
  char *server_version_string = NULL;
-@@ -170,6 +171,7 @@ ssh_proxy_fdpass_connect(const char *host, u_short port,
+@@ -174,6 +175,7 @@ ssh_proxy_fdpass_connect(const char *hos
  
  	/* Set the connection file descriptors. */
  	packet_set_connection(sock, sock);
@@ -77,7 +74,7 @@ index e636f33..451a58b 100644
  
  	return 0;
  }
-@@ -492,6 +494,7 @@ ssh_connect_direct(const char *host, struct addrinfo *aitop,
+@@ -496,6 +498,7 @@ ssh_connect_direct(const char *host, str
  
  	/* Set the connection. */
  	packet_set_connection(sock, sock);
diff --git a/openssh-6.7p1-audit.patch b/openssh-6.7p1-audit.patch
new file mode 100644
index 0000000..213ca67
--- /dev/null
+++ b/openssh-6.7p1-audit.patch
@@ -0,0 +1,2332 @@
+diff -up openssh-6.8p1/Makefile.in.audit openssh-6.8p1/Makefile.in
+--- openssh-6.8p1/Makefile.in.audit	2015-03-20 13:41:15.065883826 +0100
++++ openssh-6.8p1/Makefile.in	2015-03-20 13:41:15.100883769 +0100
+@@ -98,7 +98,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
+ 	sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \
+ 	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
++	kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o auditstub.o
+ 
+ SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
+ 	sshconnect.o sshconnect1.o sshconnect2.o mux.o \
+diff -up openssh-6.8p1/audit-bsm.c.audit openssh-6.8p1/audit-bsm.c
+--- openssh-6.8p1/audit-bsm.c.audit	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/audit-bsm.c	2015-03-20 13:41:15.092883782 +0100
+@@ -375,10 +375,23 @@ audit_connection_from(const char *host,
+ #endif
+ }
+ 
+-void
++int
+ audit_run_command(const char *command)
+ {
+ 	/* not implemented */
++	return 0;
++}
++
++void
++audit_end_command(int handle, const char *command)
++{
++	/* not implemented */
++}
++
++void
++audit_count_session_open(void)
++{
++	/* not necessary */
+ }
+ 
+ void
+@@ -393,6 +406,12 @@ audit_session_close(struct logininfo *li)
+ 	/* not implemented */
+ }
+ 
++int
++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv)
++{
++	/* not implemented */
++}
++
+ void
+ audit_event(ssh_audit_event_t event)
+ {
+@@ -454,4 +473,40 @@ audit_event(ssh_audit_event_t event)
+ 		debug("%s: unhandled event %d", __func__, event);
+ 	}
+ }
++
++void
++audit_unsupported_body(int what)
++{
++	/* not implemented */
++}
++
++void
++audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, uid_t uid)
++{
++	/* not implemented */
++}
++
++void
++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
++{
++	/* not implemented */
++}
++
++void
++audit_destroy_sensitive_data(const char *fp)
++{
++	/* not implemented */
++}
++
++void
++audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid)
++{
++	/* not implemented */
++}
++
++void
++audit_generate_ephemeral_server_key(const char *fp)
++{
++	/* not implemented */
++}
+ #endif /* BSM */
+diff -up openssh-6.8p1/audit-linux.c.audit openssh-6.8p1/audit-linux.c
+--- openssh-6.8p1/audit-linux.c.audit	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/audit-linux.c	2015-03-20 13:41:15.093883780 +0100
+@@ -35,13 +35,25 @@
+ 
+ #include "log.h"
+ #include "audit.h"
++#include "key.h"
++#include "hostfile.h"
++#include "auth.h"
++#include "misc.h"      /* servconf.h needs misc.h for struct ForwardOptions */
++#include "servconf.h"
+ #include "canohost.h"
++#include "packet.h"
++#include "cipher.h"
+ 
++#define AUDIT_LOG_SIZE 256
++
++extern ServerOptions options;
++extern Authctxt *the_authctxt;
++extern u_int utmp_len;
+ const char* audit_username(void);
+ 
+-int
+-linux_audit_record_event(int uid, const char *username,
+-    const char *hostname, const char *ip, const char *ttyn, int success)
++static void
++linux_audit_user_logxxx(int uid, const char *username,
++    const char *hostname, const char *ip, const char *ttyn, int success, int event)
+ {
+ 	int audit_fd, rc, saved_errno;
+ 
+@@ -49,11 +61,11 @@ linux_audit_record_event(int uid, const char *username,
+ 	if (audit_fd < 0) {
+ 		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
+ 		    errno == EAFNOSUPPORT)
+-			return 1; /* No audit support in kernel */
++			return; /* No audit support in kernel */
+ 		else
+-			return 0; /* Must prevent login */
++			goto fatal_report; /* Must prevent login */
+ 	}
+-	rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN,
++	rc = audit_log_acct_message(audit_fd, event,
+ 	    NULL, "login", username ? username : "(unknown)",
+ 	    username == NULL ? uid : -1, hostname, ip, ttyn, success);
+ 	saved_errno = errno;
+@@ -65,35 +77,154 @@ linux_audit_record_event(int uid, const char *username,
+ 	if ((rc == -EPERM) && (geteuid() != 0))
+ 		rc = 0;
+ 	errno = saved_errno;
+-	return (rc >= 0);
++	if (rc < 0) {
++fatal_report:
++		fatal("linux_audit_write_entry failed: %s", strerror(errno));
++	}
+ }
+ 
++static void
++linux_audit_user_auth(int uid, const char *username,
++    const char *hostname, const char *ip, const char *ttyn, int success, int event)
++{
++	int audit_fd, rc, saved_errno;
++	static const char *event_name[] = {
++		"maxtries exceeded",
++		"root denied",
++		"success",
++		"none",
++		"password",
++		"challenge-response",
++		"pubkey",
++		"hostbased",
++		"gssapi",
++		"invalid user",
++		"nologin",
++		"connection closed",
++		"connection abandoned",
++		"unknown"
++	};
++
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
++		    errno == EAFNOSUPPORT)
++			return; /* No audit support in kernel */
++		else
++			goto fatal_report; /* Must prevent login */
++	}
++	
++	if ((event < 0) || (event > SSH_AUDIT_UNKNOWN))
++		event = SSH_AUDIT_UNKNOWN;
++
++	rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH,
++	    NULL, event_name[event], username ? username : "(unknown)",
++	    username == NULL ? uid : -1, hostname, ip, ttyn, success);
++	saved_errno = errno;
++	close(audit_fd);
++	/*
++	 * Do not report error if the error is EPERM and sshd is run as non
++	 * root user.
++	 */
++	if ((rc == -EPERM) && (geteuid() != 0))
++		rc = 0;
++	errno = saved_errno;
++	if (rc < 0) {
++fatal_report:
++		fatal("linux_audit_write_entry failed: %s", strerror(errno));
++	}
++}
++
++int
++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv)
++{
++	char buf[AUDIT_LOG_SIZE];
++	int audit_fd, rc, saved_errno;
++
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
++					 errno == EAFNOSUPPORT)
++			return 1; /* No audit support in kernel */
++		else                                                                                                                                       
++			return 0; /* Must prevent login */
++	}
++	snprintf(buf, sizeof(buf), "%s_auth rport=%d", host_user ? "pubkey" : "hostbased", get_remote_port());
++	rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
++		buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv);
++	if ((rc < 0) && ((rc != -1) || (getuid() == 0)))
++		goto out;
++	/* is the fingerprint_prefix() still needed? 
++	snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s%s rport=%d",
++			type, bits, sshkey_fingerprint_prefix(), fp, get_remote_port());
++	*/
++	snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s rport=%d",
++			type, bits, fp, get_remote_port());
++	rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
++		buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv);
++out:
++	saved_errno = errno;
++	audit_close(audit_fd);
++	errno = saved_errno;
++	/* do not report error if the error is EPERM and sshd is run as non root user */
++	return (rc >= 0) || ((rc == -EPERM) && (getuid() != 0));
++}
++
++static int user_login_count = 0;
++
+ /* Below is the sshd audit API code */
+ 
+ void
+ audit_connection_from(const char *host, int port)
+ {
+-}
+ 	/* not implemented */
++}
+ 
+-void
++int
+ audit_run_command(const char *command)
+ {
+-	/* not implemented */
++	if (!user_login_count++) 
++		linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++		    NULL, "ssh", 1, AUDIT_USER_LOGIN);
++	linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++	    NULL, "ssh", 1, AUDIT_USER_START);
++	return 0;
++}
++
++void
++audit_end_command(int handle, const char *command)
++{
++	linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++	    NULL, "ssh", 1, AUDIT_USER_END);
++	if (user_login_count && !--user_login_count) 
++		linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++		    NULL, "ssh", 1, AUDIT_USER_LOGOUT);
++}
++
++void
++audit_count_session_open(void)
++{
++	user_login_count++;
+ }
+ 
+ void
+ audit_session_open(struct logininfo *li)
+ {
+-	if (linux_audit_record_event(li->uid, NULL, li->hostname,
+-	    NULL, li->line, 1) == 0)
+-		fatal("linux_audit_write_entry failed: %s", strerror(errno));
++	if (!user_login_count++) 
++		linux_audit_user_logxxx(li->uid, NULL, li->hostname,
++		    NULL, li->line, 1, AUDIT_USER_LOGIN);
++	linux_audit_user_logxxx(li->uid, NULL, li->hostname,
++	    NULL, li->line, 1, AUDIT_USER_START);
+ }
+ 
+ void
+ audit_session_close(struct logininfo *li)
+ {
+-	/* not implemented */
++	linux_audit_user_logxxx(li->uid, NULL, li->hostname,
++	    NULL, li->line, 1, AUDIT_USER_END);
++	if (user_login_count && !--user_login_count) 
++		linux_audit_user_logxxx(li->uid, NULL, li->hostname,
++		    NULL, li->line, 1, AUDIT_USER_LOGOUT);
+ }
+ 
+ void
+@@ -101,21 +232,43 @@ audit_event(ssh_audit_event_t event)
+ {
+ 	switch(event) {
+ 	case SSH_AUTH_SUCCESS:
+-	case SSH_CONNECTION_CLOSE:
++		linux_audit_user_auth(-1, audit_username(), NULL,
++			get_remote_ipaddr(), "ssh", 1, event);
++		break;
++
+ 	case SSH_NOLOGIN:
+-	case SSH_LOGIN_EXCEED_MAXTRIES:
+ 	case SSH_LOGIN_ROOT_DENIED:
++		linux_audit_user_auth(-1, audit_username(), NULL,
++			get_remote_ipaddr(), "ssh", 0, event);
++		linux_audit_user_logxxx(-1, audit_username(), NULL,
++			get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN);
+ 		break;
+ 
++	case SSH_LOGIN_EXCEED_MAXTRIES:
+ 	case SSH_AUTH_FAIL_NONE:
+ 	case SSH_AUTH_FAIL_PASSWD:
+ 	case SSH_AUTH_FAIL_KBDINT:
+ 	case SSH_AUTH_FAIL_PUBKEY:
+ 	case SSH_AUTH_FAIL_HOSTBASED:
+ 	case SSH_AUTH_FAIL_GSSAPI:
++		linux_audit_user_auth(-1, audit_username(), NULL,
++			get_remote_ipaddr(), "ssh", 0, event);
++		break;
++
++	case SSH_CONNECTION_CLOSE:
++		if (user_login_count) {
++			while (user_login_count--)
++				linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++				    NULL, "ssh", 1, AUDIT_USER_END);
++			linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++			    NULL, "ssh", 1, AUDIT_USER_LOGOUT);
++		}
++		break;
++
++	case SSH_CONNECTION_ABANDON:
+ 	case SSH_INVALID_USER:
+-		linux_audit_record_event(-1, audit_username(), NULL,
+-			get_remote_ipaddr(), "sshd", 0);
++		linux_audit_user_logxxx(-1, audit_username(), NULL,
++			get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN);
+ 		break;
+ 
+ 	default:
+@@ -123,4 +276,135 @@ audit_event(ssh_audit_event_t event)
+ 	}
+ }
+ 
++void
++audit_unsupported_body(int what)
++{
++#ifdef AUDIT_CRYPTO_SESSION
++	char buf[AUDIT_LOG_SIZE];
++	const static char *name[] = { "cipher", "mac", "comp" };
++	char *s;
++	int audit_fd;
++
++	snprintf(buf, sizeof(buf), "op=unsupported-%s direction=? cipher=? ksize=? rport=%d laddr=%s lport=%d ",
++		name[what], get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())),
++		get_local_port());
++	free(s);
++	audit_fd = audit_open();
++	if (audit_fd < 0)
++		/* no problem, the next instruction will be fatal() */
++		return;
++	audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION,
++			buf, NULL, get_remote_ipaddr(), NULL, 0);
++	audit_close(audit_fd);
++#endif
++}
++
++const static char *direction[] = { "from-server", "from-client", "both" };
++
++void
++audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid,
++	       uid_t uid)
++{
++#ifdef AUDIT_CRYPTO_SESSION
++	char buf[AUDIT_LOG_SIZE];
++	int audit_fd, audit_ok;
++	const Cipher *cipher = cipher_by_name(enc);
++	char *s;
++
++	snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s pfs=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ",
++		direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac, pfs,
++		(intmax_t)pid, (intmax_t)uid,
++		get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), get_local_port());
++	free(s);
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
++					 errno == EAFNOSUPPORT)
++			return; /* No audit support in kernel */
++		else                                                                                                                                       
++			fatal("cannot open audit"); /* Must prevent login */
++	}
++	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION,
++			buf, NULL, get_remote_ipaddr(), NULL, 1);
++	audit_close(audit_fd);
++	/* do not abort if the error is EPERM and sshd is run as non root user */
++	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
++		fatal("cannot write into audit"); /* Must prevent login */
++#endif
++}
++
++void
++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
++{
++	char buf[AUDIT_LOG_SIZE];
++	int audit_fd, audit_ok;
++	char *s;
++
++	snprintf(buf, sizeof(buf), "op=destroy kind=session fp=? direction=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ",
++		 direction[ctos], (intmax_t)pid, (intmax_t)uid,
++		 get_remote_port(),
++		 (s = get_local_ipaddr(packet_get_connection_in())),
++		 get_local_port());
++	free(s);
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno != EINVAL && errno != EPROTONOSUPPORT &&
++					 errno != EAFNOSUPPORT)
++			error("cannot open audit");
++		return;
++	}
++	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER,
++			buf, NULL, get_remote_ipaddr(), NULL, 1);
++	audit_close(audit_fd);
++	/* do not abort if the error is EPERM and sshd is run as non root user */
++	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
++		error("cannot write into audit");
++}
++
++void
++audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid)
++{
++	char buf[AUDIT_LOG_SIZE];
++	int audit_fd, audit_ok;
++
++	snprintf(buf, sizeof(buf), "op=destroy kind=server fp=%s direction=? spid=%jd suid=%jd ",
++		fp, (intmax_t)pid, (intmax_t)uid);
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno != EINVAL && errno != EPROTONOSUPPORT &&
++					 errno != EAFNOSUPPORT)
++			error("cannot open audit");
++		return;
++	}
++	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER,
++			buf, NULL,
++			listening_for_clients() ? get_remote_ipaddr() : NULL,
++			NULL, 1);
++	audit_close(audit_fd);
++	/* do not abort if the error is EPERM and sshd is run as non root user */
++	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
++		error("cannot write into audit");
++}
++
++void
++audit_generate_ephemeral_server_key(const char *fp)
++{
++	char buf[AUDIT_LOG_SIZE];
++	int audit_fd, audit_ok;
++
++	snprintf(buf, sizeof(buf), "op=create kind=server fp=%s direction=? ", fp);
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno != EINVAL && errno != EPROTONOSUPPORT &&
++					 errno != EAFNOSUPPORT)
++			error("cannot open audit");
++		return;
++	}
++	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER,
++			buf, NULL, 0, NULL, 1);
++	audit_close(audit_fd);
++	/* do not abort if the error is EPERM and sshd is run as non root user */
++	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
++		error("cannot write into audit");
++}
+ #endif /* USE_LINUX_AUDIT */
+diff -up openssh-6.8p1/audit.c.audit openssh-6.8p1/audit.c
+--- openssh-6.8p1/audit.c.audit	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/audit.c	2015-03-20 13:41:15.093883780 +0100
+@@ -28,6 +28,7 @@
+ 
+ #include <stdarg.h>
+ #include <string.h>
++#include <unistd.h>
+ 
+ #ifdef SSH_AUDIT_EVENTS
+ 
+@@ -36,6 +37,11 @@
+ #include "key.h"
+ #include "hostfile.h"
+ #include "auth.h"
++#include "ssh-gss.h"
++#include "monitor_wrap.h"
++#include "xmalloc.h"
++#include "misc.h"
++#include "servconf.h"
+ 
+ /*
+  * Care must be taken when using this since it WILL NOT be initialized when
+@@ -43,6 +49,7 @@
+  * audit_event(CONNECTION_ABANDON) is called.  Test for NULL before using.
+  */
+ extern Authctxt *the_authctxt;
++extern ServerOptions options;
+ 
+ /* Maybe add the audit class to struct Authmethod? */
+ ssh_audit_event_t
+@@ -71,13 +78,10 @@ audit_classify_auth(const char *method)
+ const char *
+ audit_username(void)
+ {
+-	static const char unknownuser[] = "(unknown user)";
+-	static const char invaliduser[] = "(invalid user)";
++	static const char unknownuser[] = "(unknown)";
+ 
+-	if (the_authctxt == NULL || the_authctxt->user == NULL)
++	if (the_authctxt == NULL || the_authctxt->user == NULL || !the_authctxt->valid)
+ 		return (unknownuser);
+-	if (!the_authctxt->valid)
+-		return (invaliduser);
+ 	return (the_authctxt->user);
+ }
+ 
+@@ -111,6 +115,40 @@ audit_event_lookup(ssh_audit_event_t ev)
+ 	return(event_lookup[i].name);
+ }
+ 
++void
++audit_key(int host_user, int *rv, const Key *key)
++{
++	char *fp;
++	const char *crypto_name;
++
++	fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX);
++	if (key->type == KEY_RSA1)
++		crypto_name = "ssh-rsa1";
++	else
++		crypto_name = key_ssh_name(key);
++	if (audit_keyusage(host_user, crypto_name, key_size(key), fp, *rv) == 0)
++		*rv = 0;
++	free(fp);
++}
++
++void
++audit_unsupported(int what)
++{
++	PRIVSEP(audit_unsupported_body(what));
++}
++
++void
++audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs)
++{
++	PRIVSEP(audit_kex_body(ctos, enc, mac, comp, pfs, getpid(), getuid()));
++}
++
++void
++audit_session_key_free(int ctos)
++{
++	PRIVSEP(audit_session_key_free_body(ctos, getpid(), getuid()));
++}
++
+ # ifndef CUSTOM_SSH_AUDIT_EVENTS
+ /*
+  * Null implementations of audit functions.
+@@ -140,6 +178,17 @@ audit_event(ssh_audit_event_t event)
+ }
+ 
+ /*
++ * Called when a child process has called, or will soon call,
++ * audit_session_open.
++ */
++void
++audit_count_session_open(void)
++{
++	debug("audit count session open euid %d user %s", geteuid(),
++	      audit_username());
++}
++
++/*
+  * Called when a user session is started.  Argument is the tty allocated to
+  * the session, or NULL if no tty was allocated.
+  *
+@@ -174,13 +223,91 @@ audit_session_close(struct logininfo *li)
+ /*
+  * This will be called when a user runs a non-interactive command.  Note that
+  * it may be called multiple times for a single connection since SSH2 allows
+- * multiple sessions within a single connection.
++ * multiple sessions within a single connection.  Returns a "handle" for
++ * audit_end_command.
+  */
+-void
++int
+ audit_run_command(const char *command)
+ {
+ 	debug("audit run command euid %d user %s command '%.200s'", geteuid(),
+ 	    audit_username(), command);
++	return 0;
++}
++
++/*
++ * This will be called when the non-interactive command finishes.  Note that
++ * it may be called multiple times for a single connection since SSH2 allows
++ * multiple sessions within a single connection.  "handle" should come from
++ * the corresponding audit_run_command.
++ */
++void
++audit_end_command(int handle, const char *command)
++{
++	debug("audit end nopty exec  euid %d user %s command '%.200s'", geteuid(),
++	    audit_username(), command);
++}
++
++/*
++ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key.
++ *
++ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key.
++ */
++int
++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv)
++{
++	debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s%s, result %d", 
++		host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), type, bits,
++		sshkey_fingerprint_prefix(), fp, rv);
++}
++
++/*
++ * This will be called when the protocol negotiation fails.
++ */
++void
++audit_unsupported_body(int what)
++{
++	debug("audit unsupported protocol euid %d type %d", geteuid(), what);
++}
++
++/*
++ * This will be called on succesfull protocol negotiation.
++ */
++void
++audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid,
++	       uid_t uid)
++{
++	debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s pfs %s from pid %ld uid %u",
++		(unsigned)geteuid(), ctos, enc, mac, compress, pfs, (long)pid,
++	        (unsigned)uid);
++}
++
++/*
++ * This will be called on succesfull session key discard
++ */
++void
++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
++{
++	debug("audit session key discard euid %u direction %d from pid %ld uid %u",
++		(unsigned)geteuid(), ctos, (long)pid, (unsigned)uid);
++}
++
++/*
++ * This will be called on destroy private part of the server key
++ */
++void
++audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid)
++{
++	debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u",
++		geteuid(), fp, (long)pid, (unsigned)uid);
++}
++
++/*
++ * This will be called on generation of the ephemeral server key
++ */
++void
++audit_generate_ephemeral_server_key(const char *)
++{
++	debug("audit create ephemeral server key euid %d fingerprint %s", geteuid(), fp);
+ }
+ # endif  /* !defined CUSTOM_SSH_AUDIT_EVENTS */
+ #endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-6.8p1/audit.h.audit openssh-6.8p1/audit.h
+--- openssh-6.8p1/audit.h.audit	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/audit.h	2015-03-20 13:41:15.093883780 +0100
+@@ -28,6 +28,7 @@
+ # define _SSH_AUDIT_H
+ 
+ #include "loginrec.h"
++#include "key.h"
+ 
+ enum ssh_audit_event_type {
+ 	SSH_LOGIN_EXCEED_MAXTRIES,
+@@ -47,11 +48,25 @@ enum ssh_audit_event_type {
+ };
+ typedef enum ssh_audit_event_type ssh_audit_event_t;
+ 
++int	listening_for_clients(void);
++
+ void	audit_connection_from(const char *, int);
+ void	audit_event(ssh_audit_event_t);
++void	audit_count_session_open(void);
+ void	audit_session_open(struct logininfo *);
+ void	audit_session_close(struct logininfo *);
+-void	audit_run_command(const char *);
++int	audit_run_command(const char *);
++void 	audit_end_command(int, const char *);
+ ssh_audit_event_t audit_classify_auth(const char *);
++int	audit_keyusage(int, const char *, unsigned, char *, int);
++void	audit_key(int, int *, const Key *);
++void	audit_unsupported(int);
++void	audit_kex(int, char *, char *, char *, char *);
++void	audit_unsupported_body(int);
++void	audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t);
++void	audit_session_key_free(int ctos);
++void	audit_session_key_free_body(int ctos, pid_t, uid_t);
++void	audit_destroy_sensitive_data(const char *, pid_t, uid_t);
++void	audit_generate_ephemeral_server_key(const char *);
+ 
+ #endif /* _SSH_AUDIT_H */
+diff -up openssh-6.8p1/auditstub.c.audit openssh-6.8p1/auditstub.c
+--- openssh-6.8p1/auditstub.c.audit	2015-03-20 13:41:15.093883780 +0100
++++ openssh-6.8p1/auditstub.c	2015-03-20 13:41:15.093883780 +0100
+@@ -0,0 +1,50 @@
++/* $Id: auditstub.c,v 1.1 jfch Exp $ */
++
++/*
++ * Copyright 2010 Red Hat, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ *
++ * 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.
++ *
++ * Red Hat author: Jan F. Chadima <jchadima at redhat.com>
++ */
++
++#include <sys/types.h>
++
++void
++audit_unsupported(int n)
++{
++}
++
++void
++audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs)
++{
++}
++
++void
++audit_session_key_free(int ctos)
++{
++}
++
++void
++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
++{
++}
+diff -up openssh-6.8p1/auth-rsa.c.audit openssh-6.8p1/auth-rsa.c
+--- openssh-6.8p1/auth-rsa.c.audit	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/auth-rsa.c	2015-03-20 13:41:15.094883779 +0100
+@@ -95,7 +95,10 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16])
+ {
+ 	u_char buf[32], mdbuf[16];
+ 	struct ssh_digest_ctx *md;
+-	int len;
++	int len, rv;
++#ifdef SSH_AUDIT_EVENTS
++	char *fp;
++#endif
+ 
+ 	/* don't allow short keys */
+ 	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
+@@ -119,12 +122,18 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16])
+ 	ssh_digest_free(md);
+ 
+ 	/* Verify that the response is the original challenge. */
+-	if (timingsafe_bcmp(response, mdbuf, 16) != 0) {
+-		/* Wrong answer. */
+-		return (0);
++	rv = timingsafe_bcmp(response, mdbuf, 16) == 0;
++
++#ifdef SSH_AUDIT_EVENTS
++	fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX);
++	if (audit_keyusage(1, "ssh-rsa1", RSA_size(key->rsa) * 8, fp, rv) == 0) {
++		debug("unsuccessful audit");
++		rv = 0;
+ 	}
+-	/* Correct answer. */
+-	return (1);
++	free(fp);
++#endif
++
++	return rv;
+ }
+ 
+ /*
+diff -up openssh-6.8p1/auth.c.audit openssh-6.8p1/auth.c
+--- openssh-6.8p1/auth.c.audit	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/auth.c	2015-03-20 13:41:15.094883779 +0100
+@@ -644,9 +644,6 @@ getpwnamallow(const char *user)
+ 		record_failed_login(user,
+ 		    get_canonical_hostname(options.use_dns), "ssh");
+ #endif
+-#ifdef SSH_AUDIT_EVENTS
+-		audit_event(SSH_INVALID_USER);
+-#endif /* SSH_AUDIT_EVENTS */
+ 		return (NULL);
+ 	}
+ 	if (!allowed_user(pw))
+diff -up openssh-6.8p1/auth.h.audit openssh-6.8p1/auth.h
+--- openssh-6.8p1/auth.h.audit	2015-03-20 13:41:15.002883927 +0100
++++ openssh-6.8p1/auth.h	2015-03-20 13:41:15.094883779 +0100
+@@ -195,6 +195,7 @@ void	abandon_challenge_response(Authctxt
+ 
+ char	*expand_authorized_keys(const char *, struct passwd *pw);
+ char	*authorized_principals_file(struct passwd *);
++int	 user_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
+ 
+ FILE	*auth_openkeyfile(const char *, struct passwd *, int);
+ FILE	*auth_openprincipals(const char *, struct passwd *, int);
+@@ -213,6 +214,7 @@ int	 get_hostkey_index(Key *, int, struc
+ int	 ssh1_session_key(BIGNUM *);
+ int	 sshd_hostkey_sign(Key *, Key *, u_char **, size_t *,
+ 	     const u_char *, size_t, u_int);
++int	 hostbased_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
+ 
+ /* debug messages during authentication */
+ void	 auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+diff -up openssh-6.8p1/auth2-hostbased.c.audit openssh-6.8p1/auth2-hostbased.c
+--- openssh-6.8p1/auth2-hostbased.c.audit	2015-03-20 13:41:15.002883927 +0100
++++ openssh-6.8p1/auth2-hostbased.c	2015-03-20 13:41:15.093883780 +0100
+@@ -147,7 +147,7 @@ userauth_hostbased(Authctxt *authctxt)
+ 	/* test for allowed key and correct signature */
+ 	authenticated = 0;
+ 	if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) &&
+-	    PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
++	    PRIVSEP(hostbased_key_verify(key, sig, slen, buffer_ptr(&b),
+ 			buffer_len(&b))) == 1)
+ 		authenticated = 1;
+ 
+@@ -164,6 +164,18 @@ done:
+ 	return authenticated;
+ }
+ 
++int
++hostbased_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen)
++{
++	int rv;
++
++	rv = key_verify(key, sig, slen, data, datalen);
++#ifdef SSH_AUDIT_EVENTS
++	audit_key(0, &rv, key);
++#endif
++	return rv;
++}
++
+ /* return 1 if given hostkey is allowed */
+ int
+ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
+diff -up openssh-6.8p1/auth2-pubkey.c.audit openssh-6.8p1/auth2-pubkey.c
+--- openssh-6.8p1/auth2-pubkey.c.audit	2015-03-20 13:41:15.013883910 +0100
++++ openssh-6.8p1/auth2-pubkey.c	2015-03-20 13:41:15.094883779 +0100
+@@ -172,7 +172,7 @@ userauth_pubkey(Authctxt *authctxt)
+ 		/* test for correct signature */
+ 		authenticated = 0;
+ 		if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
+-		    PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
++		    PRIVSEP(user_key_verify(key, sig, slen, buffer_ptr(&b),
+ 		    buffer_len(&b))) == 1) {
+ 			authenticated = 1;
+ 			/* Record the successful key to prevent reuse */
+@@ -250,6 +250,18 @@ pubkey_auth_info(Authctxt *authctxt, con
+ 	free(extra);
+ }
+ 
++int
++user_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen)
++{
++	int rv;
++
++	rv = key_verify(key, sig, slen, data, datalen);
++#ifdef SSH_AUDIT_EVENTS
++	audit_key(1, &rv, key);
++#endif
++	return rv;
++}
++
+ static int
+ match_principals_option(const char *principal_list, struct sshkey_cert *cert)
+ {
+diff -up openssh-6.8p1/auth2.c.audit openssh-6.8p1/auth2.c
+--- openssh-6.8p1/auth2.c.audit	2015-03-20 13:41:15.044883860 +0100
++++ openssh-6.8p1/auth2.c	2015-03-20 13:41:15.093883780 +0100
+@@ -249,9 +249,6 @@ input_userauth_request(int type, u_int32
+ 		} else {
+ 			logit("input_userauth_request: invalid user %s", user);
+ 			authctxt->pw = fakepw();
+-#ifdef SSH_AUDIT_EVENTS
+-			PRIVSEP(audit_event(SSH_INVALID_USER));
+-#endif
+ 		}
+ #ifdef USE_PAM
+ 		if (options.use_pam)
+diff -up openssh-6.8p1/cipher.c.audit openssh-6.8p1/cipher.c
+--- openssh-6.8p1/cipher.c.audit	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/cipher.c	2015-03-20 13:41:15.101883767 +0100
+@@ -57,26 +59,6 @@ extern const EVP_CIPHER *evp_ssh1_3des(v
+ extern int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
+ #endif
+ 
+-struct sshcipher {
+-	char	*name;
+-	int	number;		/* for ssh1 only */
+-	u_int	block_size;
+-	u_int	key_len;
+-	u_int	iv_len;		/* defaults to block_size */
+-	u_int	auth_len;
+-	u_int	discard_len;
+-	u_int	flags;
+-#define CFLAG_CBC		(1<<0)
+-#define CFLAG_CHACHAPOLY	(1<<1)
+-#define CFLAG_AESCTR		(1<<2)
+-#define CFLAG_NONE		(1<<3)
+-#ifdef WITH_OPENSSL
+-	const EVP_CIPHER	*(*evptype)(void);
+-#else
+-	void	*ignored;
+-#endif
+-};
+-
+ static const struct sshcipher ciphers[] = {
+ #ifdef WITH_SSH1
+ 	{ "des",	SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc },
+diff -up openssh-6.8p1/cipher.h.audit openssh-6.8p1/cipher.h
+--- openssh-6.8p1/cipher.h.audit	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/cipher.h	2015-03-20 13:41:15.094883779 +0100
+@@ -62,7 +62,26 @@
+ #define CIPHER_ENCRYPT		1
+ #define CIPHER_DECRYPT		0
+ 
+-struct sshcipher;
++struct sshcipher {
++	char	*name;
++	int	number;		/* for ssh1 only */
++	u_int	block_size;
++	u_int	key_len;
++	u_int	iv_len;		/* defaults to block_size */
++	u_int	auth_len;
++	u_int	discard_len;
++	u_int	flags;
++#define CFLAG_CBC		(1<<0)
++#define CFLAG_CHACHAPOLY	(1<<1)
++#define CFLAG_AESCTR		(1<<2)
++#define CFLAG_NONE		(1<<3)
++#ifdef WITH_OPENSSL
++	const EVP_CIPHER	*(*evptype)(void);
++#else
++	void	*ignored;
++#endif
++};
++
+ struct sshcipher_ctx {
+ 	int	plaintext;
+ 	int	encrypt;
+diff -up openssh-6.8p1/kex.c.audit openssh-6.8p1/kex.c
+--- openssh-6.8p1/kex.c.audit	2015-03-20 13:41:15.046883856 +0100
++++ openssh-6.8p1/kex.c	2015-03-20 13:41:15.101883767 +0100
+@@ -54,6 +55,7 @@
+ #include "ssherr.h"
+ #include "sshbuf.h"
+ #include "digest.h"
++#include "audit.h"
+ 
+ #ifdef GSSAPI
+ #include "ssh-gss.h"
+@@ -484,8 +508,12 @@ choose_enc(struct sshenc *enc, char *cli
+ {
+ 	char *name = match_list(client, server, NULL);
+ 
+-	if (name == NULL)
++	if (name == NULL) {
++#ifdef SSH_AUDIT_EVENTS
++		audit_unsupported(0);
++#endif
+ 		return SSH_ERR_NO_CIPHER_ALG_MATCH;
++	}
+ 	if ((enc->cipher = cipher_by_name(name)) == NULL)
+ 		return SSH_ERR_INTERNAL_ERROR;
+ 	enc->name = name;
+@@ -503,8 +531,12 @@ choose_mac(struct ssh *ssh, struct sshma
+ {
+ 	char *name = match_list(client, server, NULL);
+ 
+-	if (name == NULL)
++	if (name == NULL) {
++#ifdef SSH_AUDIT_EVENTS
++		audit_unsupported(1);
++#endif
+ 		return SSH_ERR_NO_MAC_ALG_MATCH;
++	}
+ 	if (mac_setup(mac, name) < 0)
+ 		return SSH_ERR_INTERNAL_ERROR;
+ 	/* truncate the key */
+@@ -521,8 +553,12 @@ choose_comp(struct sshcomp *comp, char *
+ {
+ 	char *name = match_list(client, server, NULL);
+ 
+-	if (name == NULL)
++	if (name == NULL) {
++#ifdef SSH_AUDIT_EVENTS
++		audit_unsupported(2);
++#endif
+ 		return SSH_ERR_NO_COMPRESS_ALG_MATCH;
++	}
+ 	if (strcmp(name, "zlib at openssh.com") == 0) {
+ 		comp->type = COMP_DELAYED;
+ 	} else if (strcmp(name, "zlib") == 0) {
+@@ -672,6 +708,10 @@ kex_choose_conf(struct ssh *ssh)
+ 		dh_need = MAX(dh_need, newkeys->enc.block_size);
+ 		dh_need = MAX(dh_need, newkeys->enc.iv_len);
+ 		dh_need = MAX(dh_need, newkeys->mac.key_len);
++		debug("kex: %s need=%d dh_need=%d", kex->name, need, dh_need);
++#ifdef SSH_AUDIT_EVENTS
++		audit_kex(mode, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name, kex->name);
++#endif
+ 	}
+ 	/* XXX need runden? */
+ 	kex->we_need = need;
+@@ -847,3 +887,34 @@ dump_digest(char *msg, u_char *digest, i
+ 	sshbuf_dump_data(digest, len, stderr);
+ }
+ #endif
++
++static void
++enc_destroy(struct sshenc *enc)
++{
++	if (enc == NULL)
++		return;
++
++	if (enc->key) {
++		memset(enc->key, 0, enc->key_len);
++		free(enc->key);
++	}
++
++	if (enc->iv) {
++		memset(enc->iv,  0, enc->block_size);
++		free(enc->iv);
++	}
++
++	memset(enc, 0, sizeof(*enc));
++}
++
++void
++newkeys_destroy(struct newkeys *newkeys)
++{
++	if (newkeys == NULL)
++		return;
++
++	enc_destroy(&newkeys->enc);
++	mac_destroy(&newkeys->mac);
++	memset(&newkeys->comp, 0, sizeof(newkeys->comp));
++}
++
+diff -up openssh-6.8p1/kex.h.audit openssh-6.8p1/kex.h
+--- openssh-6.8p1/kex.h.audit	2015-03-20 13:41:15.046883856 +0100
++++ openssh-6.8p1/kex.h	2015-03-20 13:41:15.095883777 +0100
+@@ -199,6 +199,8 @@ int	 kexgss_client(struct ssh *);
+ int	 kexgss_server(struct ssh *);
+ #endif
+ 
++void	newkeys_destroy(struct newkeys *newkeys);
++
+ 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 *);
+diff -up openssh-6.8p1/key.h.audit openssh-6.8p1/key.h
+--- openssh-6.8p1/key.h.audit	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/key.h	2015-03-20 13:41:15.095883777 +0100
+@@ -50,6 +50,7 @@ typedef struct sshkey Key;
+ #define key_ecdsa_bits_to_nid	sshkey_ecdsa_bits_to_nid
+ #define key_ecdsa_key_to_nid	sshkey_ecdsa_key_to_nid
+ #define key_is_cert		sshkey_is_cert
++#define key_is_private		sshkey_is_private
+ #define key_type_plain		sshkey_type_plain
+ #define key_cert_is_legacy	sshkey_cert_is_legacy
+ #define key_curve_name_to_nid	sshkey_curve_name_to_nid
+diff -up openssh-6.8p1/mac.c.audit openssh-6.8p1/mac.c
+--- openssh-6.8p1/mac.c.audit	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/mac.c	2015-03-20 13:41:15.102883766 +0100
+@@ -226,6 +246,20 @@ mac_clear(struct sshmac *mac)
+ 	mac->umac_ctx = NULL;
+ }
+ 
++void
++mac_destroy(struct sshmac *mac)
++{
++	if (mac == NULL)
++		return;
++
++	if (mac->key) {
++		memset(mac->key, 0, mac->key_len);
++		free(mac->key);
++	}
++
++	memset(mac, 0, sizeof(*mac));
++}
++
+ /* XXX copied from ciphers_valid */
+ #define	MAC_SEP	","
+ int
+diff -up openssh-6.8p1/mac.h.audit openssh-6.8p1/mac.h
+--- openssh-6.8p1/mac.h.audit	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/mac.h	2015-03-20 13:41:15.095883777 +0100
+@@ -47,5 +47,6 @@ int	 mac_init(struct sshmac *);
+ int	 mac_compute(struct sshmac *, u_int32_t, const u_char *, int,
+     u_char *, size_t);
+ void	 mac_clear(struct sshmac *);
++void	 mac_destroy(struct sshmac *);
+ 
+ #endif /* SSHMAC_H */
+diff -up openssh-6.8p1/monitor.c.audit openssh-6.8p1/monitor.c
+--- openssh-6.8p1/monitor.c.audit	2015-03-20 13:41:15.072883814 +0100
++++ openssh-6.8p1/monitor.c	2015-03-20 13:41:15.107883758 +0100
+@@ -102,6 +102,7 @@
+ #include "ssh2.h"
+ #include "roaming.h"
+ #include "authfd.h"
++#include "audit.h"
+ #include "match.h"
+ #include "ssherr.h"
+ 
+@@ -117,6 +118,8 @@ extern Buffer auth_debug;
+ extern int auth_debug_init;
+ extern Buffer loginmsg;
+ 
++extern void destroy_sensitive_data(int);
++
+ /* State exported from the child */
+ static struct sshbuf *child_state;
+ 
+@@ -167,6 +170,11 @@ int mm_answer_gss_updatecreds(int, Buffe
+ #ifdef SSH_AUDIT_EVENTS
+ int mm_answer_audit_event(int, Buffer *);
+ int mm_answer_audit_command(int, Buffer *);
++int mm_answer_audit_end_command(int, Buffer *);
++int mm_answer_audit_unsupported_body(int, Buffer *);
++int mm_answer_audit_kex_body(int, Buffer *);
++int mm_answer_audit_session_key_free_body(int, Buffer *);
++int mm_answer_audit_server_key_free(int, Buffer *);
+ #endif
+ 
+ static int monitor_read_log(struct monitor *);
+@@ -226,6 +234,10 @@ struct mon_table mon_dispatch_proto20[]
+ #endif
+ #ifdef SSH_AUDIT_EVENTS
+     {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
++    {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body},
++    {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body},
++    {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body},
++    {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free},
+ #endif
+ #ifdef BSD_AUTH
+     {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
+@@ -264,6 +276,11 @@ struct mon_table mon_dispatch_postauth20
+ #ifdef SSH_AUDIT_EVENTS
+     {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
+     {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command},
++    {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command},
++    {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body},
++    {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body},
++    {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body},
++    {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free},
+ #endif
+     {0, 0, NULL}
+ };
+@@ -296,6 +313,10 @@ struct mon_table mon_dispatch_proto15[]
+ #endif
+ #ifdef SSH_AUDIT_EVENTS
+     {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
++    {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body},
++    {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body},
++    {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body},
++    {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free},
+ #endif
+ #endif /* WITH_SSH1 */
+     {0, 0, NULL}
+@@ -309,6 +330,11 @@ struct mon_table mon_dispatch_postauth15
+ #ifdef SSH_AUDIT_EVENTS
+     {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
+     {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command},
++    {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command},
++    {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body},
++    {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body},
++    {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body},
++    {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free},
+ #endif
+ #endif /* WITH_SSH1 */
+     {0, 0, NULL}
+@@ -1466,9 +1493,11 @@ mm_answer_keyverify(int sock, Buffer *m)
+ 	Key *key;
+ 	u_char *signature, *data, *blob;
+ 	u_int signaturelen, datalen, bloblen;
++	int type = 0;
+ 	int verified = 0;
+ 	int valid_data = 0;
+ 
++	type = buffer_get_int(m);
+ 	blob = buffer_get_string(m, &bloblen);
+ 	signature = buffer_get_string(m, &signaturelen);
+ 	data = buffer_get_string(m, &datalen);
+@@ -1476,6 +1505,8 @@ mm_answer_keyverify(int sock, Buffer *m)
+ 	if (hostbased_cuser == NULL || hostbased_chost == NULL ||
+ 	  !monitor_allowed_key(blob, bloblen))
+ 		fatal("%s: bad key, not previously allowed", __func__);
++	if (type != key_blobtype)
++		fatal("%s: bad key type", __func__);
+ 
+ 	key = key_from_blob(blob, bloblen);
+ 	if (key == NULL)
+@@ -1496,7 +1527,17 @@ mm_answer_keyverify(int sock, Buffer *m)
+ 	if (!valid_data)
+ 		fatal("%s: bad signature data blob", __func__);
+ 
+-	verified = key_verify(key, signature, signaturelen, data, datalen);
++	switch (key_blobtype) {
++	case MM_USERKEY:
++		verified = user_key_verify(key, signature, signaturelen, data, datalen);
++		break;
++	case MM_HOSTKEY:
++		verified = hostbased_key_verify(key, signature, signaturelen, data, datalen);
++		break;
++	default:
++		verified = 0;
++		break;
++	}
+ 	debug3("%s: key %p signature %s",
+ 	    __func__, key, (verified == 1) ? "verified" : "unverified");
+ 
+@@ -1554,6 +1595,12 @@ mm_session_close(Session *s)
+ 		debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd);
+ 		session_pty_cleanup2(s);
+ 	}
++#ifdef SSH_AUDIT_EVENTS
++	if (s->command != NULL) {
++		debug3("%s: command %d", __func__, s->command_handle);
++		session_end_command2(s);
++	}
++#endif
+ 	session_unused(s->self);
+ }
+ 
+@@ -1836,6 +1883,8 @@ mm_answer_term(int sock, Buffer *req)
+ 		sshpam_cleanup();
+ #endif
+ 
++	destroy_sensitive_data(0);
++
+ 	while (waitpid(pmonitor->m_pid, &status, 0) == -1)
+ 		if (errno != EINTR)
+ 			exit(1);
+@@ -1878,11 +1927,43 @@ mm_answer_audit_command(int socket, Buff
+ {
+ 	u_int len;
+ 	char *cmd;
++	Session *s;
+ 
+ 	debug3("%s entering", __func__);
+ 	cmd = buffer_get_string(m, &len);
++
+ 	/* sanity check command, if so how? */
+-	audit_run_command(cmd);
++	s = session_new();
++	if (s == NULL)
++		fatal("%s: error allocating a session", __func__);
++	s->command = cmd;
++	s->command_handle = audit_run_command(cmd);
++
++	buffer_clear(m);
++	buffer_put_int(m, s->self);
++
++	mm_request_send(socket, MONITOR_ANS_AUDIT_COMMAND, m);
++
++	return (0);
++}
++
++int
++mm_answer_audit_end_command(int socket, Buffer *m)
++{
++	int handle;
++	u_int len;
++	char *cmd;
++	Session *s;
++
++	debug3("%s entering", __func__);
++	handle = buffer_get_int(m);
++	cmd = buffer_get_string(m, &len);
++
++	s = session_by_id(handle);
++	if (s == NULL || s->ttyfd != -1 || s->command == NULL ||
++	    strcmp(s->command, cmd) != 0)
++		fatal("%s: invalid handle", __func__);
++	mm_session_close(s);
+ 	free(cmd);
+ 	return (0);
+ }
+@@ -1936,6 +2017,7 @@
+ void
+ mm_get_keystate(struct monitor *pmonitor)
+ {
++	Buffer m;
+ 	debug3("%s: Waiting for new keys", __func__);
+ 
+ 	if ((child_state = sshbuf_new()) == NULL)
+@@ -1946,6 +2027,21 @@ mm_get_keystate(struct monitor *pmonitor
+ 	mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT,
+ 	    child_state);
+ 	debug3("%s: GOT new keys", __func__);
++
++#ifdef SSH_AUDIT_EVENTS
++	if (compat20) {
++		buffer_init(&m);
++		mm_request_receive_expect(pmonitor->m_sendfd,
++					  MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m);
++		mm_answer_audit_session_key_free_body(pmonitor->m_sendfd, &m);
++		buffer_free(&m);
++	}
++#endif
++
++	/* Drain any buffered messages from the child */
++	while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0)
++		;
++
+ }
+ 
+ 
+@@ -2212,3 +2308,87 @@ mm_answer_gss_updatecreds(int socket, Bu
+ 
+ #endif /* GSSAPI */
+ 
++#ifdef SSH_AUDIT_EVENTS
++int
++mm_answer_audit_unsupported_body(int sock, Buffer *m)
++{
++	int what;
++
++	what = buffer_get_int(m);
++
++	audit_unsupported_body(what);
++
++	buffer_clear(m);
++
++	mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m);
++	return 0;
++}
++
++int
++mm_answer_audit_kex_body(int sock, Buffer *m)
++{
++	int ctos, len;
++	char *cipher, *mac, *compress, *pfs;
++	pid_t pid;
++	uid_t uid;
++
++	ctos = buffer_get_int(m);
++	cipher = buffer_get_string(m, &len);
++	mac = buffer_get_string(m, &len);
++	compress = buffer_get_string(m, &len);
++	pfs = buffer_get_string(m, &len);
++	pid = buffer_get_int64(m);
++	uid = buffer_get_int64(m);
++
++	audit_kex_body(ctos, cipher, mac, compress, pfs, pid, uid);
++
++	free(cipher);
++	free(mac);
++	free(compress);
++	free(pfs);
++	buffer_clear(m);
++
++	mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m);
++	return 0;
++}
++
++int
++mm_answer_audit_session_key_free_body(int sock, Buffer *m)
++{
++	int ctos;
++	pid_t pid;
++	uid_t uid;
++
++	ctos = buffer_get_int(m);
++	pid = buffer_get_int64(m);
++	uid = buffer_get_int64(m);
++
++	audit_session_key_free_body(ctos, pid, uid);
++
++	buffer_clear(m);
++
++	mm_request_send(sock, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, m);
++	return 0;
++}
++
++int
++mm_answer_audit_server_key_free(int sock, Buffer *m)
++{
++	int len;
++	char *fp;
++	pid_t pid;
++	uid_t uid;
++
++	fp = buffer_get_string(m, &len);
++	pid = buffer_get_int64(m);
++	uid = buffer_get_int64(m);
++
++	audit_destroy_sensitive_data(fp, pid, uid);
++
++	free(fp);
++	buffer_clear(m);
++
++	mm_request_send(sock, MONITOR_ANS_AUDIT_SERVER_KEY_FREE, m);
++	return 0;
++}
++#endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-6.8p1/monitor.h.audit openssh-6.8p1/monitor.h
+--- openssh-6.8p1/monitor.h.audit	2015-03-20 13:41:15.072883814 +0100
++++ openssh-6.8p1/monitor.h	2015-03-20 13:41:15.096883775 +0100
+@@ -69,7 +69,13 @@ enum monitor_reqtype {
+ 	MONITOR_REQ_PAM_QUERY = 106, MONITOR_ANS_PAM_QUERY = 107,
+ 	MONITOR_REQ_PAM_RESPOND = 108, MONITOR_ANS_PAM_RESPOND = 109,
+ 	MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
+-	MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
++	MONITOR_REQ_AUDIT_EVENT = 112,
++	MONITOR_REQ_AUDIT_COMMAND = 114, MONITOR_ANS_AUDIT_COMMAND = 115,
++	MONITOR_REQ_AUDIT_END_COMMAND = 116,
++	MONITOR_REQ_AUDIT_UNSUPPORTED = 118, MONITOR_ANS_AUDIT_UNSUPPORTED = 119,
++	MONITOR_REQ_AUDIT_KEX = 120, MONITOR_ANS_AUDIT_KEX = 121,
++	MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 122, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 123,
++	MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124, MONITOR_ANS_AUDIT_SERVER_KEY_FREE = 125
+ 
+ };
+ 
+diff -up openssh-6.8p1/monitor_wrap.c.audit openssh-6.8p1/monitor_wrap.c
+--- openssh-6.8p1/monitor_wrap.c.audit	2015-03-20 13:41:15.047883855 +0100
++++ openssh-6.8p1/monitor_wrap.c	2015-03-20 13:41:15.108883756 +0100
+@@ -461,7 +461,7 @@ mm_key_allowed(enum mm_keytype type, cha
+  */
+ 
+ int
+-mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
++mm_key_verify(enum mm_keytype type, Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
+ {
+ 	Buffer m;
+ 	u_char *blob;
+@@ -475,6 +475,7 @@ mm_key_verify(Key *key, u_char *sig, u_i
+ 		return (0);
+ 
+ 	buffer_init(&m);
++	buffer_put_int(&m, type);
+ 	buffer_put_string(&m, blob, len);
+ 	buffer_put_string(&m, sig, siglen);
+ 	buffer_put_string(&m, data, datalen);
+@@ -492,6 +493,18 @@ mm_key_verify(Key *key, u_char *sig, u_i
+ 	return (verified);
+ }
+ 
++int
++mm_hostbased_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
++{
++	return mm_key_verify(MM_HOSTKEY, key, sig, siglen, data, datalen);
++}
++
++int
++mm_user_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
++{
++	return mm_key_verify(MM_USERKEY, key, sig, siglen, data, datalen);
++}
++
+ void
+ mm_send_keystate(struct monitor *monitor)
+ {
+@@ -1005,10 +1018,11 @@ mm_audit_event(ssh_audit_event_t event)
+ 	buffer_free(&m);
+ }
+ 
+-void
++int
+ mm_audit_run_command(const char *command)
+ {
+ 	Buffer m;
++	int handle;
+ 
+ 	debug3("%s entering command %s", __func__, command);
+ 
+@@ -1016,6 +1030,26 @@ mm_audit_run_command(const char *command
+ 	buffer_put_cstring(&m, command);
+ 
+ 	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, &m);
++
++	handle = buffer_get_int(&m);
++	buffer_free(&m);
++
++	return (handle);
++}
++
++void
++mm_audit_end_command(int handle, const char *command)
++{
++	Buffer m;
++
++	debug3("%s entering command %s", __func__, command);
++
++	buffer_init(&m);
++	buffer_put_int(&m, handle);
++	buffer_put_cstring(&m, command);
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, &m);
+ 	buffer_free(&m);
+ }
+ #endif /* SSH_AUDIT_EVENTS */
+@@ -1151,3 +1185,72 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_cc
+ 
+ #endif /* GSSAPI */
+ 
++#ifdef SSH_AUDIT_EVENTS
++void
++mm_audit_unsupported_body(int what)
++{
++	Buffer m;
++
++	buffer_init(&m);
++	buffer_put_int(&m, what);
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED,
++				  &m);
++
++	buffer_free(&m);
++}
++
++void
++mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, char *fps, pid_t pid,
++		  uid_t uid)
++{
++	Buffer m;
++
++	buffer_init(&m);
++	buffer_put_int(&m, ctos);
++	buffer_put_cstring(&m, cipher);
++	buffer_put_cstring(&m, (mac ? mac : ""));
++	buffer_put_cstring(&m, compress);
++	buffer_put_cstring(&m, fps);
++	buffer_put_int64(&m, pid);
++	buffer_put_int64(&m, uid);
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX,
++				  &m);
++
++	buffer_free(&m);
++}
++
++void
++mm_audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
++{
++	Buffer m;
++
++	buffer_init(&m);
++	buffer_put_int(&m, ctos);
++	buffer_put_int64(&m, pid);
++	buffer_put_int64(&m, uid);
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE,
++				  &m);
++	buffer_free(&m);
++}
++
++void
++mm_audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid)
++{
++	Buffer m;
++
++	buffer_init(&m);
++	buffer_put_cstring(&m, fp);
++	buffer_put_int64(&m, pid);
++	buffer_put_int64(&m, uid);
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SERVER_KEY_FREE,
++				  &m);
++	buffer_free(&m);
++}
++#endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-6.8p1/monitor_wrap.h.audit openssh-6.8p1/monitor_wrap.h
+--- openssh-6.8p1/monitor_wrap.h.audit	2015-03-20 13:41:15.048883853 +0100
++++ openssh-6.8p1/monitor_wrap.h	2015-03-20 13:41:15.096883775 +0100
+@@ -52,7 +52,8 @@ int mm_key_allowed(enum mm_keytype, char
+ int mm_user_key_allowed(struct passwd *, Key *);
+ int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *);
+ int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *);
+-int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int);
++int mm_hostbased_key_verify(Key *, u_char *, u_int, u_char *, u_int);
++int mm_user_key_verify(Key *, u_char *, u_int, u_char *, u_int);
+ int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **);
+ int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *);
+ BIGNUM *mm_auth_rsa_generate_challenge(Key *);
+@@ -79,7 +80,12 @@ void mm_sshpam_free_ctx(void *);
+ #ifdef SSH_AUDIT_EVENTS
+ #include "audit.h"
+ void mm_audit_event(ssh_audit_event_t);
+-void mm_audit_run_command(const char *);
++int mm_audit_run_command(const char *);
++void mm_audit_end_command(int, const char *);
++void mm_audit_unsupported_body(int);
++void mm_audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t);
++void mm_audit_session_key_free_body(int, pid_t, uid_t);
++void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t);
+ #endif
+ 
+ struct Session;
+diff -up openssh-6.8p1/packet.c.audit openssh-6.8p1/packet.c
+--- openssh-6.8p1/packet.c.audit	2015-03-20 13:41:14.990883947 +0100
++++ openssh-6.8p1/packet.c	2015-03-20 13:41:15.097883774 +0100
+@@ -67,6 +67,7 @@
+ #include "key.h"	/* typedefs XXX */
+ 
+ #include "xmalloc.h"
++#include "audit.h"
+ #include "crc32.h"
+ #include "deattack.h"
+ #include "compat.h"
+@@ -448,6 +449,13 @@ ssh_packet_get_connection_out(struct ssh
+ 	return ssh->state->connection_out;
+ }
+ 
++static int
++packet_state_has_keys (const struct session_state *state)
++{
++	return state != NULL &&
++		(state->newkeys[MODE_IN] != NULL || state->newkeys[MODE_OUT] != NULL);
++}
++
+ /*
+  * Returns the IP-address of the remote host as a string.  The returned
+  * string must not be freed.
+@@ -478,13 +486,6 @@ ssh_packet_close(struct ssh *ssh)
+ 	if (!state->initialized)
+ 		return;
+ 	state->initialized = 0;
+-	if (state->connection_in == state->connection_out) {
+-		shutdown(state->connection_out, SHUT_RDWR);
+-		close(state->connection_out);
+-	} else {
+-		close(state->connection_in);
+-		close(state->connection_out);
+-	}
+ 	sshbuf_free(state->input);
+ 	sshbuf_free(state->output);
+ 	sshbuf_free(state->outgoing_packet);
+@@ -516,14 +517,24 @@ ssh_packet_close(struct ssh *ssh)
+ 				inflateEnd(stream);
+ 		}
+ 	}
+-	if ((r = cipher_cleanup(&state->send_context)) != 0)
+-		error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r));
+-	if ((r = cipher_cleanup(&state->receive_context)) != 0)
+-		error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r));
++	if (packet_state_has_keys(state)) {
++		if ((r = cipher_cleanup(&state->send_context)) != 0)
++			error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r));
++		if ((r = cipher_cleanup(&state->receive_context)) != 0)
++			error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r));
++		audit_session_key_free(2);
++	}
+ 	if (ssh->remote_ipaddr) {
+ 		free(ssh->remote_ipaddr);
+ 		ssh->remote_ipaddr = NULL;
+ 	}
++	if (state->connection_in == state->connection_out) {
++		shutdown(state->connection_out, SHUT_RDWR);
++		close(state->connection_out);
++	} else {
++		close(state->connection_in);
++		close(state->connection_out);
++	}
+ 	free(ssh->state);
+ 	ssh->state = NULL;
+ }
+@@ -941,6 +952,7 @@ ssh_set_newkeys(struct ssh *ssh, int mod
+ 	}
+ 	if (state->newkeys[mode] != NULL) {
+ 		debug("set_newkeys: rekeying");
++		audit_session_key_free(mode);
+ 		if ((r = cipher_cleanup(cc)) != 0)
+ 			return r;
+ 		enc  = &state->newkeys[mode]->enc;
+@@ -2263,6 +2275,75 @@ ssh_packet_get_output(struct ssh *ssh)
+ 	return (void *)ssh->state->output;
+ }
+ 
++static void
++newkeys_destroy_and_free(struct newkeys *newkeys)
++{
++	if (newkeys == NULL)
++		return;
++
++	free(newkeys->enc.name);
++
++	if (newkeys->mac.enabled) {
++		mac_clear(&newkeys->mac);
++		free(newkeys->mac.name);
++	}
++
++	free(newkeys->comp.name);
++
++	newkeys_destroy(newkeys);
++	free(newkeys);
++}
++
++static void
++packet_destroy_state(struct session_state *state)
++{
++	if (state == NULL)
++		return;
++
++	cipher_cleanup(&state->receive_context);
++	cipher_cleanup(&state->send_context);
++
++	buffer_free(state->input);
++	state->input = NULL;
++	buffer_free(state->output);
++	state->output = NULL;
++	buffer_free(state->outgoing_packet);
++	state->outgoing_packet = NULL;
++	buffer_free(state->incoming_packet);
++	state->incoming_packet = NULL;
++	if( state->compression_buffer ) {
++		buffer_free(state->compression_buffer);
++		state->compression_buffer = NULL;
++	}
++	newkeys_destroy_and_free(state->newkeys[MODE_IN]);
++	state->newkeys[MODE_IN] = NULL;
++	newkeys_destroy_and_free(state->newkeys[MODE_OUT]);
++	state->newkeys[MODE_OUT] = NULL;
++	mac_destroy(state->packet_discard_mac);
++//	TAILQ_HEAD(, packet) outgoing;
++//	memset(state, 0, sizeof(state));
++}
++
++void
++packet_destroy_all(int audit_it, int privsep)
++{
++	if (audit_it)
++		audit_it = (active_state != NULL && packet_state_has_keys(active_state->state))
++			|| (backup_state != NULL && packet_state_has_keys(backup_state->state));
++	if (active_state != NULL)
++		packet_destroy_state(active_state->state);
++	if (backup_state != NULL)
++		packet_destroy_state(backup_state->state);
++	if (audit_it) {
++#ifdef SSH_AUDIT_EVENTS
++		if (privsep)
++			audit_session_key_free(2);
++		else
++			audit_session_key_free_body(2, getpid(), getuid());
++#endif
++	}
++}
++
+ /* XXX TODO update roaming to new API (does not work anyway) */
+ /*
+  * Save the state for the real connection, and use a separate state when
+@@ -2272,18 +2373,12 @@ void
+ ssh_packet_backup_state(struct ssh *ssh,
+     struct ssh *backup_state)
+ {
+-	struct ssh *tmp;
+-
+ 	close(ssh->state->connection_in);
+ 	ssh->state->connection_in = -1;
+ 	close(ssh->state->connection_out);
+ 	ssh->state->connection_out = -1;
+-	if (backup_state)
+-		tmp = backup_state;
+-	else
+-		tmp = ssh_alloc_session_state();
+ 	backup_state = ssh;
+-	ssh = tmp;
++	ssh = ssh_alloc_session_state();
+ }
+ 
+ /* XXX FIXME FIXME FIXME */
+@@ -2302,9 +2397,7 @@ ssh_packet_restore_state(struct ssh *ssh
+ 	backup_state = ssh;
+ 	ssh = tmp;
+ 	ssh->state->connection_in = backup_state->state->connection_in;
+-	backup_state->state->connection_in = -1;
+ 	ssh->state->connection_out = backup_state->state->connection_out;
+-	backup_state->state->connection_out = -1;
+ 	len = sshbuf_len(backup_state->state->input);
+ 	if (len > 0) {
+ 		if ((r = sshbuf_putb(ssh->state->input,
+@@ -2313,6 +2406,11 @@ ssh_packet_restore_state(struct ssh *ssh
+ 		sshbuf_reset(backup_state->state->input);
+ 		add_recv_bytes(len);
+ 	}
++	backup_state->state->connection_in = -1;
++	backup_state->state->connection_out = -1;
++	packet_destroy_state(backup_state->state);
++	free(backup_state);
++	backup_state = NULL;
+ }
+ 
+ /* Reset after_authentication and reset compression in post-auth privsep */
+diff -up openssh-6.8p1/packet.h.audit openssh-6.8p1/packet.h
+--- openssh-6.8p1/packet.h.audit	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/packet.h	2015-03-20 13:41:15.097883774 +0100
+@@ -189,7 +189,7 @@ int	sshpkt_get_end(struct ssh *ssh);
+ const u_char	*sshpkt_ptr(struct ssh *, size_t *lenp);
+ 
+ /* OLD API */
+-extern struct ssh *active_state;
++extern struct ssh *active_state, *backup_state;
+ #include "opacket.h"
+ 
+ #if !defined(WITH_OPENSSL)
+@@ -203,4 +203,5 @@ extern struct ssh *active_state;
+ # undef EC_POINT
+ #endif
+ 
++void	 packet_destroy_all(int, int);
+ #endif				/* PACKET_H */
+diff -up openssh-6.8p1/session.c.audit openssh-6.8p1/session.c
+--- openssh-6.8p1/session.c.audit	2015-03-20 13:41:15.073883813 +0100
++++ openssh-6.8p1/session.c	2015-03-20 13:41:15.097883774 +0100
+@@ -139,7 +139,7 @@ extern int log_stderr;
+ extern int debug_flag;
+ extern u_int utmp_len;
+ extern int startup_pipe;
+-extern void destroy_sensitive_data(void);
++extern void destroy_sensitive_data(int);
+ extern Buffer loginmsg;
+ 
+ /* original command from peer. */
+@@ -731,6 +731,14 @@ do_exec_pty(Session *s, const char *comm
+ 	/* Parent.  Close the slave side of the pseudo tty. */
+ 	close(ttyfd);
+ 
++#ifndef HAVE_OSF_SIA
++	/* do_login in the child did not affect state in this process,
++	   compensate.  From an architectural standpoint, this is extremely
++	   ugly. */
++	if (!(options.use_login && command == NULL))
++		audit_count_session_open();
++#endif
++
+ 	/* Enter interactive session. */
+ 	s->ptymaster = ptymaster;
+ 	packet_set_interactive(1, 
+@@ -853,15 +861,19 @@ do_exec(Session *s, const char *command)
+ 	    get_remote_port());
+ 
+ #ifdef SSH_AUDIT_EVENTS
++	if (s->command != NULL || s->command_handle != -1)
++		fatal("do_exec: command already set");
+ 	if (command != NULL)
+-		PRIVSEP(audit_run_command(command));
++		s->command = xstrdup(command);
+ 	else if (s->ttyfd == -1) {
+ 		char *shell = s->pw->pw_shell;
+ 
+ 		if (shell[0] == '\0')	/* empty shell means /bin/sh */
+ 			shell =_PATH_BSHELL;
+-		PRIVSEP(audit_run_command(shell));
++		s->command = xstrdup(shell);
+ 	}
++	if (s->command != NULL && s->ptyfd == -1)
++		s->command_handle = PRIVSEP(audit_run_command(s->command));
+ #endif
+ 	if (s->ttyfd != -1)
+ 		ret = do_exec_pty(s, command);
+@@ -1704,7 +1716,10 @@ do_child(Session *s, const char *command
+ 	int r = 0;
+ 
+ 	/* remove hostkey from the child's memory */
+-	destroy_sensitive_data();
++	destroy_sensitive_data(1);
++	/* Don't audit this - both us and the parent would be talking to the
++	   monitor over a single socket, with no synchronization. */
++	packet_destroy_all(0, 1);
+ 
+ 	/* Force a password change */
+ 	if (s->authctxt->force_pwchange) {
+@@ -1934,6 +1949,7 @@ session_unused(int id)
+ 	sessions[id].ttyfd = -1;
+ 	sessions[id].ptymaster = -1;
+ 	sessions[id].x11_chanids = NULL;
++	sessions[id].command_handle = -1;
+ 	sessions[id].next_unused = sessions_first_unused;
+ 	sessions_first_unused = id;
+ }
+@@ -2016,6 +2032,19 @@ session_open(Authctxt *authctxt, int cha
+ }
+ 
+ Session *
++session_by_id(int id)
++{
++	if (id >= 0 && id < sessions_nalloc) {
++		Session *s = &sessions[id];
++		if (s->used)
++			return s;
++	}
++	debug("session_by_id: unknown id %d", id);
++	session_dump();
++	return NULL;
++}
++
++Session *
+ session_by_tty(char *tty)
+ {
+ 	int i;
+@@ -2532,6 +2561,32 @@ session_exit_message(Session *s, int sta
+ 		chan_write_failed(c);
+ }
+ 
++#ifdef SSH_AUDIT_EVENTS
++void
++session_end_command2(Session *s)
++{
++	if (s->command != NULL) {
++		if (s->command_handle != -1)
++			audit_end_command(s->command_handle, s->command);
++		free(s->command);
++		s->command = NULL;
++		s->command_handle = -1;
++	}
++}
++
++static void
++session_end_command(Session *s)
++{
++	if (s->command != NULL) {
++		if (s->command_handle != -1)
++			PRIVSEP(audit_end_command(s->command_handle, s->command));
++		free(s->command);
++		s->command = NULL;
++		s->command_handle = -1;
++	}
++}
++#endif
++
+ void
+ session_close(Session *s)
+ {
+@@ -2540,6 +2593,10 @@ session_close(Session *s)
+ 	debug("session_close: session %d pid %ld", s->self, (long)s->pid);
+ 	if (s->ttyfd != -1)
+ 		session_pty_cleanup(s);
++#ifdef SSH_AUDIT_EVENTS
++	if (s->command)
++		session_end_command(s);
++#endif
+ 	free(s->term);
+ 	free(s->display);
+ 	free(s->x11_chanids);
+@@ -2754,6 +2811,15 @@ do_authenticated2(Authctxt *authctxt)
+ 	server_loop2(authctxt);
+ }
+ 
++static void
++do_cleanup_one_session(Session *s)
++{
++	session_pty_cleanup2(s);
++#ifdef SSH_AUDIT_EVENTS
++	session_end_command2(s);
++#endif
++}
++
+ void
+ do_cleanup(Authctxt *authctxt)
+ {
+@@ -2802,5 +2868,5 @@ do_cleanup(Authctxt *authctxt)
+ 	 * or if running in monitor.
+ 	 */
+ 	if (!use_privsep || mm_is_monitor())
+-		session_destroy_all(session_pty_cleanup2);
++		session_destroy_all(do_cleanup_one_session);
+ }
+diff -up openssh-6.8p1/session.h.audit openssh-6.8p1/session.h
+--- openssh-6.8p1/session.h.audit	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/session.h	2015-03-20 13:41:15.097883774 +0100
+@@ -61,6 +61,12 @@ struct Session {
+ 		char	*name;
+ 		char	*val;
+ 	} *env;
++
++	/* exec */
++#ifdef SSH_AUDIT_EVENTS
++	int	command_handle;
++	char	*command;
++#endif
+ };
+ 
+ void	 do_authenticated(Authctxt *);
+@@ -73,8 +79,10 @@ void	 session_close_by_pid(pid_t, int);
+ void	 session_close_by_channel(int, void *);
+ void	 session_destroy_all(void (*)(Session *));
+ void	 session_pty_cleanup2(Session *);
++void	 session_end_command2(Session *);
+ 
+ Session	*session_new(void);
++Session *session_by_id(int);
+ Session	*session_by_tty(char *);
+ void	 session_close(Session *);
+ void	 do_setusercontext(struct passwd *);
+diff -up openssh-6.8p1/sshd.c.audit openssh-6.8p1/sshd.c
+--- openssh-6.8p1/sshd.c.audit	2015-03-20 13:41:15.083883796 +0100
++++ openssh-6.8p1/sshd.c	2015-03-20 13:41:15.110883753 +0100
+@@ -121,6 +124,7 @@
+ #endif
+ #include "monitor_wrap.h"
+ #include "roaming.h"
++#include "audit.h"
+ #include "ssh-sandbox.h"
+ #include "version.h"
+ #include "ssherr.h"
+@@ -260,7 +264,7 @@ Buffer loginmsg;
+ struct passwd *privsep_pw = NULL;
+ 
+ /* Prototypes for various functions defined later in this file. */
+-void destroy_sensitive_data(void);
++void destroy_sensitive_data(int);
+ void demote_sensitive_data(void);
+ 
+ #ifdef WITH_SSH1
+@@ -281,6 +285,15 @@ close_listen_socks(void)
+ 	num_listen_socks = -1;
+ }
+ 
++/*
++ * Is this process listening for clients (i.e. not specific to any specific
++ * client connection?)
++ */
++int listening_for_clients(void)
++{
++	return num_listen_socks > 0;
++}
++
+ static void
+ close_startup_pipes(void)
+ {
+@@ -560,22 +573,45 @@ sshd_exchange_identification(int sock_in
+ 	}
+ }
+ 
+-/* Destroy the host and server keys.  They will no longer be needed. */
++/*
++ * Destroy the host and server keys.  They will no longer be needed.  Careful,
++ * this can be called from cleanup_exit() - i.e. from just about anywhere.
++ */
+ void
+-destroy_sensitive_data(void)
++destroy_sensitive_data(int privsep)
+ {
+ 	int i;
++	pid_t pid;
++	uid_t uid;
+ 
+ 	if (sensitive_data.server_key) {
+ 		key_free(sensitive_data.server_key);
+ 		sensitive_data.server_key = NULL;
+ 	}
++	pid = getpid();
++	uid = getuid();
+ 	for (i = 0; i < options.num_host_key_files; i++) {
+ 		if (sensitive_data.host_keys[i]) {
++			char *fp;
++
++			if (key_is_private(sensitive_data.host_keys[i]))
++				fp = sshkey_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX);
++			else
++				fp = NULL;
+ 			key_free(sensitive_data.host_keys[i]);
+ 			sensitive_data.host_keys[i] = NULL;
++			if (fp != NULL) {
++				if (privsep)
++					PRIVSEP(audit_destroy_sensitive_data(fp,
++						pid, uid));
++				else
++					audit_destroy_sensitive_data(fp,
++						pid, uid);
++				free(fp);
++			}
+ 		}
+-		if (sensitive_data.host_certificates[i]) {
++		if (sensitive_data.host_certificates
++		    && sensitive_data.host_certificates[i]) {
+ 			key_free(sensitive_data.host_certificates[i]);
+ 			sensitive_data.host_certificates[i] = NULL;
+ 		}
+@@ -589,6 +625,8 @@ void
+ demote_sensitive_data(void)
+ {
+ 	Key *tmp;
++	pid_t pid;
++	uid_t uid;
+ 	int i;
+ 
+ 	if (sensitive_data.server_key) {
+@@ -597,13 +635,25 @@ demote_sensitive_data(void)
+ 		sensitive_data.server_key = tmp;
+ 	}
+ 
++	pid = getpid();
++	uid = getuid();
+ 	for (i = 0; i < options.num_host_key_files; i++) {
+ 		if (sensitive_data.host_keys[i]) {
++			char *fp;
++
++			if (key_is_private(sensitive_data.host_keys[i]))
++				fp = sshkey_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX);
++			else
++				fp = NULL;
+ 			tmp = key_demote(sensitive_data.host_keys[i]);
+ 			key_free(sensitive_data.host_keys[i]);
+ 			sensitive_data.host_keys[i] = tmp;
+ 			if (tmp->type == KEY_RSA1)
+ 				sensitive_data.ssh1_host_key = tmp;
++			if (fp != NULL) {
++				audit_destroy_sensitive_data(fp, pid, uid);
++				free(fp);
++			}
+ 		}
+ 		/* Certs do not need demotion */
+ 	}
+@@ -675,7 +725,7 @@ privsep_preauth(Authctxt *authctxt)
+ 
+ 	if (use_privsep == PRIVSEP_ON)
+ 		box = ssh_sandbox_init(pmonitor);
+-	pid = fork();
++	pmonitor->m_pid = pid = fork();
+ 	if (pid == -1) {
+ 		fatal("fork of unprivileged child failed");
+ 	} else if (pid != 0) {
+@@ -759,6 +811,12 @@ privsep_postauth(Authctxt *authctxt)
+ 	else if (pmonitor->m_pid != 0) {
+ 		verbose("User child is on pid %ld", (long)pmonitor->m_pid);
+ 		buffer_clear(&loginmsg);
++		if (*pmonitor->m_pkex != NULL ){
++			newkeys_destroy((*pmonitor->m_pkex)->newkeys[MODE_OUT]);
++			newkeys_destroy((*pmonitor->m_pkex)->newkeys[MODE_IN]);
++			audit_session_key_free_body(2, getpid(), getuid());
++			packet_destroy_all(0, 0);
++		}
+ 		monitor_child_postauth(pmonitor);
+ 
+ 		/* NEVERREACHED */
+@@ -1286,6 +1341,7 @@ server_accept_loop(int *sock_in, int *so
+ 		if (received_sigterm) {
+ 			logit("Received signal %d; terminating.",
+ 			    (int) received_sigterm);
++			destroy_sensitive_data(0);
+ 			close_listen_socks();
+ 			if (options.pid_file != NULL)
+ 				unlink(options.pid_file);
+@@ -2242,6 +2321,7 @@ main(int ac, char **av)
+ 	 */
+ 	if (use_privsep) {
+ 		mm_send_keystate(pmonitor);
++		packet_destroy_all(1, 1);
+ 		exit(0);
+ 	}
+ 
+@@ -2287,7 +2367,7 @@ main(int ac, char **av)
+ 		privsep_postauth(authctxt);
+ 		/* the monitor process [priv] will not return */
+ 		if (!compat20)
+-			destroy_sensitive_data();
++			destroy_sensitive_data(0);
+ 	}
+ 
+ 	packet_set_timeout(options.client_alive_interval,
+@@ -2301,6 +2381,9 @@ main(int ac, char **av)
+ 	do_authenticated(authctxt);
+ 
+ 	/* The connection has been terminated. */
++	packet_destroy_all(1, 1);
++	destroy_sensitive_data(1);
++
+ 	packet_get_bytes(&ibytes, &obytes);
+ 	verbose("Transferred: sent %llu, received %llu bytes",
+ 	    (unsigned long long)obytes, (unsigned long long)ibytes);
+@@ -2461,6 +2544,10 @@ do_ssh1_kex(void)
+ 		if (cookie[i] != packet_get_char())
+ 			packet_disconnect("IP Spoofing check bytes do not match.");
+ 
++#ifdef SSH_AUDIT_EVENTS
++	audit_kex(2, cipher_name(cipher_type), "crc", "none", "none");
++#endif
++
+ 	debug("Encryption type: %.200s", cipher_name(cipher_type));
+ 
+ 	/* Get the encrypted integer. */
+@@ -2520,7 +2607,7 @@ do_ssh1_kex(void)
+ 	}
+ 
+ 	/* Destroy the private and public keys. No longer. */
+-	destroy_sensitive_data();
++	destroy_sensitive_data(1);
+ 
+ 	if (use_privsep)
+ 		mm_ssh1_session_id(session_id);
+@@ -2703,6 +2802,16 @@ do_ssh2_kex(void)
+ void
+ cleanup_exit(int i)
+ {
++	static int in_cleanup = 0;
++	int is_privsep_child;
++
++	/* cleanup_exit can be called at the very least from the privsep
++	   wrappers used for auditing.  Make sure we don't recurse
++	   indefinitely. */
++	if (in_cleanup)
++		_exit(i);
++	in_cleanup = 1;
++
+ 	if (the_authctxt) {
+ 		do_cleanup(the_authctxt);
+ 		if (use_privsep && privsep_is_preauth &&
+@@ -2714,9 +2823,14 @@ cleanup_exit(int i)
+ 				    pmonitor->m_pid, strerror(errno));
+ 		}
+ 	}
++	is_privsep_child = use_privsep && pmonitor != NULL && pmonitor->m_pid == 0;
++	if (sensitive_data.host_keys != NULL)
++		destroy_sensitive_data(is_privsep_child);
++	packet_destroy_all(1, is_privsep_child);
+ #ifdef SSH_AUDIT_EVENTS
+ 	/* done after do_cleanup so it can cancel the PAM auth 'thread' */
+-	if (!use_privsep || mm_is_monitor())
++	if ((the_authctxt == NULL || !the_authctxt->authenticated) &&
++	    (!use_privsep || mm_is_monitor()))
+ 		audit_event(SSH_CONNECTION_ABANDON);
+ #endif
+ 	_exit(i);
+diff -up openssh-6.8p1/sshkey.c.audit openssh-6.8p1/sshkey.c
+--- openssh-6.8p1/sshkey.c.audit	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/sshkey.c	2015-03-20 13:41:15.111883751 +0100
+@@ -317,6 +319,33 @@ sshkey_type_is_valid_ca(int type)
+ }
+ 
+ int
++sshkey_is_private(const struct sshkey *k)
++{
++      switch (k->type) {
++      case KEY_RSA_CERT_V00:
++      case KEY_RSA_CERT:
++      case KEY_RSA1:
++      case KEY_RSA:
++              return k->rsa->d != NULL;
++      case KEY_DSA_CERT_V00:
++      case KEY_DSA_CERT:
++      case KEY_DSA:
++              return k->dsa->priv_key != NULL;
++#ifdef OPENSSL_HAS_ECC
++      case KEY_ECDSA_CERT:
++      case KEY_ECDSA:
++              return EC_KEY_get0_private_key(k->ecdsa) != NULL;
++#endif
++      case KEY_ED25519_CERT:
++      case KEY_ED25519:
++              return (k->ed25519_pk != NULL);
++      default:
++              /* fatal("key_is_private: bad key type %d", k->type); */
++              return 0;
++      }
++}
++
++int
+ sshkey_is_cert(const struct sshkey *k)
+ {
+ 	if (k == NULL)
+diff -up openssh-6.8p1/sshkey.h.audit openssh-6.8p1/sshkey.h
+--- openssh-6.8p1/sshkey.h.audit	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/sshkey.h	2015-03-20 13:41:15.098883772 +0100
+@@ -134,6 +134,7 @@ u_int		 sshkey_size(const struct sshkey
+ int		 sshkey_generate(int type, u_int bits, struct sshkey **keyp);
+ int		 sshkey_from_private(const struct sshkey *, struct sshkey **);
+ int	 sshkey_type_from_name(const char *);
++int	 sshkey_is_private(const struct sshkey *);
+ int	 sshkey_is_cert(const struct sshkey *);
+ int	 sshkey_type_is_cert(int);
+ int	 sshkey_type_plain(int);
+diff -up openssh-6.8p1/sandbox-seccomp-filter.c.audit openssh-6.8p1/sandbox-seccomp-filter.c
+--- openssh-6.8p1/sandbox-seccomp-filter.c.audit	2015-03-20 13:41:15.088883788 +0100
++++ openssh-6.8p1/sandbox-seccomp-filter.c	2015-03-20 13:41:15.097883774 +0100
+@@ -110,6 +110,12 @@ static const struct sock_filter preauth_
+ #ifdef __NR_time /* not defined on EABI ARM */
+ 	SC_ALLOW(time),
+ #endif
++#ifdef SSH_AUDIT_EVENTS
++	SC_ALLOW(getuid),
++#ifdef __NR_getuid32 /* not defined on x86_64 */
++	SC_ALLOW(getuid32),
++#endif
++#endif
+ 	SC_ALLOW(read),
+ 	SC_ALLOW(write),
+ 	SC_ALLOW(close),
diff --git a/openssh-6.7p1-coverity.patch b/openssh-6.7p1-coverity.patch
new file mode 100644
index 0000000..fe3b349
--- /dev/null
+++ b/openssh-6.7p1-coverity.patch
@@ -0,0 +1,471 @@
+diff -up openssh-6.8p1/auth-pam.c.coverity openssh-6.8p1/auth-pam.c
+--- openssh-6.8p1/auth-pam.c.coverity	2015-03-18 17:21:51.792265051 +0100
++++ openssh-6.8p1/auth-pam.c	2015-03-18 17:21:51.895264835 +0100
+@@ -216,7 +216,12 @@ pthread_join(sp_pthread_t thread, void *
+ 	if (sshpam_thread_status != -1)
+ 		return (sshpam_thread_status);
+ 	signal(SIGCHLD, sshpam_oldsig);
+-	waitpid(thread, &status, 0);
++	while (waitpid(thread, &status, 0) < 0) {
++		if (errno == EINTR)
++			continue;
++		fatal("%s: waitpid: %s", __func__,
++				strerror(errno));
++	}
+ 	return (status);
+ }
+ #endif
+diff -up openssh-6.8p1/channels.c.coverity openssh-6.8p1/channels.c
+--- openssh-6.8p1/channels.c.coverity	2015-03-18 17:21:51.815265002 +0100
++++ openssh-6.8p1/channels.c	2015-03-18 17:21:51.896264833 +0100
+@@ -243,11 +243,11 @@ channel_register_fds(Channel *c, int rfd
+ 	channel_max_fd = MAX(channel_max_fd, wfd);
+ 	channel_max_fd = MAX(channel_max_fd, efd);
+ 
+-	if (rfd != -1)
++	if (rfd >= 0)
+ 		fcntl(rfd, F_SETFD, FD_CLOEXEC);
+-	if (wfd != -1 && wfd != rfd)
++	if (wfd >= 0 && wfd != rfd)
+ 		fcntl(wfd, F_SETFD, FD_CLOEXEC);
+-	if (efd != -1 && efd != rfd && efd != wfd)
++	if (efd >= 0 && efd != rfd && efd != wfd)
+ 		fcntl(efd, F_SETFD, FD_CLOEXEC);
+ 
+ 	c->rfd = rfd;
+@@ -265,11 +265,11 @@ channel_register_fds(Channel *c, int rfd
+ 
+ 	/* enable nonblocking mode */
+ 	if (nonblock) {
+-		if (rfd != -1)
++		if (rfd >= 0)
+ 			set_nonblock(rfd);
+-		if (wfd != -1)
++		if (wfd >= 0)
+ 			set_nonblock(wfd);
+-		if (efd != -1)
++		if (efd >= 0)
+ 			set_nonblock(efd);
+ 	}
+ }
+@@ -3972,13 +3972,13 @@ connect_local_xsocket_path(const char *p
+ 	int sock;
+ 	struct sockaddr_un addr;
+ 
++	if (len <= 0)
++		return -1;
+ 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ 	if (sock < 0)
+ 		error("socket: %.100s", strerror(errno));
+ 	memset(&addr, 0, sizeof(addr));
+ 	addr.sun_family = AF_UNIX;
+-	if (len <= 0)
+-		return -1;
+ 	if (len > sizeof addr.sun_path)
+ 		len = sizeof addr.sun_path;
+ 	memcpy(addr.sun_path, pathname, len);
+diff -up openssh-6.8p1/entropy.c.coverity openssh-6.8p1/entropy.c
+--- openssh-6.8p1/entropy.c.coverity	2015-03-18 17:21:51.891264843 +0100
++++ openssh-6.8p1/entropy.c	2015-03-18 17:21:51.897264831 +0100
+@@ -46,6 +46,7 @@
+ #include <openssl/err.h>
+ 
+ #include "openbsd-compat/openssl-compat.h"
++#include "openbsd-compat/port-linux.h"
+ 
+ #include "ssh.h"
+ #include "misc.h"
+diff -up openssh-6.8p1/monitor.c.coverity openssh-6.8p1/monitor.c
+--- openssh-6.8p1/monitor.c.coverity	2015-03-18 17:21:51.887264852 +0100
++++ openssh-6.8p1/monitor.c	2015-03-18 17:21:51.897264831 +0100
+@@ -444,7 +444,7 @@ monitor_child_preauth(Authctxt *_authctx
+ 	mm_get_keystate(pmonitor);
+ 
+ 	/* Drain any buffered messages from the child */
+-	while (pmonitor->m_log_recvfd != -1 && monitor_read_log(pmonitor) == 0)
++	while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0)
+ 		;
+ 
+ 	close(pmonitor->m_sendfd);
+@@ -1303,6 +1303,10 @@ mm_answer_keyallowed(int sock, Buffer *m
+ 			break;
+ 		}
+ 	}
++
++	debug3("%s: key %p is %s",
++	    __func__, key, allowed ? "allowed" : "not allowed");
++
+ 	if (key != NULL)
+ 		key_free(key);
+ 
+@@ -1324,9 +1328,6 @@ mm_answer_keyallowed(int sock, Buffer *m
+ 		free(chost);
+ 	}
+ 
+-	debug3("%s: key %p is %s",
+-	    __func__, key, allowed ? "allowed" : "not allowed");
+-
+ 	buffer_clear(m);
+ 	buffer_put_int(m, allowed);
+ 	buffer_put_int(m, forced_command != NULL);
+diff -up openssh-6.8p1/monitor_wrap.c.coverity openssh-6.8p1/monitor_wrap.c
+--- openssh-6.8p1/monitor_wrap.c.coverity	2015-03-18 17:21:51.888264849 +0100
++++ openssh-6.8p1/monitor_wrap.c	2015-03-18 17:21:51.897264831 +0100
+@@ -533,10 +533,10 @@ mm_pty_allocate(int *ptyfd, int *ttyfd,
+ 	if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 ||
+ 	    (tmp2 = dup(pmonitor->m_recvfd)) == -1) {
+ 		error("%s: cannot allocate fds for pty", __func__);
+-		if (tmp1 > 0)
++		if (tmp1 >= 0)
+ 			close(tmp1);
+-		if (tmp2 > 0)
+-			close(tmp2);
++		/*DEAD CODE if (tmp2 >= 0)
++			close(tmp2);*/
+ 		return 0;
+ 	}
+ 	close(tmp1);
+diff -up openssh-6.8p1/openbsd-compat/bindresvport.c.coverity openssh-6.8p1/openbsd-compat/bindresvport.c
+--- openssh-6.8p1/openbsd-compat/bindresvport.c.coverity	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/openbsd-compat/bindresvport.c	2015-03-18 17:21:51.897264831 +0100
+@@ -58,7 +58,7 @@ bindresvport_sa(int sd, struct sockaddr
+ 	struct sockaddr_in6 *in6;
+ 	u_int16_t *portp;
+ 	u_int16_t port;
+-	socklen_t salen;
++	socklen_t salen = sizeof(struct sockaddr_storage);
+ 	int i;
+ 
+ 	if (sa == NULL) {
+diff -up openssh-6.8p1/openbsd-compat/port-linux.h.coverity openssh-6.8p1/openbsd-compat/port-linux.h
+--- openssh-6.8p1/openbsd-compat/port-linux.h.coverity	2015-03-18 17:21:51.861264906 +0100
++++ openssh-6.8p1/openbsd-compat/port-linux.h	2015-03-18 17:21:51.897264831 +0100
+@@ -37,4 +37,6 @@ void oom_adjust_restore(void);
+ void oom_adjust_setup(void);
+ #endif
+ 
++void linux_seed(void);
++
+ #endif /* ! _PORT_LINUX_H */
+diff -up openssh-6.8p1/scp.c.coverity openssh-6.8p1/scp.c
+--- openssh-6.8p1/scp.c.coverity	2015-03-18 17:21:51.868264891 +0100
++++ openssh-6.8p1/scp.c	2015-03-18 17:21:58.281251460 +0100
+@@ -156,7 +156,7 @@ killchild(int signo)
+ {
+ 	if (do_cmd_pid > 1) {
+ 		kill(do_cmd_pid, signo ? signo : SIGTERM);
+-		waitpid(do_cmd_pid, NULL, 0);
++		(void) waitpid(do_cmd_pid, NULL, 0);
+ 	}
+ 
+ 	if (signo)
+diff -up openssh-6.8p1/servconf.c.coverity openssh-6.8p1/servconf.c
+--- openssh-6.8p1/servconf.c.coverity	2015-03-18 17:21:51.893264839 +0100
++++ openssh-6.8p1/servconf.c	2015-03-18 17:21:58.281251460 +0100
+@@ -1475,7 +1475,7 @@ process_server_config_line(ServerOptions
+ 			fatal("%s line %d: Missing subsystem name.",
+ 			    filename, linenum);
+ 		if (!*activep) {
+-			arg = strdelim(&cp);
++			/*arg =*/ (void) strdelim(&cp);
+ 			break;
+ 		}
+ 		for (i = 0; i < options->num_subsystems; i++)
+@@ -1566,8 +1566,9 @@ process_server_config_line(ServerOptions
+ 		if (*activep && *charptr == NULL) {
+ 			*charptr = tilde_expand_filename(arg, getuid());
+ 			/* increase optional counter */
+-			if (intptr != NULL)
+-				*intptr = *intptr + 1;
++			/* DEAD CODE intptr is still NULL ;)
++  			 if (intptr != NULL)
++				*intptr = *intptr + 1; */
+ 		}
+ 		break;
+ 
+diff -up openssh-6.8p1/serverloop.c.coverity openssh-6.8p1/serverloop.c
+--- openssh-6.8p1/serverloop.c.coverity	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/serverloop.c	2015-03-18 17:28:45.616436080 +0100
+@@ -147,13 +147,13 @@ notify_setup(void)
+ static void
+ notify_parent(void)
+ {
+-	if (notify_pipe[1] != -1)
++	if (notify_pipe[1] >= 0)
+ 		(void)write(notify_pipe[1], "", 1);
+ }
+ static void
+ notify_prepare(fd_set *readset)
+ {
+-	if (notify_pipe[0] != -1)
++	if (notify_pipe[0] >= 0)
+ 		FD_SET(notify_pipe[0], readset);
+ }
+ static void
+@@ -161,8 +161,8 @@ notify_done(fd_set *readset)
+ {
+ 	char c;
+ 
+-	if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset))
+-		while (read(notify_pipe[0], &c, 1) != -1)
++	if (notify_pipe[0] >= 0 && FD_ISSET(notify_pipe[0], readset))
++		while (read(notify_pipe[0], &c, 1) >= 0)
+ 			debug2("notify_done: reading");
+ }
+ 
+@@ -337,7 +337,7 @@ wait_until_can_do_something(fd_set **rea
+ 		 * If we have buffered data, try to write some of that data
+ 		 * to the program.
+ 		 */
+-		if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
++		if (fdin >= 0 && buffer_len(&stdin_buffer) > 0)
+ 			FD_SET(fdin, *writesetp);
+ 	}
+ 	notify_prepare(*readsetp);
+@@ -477,7 +477,7 @@ process_output(fd_set *writeset)
+ 	int len;
+ 
+ 	/* Write buffered data to program stdin. */
+-	if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) {
++	if (!compat20 && fdin >= 0 && FD_ISSET(fdin, writeset)) {
+ 		data = buffer_ptr(&stdin_buffer);
+ 		dlen = buffer_len(&stdin_buffer);
+ 		len = write(fdin, data, dlen);
+@@ -590,7 +590,7 @@ server_loop(pid_t pid, int fdin_arg, int
+ 	set_nonblock(fdin);
+ 	set_nonblock(fdout);
+ 	/* we don't have stderr for interactive terminal sessions, see below */
+-	if (fderr != -1)
++	if (fderr >= 0)
+ 		set_nonblock(fderr);
+ 
+ 	if (!(datafellows & SSH_BUG_IGNOREMSG) && isatty(fdin))
+@@ -614,7 +614,7 @@ server_loop(pid_t pid, int fdin_arg, int
+ 	max_fd = MAX(connection_in, connection_out);
+ 	max_fd = MAX(max_fd, fdin);
+ 	max_fd = MAX(max_fd, fdout);
+-	if (fderr != -1)
++	if (fderr >= 0)
+ 		max_fd = MAX(max_fd, fderr);
+ #endif
+ 
+@@ -644,7 +644,7 @@ server_loop(pid_t pid, int fdin_arg, int
+ 		 * If we have received eof, and there is no more pending
+ 		 * input data, cause a real eof by closing fdin.
+ 		 */
+-		if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) {
++		if (stdin_eof && fdin >= 0 && buffer_len(&stdin_buffer) == 0) {
+ 			if (fdin != fdout)
+ 				close(fdin);
+ 			else
+@@ -740,15 +740,15 @@ server_loop(pid_t pid, int fdin_arg, int
+ 	buffer_free(&stderr_buffer);
+ 
+ 	/* Close the file descriptors. */
+-	if (fdout != -1)
++	if (fdout >= 0)
+ 		close(fdout);
+ 	fdout = -1;
+ 	fdout_eof = 1;
+-	if (fderr != -1)
++	if (fderr >= 0)
+ 		close(fderr);
+ 	fderr = -1;
+ 	fderr_eof = 1;
+-	if (fdin != -1)
++	if (fdin >= 0)
+ 		close(fdin);
+ 	fdin = -1;
+ 
+@@ -950,7 +950,7 @@ server_input_window_size(int type, u_int
+ 
+ 	debug("Window change received.");
+ 	packet_check_eom();
+-	if (fdin != -1)
++	if (fdin >= 0)
+ 		pty_change_window_size(fdin, row, col, xpixel, ypixel);
+ 	return 0;
+ }
+@@ -1043,7 +1043,7 @@ server_request_tun(void)
+ 	}
+ 
+ 	tun = packet_get_int();
+-	if (forced_tun_device != -1) {
++	if (forced_tun_device >= 0) {
+ 		if (tun != SSH_TUNID_ANY && forced_tun_device != tun)
+ 			goto done;
+ 		tun = forced_tun_device;
+diff -up openssh-6.8p1/sftp.c.coverity openssh-6.8p1/sftp.c
+--- openssh-6.8p1/sftp.c.coverity	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/sftp.c	2015-03-18 17:21:58.283251456 +0100
+@@ -223,7 +223,7 @@ killchild(int signo)
+ {
+ 	if (sshpid > 1) {
+ 		kill(sshpid, SIGTERM);
+-		waitpid(sshpid, NULL, 0);
++		(void) waitpid(sshpid, NULL, 0);
+ 	}
+ 
+ 	_exit(1);
+@@ -335,7 +335,7 @@ local_do_ls(const char *args)
+ 
+ /* Strip one path (usually the pwd) from the start of another */
+ static char *
+-path_strip(char *path, char *strip)
++path_strip(const char *path, const char *strip)
+ {
+ 	size_t len;
+ 
+@@ -353,7 +353,7 @@ path_strip(char *path, char *strip)
+ }
+ 
+ static char *
+-make_absolute(char *p, char *pwd)
++make_absolute(char *p, const char *pwd)
+ {
+ 	char *abs_str;
+ 
+@@ -551,7 +551,7 @@ parse_no_flags(const char *cmd, char **a
+ }
+ 
+ static int
+-is_dir(char *path)
++is_dir(const char *path)
+ {
+ 	struct stat sb;
+ 
+@@ -563,7 +563,7 @@ is_dir(char *path)
+ }
+ 
+ static int
+-remote_is_dir(struct sftp_conn *conn, char *path)
++remote_is_dir(struct sftp_conn *conn, const char *path)
+ {
+ 	Attrib *a;
+ 
+@@ -577,7 +577,7 @@ remote_is_dir(struct sftp_conn *conn, ch
+ 
+ /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
+ static int
+-pathname_is_dir(char *pathname)
++pathname_is_dir(const char *pathname)
+ {
+ 	size_t l = strlen(pathname);
+ 
+@@ -585,7 +585,7 @@ pathname_is_dir(char *pathname)
+ }
+ 
+ static int
+-process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd,
++process_get(struct sftp_conn *conn, const char *src, const char *dst, const char *pwd,
+     int pflag, int rflag, int resume, int fflag)
+ {
+ 	char *abs_src = NULL;
+@@ -669,7 +669,7 @@ out:
+ }
+ 
+ static int
+-process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd,
++process_put(struct sftp_conn *conn, const char *src, const char *dst, const char *pwd,
+     int pflag, int rflag, int resume, int fflag)
+ {
+ 	char *tmp_dst = NULL;
+@@ -779,7 +779,7 @@ sdirent_comp(const void *aa, const void
+ 
+ /* sftp ls.1 replacement for directories */
+ static int
+-do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)
++do_ls_dir(struct sftp_conn *conn, const char *path, const char *strip_path, int lflag)
+ {
+ 	int n;
+ 	u_int c = 1, colspace = 0, columns = 1;
+@@ -864,7 +864,7 @@ do_ls_dir(struct sftp_conn *conn, char *
+ 
+ /* sftp ls.1 replacement which handles path globs */
+ static int
+-do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
++do_globbed_ls(struct sftp_conn *conn, const char *path, const char *strip_path,
+     int lflag)
+ {
+ 	char *fname, *lname;
+@@ -949,7 +949,7 @@ do_globbed_ls(struct sftp_conn *conn, ch
+ }
+ 
+ static int
+-do_df(struct sftp_conn *conn, char *path, int hflag, int iflag)
++do_df(struct sftp_conn *conn, const char *path, int hflag, int iflag)
+ {
+ 	struct sftp_statvfs st;
+ 	char s_used[FMT_SCALED_STRSIZE];
+diff -up openssh-6.8p1/ssh-agent.c.coverity openssh-6.8p1/ssh-agent.c
+--- openssh-6.8p1/ssh-agent.c.coverity	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/ssh-agent.c	2015-03-18 17:21:58.284251454 +0100
+@@ -1166,8 +1166,8 @@ main(int ac, char **av)
+ 	sanitise_stdfd();
+ 
+ 	/* drop */
+-	setegid(getgid());
+-	setgid(getgid());
++	(void) setegid(getgid());
++	(void) setgid(getgid());
+ 
+ #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
+ 	/* Disable ptrace on Linux without sgid bit */
+diff -up openssh-6.8p1/sshd.c.coverity openssh-6.8p1/sshd.c
+--- openssh-6.8p1/sshd.c.coverity	2015-03-18 17:21:51.893264839 +0100
++++ openssh-6.8p1/sshd.c	2015-03-18 17:21:58.284251454 +0100
+@@ -778,8 +778,10 @@ privsep_preauth(Authctxt *authctxt)
+ 		if (getuid() == 0 || geteuid() == 0)
+ 			privsep_preauth_child();
+ 		setproctitle("%s", "[net]");
+-		if (box != NULL)
++		if (box != NULL) {
+ 			ssh_sandbox_child(box);
++			free(box);
++		}
+ 
+ 		return 0;
+ 	}
+@@ -1518,6 +1520,9 @@ server_accept_loop(int *sock_in, int *so
+ 		if (num_listen_socks < 0)
+ 			break;
+ 	}
++
++	if (fdset != NULL)
++		free(fdset);
+ }
+ 
+ 
+diff -up openssh-6.8p1/sshkey.c.coverity openssh-6.8p1/sshkey.c
+--- openssh-6.8p1/sshkey.c.coverity	2015-03-18 17:21:58.285251452 +0100
++++ openssh-6.8p1/sshkey.c	2015-03-18 17:45:32.232705363 +0100
+@@ -58,6 +58,7 @@
+ #include "digest.h"
+ #define SSHKEY_INTERNAL
+ #include "sshkey.h"
++#include "log.h"
+ #include "match.h"
+ 
+ /* openssh private key file format */
+diff --git a/sshd.c b/sshd.c
+index 6ff8f6f..2f2fcf8 100644
+--- a/sshd.c
++++ b/sshd.c
+@@ -1548,6 +1548,7 @@ main(int ac, char **av)
+ 	int keytype;
+ 	Authctxt *authctxt;
+ 	struct connection_info *connection_info = get_connection_info(0, 0);
++	char *addr = NULL;
+ 
+ #ifdef HAVE_SECUREWARE
+ 	(void)set_auth_parameters(ac, av);
+@@ -2261,7 +2262,8 @@ main(int ac, char **av)
+ 	/* Log the connection. */
+ 	verbose("Connection from %s port %d on %s port %d",
+ 	    remote_ip, remote_port,
+-	    get_local_ipaddr(sock_in), get_local_port());
++	    (addr = get_local_ipaddr(sock_in)), get_local_port());
++	free(addr);
+ 
+ 	/*
+ 	 * We don't want to listen forever unless the other side
diff --git a/openssh-6.7p1-debian-restore-tcp-wrappers.patch b/openssh-6.7p1-debian-restore-tcp-wrappers.patch
new file mode 100644
index 0000000..63d62a0
--- /dev/null
+++ b/openssh-6.7p1-debian-restore-tcp-wrappers.patch
@@ -0,0 +1,140 @@
+diff -up openssh-6.8p1/configure.ac.tcp_wrappers openssh-6.8p1/configure.ac
+--- openssh-6.8p1/configure.ac.tcp_wrappers	2015-03-18 13:05:57.365071779 +0100
++++ openssh-6.8p1/configure.ac	2015-03-18 13:05:57.408071673 +0100
+@@ -1440,6 +1440,62 @@ AC_ARG_WITH([skey],
+ 	]
+ )
+ 
++# Check whether user wants TCP wrappers support
++TCPW_MSG="no"
++AC_ARG_WITH([tcp-wrappers],
++	[  --with-tcp-wrappers[[=PATH]] Enable tcpwrappers support (optionally in PATH)],
++	[
++		if test "x$withval" != "xno" ; then
++			saved_LIBS="$LIBS"
++			saved_LDFLAGS="$LDFLAGS"
++			saved_CPPFLAGS="$CPPFLAGS"
++			if test -n "${withval}" && \
++			    test "x${withval}" != "xyes"; then
++				if test -d "${withval}/lib"; then
++					if test -n "${need_dash_r}"; then
++						LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}"
++					else
++						LDFLAGS="-L${withval}/lib ${LDFLAGS}"
++					fi
++				else
++					if test -n "${need_dash_r}"; then
++						LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}"
++					else
++						LDFLAGS="-L${withval} ${LDFLAGS}"
++					fi
++				fi
++				if test -d "${withval}/include"; then
++					CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
++				else
++					CPPFLAGS="-I${withval} ${CPPFLAGS}"
++				fi
++			fi
++			LIBS="-lwrap $LIBS"
++			AC_MSG_CHECKING([for libwrap])
++			AC_LINK_IFELSE([AC_LANG_PROGRAM([[
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <tcpd.h>
++int deny_severity = 0, allow_severity = 0;
++				]], [[
++	hosts_access(0);
++				]])], [
++					AC_MSG_RESULT([yes])
++					AC_DEFINE([LIBWRAP], [1],
++						[Define if you want
++						TCP Wrappers support])
++					SSHDLIBS="$SSHDLIBS -lwrap"
++					TCPW_MSG="yes"
++				], [
++					AC_MSG_ERROR([*** libwrap missing])
++				
++			])
++			LIBS="$saved_LIBS"
++		fi
++	]
++)
++
+ # Check whether user wants to use ldns
+ LDNS_MSG="no"
+ AC_ARG_WITH(ldns,
+@@ -5026,6 +5082,7 @@ echo "                 KerberosV support
+ echo "                   SELinux support: $SELINUX_MSG"
+ echo "                 Smartcard support: $SCARD_MSG"
+ echo "                     S/KEY support: $SKEY_MSG"
++echo "              TCP Wrappers support: $TCPW_MSG"
+ echo "              MD5 password support: $MD5_MSG"
+ echo "                   libedit support: $LIBEDIT_MSG"
+ echo "  Solaris process contract support: $SPC_MSG"
+diff -up openssh-6.8p1/sshd.8.tcp_wrappers openssh-6.8p1/sshd.8
+--- openssh-6.8p1/sshd.8.tcp_wrappers	2015-03-18 13:05:57.377071749 +0100
++++ openssh-6.8p1/sshd.8	2015-03-18 13:05:57.408071673 +0100
+@@ -858,6 +858,12 @@ the user's home directory becomes access
+ This file should be writable only by the user, and need not be
+ readable by anyone else.
+ .Pp
++.It Pa /etc/hosts.allow
++.It Pa /etc/hosts.deny
++Access controls that should be enforced by tcp-wrappers are defined here.
++Further details are described in
++.Xr hosts_access 5 .
++.Pp
+ .It Pa /etc/hosts.equiv
+ This file is for host-based authentication (see
+ .Xr ssh 1 ) .
+@@ -981,6 +987,7 @@ IPv6 address can be used everywhere wher
+ .Xr ssh-keygen 1 ,
+ .Xr ssh-keyscan 1 ,
+ .Xr chroot 2 ,
++.Xr hosts_access 5 ,
+ .Xr login.conf 5 ,
+ .Xr moduli 5 ,
+ .Xr sshd_config 5 ,
+diff -up openssh-6.8p1/sshd.c.tcp_wrappers openssh-6.8p1/sshd.c
+--- openssh-6.8p1/sshd.c.tcp_wrappers	2015-03-18 13:05:57.402071688 +0100
++++ openssh-6.8p1/sshd.c	2015-03-18 13:06:48.199947136 +0100
+@@ -125,6 +125,13 @@
+ #include "version.h"
+ #include "ssherr.h"
+ 
++#ifdef LIBWRAP
++#include <tcpd.h>
++#include <syslog.h>
++int allow_severity;
++int deny_severity;
++#endif /* LIBWRAP */
++
+ #ifndef O_NOCTTY
+ #define O_NOCTTY	0
+ #endif
+@@ -2150,6 +2157,24 @@ main(int ac, char **av)
+ #ifdef SSH_AUDIT_EVENTS
+ 	audit_connection_from(remote_ip, remote_port);
+ #endif
++#ifdef LIBWRAP
++	allow_severity = options.log_facility|LOG_INFO;
++	deny_severity = options.log_facility|LOG_WARNING;
++	/* Check whether logins are denied from this host. */
++	if (packet_connection_is_on_socket()) {
++		struct request_info req;
++
++		request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0);
++		fromhost(&req);
++
++		if (!hosts_access(&req)) {
++			debug("Connection refused by tcp wrapper");
++			refuse(&req);
++			/* NOTREACHED */
++			fatal("libwrap refuse returns");
++		}
++	}
++#endif /* LIBWRAP */
+ 
+ 	/* Log the connection. */
+ 	verbose("Connection from %s port %d on %s port %d",
diff --git a/openssh-6.7p1-fips.patch b/openssh-6.7p1-fips.patch
new file mode 100644
index 0000000..0aafdcc
--- /dev/null
+++ b/openssh-6.7p1-fips.patch
@@ -0,0 +1,677 @@
+diff -up openssh-6.8p1/Makefile.in.fips openssh-6.8p1/Makefile.in
+--- openssh-6.8p1/Makefile.in.fips	2015-03-19 13:14:22.221212174 +0100
++++ openssh-6.8p1/Makefile.in	2015-03-19 13:14:22.230212157 +0100
+@@ -168,25 +168,25 @@ libssh.a: $(LIBSSH_OBJS)
+ 	$(RANLIB) $@
+ 
+ ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS)
+-	$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS) $(GSSLIBS)
++	$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHLIBS) $(LIBS) $(GSSLIBS)
+ 
+ sshd$(EXEEXT): libssh.a	$(LIBCOMPAT) $(SSHDOBJS)
+-	$(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS)
++	$(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS)
+ 
+ scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o
+ 	$(LD) -o $@ scp.o progressmeter.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+ 
+ ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o
+-	$(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
++	$(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
+ 
+ ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o
+-	$(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
++	$(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
+ 
+ ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o
+-	$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
++	$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
+ 
+ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o readconf.o
+-	$(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
++	$(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
+ 
+ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o
+ 	$(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
+@@ -204,7 +204,7 @@ ssh-cavs$(EXEEXT): $(LIBCOMPAT) libssh.a
+ 	$(LD) -o $@ ssh-cavs.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+ 
+ ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o
+-	$(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
++	$(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS)
+ 
+ sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o
+ 	$(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+diff -up openssh-6.8p1/cipher-ctr.c.fips openssh-6.8p1/cipher-ctr.c
+--- openssh-6.8p1/cipher-ctr.c.fips	2015-03-19 13:14:22.155212302 +0100
++++ openssh-6.8p1/cipher-ctr.c	2015-03-19 13:14:22.230212157 +0100
+@@ -179,7 +179,8 @@ evp_aes_128_ctr(void)
+ 	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;
++	    EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV |
++	    EVP_CIPH_FLAG_FIPS;
+ #endif
+ 	return (&aes_ctr);
+ }
+diff -up openssh-6.8p1/cipher.c.fips openssh-6.8p1/cipher.c
+--- openssh-6.8p1/cipher.c.fips	2015-03-19 13:14:22.224212169 +0100
++++ openssh-6.8p1/cipher.c	2015-03-19 13:14:22.230212157 +0100
+@@ -39,6 +39,8 @@
+ 
+ #include <sys/types.h>
+ 
++#include <openssl/fips.h>
++
+ #include <string.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+@@ -99,6 +101,26 @@ static const struct sshcipher ciphers[]
+ 	{ NULL,		SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL }
+ };
+ 
++static const struct sshcipher fips_ciphers[] = {
++	{ "none",	SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null },
++	{ "3des-cbc",	SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc },
++	{ "aes128-cbc",	SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 1, EVP_aes_128_cbc },
++	{ "aes192-cbc",	SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 1, EVP_aes_192_cbc },
++	{ "aes256-cbc",	SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc },
++	{ "rijndael-cbc at lysator.liu.se",
++			SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc },
++	{ "aes128-ctr",	SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr },
++	{ "aes192-ctr",	SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr },
++	{ "aes256-ctr",	SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr },
++#ifdef OPENSSL_HAVE_EVPGCM
++	{ "aes128-gcm at openssh.com",
++			SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm },
++	{ "aes256-gcm at openssh.com",
++			SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm },
++#endif
++	{ NULL,		SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL }
++};
++
+ /*--*/
+ 
+ /* Returns a comma-separated list of supported ciphers. */
+@@ -109,7 +131,7 @@ cipher_alg_list(char sep, int auth_only)
+ 	size_t nlen, rlen = 0;
+ 	const struct sshcipher *c;
+ 
+-	for (c = ciphers; c->name != NULL; c++) {
++	for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) {
+ 		if (c->number != SSH_CIPHER_SSH2)
+ 			continue;
+ 		if (auth_only && c->auth_len == 0)
+@@ -193,7 +215,7 @@ const struct sshcipher *
+ cipher_by_name(const char *name)
+ {
+ 	const struct sshcipher *c;
+-	for (c = ciphers; c->name != NULL; c++)
++	for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++)
+ 		if (strcmp(c->name, name) == 0)
+ 			return c;
+ 	return NULL;
+@@ -203,7 +225,7 @@ const struct sshcipher *
+ cipher_by_number(int id)
+ {
+ 	const struct sshcipher *c;
+-	for (c = ciphers; c->name != NULL; c++)
++	for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++)
+ 		if (c->number == id)
+ 			return c;
+ 	return NULL;
+@@ -244,7 +266,7 @@ cipher_number(const char *name)
+ 	const struct sshcipher *c;
+ 	if (name == NULL)
+ 		return -1;
+-	for (c = ciphers; c->name != NULL; c++)
++	for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++)
+ 		if (strcasecmp(c->name, name) == 0)
+ 			return c->number;
+ 	return -1;
+diff -up openssh-6.8p1/dh.h.fips openssh-6.8p1/dh.h
+--- openssh-6.8p1/dh.h.fips	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/dh.h	2015-03-19 13:14:22.230212157 +0100
+@@ -45,6 +45,7 @@ u_int	 dh_estimate(int);
+ 
+ /* Min and max values from RFC4419. */
+ #define DH_GRP_MIN	1024
++#define DH_GRP_MIN_FIPS	2048
+ #define DH_GRP_MAX	8192
+ 
+ /*
+diff -up openssh-6.8p1/entropy.c.fips openssh-6.8p1/entropy.c
+--- openssh-6.8p1/entropy.c.fips	2015-03-19 13:14:22.147212317 +0100
++++ openssh-6.8p1/entropy.c	2015-03-19 13:14:22.230212157 +0100
+@@ -217,6 +217,9 @@ seed_rng(void)
+ 		fatal("OpenSSL version mismatch. Built against %lx, you "
+ 		    "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay());
+ 
++	/* clean the PRNG status when exiting the program */
++	atexit(RAND_cleanup);
++
+ #ifndef OPENSSL_PRNG_ONLY
+ 	if (RAND_status() == 1) {
+ 		debug3("RNG is ready, skipping seeding");
+diff -up openssh-6.8p1/kex.c.fips openssh-6.8p1/kex.c
+--- openssh-6.8p1/kex.c.fips	2015-03-19 13:14:22.165212282 +0100
++++ openssh-6.8p1/kex.c	2015-03-19 13:14:22.230212157 +0100
+@@ -35,6 +35,7 @@
+ 
+ #ifdef WITH_OPENSSL
+ #include <openssl/crypto.h>
++#include <openssl/fips.h>
+ #endif
+ 
+ #include "ssh2.h"
+@@ -107,6 +108,25 @@ static const struct kexalg kexalgs[] = {
+ 	{ NULL, -1, -1, -1},
+ };
+ 
++static const struct kexalg kexalgs_fips[] = {
++	{ KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
++	{ KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
++#ifdef HAVE_EVP_SHA256
++	{ KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
++#endif
++#ifdef OPENSSL_HAS_ECC
++	{ KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2,
++	    NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
++	{ KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1,
++	    SSH_DIGEST_SHA384 },
++# ifdef OPENSSL_HAS_NISTP521
++	{ KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
++	    SSH_DIGEST_SHA512 },
++# endif
++#endif
++	{ NULL, -1, -1, -1},
++};
++
+ char *
+ kex_alg_list(char sep)
+ {
+@@ -134,7 +154,7 @@ kex_alg_by_name(const char *name)
+ {
+ 	const struct kexalg *k;
+ 
+-	for (k = kexalgs; k->name != NULL; k++) {
++	for (k = (FIPS_mode() ? kexalgs_fips : kexalgs); k->name != NULL; k++) {
+ 		if (strcmp(k->name, name) == 0)
+ 			return k;
+ #ifdef GSSAPI
+@@ -160,7 +180,10 @@ kex_names_valid(const char *names)
+ 	for ((p = strsep(&cp, ",")); p && *p != '\0';
+ 	    (p = strsep(&cp, ","))) {
+ 		if (kex_alg_by_name(p) == NULL) {
+-			error("Unsupported KEX algorithm \"%.100s\"", p);
++			if (FIPS_mode())
++				error("\"%.100s\" is not allowed in FIPS mode", p);
++			else
++				error("Unsupported KEX algorithm \"%.100s\"", p);
+ 			free(s);
+ 			return 0;
+ 		}
+diff -up openssh-6.8p1/kexgexc.c.fips openssh-6.8p1/kexgexc.c
+--- openssh-6.8p1/kexgexc.c.fips	2015-03-19 13:14:22.196212223 +0100
++++ openssh-6.8p1/kexgexc.c	2015-03-19 13:15:11.462117016 +0100
+@@ -28,6 +28,8 @@
+ 
+ #ifdef WITH_OPENSSL
+ 
++#include <openssl/fips.h>
++
+ #include <sys/types.h>
+ 
+ #include <openssl/dh.h>
+@@ -62,7 +64,7 @@ kexgex_client(struct ssh *ssh)
+ 
+ 	nbits = dh_estimate(kex->dh_need * 8);
+ 
+-	kex->min = DH_GRP_MIN;
++	kex->min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN;
+ 	kex->max = DH_GRP_MAX;
+ 
+ 	/* Servers with MAX4096DH need a preferred size (nbits) <= 4096.
+diff -up openssh-6.8p1/kexgexs.c.fips openssh-6.8p1/kexgexs.c
+--- openssh-6.8p1/kexgexs.c.fips	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/kexgexs.c	2015-03-19 13:14:22.231212155 +0100
+@@ -87,9 +87,9 @@ input_kex_dh_gex_request(int type, u_int
+ 		kex->nbits = nbits;
+ 		kex->min = min;
+ 		kex->max = max;
+-		min = MAX(DH_GRP_MIN, min);
++		min = MAX(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, min);
+ 		max = MIN(DH_GRP_MAX, max);
+-		nbits = MAX(DH_GRP_MIN, nbits);
++		nbits = MAX(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, nbits);
+ 		nbits = MIN(DH_GRP_MAX, nbits);
+ 		break;
+ 	case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
+@@ -99,7 +99,7 @@ input_kex_dh_gex_request(int type, u_int
+ 			goto out;
+ 		kex->nbits = nbits;
+ 		/* unused for old GEX */
+-		kex->min = min = DH_GRP_MIN;
++		kex->min = min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN;
+ 		kex->max = max = DH_GRP_MAX;
+ 		break;
+ 	default:
+diff -up openssh-6.8p1/mac.c.fips openssh-6.8p1/mac.c
+--- openssh-6.8p1/mac.c.fips	2015-03-19 13:14:22.224212169 +0100
++++ openssh-6.8p1/mac.c	2015-03-19 13:14:22.231212155 +0100
+@@ -27,6 +27,8 @@
+ 
+ #include <sys/types.h>
+ 
++#include <openssl/fips.h>
++
+ #include <string.h>
+ #include <stdio.h>
+ 
+@@ -54,7 +56,7 @@ struct macalg {
+ 	int		etm;		/* Encrypt-then-MAC */
+ };
+ 
+-static const struct macalg macs[] = {
++static const struct macalg all_macs[] = {
+ 	/* Encrypt-and-MAC (encrypt-and-authenticate) variants */
+ 	{ "hmac-sha1",				SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 },
+ 	{ "hmac-sha1-96",			SSH_DIGEST, SSH_DIGEST_SHA1, 96, 0, 0, 0 },
+@@ -85,6 +87,24 @@ static const struct macalg macs[] = {
+ 	{ NULL,					0, 0, 0, 0, 0, 0 }
+ };
+ 
++static const struct macalg fips_macs[] = {
++	/* Encrypt-and-MAC (encrypt-and-authenticate) variants */
++	{ "hmac-sha1",				SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 },
++#ifdef HAVE_EVP_SHA256
++	{ "hmac-sha2-256",			SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 0 },
++	{ "hmac-sha2-512",			SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 0 },
++#endif
++
++	/* Encrypt-then-MAC variants */
++	{ "hmac-sha1-etm at openssh.com",		SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 1 },
++#ifdef HAVE_EVP_SHA256
++	{ "hmac-sha2-256-etm at openssh.com",	SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 1 },
++	{ "hmac-sha2-512-etm at openssh.com",	SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 1 },
++#endif
++
++	{ NULL,					0, 0, 0, 0, 0, 0 }
++};
++
+ /* Returns a list of supported MACs separated by the specified char. */
+ char *
+ mac_alg_list(char sep)
+@@ -93,7 +113,7 @@ mac_alg_list(char sep)
+ 	size_t nlen, rlen = 0;
+ 	const struct macalg *m;
+ 
+-	for (m = macs; m->name != NULL; m++) {
++	for (m = FIPS_mode() ? fips_macs : all_macs; m->name != NULL; m++) {
+ 		if (ret != NULL)
+ 			ret[rlen++] = sep;
+ 		nlen = strlen(m->name);
+@@ -132,7 +152,7 @@ mac_setup(struct sshmac *mac, char *name
+ {
+ 	const struct macalg *m;
+ 
+-	for (m = macs; m->name != NULL; m++) {
++	for (m = FIPS_mode() ? fips_macs : all_macs; m->name != NULL; m++) {
+ 		if (strcmp(name, m->name) != 0)
+ 			continue;
+ 		if (mac != NULL)
+diff -up openssh-6.8p1/myproposal.h.fips openssh-6.8p1/myproposal.h
+--- openssh-6.8p1/myproposal.h.fips	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/myproposal.h	2015-03-19 13:14:22.231212155 +0100
+@@ -140,6 +140,28 @@
+ 	"hmac-sha1-96," \
+ 	"hmac-md5-96"
+ 
++#define KEX_DEFAULT_KEX_FIPS		\
++	KEX_ECDH_METHODS \
++	KEX_SHA256_METHODS \
++	"diffie-hellman-group-exchange-sha1," \
++	"diffie-hellman-group14-sha1"
++#define	KEX_FIPS_ENCRYPT \
++	"aes128-ctr,aes192-ctr,aes256-ctr," \
++	"aes128-cbc,3des-cbc," \
++	"aes192-cbc,aes256-cbc,rijndael-cbc at lysator.liu.se"
++#ifdef HAVE_EVP_SHA256
++#define	KEX_FIPS_MAC \
++	"hmac-sha1," \
++	"hmac-sha2-256," \
++	"hmac-sha2-512," \
++	"hmac-sha1-etm at openssh.com," \
++	"hmac-sha2-256-etm at openssh.com," \
++	"hmac-sha2-512-etm at openssh.com"
++#else
++#define        KEX_FIPS_MAC \
++       "hmac-sha1"
++#endif
++
+ #else
+ 
+ #define KEX_SERVER_KEX		\
+diff -up openssh-6.8p1/ssh.c.fips openssh-6.8p1/ssh.c
+--- openssh-6.8p1/ssh.c.fips	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/ssh.c	2015-03-19 13:14:22.232212153 +0100
+@@ -75,6 +75,8 @@
+ #include <openssl/evp.h>
+ #include <openssl/err.h>
+ #endif
++#include <openssl/fips.h>
++#include <fipscheck.h>
+ #include "openbsd-compat/openssl-compat.h"
+ #include "openbsd-compat/sys-queue.h"
+ 
+@@ -523,6 +525,14 @@ main(int ac, char **av)
+ 	sanitise_stdfd();
+ 
+ 	__progname = ssh_get_progname(av[0]);
++        SSLeay_add_all_algorithms();
++	if (access("/etc/system-fips", F_OK) == 0)
++		if (! FIPSCHECK_verify(NULL, NULL)){
++			if (FIPS_mode())
++				fatal("FIPS integrity verification test failed.");
++			else
++				logit("FIPS integrity verification test failed.");
++	}
+ 
+ #ifndef HAVE_SETPROCTITLE
+ 	/* Prepare for later setproctitle emulation */
+@@ -600,6 +610,9 @@ main(int ac, char **av)
+ 	    "ACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
+ 		switch (opt) {
+ 		case '1':
++			if (FIPS_mode()) {
++				fatal("Protocol 1 not allowed in the FIPS mode.");
++			}
+ 			options.protocol = SSH_PROTO_1;
+ 			break;
+ 		case '2':
+@@ -941,7 +954,6 @@ main(int ac, char **av)
+ 	host_arg = xstrdup(host);
+ 
+ #ifdef WITH_OPENSSL
+-	OpenSSL_add_all_algorithms();
+ 	ERR_load_crypto_strings();
+ #endif
+ 
+@@ -1115,6 +1127,10 @@ main(int ac, char **av)
+ 
+ 	seed_rng();
+ 
++	if (FIPS_mode()) {
++		logit("FIPS mode initialized");
++	}
++
+ 	if (options.user == NULL)
+ 		options.user = xstrdup(pw->pw_name);
+ 
+@@ -1192,6 +1208,12 @@ main(int ac, char **av)
+ 
+ 	timeout_ms = options.connection_timeout * 1000;
+ 
++	if (FIPS_mode()) {
++		options.protocol &= SSH_PROTO_2;
++		if (options.protocol == 0)
++			fatal("Protocol 2 disabled by configuration but required in the FIPS mode.");
++	}
++
+ 	/* Open a connection to the remote host. */
+ 	if (ssh_connect(host, addrs, &hostaddr, options.port,
+ 	    options.address_family, options.connection_attempts,
+diff -up openssh-6.8p1/sshconnect2.c.fips openssh-6.8p1/sshconnect2.c
+--- openssh-6.8p1/sshconnect2.c.fips	2015-03-19 13:14:22.188212238 +0100
++++ openssh-6.8p1/sshconnect2.c	2015-03-19 13:14:22.232212153 +0100
+@@ -46,6 +46,8 @@
+ #include <vis.h>
+ #endif
+ 
++#include <openssl/fips.h>
++
+ #include "openbsd-compat/sys-queue.h"
+ 
+ #include "xmalloc.h"
+@@ -172,20 +174,25 @@ ssh_kex2(char *host, struct sockaddr *ho
+ 
+ #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 (FIPS_mode()) {
++			logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode");
++			options.gss_keyex = 0;
++		} else {
++			/* 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);
++			}
+ 		}
+ 	}
+ #endif
+@@ -197,6 +204,10 @@ ssh_kex2(char *host, struct sockaddr *ho
+ 	if (options.ciphers != NULL) {
+ 		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+ 		myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
++	} else if (FIPS_mode()) {
++		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
++		myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT;
++
+ 	}
+ 	myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+ 	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
+@@ -212,7 +223,11 @@ ssh_kex2(char *host, struct sockaddr *ho
+ 	if (options.macs != NULL) {
+ 		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
+ 		myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
++	} else if (FIPS_mode()) {
++		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
++		myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC;
+ 	}
++
+ 	if (options.hostkeyalgorithms != NULL)
+ 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
+ 		    compat_pkalg_proposal(options.hostkeyalgorithms);
+@@ -224,9 +239,11 @@ ssh_kex2(char *host, struct sockaddr *ho
+ 	}
+ 	if (options.kex_algorithms != NULL)
+ 		myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
++	else if (FIPS_mode())
++		myproposal[PROPOSAL_KEX_ALGS] = KEX_DEFAULT_KEX_FIPS;
++
+ 	myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
+ 	    myproposal[PROPOSAL_KEX_ALGS]);
+-
+ #ifdef GSSAPI
+ 	/* If we've got GSSAPI algorithms, then we also support the
+ 	 * 'null' hostkey, as a last resort */
+diff -up openssh-6.8p1/sshd.c.fips openssh-6.8p1/sshd.c
+--- openssh-6.8p1/sshd.c.fips	2015-03-19 13:14:22.226212165 +0100
++++ openssh-6.8p1/sshd.c	2015-03-19 13:14:22.232212153 +0100
+@@ -66,6 +66,7 @@
+ #include <grp.h>
+ #include <pwd.h>
+ #include <signal.h>
++#include <syslog.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -77,6 +78,8 @@
+ #include <openssl/dh.h>
+ #include <openssl/bn.h>
+ #include <openssl/rand.h>
++#include <openssl/fips.h>
++#include <fipscheck.h>
+ #include "openbsd-compat/openssl-compat.h"
+ #endif
+ 
+@@ -1543,6 +1546,18 @@ main(int ac, char **av)
+ #endif
+ 	__progname = ssh_get_progname(av[0]);
+ 
++        SSLeay_add_all_algorithms();
++	if (access("/etc/system-fips", F_OK) == 0)
++		if (! FIPSCHECK_verify(NULL, NULL)) {
++			openlog(__progname, LOG_PID, LOG_AUTHPRIV);
++			if (FIPS_mode()) {
++				syslog(LOG_CRIT, "FIPS integrity verification test failed.");
++				cleanup_exit(255);
++			}
++			else
++				syslog(LOG_INFO, "FIPS integrity verification test failed.");
++			closelog();
++		}
+ 	/* Save argv. Duplicate so setproctitle emulation doesn't clobber it */
+ 	saved_argc = ac;
+ 	rexec_argc = ac;
+@@ -1694,7 +1709,7 @@ main(int ac, char **av)
+ 	else
+ 		closefrom(REEXEC_DEVCRYPTO_RESERVED_FD);
+ 
+-#ifdef WITH_OPENSSL
++#if 0 /* FIPS */
+ 	OpenSSL_add_all_algorithms();
+ #endif
+ 
+@@ -1890,6 +1905,10 @@ main(int ac, char **av)
+ 		    sshkey_type(pubkey) : sshkey_ssh_name(pubkey), fp);
+ 		free(fp);
+ 	}
++	if ((options.protocol & SSH_PROTO_1) && FIPS_mode()) {
++		logit("Disabling protocol version 1. Not allowed in the FIPS mode.");
++		options.protocol &= ~SSH_PROTO_1;
++	}
+ 	if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) {
+ 		logit("Disabling protocol version 1. Could not load host key");
+ 		options.protocol &= ~SSH_PROTO_1;
+@@ -2058,6 +2077,10 @@ main(int ac, char **av)
+ 	/* Reinitialize the log (because of the fork above). */
+ 	log_init(__progname, options.log_level, options.log_facility, log_stderr);
+ 
++	if (FIPS_mode()) {
++		logit("FIPS mode initialized");
++	}
++
+ 	/* Chdir to the root directory so that the current disk can be
+ 	   unmounted if desired. */
+ 	if (chdir("/") == -1)
+@@ -2642,6 +2665,9 @@ do_ssh2_kex(void)
+ 	if (options.ciphers != NULL) {
+ 		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+ 		myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
++	} else if (FIPS_mode()) {
++		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
++		myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT;
+ 	}
+ 	myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+ 	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
+@@ -2651,6 +2677,9 @@ do_ssh2_kex(void)
+ 	if (options.macs != NULL) {
+ 		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
+ 		myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
++	} else if (FIPS_mode()) {
++		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
++		myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC;
+ 	}
+ 	if (options.compression == COMP_NONE) {
+ 		myproposal[PROPOSAL_COMP_ALGS_CTOS] =
+@@ -2661,6 +2690,8 @@ do_ssh2_kex(void)
+ 	}
+ 	if (options.kex_algorithms != NULL)
+ 		myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
++	else if (FIPS_mode())
++		myproposal[PROPOSAL_KEX_ALGS] = KEX_DEFAULT_KEX_FIPS;
+ 
+ 	myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
+ 	    myproposal[PROPOSAL_KEX_ALGS]);
+@@ -2687,10 +2718,14 @@ do_ssh2_kex(void)
+ 	if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
+ 		orig = NULL;
+ 
+-	if (options.gss_keyex)
+-		gss = ssh_gssapi_server_mechanisms();
+-	else
+-		gss = NULL;
++	if (options.gss_keyex) {
++		if (FIPS_mode()) {
++			logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode");
++			options.gss_keyex = 0;
++		} else {
++			gss = ssh_gssapi_server_mechanisms();
++		}
++	}
+ 
+ 	if (gss && orig)
+ 		xasprintf(&newstr, "%s,%s", gss, orig);
+diff -up openssh-6.8p1/sshkey.c.fips openssh-6.8p1/sshkey.c
+--- openssh-6.8p1/sshkey.c.fips	2015-03-19 13:14:22.227212163 +0100
++++ openssh-6.8p1/sshkey.c	2015-03-19 13:14:22.233212151 +0100
+@@ -35,6 +35,7 @@
+ #include <openssl/evp.h>
+ #include <openssl/err.h>
+ #include <openssl/pem.h>
++#include <openssl/fips.h>
+ #endif
+ 
+ #include "crypto_api.h"
+@@ -1562,6 +1563,8 @@ rsa_generate_private_key(u_int bits, RSA
+ 	}
+ 	if (!BN_set_word(f4, RSA_F4) ||
+ 	    !RSA_generate_key_ex(private, bits, f4, NULL)) {
++			if (FIPS_mode())
++				logit("%s: the key length might be unsupported by FIPS mode approved key generation method", __func__);
+ 		ret = SSH_ERR_LIBCRYPTO_ERROR;
+ 		goto out;
+ 	}
+diff -up openssh-6.8p1/servconf.c.fips openssh-6.8p1/servconf.c
+--- openssh-6.8p1/servconf.c.fips	2015-03-19 13:14:22.210212196 +0100
++++ openssh-6.8p1/servconf.c	2015-03-19 13:14:22.233212151 +0100
+@@ -2226,8 +2226,10 @@ dump_config(ServerOptions *o)
+ 	/* string arguments */
+ 	dump_cfg_string(sPidFile, o->pid_file);
+ 	dump_cfg_string(sXAuthLocation, o->xauth_location);
+-	dump_cfg_string(sCiphers, o->ciphers ? o->ciphers : KEX_SERVER_ENCRYPT);
+-	dump_cfg_string(sMacs, o->macs ? o->macs : KEX_SERVER_MAC);
++	dump_cfg_string(sCiphers, o->ciphers ? o->ciphers : FIPS_mode()
++		? KEX_FIPS_ENCRYPT : KEX_SERVER_ENCRYPT);
++	dump_cfg_string(sMacs, o->macs ? o->macs : FIPS_mode()
++		? KEX_FIPS_MAC : KEX_SERVER_MAC);
+ 	dump_cfg_string(sBanner, o->banner);
+ 	dump_cfg_string(sForceCommand, o->adm_forced_command);
+ 	dump_cfg_string(sChrootDirectory, o->chroot_directory);
+@@ -2240,8 +2242,8 @@ dump_config(ServerOptions *o)
+ 	dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
+ 	dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
+ 	dump_cfg_string(sHostKeyAgent, o->host_key_agent);
+-	dump_cfg_string(sKexAlgorithms,
+-	    o->kex_algorithms ? o->kex_algorithms : KEX_SERVER_KEX);
++ 	dump_cfg_string(sKexAlgorithms, o->kex_algorithms ? o->kex_algorithms :
++		FIPS_mode() ? KEX_DEFAULT_KEX_FIPS : KEX_SERVER_KEX);
+ 	dump_cfg_string(sHostbasedAcceptedKeyTypes, o->hostbased_key_types ?
+ 	    o->hostbased_key_types : KEX_DEFAULT_PK_ALG);
+ 	dump_cfg_string(sPubkeyAcceptedKeyTypes, o->pubkey_key_types ?
diff --git a/openssh-6.7p1-kdf-cavs.patch b/openssh-6.7p1-kdf-cavs.patch
new file mode 100644
index 0000000..d219791
--- /dev/null
+++ b/openssh-6.7p1-kdf-cavs.patch
@@ -0,0 +1,614 @@
+diff -up openssh-6.8p1/Makefile.in.kdf-cavs openssh-6.8p1/Makefile.in
+--- openssh-6.8p1/Makefile.in.kdf-cavs	2015-03-18 11:23:46.346049359 +0100
++++ openssh-6.8p1/Makefile.in	2015-03-18 11:24:20.395968445 +0100
+@@ -29,6 +29,7 @@ SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-h
+ SSH_LDAP_WRAPPER=$(libexecdir)/ssh-ldap-wrapper
+ SSH_KEYCAT=$(libexecdir)/ssh-keycat
+ CTR_CAVSTEST=$(libexecdir)/ctr-cavstest
++SSH_CAVS=$(libexecdir)/ssh-cavs
+ SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
+ PRIVSEP_PATH=@PRIVSEP_PATH@
+ SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
+@@ -67,7 +68,7 @@ EXEEXT=@EXEEXT@
+ MANFMT=@MANFMT@
+ INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@
+ 
+-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT) ctr-cavstest$(EXEEXT)
++TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT) ctr-cavstest$(EXEEXT) ssh-cavs$(EXEEXT)
+ 
+ LIBOPENSSH_OBJS=\
+ 	ssh_api.o \
+@@ -198,6 +199,9 @@ ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHD
+ ctr-cavstest$(EXEEXT): $(LIBCOMPAT) libssh.a ctr-cavstest.o
+ 	$(LD) -o $@ ctr-cavstest.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS)
+ 
++ssh-cavs$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-cavs.o roaming_dummy.o
++	$(LD) -o $@ ssh-cavs.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
++
+ ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o
+ 	$(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
+ 
+@@ -331,6 +335,8 @@ install-files:
+ 	fi
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) ssh-keycat$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-keycat$(EXEEXT)
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) ctr-cavstest$(EXEEXT) $(DESTDIR)$(libexecdir)/ctr-cavstest$(EXEEXT)
++	$(INSTALL) -m 0755 $(STRIP_OPT) ssh-cavs$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-cavs$(EXEEXT)
++	$(INSTALL) -m 0755 $(STRIP_OPT) ssh-cavs_driver.pl $(DESTDIR)$(libexecdir)/ssh-cavs_driver.pl
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT)
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
+ 	$(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
+diff -up openssh-6.8p1/ssh-cavs.c.kdf-cavs openssh-6.8p1/ssh-cavs.c
+--- openssh-6.8p1/ssh-cavs.c.kdf-cavs	2015-03-18 11:23:46.348049354 +0100
++++ openssh-6.8p1/ssh-cavs.c	2015-03-18 11:23:46.348049354 +0100
+@@ -0,0 +1,383 @@
++/*
++ * Copyright (C) 2015, Stephan Mueller <smueller at chronox.de>
++ *
++ * 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, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 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.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ *
++ * ALTERNATIVELY, this product may be distributed under the terms of
++ * the GNU General Public License, in which case the provisions of the GPL2
++ * are required INSTEAD OF the above restrictions.  (This clause is
++ * necessary due to a potential bad interaction between the GPL and
++ * the restrictions contained in a BSD-style copyright.)
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#include "includes.h"
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <string.h>
++
++#include <openssl/bn.h>
++
++#include "xmalloc.h"
++#include "buffer.h"
++#include "key.h"
++#include "cipher.h"
++#include "kex.h"
++#include "packet.h"
++
++static int bin_char(unsigned char hex)
++{
++	if (48 <= hex && 57 >= hex)
++		return (hex - 48);
++	if (65 <= hex && 70 >= hex)
++		return (hex - 55);
++	if (97 <= hex && 102 >= hex)
++		return (hex - 87);
++	return 0;
++}
++
++/*
++ * Convert hex representation into binary string
++ * @hex input buffer with hex representation
++ * @hexlen length of hex
++ * @bin output buffer with binary data
++ * @binlen length of already allocated bin buffer (should be at least
++ *	   half of hexlen -- if not, only a fraction of hexlen is converted)
++ */
++static void hex2bin(const char *hex, size_t hexlen,
++		    unsigned char *bin, size_t binlen)
++{
++	size_t i = 0;
++	size_t chars = (binlen > (hexlen / 2)) ? (hexlen / 2) : binlen;
++
++	for (i = 0; i < chars; i++) {
++		bin[i] = bin_char(hex[(i*2)]) << 4;
++		bin[i] |= bin_char(hex[((i*2)+1)]);
++	}
++}
++
++/*
++ * Allocate sufficient space for binary representation of hex
++ * and convert hex into bin
++ *
++ * Caller must free bin
++ * @hex input buffer with hex representation
++ * @hexlen length of hex
++ * @bin return value holding the pointer to the newly allocated buffer
++ * @binlen return value holding the allocated size of bin
++ *
++ * return: 0 on success, !0 otherwise
++ */
++static int hex2bin_alloc(const char *hex, size_t hexlen,
++			 unsigned char **bin, size_t *binlen)
++{
++	unsigned char *out = NULL;
++	size_t outlen = 0;
++
++	if (!hexlen)
++		return -EINVAL;
++
++	outlen = (hexlen + 1) / 2;
++
++	out = calloc(1, outlen);
++	if (!out)
++		return -errno;
++
++	hex2bin(hex, hexlen, out, outlen);
++	*bin = out;
++	*binlen = outlen;
++	return 0;
++}
++
++static char hex_char_map_l[] = { '0', '1', '2', '3', '4', '5', '6', '7',
++				 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
++static char hex_char_map_u[] = { '0', '1', '2', '3', '4', '5', '6', '7',
++				 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
++static char hex_char(unsigned int bin, int u)
++{
++	if (bin < sizeof(hex_char_map_l))
++		return (u) ? hex_char_map_u[bin] : hex_char_map_l[bin];
++	return 'X';
++}
++
++/*
++ * Convert binary string into hex representation
++ * @bin input buffer with binary data
++ * @binlen length of bin
++ * @hex output buffer to store hex data
++ * @hexlen length of already allocated hex buffer (should be at least
++ *	   twice binlen -- if not, only a fraction of binlen is converted)
++ * @u case of hex characters (0=>lower case, 1=>upper case)
++ */
++static void bin2hex(const unsigned char *bin, size_t binlen,
++		    char *hex, size_t hexlen, int u)
++{
++	size_t i = 0;
++	size_t chars = (binlen > (hexlen / 2)) ? (hexlen / 2) : binlen;
++
++	for (i = 0; i < chars; i++) {
++		hex[(i*2)] = hex_char((bin[i] >> 4), u);
++		hex[((i*2)+1)] = hex_char((bin[i] & 0x0f), u);
++	}
++}
++
++struct kdf_cavs {
++	unsigned char *K;
++	size_t Klen;
++	unsigned char *H;
++	size_t Hlen;
++	unsigned char *session_id;
++	size_t session_id_len;
++
++	unsigned int iv_len;
++	unsigned int ek_len;
++	unsigned int ik_len;
++};
++
++static int sshkdf_cavs(struct kdf_cavs *test)
++{
++	int ret = 0;
++	struct kex kex;
++	BIGNUM *Kbn = NULL;
++	int mode = 0;
++	struct newkeys *ctoskeys;
++	struct newkeys *stockeys;
++	struct ssh *ssh = NULL;
++
++#define HEXOUTLEN 500
++	char hex[HEXOUTLEN];
++
++	memset(&kex, 0, sizeof(struct kex));
++
++	Kbn = BN_new();
++	BN_bin2bn(test->K, test->Klen, Kbn);
++	if (!Kbn) {
++		printf("cannot convert K into BIGNUM\n");
++		ret = 1;
++		goto out;
++	}
++
++	kex.session_id = test->session_id;
++	kex.session_id_len = test->session_id_len;
++
++	/* setup kex */
++
++	/* select the right hash based on struct ssh_digest digests */
++	switch (test->ik_len) {
++		case 20:
++			kex.hash_alg = 2;
++			break;
++		case 32:
++			kex.hash_alg = 3;
++			break;
++		case 48:
++			kex.hash_alg = 4;
++			break;
++		case 64:
++			kex.hash_alg = 5;
++			break;
++		default:
++			printf("Wrong hash type %u\n", test->ik_len);
++			ret = 1;
++			goto out;
++	}
++
++	/* implement choose_enc */
++	for (mode = 0; mode < 2; mode++) {
++		kex.newkeys[mode] = calloc(1, sizeof(struct newkeys));
++		if (!kex.newkeys[mode]) {
++			printf("allocation of newkeys failed\n");
++			ret = 1;
++			goto out;
++		}
++		kex.newkeys[mode]->enc.iv_len = test->iv_len;
++		kex.newkeys[mode]->enc.key_len = test->ek_len;
++		kex.newkeys[mode]->enc.block_size = (test->iv_len == 64) ? 8 : 16;
++		kex.newkeys[mode]->mac.key_len = test->ik_len;
++	}
++
++	/* implement kex_choose_conf */
++	kex.we_need = kex.newkeys[0]->enc.key_len;
++	if (kex.we_need < kex.newkeys[0]->enc.block_size)
++		kex.we_need = kex.newkeys[0]->enc.block_size;
++	if (kex.we_need < kex.newkeys[0]->enc.iv_len)
++		kex.we_need = kex.newkeys[0]->enc.iv_len;
++	if (kex.we_need < kex.newkeys[0]->mac.key_len)
++		kex.we_need = kex.newkeys[0]->mac.key_len;
++
++	/* MODE_OUT (1) -> server to client
++	 * MODE_IN (0) -> client to server */
++	kex.server = 1;
++
++	/* do it */
++	if ((ssh = ssh_packet_set_connection(NULL, -1, -1)) == NULL){
++		printf("Allocation error\n");
++		goto out;
++	}
++	ssh->kex = &kex;
++	kex_derive_keys_bn(ssh, test->H, test->Hlen, Kbn);
++
++	ctoskeys = kex.newkeys[0];
++	stockeys = kex.newkeys[1];
++
++	/* get data */
++	memset(hex, 0, HEXOUTLEN);
++	bin2hex(ctoskeys->enc.iv, (size_t)ctoskeys->enc.iv_len,
++		hex, HEXOUTLEN, 0);
++	printf("Initial IV (client to server) = %s\n", hex);
++	memset(hex, 0, HEXOUTLEN);
++	bin2hex(stockeys->enc.iv, (size_t)stockeys->enc.iv_len,
++		hex, HEXOUTLEN, 0);
++	printf("Initial IV (server to client) = %s\n", hex);
++
++	memset(hex, 0, HEXOUTLEN);
++	bin2hex(ctoskeys->enc.key, (size_t)ctoskeys->enc.key_len,
++		hex, HEXOUTLEN, 0);
++	printf("Encryption key (client to server) = %s\n", hex);
++	memset(hex, 0, HEXOUTLEN);
++	bin2hex(stockeys->enc.key, (size_t)stockeys->enc.key_len,
++		hex, HEXOUTLEN, 0);
++	printf("Encryption key (server to client) = %s\n", hex);
++
++	memset(hex, 0, HEXOUTLEN);
++	bin2hex(ctoskeys->mac.key, (size_t)ctoskeys->mac.key_len,
++		hex, HEXOUTLEN, 0);
++	printf("Integrity key (client to server) = %s\n", hex);
++	memset(hex, 0, HEXOUTLEN);
++	bin2hex(stockeys->mac.key, (size_t)stockeys->mac.key_len,
++		hex, HEXOUTLEN, 0);
++	printf("Integrity key (server to client) = %s\n", hex);
++
++	free(ctoskeys);
++	free(stockeys);
++
++out:
++	if (Kbn)
++		BN_free(Kbn);
++	if (kex.newkeys[0])
++		free(kex.newkeys[0]);
++	if (kex.newkeys[1])
++		free(kex.newkeys[1]);
++	if (ssh)
++		ssh_packet_close(ssh);
++	return ret;
++}
++
++static void usage(void)
++{
++	fprintf(stderr, "\nOpenSSH KDF CAVS Test\n\n");
++	fprintf(stderr, "Usage:\n");
++	fprintf(stderr, "\t-K\tShared secret string\n");
++	fprintf(stderr, "\t-H\tHash string\n");
++	fprintf(stderr, "\t-s\tSession ID string\n");
++	fprintf(stderr, "\t-i\tIV length to be generated\n");
++	fprintf(stderr, "\t-e\tEncryption key length to be generated\n");
++	fprintf(stderr, "\t-m\tMAC key length to be generated\n");
++}
++
++/*
++ * Test command example:
++ * ./ssh-cavs -K 0055d50f2d163cc07cd8a93cc7c3430c30ce786b572c01ad29fec7597000cf8618d664e2ec3dcbc8bb7a1a7eb7ef67f61cdaf291625da879186ac0a5cb27af571b59612d6a6e0627344d846271959fda61c78354aa498773d59762f8ca2d0215ec590d8633de921f920d41e47b3de6ab9a3d0869e1c826d0e4adebf8e3fb646a15dea20a410b44e969f4b791ed6a67f13f1b74234004d5fa5e87eff7abc32d49bbdf44d7b0107e8f10609233b7e2b7eff74a4daf25641de7553975dac6ac1e5117df6f6dbaa1c263d23a6c3e5a3d7d49ae8a828c1e333ac3f85fbbf57b5c1a45be45e43a7be1a4707eac779b8285522d1f531fe23f890fd38a004339932b93eda4 -H d3ab91a850febb417a25d892ec48ed5952c7a5de -s d3ab91a850febb417a25d892ec48ed5952c7a5de -i 8 -e 24 -m 20
++ *
++ * Initial IV (client to server) = 4bb320d1679dfd3a
++ * Initial IV (server to client) = 43dea6fdf263a308
++ * Encryption key (client to server) = 13048cc600b9d3cf9095aa6cf8e2ff9cf1c54ca0520c89ed
++ * Encryption key (server to client) = 1e483c5134e901aa11fc4e0a524e7ec7b75556148a222bb0
++ * Integrity key (client to server) = ecef63a092b0dcc585bdc757e01b2740af57d640
++ * Integrity key (server to client) = 7424b05f3c44a72b4ebd281fb71f9cbe7b64d479
++ */
++int main(int argc, char *argv[])
++{
++	struct kdf_cavs test;
++	int ret = 1;
++	int opt = 0;
++
++	memset(&test, 0, sizeof(struct kdf_cavs));
++	while((opt = getopt(argc, argv, "K:H:s:i:e:m:")) != -1)
++	{
++		size_t len = 0;
++		switch(opt)
++		{
++			/*
++			 * CAVS K is MPINT
++			 * we want a hex (i.e. the caller must ensure the
++			 * following transformations already happened):
++			 * 	1. cut off first four bytes
++			 * 	2. if most significant bit of value is
++			 *	   1, prepend 0 byte
++			 */
++			case 'K':
++				len = strlen(optarg);
++				ret = hex2bin_alloc(optarg, len,
++						    &test.K, &test.Klen);
++				if (ret)
++					goto out;
++				break;
++			case 'H':
++				len = strlen(optarg);
++				ret = hex2bin_alloc(optarg, len,
++						    &test.H, &test.Hlen);
++				if (ret)
++					goto out;
++				break;
++			case 's':
++				len = strlen(optarg);
++				ret = hex2bin_alloc(optarg, len,
++						    &test.session_id,
++						    &test.session_id_len);
++				if (ret)
++					goto out;
++				break;
++			case 'i':
++				test.iv_len = strtoul(optarg, NULL, 10);
++				break;
++			case 'e':
++				test.ek_len = strtoul(optarg, NULL, 10);
++				break;
++			case 'm':
++				test.ik_len = strtoul(optarg, NULL, 10);
++				break;
++			default:
++				usage();
++				goto out;
++		}
++	}
++
++	ret = sshkdf_cavs(&test);
++
++out:
++	if (test.session_id)
++		free(test.session_id);
++	if (test.K)
++		free(test.K);
++	if (test.H)
++		free(test.H);
++	return ret;
++
++}
+diff -up openssh-6.8p1/ssh-cavs_driver.pl.kdf-cavs openssh-6.8p1/ssh-cavs_driver.pl
+--- openssh-6.8p1/ssh-cavs_driver.pl.kdf-cavs	2015-03-18 11:23:46.348049354 +0100
++++ openssh-6.8p1/ssh-cavs_driver.pl	2015-03-18 11:23:46.348049354 +0100
+@@ -0,0 +1,184 @@
++#!/usr/bin/env perl
++#
++# CAVS test driver for OpenSSH
++#
++# Copyright (C) 2015, Stephan Mueller <smueller at chronox.de>
++#
++# Permission is hereby granted, free of charge, to any person obtaining a copy
++# of this software and associated documentation files (the "Software"), to deal
++# in the Software without restriction, including without limitation the rights
++# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++# copies of the Software, and to permit persons to whom the Software is
++# furnished to do so, subject to the following conditions:
++#
++# The above copyright notice and this permission notice shall be included in
++# all copies or substantial portions of the Software.
++#
++#                            NO WARRANTY
++#
++#    BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
++#    FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
++#    OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
++#    PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
++#    OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++#    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
++#    TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
++#    PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
++#    REPAIR OR CORRECTION.
++#
++#    IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
++#    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
++#    REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
++#    INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
++#    OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
++#    TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
++#    YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
++#    PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
++#    POSSIBILITY OF SUCH DAMAGES.
++#
++use strict;
++use warnings;
++use IPC::Open2;
++
++# Executing a program by feeding STDIN and retrieving
++# STDOUT
++# $1: data string to be piped to the app on STDIN
++# rest: program and args
++# returns: STDOUT of program as string
++sub pipe_through_program($@) {
++	my $in = shift;
++	my @args = @_;
++
++	my ($CO, $CI);
++	my $pid = open2($CO, $CI, @args);
++
++	my $out = "";
++	my $len = length($in);
++	my $first = 1;
++	while (1) {
++		my $rin = "";
++		my $win = "";
++		# Output of prog is FD that we read
++		vec($rin,fileno($CO),1) = 1;
++		# Input of prog is FD that we write
++		# check for $first is needed because we can have NULL input
++		# that is to be written to the app
++		if ( $len > 0 || $first) {
++			(vec($win,fileno($CI),1) = 1);
++			$first=0;
++		}
++		# Let us wait for 100ms
++		my $nfound = select(my $rout=$rin, my $wout=$win, undef, 0.1);
++		if ( $wout ) {
++			my $written = syswrite($CI, $in, $len);
++			die "broken pipe" if !defined $written;
++			$len -= $written;
++			substr($in, 0, $written) = "";
++			if ($len <= 0) {
++				close $CI or die "broken pipe: $!";
++			}
++		}
++		if ( $rout ) {
++			my $tmp_out = "";
++			my $bytes_read = sysread($CO, $tmp_out, 4096);
++			$out .= $tmp_out;
++			last if ($bytes_read == 0);
++		}
++	}
++	close $CO or die "broken pipe: $!";
++	waitpid $pid, 0;
++
++	return $out;
++}
++
++# Parser of CAVS test vector file
++# $1: Test vector file
++# $2: Output file for test results
++# return: nothing
++sub parse($$) {
++	my $infile = shift;
++	my $outfile = shift;
++
++	my $out = "";
++
++	my $K = "";
++	my $H = "";
++	my $session_id = "";
++	my $ivlen = 0;
++	my $eklen = "";
++	my $iklen = "";
++
++	open(IN, "<$infile");
++	while(<IN>) {
++
++		my $line = $_;
++		chomp($line);
++		$line =~ s/\r//;
++
++		if ($line =~ /\[SHA-1\]/) {
++			$iklen = 20;
++		} elsif ($line =~ /\[SHA-256\]/) {
++			$iklen = 32;
++		} elsif ($line =~ /\[SHA-384\]/) {
++			$iklen = 48;
++		} elsif ($line =~ /\[SHA-512\]/) {
++			$iklen = 64;
++		} elsif ($line =~ /^\[IV length\s*=\s*(.*)\]/) {
++			$ivlen = $1;
++			$ivlen = $ivlen / 8;
++		} elsif ($line =~ /^\[encryption key length\s*=\s*(.*)\]/) {
++			$eklen = $1;
++			$eklen = $eklen / 8;
++		} elsif ($line =~ /^K\s*=\s*(.*)/) {
++			$K = $1;
++			$K = substr($K, 8);
++			$K = "00" . $K;
++		} elsif ($line =~ /^H\s*=\s*(.*)/) {
++			$H = $1;
++		} elsif ($line =~ /^session_id\s*=\s*(.*)/) {
++			$session_id = $1;
++		}
++		$out .= $line . "\n";
++
++		if ($K ne "" && $H ne "" && $session_id ne "" &&
++		    $ivlen ne "" && $eklen ne "" && $iklen > 0) {
++			$out .= pipe_through_program("", "./ssh-cavs -H $H -K $K -s $session_id -i $ivlen -e $eklen -m $iklen");
++
++			$K = "";
++			$H = "";
++			$session_id = "";
++		}
++	}
++	close IN;
++	$out =~ s/\n/\r\n/g; # make it a dos file
++	open(OUT, ">$outfile") or die "Cannot create output file $outfile: $?";
++	print OUT $out;
++	close OUT;
++}
++
++############################################################
++#
++# let us pretend to be C :-)
++sub main() {
++
++	my $infile=$ARGV[0];
++	die "Error: Test vector file $infile not found" if (! -f $infile);
++
++	my $outfile = $infile;
++	# let us add .rsp regardless whether we could strip .req
++	$outfile =~ s/\.req$//;
++	$outfile .= ".rsp";
++	if (-f $outfile) {
++		die "Output file $outfile could not be removed: $?"
++			unless unlink($outfile);
++	}
++	print STDERR "Performing tests from source file $infile with results stored in destination file $outfile\n";
++
++	# Do the job
++	parse($infile, $outfile);
++}
++
++###########################################
++# Call it
++main();
++1;
diff --git a/openssh-6.7p1-ldap.patch b/openssh-6.7p1-ldap.patch
new file mode 100644
index 0000000..296e7ea
--- /dev/null
+++ b/openssh-6.7p1-ldap.patch
@@ -0,0 +1,2670 @@
+diff -up openssh-6.8p1/HOWTO.ldap-keys.ldap openssh-6.8p1/HOWTO.ldap-keys
+--- openssh-6.8p1/HOWTO.ldap-keys.ldap	2015-03-18 11:11:29.029801467 +0100
++++ openssh-6.8p1/HOWTO.ldap-keys	2015-03-18 11:11:29.029801467 +0100
+@@ -0,0 +1,119 @@
++
++HOW TO START
++
++1) configure LDAP server
++  * Use LDAP server documentation
++2) add appropriate LDAP schema
++  * For OpenLDAP or SunONE Use attached schema, otherwise you have to create it. 
++  * LDAP user entry
++        User entry:
++	- attached to the 'ldapPublicKey' objectclass
++	- attached to the 'posixAccount' objectclass
++	- with a filled 'sshPublicKey' attribute 
++3) insert users into LDAP
++  * Use LDAP Tree management tool as useful
++  * Entry in the LDAP server must respect 'posixAccount' and 'ldapPublicKey' which are defined in core.schema and the additionnal lpk.schema.
++  * Example:
++	dn: uid=captain,ou=commanders,dc=enterprise,dc=universe
++	objectclass: top
++	objectclass: person
++	objectclass: organizationalPerson
++	objectclass: posixAccount
++	objectclass: ldapPublicKey
++	description: Jonathan Archer
++	userPassword: Porthos
++	cn: onathan Archer
++	sn: onathan Archer
++	uid: captain
++	uidNumber: 1001
++	gidNumber: 1001
++	homeDirectory: /home/captain
++	sshPublicKey: ssh-rss AAAAB3.... =captain at universe
++	sshPublicKey: command="kill -9 1" ssh-rss AAAAM5...
++4) on the ssh side set in sshd_config
++  * Set up the backend
++	AuthorizedKeysCommand /usr/libexec/openssh/ssh-ldap-wrapper
++	AuthorizedKeysCommandUser <appropriate user to run LDAP>
++  * Do not forget to set
++	PubkeyAuthentication yes
++  * Swith off unnecessary auth methods
++5) confugure ldap.conf
++  * Default ldap.conf is placed in /etc/ssh
++  * The configuration style is the same as other ldap based aplications
++6) if necessary edit ssh-ldap-wrapper
++  * There is a possibility to change ldap.conf location
++  * There are some debug options
++  * Example
++	/usr/libexec/openssh -s -f /etc/ldap.conf -w -d >> /tmp/ldapdebuglog.txt
++
++HOW TO MIGRATE FROM LPK
++
++1) goto HOW TO START 4) .... the ldap schema is the same
++
++2) convert the group requests to the appropriate LDAP requests
++
++HOW TO SOLVE PROBLEMS
++
++1) use debug in sshd
++  * /usr/sbin/sshd -d -d -d -d
++2) use debug in ssh-ldap-helper
++  * ssh-ldap-helper -d -d -d -d -s <username>
++3) use tcpdump ... other ldap client etc.
++
++HOW TO CONFIGURE SSH FOR OTHER LDAP CONFIGURATION / SERVER /SCHEMA
++
++You can adjust search format string in /etc/ldap.conf using
++ 1) SSH_Filter option to limit results for only specified users
++    (this appends search condition after original query)
++ 2) Search_Format option to define your own search string using expansion
++    characters %u for username, %c for objectclass and %f for above mentioned filter.
++
++Example:
++Search_Format (&(objectclass=posixAccount)(objectclass=ldapPublicKey)(uid=%u)%f)
++
++ADVANTAGES
++
++1) Blocking an user account can be done directly from LDAP (if sshd is using PubkeyAuthentication + AuthorizedKeysCommand with ldap only).
++
++DISADVANTAGES
++
++1)  LDAP must be well configured, getting the public key of some user is not a problem, but if anonymous LDAP 
++  allows write to users dn, somebody could replace some user's public key by his own and impersonate some 
++  of your users in all your server farm -- be VERY CAREFUL.
++2) With incomplete PKI the MITM attack when sshd is requesting the public key, could lead to a compromise of your servers allowing login 
++  as the impersonated user.
++3) If LDAP server is down there may be no fallback on passwd auth.
++  
++MISC.
++  
++1) todo
++  * Possibility to reuse the ssh-ldap-helper.
++  * Tune the LDAP part to accept  all possible LDAP configurations.
++
++2) differences from original lpk
++  * No LDAP code in sshd.
++  * Support for various LDAP platforms and configurations.
++  * LDAP is configured in separate ldap.conf file.
++
++3) docs/link 
++  * http://pacsec.jp/core05/psj05-barisani-en.pdf
++  * http://fritz.potsdam.edu/projects/openssh-lpk/
++  * http://fritz.potsdam.edu/projects/sshgate/
++  * http://dev.inversepath.com/trac/openssh-lpk
++  * http://lam.sf.net/ ( http://lam.sourceforge.net/documentation/supportedSchemas.htm )
++
++4) contributors/ideas/greets
++  - Eric AUGE <eau at phear.org>
++  - Andrea Barisani <andrea at inversepath.com>
++  - Falk Siemonsmeier.
++  - Jacob Rief.
++  - Michael Durchgraf.
++  - frederic peters.
++  - Finlay dobbie.
++  - Stefan Fisher.
++  - Robin H. Johnson.
++  - Adrian Bridgett.
++
++5) Author
++    Jan F. Chadima <jchadima at redhat.com>
++
+diff -up openssh-6.8p1/Makefile.in.ldap openssh-6.8p1/Makefile.in
+--- openssh-6.8p1/Makefile.in.ldap	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/Makefile.in	2015-03-18 11:13:10.147561177 +0100
+@@ -25,6 +25,8 @@ SSH_PROGRAM=@bindir@/ssh
+ ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass
+ SFTP_SERVER=$(libexecdir)/sftp-server
+ SSH_KEYSIGN=$(libexecdir)/ssh-keysign
++SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper
++SSH_LDAP_WRAPPER=$(libexecdir)/ssh-ldap-wrapper
+ SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
+ PRIVSEP_PATH=@PRIVSEP_PATH@
+ SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
+@@ -61,8 +63,9 @@ XAUTH_PATH=@XAUTH_PATH@
+ LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@
+ EXEEXT=@EXEEXT@
+ MANFMT=@MANFMT@
++INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@
+ 
+-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT)
++TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT)
+ 
+ LIBOPENSSH_OBJS=\
+ 	ssh_api.o \
+@@ -112,8 +115,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw
+ 	sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
+ 	sandbox-seccomp-filter.o sandbox-capsicum.o
+ 
+-MANPAGES	= moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out
+-MANPAGES_IN	= moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5
++MANPAGES	= moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out ssh-ldap-helper.8.out ssh-ldap.conf.5.out
++MANPAGES_IN	= moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5 ssh-ldap-helper.8 ssh-ldap.conf.5
+ MANTYPE		= @MANTYPE@
+ 
+ CONFIGFILES=sshd_config.out ssh_config.out moduli.out
+@@ -184,6 +187,9 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libss
+ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o
+ 	$(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
+ 
++ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o sshbuf-getput-basic.o ssherr.o
++	$(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o sshbuf-getput-basic.o ssherr.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
++
+ ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o
+ 	$(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
+ 
+@@ -311,6 +317,10 @@ install-files:
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) sshd$(EXEEXT) $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
+ 	$(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
++	if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \
++		$(INSTALL) -m 0700 $(STRIP_OPT) ssh-ldap-helper $(DESTDIR)$(SSH_LDAP_HELPER) ; \
++		$(INSTALL) -m 0700 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \
++	fi
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT)
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
+ 	$(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
+@@ -327,6 +337,10 @@ install-files:
+ 	$(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
+ 	$(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
+ 	$(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
++	if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \
++		$(INSTALL) -m 644 ssh-ldap-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-ldap-helper.8 ; \
++		$(INSTALL) -m 644 ssh-ldap.conf.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/ssh-ldap.conf.5 ; \
++	fi
+ 	-rm -f $(DESTDIR)$(bindir)/slogin
+ 	ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
+@@ -356,6 +370,13 @@ install-sysconf:
+ 	else \
+ 		echo "$(DESTDIR)$(sysconfdir)/moduli already exists, install will not overwrite"; \
+ 	fi
++	if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \
++		if [ ! -f $(DESTDIR)$(sysconfdir)/ldap.conf ]; then \
++			$(INSTALL) -m 644 ldap.conf $(DESTDIR)$(sysconfdir)/ldap.conf; \
++		else \
++			echo "$(DESTDIR)$(sysconfdir)/ldap.conf already exists, install will not overwrite"; \
++		fi ; \
++	fi
+ 
+ host-key: ssh-keygen$(EXEEXT)
+ 	@if [ -z "$(DESTDIR)" ] ; then \
+@@ -419,6 +440,8 @@ uninstall:
+ 	-rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
+ 	-rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
+ 	-rm -f $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
++	-rm -f $(DESTDIR)$(SSH_LDAP_HELPER)$(EXEEXT)
++	-rm -f $(DESTDIR)$(SSH_LDAP_WRAPPER)$(EXEEXT)
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
+@@ -430,6 +453,7 @@ uninstall:
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
++	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-ldap-helper.8
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
+ 
+ regress-prep:
+diff -up openssh-6.8p1/configure.ac.ldap openssh-6.8p1/configure.ac
+--- openssh-6.8p1/configure.ac.ldap	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/configure.ac	2015-03-18 11:11:29.030801464 +0100
+@@ -1605,6 +1605,106 @@ if test "x$use_pie" != "xno"; then
+ 	fi
+ fi
+ 
++# Check whether user wants LDAP support
++LDAP_MSG="no"
++INSTALL_SSH_LDAP_HELPER=""
++AC_ARG_WITH(ldap,
++	[  --with-ldap[[=PATH]]      Enable LDAP pubkey support (optionally in PATH)],
++	[
++		if test "x$withval" != "xno" ; then
++
++			INSTALL_SSH_LDAP_HELPER="yes"
++			CPPFLAGS="$CPPFLAGS -DLDAP_DEPRECATED"
++
++			if test "x$withval" != "xyes" ; then
++				CPPFLAGS="$CPPFLAGS -I${withval}/include"
++				LDFLAGS="$LDFLAGS -L${withval}/lib"
++			fi
++
++			AC_DEFINE([WITH_LDAP_PUBKEY], 1, [Enable LDAP pubkey support])
++			LDAP_MSG="yes"
++
++			AC_CHECK_HEADERS(lber.h)
++			AC_CHECK_HEADERS(ldap.h, , AC_MSG_ERROR(could not locate <ldap.h>))
++			AC_CHECK_HEADERS(ldap_ssl.h)
++
++			AC_ARG_WITH(ldap-lib,
++				[  --with-ldap-lib=type    select ldap library [auto|netscape5|netscape4|netscape3|umich|openldap]])
++
++			if test -z "$with_ldap_lib"; then
++				with_ldap_lib=auto
++			fi
++
++			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = umich -o $with_ldap_lib = openldap \); then
++				AC_CHECK_LIB(lber, main, LIBS="-llber $LIBS" found_ldap_lib=yes)
++				AC_CHECK_LIB(ldap, main, LIBS="-lldap $LIBS" found_ldap_lib=yes)
++			fi
++
++			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape5 \); then
++				AC_CHECK_LIB(ldap50, main, LIBS="-lldap50 -lssldap50 -lssl3 -lnss3 -lnspr4 -lprldap50 -lplc4 -lplds4 $LIBS" found_ldap_lib=yes)
++			fi
++
++			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape4 \); then
++				AC_CHECK_LIB(ldapssl41, main, LIBS="-lldapssl41 -lplc3 -lplds3 -lnspr3 $LIBS" found_ldap_lib=yes)
++				if test -z "$found_ldap_lib"; then
++					AC_CHECK_LIB(ldapssl40, main, LIBS="-lldapssl40 $LIBS" found_ldap_lib=yes)
++				fi
++				if test -z "$found_ldap_lib"; then
++					AC_CHECK_LIB(ldap41, main, LIBS="-lldap41 $LIBS" found_ldap_lib=yes)
++				fi
++				if test -z "$found_ldap_lib"; then
++					AC_CHECK_LIB(ldap40, main, LIBS="-lldap40 $LIBS" found_ldap_lib=yes)
++				fi
++			fi
++
++			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape3 \); then
++				AC_CHECK_LIB(ldapssl30, main, LIBS="-lldapssl30 $LIBS" found_ldap_lib=yes)
++			fi
++
++			if test -z "$found_ldap_lib"; then
++				AC_MSG_ERROR(could not locate a valid LDAP library)
++			fi
++
++			AC_MSG_CHECKING([for working LDAP support])
++			AC_TRY_COMPILE(
++				[#include <sys/types.h>
++				 #include <ldap.h>],
++				[(void)ldap_init(0, 0);],
++				[AC_MSG_RESULT(yes)],
++				[
++				    AC_MSG_RESULT(no) 
++					AC_MSG_ERROR([** Incomplete or missing ldap libraries **])
++				])
++			AC_CHECK_FUNCS( \
++				ldap_init \
++				ldap_get_lderrno \
++				ldap_set_lderrno \
++				ldap_parse_result \
++				ldap_memfree \
++				ldap_controls_free \
++				ldap_set_option \
++				ldap_get_option \
++				ldapssl_init \
++				ldap_start_tls_s \
++				ldap_pvt_tls_set_option \
++				ldap_initialize \
++			)
++			AC_CHECK_FUNCS(ldap_set_rebind_proc,
++				AC_MSG_CHECKING([number arguments of ldap_set_rebind_proc])
++				AC_TRY_COMPILE(
++					[#include <lber.h>
++					#include <ldap.h>],
++					[ldap_set_rebind_proc(0, 0, 0);],
++					[ac_cv_ldap_set_rebind_proc=3],
++					[ac_cv_ldap_set_rebind_proc=2])
++				AC_MSG_RESULT($ac_cv_ldap_set_rebind_proc)
++				AC_DEFINE(LDAP_SET_REBIND_PROC_ARGS, $ac_cv_ldap_set_rebind_proc, [number arguments of ldap_set_rebind_proc])
++			)
++		fi
++	]
++)
++AC_SUBST(INSTALL_SSH_LDAP_HELPER)
++
+ dnl    Checks for library functions. Please keep in alphabetical order
+ AC_CHECK_FUNCS([ \
+ 	Blowfish_initstate \
+diff -up openssh-6.8p1/ldap-helper.c.ldap openssh-6.8p1/ldap-helper.c
+--- openssh-6.8p1/ldap-helper.c.ldap	2015-03-18 11:11:29.030801464 +0100
++++ openssh-6.8p1/ldap-helper.c	2015-03-18 11:11:29.030801464 +0100
+@@ -0,0 +1,155 @@
++/* $OpenBSD: ssh-pka-ldap.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  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 "ldapincludes.h"
++#include "log.h"
++#include "misc.h"
++#include "xmalloc.h"
++#include "ldapconf.h"
++#include "ldapbody.h"
++#include <string.h>
++#include <unistd.h>
++
++static int config_debug = 0;
++int config_exclusive_config_file = 0;
++static char *config_file_name = "/etc/ssh/ldap.conf";
++static char *config_single_user = NULL;
++static int config_verbose = SYSLOG_LEVEL_VERBOSE;
++int config_warning_config_file = 0;
++extern char *__progname;
++
++static void
++usage(void)
++{
++	fprintf(stderr, "usage: %s [options]\n",
++	    __progname);
++	fprintf(stderr, "Options:\n");
++	fprintf(stderr, "  -d          Output the log messages to stderr.\n");
++	fprintf(stderr, "  -e          Check the config file for unknown commands.\n");
++	fprintf(stderr, "  -f file     Use alternate config file (default is /etc/ssh/ldap.conf).\n");
++	fprintf(stderr, "  -s user     Do not demonize, send the user's key to stdout.\n");
++	fprintf(stderr, "  -v          Increase verbosity of the debug output (implies -d).\n");
++	fprintf(stderr, "  -w          Warn on unknown commands in the config file.\n");
++	exit(1);
++}
++
++/*
++ * Main program for the ssh pka ldap agent.
++ */
++
++int
++main(int ac, char **av)
++{
++	int opt;
++	FILE *outfile = NULL;
++
++	__progname = ssh_get_progname(av[0]);
++
++	log_init(__progname, SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0);
++
++	/*
++	 * Initialize option structure to indicate that no values have been
++	 * set.
++	 */
++	initialize_options();
++
++	/* Parse command-line arguments. */
++	while ((opt = getopt(ac, av, "def:s:vw")) != -1) {
++		switch (opt) {
++		case 'd':
++			config_debug = 1;
++			break;
++
++		case 'e':
++			config_exclusive_config_file = 1;
++			config_warning_config_file = 1;
++			break;
++
++		case 'f':
++			config_file_name = optarg;
++			break;
++
++		case 's':
++			config_single_user = optarg;
++			outfile = fdopen (dup (fileno (stdout)), "w");
++			break;
++
++		case 'v':
++			config_debug = 1;
++			if (config_verbose < SYSLOG_LEVEL_DEBUG3)
++			    config_verbose++;
++			break;
++
++		case 'w':
++			config_warning_config_file = 1;
++			break;
++
++		case '?':
++		default:
++			usage();
++			break;
++		}
++	}
++
++	/* Initialize loging */
++	log_init(__progname, config_verbose, SYSLOG_FACILITY_AUTH, config_debug);
++
++	if (ac != optind)
++	    fatal ("illegal extra parameter %s", av[1]);
++
++	/* Ensure that fds 0 and 2 are open or directed to /dev/null */
++	if (config_debug == 0)
++	    sanitise_stdfd();
++
++	/* Read config file */
++	read_config_file(config_file_name);
++	fill_default_options();
++	if (config_verbose == SYSLOG_LEVEL_DEBUG3) {
++		debug3 ("=== Configuration ===");
++		dump_config();
++		debug3 ("=== *** ===");
++	}
++
++	ldap_checkconfig();
++	ldap_do_connect();
++
++	if (config_single_user) {
++		process_user (config_single_user, outfile);
++	} else {
++		usage();
++		fatal ("Not yet implemented");
++/* TODO
++ * open unix socket a run the loop on it
++ */
++	}
++
++	ldap_do_close();
++	return 0;
++}
++
++/* Ugly hack */
++void   *buffer_get_string(Buffer *b, u_int *l) { return NULL; }
++void    buffer_put_string(Buffer *b, const void *f, u_int l) {}
++
+diff -up openssh-6.8p1/ldap-helper.h.ldap openssh-6.8p1/ldap-helper.h
+--- openssh-6.8p1/ldap-helper.h.ldap	2015-03-18 11:11:29.031801462 +0100
++++ openssh-6.8p1/ldap-helper.h	2015-03-18 11:11:29.031801462 +0100
+@@ -0,0 +1,32 @@
++/* $OpenBSD: ldap-helper.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  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 LDAP_HELPER_H
++#define LDAP_HELPER_H
++
++extern int config_exclusive_config_file;
++extern int config_warning_config_file;
++
++#endif /* LDAP_HELPER_H */
+diff -up openssh-6.8p1/ldap.conf.ldap openssh-6.8p1/ldap.conf
+--- openssh-6.8p1/ldap.conf.ldap	2015-03-18 11:11:29.031801462 +0100
++++ openssh-6.8p1/ldap.conf	2015-03-18 11:11:29.031801462 +0100
+@@ -0,0 +1,95 @@
++# $Id: openssh-5.5p1-ldap.patch,v 1.3 2010/07/07 13:48:36 jfch2222 Exp $
++#
++# This is the example configuration file for the OpenSSH
++# LDAP backend
++# 
++# see ssh-ldap.conf(5)
++#
++
++# URI with your LDAP server name. This allows to use
++# Unix Domain Sockets to connect to a local LDAP Server.
++#uri ldap://127.0.0.1/
++#uri ldaps://127.0.0.1/   
++#uri ldapi://%2fvar%2frun%2fldapi_sock/
++# Note: %2f encodes the '/' used as directory separator
++
++# Another way to specify your LDAP server is to provide an
++# host name and the port of our LDAP server. Host name
++# must be resolvable without using LDAP.
++# Multiple hosts may be specified, each separated by a 
++# space. How long nss_ldap takes to failover depends on
++# whether your LDAP client library supports configurable
++# network or connect timeouts (see bind_timelimit).
++#host 127.0.0.1
++
++# The port.
++# Optional: default is 389.
++#port 389
++
++# The distinguished name to bind to the server with.
++# Optional: default is to bind anonymously.
++#binddn cn=openssh_keys,dc=example,dc=org
++
++# The credentials to bind with. 
++# Optional: default is no credential.
++#bindpw TopSecret
++
++# The distinguished name of the search base.
++#base dc=example,dc=org
++
++# The LDAP version to use (defaults to 3
++# if supported by client library)
++#ldap_version 3
++
++# The search scope.
++#scope sub
++#scope one
++#scope base
++
++# Search timelimit
++#timelimit 30
++
++# Bind/connect timelimit
++#bind_timelimit 30
++
++# Reconnect policy: hard (default) will retry connecting to
++# the software with exponential backoff, soft will fail
++# immediately.
++#bind_policy hard
++
++# SSL setup, may be implied by URI also.
++#ssl no
++#ssl on
++#ssl start_tls
++
++# OpenLDAP SSL options
++# Require and verify server certificate (yes/no)
++# Default is to use libldap's default behavior, which can be configured in
++# /etc/openldap/ldap.conf using the TLS_REQCERT setting.  The default for
++# OpenLDAP 2.0 and earlier is "no", for 2.1 and later is "yes".
++#tls_checkpeer hard
++
++# CA certificates for server certificate verification
++# At least one of these are required if tls_checkpeer is "yes"
++#tls_cacertfile /etc/ssl/ca.cert
++#tls_cacertdir /etc/pki/tls/certs
++
++# Seed the PRNG if /dev/urandom is not provided
++#tls_randfile /var/run/egd-pool
++
++# SSL cipher suite
++# See man ciphers for syntax
++#tls_ciphers TLSv1
++
++# Client certificate and key
++# Use these, if your server requires client authentication.
++#tls_cert
++#tls_key
++
++# OpenLDAP search_format
++# format used to search for users in LDAP directory using substitution
++# for %u for user name and %f for SSH_Filter option (optional, empty by default)
++#search_format (&(objectclass=%c)(objectclass=ldapPublicKey)(uid=%u)%f)
++
++#AccountClass posixAccount
++
+diff -up openssh-6.8p1/ldapbody.c.ldap openssh-6.8p1/ldapbody.c
+--- openssh-6.8p1/ldapbody.c.ldap	2015-03-18 11:11:29.031801462 +0100
++++ openssh-6.8p1/ldapbody.c	2015-03-18 11:11:29.031801462 +0100
+@@ -0,0 +1,493 @@
++/* $OpenBSD: ldapbody.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  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 "ldapincludes.h"
++#include "log.h"
++#include "xmalloc.h"
++#include "ldapconf.h"
++#include "ldapmisc.h"
++#include "ldapbody.h"
++#include <stdio.h>
++#include <unistd.h>
++#include "misc.h"
++
++#define LDAPSEARCH_FORMAT "(&(objectclass=%c)(objectclass=ldapPublicKey)(uid=%u)%f)"
++#define PUBKEYATTR "sshPublicKey"
++#define LDAP_LOGFILE	"%s/ldap.%d"
++
++static FILE *logfile = NULL;
++static LDAP *ld;
++
++static char *attrs[] = {
++    PUBKEYATTR,
++    NULL
++};
++
++void
++ldap_checkconfig (void)
++{
++#ifdef HAVE_LDAP_INITIALIZE
++		if (options.host == NULL && options.uri == NULL)
++#else
++		if (options.host == NULL)
++#endif
++		    fatal ("missing  \"host\" in config file");
++}
++
++#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
++static int
++_rebind_proc (LDAP * ld, LDAP_CONST char *url, int request, ber_int_t msgid)
++{
++	struct timeval timeout;
++	int rc;
++#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE)
++	LDAPMessage *result;
++#endif /* HAVE_LDAP_PARSE_RESULT && HAVE_LDAP_CONTROLS_FREE */
++
++	debug2 ("Doing LDAP rebind to %s", options.binddn);
++	if (options.ssl == SSL_START_TLS) {
++		if ((rc = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS) {
++			error ("ldap_starttls_s: %s", ldap_err2string (rc));
++			return LDAP_OPERATIONS_ERROR;
++		}
++	}
++
++#if !defined(HAVE_LDAP_PARSE_RESULT) || !defined(HAVE_LDAP_CONTROLS_FREE)
++	return ldap_simple_bind_s (ld, options.binddn, options.bindpw);
++#else
++	if (ldap_simple_bind(ld, options.binddn, options.bindpw) < 0)
++	    fatal ("ldap_simple_bind %s", ldap_err2string (ldap_get_lderrno (ld, 0, 0)));
++
++	timeout.tv_sec = options.bind_timelimit;
++	timeout.tv_usec = 0;
++	result = NULL;
++	if ((rc = ldap_result (ld, msgid, FALSE, &timeout, &result)) < 1) {
++		error ("ldap_result %s", ldap_err2string (ldap_get_lderrno (ld, 0, 0)));
++		ldap_msgfree (result);
++		return LDAP_OPERATIONS_ERROR;
++	}
++	debug3 ("LDAP rebind to %s succesfull", options.binddn);
++	return rc;
++#endif
++}
++#else
++
++static int
++_rebind_proc (LDAP * ld, char **whop, char **credp, int *methodp, int freeit)
++{
++	if (freeit)
++	    return LDAP_SUCCESS;
++
++	*whop = strdup (options.binddn);
++	*credp = strdup (options.bindpw);
++	*methodp = LDAP_AUTH_SIMPLE;
++	debug2 ("Doing LDAP rebind for %s", *whop);
++	return LDAP_SUCCESS;
++}
++#endif
++
++void
++ldap_do_connect(void)
++{
++	int rc, msgid, ld_errno = 0;
++	struct timeval timeout;
++#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE)
++	int parserc;
++	LDAPMessage *result;
++	LDAPControl **controls;
++	int reconnect = 0;
++#endif /* HAVE_LDAP_PARSE_RESULT && HAVE_LDAP_CONTROLS_FREE */
++
++	debug ("LDAP do connect");
++
++retry:
++	if (reconnect) {
++		debug3 ("Reconnecting with ld_errno %d", ld_errno);
++		if (options.bind_policy == 0 ||
++		    (ld_errno != LDAP_SERVER_DOWN && ld_errno != LDAP_TIMEOUT) ||
++			reconnect > 5)
++			    fatal ("Cannot connect to LDAP server");
++	
++		if (reconnect > 1)
++			sleep (reconnect - 1);
++
++		if (ld != NULL) {
++			ldap_unbind (ld);
++			ld = NULL;
++		}
++		logit("reconnecting to LDAP server...");
++	}
++
++	if (ld == NULL) {
++		int rc;
++		struct timeval tv;
++
++#ifdef HAVE_LDAP_SET_OPTION
++		if (options.debug > 0) {
++#ifdef LBER_OPT_LOG_PRINT_FILE
++			if (options.logdir) {
++				char *logfilename;
++				int logfilenamelen;
++
++				logfilenamelen = strlen (LDAP_LOGFILE) + strlen ("000000") + strlen (options.logdir);
++				logfilename = xmalloc (logfilenamelen);
++				snprintf (logfilename, logfilenamelen, LDAP_LOGFILE, options.logdir, (int) getpid ());
++				logfilename[logfilenamelen - 1] = 0;
++				if ((logfile = fopen (logfilename, "a")) == NULL)
++				    fatal ("cannot append to %s: %s", logfilename, strerror (errno));
++				debug3 ("LDAP debug into %s", logfilename);
++				free (logfilename);
++				ber_set_option (NULL, LBER_OPT_LOG_PRINT_FILE, logfile);
++			}
++#endif
++			if (options.debug) {
++#ifdef LBER_OPT_DEBUG_LEVEL
++				ber_set_option (NULL, LBER_OPT_DEBUG_LEVEL, &options.debug);
++#endif /* LBER_OPT_DEBUG_LEVEL */
++#ifdef LDAP_OPT_DEBUG_LEVEL
++				(void) ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &options.debug);
++#endif /* LDAP_OPT_DEBUG_LEVEL */
++				debug3 ("Set LDAP debug to %d", options.debug);
++			}
++		}
++#endif /* HAVE_LDAP_SET_OPTION */
++
++		ld = NULL;
++#ifdef HAVE_LDAPSSL_INIT
++		if (options.host != NULL) {
++			if (options.ssl_on == SSL_LDAPS) {
++				if ((rc = ldapssl_client_init (options.sslpath, NULL)) != LDAP_SUCCESS)
++				    fatal ("ldapssl_client_init %s", ldap_err2string (rc));
++				debug3 ("LDAPssl client init");
++			}
++
++			if (options.ssl_on != SSL_OFF) {
++				if ((ld = ldapssl_init (options.host, options.port, TRUE)) == NULL)
++				    fatal ("ldapssl_init failed");
++				debug3 ("LDAPssl init");
++			}
++		}
++#endif /* HAVE_LDAPSSL_INIT */
++
++		/* continue with opening */
++		if (ld == NULL) {
++#if defined (HAVE_LDAP_START_TLS_S) || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS))
++			/* Some global TLS-specific options need to be set before we create our
++			 * session context, so we set them here. */
++
++#ifdef LDAP_OPT_X_TLS_RANDOM_FILE
++			/* rand file */
++			if (options.tls_randfile != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
++				    options.tls_randfile)) != LDAP_SUCCESS)
++					fatal ("ldap_set_option(LDAP_OPT_X_TLS_RANDOM_FILE): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS random file %s", options.tls_randfile);
++			}
++#endif /* LDAP_OPT_X_TLS_RANDOM_FILE */
++
++			/* ca cert file */
++			if (options.tls_cacertfile != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE,
++				    options.tls_cacertfile)) != LDAP_SUCCESS)
++					error ("ldap_set_option(LDAP_OPT_X_TLS_CACERTFILE): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS CA cert file %s ", options.tls_cacertfile);
++			}
++
++			/* ca cert directory */
++			if (options.tls_cacertdir != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR,
++				    options.tls_cacertdir)) != LDAP_SUCCESS)
++					fatal ("ldap_set_option(LDAP_OPT_X_TLS_CACERTDIR): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS CA cert dir %s ", options.tls_cacertdir);
++			}
++
++			/* require cert? */
++			if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
++			    &options.tls_checkpeer)) != LDAP_SUCCESS)
++				fatal ("ldap_set_option(LDAP_OPT_X_TLS_REQUIRE_CERT): %s",
++				    ldap_err2string (rc));
++			debug3 ("Set TLS check peer to %d ", options.tls_checkpeer);
++
++			/* set cipher suite, certificate and private key: */
++			if (options.tls_ciphers != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
++				    options.tls_ciphers)) != LDAP_SUCCESS)
++					fatal ("ldap_set_option(LDAP_OPT_X_TLS_CIPHER_SUITE): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS ciphers to %s ", options.tls_ciphers);
++			}
++
++			/* cert file */
++			if (options.tls_cert != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE,
++				    options.tls_cert)) != LDAP_SUCCESS)
++					fatal ("ldap_set_option(LDAP_OPT_X_TLS_CERTFILE): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS cert file %s ", options.tls_cert);
++			}
++
++			/* key file */
++			if (options.tls_key != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE,
++				    options.tls_key)) != LDAP_SUCCESS)
++					fatal ("ldap_set_option(LDAP_OPT_X_TLS_KEYFILE): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS key file %s ", options.tls_key);
++			}
++#endif
++#ifdef HAVE_LDAP_INITIALIZE
++			if (options.uri != NULL) {
++				if ((rc = ldap_initialize (&ld, options.uri)) != LDAP_SUCCESS)
++					fatal ("ldap_initialize %s", ldap_err2string (rc));
++				debug3 ("LDAP initialize %s", options.uri);
++			}
++	}
++#endif /* HAVE_LDAP_INTITIALIZE */
++
++		/* continue with opening */
++		if ((ld == NULL) && (options.host != NULL)) {
++#ifdef HAVE_LDAP_INIT
++			if ((ld = ldap_init (options.host, options.port)) == NULL)
++			    fatal ("ldap_init failed");
++			debug3 ("LDAP init %s:%d", options.host, options.port);
++#else
++			if ((ld = ldap_open (options.host, options.port)) == NULL)
++			    fatal ("ldap_open failed");
++			debug3 ("LDAP open %s:%d", options.host, options.port);
++#endif /* HAVE_LDAP_INIT */
++		}
++
++		if (ld == NULL)
++			fatal ("no way to open ldap");
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
++		if (options.ssl == SSL_LDAPS) {
++			if ((rc = ldap_set_option (ld, LDAP_OPT_X_TLS, &options.tls_checkpeer)) != LDAP_SUCCESS)
++				fatal ("ldap_set_option(LDAP_OPT_X_TLS) %s", ldap_err2string (rc));
++			debug3 ("LDAP set LDAP_OPT_X_TLS_%d", options.tls_checkpeer);
++		}
++#endif /* LDAP_OPT_X_TLS */
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_PROTOCOL_VERSION)
++		(void) ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION,
++		    &options.ldap_version);
++#else
++		ld->ld_version = options.ldap_version;
++#endif
++		debug3 ("LDAP set version to %d", options.ldap_version);
++
++#if LDAP_SET_REBIND_PROC_ARGS == 3
++		ldap_set_rebind_proc (ld, _rebind_proc, NULL);
++#elif LDAP_SET_REBIND_PROC_ARGS == 2
++		ldap_set_rebind_proc (ld, _rebind_proc);
++#else
++#warning unknown LDAP_SET_REBIND_PROC_ARGS
++#endif
++		debug3 ("LDAP set rebind proc");
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_DEREF)
++		(void) ldap_set_option (ld, LDAP_OPT_DEREF, &options.deref);
++#else
++		ld->ld_deref = options.deref;
++#endif
++		debug3 ("LDAP set deref to %d", options.deref);
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_TIMELIMIT)
++		(void) ldap_set_option (ld, LDAP_OPT_TIMELIMIT,
++		    &options.timelimit);
++#else
++		ld->ld_timelimit = options.timelimit;
++#endif
++		debug3 ("LDAP set timelimit to %d", options.timelimit);
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_X_OPT_CONNECT_TIMEOUT)
++		/*
++		 * This is a new option in the Netscape SDK which sets 
++		 * the TCP connect timeout. For want of a better value,
++		 * we use the bind_timelimit to control this.
++		 */
++		timeout = options.bind_timelimit * 1000;
++		(void) ldap_set_option (ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout);
++		debug3 ("LDAP set opt connect timeout to %d", timeout);
++#endif
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_NETWORK_TIMEOUT)
++		tv.tv_sec = options.bind_timelimit;
++		tv.tv_usec = 0;
++		(void) ldap_set_option (ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
++		debug3 ("LDAP set opt network timeout to %ld.0", tv.tv_sec);
++#endif
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_REFERRALS)
++		(void) ldap_set_option (ld, LDAP_OPT_REFERRALS,
++		    options.referrals ? LDAP_OPT_ON : LDAP_OPT_OFF);
++		debug3 ("LDAP set referrals to %d", options.referrals);
++#endif
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_RESTART)
++		(void) ldap_set_option (ld, LDAP_OPT_RESTART,
++		    options.restart ? LDAP_OPT_ON : LDAP_OPT_OFF);
++		debug3 ("LDAP set restart to %d", options.restart);
++#endif
++
++#ifdef HAVE_LDAP_START_TLS_S
++		if (options.ssl == SSL_START_TLS) {
++			int version;
++
++			if (ldap_get_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version)
++			    == LDAP_SUCCESS) {
++				if (version < LDAP_VERSION3) {
++					version = LDAP_VERSION3;
++					(void) ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION,
++					    &version);
++					debug3 ("LDAP set version to %d", version);
++				}
++			}
++
++			if ((rc = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS)
++			    fatal ("ldap_starttls_s: %s", ldap_err2string (rc));
++			debug3 ("LDAP start TLS");
++		}
++#endif /* HAVE_LDAP_START_TLS_S */
++	}
++
++	if ((msgid = ldap_simple_bind (ld, options.binddn,
++	    options.bindpw)) == -1) {
++		ld_errno = ldap_get_lderrno (ld, 0, 0);
++
++		error ("ldap_simple_bind %s", ldap_err2string (ld_errno));
++		reconnect++;
++		goto retry;
++	}
++	debug3 ("LDAP simple bind (%s)", options.binddn);
++
++	timeout.tv_sec = options.bind_timelimit;
++	timeout.tv_usec = 0;
++	if ((rc = ldap_result (ld, msgid, FALSE, &timeout, &result)) < 1) {
++		ld_errno = ldap_get_lderrno (ld, 0, 0);
++
++		error ("ldap_result %s", ldap_err2string (ld_errno));
++		reconnect++;
++		goto retry;
++	}
++	debug3 ("LDAP result in time");
++
++#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE)
++	controls = NULL;
++	if ((parserc = ldap_parse_result (ld, result, &rc, 0, 0, 0, &controls, TRUE)) != LDAP_SUCCESS)
++	    fatal ("ldap_parse_result %s", ldap_err2string (parserc));
++	debug3 ("LDAP parse result OK");
++
++	if (controls != NULL) {
++		ldap_controls_free (controls);
++	}
++#else
++	rc = ldap_result2error (session->ld, result, TRUE);
++#endif
++	if (rc != LDAP_SUCCESS)
++	    fatal ("error trying to bind as user \"%s\" (%s)",
++		options.binddn, ldap_err2string (rc));
++
++	debug2 ("LDAP do connect OK");
++}
++
++void
++process_user (const char *user, FILE *output)
++{
++	LDAPMessage *res, *e;
++	char *buffer, *format;
++	int rc, i;
++	struct timeval timeout;
++
++	debug ("LDAP process user");
++
++	/* quick check for attempts to be evil */
++	if ((strchr(user, '(') != NULL) || (strchr(user, ')') != NULL) ||
++	    (strchr(user, '*') != NULL) || (strchr(user, '\\') != NULL)) {
++		logit ("illegal user name %s not processed", user);
++		return;
++	}
++
++	/* build  filter for LDAP request */
++	format = LDAPSEARCH_FORMAT;
++	if (options.search_format != NULL)
++		format = options.search_format;
++	buffer = percent_expand(format, "c", options.account_class, "u", user, "f", options.ssh_filter, (char *)NULL);
++
++	debug3 ("LDAP search scope = %d %s", options.scope, buffer);
++
++	timeout.tv_sec = options.timelimit;
++	timeout.tv_usec = 0;
++	if ((rc = ldap_search_st(ld, options.base, options.scope, buffer, attrs, 0, &timeout, &res)) != LDAP_SUCCESS) {
++		error ("ldap_search_st(): %s", ldap_err2string (rc));
++		free (buffer);
++		return;
++	}
++
++	/* free */
++	free (buffer);
++
++	for (e = ldap_first_entry(ld, res); e != NULL; e = ldap_next_entry(ld, e)) {
++		int num;
++		struct berval **keys;
++
++		keys = ldap_get_values_len(ld, e, PUBKEYATTR);
++		num = ldap_count_values_len(keys);
++		for (i = 0 ; i < num ; i++) {
++			char *cp; //, *options = NULL;
++
++			for (cp = keys[i]->bv_val; *cp == ' ' || *cp == '\t'; cp++);
++			if (!*cp || *cp == '\n' || *cp == '#')
++			    continue;
++
++			/* We have found the desired key. */
++			fprintf (output, "%s\n", keys[i]->bv_val);
++		}
++
++		ldap_value_free_len(keys);
++	}
++
++	ldap_msgfree(res);
++	debug2 ("LDAP process user finished");
++}
++
++void
++ldap_do_close(void)
++{
++	int rc;
++
++	debug ("LDAP do close");
++	if ((rc = ldap_unbind_ext(ld, NULL, NULL)) != LDAP_SUCCESS)
++	    fatal ("ldap_unbind_ext: %s",
++                                    ldap_err2string (rc));
++
++	ld = NULL;
++	debug2 ("LDAP do close OK");
++	return;
++}
++
+diff -up openssh-6.8p1/ldapbody.h.ldap openssh-6.8p1/ldapbody.h
+--- openssh-6.8p1/ldapbody.h.ldap	2015-03-18 11:11:29.031801462 +0100
++++ openssh-6.8p1/ldapbody.h	2015-03-18 11:11:29.031801462 +0100
+@@ -0,0 +1,37 @@
++/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  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 LDAPBODY_H
++#define LDAPBODY_H
++
++#include <stdio.h>
++
++void ldap_checkconfig(void);
++void ldap_do_connect(void);
++void process_user(const char *, FILE *);
++void ldap_do_close(void);
++
++#endif /* LDAPBODY_H */
++
+diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c
+--- openssh-6.8p1/ldapconf.c.ldap	2015-03-18 11:11:29.032801460 +0100
++++ openssh-6.8p1/ldapconf.c	2015-03-18 11:11:29.032801460 +0100
+@@ -0,0 +1,728 @@
++/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  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 "ldapincludes.h"
++#include "ldap-helper.h"
++#include "log.h"
++#include "misc.h"
++#include "xmalloc.h"
++#include "ldapconf.h"
++#include <unistd.h>
++#include <string.h>
++
++/* Keyword tokens. */
++
++typedef enum {
++	lBadOption,
++	lHost, lURI, lBase, lBindDN, lBindPW, lRootBindDN,
++	lScope, lDeref, lPort, lTimeLimit, lBind_TimeLimit,
++	lLdap_Version, lBind_Policy, lSSLPath, lSSL, lReferrals,
++	lRestart, lTLS_CheckPeer, lTLS_CaCertFile,
++	lTLS_CaCertDir, lTLS_Ciphers, lTLS_Cert, lTLS_Key,
++	lTLS_RandFile, lLogDir, lDebug, lSSH_Filter, lSearch_Format,
++	lAccountClass, lDeprecated, lUnsupported
++} OpCodes;
++
++/* Textual representations of the tokens. */
++
++static struct {
++	const char *name;
++	OpCodes opcode;
++} keywords[] = {
++	{ "URI", lURI },
++	{ "Base", lBase },
++	{ "BindDN", lBindDN },
++	{ "BindPW", lBindPW },
++	{ "RootBindDN", lRootBindDN },
++	{ "Host", lHost },
++	{ "Port", lPort },
++	{ "Scope", lScope },
++	{ "Deref", lDeref },
++	{ "TimeLimit", lTimeLimit },
++	{ "TimeOut", lTimeLimit },
++	{ "Bind_Timelimit", lBind_TimeLimit },
++	{ "Network_TimeOut", lBind_TimeLimit },
++/*
++ * Todo
++ * SIZELIMIT
++ */
++	{ "Ldap_Version", lLdap_Version },
++	{ "Version", lLdap_Version },
++	{ "Bind_Policy", lBind_Policy },
++	{ "SSLPath", lSSLPath },
++	{ "SSL", lSSL },
++	{ "Referrals", lReferrals },
++	{ "Restart", lRestart },
++	{ "TLS_CheckPeer", lTLS_CheckPeer },
++	{ "TLS_ReqCert", lTLS_CheckPeer },
++	{ "TLS_CaCertFile", lTLS_CaCertFile },
++	{ "TLS_CaCert", lTLS_CaCertFile },
++	{ "TLS_CaCertDir", lTLS_CaCertDir },
++	{ "TLS_Ciphers", lTLS_Ciphers },
++	{ "TLS_Cipher_Suite", lTLS_Ciphers },
++	{ "TLS_Cert", lTLS_Cert },
++	{ "TLS_Certificate", lTLS_Cert },
++	{ "TLS_Key", lTLS_Key },
++	{ "TLS_RandFile", lTLS_RandFile },
++/*
++ * Todo
++ * TLS_CRLCHECK
++ * TLS_CRLFILE
++ */
++	{ "LogDir", lLogDir },
++	{ "Debug", lDebug },
++	{ "SSH_Filter", lSSH_Filter },
++	{ "search_format", lSearch_Format },
++	{ "AccountClass", lAccountClass },
++	{ NULL, lBadOption }
++};
++
++/* Configuration ptions. */
++
++Options options;
++
++/*
++ * Returns the number of the token pointed to by cp or oBadOption.
++ */
++
++static OpCodes
++parse_token(const char *cp, const char *filename, int linenum)
++{
++	u_int i;
++
++	for (i = 0; keywords[i].name; i++)
++		if (strcasecmp(cp, keywords[i].name) == 0)
++			return keywords[i].opcode;
++
++	if (config_warning_config_file) 
++	    logit("%s: line %d: Bad configuration option: %s",
++		filename, linenum, cp);
++	return lBadOption;
++}
++
++/* Characters considered whitespace in strsep calls. */
++#define WHITESPACE " \t\r\n"
++
++/* return next token in configuration line */
++static char *
++ldap_strdelim(char **s)
++{
++      char *old;
++      int wspace = 0;
++
++      if (*s == NULL)
++              return NULL;
++
++      old = *s;
++
++      *s = strpbrk(*s, WHITESPACE);
++      if (*s == NULL)
++              return (old);
++
++      *s[0] = '\0';
++
++      /* Skip any extra whitespace after first token */
++      *s += strspn(*s + 1, WHITESPACE) + 1;
++      if (*s[0] == '=' && !wspace)
++              *s += strspn(*s + 1, WHITESPACE) + 1;
++
++      return (old);
++}
++
++/*
++ * Processes a single option line as used in the configuration files. This
++ * only sets those values that have not already been set.
++ */
++#define WHITESPACE " \t\r\n"
++
++static int
++process_config_line(char *line, const char *filename, int linenum)
++{
++	char *s, **charptr, **xstringptr, *endofnumber, *keyword, *arg;
++	char *rootbinddn = NULL;
++	int opcode, *intptr, value;
++	size_t len;
++
++	/* Strip trailing whitespace */
++	for (len = strlen(line) - 1; len > 0; len--) {
++		if (strchr(WHITESPACE, line[len]) == NULL)
++			break;
++		line[len] = '\0';
++	}
++
++	s = line;
++	/* Get the keyword. (Each line is supposed to begin with a keyword). */
++	if ((keyword = ldap_strdelim(&s)) == NULL)
++		return 0;
++	/* Ignore leading whitespace. */
++	if (*keyword == '\0')
++		keyword = ldap_strdelim(&s);
++	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
++		return 0;
++
++	opcode = parse_token(keyword, filename, linenum);
++
++	switch (opcode) {
++	case lBadOption:
++		/* don't panic, but count bad options */
++		return -1;
++		/* NOTREACHED */
++
++	case lHost:
++		xstringptr = &options.host;
++parse_xstring:
++		if (!s || *s == '\0')
++		    fatal("%s line %d: missing dn",filename,linenum);
++		if (*xstringptr == NULL)
++		    *xstringptr = xstrdup(s);
++		return 0;
++
++	case lURI:
++		xstringptr = &options.uri;
++		goto parse_xstring;
++
++	case lBase:
++		xstringptr = &options.base;
++		goto parse_xstring;
++
++	case lBindDN:
++		xstringptr = &options.binddn;
++		goto parse_xstring;
++
++	case lBindPW:
++		charptr = &options.bindpw;
++parse_string:
++		arg = ldap_strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing argument.", filename, linenum);
++		if (*charptr == NULL)
++			*charptr = xstrdup(arg);
++		break;
++
++	case lRootBindDN:
++		xstringptr = &rootbinddn;
++		goto parse_xstring;
++
++	case lScope:
++		intptr = &options.scope;
++		arg = ldap_strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing sub/one/base argument.", filename, linenum);
++		value = 0;	/* To avoid compiler warning... */
++		if (strcasecmp (arg, "sub") == 0 || strcasecmp (arg, "subtree") == 0)
++			value = LDAP_SCOPE_SUBTREE;
++		else if (strcasecmp (arg, "one") == 0)
++			value = LDAP_SCOPE_ONELEVEL;
++		else if (strcasecmp (arg, "base") == 0)
++			value = LDAP_SCOPE_BASE;
++		else
++			fatal("%.200s line %d: Bad sub/one/base argument.", filename, linenum);
++		if (*intptr == -1)
++			*intptr = value;
++		break;
++
++	case lDeref:
++		intptr = &options.scope;
++		arg = ldap_strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing never/searching/finding/always argument.", filename, linenum);
++		value = 0;	/* To avoid compiler warning... */
++		if (!strcasecmp (arg, "never"))
++			value = LDAP_DEREF_NEVER;
++		else if (!strcasecmp (arg, "searching"))
++			value = LDAP_DEREF_SEARCHING;
++		else if (!strcasecmp (arg, "finding"))
++			value = LDAP_DEREF_FINDING;
++		else if (!strcasecmp (arg, "always"))
++			value = LDAP_DEREF_ALWAYS;
++		else
++			fatal("%.200s line %d: Bad never/searching/finding/always argument.", filename, linenum);
++		if (*intptr == -1)
++			*intptr = value;
++		break;
++
++	case lPort:
++		intptr = &options.port;
++parse_int:
++		arg = ldap_strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing argument.", filename, linenum);
++		if (arg[0] < '0' || arg[0] > '9')
++			fatal("%.200s line %d: Bad number.", filename, linenum);
++
++		/* Octal, decimal, or hex format? */
++		value = strtol(arg, &endofnumber, 0);
++		if (arg == endofnumber)
++			fatal("%.200s line %d: Bad number.", filename, linenum);
++		if (*intptr == -1)
++			*intptr = value;
++		break;
++
++	case lTimeLimit:
++		intptr = &options.timelimit;
++parse_time:
++		arg = ldap_strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%s line %d: missing time value.",
++			    filename, linenum);
++		if ((value = convtime(arg)) == -1)
++			fatal("%s line %d: invalid time value.",
++			    filename, linenum);
++		if (*intptr == -1)
++			*intptr = value;
++		break;
++
++	case lBind_TimeLimit:
++		intptr = &options.bind_timelimit;
++		goto parse_time;
++
++	case lLdap_Version:
++		intptr = &options.ldap_version;
++		goto parse_int;
++
++	case lBind_Policy:
++		intptr = &options.bind_policy;
++		arg = ldap_strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing soft/hard argument.", filename, linenum);
++		value = 0;	/* To avoid compiler warning... */
++		if (strcasecmp(arg, "hard") == 0 || strcasecmp(arg, "hard_open") == 0 || strcasecmp(arg, "hard_init") == 0)
++			value = 1;
++		else if (strcasecmp(arg, "soft") == 0)
++			value = 0;
++		else
++			fatal("%.200s line %d: Bad soft/hard argument.", filename, linenum);
++		if (*intptr == -1)
++			*intptr = value;
++		break;
++
++	case lSSLPath:
++		charptr = &options.sslpath;
++		goto parse_string;
++
++	case lSSL:
++		intptr = &options.ssl;
++		arg = ldap_strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing yes/no/start_tls argument.", filename, linenum);
++		value = 0;	/* To avoid compiler warning... */
++		if (strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0 || strcasecmp(arg, "on") == 0)
++			value = SSL_LDAPS;
++		else if (strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0 || strcasecmp(arg, "off") == 0)
++			value = SSL_OFF;
++		else if (!strcasecmp (arg, "start_tls"))
++			value = SSL_START_TLS;
++		else
++			fatal("%.200s line %d: Bad yes/no/start_tls argument.", filename, linenum);
++		if (*intptr == -1)
++			*intptr = value;
++		break;
++
++	case lReferrals:
++		intptr = &options.referrals;
++parse_flag:
++		arg = ldap_strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
++		value = 0;	/* To avoid compiler warning... */
++		if (strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0 || strcasecmp(arg, "on") == 0)
++			value = 1;
++		else if (strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0 || strcasecmp(arg, "off") == 0)
++			value = 0;
++		else
++			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
++		if (*intptr == -1)
++			*intptr = value;
++		break;
++
++	case lRestart:
++		intptr = &options.restart;
++		goto parse_flag;
++
++	case lTLS_CheckPeer:
++		intptr = &options.tls_checkpeer;
++		arg = ldap_strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing never/hard/demand/alow/try argument.", filename, linenum);
++		value = 0;	/* To avoid compiler warning... */
++		if (strcasecmp(arg, "never") == 0 || strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0 || strcasecmp(arg, "off") == 0)
++			value = LDAP_OPT_X_TLS_NEVER;
++		else if (strcasecmp(arg, "hard") == 0 || strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0 || strcasecmp(arg, "on") == 0)
++			value = LDAP_OPT_X_TLS_HARD;
++		else if (strcasecmp(arg, "demand") == 0)
++			value = LDAP_OPT_X_TLS_DEMAND;
++		else if (strcasecmp(arg, "allow") == 0)
++			value = LDAP_OPT_X_TLS_ALLOW;
++		else if (strcasecmp(arg, "try") == 0)
++			value = LDAP_OPT_X_TLS_TRY;
++		else
++			fatal("%.200s line %d: Bad never/hard/demand/alow/try argument.", filename, linenum);
++		if (*intptr == -1)
++			*intptr = value;
++		break;
++
++	case lTLS_CaCertFile:
++		charptr = &options.tls_cacertfile;
++		goto parse_string;
++
++	case lTLS_CaCertDir:
++		charptr = &options.tls_cacertdir;
++		goto parse_string;
++
++	case lTLS_Ciphers:
++		xstringptr = &options.tls_ciphers;
++		goto parse_xstring;
++
++	case lTLS_Cert:
++		charptr = &options.tls_cert;
++		goto parse_string;
++
++	case lTLS_Key:
++		charptr = &options.tls_key;
++		goto parse_string;
++
++	case lTLS_RandFile:
++		charptr = &options.tls_randfile;
++		goto parse_string;
++
++	case lLogDir:
++		charptr = &options.logdir;
++		goto parse_string;
++
++	case lDebug:
++		intptr = &options.debug;
++		goto parse_int;
++
++	case lSSH_Filter:
++		xstringptr = &options.ssh_filter;
++		goto parse_xstring;
++
++	case lSearch_Format:
++		charptr = &options.search_format;
++		goto parse_string;
++
++	case lAccountClass:
++		charptr = &options.account_class;
++		goto parse_string;
++
++	case lDeprecated:
++		debug("%s line %d: Deprecated option \"%s\"",
++		    filename, linenum, keyword);
++		return 0;
++
++	case lUnsupported:
++		error("%s line %d: Unsupported option \"%s\"",
++		    filename, linenum, keyword);
++		return 0;
++
++	default:
++		fatal("process_config_line: Unimplemented opcode %d", opcode);
++	}
++
++	/* Check that there is no garbage at end of line. */
++	if ((arg = ldap_strdelim(&s)) != NULL && *arg != '\0') {
++		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
++		    filename, linenum, arg);
++	}
++	return 0;
++}
++
++/*
++ * Reads the config file and modifies the options accordingly.  Options
++ * should already be initialized before this call.  This never returns if
++ * there is an error.  If the file does not exist, this returns 0.
++ */
++
++void
++read_config_file(const char *filename)
++{
++	FILE *f;
++	char line[1024];
++	int linenum;
++	int bad_options = 0;
++	struct stat sb;
++
++	if ((f = fopen(filename, "r")) == NULL)
++		fatal("fopen %s: %s", filename, strerror(errno));
++
++	if (fstat(fileno(f), &sb) == -1)
++		fatal("fstat %s: %s", filename, strerror(errno));
++	if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
++	    (sb.st_mode & 022) != 0))
++		fatal("Bad owner or permissions on %s", filename);
++
++	debug("Reading configuration data %.200s", filename);
++
++	/*
++	 * Mark that we are now processing the options.  This flag is turned
++	 * on/off by Host specifications.
++	 */
++	linenum = 0;
++	while (fgets(line, sizeof(line), f)) {
++		/* Update line number counter. */
++		linenum++;
++		if (process_config_line(line, filename, linenum) != 0)
++			bad_options++;
++	}
++	fclose(f);
++	if ((bad_options > 0) && config_exclusive_config_file) 
++		fatal("%s: terminating, %d bad configuration options",
++		    filename, bad_options);
++}
++
++/*
++ * Initializes options to special values that indicate that they have not yet
++ * been set.  Read_config_file will only set options with this value. Options
++ * are processed in the following order: command line, user config file,
++ * system config file.  Last, fill_default_options is called.
++ */
++
++void
++initialize_options(void)
++{
++	memset(&options, 'X', sizeof(options));
++	options.host = NULL;
++	options.uri = NULL;
++	options.base = NULL;
++	options.binddn = NULL;
++	options.bindpw = NULL;
++	options.scope = -1;
++	options.deref = -1;
++	options.port = -1;
++	options.timelimit = -1;
++	options.bind_timelimit = -1;
++	options.ldap_version = -1;
++	options.bind_policy = -1;
++	options.sslpath = NULL;
++	options.ssl = -1;
++	options.referrals = -1;
++	options.restart = -1;
++	options.tls_checkpeer = -1;
++	options.tls_cacertfile = NULL;
++	options.tls_cacertdir = NULL;
++	options.tls_ciphers = NULL;
++	options.tls_cert = NULL;
++	options.tls_key = NULL;
++	options.tls_randfile = NULL;
++	options.logdir = NULL;
++	options.debug = -1;
++	options.ssh_filter = NULL;
++	options.search_format = NULL;
++	options.account_class = NULL;
++}
++
++/*
++ * Called after processing other sources of option data, this fills those
++ * options for which no value has been specified with their default values.
++ */
++
++void
++fill_default_options(void)
++{
++	if (options.uri != NULL) {
++		LDAPURLDesc *ludp;
++
++		if (ldap_url_parse(options.uri, &ludp) == LDAP_SUCCESS) {
++			if (options.ssl == -1) {
++				if (strcmp (ludp->lud_scheme, "ldap") == 0)
++				    options.ssl = 2;
++				if (strcmp (ludp->lud_scheme, "ldapi") == 0)
++				    options.ssl = 0;
++				else if (strcmp (ludp->lud_scheme, "ldaps") == 0)
++				    options.ssl = 1;
++			}
++			if (options.host == NULL)
++			    options.host = xstrdup (ludp->lud_host);
++			if (options.port == -1)
++			    options.port = ludp->lud_port;
++
++			ldap_free_urldesc (ludp);
++		}
++	} 
++	if (options.ssl == -1)
++	    options.ssl = SSL_START_TLS;
++	if (options.port == -1)
++	    options.port = (options.ssl == 0) ? 389 : 636;
++	if (options.uri == NULL) {
++		int len;
++#define MAXURILEN 4096
++
++		options.uri = xmalloc (MAXURILEN);
++		len = snprintf (options.uri, MAXURILEN, "ldap%s://%s:%d",
++		    (options.ssl == 0) ? "" : "s", options.host, options.port);
++		options.uri[MAXURILEN - 1] = 0;
++		options.uri = xrealloc (options.uri, len + 1, 1);
++	}
++	if (options.binddn == NULL)
++	    options.binddn = "";
++	if (options.bindpw == NULL)
++	    options.bindpw = "";
++	if (options.scope == -1)
++	    options.scope = LDAP_SCOPE_SUBTREE;
++	if (options.deref == -1)
++	    options.deref = LDAP_DEREF_NEVER;
++	if (options.timelimit == -1)
++	    options.timelimit = 10;
++	if (options.bind_timelimit == -1)
++	    options.bind_timelimit = 10;
++	if (options.ldap_version == -1)
++	    options.ldap_version = 3;
++	if (options.bind_policy == -1)
++	    options.bind_policy = 1;
++	if (options.referrals == -1)
++	    options.referrals = 1;
++	if (options.restart == -1)
++	    options.restart = 1;
++	if (options.tls_checkpeer == -1)
++	    options.tls_checkpeer = LDAP_OPT_X_TLS_HARD;
++	if (options.debug == -1)
++	    options.debug = 0;
++	if (options.ssh_filter == NULL)
++	    options.ssh_filter = "";
++	if (options.account_class == NULL)
++	    options.account_class = "posixAccount";
++}
++
++static const char *
++lookup_opcode_name(OpCodes code)
++{
++	u_int i;
++
++	for (i = 0; keywords[i].name != NULL; i++)
++	    if (keywords[i].opcode == code)
++		return(keywords[i].name);
++	return "UNKNOWN";
++}
++
++static void
++dump_cfg_string(OpCodes code, const char *val)
++{
++	if (val == NULL)
++	    debug3("%s <UNDEFINED>", lookup_opcode_name(code));
++	else
++	    debug3("%s %s", lookup_opcode_name(code), val);
++}
++
++static void
++dump_cfg_int(OpCodes code, int val)
++{
++	if (val == -1)
++	    debug3("%s <UNDEFINED>", lookup_opcode_name(code));
++	else
++	    debug3("%s %d", lookup_opcode_name(code), val);
++}
++
++struct names {
++	int value;
++	char *name;
++};
++
++static void
++dump_cfg_namedint(OpCodes code, int val, struct names *names)
++{
++	u_int i;
++
++	if (val == -1)
++	    debug3("%s <UNDEFINED>", lookup_opcode_name(code));
++	else {
++		for (i = 0; names[i].value != -1; i++)
++	 	    if (names[i].value == val) {
++	    		debug3("%s %s", lookup_opcode_name(code), names[i].name);
++			    return;
++		}
++		debug3("%s unknown: %d", lookup_opcode_name(code), val);
++	}
++}
++
++static struct names _yesnotls[] = {
++	{ 0, "No" },
++	{ 1, "Yes" },
++	{ 2, "Start_TLS" },
++	{ -1, NULL }};
++
++static struct names _scope[] = {
++	{ LDAP_SCOPE_BASE, "Base" },
++	{ LDAP_SCOPE_ONELEVEL, "One" },
++	{ LDAP_SCOPE_SUBTREE, "Sub"},
++	{ -1, NULL }};
++
++static struct names _deref[] = {
++	{ LDAP_DEREF_NEVER, "Never" },
++	{ LDAP_DEREF_SEARCHING, "Searching" },
++	{ LDAP_DEREF_FINDING, "Finding" },
++	{ LDAP_DEREF_ALWAYS, "Always" },
++	{ -1, NULL }};
++
++static struct names _yesno[] = {
++	{ 0, "No" },
++	{ 1, "Yes" },
++	{ -1, NULL }};
++
++static struct names _bindpolicy[] = {
++	{ 0, "Soft" },
++	{ 1, "Hard" },
++	{ -1, NULL }};
++
++static struct names _checkpeer[] = {
++	{ LDAP_OPT_X_TLS_NEVER, "Never" },
++	{ LDAP_OPT_X_TLS_HARD, "Hard" },
++	{ LDAP_OPT_X_TLS_DEMAND, "Demand" },
++	{ LDAP_OPT_X_TLS_ALLOW, "Allow" },
++	{ LDAP_OPT_X_TLS_TRY, "TRY" },
++	{ -1, NULL }};
++
++void
++dump_config(void)
++{
++	dump_cfg_string(lURI, options.uri);
++	dump_cfg_string(lHost, options.host);
++	dump_cfg_int(lPort, options.port);
++	dump_cfg_namedint(lSSL, options.ssl, _yesnotls);
++	dump_cfg_int(lLdap_Version, options.ldap_version);
++	dump_cfg_int(lTimeLimit, options.timelimit);
++	dump_cfg_int(lBind_TimeLimit, options.bind_timelimit);
++	dump_cfg_string(lBase, options.base);
++	dump_cfg_string(lBindDN, options.binddn);
++	dump_cfg_string(lBindPW, options.bindpw);
++	dump_cfg_namedint(lScope, options.scope, _scope);
++	dump_cfg_namedint(lDeref, options.deref, _deref);
++	dump_cfg_namedint(lReferrals, options.referrals, _yesno);
++	dump_cfg_namedint(lRestart, options.restart, _yesno);
++	dump_cfg_namedint(lBind_Policy, options.bind_policy, _bindpolicy);
++	dump_cfg_string(lSSLPath, options.sslpath);
++	dump_cfg_namedint(lTLS_CheckPeer, options.tls_checkpeer, _checkpeer);
++	dump_cfg_string(lTLS_CaCertFile, options.tls_cacertfile);
++	dump_cfg_string(lTLS_CaCertDir, options.tls_cacertdir);
++	dump_cfg_string(lTLS_Ciphers, options.tls_ciphers);
++	dump_cfg_string(lTLS_Cert, options.tls_cert);
++	dump_cfg_string(lTLS_Key, options.tls_key);
++	dump_cfg_string(lTLS_RandFile, options.tls_randfile);
++	dump_cfg_string(lLogDir, options.logdir);
++	dump_cfg_int(lDebug, options.debug);
++	dump_cfg_string(lSSH_Filter, options.ssh_filter);
++	dump_cfg_string(lSearch_Format, options.search_format);
++	dump_cfg_string(lAccountClass, options.account_class);
++}
++
+diff -up openssh-6.8p1/ldapconf.h.ldap openssh-6.8p1/ldapconf.h
+--- openssh-6.8p1/ldapconf.h.ldap	2015-03-18 11:11:29.032801460 +0100
++++ openssh-6.8p1/ldapconf.h	2015-03-18 11:11:29.032801460 +0100
+@@ -0,0 +1,73 @@
++/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  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 LDAPCONF_H
++#define LDAPCONF_H
++
++#define SSL_OFF          0
++#define SSL_LDAPS        1
++#define SSL_START_TLS    2
++
++/* Data structure for representing option data. */
++
++typedef struct {
++	char *host;
++	char *uri;
++	char *base;
++	char *binddn;
++	char *bindpw;
++	int scope;
++	int deref;
++	int port;
++	int timelimit;
++	int bind_timelimit;
++	int ldap_version;
++	int bind_policy;
++	char *sslpath;
++	int ssl;
++	int referrals;
++	int restart;
++	int tls_checkpeer;
++	char *tls_cacertfile;
++	char *tls_cacertdir;
++	char *tls_ciphers;
++	char *tls_cert;
++	char *tls_key;
++	char *tls_randfile;
++	char *logdir;
++	int debug;
++	char *ssh_filter;
++	char *search_format;
++	char *account_class;
++}       Options;
++
++extern Options options;
++
++void read_config_file(const char *);
++void initialize_options(void);
++void fill_default_options(void);
++void dump_config(void);
++
++#endif /* LDAPCONF_H */
+diff -up openssh-6.8p1/ldapincludes.h.ldap openssh-6.8p1/ldapincludes.h
+--- openssh-6.8p1/ldapincludes.h.ldap	2015-03-18 11:11:29.032801460 +0100
++++ openssh-6.8p1/ldapincludes.h	2015-03-18 11:11:29.032801460 +0100
+@@ -0,0 +1,41 @@
++/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  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 LDAPINCLUDES_H
++#define LDAPINCLUDES_H
++
++#include "includes.h"
++
++#ifdef HAVE_LBER_H
++#include <lber.h>
++#endif
++#ifdef HAVE_LDAP_H
++#include <ldap.h>
++#endif
++#ifdef HAVE_LDAP_SSL_H
++#include <ldap_ssl.h>
++#endif
++
++#endif /* LDAPINCLUDES_H */
+diff -up openssh-6.8p1/ldapmisc.c.ldap openssh-6.8p1/ldapmisc.c
+--- openssh-6.8p1/ldapmisc.c.ldap	2015-03-18 11:11:29.032801460 +0100
++++ openssh-6.8p1/ldapmisc.c	2015-03-18 11:11:29.032801460 +0100
+@@ -0,0 +1,79 @@
++
++#include "ldapincludes.h"
++#include "ldapmisc.h"
++
++#ifndef HAVE_LDAP_GET_LDERRNO
++int
++ldap_get_lderrno (LDAP * ld, char **m, char **s)
++{
++#ifdef HAVE_LDAP_GET_OPTION
++	int rc;
++#endif
++	int lderrno;
++
++#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
++	if ((rc = ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, &lderrno)) != LDAP_SUCCESS)
++	    return rc;
++#else
++	lderrno = ld->ld_errno;
++#endif
++
++	if (s != NULL) {
++#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_STRING)
++		if ((rc = ldap_get_option (ld, LDAP_OPT_ERROR_STRING, s)) != LDAP_SUCCESS)
++		    return rc;
++#else
++		*s = ld->ld_error;
++#endif
++	}
++
++	if (m != NULL) {
++#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_MATCHED_DN)
++		if ((rc = ldap_get_option (ld, LDAP_OPT_MATCHED_DN, m)) != LDAP_SUCCESS)
++		    return rc;
++#else
++		*m = ld->ld_matched;
++#endif
++	}
++
++	return lderrno;
++}
++#endif
++
++#ifndef HAVE_LDAP_SET_LDERRNO
++int
++ldap_set_lderrno (LDAP * ld, int lderrno, const char *m, const char *s)
++{
++#ifdef HAVE_LDAP_SET_OPTION
++	int rc;
++#endif
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
++	if ((rc = ldap_set_option (ld, LDAP_OPT_ERROR_NUMBER, &lderrno)) != LDAP_SUCCESS)
++	    return rc;
++#else
++	ld->ld_errno = lderrno;
++#endif
++
++	if (s != NULL) {
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_ERROR_STRING)
++		if ((rc = ldap_set_option (ld, LDAP_OPT_ERROR_STRING, s)) != LDAP_SUCCESS)
++		    return rc;
++#else
++		ld->ld_error = s;
++#endif
++	}
++
++	if (m != NULL) {
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_MATCHED_DN)
++		if ((rc = ldap_set_option (ld, LDAP_OPT_MATCHED_DN, m)) != LDAP_SUCCESS)
++		    return rc;
++#else
++		ld->ld_matched = m;
++#endif
++	}
++
++	return LDAP_SUCCESS;
++}
++#endif
++
+diff -up openssh-6.8p1/ldapmisc.h.ldap openssh-6.8p1/ldapmisc.h
+--- openssh-6.8p1/ldapmisc.h.ldap	2015-03-18 11:11:29.032801460 +0100
++++ openssh-6.8p1/ldapmisc.h	2015-03-18 11:11:29.032801460 +0100
+@@ -0,0 +1,35 @@
++/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  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 LDAPMISC_H
++#define LDAPMISC_H
++
++#include "ldapincludes.h"
++
++int ldap_get_lderrno (LDAP *, char **, char **);
++int ldap_set_lderrno (LDAP *, int, const char *, const char *);
++
++#endif /* LDAPMISC_H */
++
+diff -up openssh-6.8p1/openssh-lpk-openldap.schema.ldap openssh-6.8p1/openssh-lpk-openldap.schema
+--- openssh-6.8p1/openssh-lpk-openldap.schema.ldap	2015-03-18 11:11:29.033801457 +0100
++++ openssh-6.8p1/openssh-lpk-openldap.schema	2015-03-18 11:11:29.033801457 +0100
+@@ -0,0 +1,21 @@
++#
++# LDAP Public Key Patch schema for use with openssh-ldappubkey
++#                              useful with PKA-LDAP also
++#
++# Author: Eric AUGE <eau at phear.org>
++# 
++# Based on the proposal of : Mark Ruijter
++#
++
++
++# octetString SYNTAX
++attributetype ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' 
++	DESC 'MANDATORY: OpenSSH Public key' 
++	EQUALITY octetStringMatch
++	SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
++
++# printableString SYNTAX yes|no
++objectclass ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
++	DESC 'MANDATORY: OpenSSH LPK objectclass'
++	MUST ( sshPublicKey $ uid ) 
++	)
+diff -up openssh-6.8p1/openssh-lpk-sun.schema.ldap openssh-6.8p1/openssh-lpk-sun.schema
+--- openssh-6.8p1/openssh-lpk-sun.schema.ldap	2015-03-18 11:11:29.033801457 +0100
++++ openssh-6.8p1/openssh-lpk-sun.schema	2015-03-18 11:11:29.033801457 +0100
+@@ -0,0 +1,23 @@
++#
++# LDAP Public Key Patch schema for use with openssh-ldappubkey
++#                              useful with PKA-LDAP also
++#
++# Author: Eric AUGE <eau at phear.org>
++# 
++# Schema for Sun Directory Server.
++# Based on the original schema, modified by Stefan Fischer.
++#
++
++dn: cn=schema
++
++# octetString SYNTAX
++attributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' 
++	DESC 'MANDATORY: OpenSSH Public key' 
++	EQUALITY octetStringMatch
++	SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
++
++# printableString SYNTAX yes|no
++objectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
++	DESC 'MANDATORY: OpenSSH LPK objectclass'
++	MUST ( sshPublicKey $ uid ) 
++	)
+diff -up openssh-6.8p1/ssh-ldap-helper.8.ldap openssh-6.8p1/ssh-ldap-helper.8
+--- openssh-6.8p1/ssh-ldap-helper.8.ldap	2015-03-18 11:11:29.033801457 +0100
++++ openssh-6.8p1/ssh-ldap-helper.8	2015-03-18 11:11:29.033801457 +0100
+@@ -0,0 +1,79 @@
++.\" $OpenBSD: ssh-ldap-helper.8,v 1.1 2010/02/10 23:20:38 markus Exp $
++.\"
++.\" Copyright (c) 2010 Jan F. Chadima.  All rights reserved.
++.\"
++.\" 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.
++.\"
++.Dd $Mdocdate: April 29 2010 $
++.Dt SSH-LDAP-HELPER 8
++.Os
++.Sh NAME
++.Nm ssh-ldap-helper
++.Nd sshd helper program for ldap support
++.Sh SYNOPSIS
++.Nm ssh-ldap-helper
++.Op Fl devw
++.Op Fl f Ar file
++.Op Fl s Ar user
++.Sh DESCRIPTION
++.Nm
++is used by
++.Xr sshd 1
++to access keys provided by an LDAP.
++.Nm
++is disabled by default and can only be enabled in the
++sshd configuration file
++.Pa /etc/ssh/sshd_config
++by setting
++.Cm AuthorizedKeysCommand
++to
++.Dq /usr/libexec/ssh-ldap-wrapper .
++.Pp
++.Nm
++is not intended to be invoked by the user, but from
++.Xr sshd 8 via
++.Xr ssh-ldap-wrapper .
++.Pp
++The options are as follows:
++.Bl -tag -width Ds
++.It Fl d
++Set the debug mode; 
++.Nm
++prints all logs to stderr instead of syslog.
++.It Fl e
++Implies \-w;
++.Nm
++halts if it encounters an unknown item in the ldap.conf file.
++.It Fl f
++.Nm
++uses this file as the ldap configuration file instead of /etc/ssh/ldap.conf (default).
++.It Fl s
++.Nm
++prints out the user's keys to stdout and exits.
++.It Fl v
++Implies \-d;
++increases verbosity.
++.It Fl w
++.Nm
++writes warnings about unknown items in the ldap.conf configuration file.
++.El
++.Sh SEE ALSO
++.Xr sshd 8 ,
++.Xr sshd_config 5 ,
++.Xr ssh-ldap.conf 5 ,
++.Sh HISTORY
++.Nm
++first appeared in
++OpenSSH 5.5 + PKA-LDAP .
++.Sh AUTHORS
++.An Jan F. Chadima Aq jchadima at redhat.com
+diff -up openssh-6.8p1/ssh-ldap-wrapper.ldap openssh-6.8p1/ssh-ldap-wrapper
+--- openssh-6.8p1/ssh-ldap-wrapper.ldap	2015-03-18 11:11:29.033801457 +0100
++++ openssh-6.8p1/ssh-ldap-wrapper	2015-03-18 11:11:29.033801457 +0100
+@@ -0,0 +1,4 @@
++#!/bin/sh
++
++exec /usr/libexec/openssh/ssh-ldap-helper -s "$1"
++
+diff -up openssh-6.8p1/ssh-ldap.conf.5.ldap openssh-6.8p1/ssh-ldap.conf.5
+--- openssh-6.8p1/ssh-ldap.conf.5.ldap	2015-03-18 11:11:29.033801457 +0100
++++ openssh-6.8p1/ssh-ldap.conf.5	2015-03-18 11:11:29.033801457 +0100
+@@ -0,0 +1,385 @@
++.\" $OpenBSD: ssh-ldap.conf.5,v 1.1 2010/02/10 23:20:38 markus Exp $
++.\"
++.\" Copyright (c) 2010 Jan F. Chadima.  All rights reserved.
++.\"
++.\" 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.
++.\"
++.Dd $Mdocdate: may 12 2010 $
++.Dt SSH-LDAP.CONF 5
++.Os
++.Sh NAME
++.Nm ssh-ldap.conf
++.Nd configuration file for ssh-ldap-helper
++.Sh SYNOPSIS
++.Nm /etc/ssh/ldap.conf
++.Sh DESCRIPTION
++.Xr ssh-ldap-helper 8
++reads configuration data from
++.Pa /etc/ssh/ldap.conf
++(or the file specified with
++.Fl f
++on the command line).
++The file contains keyword-argument pairs, one per line.
++Lines starting with
++.Ql #
++and empty lines are interpreted as comments.
++.Pp
++The value starts with the first non-blank character after 
++the keyword's name, and terminates at the end of the line, 
++or at the last sequence of blanks before the end of the line.
++Quoting values that contain blanks 
++may be incorrect, as the quotes would become part of the value.
++The possible keywords and their meanings are as follows (note that
++keywords are case-insensitive, and arguments, on a case by case basis, may be case-sensitive).
++.Bl -tag -width Ds
++.It Cm URI
++The argument(s) are in the form
++.Pa ldap[si]://[name[:port]]
++and specify the URI(s) of an LDAP server(s) to which the
++.Xr ssh-ldap-helper 8 
++should connect. The URI scheme may be any of
++.Dq ldap ,
++.Dq ldaps 
++or
++.Dq ldapi ,
++which refer to LDAP over TCP, LDAP over SSL (TLS) and LDAP
++over IPC (UNIX domain sockets), respectively.
++Each server's name can be specified as a
++domain-style name or an IP address literal.  Optionally, the
++server's name can followed by a ':' and the port number the LDAP
++server is listening on.  If no port number is provided, the default
++port for the scheme is used (389 for ldap://, 636 for ldaps://).
++For LDAP over IPC, name is the name of the socket, and no port
++is required, nor allowed; note that directory separators must be 
++URL-encoded, like any other characters that are special to URLs; 
++A space separated list of URIs may be provided.
++There is no default.
++.It Cm Base
++Specifies the default base Distinguished Name (DN) to use when performing ldap operations.
++The base must be specified as a DN in LDAP format.
++There is no default.
++.It Cm BindDN
++Specifies the default BIND DN to use when connecting to the ldap server.
++The bind DN must be specified as a Distinguished Name in LDAP format.
++There is no default.
++.It Cm BindPW
++Specifies the default password to use when connecting to the ldap server via
++.Cm BindDN .
++There is no default.
++.It Cm RootBindDN
++Intentionaly does nothing. Recognized for compatibility reasons.
++.It Cm Host
++The argument(s) specifies the name(s) of an LDAP server(s) to which the
++.Xr ssh-ldap-helper 8
++should connect.  Each server's name can be specified as a
++domain-style name or an IP address and optionally followed by a ':' and
++the port number the ldap server is listening on.  A space-separated
++list of hosts may be provided.
++There is no default.
++.Cm Host
++is deprecated in favor of
++.Cm URI .
++.It Cm Port
++Specifies the default port used when connecting to LDAP servers(s).
++The port may be specified as a number.
++The default port is 389 for ldap:// or 636 for ldaps:// respectively.
++.Cm Port
++is deprecated in favor of
++.Cm URI .
++.It Cm Scope
++Specifies the starting point of an LDAP search and the depth from the base DN to which the search should descend.
++There are three options (values) that can be assigned to the
++.Cm Scope parameter:
++.Dq base ,
++.Dq one
++and
++.Dq subtree .
++Alias for the subtree is
++.Dq sub .
++The value
++.Dq base
++is used to indicate searching only the entry at the base DN, resulting in only that entry being returned (keeping in mind that it also has to meet the search filter criteria!).
++The value
++.Dq one
++is used to indicate searching all entries one level under the base DN, but not including the base DN and not including any entries under that one level under the base DN.
++The value
++.Dq subtree
++is used to indicate searching of all entries at all levels under and including the specified base DN.
++The default is
++.Dq subtree .
++.It Cm Deref
++Specifies how alias dereferencing is done when performing a search. There are four
++possible values that can be assigned to the
++.Cm Deref
++parameter:
++.Dq never ,
++.Dq searching ,
++.Dq finding ,
++and
++.Dq always .
++The value
++.Dq never
++means that the aliases are never dereferenced.
++The value
++.Dq searching
++means that the aliases are dereferenced in subordinates of the base object, but
++not in locating the base object of the search.
++The value
++.Dq finding
++means that the aliases are only dereferenced when locating the base object of the search.
++The value
++.Dq always
++means that the aliases are dereferenced both in searching and in locating the base object
++of the search.
++The default is
++.Dq never .
++.It Cm TimeLimit
++Specifies a time limit (in seconds) to use when performing searches.
++The number should be a non-negative integer. A
++.Cm TimeLimit
++of zero (0) specifies that the search time is unlimited. Please note that the server
++may still apply any server-side limit on the duration of a search operation.
++The default value is 10.
++.It Cm TimeOut
++Is an aliast to
++.Cm TimeLimit .
++.It Cm Bind_TimeLimit
++Specifies the timeout (in seconds) after which the poll(2)/select(2)
++following a connect(2) returns in case of no activity.
++The default value is 10.
++.It Cm Network_TimeOut
++Is an alias to
++.Cm Bind_TimeLimit .
++.It Cm Ldap_Version
++Specifies what version of the LDAP protocol should be used.
++The allowed values are 2 or 3. The default is 3.
++.It Cm Version
++Is an alias to
++.Cm Ldap_Version .
++.It Cm Bind_Policy
++Specifies the policy to use for reconnecting to an unavailable LDAP server. There are 2 available values:
++.Dq hard
++and
++.Dq soft.
++.Dq hard has 2 aliases
++.Dq hard_open
++and
++.Dq hard_init .
++The value
++.Dq hard
++means that reconects that the
++.Xr ssh-ldap-helper 8
++tries to reconnect to the LDAP server 5 times before failure. There is exponential backoff before retrying.
++The value
++.Dq soft
++means that
++.Xr ssh-ldap-helper 8
++fails immediately when it cannot connect to the LDAP seerver.
++The deault is
++.Dq hard .
++.It Cm SSLPath
++Specifies the path to the X.509 certificate database.
++There is no default.
++.It Cm SSL
++Specifies whether to use SSL/TLS or not.
++There are three allowed values:
++.Dq yes ,
++.Dq no
++and
++.Dq start_tls
++Both
++.Dq true
++and
++.Dq on
++are the aliases for
++.Dq yes .
++.Dq false
++and
++.Dq off
++are the aliases for
++.Dq no .
++If
++.Dq start_tls
++is specified then StartTLS is used rather than raw LDAP over SSL.
++The default for ldap:// is
++.Dq start_tls ,
++for ldaps://
++.Dq yes
++and
++.Dq no
++for the ldapi:// .
++In case of host based configuration the default is
++.Dq start_tls .
++.It Cm Referrals
++Specifies if the client should automatically follow referrals returned
++by LDAP servers.
++The value can be or
++.Dq yes
++or
++.Dq no .
++.Dq true
++and
++.Dq on
++are the aliases for
++.Dq yes .
++.Dq false
++and
++.Dq off
++are the aliases for
++.Dq no .
++The default is yes.
++.It Cm Restart
++Specifies whether the LDAP client library should restart the select(2) system call when interrupted.
++The value can be or
++.Dq yes
++or
++.Dq no .
++.Dq true
++and
++.Dq on
++are the aliases for
++.Dq yes .
++.Dq false
++and
++.Dq off
++are the aliases for
++.Dq no .
++The default is yes.
++.It Cm TLS_CheckPeer
++Specifies what checks to perform on server certificates in a TLS session,
++if any. The value
++can be specified as one of the following keywords:
++.Dq never ,
++.Dq hard ,
++.Dq demand ,
++.Dq allow
++and
++.Dq try .
++.Dq true ,
++.Dq on
++and
++.Dq yes
++are aliases for
++.Dq hard .
++.Dq false ,
++.Dq off
++and
++.Dq no
++are the aliases for
++.Dq never .
++The value
++.Dq never
++means that the client will not request or check any server certificate.
++The value
++.Dq allow
++means that the server certificate is requested. If no certificate is provided,
++the session proceeds normally. If a bad certificate is provided, it will
++be ignored and the session proceeds normally.
++The value
++.Dq try
++means that the server certificate is requested. If no certificate is provided,
++the session proceeds normally. If a bad certificate is provided,
++the session is immediately terminated.
++The value
++.Dq demand
++means that the server certificate is requested. If no
++certificate is provided, or a bad certificate is provided, the session
++is immediately terminated.
++The value
++.Dq hard
++is the same as
++.Dq demand .
++It requires an SSL connection. In the case of the plain conection the
++session is immediately terminated.
++The default is
++.Dq hard .
++.It Cm TLS_ReqCert
++Is an alias for 
++.Cm TLS_CheckPeer .
++.It Cm TLS_CACertFile
++Specifies the file that contains certificates for all of the Certificate
++Authorities the client will recognize.
++There is no default.
++.It Cm TLS_CACert
++Is an alias for
++.Cm TLS_CACertFile .
++.It Cm TLS_CACertDIR
++Specifies the path of a directory that contains Certificate Authority
++certificates in separate individual files. The
++.Cm TLS_CACert
++is always used before
++.Cm TLS_CACertDir .
++The specified directory must be managed with the OpenSSL c_rehash utility.
++There is no default.
++.It Cm TLS_Ciphers
++Specifies acceptable cipher suite and preference order.
++The value should be a cipher specification for OpenSSL,
++e.g.,
++.Dq HIGH:MEDIUM:+SSLv2 .
++The default is
++.Dq ALL .
++.It Cm TLS_Cipher_Suite
++Is an alias for
++.Cm TLS_Ciphers .
++.It Cm TLS_Cert
++Specifies the file that contains the client certificate.
++There is no default.
++.It Cm TLS_Certificate
++Is an alias for
++.Cm TLS_Cert .
++.It Cm TLS_Key
++Specifies the file that contains the private key that matches the certificate
++stored in the
++.Cm TLS_Cert
++file. Currently, the private key must not be protected with a password, so
++it is of critical importance that the key file is protected carefully.
++There is no default.
++.It Cm TLS_RandFile
++Specifies the file to obtain random bits from when /dev/[u]random is
++not available. Generally set to the name of the EGD/PRNGD socket.
++The environment variable RANDFILE can also be used to specify the filename.
++There is no default.
++.It Cm LogDir
++Specifies the directory used for logging by the LDAP client library.
++There is no default.
++.It Cm Debug
++Specifies the debug level used for logging by the LDAP client library.
++There is no default.
++.It Cm SSH_Filter
++Specifies the user filter applied on the LDAP search.
++The default is no filter.
++.It Cm AccountClass
++Specifies the LDAP class used to find user accounts.
++The default is posixAccount.
++.It Cm search_format
++Specifies the user format of search string in LDAP substituting %u for user name
++and %f for additional ssh filter
++.Cm SSH_Filter
++(optional).
++The default value is (&(objectclass=%c)(objectclass=ldapPublicKey)(uid=%u)%f)
++.El
++.Sh FILES
++.Bl -tag -width Ds
++.It Pa  /etc/ssh/ldap.conf
++Ldap configuration file for
++.Xr ssh-ldap-helper 8 .
++.El
++.Sh "SEE ALSO"
++.Xr ldap.conf 5 ,
++.Xr ssh-ldap-helper 8
++.Sh HISTORY
++.Nm
++first appeared in
++OpenSSH 5.5 + PKA-LDAP .
++.Sh AUTHORS
++.An Jan F. Chadima Aq jchadima at redhat.com
diff --git a/openssh-6.7p1-seccomp-aarch64.patch b/openssh-6.7p1-seccomp-aarch64.patch
new file mode 100644
index 0000000..4285bd9
--- /dev/null
+++ b/openssh-6.7p1-seccomp-aarch64.patch
@@ -0,0 +1,66 @@
+diff --git a/configure.ac b/configure.ac
+index 4065d0e..d59ad44 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -764,9 +764,12 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
+ 	i*86-*)
+ 		seccomp_audit_arch=AUDIT_ARCH_I386
+ 		;;
+-        arm*-*)
++	aarch64*-*)
++		seccomp_audit_arch=AUDIT_ARCH_AARCH64
++		;;
++	arm*-*)
+ 		seccomp_audit_arch=AUDIT_ARCH_ARM
+-                ;;
++		;;
+ 	esac
+ 	if test "x$seccomp_audit_arch" != "x" ; then
+ 		AC_MSG_RESULT(["$seccomp_audit_arch"])
+diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c
+index 095b04a..52f6810 100644
+--- a/sandbox-seccomp-filter.c
++++ b/sandbox-seccomp-filter.c
+@@ -90,8 +90,20 @@ static const struct sock_filter preauth_insns[] = {
+ 	/* Load the syscall number for checking. */
+ 	BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
+ 		offsetof(struct seccomp_data, nr)),
+-	SC_DENY(open, EACCES),
+-	SC_DENY(stat, EACCES),
++	SC_DENY(openat, EACCES),
++#ifdef __NR_open
++	SC_DENY(open, EACCES), /* not on AArch64 */
++#endif
++#ifdef __NR_fstat
++	SC_DENY(fstat, EACCES), /* x86_64, Aarch64 */
++#endif
++#if defined(__NR_stat64) && defined(__NR_fstat64)
++	SC_DENY(stat64, EACCES), /* ix86, arm */
++	SC_DENY(fstat64, EACCES),
++#endif
++#ifdef __NR_newfstatat
++	SC_DENY(newfstatat, EACCES), /* Aarch64 */
++#endif
+ 	SC_ALLOW(getpid),
+ 	SC_ALLOW(gettimeofday),
+ 	SC_ALLOW(clock_gettime),
+@@ -111,12 +123,19 @@ static const struct sock_filter preauth_insns[] = {
+ 	SC_ALLOW(shutdown),
+ #endif
+ 	SC_ALLOW(brk),
++#ifdef __NR_poll /* not on AArch64 */
+ 	SC_ALLOW(poll),
++#endif
+ #ifdef __NR__newselect
+ 	SC_ALLOW(_newselect),
+ #else
++#ifdef __NR_select /* not on AArch64 */
+ 	SC_ALLOW(select),
+ #endif
++#ifdef __NR_pselect6 /* AArch64 */
++	SC_ALLOW(pselect6),
++#endif
++#endif
+ 	SC_ALLOW(madvise),
+ #ifdef __NR_mmap2 /* EABI ARM only has mmap2() */
+ 	SC_ALLOW(mmap2),
diff --git a/openssh-6.7p1-sftp-force-permission.patch b/openssh-6.7p1-sftp-force-permission.patch
new file mode 100644
index 0000000..1a88e50
--- /dev/null
+++ b/openssh-6.7p1-sftp-force-permission.patch
@@ -0,0 +1,81 @@
+diff -up openssh-6.8p1/sftp-server.8.sftp-force-mode openssh-6.8p1/sftp-server.8
+--- openssh-6.8p1/sftp-server.8.sftp-force-mode	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/sftp-server.8	2015-03-18 13:18:05.898306477 +0100
+@@ -38,6 +38,7 @@
+ .Op Fl P Ar blacklisted_requests
+ .Op Fl p Ar whitelisted_requests
+ .Op Fl u Ar umask
++.Op Fl m Ar force_file_perms
+ .Ek
+ .Nm
+ .Fl Q Ar protocol_feature
+@@ -138,6 +139,10 @@ Sets an explicit
+ .Xr umask 2
+ to be applied to newly-created files and directories, instead of the
+ user's default mask.
++.It Fl m Ar force_file_perms
++Sets explicit file permissions to be applied to newly-created files instead
++of the default or client requested mode.  Numeric values include:
++777, 755, 750, 666, 644, 640, etc.  Option -u is ineffective if -m is set.
+ .El
+ .Pp
+ On some systems,
+diff -up openssh-6.8p1/sftp-server.c.sftp-force-mode openssh-6.8p1/sftp-server.c
+--- openssh-6.8p1/sftp-server.c.sftp-force-mode	2015-03-18 13:18:05.883306513 +0100
++++ openssh-6.8p1/sftp-server.c	2015-03-18 13:18:36.697232193 +0100
+@@ -70,6 +70,10 @@ struct sshbuf *oqueue;
+ /* Version of client */
+ static u_int version;
+ 
++/* Force file permissions */
++int permforce = 0;
++long permforcemode;
++
+ /* SSH2_FXP_INIT received */
+ static int init_done;
+ 
+@@ -693,6 +697,10 @@ process_open(u_int32_t id)
+ 	debug3("request %u: open flags %d", id, pflags);
+ 	flags = flags_from_portable(pflags);
+ 	mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a.perm : 0666;
++	if (permforce == 1) {   /* Force perm if -m is set */
++		mode = permforcemode;
++		(void)umask(0); /* so umask does not interfere		 */
++	}	
+ 	logit("open \"%s\" flags %s mode 0%o",
+ 	    name, string_from_portable(pflags), mode);
+ 	if (readonly &&
+@@ -1495,7 +1503,7 @@ sftp_server_usage(void)
+ 	fprintf(stderr,
+ 	    "usage: %s [-ehR] [-d start_directory] [-f log_facility] "
+ 	    "[-l log_level]\n\t[-P blacklisted_requests] "
+-	    "[-p whitelisted_requests] [-u umask]\n"
++	    "[-p whitelisted_requests] [-u umask] [-m force_file_perms]\n"
+ 	    "       %s -Q protocol_feature\n",
+ 	    __progname, __progname);
+ 	exit(1);
+@@ -1520,7 +1528,7 @@ sftp_server_main(int argc, char **argv,
+ 	pw = pwcopy(user_pw);
+ 
+ 	while (!skipargs && (ch = getopt(argc, argv,
+-	    "d:f:l:P:p:Q:u:cehR")) != -1) {
++	    "d:f:l:P:p:Q:u:m:cehR")) != -1) {
+ 		switch (ch) {
+ 		case 'Q':
+ 			if (strcasecmp(optarg, "requests") != 0) {
+@@ -1580,6 +1588,15 @@ sftp_server_main(int argc, char **argv,
+ 				fatal("Invalid umask \"%s\"", optarg);
+ 			(void)umask((mode_t)mask);
+ 			break;
++		case 'm':
++			/* Force permissions on file received via sftp */
++			permforce = 1;
++			permforcemode = strtol(optarg, &cp, 8);
++			if (permforcemode < 0 || permforcemode > 0777 ||
++			    *cp != '\0' || (permforcemode == 0 &&
++			    errno != 0))
++				fatal("Invalid file mode \"%s\"", optarg);
++			break;
+ 		case 'h':
+ 		default:
+ 			sftp_server_usage();
diff --git a/openssh-6.7p1-sshdT-output.patch b/openssh-6.7p1-sshdT-output.patch
new file mode 100644
index 0000000..aa09346
--- /dev/null
+++ b/openssh-6.7p1-sshdT-output.patch
@@ -0,0 +1,56 @@
+diff -up openssh-6.8p1/servconf.c.sshdt openssh-6.8p1/servconf.c
+--- openssh-6.8p1/servconf.c.sshdt	2015-03-18 13:07:24.457858235 +0100
++++ openssh-6.8p1/servconf.c	2015-03-18 13:09:27.253557396 +0100
+@@ -2118,6 +2118,8 @@ dump_cfg_strarray_oneline(ServerOpCodes
+ {
+ 	u_int i;
+ 
++	if (count <= 0)
++		return;
+ 	printf("%s", lookup_opcode_name(code));
+ 	for (i = 0; i < count; i++)
+ 		printf(" %s",  vals[i]);
+@@ -2156,7 +2158,7 @@ dump_config(ServerOptions *o)
+ 
+ 	/* integer arguments */
+ #ifdef USE_PAM
+-	dump_cfg_int(sUsePAM, o->use_pam);
++	dump_cfg_fmtint(sUsePAM, o->use_pam);
+ #endif
+ 	dump_cfg_int(sServerKeyBits, o->server_key_bits);
+ 	dump_cfg_int(sLoginGraceTime, o->login_grace_time);
+@@ -2166,6 +2168,7 @@ dump_config(ServerOptions *o)
+ 	dump_cfg_int(sMaxSessions, o->max_sessions);
+ 	dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
+ 	dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
++	dump_cfg_int(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
+ 
+ 	/* formatted integer arguments */
+ 	dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
+@@ -2213,6 +2216,7 @@ dump_config(ServerOptions *o)
+ 	dump_cfg_fmtint(sShowPatchLevel, o->show_patchlevel);
+ 	dump_cfg_fmtint(sUseDNS, o->use_dns);
+ 	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
++	dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding);
+ 	dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
+ 	dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
+ 	dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
+@@ -2231,7 +2235,8 @@ dump_config(ServerOptions *o)
+ 	dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
+ 	dump_cfg_string(sAuthorizedPrincipalsFile,
+ 	    o->authorized_principals_file);
+-	dump_cfg_string(sVersionAddendum, o->version_addendum);
++	dump_cfg_string(sVersionAddendum, *o->version_addendum == '\0'
++	    ? "none" : o->version_addendum);
+ 	dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
+ 	dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
+ 	dump_cfg_string(sHostKeyAgent, o->host_key_agent);
+@@ -2251,7 +2256,7 @@ dump_config(ServerOptions *o)
+ 	    o->authorized_keys_files);
+ 	dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
+ 	     o->host_key_files);
+-	dump_cfg_strarray(sHostKeyFile, o->num_host_cert_files,
++	dump_cfg_strarray(sHostCertificate, o->num_host_cert_files,
+ 	     o->host_cert_files);
+ 	dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
+ 	dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
diff --git a/openssh-6.8p1-880575.patch b/openssh-6.8p1-880575.patch
new file mode 100644
index 0000000..9936282
--- /dev/null
+++ b/openssh-6.8p1-880575.patch
@@ -0,0 +1,11 @@
+--- openssh-6.8p1/authfile.c.orig	2015-03-26 09:59:06.646924879 +0100
++++ openssh-6.8p1/authfile.c	2015-03-26 09:59:19.310905998 +0100
+@@ -194,7 +194,7 @@
+ 		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+ 		error("Permissions 0%3.3o for '%s' are too open.",
+ 		    (u_int)st.st_mode & 0777, filename);
+-		error("It is recommended that your private key files are NOT accessible by others.");
++		error("It is required that your private key files are NOT accessible by others.");
+ 		error("This private key will be ignored.");
+ 		return SSH_ERR_KEY_BAD_PERMISSIONS;
+ 	}
diff --git a/openssh-6.8p1-gsissh.patch b/openssh-6.8p1-gsissh.patch
new file mode 100644
index 0000000..2ffe24a
--- /dev/null
+++ b/openssh-6.8p1-gsissh.patch
@@ -0,0 +1,3012 @@
+diff -Nur openssh-6.8p1.orig/auth2.c openssh-6.8p1/auth2.c
+--- openssh-6.8p1.orig/auth2.c	2015-04-13 20:23:30.749419514 +0200
++++ openssh-6.8p1/auth2.c	2015-04-13 20:24:30.206740480 +0200
+@@ -50,6 +50,7 @@
+ #include "dispatch.h"
+ #include "pathnames.h"
+ #include "buffer.h"
++#include "canohost.h"
+ 
+ #ifdef GSSAPI
+ #include "ssh-gss.h"
+@@ -74,6 +75,8 @@
+ extern Authmethod method_gssapi;
+ #endif
+ 
++static int log_flag = 0;
++
+ Authmethod *authmethods[] = {
+ 	&method_none,
+ 	&method_pubkey,
+@@ -228,7 +231,33 @@
+ 	user = packet_get_cstring(NULL);
+ 	service = packet_get_cstring(NULL);
+ 	method = packet_get_cstring(NULL);
+-	debug("userauth-request for user %s service %s method %s", user, service, method);
++
++#ifdef GSSAPI
++	if (user[0] == '\0') {
++		debug("received empty username for %s", method);
++		if (strcmp(method, "gssapi-keyex") == 0) {
++			char *lname = NULL;
++			PRIVSEP(ssh_gssapi_localname(&lname));
++			if (lname && lname[0] != '\0') {
++				free(user);
++				user = lname;
++				debug("set username to %s from gssapi context", user);
++			} else {
++				debug("failed to set username from gssapi context");
++				packet_send_debug("failed to set username from gssapi context");
++			}
++		}
++	}
++#endif
++
++	debug("userauth-request for user %s service %s method %s",
++	    user[0] ? user : "<implicit>", service, method);
++	if (!log_flag) {
++		logit("SSH: Server;Ltype: Authname;Remote: %s-%d;Name: %s", 
++		      get_remote_ipaddr(), get_remote_port(),
++		      user[0] ? user : "<implicit>");
++		log_flag = 1;
++	}
+ 	debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
+ 
+ #ifdef WITH_SELINUX
+@@ -239,23 +268,48 @@
+ 	if ((style = strchr(user, ':')) != NULL)
+ 		*style++ = 0;
+ 
+-	if (authctxt->attempt++ == 0) {
+-		/* setup auth context */
+-		authctxt->pw = PRIVSEP(getpwnamallow(user));
++	/* If first time or username changed or empty username,
++	   setup/reset authentication context. */
++	if ((authctxt->attempt++ == 0) ||
++	    (strcmp(user, authctxt->user) != 0) ||
++	    (strcmp(user, "") == 0)) {
++		if (authctxt->user) {
++			free(authctxt->user);
++			authctxt->user = NULL;
++		}
++		authctxt->valid = 0;
+ 		authctxt->user = xstrdup(user);
+-		if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
++		if (strcmp(service, "ssh-connection") != 0) {
++			packet_disconnect("Unsupported service %s", service);
++		}
++#ifdef GSSAPI
++		/* If we're going to set the username based on the
++		   GSSAPI context later, then wait until then to
++		   verify it. Just put in placeholders for now. */
++		if ((strcmp(user, "") == 0) &&
++		    ((strcmp(method, "gssapi") == 0) ||
++		     (strcmp(method, "gssapi-with-mic") == 0))) {
++			authctxt->pw = fakepw();
++		} else {
++#endif
++		authctxt->pw = PRIVSEP(getpwnamallow(user));
++		if (authctxt->pw) {
+ 			authctxt->valid = 1;
+ 			debug2("input_userauth_request: setting up authctxt for %s", user);
+ 		} else {
+ 			logit("input_userauth_request: invalid user %s", user);
+ 			authctxt->pw = fakepw();
+ 		}
++#ifdef GSSAPI
++		} /* endif for setting username based on GSSAPI context */
++#endif
+ #ifdef USE_PAM
+ 		if (options.use_pam)
+ 			PRIVSEP(start_pam(authctxt));
+ #endif
+ 		setproctitle("%s%s", authctxt->valid ? user : "unknown",
+ 		    use_privsep ? " [net]" : "");
++		if (authctxt->attempt == 1) {
+ 		authctxt->service = xstrdup(service);
+ 		authctxt->style = style ? xstrdup(style) : NULL;
+ #ifdef WITH_SELINUX
+@@ -270,9 +324,10 @@
+ 		userauth_banner();
+ 		if (auth2_setup_methods_lists(authctxt) != 0)
+ 			packet_disconnect("no authentication methods enabled");
+-	} else if (strcmp(user, authctxt->user) != 0 ||
+-	    strcmp(service, authctxt->service) != 0) {
+-		packet_disconnect("Change of username or service not allowed: "
++		}
++	}
++	if (strcmp(service, authctxt->service) != 0) {
++		packet_disconnect("Change of service not allowed: "
+ 		    "(%s,%s) -> (%s,%s)",
+ 		    authctxt->user, authctxt->service, user, service);
+ 	}
+diff -Nur openssh-6.8p1.orig/auth2-gss.c openssh-6.8p1/auth2-gss.c
+--- openssh-6.8p1.orig/auth2-gss.c	2015-04-13 20:23:30.664420485 +0200
++++ openssh-6.8p1/auth2-gss.c	2015-04-13 20:31:12.831142116 +0200
+@@ -49,6 +49,7 @@
+ 
+ extern ServerOptions options;
+ 
++static void ssh_gssapi_userauth_error(Gssctxt *ctxt);
+ static int input_gssapi_token(int type, u_int32_t plen, void *ctxt);
+ static int input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
+ static int input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
+@@ -61,8 +62,8 @@
+ userauth_gsskeyex(Authctxt *authctxt)
+ {
+ 	int authenticated = 0;
+-	Buffer b;
+-	gss_buffer_desc mic, gssbuf;
++	Buffer b, b2;
++	gss_buffer_desc mic, gssbuf, gssbuf2;
+ 	u_int len;
+ 
+ 	mic.value = packet_get_string(&len);
+@@ -76,13 +77,27 @@
+ 	gssbuf.value = buffer_ptr(&b);
+ 	gssbuf.length = buffer_len(&b);
+ 
++	/* client may have used empty username to determine target
++	   name from GSSAPI context */
++	ssh_gssapi_buildmic(&b2, "", authctxt->service, "gssapi-keyex");
++
++	gssbuf2.value = buffer_ptr(&b2);
++	gssbuf2.length = buffer_len(&b2);
++
+ 	/* 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));
++						   &gssbuf, &mic))) ||
++	    !GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, 
++						   &gssbuf2, &mic)))) {
++		if (authctxt->valid && authctxt->user && authctxt->user[0]) {
++			authenticated =
++			    PRIVSEP(ssh_gssapi_userok(authctxt->user,
++				    authctxt->pw, 1 /* gssapi-keyex */));
++		}
++	}
+ 	
+ 	buffer_free(&b);
++	buffer_free(&b2);
+ 	free(mic.value);
+ 
+ 	return (authenticated);
+@@ -103,7 +118,10 @@
+ 	u_int len;
+ 	u_char *doid = NULL;
+ 
+-	if (!authctxt->valid || authctxt->user == NULL)
++	/* authctxt->valid may be 0 if we haven't yet determined
++	   username from gssapi context. */
++
++	if (authctxt->user == NULL)
+ 		return (0);
+ 
+ 	mechs = packet_get_int();
+@@ -168,7 +186,7 @@
+ 	Gssctxt *gssctxt;
+ 	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+ 	gss_buffer_desc recv_tok;
+-	OM_uint32 maj_status, min_status, flags;
++	OM_uint32 maj_status, min_status, flags = 0;
+ 	u_int len;
+ 
+ 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
+@@ -186,6 +204,7 @@
+ 	free(recv_tok.value);
+ 
+ 	if (GSS_ERROR(maj_status)) {
++		ssh_gssapi_userauth_error(gssctxt);
+ 		if (send_tok.length != 0) {
+ 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+ 			packet_put_string(send_tok.value, send_tok.length);
+@@ -251,6 +270,32 @@
+ 	return 0;
+ }
+ 
++static void
++gssapi_set_username(Authctxt *authctxt)
++{
++	char *lname = NULL;
++
++	if ((authctxt->user == NULL) || (authctxt->user[0] == '\0')) {
++		PRIVSEP(ssh_gssapi_localname(&lname));
++		if (lname && lname[0] != '\0') {
++			if (authctxt->user) free(authctxt->user);
++			authctxt->user = lname;
++			debug("set username to %s from gssapi context", lname);
++			authctxt->pw = PRIVSEP(getpwnamallow(authctxt->user));
++			if (authctxt->pw) {
++				authctxt->valid = 1;
++#ifdef USE_PAM
++				if (options.use_pam)
++					PRIVSEP(start_pam(authctxt));
++#endif
++			}
++		} else {
++			debug("failed to set username from gssapi context");
++			packet_send_debug("failed to set username from gssapi context");
++		}
++	}
++}
++
+ /*
+  * This is called when the client thinks we've completed authentication.
+  * It should only be enabled in the dispatch handler by the function above,
+@@ -266,6 +311,8 @@
+ 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
+ 		fatal("No authentication or GSSAPI context");
+ 
++	gssapi_set_username(authctxt);
++
+ 	/*
+ 	 * We don't need to check the status, because we're only enabled in
+ 	 * the dispatcher once the exchange is complete
+@@ -273,8 +320,13 @@
+ 
+ 	packet_check_eom();
+ 
+-	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
+-	    authctxt->pw));
++	/* user should be set if valid but we double-check here */
++	if (authctxt->valid && authctxt->user && authctxt->user[0]) {
++		authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
++					authctxt->pw, 0 /* !gssapi-keyex */));
++	} else {
++		authenticated = 0;
++	}
+ 
+ 	authctxt->postponed = 0;
+ 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+@@ -316,9 +368,16 @@
+ 	gssbuf.value = buffer_ptr(&b);
+ 	gssbuf.length = buffer_len(&b);
+ 
++	gssapi_set_username(authctxt);
++
+ 	if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
+-		authenticated = 
+-		    PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
++		if (authctxt->valid && authctxt->user && authctxt->user[0]) {
++			authenticated =
++			    PRIVSEP(ssh_gssapi_userok(authctxt->user,
++				    authctxt->pw, 0 /* !gssapi-keyex */));
++		} else {
++			authenticated = 0;
++		}
+ 	else
+ 		logit("GSSAPI MIC check failed");
+ 
+@@ -336,6 +395,23 @@
+ 	return 0;
+ }
+ 
++static void ssh_gssapi_userauth_error(Gssctxt *ctxt) {
++	char *errstr;
++	OM_uint32 maj,min;
++	
++	errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
++	if (errstr) {
++		packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR);
++		packet_put_int(maj);
++		packet_put_int(min);
++		packet_put_cstring(errstr);
++		packet_put_cstring("");
++		packet_send();
++		packet_write_wait();
++		free(errstr);
++	}
++}
++
+ Authmethod method_gsskeyex = {
+ 	"gssapi-keyex",
+ 	userauth_gsskeyex,
+diff -Nur openssh-6.8p1.orig/auth.c openssh-6.8p1/auth.c
+--- openssh-6.8p1.orig/auth.c	2015-04-13 20:23:30.748419526 +0200
++++ openssh-6.8p1/auth.c	2015-04-13 20:24:30.208740457 +0200
+@@ -75,6 +75,9 @@
+ #include "ssherr.h"
+ #include "compat.h"
+ 
++#include "version.h"
++#include "ssh-globus-usage.h"
++
+ /* import */
+ extern ServerOptions options;
+ extern int use_privsep;
+@@ -299,7 +302,8 @@
+ 	    method,
+ 	    submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
+ 	    authctxt->valid ? "" : "invalid user ",
+-	    authctxt->user,
++	    (authctxt->user && authctxt->user[0]) ?
++		authctxt->user : "unknown",
+ 	    get_remote_ipaddr(),
+ 	    get_remote_port(),
+ 	    compat20 ? "ssh2" : "ssh1",
+@@ -325,6 +329,23 @@
+ 	if (authenticated == 0 && !authctxt->postponed)
+ 		audit_event(audit_classify_auth(method));
+ #endif
++	if (authenticated) {
++		char *userdn = NULL;
++		char *mech_name = NULL;
++#ifdef GSSAPI
++		ssh_gssapi_get_client_info(&userdn, &mech_name);
++#endif
++		debug("REPORTING (%s) (%s) (%s) (%s) (%s) (%s) (%s)",
++			 SSH_RELEASE, SSLeay_version(SSLEAY_VERSION),
++			 method, mech_name?mech_name:"NULL", get_remote_ipaddr(),
++			 (authctxt->user && authctxt->user[0])?
++				authctxt->user : "unknown",
++			userdn?userdn:"NULL");
++		ssh_globus_send_usage_metrics(SSH_RELEASE,
++					SSLeay_version(SSLEAY_VERSION),
++					method, mech_name, get_remote_ipaddr(),
++					authctxt->user, userdn);
++	}
+ }
+ 
+ 
+@@ -620,6 +641,10 @@
+ #endif
+ 
+ 	pw = getpwnam(user);
++#ifdef USE_PAM
++	if (options.use_pam && options.permit_pam_user_change && pw == NULL)
++		pw = sshpam_getpw(user);
++#endif
+ 
+ #if defined(_AIX) && defined(HAVE_SETAUTHDB)
+ 	aix_restoreauthdb();
+@@ -639,7 +664,8 @@
+ #endif
+ 	if (pw == NULL) {
+ 		logit("Invalid user %.100s from %.100s",
+-		    user, get_remote_ipaddr());
++		      (user && user[0]) ? user : "unknown",
++		      get_remote_ipaddr());
+ #ifdef CUSTOM_FAILED_LOGIN
+ 		record_failed_login(user,
+ 		    get_canonical_hostname(options.use_dns), "ssh");
+diff -Nur openssh-6.8p1.orig/auth-pam.c openssh-6.8p1/auth-pam.c
+--- openssh-6.8p1.orig/auth-pam.c	2015-04-13 20:23:30.769419286 +0200
++++ openssh-6.8p1/auth-pam.c	2015-04-14 08:07:16.092353124 +0200
+@@ -122,6 +122,10 @@
+  */
+ typedef pthread_t sp_pthread_t;
+ #else
++#define pthread_create openssh_pthread_create
++#define pthread_exit openssh_pthread_exit
++#define pthread_cancel openssh_pthread_cancel
++#define pthread_join openssh_pthread_join
+ typedef pid_t sp_pthread_t;
+ #endif
+ 
+@@ -277,6 +281,56 @@
+ # define pam_chauthtok(a,b)	(sshpam_chauthtok_ruid((a), (b)))
+ #endif
+ 
++struct passwd *
++sshpam_getpw(const char *user)
++{
++	struct passwd *pw;
++
++	if ((pw = getpwnam(user)) != NULL)
++		return(pw);
++
++	debug("PAM: faking passwd struct for user '%.100s'", user);
++	if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL)
++		return NULL;
++	pw->pw_name = xstrdup(user);	/* XXX leak */
++	pw->pw_shell = "/bin/true";
++	pw->pw_gecos = "sshd fake PAM user";
++	return (pw);
++}
++
++void
++sshpam_check_userchanged(void)
++{
++	int sshpam_err;
++	struct passwd *pw;
++	const char *user;
++
++	debug("sshpam_check_userchanged");
++	sshpam_err = pam_get_item(sshpam_handle, PAM_USER,
++				  (sshpam_const void **)&user);
++	if (sshpam_err != PAM_SUCCESS)
++		fatal("PAM: could not get PAM_USER: %s",
++		    pam_strerror(sshpam_handle, sshpam_err));
++	debug("sshpam_check_userchanged: user was '%.100s'",
++	      sshpam_authctxt->pw->pw_name);
++	if (strcmp(user, sshpam_authctxt->pw->pw_name) != 0) {
++		debug("PAM: user mapped from '%.100s' to '%.100s'",
++		    sshpam_authctxt->pw->pw_name, user);
++		if ((pw = getpwnam(user)) == NULL)
++			fatal("PAM: could not get passwd entry for user "
++			    "'%.100s' provided by PAM_USER", user);
++		pwfree(sshpam_authctxt->pw);
++		sshpam_authctxt->pw = pwcopy(pw);
++		sshpam_authctxt->valid = allowed_user(pw);
++		free(sshpam_authctxt->user);
++		sshpam_authctxt->user = xstrdup(user);
++		debug("PAM: user '%.100s' now %svalid", user,
++		    sshpam_authctxt->valid ? "" : "in");
++	}
++	debug("sshpam_check_userchanged: user is '%.100s'",
++	      sshpam_authctxt->pw->pw_name);
++}
++
+ void
+ sshpam_password_change_required(int reqd)
+ {
+@@ -299,7 +353,7 @@
+ static void
+ import_environments(Buffer *b)
+ {
+-	char *env;
++	char *env, *user;
+ 	u_int i, num_env;
+ 	int err;
+ 
+@@ -309,6 +363,17 @@
+ 	/* Import variables set by do_pam_account */
+ 	sshpam_account_status = buffer_get_int(b);
+ 	sshpam_password_change_required(buffer_get_int(b));
++	if (options.permit_pam_user_change) {
++		user = buffer_get_string(b, NULL);
++		debug("PAM: user is '%.100s'",
++		      sshpam_authctxt->pw->pw_name);
++		debug("PAM: got username '%.100s' from thread", user);
++		if ((err = pam_set_item(sshpam_handle, PAM_USER, user)) != PAM_SUCCESS)
++			fatal("PAM: failed to set PAM_USER: %s",
++			      pam_strerror(sshpam_handle, err));
++		pwfree(sshpam_authctxt->pw);
++		sshpam_authctxt->pw = pwcopy(sshpam_getpw(user));
++	}
+ 
+ 	/* Import environment from subprocess */
+ 	num_env = buffer_get_int(b);
+@@ -475,6 +540,13 @@
+ 	if (sshpam_err != PAM_SUCCESS)
+ 		goto auth_fail;
+ 
++	if (options.permit_pam_user_change) {
++		debug("sshpam_thread: user is '%.100s'",
++		      sshpam_authctxt->pw->pw_name);
++		sshpam_check_userchanged();
++		debug("sshpam_thread: user is '%.100s'",
++		      sshpam_authctxt->pw->pw_name);
++	}
+ 	if (compat20) {
+ 		if (!do_pam_account()) {
+ 			sshpam_err = PAM_ACCT_EXPIRED;
+@@ -495,6 +567,11 @@
+ 	/* Export variables set by do_pam_account */
+ 	buffer_put_int(&buffer, sshpam_account_status);
+ 	buffer_put_int(&buffer, sshpam_authctxt->force_pwchange);
++	if (options.permit_pam_user_change) {
++		debug("sshpam_thread: user is '%.100s'",
++		      sshpam_authctxt->pw->pw_name);
++		buffer_put_cstring(&buffer, sshpam_authctxt->pw->pw_name);
++	}
+ 
+ 	/* Export any environment strings set in child */
+ 	for(i = 0; environ[i] != NULL; i++)
+@@ -912,6 +989,18 @@
+ 	debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
+ 	    pam_strerror(sshpam_handle, sshpam_err));
+ 
++	if (options.permit_pam_user_change) {
++		debug("do_pam_account: user is '%.100s'",
++		      sshpam_authctxt->pw->pw_name);
++		sshpam_check_userchanged();
++		debug("do_pam_account: user is '%.100s'",
++		      sshpam_authctxt->pw->pw_name);
++		if (getpwnam(sshpam_authctxt->pw->pw_name) == NULL)
++		    fatal("PAM: completed authentication but PAM account invalid");
++		debug("do_pam_account: user is '%.100s'",
++		      sshpam_authctxt->pw->pw_name);
++	}
++
+ 	if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) {
+ 		sshpam_account_status = 0;
+ 		return (sshpam_account_status);
+@@ -1209,6 +1298,9 @@
+ 		    pam_strerror(sshpam_handle, sshpam_err));
+ 
+ 	sshpam_err = pam_authenticate(sshpam_handle, flags);
++	if (options.permit_pam_user_change) {
++		sshpam_check_userchanged();
++	}
+ 	sshpam_password = NULL;
+ 	if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
+ 		debug("PAM: password authentication accepted for %.100s",
+diff -Nur openssh-6.8p1.orig/auth-pam.h openssh-6.8p1/auth-pam.h
+--- openssh-6.8p1.orig/auth-pam.h	2015-04-13 20:23:30.590421330 +0200
++++ openssh-6.8p1/auth-pam.h	2015-04-13 20:24:30.209740445 +0200
+@@ -46,5 +46,6 @@
+ void sshpam_cleanup(void);
+ int sshpam_auth_passwd(Authctxt *, const char *);
+ int is_pam_session_open(void);
++struct passwd *sshpam_getpw(const char *);
+ 
+ #endif /* USE_PAM */
+diff -Nur openssh-6.8p1.orig/canohost.c openssh-6.8p1/canohost.c
+--- openssh-6.8p1.orig/canohost.c	2015-04-13 20:23:30.694420142 +0200
++++ openssh-6.8p1/canohost.c	2015-04-13 20:30:24.391695342 +0200
+@@ -17,6 +17,7 @@
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <sys/un.h>
++#include <sys/param.h>          /* for MAXHOSTNAMELEN */
+ 
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+@@ -468,3 +469,33 @@
+ {
+ 	return get_port(1);
+ }
++
++void
++resolve_localhost(char **host)
++{
++	struct hostent *hostinfo;
++
++	hostinfo = gethostbyname(*host);
++	if (hostinfo == NULL || hostinfo->h_name == NULL) {
++		debug("gethostbyname(%s) failed", *host);
++		return;
++	}
++	if (hostinfo->h_addrtype == AF_INET) {
++		struct in_addr addr;
++		addr = *(struct in_addr *)(hostinfo->h_addr);
++		if (ntohl(addr.s_addr) == INADDR_LOOPBACK) {
++			char buf[MAXHOSTNAMELEN];
++			if (gethostname(buf, sizeof(buf)) < 0) {
++				debug("gethostname() failed");
++				return;
++			}
++			hostinfo = gethostbyname(buf);
++			free(*host);
++			if (hostinfo == NULL || hostinfo->h_name == NULL) {
++				*host = xstrdup(buf);
++			} else {
++				*host = xstrdup(hostinfo->h_name);
++			}
++		}
++	}
++}
+diff -Nur openssh-6.8p1.orig/canohost.h openssh-6.8p1/canohost.h
+--- openssh-6.8p1.orig/canohost.h	2015-04-13 20:23:30.695420131 +0200
++++ openssh-6.8p1/canohost.h	2015-04-13 20:24:30.210740434 +0200
+@@ -27,4 +27,6 @@
+ int		 get_sock_port(int, int);
+ void		 clear_cached_addr(void);
+ 
++void		 resolve_localhost(char **host);
++
+ void		 ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *);
+diff -Nur openssh-6.8p1.orig/configure.ac openssh-6.8p1/configure.ac
+--- openssh-6.8p1.orig/configure.ac	2015-04-13 20:23:30.736419663 +0200
++++ openssh-6.8p1/configure.ac	2015-04-13 20:24:30.211740422 +0200
+@@ -4244,6 +4244,14 @@
+ 			AC_CHECK_HEADER([gssapi_krb5.h], ,
+ 					[ CPPFLAGS="$oldCPP" ])
+ 
++			# If we're using some other GSSAPI
++			if test -n "$GSSAPI" ; then
++				AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Kerberos GSI.])
++			fi
++
++			if test -z "$GSSAPI"; then
++				GSSAPI="KRB5";
++			fi
+ 		fi
+ 		if test ! -z "$need_dash_r" ; then
+ 			LDFLAGS="$LDFLAGS -R${KRB5ROOT}/lib"
+@@ -4283,6 +4291,50 @@
+ AC_SUBST([GSSLIBS])
+ AC_SUBST([K5LIBS])
+ 
++# Check whether the user wants GSI (Globus) support
++gsi="no"
++AC_ARG_WITH(gsi,
++	[  --with-gsi              Enable Globus GSI authentication support],
++	[
++		gsi="$withval"
++	]
++)
++
++if test "x$gsi" != "xno" ; then
++	# Globus GSSAPI configuration
++	AC_MSG_CHECKING(for Globus GSI)
++	AC_DEFINE(GSI, 1, [Define if you want GSI/Globus authentication support.])
++
++	if test -n "$GSSAPI" ; then
++		AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Globus GSI.])
++	fi
++
++	if test -z "$GSSAPI" ; then	
++		GSSAPI="GSI"
++	fi
++
++	LIBS="$LIBS `pkg-config --libs globus-gss-assist globus-gssapi-gsi globus-common`"
++	CPPFLAGS="$CPPFLAGS `pkg-config --cflags globus-gss-assist globus-gssapi-gsi globus-common`"
++
++	AC_DEFINE(GSSAPI)
++	AC_DEFINE(HAVE_GSSAPI_H)
++
++	AC_CHECK_FUNCS(globus_gss_assist_map_and_authorize)
++
++	dnl
++	dnl Check for globus_usage_stats_send
++	dnl
++	AC_SEARCH_LIBS(globus_usage_stats_send,
++	               globus_usage,
++	               AC_DEFINE([HAVE_GLOBUS_USAGE], 1, [Have Globus Usage]))
++	dnl
++	dnl Check for globus_usage_stats_send_array
++	dnl
++	AC_SEARCH_LIBS(globus_usage_stats_send_array,
++		       globus_usage,
++	               AC_DEFINE([HAVE_GLOBUS_USAGE_SEND_ARRAY], 1, [Have Globus Usage send_array]))
++fi
++
+ # Looking for programs, paths and files
+ 
+ PRIVSEP_PATH=/var/empty
+diff -Nur openssh-6.8p1.orig/gss-genr.c openssh-6.8p1/gss-genr.c
+--- openssh-6.8p1.orig/gss-genr.c	2015-04-13 20:23:30.666420462 +0200
++++ openssh-6.8p1/gss-genr.c	2015-04-13 20:24:30.212740411 +0200
+@@ -39,6 +39,7 @@
+ #include "xmalloc.h"
+ #include "buffer.h"
+ #include "log.h"
++#include "canohost.h"
+ #include "ssh2.h"
+ #include "cipher.h"
+ #include "key.h"
+@@ -368,9 +369,18 @@
+ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
+ {
+ 	gss_buffer_desc gssbuf;
++	char *xhost;
+ 	char *val;
+ 
+-	xasprintf(&val, "host@%s", host);
++	/* Make a copy of the host name, in case it was returned by a
++	 * previous call to gethostbyname(). */	
++	xhost = xstrdup(host);
++
++	/* Make sure we have the FQDN. Some GSSAPI implementations don't do
++	 * this for us themselves */
++	resolve_localhost(&xhost);
++	
++	xasprintf(&val, "host@%s", xhost);
+ 	gssbuf.value = val;
+ 	gssbuf.length = strlen(gssbuf.value);
+ 
+@@ -378,6 +388,7 @@
+ 	    &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name)))
+ 		ssh_gssapi_error(ctx);
+ 
++	free(xhost);
+ 	free(gssbuf.value);
+ 	return (ctx->major);
+ }
+diff -Nur openssh-6.8p1.orig/gss-serv.c openssh-6.8p1/gss-serv.c
+--- openssh-6.8p1.orig/gss-serv.c	2015-04-13 20:23:30.667420451 +0200
++++ openssh-6.8p1/gss-serv.c	2015-04-13 20:24:30.214740388 +0200
+@@ -47,14 +47,17 @@
+ #include "servconf.h"
+ #include "uidswap.h"
+ 
++#include "xmalloc.h"
+ #include "ssh-gss.h"
+ #include "monitor_wrap.h"
+ 
+ extern ServerOptions options;
++extern Authctxt *the_authctxt;
+ 
+ static ssh_gssapi_client gssapi_client =
+     { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
+-    GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME,  NULL, {NULL, NULL, NULL}, 0, 0};
++      GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL},
++      GSS_C_NO_CONTEXT, 0, 0};
+ 
+ ssh_gssapi_mech gssapi_null_mech =
+     { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
+@@ -62,14 +65,24 @@
+ #ifdef KRB5
+ extern ssh_gssapi_mech gssapi_kerberos_mech;
+ #endif
++#ifdef GSI
++extern ssh_gssapi_mech gssapi_gsi_mech;
++#endif
+ 
+ ssh_gssapi_mech* supported_mechs[]= {
+ #ifdef KRB5
+ 	&gssapi_kerberos_mech,
+ #endif
++#ifdef GSI
++	&gssapi_gsi_mech,
++#endif
+ 	&gssapi_null_mech,
+ };
+ 
++#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
++static int limited = 0;
++#endif
++
+ /*
+  * ssh_gssapi_supported_oids() can cause sandbox violations, so prepare the
+  * list of supported mechanisms before privsep is set up.
+@@ -230,6 +243,10 @@
+ 	    (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) {
+ 		if (ssh_gssapi_getclient(ctx, &gssapi_client))
+ 			fatal("Couldn't convert client name");
++#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
++		if (flags && (*flags & GSS_C_GLOBUS_LIMITED_PROXY_FLAG))
++			limited=1;
++#endif
+ 	}
+ 
+ 	return (status);
+@@ -249,6 +266,17 @@
+ 
+ 	tok = ename->value;
+ 
++#ifdef GSI /* GSI gss_export_name() is broken. */
++	if ((ctx->oid->length == gssapi_gsi_mech.oid.length) &&
++	    (memcmp(ctx->oid->elements, gssapi_gsi_mech.oid.elements,
++		    gssapi_gsi_mech.oid.length) == 0)) {
++		name->length = ename->length;
++		name->value = xmalloc(ename->length+1);
++		memcpy(name->value, ename->value, ename->length);
++		return GSS_S_COMPLETE;
++	}
++#endif
++
+ 	/*
+ 	 * Check that ename is long enough for all of the fixed length
+ 	 * header, and that the initial ID bytes are correct
+@@ -316,8 +344,11 @@
+ 			return GSS_S_COMPLETE;
+ 		}
+ 
+-		if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, 
+-		    ctx->client_creds, ctx->oid, &new_name, 
++		/* Call gss_inquire_cred rather than gss_inquire_cred_by_mech
++		   because GSI doesn't support the latter. -jbasney */
++
++		if ((ctx->major = gss_inquire_cred(&ctx->minor, 
++		    ctx->client_creds, &new_name, 
+ 		    NULL, NULL, NULL))) {
+ 			ssh_gssapi_error(ctx);
+ 			return (ctx->major);
+@@ -360,9 +391,12 @@
+ 	if (client->mech == NULL)
+ 		return GSS_S_FAILURE;
+ 
++	/* Call gss_inquire_cred rather than gss_inquire_cred_by_mech
++	   because GSI doesn't support the latter. -jbasney */
++
+ 	if (ctx->client_creds &&
+-	    (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
+-	     ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
++	    (ctx->major = gss_inquire_cred(&ctx->minor,
++	     ctx->client_creds, &client->name, NULL, NULL, NULL))) {
+ 		ssh_gssapi_error(ctx);
+ 		return (ctx->major);
+ 	}
+@@ -389,6 +423,10 @@
+ 	/* 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;
++
++	/* needed for globus_gss_assist_map_and_authorize() */
++	client->context = ctx->context;
++
+ 	return (ctx->major);
+ }
+ 
+@@ -396,6 +434,7 @@
+ void
+ ssh_gssapi_cleanup_creds(void)
+ {
++#ifdef KRB5
+ 	krb5_ccache ccache = NULL;
+ 	krb5_error_code problem;
+ 
+@@ -411,6 +450,14 @@
+ 			gssapi_client.store.data = NULL;
+ 		}
+ 	}
++#else
++	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);
++	}
++#endif
+ }
+ 
+ /* As user */
+@@ -418,6 +465,11 @@
+ ssh_gssapi_storecreds(void)
+ {
+ 	if (gssapi_client.mech && gssapi_client.mech->storecreds) {
++		if (options.gss_creds_path) {
++			gssapi_client.store.filename =
++				expand_authorized_keys(options.gss_creds_path,
++						       the_authctxt->pw);
++		}
+ 		(*gssapi_client.mech->storecreds)(&gssapi_client);
+ 	} else
+ 		debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
+@@ -441,8 +493,9 @@
+ }
+ 
+ /* Privileged */
++/* gssapi_keyex arg added for Globus usage */
+ int
+-ssh_gssapi_userok(char *user, struct passwd *pw)
++ssh_gssapi_userok(char *user, struct passwd *pw, int gssapi_keyex)
+ {
+ 	OM_uint32 lmin;
+ 
+@@ -451,6 +504,12 @@
+ 		debug("No suitable client data");
+ 		return 0;
+ 	}
++#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
++	if (limited && options.gsi_allow_limited_proxy != 1) {
++		debug("limited proxy not acceptable for remote login");
++		return 0;
++	}
++#endif
+ 	if (gssapi_client.mech && gssapi_client.mech->userok)
+ 		if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
+ 			gssapi_client.used = 1;
+@@ -470,6 +529,24 @@
+ 	return (0);
+ }
+ 
++/* Priviledged */
++int
++ssh_gssapi_localname(char **user)
++{
++    	*user = NULL;
++	if (gssapi_client.displayname.length == 0 || 
++	    gssapi_client.displayname.value == NULL) {
++		debug("No suitable client data");
++		return(0);
++	}
++	if (gssapi_client.mech && gssapi_client.mech->localname) {
++		return((*gssapi_client.mech->localname)(&gssapi_client,user));
++	} else {
++		debug("Unknown client authentication type");
++	}
++	return(0);
++}
++
+ /* These bits are only used for rekeying. The unpriviledged child is running 
+  * as the user, the monitor is root.
+  *
+@@ -496,6 +573,7 @@
+ 	pam_handle_t *pamh = NULL;
+ 	struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
+ 	char *envstr;
++	char **p; char **pw;
+ #endif
+ 
+ 	if (gssapi_client.store.filename == NULL && 
+@@ -525,6 +603,18 @@
+ 	if (ret)
+ 		return;
+ 
++	/* Put ssh pam stack env variables in this new pam stack env 
++	 * Using pam-pkinit, KRB5CCNAME is set during do_pam_session
++	 * this addition enables pam-pkinit to access KRB5CCNAME if used 
++	 * in sshd-rekey stack too
++	 */
++	pw = p = fetch_pam_environment();
++	while ( *pw != NULL ) {
++	        pam_putenv(pamh, *pw);
++		pw++;
++	}
++	free_pam_environment(p);
++
+ 	xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, 
+ 	    gssapi_client.store.envval);
+ 
+@@ -556,4 +646,13 @@
+ 	return ok;
+ }
+ 
++/* added for Globus usage */
++void
++ssh_gssapi_get_client_info(char **userdn, char **mech) {
++	*userdn = gssapi_client.displayname.value;
++
++	if (gssapi_client.mech)
++		*mech = gssapi_client.mech->name;
++}
++
+ #endif
+diff -Nur openssh-6.8p1.orig/gss-serv-gsi.c openssh-6.8p1/gss-serv-gsi.c
+--- openssh-6.8p1.orig/gss-serv-gsi.c	1970-01-01 01:00:00.000000000 +0100
++++ openssh-6.8p1/gss-serv-gsi.c	2015-04-13 23:54:37.138628621 +0200
+@@ -0,0 +1,239 @@
++/*
++ * Copyright (c) 2001-2003 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
++#ifdef GSI
++
++#include <sys/types.h>
++
++#include <stdarg.h>
++#include <string.h>
++
++#include "xmalloc.h"
++#include "key.h"
++#include "hostfile.h"
++#include "auth.h"
++#include "log.h"
++#include "misc.h"      /* servconf.h needs misc.h for struct ForwardOptions */
++#include "servconf.h"
++
++#include "buffer.h"
++#include "ssh-gss.h"
++
++extern ServerOptions options;
++
++#include <globus_gss_assist.h>
++
++static int ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name);
++static int ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user);
++static void ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client);
++static int ssh_gssapi_gsi_updatecreds(ssh_gssapi_ccache *store,
++				       ssh_gssapi_client *client);
++
++ssh_gssapi_mech gssapi_gsi_mech = {
++	"dZuIebMjgUqaxvbF7hDbAw==",
++	"GSI",
++	{9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"},
++	NULL,
++	&ssh_gssapi_gsi_userok,
++	&ssh_gssapi_gsi_localname,
++	&ssh_gssapi_gsi_storecreds,
++	&ssh_gssapi_gsi_updatecreds
++};
++
++/*
++ * Check if this user is OK to login under GSI. User has been authenticated
++ * as identity in global 'client_name.value' and is trying to log in as passed
++ * username in 'name'.
++ *
++ * Returns non-zero if user is authorized, 0 otherwise.
++ */
++static int
++ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name)
++{
++    int authorized = 0;
++    globus_result_t res;
++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
++    char lname[256] = "";
++#endif
++    
++#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
++    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
++	return 0;
++    }
++#endif
++
++/* use new globus_gss_assist_map_and_authorize() interface if available */
++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
++    debug("calling globus_gss_assist_map_and_authorize()");
++    if (GLOBUS_SUCCESS !=
++        (res = globus_gss_assist_map_and_authorize(client->context, "ssh",
++                                                   name, lname, 256))) {
++        debug("%s", globus_error_print_chain(globus_error_get(res)));
++    } else if (lname[0] && strcmp(name, lname) != 0) {
++        debug("GSI user maps to %s, not %s", lname, name);
++    } else {
++        authorized = 1;
++    }
++#else
++    debug("calling globus_gss_assist_userok()");
++    if (GLOBUS_SUCCESS !=
++        (res = (globus_gss_assist_userok(client->displayname.value,
++                                         name)))) {
++        debug("%s", globus_error_print_chain(globus_error_get(res)));
++    } else {
++        authorized = 1;
++    }
++#endif
++    
++    logit("GSI user %s is%s authorized as target user %s",
++	(char *) client->displayname.value, (authorized ? "" : " not"), name);
++    
++    return authorized;
++}
++
++/*
++ * Return the local username associated with the GSI credentials.
++ */
++int
++ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user)
++{
++    globus_result_t res;
++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
++    char lname[256] = "";
++#endif
++
++#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
++    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
++	return 0;
++    }
++#endif
++
++/* use new globus_gss_assist_map_and_authorize() interface if available */
++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
++    debug("calling globus_gss_assist_map_and_authorize()");
++    if (GLOBUS_SUCCESS !=
++        (res = globus_gss_assist_map_and_authorize(client->context, "ssh",
++                                                   NULL, lname, 256))) {
++        debug("%s", globus_error_print_chain(globus_error_get(res)));
++        logit("failed to map GSI user %s", (char *)client->displayname.value);
++        return 0;
++    }
++    *user = strdup(lname);
++#else
++    debug("calling globus_gss_assist_gridmap()");
++    if (GLOBUS_SUCCESS !=
++        (res = globus_gss_assist_gridmap(client->displayname.value, user))) {
++        debug("%s", globus_error_print_chain(globus_error_get(res)));
++        logit("failed to map GSI user %s", (char *)client->displayname.value);
++        return 0;
++    }
++#endif
++
++    logit("GSI user %s mapped to target user %s",
++          (char *) client->displayname.value, *user);
++
++    return 1;
++}
++
++/*
++ * Export GSI credentials to disk.
++ */
++static void
++ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client)
++{
++	OM_uint32	major_status;
++	OM_uint32	minor_status;
++	gss_buffer_desc	export_cred = GSS_C_EMPTY_BUFFER;
++	char *		p;
++	
++	if (!client || !client->creds) {
++	    return;
++	}
++
++	major_status = gss_export_cred(&minor_status,
++				       client->creds,
++				       GSS_C_NO_OID,
++				       1,
++				       &export_cred);
++	if (GSS_ERROR(major_status) && major_status != GSS_S_UNAVAILABLE) {
++	    Gssctxt *ctx;
++	    ssh_gssapi_build_ctx(&ctx);
++	    ctx->major = major_status;
++	    ctx->minor = minor_status;
++	    ssh_gssapi_set_oid(ctx, &gssapi_gsi_mech.oid);
++	    ssh_gssapi_error(ctx);
++	    ssh_gssapi_delete_ctx(&ctx);
++	    return;
++	}
++	
++	p = strchr((char *) export_cred.value, '=');
++	if (p == NULL) {
++	    logit("Failed to parse exported credentials string '%.100s'",
++		(char *)export_cred.value);
++	    gss_release_buffer(&minor_status, &export_cred);
++	    return;
++	}
++	*p++ = '\0';
++	if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0) {
++	    client->store.envvar = strdup("X509_USER_PROXY");
++	} else {
++	    client->store.envvar = strdup((char *)export_cred.value);
++	}
++	if (access(p, R_OK) == 0) {
++        if (client->store.filename) {
++            if (rename(p, client->store.filename) < 0) {
++                logit("Failed to rename %s to %s: %s", p,
++                      client->store.filename, strerror(errno));
++                free(client->store.filename);
++                client->store.filename = strdup(p);
++            } else {
++                p = client->store.filename;
++            }
++        } else {
++            client->store.filename = strdup(p);
++        }
++	}
++	client->store.envval = strdup(p);
++#ifdef USE_PAM
++	if (options.use_pam)
++	    do_pam_putenv(client->store.envvar, client->store.envval);
++#endif
++	gss_release_buffer(&minor_status, &export_cred);
++}
++
++/*
++ * Export updated GSI credentials to disk.
++ */
++static int
++ssh_gssapi_gsi_updatecreds(ssh_gssapi_ccache *store,ssh_gssapi_client *client)
++{
++	ssh_gssapi_gsi_storecreds(client);
++	return 1;
++}
++
++#endif /* GSI */
++#endif /* GSSAPI */
+diff -Nur openssh-6.8p1.orig/gss-serv-krb5.c openssh-6.8p1/gss-serv-krb5.c
+--- openssh-6.8p1.orig/gss-serv-krb5.c	2015-04-13 20:23:30.722419823 +0200
++++ openssh-6.8p1/gss-serv-krb5.c	2015-04-13 20:24:30.215740377 +0200
+@@ -359,6 +359,34 @@
+ 	return found_principal;
+ }
+  
++/* Retrieve the local username associated with a set of Kerberos 
++ * credentials. Hopefully we can use this for the 'empty' username
++ * logins discussed in the draft  */
++static int
++ssh_gssapi_krb5_localname(ssh_gssapi_client *client, char **user) {
++	krb5_principal princ;
++	int retval;
++
++	if (ssh_gssapi_krb5_init() == 0)
++		return 0;
++
++	if ((retval=krb5_parse_name(krb_context, client->displayname.value, 
++				    &princ))) {
++		logit("krb5_parse_name(): %.100s", 
++			krb5_get_err_text(krb_context,retval));
++		return 0;
++	}
++
++	/* We've got to return a malloc'd string */
++	*user = (char *)xmalloc(256);
++	if (krb5_aname_to_localname(krb_context, princ, 256, *user)) {
++		free(*user);
++		*user = NULL;
++		return(0);
++	}
++
++	return(1);
++}
+ 
+ /* This writes out any forwarded credentials from the structure populated
+  * during userauth. Called after we have setuid to the user */
+@@ -463,7 +491,7 @@
+ 	return;
+ }
+ 
+-int
++static int
+ ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, 
+     ssh_gssapi_client *client)
+ {
+@@ -534,7 +562,7 @@
+ 	{9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"},
+ 	NULL,
+ 	&ssh_gssapi_krb5_userok,
+-	NULL,
++	&ssh_gssapi_krb5_localname,
+ 	&ssh_gssapi_krb5_storecreds,
+ 	&ssh_gssapi_krb5_updatecreds
+ };
+diff -Nur openssh-6.8p1.orig/kexgsss.c openssh-6.8p1/kexgsss.c
+--- openssh-6.8p1.orig/kexgsss.c	2015-04-13 20:23:30.668420439 +0200
++++ openssh-6.8p1/kexgsss.c	2015-04-13 20:24:30.216740365 +0200
+@@ -47,6 +47,7 @@
+ #include "ssh-gss.h"
+ #include "digest.h"
+ 
++static void kex_gss_send_error(Gssctxt *ctxt);
+ extern ServerOptions options;
+ 
+ int
+@@ -94,8 +95,10 @@
+ 
+ 	debug2("%s: Acquiring credentials", __func__);
+ 
+-	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
++	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) {
++		kex_gss_send_error(ctxt);
+ 		fatal("Unable to acquire credentials for the server");
++	}
+ 
+ 	switch (ssh->kex->kex_type) {
+ 	case KEX_GSS_GRP1_SHA1:
+@@ -181,12 +184,13 @@
+ 	} while (maj_status & GSS_S_CONTINUE_NEEDED);
+ 
+ 	if (GSS_ERROR(maj_status)) {
++		kex_gss_send_error(ctxt);
+ 		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");
++		packet_disconnect("GSSAPI Key Exchange handshake failed");
+ 	}
+ 
+ 	if (!(ret_flags & GSS_C_MUTUAL_FLAG))
+@@ -292,4 +296,23 @@
+ 		ssh_gssapi_rekey_creds();
+ 	return 0;
+ }
++
++static void 
++kex_gss_send_error(Gssctxt *ctxt) {
++	char *errstr;
++	OM_uint32 maj,min;
++		
++	errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
++	if (errstr) {
++		packet_start(SSH2_MSG_KEXGSS_ERROR);
++		packet_put_int(maj);
++		packet_put_int(min);
++		packet_put_cstring(errstr);
++		packet_put_cstring("");
++		packet_send();
++		packet_write_wait();
++		/* XXX - We should probably log the error locally here */
++		free(errstr);
++	}
++}
+ #endif /* GSSAPI */
+diff -Nur openssh-6.8p1.orig/LICENSE.globus_usage openssh-6.8p1/LICENSE.globus_usage
+--- openssh-6.8p1.orig/LICENSE.globus_usage	1970-01-01 01:00:00.000000000 +0100
++++ openssh-6.8p1/LICENSE.globus_usage	2015-04-13 20:24:30.216740365 +0200
+@@ -0,0 +1,18 @@
++/*
++ * Portions of the Usage Metrics suport code are derived from the
++ * Globus project's GridFTP subject to the following license.
++ *
++ * Copyright 2010 University of Chicago
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
+diff -Nur openssh-6.8p1.orig/Makefile.in openssh-6.8p1/Makefile.in
+--- openssh-6.8p1.orig/Makefile.in	2015-04-13 20:23:30.759419400 +0200
++++ openssh-6.8p1/Makefile.in	2015-04-13 20:24:30.217740354 +0200
+@@ -113,8 +113,10 @@
+ 	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  kexgsss.o \
++	gss-serv-gsi.o \
+ 	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
+ 	sftp-server.o sftp-common.o \
++	ssh-globus-usage.o \
+ 	roaming_common.o roaming_serv.o \
+ 	sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
+ 	sandbox-seccomp-filter.o sandbox-capsicum.o
+diff -Nur openssh-6.8p1.orig/misc.c openssh-6.8p1/misc.c
+--- openssh-6.8p1.orig/misc.c	2015-04-13 20:23:30.719419857 +0200
++++ openssh-6.8p1/misc.c	2015-04-13 20:24:30.218740342 +0200
+@@ -160,11 +160,14 @@
+ #define WHITESPACE " \t\r\n"
+ #define QUOTE	"\""
+ 
++/* Characters considered as quotations. */
++#define QUOTES "'\""
++
+ /* return next token in configuration line */
+ char *
+ strdelim(char **s)
+ {
+-	char *old;
++	char *old, *p, *q;
+ 	int wspace = 0;
+ 
+ 	if (*s == NULL)
+@@ -172,6 +175,21 @@
+ 
+ 	old = *s;
+ 
++	if ((q=strchr(QUOTES, (int) *old)) && *q)
++	{
++		/* find next quote character, point old to start of quoted
++		 * string */
++		for (p = ++old; *p && *p != *q; p++)
++			;
++
++		/* find start of next token */
++		*s = (*p) ? p + strspn(p + 1, WHITESPACE) + 1 : NULL;
++
++		/* terminate 'old' token */
++		*p = '\0';
++		return (old);
++	}
++
+ 	*s = strpbrk(*s, WHITESPACE QUOTE "=");
+ 	if (*s == NULL)
+ 		return (old);
+@@ -227,6 +245,20 @@
+ 	return copy;
+ }
+ 
++void
++pwfree(struct passwd *pw)
++{
++	free(pw->pw_name);
++	free(pw->pw_passwd);
++	free(pw->pw_gecos);
++#ifdef HAVE_PW_CLASS_IN_PASSWD
++	free(pw->pw_class);
++#endif
++	free(pw->pw_dir);
++	free(pw->pw_shell);
++	free(pw);
++}
++
+ /*
+  * Convert ASCII string to TCP/IP port number.
+  * Port must be >=0 and <=65535.
+diff -Nur openssh-6.8p1.orig/misc.h openssh-6.8p1/misc.h
+--- openssh-6.8p1.orig/misc.h	2015-04-13 20:23:30.698420097 +0200
++++ openssh-6.8p1/misc.h	2015-04-13 20:24:30.218740342 +0200
+@@ -61,6 +61,7 @@
+ void	 sock_set_v6only(int);
+ 
+ struct passwd *pwcopy(struct passwd *);
++void pwfree(struct passwd *);
+ const char *ssh_gai_strerror(int);
+ 
+ typedef struct arglist arglist;
+diff -Nur openssh-6.8p1.orig/monitor.c openssh-6.8p1/monitor.c
+--- openssh-6.8p1.orig/monitor.c	2015-04-13 20:23:30.771419263 +0200
++++ openssh-6.8p1/monitor.c	2015-04-13 20:24:30.220740320 +0200
+@@ -164,6 +164,9 @@
+ 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_error(int, Buffer *);
++int mm_answer_gss_indicate_mechs(int, Buffer *);
++int mm_answer_gss_localname(int, Buffer *);
+ int mm_answer_gss_updatecreds(int, Buffer *);
+ #endif
+ 
+@@ -217,7 +220,7 @@
+     {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli},
+ #endif
+     {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
+-    {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
++    {MONITOR_REQ_PWNAM, MON_AUTH, mm_answer_pwnamallow},
+     {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
+ #ifdef WITH_SELINUX
+     {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole},
+@@ -225,7 +228,7 @@
+     {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
+     {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
+ #ifdef USE_PAM
+-    {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
++    {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start},
+     {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
+     {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
+     {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
+@@ -255,6 +258,9 @@
+     {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},
++    {MONITOR_REQ_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error},
++    {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs},
++    {MONITOR_REQ_GSSLOCALNAME, MON_ISAUTH, mm_answer_gss_localname},
+ #endif
+     {0, 0, NULL}
+ };
+@@ -264,6 +270,8 @@
+     {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_GSSERR, 0, mm_answer_gss_error},
++    {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs},
+     {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
+ #endif
+ #ifdef WITH_OPENSSL
+@@ -304,7 +312,7 @@
+     {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond},
+ #endif
+ #ifdef USE_PAM
+-    {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
++    {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start},
+     {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
+     {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
+     {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
+@@ -399,6 +407,8 @@
+ #ifdef GSSAPI
+ 		/* and for the GSSAPI key exchange */
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
++		monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
++		monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1);
+ #endif
+ 	} else {
+ 		mon_dispatch = mon_dispatch_proto15;
+@@ -513,6 +523,8 @@
+ #ifdef GSSAPI
+ 		/* and for the GSSAPI key exchange */
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
++		monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
++		monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1);
+ #endif		
+ 	} else {
+ 		mon_dispatch = mon_dispatch_postauth15;
+@@ -844,14 +856,17 @@
+ 
+ 	debug3("%s", __func__);
+ 
+-	if (authctxt->attempt++ != 0)
+-		fatal("%s: multiple attempts for getpwnam", __func__);
+-
+ 	username = buffer_get_string(m, NULL);
+ 
+ 	pwent = getpwnamallow(username);
+ 
++	if (authctxt->user) free(authctxt->user);
+ 	authctxt->user = xstrdup(username);
++#ifdef USE_PAM
++	if (options.permit_pam_user_change)
++		setproctitle("%s [priv]", pwent ? "[pam]" : "unknown");
++	else
++#endif
+ 	setproctitle("%s [priv]", pwent ? username : "unknown");
+ 	free(username);
+ 
+@@ -2221,12 +2236,15 @@
+ mm_answer_gss_userok(int sock, Buffer *m)
+ {
+ 	int authenticated;
++	int gssapi_keyex;
+ 
+ 	if (!options.gss_authentication && !options.gss_keyex)
+ 		fatal("In GSSAPI monitor when GSSAPI is disabled");
+ 
++	gssapi_keyex = buffer_get_int(m);
++
+ 	authenticated = authctxt->valid && 
+-	    ssh_gssapi_userok(authctxt->user, authctxt->pw);
++	    ssh_gssapi_userok(authctxt->user, authctxt->pw, gssapi_keyex);
+ 
+ 	buffer_clear(m);
+ 	buffer_put_int(m, authenticated);
+@@ -2234,12 +2252,77 @@
+ 	debug3("%s: sending result %d", __func__, authenticated);
+ 	mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m);
+ 
+-	auth_method = "gssapi-with-mic";
++	if (gssapi_keyex)
++		auth_method = "gssapi-keyex";
++	else
++		auth_method = "gssapi-with-mic";
+ 
+ 	/* Monitor loop will terminate if authenticated */
+ 	return (authenticated);
+ }
+ 
++int
++mm_answer_gss_error(int socket, Buffer *m) {
++	OM_uint32 major, minor;
++	char *msg;
++
++	msg=ssh_gssapi_last_error(gsscontext, &major, &minor);
++	buffer_clear(m);
++	buffer_put_int(m, major);
++	buffer_put_int(m, minor);
++	buffer_put_cstring(m, msg);
++
++	mm_request_send(socket, MONITOR_ANS_GSSERR, m);
++
++	free(msg);
++
++	return(0);
++}
++
++int
++mm_answer_gss_indicate_mechs(int socket, Buffer *m) {
++	OM_uint32 major, minor;
++	gss_OID_set mech_set;
++	size_t i;
++
++	major=gss_indicate_mechs(&minor, &mech_set);
++
++	buffer_clear(m);
++	buffer_put_int(m, major);
++	buffer_put_int(m, mech_set->count);
++	for (i = 0; i < mech_set->count; i++) {
++		buffer_put_string(m, mech_set->elements[i].elements,
++				  mech_set->elements[i].length);
++	}
++
++	gss_release_oid_set(&minor, &mech_set);
++
++	mm_request_send(socket, MONITOR_ANS_GSSMECHS, m);
++
++	return(0);
++}
++
++int
++mm_answer_gss_localname(int socket, Buffer *m) {
++	char *name;
++
++	ssh_gssapi_localname(&name);
++
++	buffer_clear(m);
++	if (name) {
++		buffer_put_cstring(m, name);
++		debug3("%s: sending result %s", __func__, name);
++		free(name);
++	} else {
++		buffer_put_cstring(m, "");
++		debug3("%s: sending result \"\"", __func__);
++	}
++
++	mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m);
++
++	return(0);
++}
++
+ int 
+ mm_answer_gss_sign(int socket, Buffer *m)
+ {
+diff -Nur openssh-6.8p1.orig/monitor.h openssh-6.8p1/monitor.h
+--- openssh-6.8p1.orig/monitor.h	2015-04-13 20:23:30.752419480 +0200
++++ openssh-6.8p1/monitor.h	2015-04-13 20:24:30.221740308 +0200
+@@ -75,8 +75,10 @@
+ 	MONITOR_REQ_AUDIT_UNSUPPORTED = 118, MONITOR_ANS_AUDIT_UNSUPPORTED = 119,
+ 	MONITOR_REQ_AUDIT_KEX = 120, MONITOR_ANS_AUDIT_KEX = 121,
+ 	MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 122, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 123,
+-	MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124, MONITOR_ANS_AUDIT_SERVER_KEY_FREE = 125
+-
++	MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124, MONITOR_ANS_AUDIT_SERVER_KEY_FREE = 125,
++	MONITOR_REQ_GSSMECHS = 200, MONITOR_ANS_GSSMECHS = 201,
++	MONITOR_REQ_GSSLOCALNAME = 202, MONITOR_ANS_GSSLOCALNAME = 203,
++	MONITOR_REQ_GSSERR = 204, MONITOR_ANS_GSSERR = 205,
+ };
+ 
+ struct mm_master;
+diff -Nur openssh-6.8p1.orig/monitor_wrap.c openssh-6.8p1/monitor_wrap.c
+--- openssh-6.8p1.orig/monitor_wrap.c	2015-04-13 20:23:30.771419263 +0200
++++ openssh-6.8p1/monitor_wrap.c	2015-04-13 20:24:30.222740297 +0200
+@@ -1121,12 +1121,13 @@
+ }
+ 
+ int
+-mm_ssh_gssapi_userok(char *user, struct passwd *pw)
++mm_ssh_gssapi_userok(char *user, struct passwd *pw, int gssapi_keyex)
+ {
+ 	Buffer m;
+ 	int authenticated = 0;
+ 
+ 	buffer_init(&m);
++	buffer_put_int(&m, gssapi_keyex);
+ 
+ 	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m);
+ 	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK,
+@@ -1139,6 +1140,83 @@
+ 	return (authenticated);
+ }
+ 
++char *
++mm_ssh_gssapi_last_error(Gssctxt *ctx, OM_uint32 *major, OM_uint32 *minor) {
++	Buffer m;
++	OM_uint32 maj,min;
++	char *errstr;
++
++	buffer_init(&m);
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSERR, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSERR, &m);
++
++	maj = buffer_get_int(&m);
++	min = buffer_get_int(&m);
++
++	if (major) *major=maj;
++	if (minor) *minor=min;
++
++	errstr=buffer_get_string(&m,NULL);
++
++	buffer_free(&m);
++
++	return(errstr);
++}
++
++OM_uint32
++mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set)
++{
++	Buffer m;
++	OM_uint32 major,minor;
++	int count;
++	gss_OID_desc oid;
++	u_int length;
++
++	buffer_init(&m);
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSMECHS, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSMECHS,
++				  &m);
++	major=buffer_get_int(&m);
++	count=buffer_get_int(&m);
++	
++	gss_create_empty_oid_set(&minor,mech_set);
++	while(count-->0) {
++	    oid.elements=buffer_get_string(&m,&length);
++	    oid.length=length;
++	    gss_add_oid_set_member(&minor,&oid,mech_set);
++	}
++
++	buffer_free(&m);
++	
++	return(major);
++}
++
++int
++mm_ssh_gssapi_localname(char **lname)
++{
++	Buffer m;
++
++	buffer_init(&m);
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, &m);
++
++	debug3("%s: waiting for MONITOR_ANS_GSSLOCALNAME", __func__);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME,
++				  &m);
++
++	*lname = buffer_get_string(&m, NULL);
++
++	buffer_free(&m);
++	if (lname[0] == '\0') {
++	    debug3("%s: gssapi identity mapping failed", __func__);
++	} else {
++	    debug3("%s: gssapi identity mapped to %s", __func__, *lname);
++	}
++
++	return(0);
++}
++
+ OM_uint32
+ mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
+ {
+diff -Nur openssh-6.8p1.orig/monitor_wrap.h openssh-6.8p1/monitor_wrap.h
+--- openssh-6.8p1.orig/monitor_wrap.h	2015-04-13 20:23:30.752419480 +0200
++++ openssh-6.8p1/monitor_wrap.h	2015-04-13 20:24:30.223740285 +0200
+@@ -62,9 +62,13 @@
+ 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, struct passwd *);
++int mm_ssh_gssapi_userok(char *user, struct passwd *, int gssapi_keyex);
+ 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_localname(char **user);
++OM_uint32 mm_gss_indicate_mechs(OM_uint32 *minor_status,
++				gss_OID_set *mech_set);
++char *mm_ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min);
+ int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
+ #endif
+ 
+diff -Nur openssh-6.8p1.orig/readconf.c openssh-6.8p1/readconf.c
+--- openssh-6.8p1.orig/readconf.c	2015-04-13 20:23:30.670420417 +0200
++++ openssh-6.8p1/readconf.c	2015-04-13 20:24:30.224740274 +0200
+@@ -1763,13 +1763,13 @@
+ 	if (options->challenge_response_authentication == -1)
+ 		options->challenge_response_authentication = 1;
+ 	if (options->gss_authentication == -1)
+-		options->gss_authentication = 0;
++		options->gss_authentication = 1;
+ 	if (options->gss_keyex == -1)
+-		options->gss_keyex = 0;
++		options->gss_keyex = 1;
+ 	if (options->gss_deleg_creds == -1)
+-		options->gss_deleg_creds = 0;
++		options->gss_deleg_creds = 1;
+ 	if (options->gss_trust_dns == -1)
+-		options->gss_trust_dns = 0;
++		options->gss_trust_dns = 1;
+ 	if (options->gss_renewal_rekey == -1)
+ 		options->gss_renewal_rekey = 0;
+ 	if (options->password_authentication == -1)
+diff -Nur openssh-6.8p1.orig/readconf.h openssh-6.8p1/readconf.h
+--- openssh-6.8p1.orig/readconf.h	2015-04-13 20:23:30.670420417 +0200
++++ openssh-6.8p1/readconf.h	2015-04-13 20:24:30.225740263 +0200
+@@ -84,6 +84,8 @@
+ 	char   *host_key_alias;	/* hostname alias for .ssh/known_hosts */
+ 	char   *proxy_command;	/* Proxy command for connecting the host. */
+ 	char   *user;		/* User to log in as. */
++	int     implicit;	/* Login user was not specified.
++				   Server may choose based on authctxt. */
+ 	int     escape_char;	/* Escape character; -2 = none */
+ 
+ 	u_int	num_system_hostfiles;	/* Paths for /etc/ssh/ssh_known_hosts */
+diff -Nur openssh-6.8p1.orig/servconf.c openssh-6.8p1/servconf.c
+--- openssh-6.8p1.orig/servconf.c	2015-04-13 20:23:30.772419252 +0200
++++ openssh-6.8p1/servconf.c	2015-04-14 10:46:40.415664385 +0200
+@@ -74,6 +74,7 @@
+ 
+ 	/* Portable-specific options */
+ 	options->use_pam = -1;
++	options->permit_pam_user_change = -1;
+ 
+ 	/* Standard Options */
+ 	options->num_ports = 0;
+@@ -114,9 +115,11 @@
+ 	options->kerberos_ticket_cleanup = -1;
+ 	options->kerberos_get_afs_token = -1;
+ 	options->gss_authentication=-1;
++	options->gss_deleg_creds = -1;
+ 	options->gss_keyex = -1;
+ 	options->gss_cleanup_creds = -1;
+ 	options->gss_strict_acceptor = -1;
++	options->gsi_allow_limited_proxy = -1;
+ 	options->gss_store_rekey = -1;
+ 	options->password_authentication = -1;
+ 	options->kbd_interactive_authentication = -1;
+@@ -160,6 +163,8 @@
+ 	options->chroot_directory = NULL;
+ 	options->authorized_keys_command = NULL;
+ 	options->authorized_keys_command_user = NULL;
++	options->disable_usage_stats = 0;
++	options->usage_stats_targets = NULL;
+ 	options->revoked_keys_file = NULL;
+ 	options->trusted_user_ca_keys = NULL;
+ 	options->authorized_principals_file = NULL;
+@@ -186,6 +191,8 @@
+ 	/* Portable-specific options */
+ 	if (options->use_pam == -1)
+ 		options->use_pam = 0;
++	if (options->permit_pam_user_change == -1)
++		options->permit_pam_user_change = 0;
+ 
+ 	/* Standard Options */
+ 	if (options->protocol == SSH_PROTO_UNKNOWN)
+@@ -274,13 +281,17 @@
+ 	if (options->kerberos_get_afs_token == -1)
+ 		options->kerberos_get_afs_token = 0;
+ 	if (options->gss_authentication == -1)
+-		options->gss_authentication = 0;
++		options->gss_authentication = 1;
++	if (options->gss_deleg_creds == -1)
++		options->gss_deleg_creds = 1;
+ 	if (options->gss_keyex == -1)
+-		options->gss_keyex = 0;
++		options->gss_keyex = 1;
+ 	if (options->gss_cleanup_creds == -1)
+ 		options->gss_cleanup_creds = 1;
+ 	if (options->gss_strict_acceptor == -1)
+ 		options->gss_strict_acceptor = 1;
++	if (options->gsi_allow_limited_proxy == -1)
++		options->gsi_allow_limited_proxy = 0;
+ 	if (options->gss_store_rekey == -1)
+ 		options->gss_store_rekey = 0;
+ 	if (options->password_authentication == -1)
+@@ -388,7 +399,7 @@
+ typedef enum {
+ 	sBadOption,		/* == unknown option */
+ 	/* Portable-specific options */
+-	sUsePAM,
++	sUsePAM, sPermitPAMUserChange,
+ 	/* Standard Options */
+ 	sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime,
+ 	sKeyRegenerationTime, sPermitRootLogin, sLogFacility, sLogLevel,
+@@ -409,10 +420,14 @@
+ 	sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication,
+ 	sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes,
+ 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
++	sGssDelegateCreds,
++	sGssCredsPath,
++	sGsiAllowLimitedProxy,
+ 	sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor,
+ 	sGssKeyEx, sGssStoreRekey, sAcceptEnv, sPermitTunnel,
+ 	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
+ 	sUsePrivilegeSeparation, sAllowAgentForwarding,
++	sDisUsageStats, sUsageStatsTarg,
+ 	sHostCertificate,
+ 	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
+ 	sKexAlgorithms, sIPQoS, sVersionAddendum,
+@@ -436,8 +451,10 @@
+ 	/* Portable-specific options */
+ #ifdef USE_PAM
+ 	{ "usepam", sUsePAM, SSHCFG_GLOBAL },
++	{ "permitpamuserchange", sPermitPAMUserChange, SSHCFG_GLOBAL },
+ #else
+ 	{ "usepam", sUnsupported, SSHCFG_GLOBAL },
++	{ "permitpamuserchange", sUnsupported, SSHCFG_GLOBAL },
+ #endif
+ 	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
+ 	/* Standard Options */
+@@ -482,16 +499,26 @@
+ 	{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
+ #ifdef GSSAPI
+ 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
++	{ "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_ALL },
+ 	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
+ 	{ "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
++	{ "gssapicredentialspath", sGssCredsPath, SSHCFG_GLOBAL },
++#ifdef GSI
++	{ "gsiallowlimitedproxy", sGsiAllowLimitedProxy, SSHCFG_GLOBAL },
++#else
++	{ "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL },
++#endif
+ 	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
+ 	{ "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
+ 	{ "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
+ 	{ "gssapienablek5users", sGssEnablek5users, SSHCFG_ALL },
+ #else
+ 	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
++	{ "gssapidelegatecredentials", sUnsupported, SSHCFG_ALL },
+ 	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
+ 	{ "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
++	{ "gssapicredentialspath", sUnsupported, SSHCFG_GLOBAL },
++	{ "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL },
+ 	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
+ 	{ "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
+ 	{ "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
+@@ -554,6 +581,8 @@
+ 	{ "permitopen", sPermitOpen, SSHCFG_ALL },
+ 	{ "forcecommand", sForceCommand, SSHCFG_ALL },
+ 	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
++	{ "disableusagestats", sDisUsageStats, SSHCFG_GLOBAL},
++	{ "usagestatstargets", sUsageStatsTarg, SSHCFG_GLOBAL},
+ 	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
+ 	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
+ 	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
+@@ -967,6 +996,10 @@
+ 		intptr = &options->use_pam;
+ 		goto parse_flag;
+ 
++	case sPermitPAMUserChange:
++		intptr = &options->permit_pam_user_change;
++		goto parse_flag;
++
+ 	/* Standard Options */
+ 	case sBadOption:
+ 		return -1;
+@@ -1200,6 +1233,10 @@
+ 		intptr = &options->gss_authentication;
+ 		goto parse_flag;
+ 
++	case sGssDelegateCreds:
++		intptr = &options->gss_deleg_creds;
++		goto parse_flag;
++
+ 	case sGssKeyEx:
+ 		intptr = &options->gss_keyex;
+ 		goto parse_flag;
+@@ -1208,6 +1245,10 @@
+ 		intptr = &options->gss_cleanup_creds;
+ 		goto parse_flag;
+ 
++	case sGssCredsPath:
++		charptr = &options->gss_creds_path;
++		goto parse_filename;
++
+ 	case sGssStrictAcceptor:
+ 		intptr = &options->gss_strict_acceptor;
+ 		goto parse_flag;
+@@ -1216,6 +1257,12 @@
+ 		intptr = &options->gss_store_rekey;
+ 		goto parse_flag;
+ 
++#ifdef GSI
++	case sGsiAllowLimitedProxy:
++		intptr = &options->gsi_allow_limited_proxy;
++		goto parse_flag;
++#endif
++
+ 	case sPasswordAuthentication:
+ 		intptr = &options->password_authentication;
+ 		goto parse_flag;
+@@ -1690,6 +1737,35 @@
+ 			*charptr = xstrdup(arg);
+ 		break;
+ 
++	case sDisUsageStats:
++		arg = strdelim(&cp);
++		if (!arg || *arg == '\0')
++			fatal("%s line %d: missing value.",
++			    filename, linenum);
++		if (!strcasecmp(arg, "true") ||
++		    !strcasecmp(arg, "enabled") ||
++		    !strcasecmp(arg, "yes") ||
++		    !strcasecmp(arg, "on") ||
++		    !strcasecmp(arg, "1"))
++			options->disable_usage_stats = 1;
++		else if (!strcasecmp(arg, "false") ||
++			 !strcasecmp(arg, "disabled") ||
++			 !strcasecmp(arg, "no") ||
++			 !strcasecmp(arg, "off") ||
++			 !strcasecmp(arg, "0"))
++			options->disable_usage_stats = 0;
++		else
++			fatal("Incorrect value for disable_usage_stats");
++		break;
++
++	case sUsageStatsTarg:
++		arg = strdelim(&cp);
++		if (!arg || *arg == '\0')
++			fatal("%s line %d: missing value.",
++			    filename, linenum);
++		options->usage_stats_targets = xstrdup(arg);
++		break;
++
+ 	case sTrustedUserCAKeys:
+ 		charptr = &options->trusted_user_ca_keys;
+ 		goto parse_filename;
+@@ -1933,6 +2009,7 @@
+ 
+ 	M_CP_INTOPT(password_authentication);
+ 	M_CP_INTOPT(gss_authentication);
++	M_CP_INTOPT(gss_deleg_creds);
+ 	M_CP_INTOPT(rsa_authentication);
+ 	M_CP_INTOPT(pubkey_authentication);
+ 	M_CP_INTOPT(kerberos_authentication);
+diff -Nur openssh-6.8p1.orig/servconf.h openssh-6.8p1/servconf.h
+--- openssh-6.8p1.orig/servconf.h	2015-04-13 20:23:30.723419811 +0200
++++ openssh-6.8p1/servconf.h	2015-04-13 20:24:30.228740228 +0200
+@@ -114,9 +114,12 @@
+ 						 * file on logout. */
+ 	int     kerberos_get_afs_token;		/* If true, try to get AFS token if
+ 						 * authenticated with Kerberos. */
++	int     gsi_allow_limited_proxy;	/* If true, accept limited proxies */
+ 	int     gss_authentication;	/* If true, permit GSSAPI authentication */
++	int     gss_deleg_creds;	/* If true, store delegated GSSAPI credentials*/
+ 	int     gss_keyex;		/* If true, permit GSSAPI key exchange */
+ 	int     gss_cleanup_creds;	/* If true, destroy cred cache on logout */
++	char   *gss_creds_path;		/* Use non-default credentials path */
+ 	int 	gss_strict_acceptor;	/* If true, restrict the GSSAPI acceptor name */
+ 	int 	gss_store_rekey;
+ 	int     password_authentication;	/* If true, permit password
+@@ -172,6 +175,7 @@
+ 	char   *adm_forced_command;
+ 
+ 	int	use_pam;		/* Enable auth via PAM */
++	int	permit_pam_user_change;	/* Allow PAM to change user name */
+ 
+ 	int	permit_tun;
+ 
+@@ -180,6 +184,10 @@
+ 	int		use_kuserok;
+ 	int		enable_k5users;
+ 	char   *chroot_directory;
++
++	int	disable_usage_stats;
++	char   *usage_stats_targets;
++
+ 	char   *revoked_keys_file;
+ 	char   *trusted_user_ca_keys;
+ 	char   *authorized_principals_file;
+diff -Nur openssh-6.8p1.orig/ssh.1 openssh-6.8p1/ssh.1
+--- openssh-6.8p1.orig/ssh.1	2015-04-13 20:23:30.642420736 +0200
++++ openssh-6.8p1/ssh.1	2015-04-13 20:24:30.229740217 +0200
+@@ -1298,6 +1298,18 @@
+ on to new connections).
+ .It Ev USER
+ Set to the name of the user logging in.
++.It Ev X509_CERT_DIR
++Used for GSI authentication. Specifies a non-standard location for the
++CA certificates directory.
++.It Ev X509_USER_CERT
++Used for GSI authentication. Specifies a non-standard location for the
++certificate to be used for authentication to the server.
++.It Ev X509_USER_KEY
++Used for GSI authentication. Specifies a non-standard location for the
++private key to be used for authentication to the server.
++.It Ev X509_USER_PROXY
++Used for GSI authentication. Specifies a non-standard location for the
++proxy credential to be used for authentication to the server.
+ .El
+ .Pp
+ Additionally,
+diff -Nur openssh-6.8p1.orig/ssh.c openssh-6.8p1/ssh.c
+--- openssh-6.8p1.orig/ssh.c	2015-04-13 20:23:30.763419355 +0200
++++ openssh-6.8p1/ssh.c	2015-04-13 22:10:01.137426177 +0200
+@@ -466,6 +466,32 @@
+ 			fatal("Can't open user config file %.100s: "
+ 			    "%.100s", config, strerror(errno));
+ 	} else {
++	    /*
++	     * Since the config file parsing code aborts if it sees
++	     * options it doesn't recognize, allow users to put
++	     * options specific to compile-time add-ons in alternate
++	     * config files so their primary config file will
++	     * interoperate SSH versions that don't support those
++	     * options.
++	     */
++#ifdef GSSAPI
++		r = snprintf(buf, sizeof buf, "%s/%s.gssapi", pw->pw_dir,
++		    _PATH_SSH_USER_CONFFILE);
++		if (r > 0 && (size_t)r < sizeof(buf))
++			(void)read_config_file(buf, pw, host, host_arg, &options, 1);
++#ifdef GSI
++		r = snprintf(buf, sizeof buf, "%s/%s.gsi", pw->pw_dir,
++		    _PATH_SSH_USER_CONFFILE);
++		if (r > 0 && (size_t)r < sizeof(buf))
++			(void)read_config_file(buf, pw, host, host_arg, &options, 1);
++#endif
++#if defined(KRB5)
++		r = snprintf(buf, sizeof buf, "%s/%s.krb", pw->pw_dir,
++		    _PATH_SSH_USER_CONFFILE);
++		if (r > 0 && (size_t)r < sizeof(buf))
++			(void)read_config_file(buf, pw, host, host_arg, &options, 1);
++#endif
++#endif
+ 		r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
+ 		    _PATH_SSH_USER_CONFFILE);
+ 		if (r > 0 && (size_t)r < sizeof(buf))
+@@ -1131,8 +1157,12 @@
+ 		logit("FIPS mode initialized");
+ 	}
+ 
+-	if (options.user == NULL)
++	if (options.user == NULL) {
+ 		options.user = xstrdup(pw->pw_name);
++		options.implicit = 1;
++	} else {
++		options.implicit = 0;
++	}
+ 
+ 	if (gethostname(thishost, sizeof(thishost)) == -1)
+ 		fatal("gethostname: %s", strerror(errno));
+diff -Nur openssh-6.8p1.orig/ssh_config openssh-6.8p1/ssh_config
+--- openssh-6.8p1.orig/ssh_config	2015-04-13 20:23:30.672420394 +0200
++++ openssh-6.8p1/ssh_config	2015-04-13 20:24:30.230740205 +0200
+@@ -24,10 +24,10 @@
+ #   RSAAuthentication yes
+ #   PasswordAuthentication yes
+ #   HostbasedAuthentication no
+-#   GSSAPIAuthentication no
+-#   GSSAPIDelegateCredentials no
+-#   GSSAPIKeyExchange no
+-#   GSSAPITrustDNS no
++#   GSSAPIAuthentication yes
++#   GSSAPIDelegateCredentials yes
++#   GSSAPIKeyExchange yes
++#   GSSAPITrustDNS yes
+ #   BatchMode no
+ #   CheckHostIP yes
+ #   AddressFamily any
+diff -Nur openssh-6.8p1.orig/ssh_config.5 openssh-6.8p1/ssh_config.5
+--- openssh-6.8p1.orig/ssh_config.5	2015-04-13 20:23:30.672420394 +0200
++++ openssh-6.8p1/ssh_config.5	2015-04-13 20:24:30.231740194 +0200
+@@ -55,6 +55,12 @@
+ user's configuration file
+ .Pq Pa ~/.ssh/config
+ .It
++GSSAPI configuration file
++.Pq Pa $HOME/.ssh/config.gssapi
++.It
++Kerberos configuration file
++.Pq Pa $HOME/.ssh/config.krb
++.It
+ system-wide configuration file
+ .Pq Pa /etc/ssh/ssh_config
+ .El
+diff -Nur openssh-6.8p1.orig/sshconnect2.c openssh-6.8p1/sshconnect2.c
+--- openssh-6.8p1.orig/sshconnect2.c	2015-04-13 20:23:30.763419355 +0200
++++ openssh-6.8p1/sshconnect2.c	2015-04-13 20:24:30.231740194 +0200
+@@ -747,6 +747,11 @@
+ 	int ok = 0;
+ 	const char *gss_host = NULL;
+ 
++	if (!options.gss_authentication) {
++		verbose("GSSAPI authentication disabled.");
++		return 0;
++	}
++
+ 	if (options.gss_server_identity)
+ 		gss_host = options.gss_server_identity;
+ 	else if (options.gss_trust_dns) {
+@@ -984,6 +989,15 @@
+ 	return 0;
+ }
+ 
++#ifdef GSI
++extern
++const gss_OID_desc * const gss_mech_globus_gssapi_openssl;
++#define is_gsi_oid(oid) \
++  (oid->length == gss_mech_globus_gssapi_openssl->length && \
++   (memcmp(oid->elements, gss_mech_globus_gssapi_openssl->elements, \
++	   oid->length) == 0))
++#endif
++
+ int
+ userauth_gsskeyex(Authctxt *authctxt)
+ {
+@@ -1001,8 +1015,16 @@
+ 		return (0);
+ 	}
+ 
++#ifdef GSI
++	if (options.implicit && is_gsi_oid(gss_kex_context->oid)) {
++		ssh_gssapi_buildmic(&b, "", authctxt->service, "gssapi-keyex");
++	} else {
++#endif
+ 	ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
+ 	    "gssapi-keyex");
++#ifdef GSI
++	}
++#endif
+ 
+ 	gssbuf.value = buffer_ptr(&b);
+ 	gssbuf.length = buffer_len(&b);
+@@ -1013,7 +1035,15 @@
+ 	}
+ 
+ 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
++#ifdef GSI
++	if (options.implicit && is_gsi_oid(gss_kex_context->oid)) {
++		packet_put_cstring("");
++	} else {
++#endif
+ 	packet_put_cstring(authctxt->server_user);
++#ifdef GSI
++	}
++#endif
+ 	packet_put_cstring(authctxt->service);
+ 	packet_put_cstring(authctxt->method->name);
+ 	packet_put_string(mic.value, mic.length);
+diff -Nur openssh-6.8p1.orig/sshd.8 openssh-6.8p1/sshd.8
+--- openssh-6.8p1.orig/sshd.8	2015-04-13 20:23:30.727419766 +0200
++++ openssh-6.8p1/sshd.8	2015-04-13 20:24:30.232740183 +0200
+@@ -766,6 +766,44 @@
+ # A CA key, accepted for any host in *.mydomain.com or *.mydomain.org
+ @cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W...
+ .Ed
++.Sh ENVIRONMENT
++.Nm
++will normally set the following environment variables:
++.Bl -tag -width "SSH_ORIGINAL_COMMAND"
++.It Ev GLOBUS_USAGE_OPTOUT
++Setting this environment variable to "1" will disable the reporting
++of usage metrics. Usage metrics can also be disabled using the
++.Cm DisableUsageStats
++setting in
++.Xr sshd_config 5 .
++.It Ev GLOBUS_USAGE_TARGETS
++If
++.Cm UsageStatsTargets
++is not specified in
++.Xr sshd_config 5 ,
++a comma-separated list of targets (without any tags specified) if
++specified in the environment variable
++.Ev GLOBUS_USAGE_TARGETS
++will be used.
++.It Ev GRIDMAP
++Applies to GSI authentication/authorization. Specifies the location of the
++gridmapfile. If not specified, the gridmap file is assumed to be available at
++/etc/grid-security/grid-mapfile for services running as root and at
++HOME/.gridmap for services running as non-root where HOME is the home directory
++of the effective user from the password file entry.
++.It Ev X509_CERT_DIR
++Used for GSI authentication. Specifies a non-standard location for the
++CA certificates directory.
++.It Ev X509_USER_CERT
++Used for GSI authentication. Specifies a non-standard location for the
++certificate to be used for authentication to the client.
++.It Ev X509_USER_KEY
++Used for GSI authentication. Specifies a non-standard location for the
++private key to be used for authentication to the client.
++.It Ev X509_USER_PROXY
++Used for GSI authentication. Specifies a non-standard location for the
++proxy credential to be used for authentication to the client.
++.El
+ .Sh FILES
+ .Bl -tag -width Ds -compact
+ .It Pa ~/.hushlogin
+diff -Nur openssh-6.8p1.orig/sshd.c openssh-6.8p1/sshd.c
+--- openssh-6.8p1.orig/sshd.c	2015-04-13 20:23:30.776419206 +0200
++++ openssh-6.8p1/sshd.c	2015-04-13 20:32:10.658481671 +0200
+@@ -128,6 +128,7 @@
+ #include "ssh-sandbox.h"
+ #include "version.h"
+ #include "ssherr.h"
++#include "ssh-globus-usage.h"
+ 
+ #ifdef LIBWRAP
+ #include <tcpd.h>
+@@ -1788,6 +1789,13 @@
+ 	/* Fill in default values for those options not explicitly set. */
+ 	fill_default_server_options(&options);
+ 
++#ifdef HAVE_GLOBUS_USAGE
++	if (ssh_usage_stats_init(options.disable_usage_stats,
++			options.usage_stats_targets) != GLOBUS_SUCCESS) {
++		error("Error initializing Globus Usage Metrics, but continuing ...");
++	}
++#endif /* HAVE_GLOBUS_USAGE */
++
+ 	/* challenge-response is implemented via keyboard interactive */
+ 	if (options.challenge_response_authentication)
+ 		options.kbd_interactive_authentication = 1;
+@@ -2348,7 +2356,7 @@
+ #endif
+ 
+ #ifdef GSSAPI
+-	if (options.gss_authentication) {
++	if (options.gss_authentication && options.gss_deleg_creds) {
+ 		temporarily_use_uid(authctxt->pw);
+ 		ssh_gssapi_storecreds();
+ 		restore_uid();
+diff -Nur openssh-6.8p1.orig/sshd_config openssh-6.8p1/sshd_config
+--- openssh-6.8p1.orig/sshd_config	2015-04-13 20:23:30.723419811 +0200
++++ openssh-6.8p1/sshd_config	2015-04-14 08:42:12.640139901 +0200
+@@ -90,10 +90,11 @@
+ #KerberosUseKuserok yes
+ 
+ # GSSAPI options
+-GSSAPIAuthentication yes
++#GSSAPIAuthentication yes
++#GSSAPIDelegateCredentials yes
+ GSSAPICleanupCredentials no
+ #GSSAPIStrictAcceptorCheck yes
+-#GSSAPIKeyExchange no
++#GSSAPIKeyExchange yes
+ #GSSAPIEnablek5users no
+ 
+ # Set this to 'yes' to enable PAM authentication, account processing,
+@@ -109,6 +110,10 @@
+ # problems.
+ UsePAM yes
+ 
++# Set to 'yes' to allow the PAM stack to change the user name during
++# calls to authentication
++#PermitPAMUserChange no
++
+ #AllowAgentForwarding yes
+ #AllowTcpForwarding yes
+ #GatewayPorts no
+@@ -151,3 +156,6 @@
+ #	AllowTcpForwarding no
+ #	PermitTTY no
+ #	ForceCommand cvs server
++
++# Usage Metrics
++#UsageStatsTargets usage-stats.example.edu:4810
+diff -Nur openssh-6.8p1.orig/sshd_config.5 openssh-6.8p1/sshd_config.5
+--- openssh-6.8p1.orig/sshd_config.5	2015-04-13 20:23:30.723419811 +0200
++++ openssh-6.8p1/sshd_config.5	2015-04-14 07:58:57.173124634 +0200
+@@ -512,6 +512,15 @@
+ See PATTERNS in
+ .Xr ssh_config 5
+ for more information on patterns.
++.It Cm DisableUsageStats
++This keyword can be followed by one of the keywords "true", "enabled", "yes",
++"on" or "1" to disable reporting of usage metrics. Or it can be set to "false",
++"disabled", "no", "off", "0" to enable reporting of usage metrics. Setting the
++.Cm GLOBUS_USAGE_OPTOUT
++environment variable to "1" will also disable the reporting of usage metrics.
++Disabling reporting of usage metrics will cause the
++.Cm UsageStatsTargets
++setting to be ignored.
+ .It Cm FingerprintHash
+ Specifies the hash algorithm used when logging key fingerprints.
+ Valid options are:
+@@ -564,6 +573,10 @@
+ The default is
+ .Dq no .
+ Note that this option applies to protocol version 2 only.
++.It Cm GSSAPIDelegateCredentials
++Specifies whether delegated credentials are stored in the user's environment.
++The default is
++.Dq yes .
+ .It Cm GSSAPIKeyExchange
+ Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
+ doesn't rely on ssh keys to verify host identity.
+@@ -582,6 +595,22 @@
+ .Xr ksu 1 .
+ The default is
+ .Dq no .
++.It Cm GSSAPICredentialsPath
++If specified, the delegated GSSAPI credential is stored in the
++given path, overwriting any existing credentials.  
++Paths can be specified with syntax similar to the AuthorizedKeysFile 
++option (i.e., accepting %h and %u tokens).  
++When using this option,
++setting 'GssapiCleanupCredentials no' is recommended,
++so logging out of one session
++doesn't remove the credentials in use by another session of
++the same user.
++Currently only implemented for the GSI mechanism.
++.It Cm GSIAllowLimitedProxy
++Specifies whether to accept limited proxy credentials for
++authentication.
++The default is
++.Dq no .
+ .It Cm GSSAPIStrictAcceptorCheck
+ Determines whether to be strict about the identity of the GSSAPI acceptor 
+ a client authenticates against. If
+@@ -1410,6 +1439,103 @@
+ .Pp
+ To disable TCP keepalive messages, the value should be set to
+ .Dq no .
++.It Cm UsageStatsTargets
++This option can be used to specify the target collector hosts to which usage
++metrics should be reported. This setting will be ignored if
++.Cm DisableUsageStats
++is enabled. Multiple targets can be specified separated by comma(s), but no
++space(s). Each target specification is of the format
++.Pa host:port[!tags].
++Tags control what data elements are reported. The following list specifies
++the tags for the corresponding data elements.
++.Pp
++.Bl -item -offset indent -compact
++.It
++.Cm V
++.Sm off
++- OpenSSH version, reported by default.
++.Sm on
++.It
++.Cm v
++.Sm off
++- SSL version, reported by default.
++.Sm on
++.It
++.Cm M
++.Sm off
++- User authentication method used such as "gssapi-keyex", "gssapi-with-mic", etc. Reported by default.
++.Sm on
++.It
++.Cm m
++.Sm off
++- User authentication mechanism used such as "GSI", "Kerberos", etc. Reported by default.
++.Sm on
++.It
++.Cm I
++.Sm off
++- Client IP address. Not reported by default.
++.Sm on
++.It
++.Cm u
++.Sm off
++- User name. Not reported by default.
++.Sm on
++.It
++.Cm U
++.Sm off
++- User DN. Not reported by default.
++.Sm on
++.Pp
++In addition to the above selected information, the following data are
++reported to ALL the specified/default target collectors. There's no way to
++exclude these from being reported other than by disabling the reporting of
++usage metrics altogether:
++.Pp
++.It
++.Cm Component code
++.Sm off
++- 12 for GSI OpenSSH
++.Sm on
++.It
++.Cm Component Data Format version
++.Sm off
++- 0 currently
++.Sm on
++.It
++.Cm IP Address
++.Sm off
++- IP address of reporting server
++.Sm on
++.It
++.Cm Timestamp
++.It
++.Cm Hostname
++.Sm off
++- Host name of reporting server
++.Sm on
++.Pp
++If no tags are specified in a host spec, or the special string
++.Dq default
++is specified, the tags
++.Dq VvMm
++are assumed. A site could choose to allow a
++different set of data to be reported by specifying a different tag set. The
++last 3 tags
++.Dq I ,
++.Dq u
++and
++.Dq U
++above are more meant for a local collector that a
++site might like to deploy since they could be construed as private information.
++The special string
++.Dq all
++denotes all tags.
++.El
++.Pp
++Usage Metrics reporting is disabled unless
++.Cm UsageStatsTargets
++is specified.
++.Pp
+ .It Cm TrustedUserCAKeys
+ Specifies a file containing public keys of certificate authorities that are
+ trusted to sign user certificates for authentication.
+@@ -1475,6 +1601,12 @@
+ as a non-root user.
+ The default is
+ .Dq no .
++.It Cm PermitPAMUserChange
++If set to
++.Dq yes
++this will enable PAM authentication to change the name of the user being
++authenticated.  The default is
++.Dq no .
+ .It Cm UsePrivilegeSeparation
+ Specifies whether
+ .Xr sshd 8
+diff -Nur openssh-6.8p1.orig/ssh-globus-usage.c openssh-6.8p1/ssh-globus-usage.c
+--- openssh-6.8p1.orig/ssh-globus-usage.c	1970-01-01 01:00:00.000000000 +0100
++++ openssh-6.8p1/ssh-globus-usage.c	2015-04-14 07:26:22.280670505 +0200
+@@ -0,0 +1,396 @@
++/*
++ * Copyright 2009 The Board of Trustees of the University
++ * of Illinois.  See the LICENSE file for detailed license information.
++ *
++ * Portions, specifically log_usage_stats(), ssh_usage_stats_init(),
++ * ssh_usage_stats_close(), ssh_usage_ent_s, ssh_usage_tag_e and
++ * TAG #defines were based on those from Usage Metrics portions of:
++ * gridftp/server/source/globus_i_gfs_log.c
++ *
++ * Copyright 1999-2006 University of Chicago
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include "includes.h"
++
++#ifdef HAVE_GLOBUS_USAGE
++
++#include <stdarg.h>
++#include <unistd.h> 
++
++#include "log.h"
++#include "ssh-globus-usage.h"
++
++static globus_list_t *usage_handle_list = NULL;
++
++#define SSH_GLOBUS_USAGE_ID 12
++#define SSH_GLOBUS_USAGE_VER 0
++
++#define SSH_GLOBUS_DEFAULT_TAGLIST "VvMm"
++#define SSH_GLOBUS_ALL_TAGLIST     "VvMmIuU"
++#define SSH_GLOBUS_TAGCOUNT 25
++
++typedef enum ssh_usage_tag_e
++{
++    SSH_GLOBUS_USAGE_SSH_VER        = 'V',
++    SSH_GLOBUS_USAGE_SSL_VER        = 'v',
++    SSH_GLOBUS_USAGE_METHOD         = 'M',
++    SSH_GLOBUS_USAGE_MECHANISM      = 'm',
++    SSH_GLOBUS_USAGE_CLIENTIP       = 'I',
++    SSH_GLOBUS_USAGE_USERNAME       = 'u',
++    SSH_GLOBUS_USAGE_USERDN         = 'U'
++    /* !! ADD to ALL_TAGLIST above and to globus_usage_stats_send()
++          invocation below when adding here */
++} ssh_usage_tag_t;
++
++typedef struct ssh_usage_ent_s
++{
++    globus_usage_stats_handle_t         handle;
++    char *                              target;
++    char *                              taglist;
++} ssh_usage_ent_t;
++
++
++globus_result_t
++ssh_usage_stats_init(int disable_usage_stats, char *usage_stats_targets)
++{
++    globus_result_t                     result;
++    char *                              target_str = NULL;
++    char *                              ptr = ptr;
++    char *                              target = NULL;
++    char *                              entry = NULL;
++    globus_list_t *                     list = NULL;
++    ssh_usage_ent_t *               usage_ent = NULL;
++
++    if (disable_usage_stats || !usage_stats_targets)
++	return GLOBUS_SUCCESS;
++
++    result = globus_module_activate(GLOBUS_USAGE_MODULE);
++    if (result != GLOBUS_SUCCESS)
++    {
++        error("ERROR: couldn't activate USAGE STATS module");
++        return result;
++    }
++
++    target_str = strdup(usage_stats_targets);
++    if (target_str == NULL)
++    {
++        error("ERROR: strdup failure for target_str");
++        goto error;
++    }
++    debug("Processing usage_stats_target (%s)\n", target_str);
++
++    if(target_str && (strchr(target_str, ',') || strchr(target_str, '!')))
++    {
++        target = target_str;
++
++        do {
++            usage_ent = (ssh_usage_ent_t *) malloc(sizeof(ssh_usage_ent_t));
++            if (usage_ent == NULL)
++            {
++                error("ERROR: couldn't allocate for ssh_usage_ent_t");
++                goto error;
++            }
++
++            if ((ptr = strchr(target, ',')) != NULL)
++                *ptr = '\0';
++
++            entry = strdup(target);
++            if (entry == NULL)
++            {
++                error("ERROR: strdup failure for target");
++                goto error;
++            }
++
++            if (ptr)
++                target = ptr + 1;
++            else
++                target = NULL;
++
++            if((ptr = strchr(entry, '!')) != NULL)
++            {
++                *ptr = '\0';
++                usage_ent->taglist = strdup(ptr + 1);
++                if (usage_ent->taglist == NULL)
++                {
++                    error("ERROR: strdup failure for taglist");
++                    goto error;
++                }
++                if(strlen(usage_ent->taglist) > SSH_GLOBUS_TAGCOUNT)
++                {
++                    usage_ent->taglist[SSH_GLOBUS_TAGCOUNT + 1] = '\0';
++                }
++            }
++            else
++            {
++                usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST);
++                if (usage_ent->taglist == NULL)
++                {
++                    error("ERROR: couldn't allocate for taglist");
++                    goto error;
++                }
++            }
++            
++            if(strcasecmp(usage_ent->taglist, "default") == 0)
++            {
++                free(usage_ent->taglist);
++                usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST);
++                if (usage_ent->taglist == NULL)
++                {
++                    error("ERROR: couldn't allocate for taglist");
++                    goto error;
++                }
++            }                
++            else if(strcasecmp(usage_ent->taglist, "all") == 0)
++            {
++                free(usage_ent->taglist);
++                usage_ent->taglist = strdup(SSH_GLOBUS_ALL_TAGLIST);
++                if (usage_ent->taglist == NULL)
++                {
++                    error("ERROR: couldn't allocate for taglist");
++                    goto error;
++                }
++            }
++            
++            usage_ent->target = entry;
++
++            globus_list_insert(&usage_handle_list, usage_ent);
++        }
++        while(target != NULL);
++
++        free(target_str);
++    }
++    else
++    {
++        usage_ent = (ssh_usage_ent_t *) malloc(sizeof(ssh_usage_ent_t));
++        if (usage_ent == NULL)
++        {
++             error("ERROR: couldn't allocate for usage_ent");
++             goto error;
++        }
++
++        usage_ent->target = target_str;
++        usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST);
++        if (usage_ent->taglist == NULL)
++        {
++             error("ERROR: couldn't allocate for taglist");
++             goto error;
++        }
++
++        globus_list_insert(&usage_handle_list, usage_ent);
++    }
++
++    result = GLOBUS_SUCCESS;
++    for(list = usage_handle_list;
++        !globus_list_empty(list);
++        list = globus_list_rest(list))
++    {
++        usage_ent = (ssh_usage_ent_t *) globus_list_first(list);
++
++        usage_ent->handle = NULL;
++        if (globus_usage_stats_handle_init(
++            &usage_ent->handle,
++            SSH_GLOBUS_USAGE_ID,
++            SSH_GLOBUS_USAGE_VER,
++            usage_ent->target) != GLOBUS_SUCCESS)
++        {
++            error("USAGE-STATS: Error initializing (%s) (%s)",
++                     usage_ent->target?:"NULL",
++                     usage_ent->taglist?:"NULL");
++            result = GLOBUS_FAILURE;
++        } else
++            debug("USAGE-STATS: Initialized (%s) (%s)", usage_ent->target?:"NULL",
++                     usage_ent->taglist?:"NULL");
++
++    }
++
++    return result;
++
++error:
++    if (target_str)
++    {
++        free(target_str); 
++        target_str = NULL;
++    }
++    if (entry)
++    {
++        free(target_str); 
++        target_str = NULL;
++    }
++    return GLOBUS_FAILURE;
++}
++
++void
++ssh_usage_stats_close(int disable_usage_stats)
++{
++    globus_list_t *list;
++
++    if (disable_usage_stats)
++	return;
++
++    list = usage_handle_list;
++    
++    while(!globus_list_empty(list))
++    {
++        ssh_usage_ent_t *usage_ent;
++        
++        usage_ent = (ssh_usage_ent_t *) 
++            globus_list_remove(&list, list);
++    
++        if(usage_ent)
++        {
++            if(usage_ent->handle)
++            {
++                globus_usage_stats_handle_destroy(usage_ent->handle);
++            }
++            if(usage_ent->target)
++            {
++                free(usage_ent->target);
++            }
++            if(usage_ent->taglist)
++            {
++                free(usage_ent->taglist);
++            }
++            free(usage_ent);
++        }
++    }
++    usage_handle_list = NULL;
++}
++
++static void
++log_usage_stats(const char *ssh_release, const char *ssl_release,
++                const char *method, const char *mechanism,
++                const char *clientip,
++                const char *username, const char *userdn)
++{
++    globus_result_t                     result;
++    globus_list_t *                     list;
++    ssh_usage_ent_t *                   usage_ent;
++    char *                              keys[SSH_GLOBUS_TAGCOUNT];
++    char *                              values[SSH_GLOBUS_TAGCOUNT];
++    char *                              ptr;
++    char *                              key;
++    char *                              value;
++    int                                 i = 0;
++    char *                              save_taglist = NULL;
++
++    for(list = usage_handle_list;
++        !globus_list_empty(list);
++        list = globus_list_rest(list))
++    {
++        usage_ent = (ssh_usage_ent_t *) globus_list_first(list);
++
++        if(!usage_ent || usage_ent->handle == NULL)
++            continue;
++        
++        if(save_taglist == NULL || 
++            strcmp(save_taglist, usage_ent->taglist) != 0)
++        {
++            save_taglist = usage_ent->taglist;
++            
++            ptr = usage_ent->taglist;
++            i = 0;
++            while(ptr && *ptr)
++            {
++                switch(*ptr)
++                {
++                  case SSH_GLOBUS_USAGE_SSH_VER:
++                    key = "SSH_VER";
++                    value = (char *) ssh_release;
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_SSL_VER:
++                    key = "SSL_VER";
++                    value = (char *) ssl_release;
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_METHOD:
++                    key = "METHOD";
++                    value = (char *) method;
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_MECHANISM:
++                    key = "MECH";
++                    value = (char *) mechanism?:"";
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_CLIENTIP:
++                    key = "CLIENTIP";
++                    value = (char *) clientip?:"";
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_USERNAME:
++                    key = "USER";
++                    value = (char *) username?:"";
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_USERDN:
++                    key = "USERDN";
++                    value = (char *) userdn?:"";
++                    break;
++    
++                  default:
++                    key = NULL;
++                    value = NULL;
++                    break;
++                }
++                
++                if(key != NULL && value != NULL)
++                {
++                    keys[i] = key;
++                    values[i] = value;
++                    i++;
++                }
++                
++                ptr++;
++            }
++        }
++
++#ifdef HAVE_GLOBUS_USAGE_SEND_ARRAY
++        result = globus_usage_stats_send_array(
++            usage_ent->handle, i, keys, values);
++#else
++        if (i)
++            result = globus_usage_stats_send(
++                usage_ent->handle, i,
++                i>0?keys[0]:NULL, i>0?values[0]:NULL,
++                i>1?keys[1]:NULL, i>1?values[1]:NULL,
++                i>2?keys[2]:NULL, i>2?values[2]:NULL,
++                i>3?keys[3]:NULL, i>3?values[3]:NULL,
++                i>4?keys[4]:NULL, i>4?values[4]:NULL,
++                i>5?keys[5]:NULL, i>5?values[5]:NULL,
++                i>6?keys[6]:NULL, i>6?values[6]:NULL);
++#endif /* HAVE_GLOBUS_USAGE_SEND_ARRAY */
++    }
++    
++    return;
++}
++#endif /* HAVE_GLOBUS_USAGE */
++
++void
++ssh_globus_send_usage_metrics(const char *ssh_release,
++                              const char *ssl_release,
++                              const char *method,
++                              const char *mechanism,
++                              const char *client_ip,
++                              const char *username,
++                              const char *userdn)
++{
++#ifdef HAVE_GLOBUS_USAGE
++
++    log_usage_stats(ssh_release, ssl_release, method, mechanism,
++                    client_ip, username, userdn);
++
++#endif /* HAVE_GLOBUS_USAGE */
++}
+diff -Nur openssh-6.8p1.orig/ssh-globus-usage.h openssh-6.8p1/ssh-globus-usage.h
+--- openssh-6.8p1.orig/ssh-globus-usage.h	1970-01-01 01:00:00.000000000 +0100
++++ openssh-6.8p1/ssh-globus-usage.h	2015-04-14 07:28:43.646038850 +0200
+@@ -0,0 +1,48 @@
++/*
++ * Copyright 2009 The Board of Trustees of the University
++ * of Illinois.  See the LICENSE file for detailed license information.
++ *
++ * Portions, specifically ssh_usage_stats_init(), ssh_usage_stats_close()
++ * were based on those from: gridftp/server/source/globus_i_gfs_log.h
++ * Copyright 1999-2006 University of Chicago
++ * 
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ * 
++ * http://www.apache.org/licenses/LICENSE-2.0
++ * 
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef __SSH_GLOBUS_USAGE_H
++#define __SSH_GLOBUS_USAGE_H
++
++#include "includes.h"
++
++#ifdef HAVE_GLOBUS_USAGE
++
++#include "globus_usage.h"
++
++globus_result_t
++ssh_usage_stats_init(int disable_usage_stats, char *usage_stats_targets);
++
++void
++ssh_usage_stats_close(int disable_usage_stats);
++
++#endif /* HAVE_GLOBUS_USAGE */
++
++void
++ssh_globus_send_usage_metrics(const char *ssh_release,
++                              const char *ssl_release,
++                              const char *method,
++                              const char *mechanism,
++                              const char *client_ip,
++                              const char *username,
++                              const char *userdn);
++
++#endif /* __SSH_GLOBUS_USAGE_H */
+diff -Nur openssh-6.8p1.orig/ssh-gss.h openssh-6.8p1/ssh-gss.h
+--- openssh-6.8p1.orig/ssh-gss.h	2015-04-13 20:23:30.677420337 +0200
++++ openssh-6.8p1/ssh-gss.h	2015-04-13 20:33:05.203858665 +0200
+@@ -91,6 +91,7 @@
+ 	gss_name_t name;
+ 	struct ssh_gssapi_mech_struct *mech;
+ 	ssh_gssapi_ccache store;
++	gss_ctx_id_t context; /* needed for globus_gss_assist_map_and_authorize() */
+ 	int used;
+ 	int updated;
+ } ssh_gssapi_client;
+@@ -111,7 +112,7 @@
+ 	OM_uint32	minor; /* both */
+ 	gss_ctx_id_t	context; /* both */
+ 	gss_name_t	name; /* both */
+-	gss_OID		oid; /* client */
++	gss_OID		oid; /* both */
+ 	gss_cred_id_t	creds; /* server */
+ 	gss_name_t	client; /* server */
+ 	gss_cred_id_t	client_creds; /* both */
+@@ -144,6 +145,9 @@
+ OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
+ int ssh_gssapi_credentials_updated(Gssctxt *);
+ 
++int ssh_gssapi_localname(char **name);
++void ssh_gssapi_rekey_creds();
++
+ /* In the server */
+ typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, 
+     const char *);
+@@ -154,7 +158,7 @@
+ 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, struct passwd *);
++int ssh_gssapi_userok(char *name, struct passwd *, int gssapi_keyex);
+ 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);
+@@ -166,6 +170,7 @@
+ int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
+ 
+ void ssh_gssapi_rekey_creds(void);
++void ssh_gssapi_get_client_info(char **userdn, char **mech);
+ #endif /* GSSAPI */
+ 
+ #endif /* _SSH_GSS_H */
+diff -Nur openssh-6.8p1.orig/version.h openssh-6.8p1/version.h
+--- openssh-6.8p1.orig/version.h	2015-03-17 06:49:20.000000000 +0100
++++ openssh-6.8p1/version.h	2015-04-14 07:47:24.569105583 +0200
+@@ -1,6 +1,21 @@
+ /* $OpenBSD: version.h,v 1.72 2015/03/04 18:53:53 djm Exp $ */
+ 
++#ifdef GSI
++#define GSI_VERSION	" GSI"
++#else
++#define GSI_VERSION	""
++#endif
++
++#ifdef KRB5
++#define KRB5_VERSION	" KRB5"
++#else
++#define KRB5_VERSION	""
++#endif
++
++#define NCSA_VERSION	" GSI_GSSAPI_20150323"
++
+ #define SSH_VERSION	"OpenSSH_6.8"
+ 
+ #define SSH_PORTABLE	"p1"
+-#define SSH_RELEASE	SSH_VERSION SSH_PORTABLE
++#define SSH_RELEASE	SSH_VERSION SSH_PORTABLE \
++				    NCSA_VERSION GSI_VERSION KRB5_VERSION
diff --git a/sources b/sources
index a3faed2..d5b3f7b 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-3e9800e6bca1fbac0eea4d41baa7f239  openssh-6.6p1.tar.gz
+08f72de6751acfbd0892b5f003922701  openssh-6.8p1.tar.gz
-- 
cgit v0.10.2


	http://pkgs.fedoraproject.org/cgit/gsi-openssh.git/commit/?h=f22&id=04aef646ab7de9bcb4738db00e9d26febd5f0875


More information about the scm-commits mailing list