diff --git a/SOURCES/openssh-5.1p1-scp-manpage.patch b/SOURCES/openssh-5.1p1-scp-manpage.patch
deleted file mode 100644
index e314a05..0000000
--- a/SOURCES/openssh-5.1p1-scp-manpage.patch
+++ /dev/null
@@ -1,18 +0,0 @@
-diff -up openssh-5.1p1/scp.1.manpage openssh-5.1p1/scp.1
---- openssh-5.1p1/scp.1.manpage	2008-07-12 09:12:49.000000000 +0200
-+++ openssh-5.1p1/scp.1	2008-07-23 19:18:15.000000000 +0200
-@@ -66,6 +66,14 @@ treating file names containing
- as host specifiers.
- Copies between two remote hosts are also permitted.
- .Pp
-+When copying a source file to a target file which already exists,
-+.Nm 
-+will replace the contents of the target file (keeping the inode).
-+.Pp
-+If the target file does not yet exist, an empty file with the target
-+file name is created, then filled with the source file contents.
-+No attempt is made at "near-atomic" transfer using temporary files.
-+.Pp
- The options are as follows:
- .Bl -tag -width Ds
- .It Fl 1
diff --git a/SOURCES/openssh-5.8p1-getaddrinfo.patch b/SOURCES/openssh-5.8p1-getaddrinfo.patch
deleted file mode 100644
index 76deaef..0000000
--- a/SOURCES/openssh-5.8p1-getaddrinfo.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-diff -up openssh-5.6p1/channels.c.getaddrinfo openssh-5.6p1/channels.c
---- openssh-5.6p1/channels.c.getaddrinfo	2012-02-14 16:12:54.427852524 +0100
-+++ openssh-5.6p1/channels.c	2012-02-14 16:13:22.818928690 +0100
-@@ -3275,6 +3275,9 @@ x11_create_display_inet(int x11_display_
- 		memset(&hints, 0, sizeof(hints));
- 		hints.ai_family = IPv4or6;
- 		hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE;
-+#ifdef AI_ADDRCONFIG
-+		hints.ai_flags |= AI_ADDRCONFIG;
-+#endif
- 		hints.ai_socktype = SOCK_STREAM;
- 		snprintf(strport, sizeof strport, "%d", port);
- 		if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) {
-diff -up openssh-5.6p1/sshconnect.c.getaddrinfo openssh-5.6p1/sshconnect.c
---- openssh-5.6p1/sshconnect.c.getaddrinfo	2012-02-14 16:09:25.057964291 +0100
-+++ openssh-5.6p1/sshconnect.c	2012-02-14 16:09:25.106047007 +0100
-@@ -343,6 +343,7 @@ ssh_connect(const char *host, struct soc
- 	memset(&hints, 0, sizeof(hints));
- 	hints.ai_family = family;
- 	hints.ai_socktype = SOCK_STREAM;
-+	hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
- 	snprintf(strport, sizeof strport, "%u", port);
- 	if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
- 		fatal("%s: Could not resolve hostname %.100s: %s", __progname,
diff --git a/SOURCES/openssh-5.8p1-glob.patch b/SOURCES/openssh-5.8p1-glob.patch
deleted file mode 100644
index 4b1d8a7..0000000
--- a/SOURCES/openssh-5.8p1-glob.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-diff -up openssh-5.8p1/sftp-glob.c.glob openssh-5.8p1/sftp-glob.c
---- openssh-5.8p1/sftp-glob.c.glob	2011-03-07 20:17:34.000000000 +0100
-+++ openssh-5.8p1/sftp-glob.c	2011-03-07 20:18:47.000000000 +0100
-@@ -145,5 +145,5 @@ remote_glob(struct sftp_conn *conn, cons
- 	memset(&cur, 0, sizeof(cur));
- 	cur.conn = conn;
- 
--	return(glob(pattern, flags | GLOB_ALTDIRFUNC, errfunc, pglob));
-+	return(glob(pattern, flags | GLOB_LIMIT | GLOB_ALTDIRFUNC, errfunc, pglob));
- }
-diff --git a/openbsd-compat/glob.c b/openbsd-compat/glob.c
-index 742b4b9..acae399 100644
---- a/openbsd-compat/glob.c
-+++ b/openbsd-compat/glob.c
-@@ -130,8 +130,8 @@ typedef char Char;
- #define	M_CLASS		META(':')
- #define	ismeta(c)	(((c)&M_QUOTE) != 0)
- 
--#define	GLOB_LIMIT_MALLOC	65536
--#define	GLOB_LIMIT_STAT		128
-+#define	GLOB_LIMIT_MALLOC	65536*64
-+#define	GLOB_LIMIT_STAT		128*64
- #define	GLOB_LIMIT_READDIR	16384
- 
- /* Limit of recursion during matching attempts. */
diff --git a/SOURCES/openssh-6.6p1-AuthenticationMethods.patch b/SOURCES/openssh-6.6p1-AuthenticationMethods.patch
new file mode 100644
index 0000000..de7f59d
--- /dev/null
+++ b/SOURCES/openssh-6.6p1-AuthenticationMethods.patch
@@ -0,0 +1,110 @@
+diff -up openssh-6.6p1/servconf.c.auth_meth openssh-6.6p1/servconf.c
+--- openssh-6.6p1/servconf.c.auth_meth	2016-06-24 13:39:30.022263557 +0200
++++ openssh-6.6p1/servconf.c	2016-06-24 13:48:35.879948274 +0200
+@@ -327,6 +327,14 @@ fill_default_server_options(ServerOption
+ 	if (use_privsep == -1)
+ 		use_privsep = PRIVSEP_NOSANDBOX;
+ 
++	/* Similar handling for AuthenticationMethods=any */
++	if (options->num_auth_methods == 1 &&
++	    strcmp(options->auth_methods[0], "any") == 0) {
++		free(options->auth_methods[0]);
++		options->auth_methods[0] = NULL;
++		options->num_auth_methods = 0;
++	}
++
+ #ifndef HAVE_MMAP
+ 	if (use_privsep && options->compression == 1) {
+ 		error("This platform does not support both privilege "
+@@ -1680,22 +1688,42 @@ process_server_config_line(ServerOptions
+ 		break;
+ 
+ 	case sAuthenticationMethods:
+-		if (cp == NULL || *cp == '\0')
+-			fatal("%.200s line %d: Missing argument.", filename, linenum);
+-		if (*activep && options->num_auth_methods == 0) {
++		if (options->num_auth_methods == 0) {
++			value = 0; /* seen "any" pseudo-method */
++			value2 = 0; /* sucessfully parsed any method */
+ 			while ((arg = strdelim(&cp)) && *arg != '\0') {
+ 				if (options->num_auth_methods >=
+ 				    MAX_AUTH_METHODS)
+ 					fatal("%s line %d: "
+ 					    "too many authentication methods.",
+ 					    filename, linenum);
+-				if (auth2_methods_valid(arg, 0) != 0)
++				if (strcmp(arg, "any") == 0) {
++					if (options->num_auth_methods > 0) {
++						fatal("%s line %d: \"any\" "
++						    "must appear alone in "
++						    "AuthenticationMethods",
++						    filename, linenum);
++					}
++					value = 1;
++				} else if (value) {
++					fatal("%s line %d: \"any\" must appear "
++					    "alone in AuthenticationMethods",
++					    filename, linenum);
++				} else if (auth2_methods_valid(arg, 0) != 0) {
+ 					fatal("%s line %d: invalid "
+ 					    "authentication method list.",
+ 					    filename, linenum);
++				}
++				value2 = 1;
++ 				if (!*activep)
++ 					continue;
+ 				options->auth_methods[
+ 				    options->num_auth_methods++] = xstrdup(arg);
+ 			}
++			if (value2 == 0) {
++				fatal("%s line %d: no AuthenticationMethods "
++				    "specified", filename, linenum);
++			}
+ 		}
+ 		return 0;
+ 
+@@ -2195,11 +2221,13 @@ dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
+ {
+ 	u_int i;
+ 
+-	if (count <= 0)
++	if (count <= 0 && code != sAuthenticationMethods)
+ 		return;
+ 	printf("%s", lookup_opcode_name(code));
+ 	for (i = 0; i < count; i++)
+ 		printf(" %s",  vals[i]);
++	if (code == sAuthenticationMethods && count == 0)
++		printf(" any");
+ 	printf("\n");
+ }
+ 
+diff -up openssh-6.6p1/sshd_config.5.auth_meth openssh-6.6p1/sshd_config.5
+--- openssh-6.6p1/sshd_config.5.auth_meth	2016-06-24 13:39:30.007263566 +0200
++++ openssh-6.6p1/sshd_config.5	2016-06-24 13:39:30.021263557 +0200
+@@ -172,9 +172,12 @@ for more information on patterns.
+ Specifies the authentication methods that must be successfully completed
+ for a user to be granted access.
+ This option must be followed by one or more comma-separated lists of
+-authentication method names.
+-Successful authentication requires completion of every method in at least
+-one of these lists.
++authentication method names, or by the single string
++.Dq any
++to indicate the default behaviour of accepting any single authentication
++method.
++if the default is overridden, then successful authentication requires
++completion of every method in at least one of these lists.
+ .Pp
+ For example, an argument of
+ .Dq publickey,password publickey,keyboard-interactive
+@@ -202,7 +205,9 @@ This option is only available for SSH pr
+ error if enabled if protocol 1 is also enabled.
+ Note that each authentication method listed should also be explicitly enabled
+ in the configuration.
+-The default is not to require multiple authentication; successful completion
++The default
++.Dq any
++is not to require multiple authentication; successful completion
+ of a single authentication method is sufficient.
+ .It Cm AuthorizedKeysCommand
+ Specifies a program to be used to look up the user's public keys.
diff --git a/SOURCES/openssh-6.6p1-CVE-2015-8325.patch b/SOURCES/openssh-6.6p1-CVE-2015-8325.patch
new file mode 100644
index 0000000..4224051
--- /dev/null
+++ b/SOURCES/openssh-6.6p1-CVE-2015-8325.patch
@@ -0,0 +1,32 @@
+From 85bdcd7c92fe7ff133bbc4e10a65c91810f88755 Mon Sep 17 00:00:00 2001
+From: Damien Miller <djm@mindrot.org>
+Date: Wed, 13 Apr 2016 10:39:57 +1000
+Subject: ignore PAM environment vars when UseLogin=yes
+
+If PAM is configured to read user-specified environment variables
+and UseLogin=yes in sshd_config, then a hostile local user may
+attack /bin/login via LD_PRELOAD or similar environment variables
+set via PAM.
+
+CVE-2015-8325, found by Shayan Sadigh, via Colin Watson
+---
+ session.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/session.c b/session.c
+index 4859245..4653b09 100644
+--- a/session.c
++++ b/session.c
+@@ -1322,7 +1322,7 @@ do_setup_env(Session *s, const char *shell)
+ 	 * Pull in any environment variables that may have
+ 	 * been set by PAM.
+ 	 */
+-	if (options.use_pam) {
++	if (options.use_pam && !options.use_login) {
+ 		char **p;
+ 
+ 		p = fetch_pam_child_environment();
+-- 
+cgit v0.11.2
+
+
diff --git a/SOURCES/openssh-6.6p1-ControlPersist-stderr.patch b/SOURCES/openssh-6.6p1-ControlPersist-stderr.patch
new file mode 100644
index 0000000..1cffa1b
--- /dev/null
+++ b/SOURCES/openssh-6.6p1-ControlPersist-stderr.patch
@@ -0,0 +1,53 @@
+From d2d6bf864e52af8491a60dd507f85b74361f5da3 Mon Sep 17 00:00:00 2001
+From: "djm@openbsd.org" <djm@openbsd.org>
+Date: Fri, 29 Apr 2016 08:07:53 +0000
+Subject: [PATCH] upstream commit
+
+close ControlPersist background process stderr when not
+ in debug mode or when logging to a file or syslog. bz#1988 ok dtucker
+
+Upstream-ID: 4fb726f0fdcb155ad419913cea10dc4afd409d24
+---
+ log.c | 4 ++--
+ ssh.c | 8 +++++---
+ 2 files changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/log.c b/log.c
+index ad12930..277afda 100644
+--- a/log.c
++++ b/log.c
+@@ -342,7 +342,7 @@ log_change_level(LogLevel new_log_level)
+ int
+ log_is_on_stderr(void)
+ {
+-	return log_on_stderr;
++	return log_on_stderr && log_stderr_fd == STDERR_FILENO;
+ }
+ 
+ /* redirect what would usually get written to stderr to specified file */
+diff --git a/ssh.c b/ssh.c
+index a999d50..a881ba1 100644
+--- a/ssh.c
++++ b/ssh.c
+@@ -1395,7 +1395,7 @@ static void
+ control_persist_detach(void)
+ {
+ 	pid_t pid;
+-	int devnull;
++	int devnull, keep_stderr;
+ 
+ 	debug("%s: backgrounding master process", __func__);
+ 
+@@ -1426,8 +1426,10 @@ control_persist_detach(void)
+ 		error("%s: open(\"/dev/null\"): %s", __func__,
+ 		    strerror(errno));
+ 	} else {
++		keep_stderr = log_is_on_stderr() && debug_flag;
+ 		if (dup2(devnull, STDIN_FILENO) == -1 ||
+-		    dup2(devnull, STDOUT_FILENO) == -1)
++		    dup2(devnull, STDOUT_FILENO) == -1 ||
++		    (!keep_stderr && dup2(devnull, STDERR_FILENO) == -1))
+ 			error("%s: dup2: %s", __func__, strerror(errno));
+ 		if (devnull > STDERR_FILENO)
+ 			close(devnull);
+
diff --git a/SOURCES/openssh-6.6p1-audit-race-condition.patch b/SOURCES/openssh-6.6p1-audit-race-condition.patch
new file mode 100644
index 0000000..5fffe10
--- /dev/null
+++ b/SOURCES/openssh-6.6p1-audit-race-condition.patch
@@ -0,0 +1,122 @@
+diff -up openssh-6.6p1/monitor_wrap.c.audit-race openssh-6.6p1/monitor_wrap.c
+--- openssh-6.6p1/monitor_wrap.c.audit-race	2016-02-23 13:43:59.958203930 +0100
++++ openssh-6.6p1/monitor_wrap.c	2016-02-23 13:43:59.959203930 +0100
+@@ -1456,4 +1456,31 @@ mm_audit_destroy_sensitive_data(const ch
+ 	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, &m);
+ 	buffer_free(&m);
+ }
++
++int mm_forward_audit_messages(int fdin)
++{
++	static char fb[256];
++	size_t fblen;
++	do {
++		fblen = atomicio(read, fdin, fb, sizeof(fb));
++		if (fblen == 0) {
++			// atomicio read returns EPIPE also with EOF
++			if (errno != EPIPE) {
++				error("%s: Failed to read the messages from child", __func__);
++				return -1;
++			}
++			return 0;
++		}
++		fblen = atomicio(vwrite, pmonitor->m_recvfd, fb, fblen);
++		if (fblen == 0 && errno != EPIPE) {
++			error("%s: Failed to pass the messages to the monitor", __func__);
++			return -1;
++		}
++	} while(fblen > 0);
++	return 0;
++}
++void mm_set_monitor_pipe(int fd)
++{
++	pmonitor->m_recvfd = fd;
++}
+ #endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-6.6p1/monitor_wrap.h.audit-race openssh-6.6p1/monitor_wrap.h
+--- openssh-6.6p1/monitor_wrap.h.audit-race	2016-02-23 13:43:59.958203930 +0100
++++ openssh-6.6p1/monitor_wrap.h	2016-02-23 13:43:59.959203930 +0100
+@@ -86,6 +86,8 @@ 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);
++int mm_forward_audit_messages(int);
++void mm_set_monitor_pipe(int);
+ #endif
+ 
+ struct Session;
+diff -up openssh-6.6p1/session.c.audit-race openssh-6.6p1/session.c
+--- openssh-6.6p1/session.c.audit-race	2016-02-23 13:43:59.954203931 +0100
++++ openssh-6.6p1/session.c	2016-02-23 13:45:14.758194058 +0100
+@@ -158,6 +159,10 @@ static Session *sessions = NULL;
+ login_cap_t *lc;
+ #endif
+ 
++#ifdef SSH_AUDIT_EVENTS
++int paudit[2];
++#endif
++
+ static int is_child = 0;
+ 
+ static int have_dev_log = 1;
+@@ -891,6 +896,8 @@ do_exec(Session *s, const char *command)
+ 	}
+ 	if (s->command != NULL && s->ptyfd == -1)
+ 		s->command_handle = PRIVSEP(audit_run_command(s->command));
++	if (pipe(paudit) < 0)
++		fatal("pipe: %s", strerror(errno));
+ #endif
+ 	if (s->ttyfd != -1)
+ 		ret = do_exec_pty(s, command);
+@@ -906,6 +913,20 @@ do_exec(Session *s, const char *command)
+ 	 */
+ 	buffer_clear(&loginmsg);
+ 
++#ifdef SSH_AUDIT_EVENTS
++	close(paudit[1]);
++	if (use_privsep && ret == 0) {
++		/*
++		 * Read the audit messages from forked child and send them
++		 * back to monitor. We don't want to communicate directly,
++		 * because the messages might get mixed up.
++		 * Continue after the pipe gets closed (all messages sent).
++		 */
++		ret = mm_forward_audit_messages(paudit[0]);
++	}
++	close(paudit[0]);
++#endif /* SSH_AUDIT_EVENTS */
++
+ 	return ret;
+ }
+ 
+@@ -1718,12 +1739,27 @@ do_child(Session *s, const char *command
+ 	struct passwd *pw = s->pw;
+ 	int r = 0;
+ 
++#ifdef SSH_AUDIT_EVENTS
++	close(paudit[0]);
++	/* Hack the monitor pipe to avoid race condition with parent */
++	if (use_privsep)
++		mm_set_monitor_pipe(paudit[1]);
++#endif
++
+ 	/* remove hostkey from the child's memory */
+-	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. */
++	destroy_sensitive_data(use_privsep);
++	/*
++	 * We can audit this, because we hacked the pipe to direct the
++	 * messages over postauth child. But this message requires answer
++	 * which we can't do using one-way pipe.
++	 */
+ 	packet_destroy_all(0, 1);
+ 
++#ifdef SSH_AUDIT_EVENTS
++	/* Notify parent that we are done */
++	close(paudit[1]);
++#endif
++
+ 	/* Force a password change */
+ 	if (s->authctxt->force_pwchange) {
+ 		do_setusercontext(pw);
diff --git a/SOURCES/openssh-6.6p1-audit.patch b/SOURCES/openssh-6.6p1-audit.patch
index dd0c06e..66f7438 100644
--- a/SOURCES/openssh-6.6p1-audit.patch
+++ b/SOURCES/openssh-6.6p1-audit.patch
@@ -855,9 +855,9 @@ index 95d678e..48aede4 100644
  	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)
+ 			buffer_len(&b))) == 1) {
  		authenticated = 1;
- 
+ 		authctxt->last_details = pubkey;
 @@ -154,6 +154,18 @@ done:
  	return authenticated;
  }
@@ -887,9 +887,9 @@ index cb0f931..6d1c872 100644
  		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)
+ 		    buffer_len(&b))) == 1) {
+ 			authctxt->last_details = pubkey;
  			authenticated = 1;
- 		buffer_free(&b);
 @@ -231,6 +231,18 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
  	free(extra);
  }
diff --git a/SOURCES/openssh-6.6p1-chroot-capabilities.patch b/SOURCES/openssh-6.6p1-chroot-capabilities.patch
new file mode 100644
index 0000000..4fb3f21
--- /dev/null
+++ b/SOURCES/openssh-6.6p1-chroot-capabilities.patch
@@ -0,0 +1,100 @@
+diff -up openssh-6.6p1/configure.ac.chroot-cap openssh-6.6p1/configure.ac
+--- openssh-6.6p1/configure.ac.chroot-cap	2016-07-28 10:08:11.183483309 +0200
++++ openssh-6.6p1/configure.ac	2016-07-28 10:08:11.273483277 +0200
+@@ -4783,6 +4783,37 @@ if test -n "$conf_lastlog_location"; the
+ 		[Define if you want to specify the path to your lastlog file])
+ fi
+ 
++AC_ARG_WITH(libcap-ng,
++	[  --with-libcap-ng=[auto/yes/no]  Add Libcap-ng support [default=auto]],,
++	with_libcap_ng=auto)
++
++dnl libcap-ng detection
++if test x$with_libcap_ng = xno ; then
++	have_libcap_ng=no;
++else
++	# Start by checking for header file
++	AC_CHECK_HEADER(cap-ng.h, capng_headers=yes, capng_headers=no)
++
++	# See if we have libcap-ng library
++	AC_CHECK_LIB(cap-ng, capng_clear, CAPNG_LDADD=-lcap-ng,)
++
++	# Check results are usable
++	if test x$with_libcap_ng = xyes -a x$CAPNG_LDADD = x ; then
++	AC_MSG_ERROR(libcap-ng support was requested and the library was not found)
++	fi
++	if test x$CAPNG_LDADD != x -a $capng_headers = no ; then
++	AC_MSG_ERROR(libcap-ng libraries found but headers are missing)
++	fi
++fi
++AC_MSG_CHECKING(whether to use libcap-ng)
++if test x$CAPNG_LDADD != x ; then
++	AC_DEFINE(HAVE_LIBCAP_NG,1,[libcap-ng support])
++	SSHDLIBS="$SSHDLIBS -lcap-ng"
++	AC_MSG_RESULT(yes)
++else
++	AC_MSG_RESULT(no)
++fi
++
+ dnl utmp detection
+ AC_MSG_CHECKING([if your system defines UTMP_FILE])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+diff -up openssh-6.6p1/session.c.chroot-cap openssh-6.6p1/session.c
+--- openssh-6.6p1/session.c.chroot-cap	2016-07-28 10:08:11.269483278 +0200
++++ openssh-6.6p1/session.c	2016-07-28 10:09:10.458455211 +0200
+@@ -95,6 +95,10 @@
+ #include "monitor_wrap.h"
+ #include "sftp.h"
+ 
++#ifdef HAVE_LIBCAP_NG
++#include <cap-ng.h>
++#endif
++
+ #if defined(KRB5) && defined(USE_AFS)
+ #include <kafs.h>
+ #endif
+@@ -1569,6 +1573,7 @@ void
+ do_setusercontext(struct passwd *pw)
+ {
+ 	char *chroot_path, *tmp;
++	int dropped_suid = -1;
+ 
+ 	platform_setusercontext(pw);
+ 
+@@ -1602,10 +1607,24 @@ do_setusercontext(struct passwd *pw)
+ 			    pw->pw_uid);
+ 			chroot_path = percent_expand(tmp, "h", pw->pw_dir,
+ 			    "u", pw->pw_name, (char *)NULL);
++#ifdef HAVE_LIBCAP_NG
++			/* drop suid soon, retain SYS_CHROOT capability */
++			capng_clear(CAPNG_SELECT_BOTH);
++			capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_SYS_CHROOT);
++			if ((dropped_suid = capng_change_id(pw->pw_uid, pw->pw_gid, CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING)) != 0)
++				logit("capng_change_id() = %d (failure): Try to drop UID later", dropped_suid);
++#endif
+ #ifdef WITH_SELINUX
+ 			sshd_selinux_copy_context();
+ #endif
+ 			safely_chroot(chroot_path, pw->pw_uid);
++#ifdef HAVE_LIBCAP_NG
++			/* Drop chroot capability. Already used */
++			if (dropped_suid == 0) {
++				capng_clear(CAPNG_SELECT_BOTH);
++				capng_apply(CAPNG_SELECT_BOTH);
++			}
++#endif
+ 			free(tmp);
+ 			free(chroot_path);
+ 			/* Make sure we don't attempt to chroot again */
+@@ -1629,8 +1648,9 @@ do_setusercontext(struct passwd *pw)
+ 		fatal("set_id(%s) Failed", pw->pw_name);
+ 	}
+ # endif /* USE_LIBIAF */
+-		/* Permanently switch to the desired uid. */
+-		permanently_set_uid(pw);
++		/* Permanently switch to the desired uid if not yet done. */
++		if (dropped_suid != 0)
++			permanently_set_uid(pw);
+ #endif
+ 
+ #ifdef WITH_SELINUX
diff --git a/SOURCES/openssh-6.6p1-ctr-cavstest.patch b/SOURCES/openssh-6.6p1-ctr-cavstest.patch
index 1997fa6..3b0d744 100644
--- a/SOURCES/openssh-6.6p1-ctr-cavstest.patch
+++ b/SOURCES/openssh-6.6p1-ctr-cavstest.patch
@@ -21,7 +21,7 @@ index 4ab6717..581b121 100644
  	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
  ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHDOBJS) libssh.a ssh-keycat.o
- 	$(LD) -o $@ ssh-keycat.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHDLIBS) $(SSHLIBS)
+ 	$(LD) -o $@ ssh-keycat.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(KEYCATLIBS) $(SSHLIBS)
  
 +ctr-cavstest$(EXEEXT): $(LIBCOMPAT) libssh.a ctr-cavstest.o
 +	$(LD) -o $@ ctr-cavstest.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS)
diff --git a/SOURCES/openssh-6.6p1-expose-auth-information.patch b/SOURCES/openssh-6.6p1-expose-auth-information.patch
new file mode 100644
index 0000000..ed508fd
--- /dev/null
+++ b/SOURCES/openssh-6.6p1-expose-auth-information.patch
@@ -0,0 +1,512 @@
+diff -up openssh-6.6p1/auth2.c.expose-auth openssh-6.6p1/auth2.c
+--- openssh-6.6p1/auth2.c.expose-auth	2016-06-27 12:19:39.134443822 +0200
++++ openssh-6.6p1/auth2.c	2016-06-27 12:19:39.178443747 +0200
+@@ -309,6 +309,7 @@ userauth_finish(Authctxt *authctxt, int
+     const char *submethod)
+ {
+ 	char *methods;
++	char *prev_auth_details;
+ 	int partial = 0;
+ 
+ 	if (!authctxt->valid && authenticated)
+@@ -339,6 +340,18 @@ userauth_finish(Authctxt *authctxt, int
+ 	if (authctxt->postponed)
+ 		return;
+ 
++	if (authenticated || partial) {
++		prev_auth_details = authctxt->auth_details;
++		xasprintf(&authctxt->auth_details, "%s%s%s%s%s",
++		    prev_auth_details ? prev_auth_details : "",
++		    prev_auth_details ? ", " : "", method,
++		    authctxt->last_details ? ": " : "",
++		    authctxt->last_details ? authctxt->last_details : "");
++		free(authctxt->last_details);
++		authctxt->last_details = NULL;
++		free(prev_auth_details);
++	}
++
+ #ifdef USE_PAM
+ 	if (options.use_pam && authenticated) {
+ 		if (!PRIVSEP(do_pam_account())) {
+diff -up openssh-6.6p1/auth2-gss.c.expose-auth openssh-6.6p1/auth2-gss.c
+--- openssh-6.6p1/auth2-gss.c.expose-auth	2016-06-27 12:19:39.102443877 +0200
++++ openssh-6.6p1/auth2-gss.c	2016-06-27 12:19:39.179443745 +0200
+@@ -272,6 +272,9 @@ input_gssapi_exchange_complete(int type,
+ 	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
+ 	    authctxt->pw));
+ 
++	if (authenticated)
++		authctxt->last_details = ssh_gssapi_get_displayname();
++
+ 	authctxt->postponed = 0;
+ 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+ 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
+@@ -317,6 +320,9 @@ input_gssapi_mic(int type, u_int32_t ple
+ 	else
+ 		logit("GSSAPI MIC check failed");
+ 
++	if (authenticated)
++		authctxt->last_details = ssh_gssapi_get_displayname();
++
+ 	buffer_free(&b);
+ 	if (micuser != authctxt->user)
+ 		free(micuser);
+diff -up openssh-6.6p1/auth2-hostbased.c.expose-auth openssh-6.6p1/auth2-hostbased.c
+--- openssh-6.6p1/auth2-hostbased.c.expose-auth	2016-06-27 12:19:39.051443964 +0200
++++ openssh-6.6p1/auth2-hostbased.c	2016-06-27 12:19:39.179443745 +0200
+@@ -58,7 +58,7 @@ userauth_hostbased(Authctxt *authctxt)
+ {
+ 	Buffer b;
+ 	Key *key = NULL;
+-	char *pkalg, *cuser, *chost, *service;
++	char *pkalg, *cuser, *chost, *service, *pubkey;
+ 	u_char *pkblob, *sig;
+ 	u_int alen, blen, slen;
+ 	int pktype;
+@@ -131,15 +131,21 @@ userauth_hostbased(Authctxt *authctxt)
+ 	buffer_dump(&b);
+ #endif
+ 
+-	pubkey_auth_info(authctxt, key,
+-	    "client user \"%.100s\", client host \"%.100s\"", cuser, chost);
++	pubkey = key_format_oneline(key);
++	auth_info(authctxt,
++	    "%s, client user \"%.100s\", client host \"%.100s\"",
++	    pubkey, cuser, chost);
+ 
+ 	/* 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),
+-			buffer_len(&b))) == 1)
++			buffer_len(&b))) == 1) {
+ 		authenticated = 1;
++		authctxt->last_details = pubkey;
++	} else {
++		free(pubkey);
++	}
+ 
+ 	buffer_free(&b);
+ done:
+diff -up openssh-6.6p1/auth2-pubkey.c.expose-auth openssh-6.6p1/auth2-pubkey.c
+--- openssh-6.6p1/auth2-pubkey.c.expose-auth	2016-06-27 12:19:39.068443935 +0200
++++ openssh-6.6p1/auth2-pubkey.c	2016-06-27 12:19:39.179443745 +0200
+@@ -75,7 +75,7 @@ userauth_pubkey(Authctxt *authctxt)
+ {
+ 	Buffer b;
+ 	Key *key = NULL;
+-	char *pkalg, *userstyle;
++	char *pkalg, *userstyle, *pubkey;
+ 	u_char *pkblob, *sig;
+ 	u_int alen, blen, slen;
+ 	int have_sig, pktype;
+@@ -155,14 +155,19 @@ userauth_pubkey(Authctxt *authctxt)
+ #ifdef DEBUG_PK
+ 		buffer_dump(&b);
+ #endif
+-		pubkey_auth_info(authctxt, key, NULL);
++		pubkey = key_format_oneline(key);
++		auth_info(authctxt, "%s", pubkey);
+ 
+ 		/* test for correct signature */
+ 		authenticated = 0;
+ 		if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
+ 		    PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
+-		    buffer_len(&b))) == 1)
++		    buffer_len(&b))) == 1) {
++			authctxt->last_details = pubkey;
+ 			authenticated = 1;
++		} else {
++			free(pubkey);
++ 		}
+ 		buffer_free(&b);
+ 		free(sig);
+ 	} else {
+@@ -200,7 +205,7 @@ done:
+ void
+ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
+ {
+-	char *fp, *extra;
++	char *extra, *pubkey;
+ 	va_list ap;
+ 	int i;
+ 
+@@ -210,24 +215,13 @@ pubkey_auth_info(Authctxt *authctxt, con
+ 		i = vasprintf(&extra, fmt, ap);
+ 		va_end(ap);
+ 		if (i < 0 || extra == NULL)
+-			fatal("%s: vasprintf failed", __func__);	
++			fatal("%s: vasprintf failed", __func__);
+ 	}
+ 
+-	if (key_is_cert(key)) {
+-		fp = key_fingerprint(key->cert->signature_key,
+-		    SSH_FP_MD5, 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,
+-		    key_type(key->cert->signature_key), fp,
+-		    extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
+-		free(fp);
+-	} else {
+-		fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+-		auth_info(authctxt, "%s %s%s%s", key_type(key), fp,
+-		    extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
+-		free(fp);
+-	}
++	pubkey = key_format_oneline(key);
++	auth_info(authctxt, "%s%s%s", pubkey, extra == NULL ? "" : ", ",
++	    extra == NULL ? "" : extra);
++	free(pubkey);
+ 	free(extra);
+ }
+ 
+diff -up openssh-6.6p1/auth.h.expose-auth openssh-6.6p1/auth.h
+--- openssh-6.6p1/auth.h.expose-auth	2016-06-27 12:19:39.144443805 +0200
++++ openssh-6.6p1/auth.h	2016-06-27 12:19:39.179443745 +0200
+@@ -78,6 +78,9 @@ struct Authctxt {
+ #endif
+ 	Buffer		*loginmsg;
+ 	void		*methoddata;
++
++	char		*last_details;
++	char		*auth_details;
+ };
+ /*
+  * Every authentication method has to handle authentication requests for
+diff -up openssh-6.6p1/auth-pam.c.expose-auth openssh-6.6p1/auth-pam.c
+--- openssh-6.6p1/auth-pam.c.expose-auth	2016-06-27 12:19:39.049443967 +0200
++++ openssh-6.6p1/auth-pam.c	2016-06-27 12:19:39.179443745 +0200
+@@ -688,6 +688,11 @@ sshpam_init_ctx(Authctxt *authctxt)
+ 		return (NULL);
+ 	}
+ 
++	/* Notify PAM about any already successful auth methods */
++	if (options.expose_auth_methods >= EXPOSE_AUTHMETH_PAMONLY &&
++			authctxt->auth_details)
++		do_pam_putenv("SSH_USER_AUTH", authctxt->auth_details);
++
+ 	ctxt = xcalloc(1, sizeof *ctxt);
+ 
+ 	/* Start the authentication thread */
+diff -up openssh-6.6p1/gss-serv.c.expose-auth openssh-6.6p1/gss-serv.c
+--- openssh-6.6p1/gss-serv.c.expose-auth	2016-06-27 12:19:39.160443778 +0200
++++ openssh-6.6p1/gss-serv.c	2016-06-27 12:19:39.180443743 +0200
+@@ -471,6 +471,16 @@ ssh_gssapi_userok(char *user, struct pas
+ 	return (0);
+ }
+ 
++/* Privileged */
++char*
++ssh_gssapi_get_displayname(void)
++{
++	if (gssapi_client.displayname.length != 0 &&
++	    gssapi_client.displayname.value != NULL)
++		return strdup((char *)gssapi_client.displayname.value);
++	return NULL;
++}
++
+ /* These bits are only used for rekeying. The unpriviledged child is running 
+  * as the user, the monitor is root.
+  *
+diff -up openssh-6.6p1/key.c.expose-auth openssh-6.6p1/key.c
+--- openssh-6.6p1/key.c.expose-auth	2016-06-27 12:19:39.105443872 +0200
++++ openssh-6.6p1/key.c	2016-06-27 12:19:39.180443743 +0200
+@@ -57,6 +57,7 @@
+ #include "misc.h"
+ #include "ssh2.h"
+ #include "digest.h"
++#include "xmalloc.h"
+ 
+ static int to_blob(const Key *, u_char **, u_int *, int);
+ static Key *key_from_blob2(const u_char *, u_int, int);
+@@ -628,6 +629,30 @@ key_fingerprint(const Key *k, enum fp_ty
+ 	return retval;
+ }
+ 
++char *
++key_format_oneline(const Key *key)
++{
++	char *fp, *result;
++
++	if (key_is_cert(key)) {
++		fp = key_fingerprint(key->cert->signature_key, SSH_FP_MD5,
++		    SSH_FP_HEX);
++		xasprintf(&result, "%s ID %s (serial %llu) CA %s %s",
++		    key_type(key), key->cert->key_id,
++		    (unsigned long long)key->cert->serial,
++		    key_type(key->cert->signature_key),
++		    fp == NULL ? "(null)" : fp);
++		free(fp);
++	} else {
++		fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
++		xasprintf(&result, "%s %s", key_type(key),
++		    fp == NULL ? "(null)" : fp);
++		free(fp);
++	}
++
++	return result;
++}
++
+ enum fp_type
+ key_fingerprint_selection(void)
+ {
+diff -up openssh-6.6p1/key.h.expose-auth openssh-6.6p1/key.h
+--- openssh-6.6p1/key.h.expose-auth	2016-06-27 12:19:43.322436657 +0200
++++ openssh-6.6p1/key.h	2016-06-27 12:20:25.898363835 +0200
+@@ -108,6 +108,7 @@ u_char		*key_fingerprint_raw(const Key *
+ enum fp_type	 key_fingerprint_selection(void);
+ char		*key_selected_fingerprint(Key *, enum fp_rep);
+ char		*key_fingerprint_prefix(void);
++char		*key_format_oneline(const Key *k);
+ const char	*key_type(const Key *);
+ const char	*key_cert_type(const Key *);
+ int		 key_write(const Key *, FILE *);
+diff -up openssh-6.6p1/monitor.c.expose-auth openssh-6.6p1/monitor.c
+--- openssh-6.6p1/monitor.c.expose-auth	2016-06-27 12:19:39.165443769 +0200
++++ openssh-6.6p1/monitor.c	2016-06-27 12:19:39.180443743 +0200
+@@ -357,6 +357,7 @@ monitor_child_preauth(Authctxt *_authctx
+ {
+ 	struct mon_table *ent;
+ 	int authenticated = 0, partial = 0;
++	char *prev_auth_details;
+ 
+ 	debug3("preauth child monitor started");
+ 
+@@ -394,6 +395,18 @@ monitor_child_preauth(Authctxt *_authctx
+ 		auth_submethod = NULL;
+ 		authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1);
+ 
++		if (authenticated) {
++			prev_auth_details = authctxt->auth_details;
++			xasprintf(&authctxt->auth_details, "%s%s%s%s%s",
++			    prev_auth_details ? prev_auth_details : "",
++			    prev_auth_details ? ", " : "", auth_method,
++			    authctxt->last_details ? ": " : "",
++			    authctxt->last_details ? authctxt->last_details : "");
++			free(authctxt->last_details);
++			authctxt->last_details = NULL;
++			free(prev_auth_details);
++		}
++
+ 		/* Special handling for multiple required authentications */
+ 		if (options.num_auth_methods != 0) {
+ 			if (!compat20)
+@@ -1432,6 +1445,9 @@ mm_answer_keyverify(int sock, Buffer *m)
+ 	debug3("%s: key %p signature %s",
+ 	    __func__, key, (verified == 1) ? "verified" : "unverified");
+ 
++	if (verified == 1)
++		authctxt->last_details = key_format_oneline(key);
++
+ 	key_free(key);
+ 	free(blob);
+ 	free(signature);
+@@ -2224,6 +2240,9 @@ mm_answer_gss_userok(int sock, Buffer *m
+ 
+ 	auth_method = "gssapi-with-mic";
+ 
++	if (authenticated)
++		authctxt->last_details = ssh_gssapi_get_displayname();
++
+ 	/* Monitor loop will terminate if authenticated */
+ 	return (authenticated);
+ }
+diff -up openssh-6.6p1/servconf.c.expose-auth openssh-6.6p1/servconf.c
+--- openssh-6.6p1/servconf.c.expose-auth	2016-06-27 12:19:39.177443748 +0200
++++ openssh-6.6p1/servconf.c	2016-06-27 12:19:39.181443742 +0200
+@@ -161,6 +161,7 @@ initialize_server_options(ServerOptions
+ 	options->version_addendum = NULL;
+ 	options->use_kuserok = -1;
+ 	options->enable_k5users = -1;
++	options->expose_auth_methods = -1;
+ }
+ 
+ void
+@@ -322,6 +323,8 @@ fill_default_server_options(ServerOption
+ 		options->use_kuserok = 1;
+ 	if (options->enable_k5users == -1)
+ 		options->enable_k5users = 0;
++	if (options->expose_auth_methods == -1)
++		options->expose_auth_methods = EXPOSE_AUTHMETH_NEVER;
+ 
+ 	/* Turn privilege separation on by default */
+ 	if (use_privsep == -1)
+@@ -380,6 +383,7 @@ typedef enum {
+ 	sKexAlgorithms, sIPQoS, sVersionAddendum,
+ 	sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
+ 	sAuthenticationMethods, sHostKeyAgent,
++	sExposeAuthenticationMethods,
+ 	sDeprecated, sUnsupported
+ } ServerOpCodes;
+ 
+@@ -523,6 +527,7 @@ static struct {
+ 	{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
+ 	{ "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
+ 	{ "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
++	{ "exposeauthenticationmethods", sExposeAuthenticationMethods, SSHCFG_ALL },
+ 	{ NULL, sBadOption, 0 }
+ };
+ 
+@@ -869,6 +874,12 @@ static const struct multistate multistat
+ 	{ "local",			FORWARD_LOCAL },
+ 	{ NULL, -1 }
+ };
++static const struct multistate multistate_exposeauthmeth[] = {
++	{ "never",			EXPOSE_AUTHMETH_NEVER },
++	{ "pam-only",			EXPOSE_AUTHMETH_PAMONLY },
++	{ "pam-and-env",		EXPOSE_AUTHMETH_PAMENV },
++	{ NULL, -1}
++};
+ 
+ int
+ process_server_config_line(ServerOptions *options, char *line,
+@@ -1727,6 +1738,11 @@ process_server_config_line(ServerOptions
+ 		}
+ 		return 0;
+ 
++	case sExposeAuthenticationMethods:
++		intptr = &options->expose_auth_methods;
++		multistate_ptr = multistate_exposeauthmeth;
++		goto parse_multistate;
++
+ 	case sDeprecated:
+ 		logit("%s line %d: Deprecated option %s",
+ 		    filename, linenum, arg);
+@@ -1883,6 +1899,7 @@ copy_set_server_options(ServerOptions *d
+ 	M_CP_INTOPT(enable_k5users);
+ 	M_CP_INTOPT(rekey_limit);
+ 	M_CP_INTOPT(rekey_interval);
++	M_CP_INTOPT(expose_auth_methods);
+ 
+ 	/* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */
+ #define M_CP_STROPT(n) do {\
+@@ -1971,6 +1988,8 @@ fmt_intarg(ServerOpCodes code, int val)
+ 		return fmt_multistate_int(val, multistate_privsep);
+ 	case sAllowTcpForwarding:
+ 		return fmt_multistate_int(val, multistate_tcpfwd);
++	case sExposeAuthenticationMethods:
++		return fmt_multistate_int(val, multistate_exposeauthmeth);
+ 	case sProtocol:
+ 		switch (val) {
+ 		case SSH_PROTO_1:
+@@ -2182,6 +2201,7 @@ dump_config(ServerOptions *o)
+ 	dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
+ 	dump_cfg_strarray_oneline(sAuthenticationMethods,
+ 	    o->num_auth_methods, o->auth_methods);
++	dump_cfg_fmtint(sExposeAuthenticationMethods, o->expose_auth_methods);
+ 
+ 	/* other arguments */
+ 	for (i = 0; i < o->num_subsystems; i++)
+diff -up openssh-6.6p1/servconf.h.expose-auth openssh-6.6p1/servconf.h
+--- openssh-6.6p1/servconf.h.expose-auth	2016-06-27 12:19:39.162443774 +0200
++++ openssh-6.6p1/servconf.h	2016-06-27 12:19:39.181443742 +0200
+@@ -48,6 +48,11 @@
+ #define FORWARD_LOCAL		(1<<1)
+ #define FORWARD_ALLOW		(FORWARD_REMOTE|FORWARD_LOCAL)
+ 
++/* Expose AuthenticationMethods */
++#define EXPOSE_AUTHMETH_NEVER   0
++#define EXPOSE_AUTHMETH_PAMONLY 1
++#define EXPOSE_AUTHMETH_PAMENV  2
++
+ #define DEFAULT_AUTH_FAIL_MAX	6	/* Default for MaxAuthTries */
+ #define DEFAULT_SESSIONS_MAX	10	/* Default for MaxSessions */
+ 
+@@ -190,6 +195,8 @@ typedef struct {
+ 
+ 	u_int	num_auth_methods;
+ 	char   *auth_methods[MAX_AUTH_METHODS];
++
++	int	expose_auth_methods; /* EXPOSE_AUTHMETH_* above */
+ }       ServerOptions;
+ 
+ /* Information about the incoming connection as used by Match */
+diff -up openssh-6.6p1/session.c.expose-auth openssh-6.6p1/session.c
+--- openssh-6.6p1/session.c.expose-auth	2016-06-27 12:19:39.171443759 +0200
++++ openssh-6.6p1/session.c	2016-06-27 12:19:39.181443742 +0200
+@@ -1196,6 +1196,12 @@ copy_environment(char **source, char ***
+ 		}
+ 		*var_val++ = '\0';
+ 
++		if (options.expose_auth_methods < EXPOSE_AUTHMETH_PAMENV &&
++				strcmp(var_name, "SSH_USER_AUTH") == 0) {
++			free(var_name);
++			continue;
++		}
++
+ 		debug3("Copy environment: %s=%s", var_name, var_val);
+ 		child_set_env(env, envsize, var_name, var_val);
+ 
+@@ -1375,6 +1381,11 @@ do_setup_env(Session *s, const char *she
+ 	}
+ #endif /* USE_PAM */
+ 
++	if (options.expose_auth_methods >= EXPOSE_AUTHMETH_PAMENV &&
++			s->authctxt->auth_details)
++		child_set_env(&env, &envsize, "SSH_USER_AUTH",
++		     s->authctxt->auth_details);
++
+ 	if (auth_sock_name != NULL)
+ 		child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
+ 		    auth_sock_name);
+@@ -2805,6 +2816,9 @@ do_cleanup(Authctxt *authctxt)
+ 	if (authctxt == NULL)
+ 		return;
+ 
++	free(authctxt->auth_details);
++	authctxt->auth_details = NULL;
++
+ #ifdef USE_PAM
+ 	if (options.use_pam) {
+ 		sshpam_cleanup();
+diff -up openssh-6.6p1/ssh.1.expose-auth openssh-6.6p1/ssh.1
+--- openssh-6.6p1/ssh.1.expose-auth	2016-06-27 12:19:39.163443772 +0200
++++ openssh-6.6p1/ssh.1	2016-06-27 12:19:39.181443742 +0200
+@@ -1289,6 +1289,10 @@ server IP address, and server port numbe
+ This variable contains the original command line if a forced command
+ is executed.
+ It can be used to extract the original arguments.
++.It Ev SSH_USER_AUTH
++This variable contains, for SSH2 only, a comma-separated list of authentication
++methods that were successfuly used to authenticate. When possible, these
++methods are extended with detailed information on the credential used.
+ .It Ev SSH_TTY
+ This is set to the name of the tty (path to the device) associated
+ with the current shell or command.
+diff -up openssh-6.6p1/sshd_config.5.expose-auth openssh-6.6p1/sshd_config.5
+--- openssh-6.6p1/sshd_config.5.expose-auth	2016-06-27 12:19:39.177443748 +0200
++++ openssh-6.6p1/sshd_config.5	2016-06-27 12:19:39.182443740 +0200
+@@ -466,6 +466,21 @@ is allowed to log in.
+ See PATTERNS in
+ .Xr ssh_config 5
+ for more information on patterns.
++.It Cm ExposeAuthenticationMethods
++When using SSH2, this option controls the exposure of the list of
++successful authentication methods to PAM during the authentication
++and to the shell environment via the
++.Cm SSH_USER_AUTH
++variable. See the description of this variable for more details.
++Valid options are:
++.Dq never
++(Do not expose successful authentication methods),
++.Dq pam-only
++(Only expose them to PAM during authentication, not afterwards),
++.Dq pam-and-env
++(Expose them to PAM and keep them in the shell environment).
++The default is
++.Dq never .
+ .It Cm ForceCommand
+ Forces the execution of the command specified by
+ .Cm ForceCommand ,
+diff -up openssh-6.6p1/ssh-gss.h.expose-auth openssh-6.6p1/ssh-gss.h
+--- openssh-6.6p1/ssh-gss.h.expose-auth	2016-06-27 12:19:39.163443772 +0200
++++ openssh-6.6p1/ssh-gss.h	2016-06-27 12:19:39.182443740 +0200
+@@ -160,6 +160,7 @@ int ssh_gssapi_server_check_mech(Gssctxt
+     const char *);
+ OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
+ int ssh_gssapi_userok(char *name, struct passwd *);
++char* ssh_gssapi_get_displayname(void);
+ 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);
diff --git a/SOURCES/openssh-6.6p1-fips.patch b/SOURCES/openssh-6.6p1-fips.patch
index 77760db..a9a3145 100644
--- a/SOURCES/openssh-6.6p1-fips.patch
+++ b/SOURCES/openssh-6.6p1-fips.patch
@@ -55,30 +55,9 @@ diff -up openssh-6.6p1/auth-rsa.c.fips openssh-6.6p1/auth-rsa.c
  		    file, linenum, key_type(key), fp);
  		free(fp);
 diff -up openssh-6.6p1/auth2-pubkey.c.fips openssh-6.6p1/auth2-pubkey.c
---- openssh-6.6p1/auth2-pubkey.c.fips	2015-08-13 15:09:43.345350133 +0200
-+++ openssh-6.6p1/auth2-pubkey.c	2015-08-13 15:09:43.353350119 +0200
-@@ -214,8 +214,7 @@ pubkey_auth_info(Authctxt *authctxt, con
- 	}
- 
- 	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, con
- 		    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 -up openssh-6.6p1/authfile.c.fips openssh-6.6p1/authfile.c
---- openssh-6.6p1/authfile.c.fips	2015-08-13 15:09:43.213350355 +0200
-+++ openssh-6.6p1/authfile.c	2015-08-13 15:09:43.354350118 +0200
+--- openssh-6.6p1/authfile.c.fips	2016-06-27 09:51:39.334362038 +0200
++++ openssh-6.6p1/authfile.c	2016-06-27 09:51:39.443361948 +0200
 @@ -46,6 +46,7 @@
  #include <openssl/err.h>
  #include <openssl/evp.h>
@@ -375,7 +354,25 @@ diff -up openssh-6.6p1/key.c.fips openssh-6.6p1/key.c
  #include <openbsd-compat/openssl-compat.h>
  
  #include <stdarg.h>
-@@ -636,9 +637,13 @@ key_fingerprint_selection(void)
+@@ -635,7 +636,7 @@ sshkey_format_oneline(const struct sshke
+ 	char *fp, *result;
+ 
+ 	if (key_is_cert(key)) {
+-		fp = key_fingerprint(key->cert->signature_key, SSH_FP_MD5,
++		fp = key_selected_fingerprint(key->cert->signature_key,
+ 		    SSH_FP_HEX);
+ 		xasprintf(&result, "%s ID %s (serial %llu) CA %s %s",
+ 		    key_type(key), key->cert->key_id,
+@@ -644,7 +645,7 @@ sshkey_format_oneline(const struct sshke
+ 		    fp == NULL ? "(null)" : fp);
+ 		free(fp);
+ 	} else {
+-		fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
++		fp = key_selected_fingerprint(key, SSH_FP_HEX);
+ 		xasprintf(&result, "%s %s", key_type(key),
+ 		    fp == NULL ? "(null)" : fp);
+ 		free(fp);
+@@ -661,9 +662,13 @@ key_fingerprint_selection(void)
  	char *env;
  
  	if (!rv_defined) {
@@ -811,3 +808,25 @@ diff -up openssh-6.6p1/sshd.c.fips openssh-6.6p1/sshd.c
  
  	if (gss && orig)
  		xasprintf(&newstr, "%s,%s", gss, orig);
+diff --git a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c
+index 13b0a6f..3ec2454 100644
+--- a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c
++++ b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c
+@@ -54,6 +54,7 @@
+ #include "secure_filename.h"
+ #include "uidswap.h"
+ #include <unistd.h>
++#include <openssl/crypto.h>
+ 
+ #include "identity.h"
+ 
+@@ -103,7 +104,8 @@ pamsshagentauth_check_authkeys_file(FILE * f, char *file, Key * key)
+             found_key = 1;
+             logit("matching key found: file/command %s, line %lu", file,
+                                   linenum);
+-            fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
++            fp = key_fingerprint(found, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5,
++			    SSH_FP_HEX);
+             logit("Found matching %s key: %s",
+                                   key_type(found), fp);
+             free(fp);
diff --git a/SOURCES/openssh-6.6p1-gssKexAlgorithms.patch b/SOURCES/openssh-6.6p1-gssKexAlgorithms.patch
index fec7e7f..3854b40 100644
--- a/SOURCES/openssh-6.6p1-gssKexAlgorithms.patch
+++ b/SOURCES/openssh-6.6p1-gssKexAlgorithms.patch
@@ -396,3 +396,15 @@ index 5e8c6c6..4c670aa 100644
  .It Cm HostbasedAuthentication
  Specifies whether rhosts or /etc/hosts.equiv authentication together
  with successful public key client host authentication is allowed
+diff --git a/kex.h b/kex.h
+index db3dde4..17ae43b 100644
+--- a/kex.h
++++ b/kex.h
+@@ -158,6 +158,7 @@ struct Kex {
+ 
+ int	 kex_names_valid(const char *);
+ char	*kex_alg_list(char);
++int	 gss_kex_names_valid(const char *);
+ 
+ Kex	*kex_setup(char *[PROPOSAL_MAX]);
+ void	 kex_finish(Kex *);
diff --git a/SOURCES/openssh-6.6p1-gsskex.patch b/SOURCES/openssh-6.6p1-gsskex.patch
index 826acd4..d1ee1ab 100644
--- a/SOURCES/openssh-6.6p1-gsskex.patch
+++ b/SOURCES/openssh-6.6p1-gsskex.patch
@@ -2811,3 +2811,15 @@ index 95b5f8c..1fb002d 100644
  .It Cm HostbasedAuthentication
  Specifies whether rhosts or /etc/hosts.equiv authentication together
  with successful public key client host authentication is allowed
+diff --git a/ssh-gss.h b/ssh-gss.h
+index 132fd0d..39f6645 100644
+--- a/ssh-gss.h
++++ b/ssh-gss.h
+@@ -169,6 +169,7 @@ char *ssh_gssapi_server_mechanisms(void);
+ int ssh_gssapi_oid_table_ok();
+ 
+ int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
++void ssh_gssapi_rekey_creds();
+ #endif /* GSSAPI */
+ 
+ #endif /* _SSH_GSS_H */
diff --git a/SOURCES/openssh-6.6p1-k5login_directory.patch b/SOURCES/openssh-6.6p1-k5login_directory.patch
new file mode 100644
index 0000000..308c452
--- /dev/null
+++ b/SOURCES/openssh-6.6p1-k5login_directory.patch
@@ -0,0 +1,87 @@
+diff --git a/auth-krb5.c b/auth-krb5.c
+index 2b02a04..19b9364 100644
+--- a/auth-krb5.c
++++ b/auth-krb5.c
+@@ -375,6 +375,22 @@ cleanup:
+ 	return -1;
+ }
+ 
++/*
++ * Reads  k5login_directory  option from the  krb5.conf
++ */
++krb5_error_code
++ssh_krb5_get_k5login_directory(krb5_context ctx, char **k5login_directory) {
++	profile_t p;
++	int ret = 0;
++
++	ret = krb5_get_profile(ctx, &p);
++	if (ret)
++		return ret;
++
++	return profile_get_string(p, "libdefaults", "k5login_directory", NULL, NULL,
++		k5login_directory);
++}
++
+ krb5_error_code
+ ssh_krb5_get_cctemplate(krb5_context ctx, char **ccname) {
+ 	profile_t p;
+diff --git a/auth.h b/auth.h
+index f9d191c..c432d2f 100644
+--- a/auth.h
++++ b/auth.h
+@@ -222,5 +222,7 @@ int	 sys_auth_passwd(Authctxt *, const char *);
+ #if defined(KRB5) && !defined(HEIMDAL)
+ #include <krb5.h>
+ krb5_error_code ssh_krb5_cc_gen(krb5_context, krb5_ccache *);
++krb5_error_code ssh_krb5_get_k5login_directory(krb5_context ctx,
++	char **k5login_directory);
+ #endif
+ #endif
+diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
+index a7c0c5f..df8cc9a 100644
+--- a/gss-serv-krb5.c
++++ b/gss-serv-krb5.c
+@@ -244,8 +244,27 @@ ssh_gssapi_k5login_exists()
+ {
+ 	char file[MAXPATHLEN];
+ 	struct passwd *pw = the_authctxt->pw;
++	char *k5login_directory = NULL;
++	int ret = 0;
++
++	ret = ssh_krb5_get_k5login_directory(krb_context, &k5login_directory);
++	debug3("%s: k5login_directory = %s (rv=%d)", __func__, k5login_directory, ret);
++	if (k5login_directory == NULL || ret != 0) {
++		/* If not set, the library will look for  k5login
++		 * files in the user's home directory, with the filename  .k5login.
++		 */
++		snprintf(file, sizeof(file), "%s/.k5login", pw->pw_dir);
++	} else {
++		/* If set, the library will look for a local user's k5login file
++		 * within the named directory, with a filename corresponding to the
++		 * local username.
++		 */
++		snprintf(file, sizeof(file), "%s%s%s", k5login_directory, 
++			k5login_directory[strlen(k5login_directory)-1] != '/' ? "/" : "",
++			pw->pw_name);
++	}
++	debug("%s: Checking existence of file %s", __func__, file);
+ 
+-	snprintf(file, sizeof(file), "%s/.k5login", pw->pw_dir);
+ 	return access(file, F_OK) == 0;
+ }
+ 
+diff --git a/sshd.8 b/sshd.8
+index 5c4f15b..135e290 100644
+--- a/sshd.8
++++ b/sshd.8
+@@ -806,6 +806,10 @@ rlogin/rsh.
+ These files enforce GSSAPI/Kerberos authentication access control.
+ Further details are described in
+ .Xr ksu 1 .
++The location of the k5login file depends on the configuration option
++.Cm k5login_directory
++in the
++.Xr krb5.conf 5 .
+ .Pp
+ .It Pa ~/.ssh/
+ This directory is the default location for all user-specific configuration
diff --git a/SOURCES/openssh-6.6p1-keycat.patch b/SOURCES/openssh-6.6p1-keycat.patch
index d30dedb..49b9798 100644
--- a/SOURCES/openssh-6.6p1-keycat.patch
+++ b/SOURCES/openssh-6.6p1-keycat.patch
@@ -28,6 +28,14 @@ index 411eadb..4ab6717 100644
  SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
  PRIVSEP_PATH=@PRIVSEP_PATH@
  SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
+@@ -52,6 +52,7 @@ K5LIBS=@K5LIBS@
+ GSSLIBS=@GSSLIBS@
+ SSHLIBS=@SSHLIBS@
+ SSHDLIBS=@SSHDLIBS@
++KEYCATLIBS=@KEYCATLIBS@
+ LIBEDIT=@LIBEDIT@
+ AR=@AR@
+ AWK=@AWK@
 @@ -64,7 +65,7 @@ EXEEXT=@EXEEXT@
  MANFMT=@MANFMT@
  INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@
@@ -42,7 +50,7 @@ index 411eadb..4ab6717 100644
  	$(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.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)
++	$(LD) -o $@ ssh-keycat.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(KEYCATLIBS) $(SSHLIBS)
 +
  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)
@@ -443,3 +451,41 @@ index 0000000..f8ed7af
 +	}
 +	return ev;
 +}
+diff --git a/configure.ac b/configure.ac
+index 3bbccfd..6481f1f 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -2952,6 +2952,7 @@ AC_ARG_WITH([pam],
+ 			PAM_MSG="yes"
+ 
+ 			SSHDLIBS="$SSHDLIBS -lpam"
++			KEYCATLIBS="$KEYCATLIBS -lpam"
+ 			AC_DEFINE([USE_PAM], [1],
+ 				[Define if you want to enable PAM support])
+ 
+@@ -2962,6 +2963,7 @@ AC_ARG_WITH([pam],
+ 					;;
+ 				*)
+ 					SSHDLIBS="$SSHDLIBS -ldl"
++					KEYCATLIBS="$KEYCATLIBS -ldl"
+ 					;;
+ 				esac
+ 			fi
+@@ -4042,6 +4044,7 @@ AC_ARG_WITH([selinux],
+ )
+ AC_SUBST([SSHLIBS])
+ AC_SUBST([SSHDLIBS])
++AC_SUBST([KEYCATLIBS])
+ 
+ # Check whether user wants Kerberos 5 support
+ KRB5_MSG="no"
+@@ -5031,6 +5034,9 @@ fi
+ if test ! -z "${SSHLIBS}"; then
+ echo "          +for ssh: ${SSHLIBS}"
+ fi
++if test ! -z "${KEYCATLIBS}"; then
++echo "   +for ssh-keycat: ${KEYCATLIBS}"
++fi
+ 
+ echo ""
+ 
diff --git a/SOURCES/openssh-6.6p1-permitopen-any-host.patch b/SOURCES/openssh-6.6p1-permitopen-any-host.patch
new file mode 100644
index 0000000..ec519b2
--- /dev/null
+++ b/SOURCES/openssh-6.6p1-permitopen-any-host.patch
@@ -0,0 +1,74 @@
+diff -up openssh-6.6p1/channels.c.permitopen openssh-6.6p1/channels.c
+--- openssh-6.6p1/channels.c.permitopen	2016-06-29 15:37:08.780327108 +0200
++++ openssh-6.6p1/channels.c	2016-06-29 16:04:38.480857525 +0200
+@@ -128,6 +128,9 @@ static int num_adm_permitted_opens = 0;
+ /* special-case port number meaning allow any port */
+ #define FWD_PERMIT_ANY_PORT	0
+ 
++/* special-case wildcard meaning allow any host */
++#define FWD_PERMIT_ANY_HOST	"*"
++
+ /*
+  * If this is true, all opens are permitted.  This is the case on the server
+  * on which we have to trust the client anyway, and the user could do
+@@ -3271,6 +3274,21 @@ port_match(u_short allowedport, u_short
+ 	return 0;
+ }
+ 
++static int
++open_match(ForwardPermission *allowed_open, const char *requestedhost,
++    u_short requestedport)
++{
++	if (allowed_open->host_to_connect == NULL)
++		return 0;
++	if (allowed_open->port_to_connect != FWD_PERMIT_ANY_PORT &&
++	    allowed_open->port_to_connect != requestedport)
++		return 0;
++	if (strcmp(allowed_open->host_to_connect, FWD_PERMIT_ANY_HOST) != 0 &&
++	    strcmp(allowed_open->host_to_connect, requestedhost) != 0)
++		return 0;
++	return 1;
++}
++
+ /* Try to start non-blocking connect to next host in cctx list */
+ static int
+ connect_next(struct channel_connect *cctx)
+@@ -3391,20 +3409,18 @@ channel_connect_to(const char *host, u_s
+ 	permit = all_opens_permitted;
+ 	if (!permit) {
+ 		for (i = 0; i < num_permitted_opens; i++)
+-			if (permitted_opens[i].host_to_connect != NULL &&
+-			    port_match(permitted_opens[i].port_to_connect, port) &&
+-			    strcmp(permitted_opens[i].host_to_connect, host) == 0)
++			if (open_match(&permitted_opens[i], host, port)) {
+ 				permit = 1;
++			}
+ 	}
+ 
+ 	if (num_adm_permitted_opens > 0) {
+ 		permit_adm = 0;
+ 		for (i = 0; i < num_adm_permitted_opens; i++)
+-			if (permitted_adm_opens[i].host_to_connect != NULL &&
+-			    port_match(permitted_adm_opens[i].port_to_connect, port) &&
+-			    strcmp(permitted_adm_opens[i].host_to_connect, host)
+-			    == 0)
++			if (open_match(&permitted_adm_opens[i], host, port)) {
+ 				permit_adm = 1;
++				break;
++			}
+ 	}
+ 
+ 	if (!permit || !permit_adm) {
+diff -up openssh-6.6p1/sshd_config.5.permitopen openssh-6.6p1/sshd_config.5
+--- openssh-6.6p1/sshd_config.5.permitopen	2016-06-29 15:37:08.778327110 +0200
++++ openssh-6.6p1/sshd_config.5	2016-06-29 15:37:08.782327106 +0200
+@@ -1005,6 +1005,9 @@ can be used to remove all restrictions a
+ An argument of
+ .Dq none
+ can be used to prohibit all forwarding requests.
++Wildcard
++.Dq *
++can be used for host or port to allow all hosts or all ports respectively.
+ By default all port forwarding requests are permitted.
+ .It Cm PermitRootLogin
+ Specifies whether root can log in using
diff --git a/SOURCES/openssh-6.6p1-s390-closefrom.patch b/SOURCES/openssh-6.6p1-s390-closefrom.patch
new file mode 100644
index 0000000..301a523
--- /dev/null
+++ b/SOURCES/openssh-6.6p1-s390-closefrom.patch
@@ -0,0 +1,52 @@
+Zseries only: Leave the hardware filedescriptors open.
+
+All filedescriptors above 2 are getting closed when a new
+sshd process to handle a new client connection is
+spawned. As the process also chroot into an empty filesystem
+without any device nodes, there is no chance to reopen the
+files. This patch filters out the reqired fds in the
+closefrom function so these are skipped in the close loop.
+
+Author: Harald Freudenberger <freude@de.ibm.com>
+
+---
+ openbsd-compat/bsd-closefrom.c |   26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+--- a/openbsd-compat/bsd-closefrom.c
++++ b/openbsd-compat/bsd-closefrom.c
+@@ -82,7 +82,33 @@ closefrom(int lowfd)
+ 	    fd = strtol(dent->d_name, &endp, 10);
+ 	    if (dent->d_name != endp && *endp == '\0' &&
+ 		fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
++#ifdef __s390__
++		{
++		    /*
++		     * the filedescriptors used to communicate with
++		     * the device drivers to provide hardware support
++		     * should survive. HF <freude@de.ibm.com>
++		     */
++		    char fpath[PATH_MAX], lpath[PATH_MAX];
++		    len = snprintf(fpath, sizeof(fpath), "%s/%s",
++				   fdpath, dent->d_name);
++		    if (len > 0 && (size_t)len <= sizeof(fpath)) {
++			len = readlink(fpath, lpath, sizeof(lpath));
++			if (len > 0) {
++			    lpath[len] = 0;
++			    if (strstr(lpath, "dev/z90crypt")
++				|| strstr(lpath, "dev/zcrypt")
++				|| strstr(lpath, "dev/prandom")
++				|| strstr(lpath, "dev/shm/icastats"))
++				fd = -1;
++			}
++		    }
++		    if (fd >= 0)
++			(void) close((int) fd);
++		}
++#else
+ 		(void) close((int) fd);
++#endif
+ 	}
+ 	(void) closedir(dirp);
+     } else
+
diff --git a/SOURCES/openssh-6.6p1-sftp-force-permission.patch b/SOURCES/openssh-6.6p1-sftp-force-permission.patch
index 2853bdd..a35b7b7 100644
--- a/SOURCES/openssh-6.6p1-sftp-force-permission.patch
+++ b/SOURCES/openssh-6.6p1-sftp-force-permission.patch
@@ -34,18 +34,35 @@ diff -up openssh-6.6p1/sftp-server.c.sftp-force-mode openssh-6.6p1/sftp-server.c
  /* SSH2_FXP_INIT received */
  static int init_done;
  
-@@ -675,6 +679,10 @@ process_open(u_int32_t id)
+@@ -668,6 +672,7 @@ process_open(u_int32_t id)
+ 	Attrib *a;
+ 	char *name;
+ 	int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
++	mode_t old_umask;
+ 
+ 	name = get_string(NULL);
+ 	pflags = get_int();		/* portable flags */
+@@ -675,6 +680,10 @@ process_open(u_int32_t id)
  	a = get_attrib();
  	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		 */
-+	}	
++		old_umask = umask(0); /* so umask does not interfere */
++	}
  	logit("open \"%s\" flags %s mode 0%o",
  	    name, string_from_portable(pflags), mode);
  	if (readonly &&
-@@ -1430,7 +1438,7 @@ sftp_server_usage(void)
+@@ -696,6 +705,8 @@ process_open(u_int32_t id)
+ 			}
+ 		}
+ 	}
++	if (permforce == 1)
++		(void) umask(old_umask); /* restore umask to something sane */
+ 	if (status != SSH2_FX_OK)
+ 		send_status(id, status);
+ 	free(name);
+@@ -1430,7 +1441,7 @@ sftp_server_usage(void)
  	fprintf(stderr,
  	    "usage: %s [-ehR] [-d start_directory] [-f log_facility] "
  	    "[-l log_level]\n\t[-P blacklisted_requests] "
diff --git a/SOURCES/openssh-6.6p1-ssh-copy-id-quiet.patch b/SOURCES/openssh-6.6p1-ssh-copy-id-quiet.patch
new file mode 100644
index 0000000..4cce020
--- /dev/null
+++ b/SOURCES/openssh-6.6p1-ssh-copy-id-quiet.patch
@@ -0,0 +1,11 @@
+diff -up openssh-6.6p1/contrib/ssh-copy-id.quiet openssh-6.6p1/contrib/ssh-copy-id
+--- openssh-6.6p1/contrib/ssh-copy-id.quiet	2016-06-27 13:42:47.844393842 +0200
++++ openssh-6.6p1/contrib/ssh-copy-id	2016-06-27 13:42:57.861398744 +0200
+@@ -215,6 +215,7 @@ populate_new_ids() {
+         # The point being that if file based, ssh needs the private key, which it cannot
+         # find if only given the contents of the .pub file in an unrelated tmpfile
+         ssh -i "${PRIV_ID_FILE:-$L_TMP_ID_FILE}" \
++            -o LogLevel=INFO \
+             -o PreferredAuthentications=publickey \
+             -o IdentitiesOnly=yes "$@" exit 2>$L_TMP_ID_FILE.stderr </dev/null
+         if [ "$?" = "$L_SUCCESS" ] ; then
diff --git a/SOURCES/openssh-6.6p1-x11-max-displays.patch b/SOURCES/openssh-6.6p1-x11-max-displays.patch
new file mode 100644
index 0000000..f5b339f
--- /dev/null
+++ b/SOURCES/openssh-6.6p1-x11-max-displays.patch
@@ -0,0 +1,214 @@
+diff -up openssh-6.6p1/channels.c.x11max openssh-6.6p1/channels.c
+--- openssh-6.6p1/channels.c.x11max	2016-06-27 16:28:49.803631684 +0200
++++ openssh-6.6p1/channels.c	2016-06-27 16:28:49.814631678 +0200
+@@ -138,8 +138,8 @@ static int all_opens_permitted = 0;
+ 
+ /* -- X11 forwarding */
+ 
+-/* Maximum number of fake X11 displays to try. */
+-#define MAX_DISPLAYS  1000
++/* Minimum port number for X11 forwarding */
++#define X11_PORT_MIN 6000
+ 
+ /* Saved X11 local (client) display. */
+ static char *x11_saved_display = NULL;
+@@ -3445,7 +3445,8 @@ channel_send_window_changes(void)
+  */
+ int
+ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
+-    int single_connection, u_int *display_numberp, int **chanids)
++    int x11_max_displays, int single_connection, u_int *display_numberp,
++    int **chanids)
+ {
+ 	Channel *nc = NULL;
+ 	int display_number, sock;
+@@ -3457,10 +3458,15 @@ x11_create_display_inet(int x11_display_
+ 	if (chanids == NULL)
+ 		return -1;
+ 
++	/* Try to bind ports starting at 6000+X11DisplayOffset */
++	x11_max_displays = x11_max_displays + x11_display_offset;
++
+ 	for (display_number = x11_display_offset;
+-	    display_number < MAX_DISPLAYS;
++	    display_number < x11_max_displays;
+ 	    display_number++) {
+-		port = 6000 + display_number;
++		port = X11_PORT_MIN + display_number;
++		if (port < X11_PORT_MIN) /* overflow */
++			break;
+ 		memset(&hints, 0, sizeof(hints));
+ 		hints.ai_family = IPv4or6;
+ 		hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE;
+@@ -3512,7 +3518,7 @@ x11_create_display_inet(int x11_display_
+ 		if (num_socks > 0)
+ 			break;
+ 	}
+-	if (display_number >= MAX_DISPLAYS) {
++	if (display_number >= x11_max_displays || port < X11_PORT_MIN ) {
+ 		error("Failed to allocate internet-domain X11 display socket.");
+ 		return -1;
+ 	}
+@@ -3658,7 +3664,7 @@ x11_connect_display(void)
+ 	memset(&hints, 0, sizeof(hints));
+ 	hints.ai_family = IPv4or6;
+ 	hints.ai_socktype = SOCK_STREAM;
+-	snprintf(strport, sizeof strport, "%u", 6000 + display_number);
++	snprintf(strport, sizeof strport, "%u", X11_PORT_MIN + display_number);
+ 	if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
+ 		error("%.100s: unknown host. (%s)", buf,
+ 		ssh_gai_strerror(gaierr));
+@@ -3674,7 +3680,7 @@ x11_connect_display(void)
+ 		/* Connect it to the display. */
+ 		if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+ 			debug2("connect %.100s port %u: %.100s", buf,
+-			    6000 + display_number, strerror(errno));
++			    X11_PORT_MIN + display_number, strerror(errno));
+ 			close(sock);
+ 			continue;
+ 		}
+@@ -3683,8 +3689,8 @@ x11_connect_display(void)
+ 	}
+ 	freeaddrinfo(aitop);
+ 	if (!ai) {
+-		error("connect %.100s port %u: %.100s", buf, 6000 + display_number,
+-		    strerror(errno));
++		error("connect %.100s port %u: %.100s", buf,
++		    X11_PORT_MIN + display_number, strerror(errno));
+ 		return -1;
+ 	}
+ 	set_nodelay(sock);
+diff -up openssh-6.6p1/channels.h.x11max openssh-6.6p1/channels.h
+--- openssh-6.6p1/channels.h.x11max	2016-06-27 16:28:49.814631678 +0200
++++ openssh-6.6p1/channels.h	2016-06-27 16:31:18.925557840 +0200
+@@ -281,7 +281,7 @@ int	 permitopen_port(const char *);
+ 
+ void	 channel_set_x11_refuse_time(u_int);
+ int	 x11_connect_display(void);
+-int	 x11_create_display_inet(int, int, int, u_int *, int **);
++int	 x11_create_display_inet(int, int, int, int, u_int *, int **);
+ void     x11_input_open(int, u_int32_t, void *);
+ void	 x11_request_forwarding_with_spoofing(int, const char *, const char *,
+ 	     const char *, int);
+diff -up openssh-6.6p1/servconf.c.x11max openssh-6.6p1/servconf.c
+--- openssh-6.6p1/servconf.c.x11max	2016-06-27 16:28:49.808631681 +0200
++++ openssh-6.6p1/servconf.c	2016-06-27 16:30:46.941573678 +0200
+@@ -92,6 +92,7 @@ initialize_server_options(ServerOptions
+ 	options->print_lastlog = -1;
+ 	options->x11_forwarding = -1;
+ 	options->x11_display_offset = -1;
++	options->x11_max_displays = -1;
+ 	options->x11_use_localhost = -1;
+ 	options->permit_tty = -1;
+ 	options->xauth_location = NULL;
+@@ -219,6 +220,8 @@ fill_default_server_options(ServerOption
+ 		options->x11_forwarding = 0;
+ 	if (options->x11_display_offset == -1)
+ 		options->x11_display_offset = 10;
++	if (options->x11_max_displays == -1)
++		options->x11_max_displays = DEFAULT_MAX_DISPLAYS;
+ 	if (options->x11_use_localhost == -1)
+ 		options->x11_use_localhost = 1;
+ 	if (options->xauth_location == NULL)
+@@ -364,7 +367,7 @@ typedef enum {
+ 	sPasswordAuthentication, sKbdInteractiveAuthentication,
+ 	sListenAddress, sAddressFamily,
+ 	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
+-	sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
++	sX11Forwarding, sX11DisplayOffset, sX11MaxDisplays, sX11UseLocalhost,
+ 	sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive,
+ 	sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
+ 	sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
+@@ -476,6 +479,7 @@ static struct {
+ 	{ "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
+ 	{ "x11forwarding", sX11Forwarding, SSHCFG_ALL },
+ 	{ "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
++	{ "x11maxdisplays", sX11MaxDisplays, SSHCFG_ALL },
+ 	{ "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
+ 	{ "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
+ 	{ "strictmodes", sStrictModes, SSHCFG_GLOBAL },
+@@ -1202,6 +1206,10 @@ process_server_config_line(ServerOptions
+ 		intptr = &options->x11_display_offset;
+ 		goto parse_int;
+ 
++	case sX11MaxDisplays:
++		intptr = &options->x11_max_displays;
++		goto parse_int;
++
+ 	case sX11UseLocalhost:
+ 		intptr = &options->x11_use_localhost;
+ 		goto parse_flag;
+@@ -1889,6 +1897,7 @@ copy_set_server_options(ServerOptions *d
+ 	M_CP_INTOPT(gateway_ports);
+ 	M_CP_INTOPT(x11_display_offset);
+ 	M_CP_INTOPT(x11_forwarding);
++	M_CP_INTOPT(x11_max_displays);
+ 	M_CP_INTOPT(x11_use_localhost);
+ 	M_CP_INTOPT(permit_tty);
+ 	M_CP_INTOPT(max_sessions);
+@@ -2106,6 +2115,7 @@ dump_config(ServerOptions *o)
+ 	dump_cfg_int(sLoginGraceTime, o->login_grace_time);
+ 	dump_cfg_int(sKeyRegenerationTime, o->key_regeneration_time);
+ 	dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
++	dump_cfg_int(sX11MaxDisplays, o->x11_max_displays);
+ 	dump_cfg_int(sMaxAuthTries, o->max_authtries);
+ 	dump_cfg_int(sMaxSessions, o->max_sessions);
+ 	dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
+diff -up openssh-6.6p1/servconf.h.x11max openssh-6.6p1/servconf.h
+--- openssh-6.6p1/servconf.h.x11max	2016-06-27 16:28:49.809631681 +0200
++++ openssh-6.6p1/servconf.h	2016-06-27 16:28:49.815631678 +0200
+@@ -55,6 +55,7 @@
+ 
+ #define DEFAULT_AUTH_FAIL_MAX	6	/* Default for MaxAuthTries */
+ #define DEFAULT_SESSIONS_MAX	10	/* Default for MaxSessions */
++#define DEFAULT_MAX_DISPLAYS	1000 /* Maximum number of fake X11 displays to try. */
+ 
+ /* Magic name for internal sftp-server */
+ #define INTERNAL_SFTP_NAME	"internal-sftp"
+@@ -85,6 +86,7 @@ typedef struct {
+ 	int     x11_forwarding;	/* If true, permit inet (spoofing) X11 fwd. */
+ 	int     x11_display_offset;	/* What DISPLAY number to start
+ 					 * searching at */
++	int 	x11_max_displays; /* Number of displays to search */
+ 	int     x11_use_localhost;	/* If true, use localhost for fake X11 server. */
+ 	char   *xauth_location;	/* Location of xauth program */
+ 	int	permit_tty;	/* If false, deny pty allocation */
+diff -up openssh-6.6p1/session.c.x11max openssh-6.6p1/session.c
+--- openssh-6.6p1/session.c.x11max	2016-06-27 16:28:49.809631681 +0200
++++ openssh-6.6p1/session.c	2016-06-27 16:28:49.815631678 +0200
+@@ -2741,8 +2741,9 @@ session_setup_x11fwd(Session *s)
+ 		return 0;
+ 	}
+ 	if (x11_create_display_inet(options.x11_display_offset,
+-	    options.x11_use_localhost, s->single_connection,
+-	    &s->display_number, &s->x11_chanids) == -1) {
++	    options.x11_use_localhost, options.x11_max_displays,
++	    s->single_connection, &s->display_number,
++	    &s->x11_chanids) == -1) {
+ 		debug("x11_create_display_inet failed.");
+ 		return 0;
+ 	}
+diff -up openssh-6.6p1/sshd_config.5.x11max openssh-6.6p1/sshd_config.5
+--- openssh-6.6p1/sshd_config.5.x11max	2016-06-27 16:28:49.809631681 +0200
++++ openssh-6.6p1/sshd_config.5	2016-06-27 16:32:01.253536879 +0200
+@@ -930,6 +930,7 @@ Available keywords are
+ .Cm RhostsRSAAuthentication ,
+ .Cm RSAAuthentication ,
+ .Cm X11DisplayOffset ,
++.Cm X11MaxDisplays ,
+ .Cm X11Forwarding
+ and
+ .Cm X11UseLocalHost .
+@@ -1339,6 +1340,12 @@ Specifies the first display number avail
+ X11 forwarding.
+ This prevents sshd from interfering with real X11 servers.
+ The default is 10.
++.It Cm X11MaxDisplays
++Specifies the maximum number of displays available for
++.Xr sshd 8 Ns 's
++X11 forwarding.
++This prevents sshd from exhausting local ports.
++The default is 1000.
+ .It Cm X11Forwarding
+ Specifies whether X11 forwarding is permitted.
+ The argument must be
diff --git a/SOURCES/pam_ssh_agent_auth-0.9.3-command.patch b/SOURCES/pam_ssh_agent_auth-0.9.3-command.patch
new file mode 100644
index 0000000..88e8d7d
--- /dev/null
+++ b/SOURCES/pam_ssh_agent_auth-0.9.3-command.patch
@@ -0,0 +1,1451 @@
+From b0695cc9f5478daa14d3f451ecdd39ba6e6abe0f Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Tue, 19 Jan 2016 15:29:22 +0100
+Subject: [PATCH] authorized_keys_command
+
+---
+ pam_ssh_agent_auth-0.9.3/CONTRIBUTORS              |   2 +
+ pam_ssh_agent_auth-0.9.3/Makefile.in               |  28 +-
+ pam_ssh_agent_auth-0.9.3/README                    |  38 +++
+ pam_ssh_agent_auth-0.9.3/configure.ac              |  27 +-
+ pam_ssh_agent_auth-0.9.3/get_command_line.c        | 113 +++++++
+ pam_ssh_agent_auth-0.9.3/get_command_line.h        |  40 +++
+ pam_ssh_agent_auth-0.9.3/identity.h                |  24 ++
+ pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c  | 137 ++++++++-
+ pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.h  |   2 +-
+ pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.c      |  16 +-
+ pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.pod    |  50 ++-
+ pam_ssh_agent_auth-0.9.3/pam_static_macros.h       |  29 ++
+ .../pam_user_authorized_keys.c                     |  23 +-
+ .../pam_user_authorized_keys.h                     |   2 +-
+ pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c   | 334 ++++++++++++++++-----
+ pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.h   |   3 +-
+ pam_ssh_agent_auth-0.9.3/secure_filename.c         |  51 +++-
+ pam_ssh_agent_auth-0.9.3/secure_filename.h         |   4 +-
+ pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.c |  20 +-
+ pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.h |   2 +-
+ 20 files changed, 805 insertions(+), 140 deletions(-)
+ create mode 100644 pam_ssh_agent_auth-0.9.3/README
+ create mode 100644 pam_ssh_agent_auth-0.9.3/get_command_line.c
+ create mode 100644 pam_ssh_agent_auth-0.9.3/get_command_line.h
+
+diff --git a/pam_ssh_agent_auth-0.9.3/CONTRIBUTORS b/pam_ssh_agent_auth-0.9.3/CONTRIBUTORS
+index d5a21cb..22b424a 100644
+--- a/pam_ssh_agent_auth-0.9.3/CONTRIBUTORS
++++ b/pam_ssh_agent_auth-0.9.3/CONTRIBUTORS
+@@ -1,3 +1,5 @@
+ * Foremost, OpenSSH from which this project is derived.
+ * Jamie Beverly
+ * Rafael D'Halleweyn - 2011-06-05 18:56:24 EDT
++* Jan-Pieter Cornet ( johnpc ) - 2012-03-23 03:25:52 PDT
++* chrysn@fsfe.org
+diff --git a/pam_ssh_agent_auth-0.9.3/Makefile.in b/pam_ssh_agent_auth-0.9.3/Makefile.in
+index 47bb103..4977838 100644
+--- a/pam_ssh_agent_auth-0.9.3/Makefile.in
++++ b/pam_ssh_agent_auth-0.9.3/Makefile.in
+@@ -1,4 +1,28 @@
+ # $Id: Makefile.in,v 1.289 2008/03/13 01:41:31 djm Exp $
++#
++# Copyright (c) 2000 Markus Friedl.  All rights reserved.
++# Modifications Copyright (c) 2008-2014 Jamie Beverly. 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.
++#
+ 
+ # uncomment if you run a non bourne compatable shell. Ie. csh
+ #SHELL = @SH@
+@@ -46,9 +70,9 @@ INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
+ 
+ PAM_MODULES=pam_ssh_agent_auth.so
+ 
+-SSHOBJS=xmalloc.o atomicio.o authfd.o bufaux.o bufbn.o buffer.o cleanup.o entropy.o fatal.o key.o log.o misc.o secure_filename.o ssh-dss.o ssh-rsa.o uuencode.o compat.o
++SSHOBJS=xmalloc.o atomicio.o authfd.o bufaux.o bufbn.o buffer.o cleanup.o entropy.o fatal.o key.o log.o misc.o secure_filename.o ssh-dss.o ssh-rsa.o uuencode.o compat.o uidswap.o
+ 
+-PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o secure_filename.o
++PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o secure_filename.o get_command_line.o
+ 
+ 
+ MANPAGES_IN	= pam_ssh_agent_auth.pod
+diff --git a/pam_ssh_agent_auth-0.9.3/README b/pam_ssh_agent_auth-0.9.3/README
+new file mode 100644
+index 0000000..c1a49ef
+--- /dev/null
++++ b/pam_ssh_agent_auth-0.9.3/README
+@@ -0,0 +1,38 @@
++pam_ssh_agent_auth is a PAM module which permits PAM authentication via your
++keyring in a forwarded ssh-agent.
++
++Release 0.10.1 is stable, and has been tested on FreeBSD, Solaris 10, Solaris 11,
++RHEL5, RHEL6, Debian Wheezy, Ubuntu 12.04 (LTS), Ubuntu 13.10,
++and MacOS X 10.7.
++
++This module can be used to provide authentication for anything run locally that
++supports PAM. It was written specifically with the intention of permitting
++authentication for sudo without password entry, and also has been proven useful
++for use with su as an alternative to wheel.
++
++It serves as middle ground between the two most common, and suboptimal
++alternatives for large-scale system administration: allowing rootlogin via ssh,
++or using NOPASSWD in sudoers. This module allows for ssh public-key
++authentication, and it does this by leveraging an authentication mechanism you
++are probably already using, ssh-agent.
++
++There are caveats of course, ssh-agent forwarding has it’s own security risks
++which must be carefully considered for your environment. In cases where there
++are not untrustworthy intermediate servers, and you wish to retain traceability,
++accountability, and required authentication for privileged command invocation,
++the benefits should outweigh the risks. Release 0.10.1 can be downloaded from
++SourceForge: https://sourceforge.net/project/showfiles.php?group_id=249556
++
++If you encounter any issues with usability or security, please use the project's
++SourceForge tracker:
++https://sourceforge.net/tracker2/?group_id=249556&atid=1126337
++
++Note that if you wish to use this for sudo, you will need a version of sudo that
++preserves the env_keep environment during authentication; and ideally a version
++incorporating my minor patch which ensures RUSER is set during PAM authentication.
++
++sudo 1.6.8p12 does not work correctly with this PAM module, because it clears the
++environment (even env_keep variables) prior to attempting PAM authentication.
++
++sudo 1.7.2p1 or later is preferred, as it correctly sets PAM_RUSER for
++authentication.
+diff --git a/pam_ssh_agent_auth-0.9.3/configure.ac b/pam_ssh_agent_auth-0.9.3/configure.ac
+index 1f372ce..4eb1f32 100644
+--- a/pam_ssh_agent_auth-0.9.3/configure.ac
++++ b/pam_ssh_agent_auth-0.9.3/configure.ac
+@@ -18,8 +18,10 @@ AC_INIT(OpenSSH, Portable, openssh-unix-dev@mindrot.org)
+ AC_REVISION($Revision: 1.397 $)
+ AC_CONFIG_SRCDIR([pam_ssh_agent_auth.c])
+ 
+-AC_CONFIG_HEADER(config.h)
++AC_CONFIG_SRCDIR([config.h.in])
++AC_CONFIG_HEADERS([config.h])
+ AC_PROG_CC
++AC_C_INLINE
+ AC_CANONICAL_HOST
+ AC_C_BIGENDIAN
+ 
+@@ -117,7 +119,6 @@ if test -z "$LD" ; then
+ fi
+ AC_SUBST(LD)
+ 
+-AC_C_INLINE
+ 
+ AC_CHECK_DECL(LLONG_MAX, have_llong_max=1, , [#include <limits.h>])
+ 
+@@ -151,7 +152,7 @@ if test "$GCC" = "yes" || test "$GCC" = "egcs"; then
+ 		     ;;
+ 		2.*) no_attrib_nonnull=1 ;;
+ 		3.*) CFLAGS="$CFLAGS -Wsign-compare" ;;
+-		4.*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" ;;
++		4.*) CFLAGS="$CFLAGS -Wsign-compare -Wall -Wextra" ;;
+ 		*) ;;
+ 	esac
+ 
+@@ -1656,11 +1657,11 @@ fi
+ 
+ if test "x$check_for_conflicting_getspnam" = "x1"; then
+ 	AC_MSG_CHECKING(for conflicting getspnam in shadow.h)
+-	AC_COMPILE_IFELSE(
++	AC_COMPILE_IFELSE([AC_LANG_SOURCE(
+ 		[
+ #include <shadow.h>
+ int main(void) {exit(0);}
+-		],
++		])],
+ 		[
+ 			AC_MSG_RESULT(no)
+ 		],
+@@ -2720,7 +2721,7 @@ fi
+ dnl make sure we're using the real structure members and not defines
+ AC_CACHE_CHECK([for msg_accrights field in struct msghdr],
+ 		ac_cv_have_accrights_in_msghdr, [
+-	AC_COMPILE_IFELSE(
++	AC_COMPILE_IFELSE([AC_LANG_SOURCE(
+ 		[
+ #include <sys/types.h>
+ #include <sys/socket.h>
+@@ -2734,7 +2735,7 @@ struct msghdr m;
+ m.msg_accrights = 0;
+ exit(0);
+ }
+-		],
++		])],
+ 		[ ac_cv_have_accrights_in_msghdr="yes" ],
+ 		[ ac_cv_have_accrights_in_msghdr="no" ]
+ 	)
+@@ -2747,7 +2748,7 @@ fi
+ 
+ AC_CACHE_CHECK([for msg_control field in struct msghdr],
+ 		ac_cv_have_control_in_msghdr, [
+-	AC_COMPILE_IFELSE(
++	AC_COMPILE_IFELSE([AC_LANG_SOURCE(
+ 		[
+ #include <sys/types.h>
+ #include <sys/socket.h>
+@@ -2761,7 +2762,7 @@ struct msghdr m;
+ m.msg_control = 0;
+ exit(0);
+ }
+-		],
++		])],
+ 		[ ac_cv_have_control_in_msghdr="yes" ],
+ 		[ ac_cv_have_control_in_msghdr="no" ]
+ 	)
+@@ -2891,14 +2892,14 @@ AC_SEARCH_LIBS(getrrsetbyname, resolv,
+ 		    saved_LIBS="$LIBS"
+ 		    LIBS="$LIBS -lresolv"
+ 		    AC_MSG_CHECKING(for res_query in -lresolv)
+-		    AC_LINK_IFELSE([
++		    AC_LINK_IFELSE([AC_LANG_SOURCE([
+ #include <resolv.h>
+ int main()
+ {
+ 	res_query (0, 0, 0, 0, 0);
+ 	return 0;
+ }
+-			],
++			])],
+ 			[LIBS="$LIBS -lresolv"
+ 			 AC_MSG_RESULT(yes)],
+ 			[LIBS="$saved_LIBS"
+@@ -2915,7 +2916,7 @@ int main()
+ 	])
+ 
+ AC_MSG_CHECKING(if struct __res_state _res is an extern)
+-AC_LINK_IFELSE([
++AC_LINK_IFELSE([AC_LANG_SOURCE([
+ #include <stdio.h>
+ #if HAVE_SYS_TYPES_H
+ # include <sys/types.h>
+@@ -2925,7 +2926,7 @@ AC_LINK_IFELSE([
+ #include <resolv.h>
+ extern struct __res_state _res;
+ int main() { return 0; }
+-		],
++		])],
+ 		[AC_MSG_RESULT(yes)
+ 		 AC_DEFINE(HAVE__RES_EXTERN, 1,
+ 		    [Define if you have struct __res_state _res as an extern])
+diff --git a/pam_ssh_agent_auth-0.9.3/get_command_line.c b/pam_ssh_agent_auth-0.9.3/get_command_line.c
+new file mode 100644
+index 0000000..e880fee
+--- /dev/null
++++ b/pam_ssh_agent_auth-0.9.3/get_command_line.c
+@@ -0,0 +1,113 @@
++/*
++ * Copyright (c) 2014, Jamie Beverly.
++ * 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 Jamie Beverly ``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 Jamie Beverly OR
++ * CONTRIBUTORS 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.
++ *
++ * The views and conclusions contained in the software and documentation are those of the
++ * authors and should not be interpreted as representing official policies, either expressed
++ * or implied, of Jamie Beverly.
++ */
++
++#include <stdio.h>
++#include <errno.h>
++#include <string.h>
++
++#include "includes.h"
++#include "xmalloc.h"
++#include "get_command_line.h"
++
++#ifdef HAVE_PROC_PID_CMDLINE
++
++static size_t
++proc_pid_cmdline(char *** inargv)
++{
++    pid_t pid;
++    FILE *f = NULL;
++    char filename[64] = { 0 }, c = '\0';
++    char ** argv;
++    char argbuf[MAX_LEN_PER_CMDLINE_ARG + 1] = { 0 };
++    size_t count = 0, len = 0;
++
++    pid = getpid();
++    argv = NULL;
++
++    snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid);
++    f = fopen(filename, "r");
++
++    if (f) { 
++        while (!feof(f) && count < MAX_CMDLINE_ARGS) {
++            if (len > MAX_LEN_PER_CMDLINE_ARG) {
++                while (!feof(f) && (c = fgetc(f)) != '\0');
++            }
++            else {
++                c = fgetc(f);
++            }
++            switch (c) {
++                case EOF:
++                case '\0':
++                    if (len > 0) { 
++                        argv = xrealloc(argv, count + 1, sizeof(*argv));
++                        argv[count] = xcalloc(len + 1, sizeof(*argv[count]));
++                        strncpy(argv[count++], argbuf, len);
++                        memset(argbuf, '\0', MAX_LEN_PER_CMDLINE_ARG + 1);
++                        len = 0;
++                    }
++                    break;
++                default:
++                    argbuf[len++] = c;
++                    break;
++            }
++        }
++        fclose(f);
++    }
++    *inargv = argv;
++    return count;
++}
++#endif
++
++
++/*
++ * takes a pointer to an unallocated array of arrays of strings, populates the
++ * given pointer with the address of the allocated array of strings collected
++ */
++size_t 
++pamsshagentauth_get_command_line(char *** argv)
++{
++#ifdef HAVE_PROC_PID_CMDLINE
++    return proc_pid_cmdline(argv);
++#else
++    /* No other supported implementations at this time */
++    return 0;
++#endif
++}
++
++void
++pamsshagentauth_free_command_line(char ** argv, size_t n_args)
++{
++    size_t i;
++    for (i = 0; i < n_args; i++)
++        free(argv[i]);
++
++    free(argv);
++    return;
++}
++
+diff --git a/pam_ssh_agent_auth-0.9.3/get_command_line.h b/pam_ssh_agent_auth-0.9.3/get_command_line.h
+new file mode 100644
+index 0000000..37cd077
+--- /dev/null
++++ b/pam_ssh_agent_auth-0.9.3/get_command_line.h
+@@ -0,0 +1,40 @@
++/*
++ * Copyright (c) 2014, Jamie Beverly.
++ * 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 Jamie Beverly ``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 Jamie Beverly OR
++ * CONTRIBUTORS 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.
++ *
++ * The views and conclusions contained in the software and documentation are those of the
++ * authors and should not be interpreted as representing official policies, either expressed
++ * or implied, of Jamie Beverly.
++ */
++
++#ifndef _GET_COMMAND_LINE_H
++#define _GET_COMMAND_LINE_H
++
++#include "includes.h"
++
++size_t pamsshagentauth_get_command_line(char ***);
++void pamsshagentauth_free_command_line(char **, size_t);
++#define MAX_CMDLINE_ARGS 255
++#define MAX_LEN_PER_CMDLINE_ARG 255
++
++#endif
+diff --git a/pam_ssh_agent_auth-0.9.3/identity.h b/pam_ssh_agent_auth-0.9.3/identity.h
+index eb21320..0bde782 100644
+--- a/pam_ssh_agent_auth-0.9.3/identity.h
++++ b/pam_ssh_agent_auth-0.9.3/identity.h
+@@ -1,3 +1,27 @@
++/*
++ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
+ #ifndef _IDENTITY_H
+ #define _IDENTITY_H
+ #include "includes.h"
+diff --git a/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c b/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c
+index 11ab6e2..6b4d531 100644
+--- a/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c
++++ b/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c
+@@ -28,6 +28,8 @@
+  */
+ 
+ 
++#include <string.h>
++
+ #include "includes.h"
+ #include "config.h"
+ 
+@@ -48,26 +50,75 @@
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <openssl/evp.h>
++#include "ssh2.h"
++#include "misc.h"
+ 
+ #include "userauth_pubkey_from_id.h"
+ #include "identity.h"
++#include "get_command_line.h"
++extern char **environ;
++
++#define PAM_SSH_AGENT_AUTH_REQUESTv1 101
++
++static char *
++log_action(char ** action, size_t count)
++{
++    size_t i;
++    char *buf = NULL;
++
++    if (count == 0)
++        return NULL;
++   
++    buf = xcalloc((count * MAX_LEN_PER_CMDLINE_ARG) + (count * 3), sizeof(*buf));
++    for (i = 0; i < count; i++) {
++        strcat(buf, (i > 0) ? " '" : "'");
++        strncat(buf, action[i], MAX_LEN_PER_CMDLINE_ARG);
++        strcat(buf, "'");
++    }
++    return buf;
++}
++
++void
++agent_action(Buffer *buf, char ** action, size_t count)
++{
++    size_t i;
++    buffer_init(buf);
+ 
+-u_char * session_id2 = NULL;
+-uint8_t session_id_len = 0;
++    buffer_put_int(buf, count);
++
++    for (i = 0; i < count; i++) {
++        buffer_put_cstring(buf, action[i]);
++    }
++}
+ 
+-u_char *
+-session_id2_gen()
++void
++session_id2_gen(Buffer * session_id2, const char * user,
++                const char * ruser, const char * servicename)
+ {
+     char *cookie = NULL;
+     uint8_t i = 0;
+     uint32_t rnd = 0;
++    uint8_t cookie_len;
++    char hostname[256] = { 0 };
++    char pwd[1024] = { 0 };
++    time_t ts;
++    char ** reported_argv = NULL;
++    size_t count = 0;
++    char * action_logbuf = NULL;
++    Buffer action_agentbuf;
++    uint8_t free_logbuf = 0;
++    char * retc;
++    int32_t reti;
+ 
+     rnd = arc4random();
+-    session_id_len = (uint8_t) rnd;
++    cookie_len = ((uint8_t) rnd);
++    while (cookie_len < 16) { 
++        cookie_len += 16;                                          /* Add 16 bytes to the size to ensure that while the length is random, the length is always reasonable; ticket #18 */
++    }
+ 
+-    cookie = calloc(1,session_id_len);
++    cookie = xcalloc(1, cookie_len);
+ 
+-    for (i = 0; i < session_id_len; i++) {
++    for (i = 0; i < cookie_len; i++) {
+         if (i % 4 == 0) {
+             rnd = arc4random();
+         }
+@@ -75,7 +126,64 @@ session_id2_gen()
+         rnd >>= 8;
+     }
+ 
+-    return cookie;
++    count = pamsshagentauth_get_command_line(&reported_argv);
++    if (count > 0) { 
++        free_logbuf = 1;
++        action_logbuf = log_action(reported_argv, count);
++        agent_action(&action_agentbuf, reported_argv, count);
++        pamsshagentauth_free_command_line(reported_argv, count);
++    }
++    else {
++        action_logbuf = "unknown on this platform";
++        buffer_init(&action_agentbuf); /* stays empty, means unavailable */
++    }
++    
++    /*
++    action = getenv("SUDO_COMMAND");
++    if(!action) {
++        action = getenv("PAM_AUTHORIZED_ACTION");
++        if(!action) {
++            action = empty;
++        }
++    }
++    */
++
++    reti = gethostname(hostname, sizeof(hostname) - 1);
++    retc = getcwd(pwd, sizeof(pwd) - 1);
++    time(&ts);
++
++    buffer_init(session_id2);
++
++    buffer_put_int(session_id2, PAM_SSH_AGENT_AUTH_REQUESTv1);
++    /* debug3("cookie: %s", tohex(cookie, cookie_len)); */
++    buffer_put_string(session_id2, cookie, cookie_len);
++    /* debug3("user: %s", user); */
++    buffer_put_cstring(session_id2, user);
++    /* debug3("ruser: %s", ruser); */
++    buffer_put_cstring(session_id2, ruser);
++    /* debug3("servicename: %s", servicename); */
++    buffer_put_cstring(session_id2, servicename);
++    /* debug3("pwd: %s", pwd); */
++    if(retc)
++        buffer_put_cstring(session_id2, pwd);
++    else
++        buffer_put_cstring(session_id2, "");
++    /* debug3("action: %s", action_logbuf); */
++    buffer_put_string(session_id2, action_agentbuf.buf + action_agentbuf.offset, action_agentbuf.end - action_agentbuf.offset);
++    if (free_logbuf) { 
++        free(action_logbuf);
++        buffer_free(&action_agentbuf);
++    }
++    /* debug3("hostname: %s", hostname); */
++    if(reti >= 0)
++        buffer_put_cstring(session_id2, hostname);
++    else
++        buffer_put_cstring(session_id2, "");
++    /* debug3("ts: %ld", ts); */
++    buffer_put_int64(session_id2, (uint64_t) ts);
++
++    free(cookie);
++    return;
+ }
+ 
+ /* 
+@@ -174,19 +282,21 @@ ssh_get_authentication_connection_for_uid(uid_t uid)
+ }
+ 
+ int
+-find_authorized_keys(uid_t uid)
++find_authorized_keys(const char * user, const char * ruser, const char * servicename)
+ {
++    Buffer session_id2 = { 0 };
+     Identity *id;
+     Key *key;
+     AuthenticationConnection *ac;
+     char *comment;
+     uint8_t retval = 0;
++    uid_t uid = getpwnam(ruser)->pw_uid;
+ 
+     OpenSSL_add_all_digests();
+-    session_id2 = session_id2_gen();
++    session_id2_gen(&session_id2, user, ruser, servicename);
+ 
+     if ((ac = ssh_get_authentication_connection_for_uid(uid))) {
+-        verbose("Contacted ssh-agent of user %s (%u)", getpwuid(uid)->pw_name, uid);
++        verbose("Contacted ssh-agent of user %s (%u)", ruser, uid);
+         for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) 
+         {
+             if(key != NULL) {
+@@ -194,7 +304,7 @@ find_authorized_keys(uid_t uid)
+                 id->key = key;
+                 id->filename = comment;
+                 id->ac = ac;
+-                if(userauth_pubkey_from_id(id)) {
++                if(userauth_pubkey_from_id(ruser, id, &session_id2)) {
+                     retval = 1;
+                 }
+                 free(id->filename);
+@@ -204,12 +314,13 @@ find_authorized_keys(uid_t uid)
+                     break;
+             }
+         }
++        buffer_free(&session_id2);
+         ssh_close_authentication_connection(ac);
+     }
+     else {
+         verbose("No ssh-agent could be contacted");
+     }
+-    free(session_id2);
++    /*free(session_id2);*/
+     EVP_cleanup();
+     return retval;
+ }
+diff --git a/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.h b/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.h
+index ed7549e..e6c75aa 100644
+--- a/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.h
++++ b/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.h
+@@ -31,6 +31,6 @@
+ #ifndef _ITERATE_SSH_AGENT_KEYS_H
+ #define _ITERATE_SSH_AGENT_KEYS_H
+ 
+-int find_authorized_keys(uid_t);
++int find_authorized_keys(const char * user, const char * ruser, const char * servicename);
+ 
+ #endif
+diff --git a/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.c b/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.c
+index d3f4325..37309f7 100644
+--- a/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.c
++++ b/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.c
+@@ -59,9 +59,12 @@
+ #include "pam_user_authorized_keys.h"
+ 
+ #define strncasecmp_literal(A,B) strncasecmp( A, B, sizeof(B) - 1)
++#define UNUSED(expr) do { (void)(expr); } while (0)
+ 
+ char           *authorized_keys_file = NULL;
+ uint8_t         allow_user_owned_authorized_keys_file = 0;
++char           *authorized_keys_command = NULL;
++char           *authorized_keys_command_user = NULL;
+ 
+ #if ! HAVE___PROGNAME || HAVE_BUNDLE
+ char           *__progname;
+@@ -90,6 +93,7 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv)
+     facility = SYSLOG_FACILITY_AUTHPRIV;
+ #endif
+ 
++    UNUSED(flags);
+     pam_get_item(pamh, PAM_SERVICE, (void *) &servicename);
+ /*
+  * XXX: 
+@@ -113,6 +117,12 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv)
+         if(strncasecmp_literal(*argv_ptr, "file=") == 0 ) { 
+             authorized_keys_file_input = *argv_ptr + sizeof("file=") - 1;
+         }
++        if(strncasecmp_literal(*argv_ptr, "authorized_keys_command=") == 0 ) { 
++            authorized_keys_command = *argv_ptr + sizeof("authorized_keys_command=") - 1;
++        }
++        if(strncasecmp_literal(*argv_ptr, "authorized_keys_command_user=") == 0 ) { 
++            authorized_keys_command_user = *argv_ptr + sizeof("authorized_keys_command_user=") - 1;
++        }
+ #ifdef ENABLE_SUDO_HACK
+         if(strncasecmp_literal(*argv_ptr, "sudo_service_name=") == 0) { 
+             strncpy( sudo_service_name, *argv_ptr + sizeof("sudo_service_name=") - 1, sizeof(sudo_service_name) - 1);
+@@ -182,7 +192,7 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv)
+         /* 
+          * this pw_uid is used to validate the SSH_AUTH_SOCK, and so must be the uid of the ruser invoking the program, not the target-user
+          */
+-        if(find_authorized_keys(getpwnam(ruser)->pw_uid)) {
++        if(find_authorized_keys(user, ruser, servicename)) { /* getpwnam(ruser)->pw_uid)) { */
+             logit("Authenticated: `%s' as `%s' using %s", ruser, user, authorized_keys_file);
+             retval = PAM_SUCCESS;
+         } else {
+@@ -207,6 +217,10 @@ cleanexit:
+ PAM_EXTERN int __attribute__ ((visibility ("default")))
+ pam_sm_setcred(pam_handle_t * pamh, int flags, int argc, const char **argv)
+ {
++    UNUSED(pamh);
++    UNUSED(flags);
++    UNUSED(argc);
++    UNUSED(argv);
+     return PAM_SUCCESS;
+ }
+ 
+diff --git a/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.pod b/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.pod
+index 4570746..76b1f0f 100644
+--- a/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.pod
++++ b/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.pod
+@@ -1,8 +1,12 @@
+-=head1 PAM_SSH_AGENT_AUTH
++=head1 NAME
++
++pam_ssh_agent_auth - PAM module for granting permissions based on SSH agent requests
++
++=head1 DESCRIPTION
+ 
+ This module provides authentication via ssh-agent.  If an ssh-agent listening at SSH_AUTH_SOCK can successfully authenticate that it has the secret key for a public key in the specified file, authentication is granted, otherwise authentication fails.
+ 
+-=head1 SUMMARY
++=head1 CONFIGURATION
+ 
+ =over
+ 
+@@ -10,7 +14,8 @@ This module provides authentication via ssh-agent.  If an ssh-agent listening at
+  auth	sufficient	pam_ssh_agent_auth.so file=/etc/security/authorized_keys
+ 
+ =item /etc/sudoers:
+-
++ 
++In older versions of sudo (< 1.8.5) it was necessary to set:
+  Defaults    env_keep += "SSH_AUTH_SOCK"
+ 
+ =back
+@@ -33,6 +38,15 @@ Specify the path to the authorized_keys file(s) you would like to use for authen
+ A flag which enables authorized_keys files to be owned by the invoking user, instead of root. This flag is enabled automatically whenever
+ the expansions %h or ~ are used.
+ 
++=item authorized_keys_command=<path to executable>
++
++Specify an external command to run, which should take a single argument, the username of the person being authenticated, and emit to its stdout a file in authorized_keys format.
++This is ideally suited for use with sssd's sss_ssh_authorizedkeys, for authenticating users via authorized_keys stored in ldap or other sssd supported security service.
++
++=item authorized_keys_command_user=<username>
++
++Specify a user to run the authorized_keys_command as. If this option is not specified, the authorized_keys_command will be run as the user being authenticated.
++
+ =item debug
+ 
+ A flag which enables verbose logging
+@@ -105,4 +119,34 @@ so this file must be owned by root.
+ 
+ =back
+ 
++=head1 COPYRIGHT
++
++ Copyright (c) 2008-2014, Jamie Beverly.
++ And is based on openssh, and the included works by Markus Friedl, Darren Tucker,
++ Todd C. Miller, Ben Lindstrom, Tim Rice, Damien Miller, and many others.
++
++ All rights reserved.
++
++ See sources for complete attributions.
++ 
++ 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 Jamie Beverly ``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 Jamie Beverly OR
++ CONTRIBUTORS 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.
++
+ =cut
+diff --git a/pam_ssh_agent_auth-0.9.3/pam_static_macros.h b/pam_ssh_agent_auth-0.9.3/pam_static_macros.h
+index a4938d3..a991704 100644
+--- a/pam_ssh_agent_auth-0.9.3/pam_static_macros.h
++++ b/pam_ssh_agent_auth-0.9.3/pam_static_macros.h
+@@ -1,3 +1,32 @@
++/*
++ * Copyright (c) 2008, Jamie Beverly.
++ * 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 Jamie Beverly ``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 Jamie Beverly OR
++ * CONTRIBUTORS 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.
++ *
++ * The views and conclusions contained in the software and documentation are those of the
++ * authors and should not be interpreted as representing official policies, either expressed
++ * or implied, of Jamie Beverly.
++ */
++
+ #ifndef __PAM_STATIC_MACROS_H
+ #define __PAM_STATIC_MACROS_H
+ 
+diff --git a/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c b/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c
+index 60bef68..abc0a62 100644
+--- a/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c
++++ b/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c
+@@ -1,4 +1,4 @@
+-/*
++/* 
+  * Copyright (c) 2008, Jamie Beverly. 
+  * All rights reserved.
+  * 
+@@ -80,9 +80,15 @@
+ #include "identity.h"
+ #include "pam_user_key_allowed2.h"
+ 
+-extern char    *authorized_keys_file;
+-extern uint8_t  allow_user_owned_authorized_keys_file;
+-uid_t           authorized_keys_file_allowed_owner_uid;
++extern char *authorized_keys_file;
++
++extern char *authorized_keys_command;
++
++extern char *authorized_keys_command_user;
++
++extern uint8_t allow_user_owned_authorized_keys_file;
++
++uid_t authorized_keys_file_allowed_owner_uid;
+ 
+ void
+ parse_authorized_key_file(const char *user, const char *authorized_keys_file_input)
+@@ -137,8 +143,11 @@ parse_authorized_key_file(const char *user, const char *authorized_keys_file_inp
+ }
+ 
+ int
+-pam_user_key_allowed(Key * key)
++pam_user_key_allowed(const char *ruser, Key * key)
+ {
+     return pam_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), key, authorized_keys_file)
+-        || pam_user_key_allowed2(getpwuid(0), key, authorized_keys_file);
++        || pam_user_key_allowed2(getpwuid(0), key, authorized_keys_file)
++        || pam_user_key_command_allowed2(authorized_keys_command,
++                                         authorized_keys_command_user,
++                                         getpwnam(ruser), key);
+ }
+diff --git a/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.h b/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.h
+index ae9a4b8..a871bf0 100644
+--- a/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.h
++++ b/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.h
+@@ -32,7 +32,7 @@
+ #define _PAM_USER_KEY_ALLOWED_H
+ 
+ #include "identity.h"
+-int pam_user_key_allowed(Key *);
++int pam_user_key_allowed(const char *, Key *);
+ void parse_authorized_key_file(const char *, const char *);
+ 
+ #endif
+diff --git a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c
+index c6680e4..4aceecb 100644
+--- a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c
++++ b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c
+@@ -1,4 +1,4 @@
+-/*
++/* 
+  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+@@ -33,9 +33,14 @@
+ 
+ #include <sys/types.h>
+ #include <sys/stat.h>
++#include <sys/wait.h>
++#include <fcntl.h>
+ 
+ #include <pwd.h>
+ #include <stdio.h>
++#include <signal.h>
++#include <errno.h>
++#include <string.h>
+ 
+ #include "xmalloc.h"
+ #include "ssh.h"
+@@ -48,87 +53,263 @@
+ #include "pathnames.h"
+ #include "misc.h"
+ #include "secure_filename.h"
++#include "uidswap.h"
++#include <unistd.h>
+ 
+ #include "identity.h"
+ 
+ /* return 1 if user allows given key */
+ /* Modified slightly from original found in auth2-pubkey.c */
++static int
++pamsshagentauth_check_authkeys_file(FILE * f, char *file, Key * key)
++{
++    char line[SSH_MAX_PUBKEY_BYTES];
++    int found_key = 0;
++    u_long linenum = 0;
++    Key *found;
++    char *fp;
++
++    found_key = 0;
++    found = key_new(key->type);
++
++    while(read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
++        char *cp = NULL; /* *key_options = NULL; */
++
++        /* Skip leading whitespace, empty and comment lines. */
++        for(cp = line; *cp == ' ' || *cp == '\t'; cp++);
++        if(!*cp || *cp == '\n' || *cp == '#')
++            continue;
++
++        if(key_read(found, &cp) != 1) {
++            /* no key? check if there are options for this key */
++            int quoted = 0;
++
++            verbose("user_key_allowed: check options: '%s'", cp);
++            /* key_options = cp; */
++            for(; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
++                if(*cp == '\\' && cp[1] == '"')
++                    cp++;                                  /* Skip both */
++                else if(*cp == '"')
++                    quoted = !quoted;
++            }
++            /* Skip remaining whitespace. */
++            for(; *cp == ' ' || *cp == '\t'; cp++);
++            if(key_read(found, &cp) != 1) {
++                verbose("user_key_allowed: advance: '%s'", cp);
++                /* still no key? advance to next line */
++                continue;
++            }
++        }
++        if(key_equal(found, key)) {
++            found_key = 1;
++            logit("matching key found: file/command %s, line %lu", file,
++                                  linenum);
++            fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
++            logit("Found matching %s key: %s",
++                                  key_type(found), fp);
++            free(fp);
++            break;
++        }
++    }
++    key_free(found);
++    if(!found_key)
++        verbose("key not found");
++    return found_key;
++}
++
++/* 
++ * Checks whether key is allowed in file.
++ * returns 1 if the key is allowed or 0 otherwise.
++ */
+ int
+ pam_user_key_allowed2(struct passwd *pw, Key *key, char *file)
+ {
+-	char line[SSH_MAX_PUBKEY_BYTES];
+-	int found_key = 0;
+-	FILE *f;
+-	u_long linenum = 0;
+-	struct stat st;
+-	Key *found;
+-	char *fp;
+-
+-	verbose("trying public key file %s", file);
+-
+-	/* Fail not so quietly if file does not exist */
+-	if (stat(file, &st) < 0) {
++    FILE *f;
++    int found_key = 0;
++    struct stat st;
++    char buf[SSH_MAX_PUBKEY_BYTES];
++
++    /* Temporarily use the user's uid. */
++    verbose("trying public key file %s", file);
++
++    /* Fail not so quietly if file does not exist */
++    if(stat(file, &st) < 0) {
+         verbose("File not found: %s", file);
+-		return 0;
+-	}
+-	/* Open the file containing the authorized keys. */
+-	f = fopen(file, "r");
+-	if (!f) {
+-		return 0;
+-	}
+-	if (
+-	    secure_filename(f, file, pw, line, sizeof(line)) != 0) {
+-		fclose(f);
+-		logit("Authentication refused: %s", line);
+-		return 0;
+-	}
+-
+-	found_key = 0;
+-	found = key_new(key->type);
+-
+-	while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
+-		char *cp, *key_options = NULL;
+-
+-		/* Skip leading whitespace, empty and comment lines. */
+-		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
+-			;
+-		if (!*cp || *cp == '\n' || *cp == '#')
+-			continue;
+-
+-		if (key_read(found, &cp) != 1) {
+-			/* no key?  check if there are options for this key */
+-			int quoted = 0;
+-			verbose("user_key_allowed: check options: '%s'", cp);
+-			key_options = cp;
+-			for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
+-				if (*cp == '\\' && cp[1] == '"')
+-					cp++;	/* Skip both */
+-				else if (*cp == '"')
+-					quoted = !quoted;
+-			}
+-			/* Skip remaining whitespace. */
+-			for (; *cp == ' ' || *cp == '\t'; cp++)
+-				;
+-			if (key_read(found, &cp) != 1) {
+-				verbose("user_key_allowed: advance: '%s'", cp);
+-				/* still no key?  advance to next line*/
+-				continue;
+-			}
+-		}
+-		if (key_equal(found, key)) {
+-			found_key = 1;
+-			logit("matching key found: file %s, line %lu",
+-			    file, linenum);
+-			fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
+-			logit("Found matching %s key: %s",
+-			    key_type(found), fp);
+-			free(fp);
+-			break;
+-		}
+-	}
+-	fclose(f);
+-	key_free(found);
+-	if (!found_key)
+-		verbose("key not found");
+-	return found_key;
++        return 0;
++    }
++
++    /* Open the file containing the authorized keys. */
++    f = fopen(file, "r");
++    if(!f) {
++        return 0;
++    }
++
++    if(secure_filename(f, file, pw, buf, sizeof(buf)) != 0) {
++        fclose(f);
++        logit("Authentication refused: %s", buf);
++        return 0;
++    }
++
++    found_key = pamsshagentauth_check_authkeys_file(f, file, key);
++    fclose(f);
++    return found_key;
++}
++
++/* 
++ * Checks whether key is allowed in output of command.
++ * returns 1 if the key is allowed or 0 otherwise.
++ */
++int
++pam_user_key_command_allowed2(char *authorized_keys_command,
++                          char *authorized_keys_command_user,
++                          struct passwd *user_pw, Key * key)
++{
++    FILE *f;
++    int ok, found_key = 0;
++    struct passwd *pw;
++    struct stat st;
++    int status, devnull, p[2], i;
++    pid_t pid;
++    char errmsg[512];
++    char username[512] = { 0 };
++    
++
++
++    if(authorized_keys_command == NULL || authorized_keys_command[0] != '/')
++        return 0;
++
++
++    /* getpwnam of authorized_keys_command_user will overwrite the statics used by getpwnam (including pw_name) */
++    strncpy(username, user_pw->pw_name, sizeof(username) - 1);
++
++    /* If no user specified to run commands the default to target user */
++    if(authorized_keys_command_user == NULL) {
++        pw = user_pw;
++    }
++    else {
++        pw = getpwnam(authorized_keys_command_user);
++        if(pw == NULL) {
++            error("authorized_keys_command_user \"%s\" not found: %s",
++                 authorized_keys_command_user, strerror(errno));
++            return 0;
++        }
++    }
++
++    temporarily_use_uid(pw);
++
++    if(stat(authorized_keys_command, &st) < 0) {
++        error
++            ("Could not stat AuthorizedKeysCommand \"%s\": %s",
++             authorized_keys_command, strerror(errno));
++        goto out;
++    }
++    if(pamsshagentauth_auth_secure_path
++       (authorized_keys_command, &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) {
++        error("Unsafe AuthorizedKeysCommand: %s", errmsg);
++        goto out;
++    }
++
++    /* open the pipe and read the keys */
++    if(pipe(p) != 0) {
++        error("%s: pipe: %s", __func__, strerror(errno));
++        goto out;
++    }
++
++    debug("Running AuthorizedKeysCommand: \"%s\" as \"%s\" with argument: \"%s\"",
++                          authorized_keys_command, pw->pw_name, username);
++
++    /* 
++     * Don't want to call this in the child, where it can fatal() and
++     * run cleanup_exit() code.
++     */
++    restore_uid();
++
++    switch ((pid = fork())) {
++    case -1:                                              /* error */
++        error("%s: fork: %s", __func__, strerror(errno));
++        close(p[0]);
++        close(p[1]);
++        return 0;
++    case 0:                                               /* child */
++        for(i = 0; i < NSIG; i++)
++            signal(i, SIG_DFL);
++
++        /* do this before the setresuid so thta they can be logged */
++        if((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
++            error("%s: open %s: %s", __func__, _PATH_DEVNULL,
++                                     strerror(errno));
++            _exit(1);
++        }
++        if(dup2(devnull, STDIN_FILENO) == -1 || dup2(p[1], STDOUT_FILENO) == -1
++           || dup2(devnull, STDERR_FILENO) == -1) {
++            error("%s: dup2: %s", __func__, strerror(errno));
++            _exit(1);
++        }
++#if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID)
++        if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
++#else
++        if (setgid(pw->pw_gid) != 0 || setegid(pw->pw_gid) != 0) {
++#endif
++            error("setresgid %u: %s", (u_int) pw->pw_gid,
++                                     strerror(errno));
++            _exit(1);
++        }
++
++#ifdef HAVE_SETRESUID
++        if(setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
++#else
++        if (setuid(pw->pw_uid) != 0 || seteuid(pw->pw_uid) != 0) {
++#endif
++            error("setresuid %u: %s", (u_int) pw->pw_uid,
++                                     strerror(errno));
++            _exit(1);
++        }
++
++        close(p[0]);
++        closefrom(STDERR_FILENO + 1);
++
++        execl(authorized_keys_command, authorized_keys_command, username, (char *)NULL);
++
++        /* pretty sure this will barf because we are now suid, but since we
++           should't reach this anyway, I'll leave it here */
++        error("AuthorizedKeysCommand %s exec failed: %s",
++                                 authorized_keys_command, strerror(errno));
++        _exit(127);
++    default:                                              /* parent */
++        break;
++    }
++
++    temporarily_use_uid(pw);
++
++    close(p[1]);
++    if((f = fdopen(p[0], "r")) == NULL) {
++        error("%s: fdopen: %s", __func__, strerror(errno));
++        close(p[0]);
++        /* Don't leave zombie child */
++        while(waitpid(pid, NULL, 0) == -1 && errno == EINTR);
++        goto out;
++    }
++    ok = pamsshagentauth_check_authkeys_file(f, authorized_keys_command, key);
++    fclose(f);
++
++    while(waitpid(pid, &status, 0) == -1) {
++        if(errno != EINTR) {
++            error("%s: waitpid: %s", __func__,
++                                     strerror(errno));
++            goto out;
++        }
++    }
++    if(WIFSIGNALED(status)) {
++        error("AuthorizedKeysCommand %s exited on signal %d",
++                                 authorized_keys_command, WTERMSIG(status));
++        goto out;
++    } else if(WEXITSTATUS(status) != 0) {
++        error("AuthorizedKeysCommand %s returned status %d",
++                                 authorized_keys_command, WEXITSTATUS(status));
++        goto out;
++    }
++    found_key = ok;
++  out:
++    restore_uid();
++    return found_key;
+ }
+diff --git a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.h b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.h
+index 416d055..24533a0 100644
+--- a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.h
++++ b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.h
+@@ -32,5 +32,6 @@
+ 
+ #include "identity.h"
+ int pam_user_key_allowed2(struct passwd *, Key *, char *);
++int pam_user_key_command_allowed2(char *, char *, struct passwd *, Key *);
+ 
+ #endif
+diff --git a/pam_ssh_agent_auth-0.9.3/secure_filename.c b/pam_ssh_agent_auth-0.9.3/secure_filename.c
+index c24cab2..d685599 100644
+--- a/pam_ssh_agent_auth-0.9.3/secure_filename.c
++++ b/pam_ssh_agent_auth-0.9.3/secure_filename.c
+@@ -71,29 +71,38 @@
+  * Returns 0 on success and -1 on failure
+  */
+ int
+-secure_filename(FILE *f, const char *file, struct passwd *pw,
+-    char *err, size_t errlen)
++pamsshagentauth_auth_secure_path(const char *name, struct stat *stp,
++        const char *pw_dir, uid_t uid, char *err, size_t errlen)
+ {
+-	uid_t uid = pw->pw_uid;
+ 	char buf[MAXPATHLEN], homedir[MAXPATHLEN];
+ 	char *cp;
+ 	int comparehome = 0;
+ 	struct stat st;
+ 
+-    verbose("secure_filename: checking for uid: %u", uid);
++    verbose("auth_secure_filename: checking for uid: %u", uid);
+ 
+-	if (realpath(file, buf) == NULL) {
+-		snprintf(err, errlen, "realpath %s failed: %s", file,
++	/* if (realpath(pw->pw_dir, homedir) != NULL) */
++    if (realpath(name, buf) == NULL) {
++		snprintf(err, errlen, "realpath %s failed: %s", name,
+ 		    strerror(errno));
+ 		return -1;
+ 	}
+-	if (realpath(pw->pw_dir, homedir) != NULL)
++	if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
+ 		comparehome = 1;
+ 
+ 	/* check the open file to avoid races */
+-	if (fstat(fileno(f), &st) < 0 ||
+-	    (st.st_uid != 0 && st.st_uid != uid) ||
+-	    (st.st_mode & 022) != 0) {
++	/* 
++     * if (fstat(fileno(f), &st) < 0 ||
++	 *    (st.st_uid != 0 && st.st_uid != uid) ||
++	 *    (st.st_mode & 022) != 0) {
++    */
++    if (!S_ISREG(stp->st_mode)) {
++        snprintf(err, errlen, "%s is not a regular file", buf);
++        return -1;
++    }
++
++    if ((stp->st_uid != 0 && stp->st_uid != uid) ||
++            (stp->st_mode & 022) != 0) {
+ 		snprintf(err, errlen, "bad ownership or modes for file %s",
+ 		    buf);
+ 		return -1;
+@@ -132,3 +141,25 @@ secure_filename(FILE *f, const char *file, struct passwd *pw,
+ 	return 0;
+ }
+ 
++/*
++ * Version of secure_path() that accepts an open file descriptor to
++ * avoid races.
++ *
++ * Returns 0 on success and -1 on failure
++ */
++int
++secure_filename(FILE *f, const char *file, struct passwd *pw,
++    char *err, size_t errlen)
++{
++   struct stat st;
++   char buf[MAXPATHLEN] = { 0 };
++
++   /* check the open file to avoid races */
++   if (fstat(fileno(f), &st) < 0) {
++       snprintf(err, errlen, "cannot stat file %s: %s",
++           buf, strerror(errno));
++       return -1;
++   }
++   return pamsshagentauth_auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
++}
++
+diff --git a/pam_ssh_agent_auth-0.9.3/secure_filename.h b/pam_ssh_agent_auth-0.9.3/secure_filename.h
+index 198c13d..4c1a208 100644
+--- a/pam_ssh_agent_auth-0.9.3/secure_filename.h
++++ b/pam_ssh_agent_auth-0.9.3/secure_filename.h
+@@ -28,5 +28,7 @@
+ #define _SECURE_FILENAME_H
+ #include <pwd.h>
+ #include <stdio.h>
++struct stat;
+ int secure_filename(FILE *, const char *, struct passwd *, char *, size_t);
++int pamsshagentauth_auth_secure_path(const char *, struct stat *, const char *, uid_t, char *, size_t);
+ #endif
+diff --git a/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.c b/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.c
+index 163278b..31849f8 100644
+--- a/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.c
++++ b/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.c
+@@ -48,11 +48,14 @@
+ #include "identity.h"
+ #include "pam_user_authorized_keys.h"
+ 
+-extern u_char  *session_id2;
++#define SSH2_MSG_USERAUTH_TRUST_REQUEST          54
++
++/* extern u_char  *session_id2;
+ extern uint8_t  session_id_len;
++ */
+ 
+ int
+-userauth_pubkey_from_id(Identity * id)
++userauth_pubkey_from_id(const char *ruser, Identity * id, Buffer * session_id2)
+ {
+     Buffer          b = { 0 };
+     char           *pkalg = NULL;
+@@ -63,7 +66,7 @@ userauth_pubkey_from_id(Identity * id)
+     pkalg = (char *) key_ssh_name(id->key);
+ 
+     /* first test if this key is even allowed */
+-    if(! pam_user_key_allowed(id->key))
++    if(! pam_user_key_allowed(ruser, id->key))
+         goto user_auth_clean_exit;
+ 
+     if(key_to_blob(id->key, &pkblob, &blen) == 0)
+@@ -72,10 +75,10 @@ userauth_pubkey_from_id(Identity * id)
+     /* construct packet to sign and test */
+     buffer_init(&b);
+ 
+-    buffer_put_string(&b, session_id2, session_id_len);
+-    buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+-    buffer_put_cstring(&b, "root");
+-    buffer_put_cstring(&b, "ssh-userauth");
++    buffer_put_string(&b, session_id2->buf + session_id2->offset, session_id2->end - session_id2->offset);
++    buffer_put_char(&b, SSH2_MSG_USERAUTH_TRUST_REQUEST); 
++    buffer_put_cstring(&b, ruser);
++    buffer_put_cstring(&b, "pam_ssh_agent_auth");
+     buffer_put_cstring(&b, "publickey");
+     buffer_put_char(&b, 1);
+     buffer_put_cstring(&b, pkalg);
+@@ -89,8 +92,7 @@ userauth_pubkey_from_id(Identity * id)
+         authenticated = 1;
+ 
+   user_auth_clean_exit:
+-    if(&b != NULL)
+-        buffer_free(&b);
++    buffer_free(&b);
+     if(sig != NULL)
+         free(sig);
+     if(pkblob != NULL)
+diff --git a/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.h b/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.h
+index 1e14231..7758808 100644
+--- a/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.h
++++ b/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.h
+@@ -32,6 +32,6 @@
+ #define _USERAUTH_PUBKEY_FROM_ID_H
+ 
+ #include <identity.h>
+-int userauth_pubkey_from_id(Identity *);
++int userauth_pubkey_from_id(const char *, Identity *, Buffer *);
+ 
+ #endif
+-- 
+2.5.0
+
+--- openssh-6.6p1/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c.psaa-command	2016-04-20 09:31:32.164686370 +0200
++++ openssh-6.6p1/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c	2016-04-20 09:35:49.778344576 +0200
+@@ -145,8 +145,12 @@
+ int
+ pam_user_key_allowed(const char *ruser, Key * key)
+ {
+-    return pam_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), key, authorized_keys_file)
+-        || pam_user_key_allowed2(getpwuid(0), key, authorized_keys_file)
++    struct passwd *pw;
++    return
++        ((pw = getpwuid(authorized_keys_file_allowed_owner_uid)) &&
++            pam_user_key_allowed2(pw, key, authorized_keys_file))
++        || ((pw = getpwuid(0)) &&
++            pam_user_key_allowed2(pw, key, authorized_keys_file))
+         || pam_user_key_command_allowed2(authorized_keys_command,
+                                          authorized_keys_command_user,
+                                          getpwnam(ruser), key);
diff --git a/SOURCES/sshd-keygen.service b/SOURCES/sshd-keygen.service
index a27d4f6..77cffeb 100644
--- a/SOURCES/sshd-keygen.service
+++ b/SOURCES/sshd-keygen.service
@@ -1,8 +1,8 @@
 [Unit]
 Description=OpenSSH Server Key Generation
-ConditionPathExists=|!/etc/ssh/ssh_host_rsa_key
-ConditionPathExists=|!/etc/ssh/ssh_host_ecdsa_key
-ConditionPathExists=|!/etc/ssh/ssh_host_ed25519_key
+ConditionFileNotEmpty=|!/etc/ssh/ssh_host_rsa_key
+ConditionFileNotEmpty=|!/etc/ssh/ssh_host_ecdsa_key
+ConditionFileNotEmpty=|!/etc/ssh/ssh_host_ed25519_key
 PartOf=sshd.service sshd.socket
 
 [Service]
diff --git a/SOURCES/sshd.service b/SOURCES/sshd.service
index eb87d32..089d4a7 100644
--- a/SOURCES/sshd.service
+++ b/SOURCES/sshd.service
@@ -5,8 +5,10 @@ After=network.target sshd-keygen.service
 Wants=sshd-keygen.service
 
 [Service]
+Type=forking
+PIDFile=/var/run/sshd.pid
 EnvironmentFile=/etc/sysconfig/sshd
-ExecStart=/usr/sbin/sshd -D $OPTIONS
+ExecStart=/usr/sbin/sshd $OPTIONS
 ExecReload=/bin/kill -HUP $MAINPID
 KillMode=process
 Restart=on-failure
diff --git a/SPECS/openssh.spec b/SPECS/openssh.spec
index d13eff8..3eaee3a 100644
--- a/SPECS/openssh.spec
+++ b/SPECS/openssh.spec
@@ -64,7 +64,7 @@
 
 # Do not forget to bump pam_ssh_agent_auth release if you rewind the main package release to 1
 %define openssh_ver 6.6.1p1
-%define openssh_rel 25
+%define openssh_rel 31
 %define pam_ssh_agent_ver 0.9.3
 %define pam_ssh_agent_rel 9
 
@@ -96,9 +96,6 @@ Patch0: openssh-5.9p1-wIm.patch
 Patch100: openssh-6.6.1p1-coverity.patch
 #https://bugzilla.mindrot.org/show_bug.cgi?id=1872
 Patch101: openssh-6.6p1-fingerprint.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
 #https://bugzilla.mindrot.org/show_bug.cgi?id=1889
 Patch103: openssh-5.8p1-packet.patch
 
@@ -107,6 +104,8 @@ 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
+# Do not write to one socket from more processes (#1310684)
+Patch202: openssh-6.6p1-audit-race-condition.patch
 
 # --- pam_ssh-agent ---
 # make it build reusing the openssh sources
@@ -117,6 +116,9 @@ Patch301: pam_ssh_agent_auth-0.9.2-seteuid.patch
 Patch302: pam_ssh_agent_auth-0.9.2-visibility.patch
 # don't use xfree (#1024965)
 Patch303: pam_ssh_agent_auth-0.9.3-no-xfree.patch
+# don't use xfree (#1024965)
+Patch304: pam_ssh_agent_auth-0.9.3-command.patch
+
 #https://bugzilla.mindrot.org/show_bug.cgi?id=1641 (WONTFIX)
 Patch400: openssh-6.6p1-role-mls.patch
 #https://bugzilla.redhat.com/show_bug.cgi?id=781634
@@ -129,8 +131,6 @@ Patch502: openssh-6.6p1-keycat.patch
 
 #http6://bugzilla.mindrot.org/show_bug.cgi?id=1644
 Patch601: openssh-6.6p1-allow-ip-opts.patch
-#http://cvsweb.netbsd.org/cgi-bin/cvsweb.cgi/src/crypto/dist/ssh/Attic/sftp-glob.c.diff?r1=1.13&r2=1.13.12.1&f=h
-Patch603: openssh-5.8p1-glob.patch
 #https://bugzilla.mindrot.org/show_bug.cgi?id=1893
 Patch604: openssh-6.6p1-keyperm.patch
 #https://bugzilla.mindrot.org/show_bug.cgi?id=1925
@@ -153,8 +153,6 @@ Patch703: openssh-4.3p2-askpass-grab-info.patch
 # https://bugzilla.redhat.com/show_bug.cgi?id=205842
 # drop? Patch704: openssh-5.9p1-edns.patch
 #?
-Patch705: openssh-5.1p1-scp-manpage.patch
-#?
 Patch706: openssh-6.6.1p1-localdomain.patch
 #https://bugzilla.mindrot.org/show_bug.cgi?id=1635 (WONTFIX)
 Patch707: openssh-6.6p1-redhat.patch
@@ -178,6 +176,8 @@ Patch801: openssh-6.6p1-force_krb.patch
 # add new option GSSAPIEnablek5users and disable using ~/.k5users by default (#1169843)
 # CVE-2014-9278
 Patch802: openssh-6.6p1-GSSAPIEnablek5users.patch
+# Respect k5login_directory option in krk5.conf (#1328243)
+Patch803: openssh-6.6p1-k5login_directory.patch
 Patch900: openssh-6.1p1-gssapi-canohost.patch
 #https://bugzilla.mindrot.org/show_bug.cgi?id=1780
 Patch901: openssh-6.6p1-kuserok.patch
@@ -250,6 +250,24 @@ Patch930: openssh-6.6p1-disable-roaming.patch
 Patch931: openssh-6.6p1-CVE-2016-3115.patch
 # CVE-2016-1908: possible fallback from untrusted X11 forwarding (#1298741)
 Patch932: openssh-6.6p1-fallback-X11-untrusted.patch
+# CVE-2015-8325: privilege escalation via user's PAM environment and UseLogin=yes (#1328012)
+Patch933: openssh-6.6p1-CVE-2015-8325.patch
+# close ControlPersist background process stderr when not in debug mode (#1335540)
+Patch934: openssh-6.6p1-ControlPersist-stderr.patch
+# make s390 use /dev/ crypto devices -- ignore closefrom (#1318760)
+Patch935: openssh-6.6p1-s390-closefrom.patch
+# Default value and proper dump of  AuthenticationMethods (#1237129)
+Patch936: openssh-6.6p1-AuthenticationMethods.patch
+# ssh-copy-id does not work with LogLevel=quiet (#1349556)
+Patch937: openssh-6.6p1-ssh-copy-id-quiet.patch
+# expose more information to PAM (#1312304)
+Patch938: openssh-6.6p1-expose-auth-information.patch
+# Move MAX_DISPLAYS to a configuration option (#1341302)
+Patch939: openssh-6.6p1-x11-max-displays.patch
+# Add a wildcard option to PermitOpen directive (#1344106)
+Patch940: openssh-6.6p1-permitopen-any-host.patch
+# Rework capabilities handling for SELinux confined users (#1357859)
+Patch941: openssh-6.6p1-chroot-capabilities.patch
 
 
 License: BSD
@@ -287,10 +305,12 @@ BuildRequires: libedit-devel ncurses-devel
 %endif
 
 %if %{WITH_SELINUX}
+Conflicts: selinux-policy < 3.13.1-92
 Requires: libselinux >= 1.27.7
 BuildRequires: libselinux-devel >= 1.27.7
 Requires: audit-libs >= 1.0.8
 BuildRequires: audit-libs >= 1.0.8
+BuildRequires: libcap-ng-devel
 %endif
 
 BuildRequires: xauth
@@ -407,7 +427,6 @@ The module is most useful for su and sudo service stacks.
 %endif
 
 %patch101 -p1 -b .fingerprint
-# investigate %patch102 -p1 -b .getaddrinfo
 %patch103 -p1 -b .packet
 
 %if %{pam_ssh_agent}
@@ -416,6 +435,7 @@ pushd pam_ssh_agent_auth-%{pam_ssh_agent_ver}
 %patch301 -p1 -b .psaa-seteuid
 %patch302 -p1 -b .psaa-visibility
 %patch303 -p1 -b .psaa-xfree
+%patch304 -p2 -b .psaa-command
 # Remove duplicate headers
 rm -f $(cat %{SOURCE5})
 popd
@@ -432,7 +452,6 @@ popd
 %patch502 -p1 -b .keycat
 
 %patch601 -p1 -b .ip-opts
-%patch603 -p1 -b .glob
 %patch604 -p1 -b .keyperm
 %patch606 -p1 -b .ipv6man
 %patch607 -p1 -b .sigpipe
@@ -444,7 +463,6 @@ popd
 %patch703 -p1 -b .grab-info
 # investigate - https://bugzilla.redhat.com/show_bug.cgi?id=205842
 # probably not needed anymore %patch704 -p1 -b .edns
-# drop it %patch705 -p1 -b .manpage
 %patch706 -p1 -b .localdomain
 %patch707 -p1 -b .redhat
 %patch708 -p1 -b .entropy
@@ -474,6 +492,7 @@ popd
 %patch918 -p1 -b .log-in-chroot
 %patch919 -p1 -b .mls-labels
 %patch802 -p1 -b .GSSAPIEnablek5users
+%patch803 -p1 -b .k5login
 %patch920 -p1 -b .sshd-t
 %patch921 -p1 -b .sftp-force-mode
 %patch922 -p1 -b .term
@@ -487,9 +506,19 @@ popd
 %patch930 -p1 -b .roaming
 %patch931 -p1 -b .xauth
 %patch932 -p1 -b .untrusted
+%patch933 -p1 -b .uselogin
+%patch934 -p1 -b .stderr
+%patch935 -p1 -b .s390
+%patch936 -p1 -b .auth_meth
+%patch937 -p1 -b .quiet
+%patch938 -p1 -b .expose-auth
+%patch939 -p1 -b .x11max
+%patch940 -p1 -b .permitopen
+%patch941 -p1 -b .chroot-cap
 
 %patch200 -p1 -b .audit
 %patch201 -p1 -b .audit-fps
+%patch202 -p1 -b .audit-race
 %patch700 -p1 -b .fips
 
 %patch100 -p1 -b .coverity
@@ -697,18 +726,6 @@ getent passwd sshd >/dev/null || \
 %postun server
 %systemd_postun_with_restart sshd.service
 
-%triggerun -n openssh-server -- openssh-server < 5.8p2-12
-/usr/bin/systemd-sysv-convert --save sshd >/dev/null 2>&1 || :
-/bin/systemctl enable sshd.service >/dev/null 2>&1
-/sbin/chkconfig --del sshd >/dev/null 2>&1 || :
-/bin/systemctl try-restart sshd.service >/dev/null 2>&1 || :
-
-%triggerun -n openssh-server -- openssh-server < 5.9p1-22
-/bin/systemctl --no-reload disable sshd-keygen.service >/dev/null 2>&1 || :
-
-%triggerpostun -n openssh-server-sysvinit -- openssh-server < 5.8p2-12
-/sbin/chkconfig --add sshd >/dev/null 2>&1 || :
-
 %files
 %defattr(-,root,root)
 %{!?_licensedir:%global license %%doc}
@@ -811,11 +828,44 @@ getent passwd sshd >/dev/null || \
 %endif
 
 %changelog
+* Tue Sep 06 2016 Jakub Jelen <jjelen@redhat.com> - 6.6.1p1-31 + 0.9.3-9
+- Do not depend on selinux-policy (#1373297)
+
+* Fri Jul 29 2016 Jakub Jelen <jjelen@redhat.com> - 6.6.1p1-30 + 0.9.3-9
+- Drop dependency on libcap-ng for ssh-keycat (#1357859)
+
+* Thu Jul 28 2016 Jakub Jelen <jjelen@redhat.com> - 6.6.1p1-29 + 0.9.3-9
+- Rework SELinux context handling with chroot using libcap-ng (#1357859)
+
+* Fri Jul 01 2016 Jakub Jelen <jjelen@redhat.com> - 6.6.1p1-28 + 0.9.3-9
+- SFTP force permission collision with umask (#1344614)
+- Make closefrom() ignore FD's to /dev/ devices on s390 (#1318760)
+- Create a default value for AuthenticationMethods any (#1237129)
+- Fix ssh-copy-id with LogLevel=quiet (#1349556)
+- Expose more information to PAM (#1312304)
+- Move MAX_DISPLAYS to a configuration option (#1341302)
+- Add a wildcard option to PermitOpen directive (host) (#1344106)
+
+* Tue May 31 2016 Jakub Jelen <jjelen@redhat.com> - 6.6.1p1-27 + 0.9.3-9
+- Coverity and RPMDiff build issues (#1334326)
+- CVE-2015-8325: privilege escalation via user's PAM environment and UseLogin=yes (#1329191)
+- Check for real location of .k5login file (#1328243)
+- close ControlPersist background process stderr (#1335540)
+
+* Fri Apr 01 2016 Jakub Jelen <jjelen@redhat.com> 6.6.1p1-26 + 0.9.3-9
+- Drop glob patch for sftp client preventing listing many files (#1310303)
+- Fix race condition between audit messages from different processes (#1310684)
+- Make systemd service forking to properly report state (#1291172)
+- Get rid of rpm triggers for openssh-5.x (#1312013)
+- Generate the host keys when the key files are empty (#1266043)
+- pam_ssh_agent_auth: authorized_keys_command option (#1317858)
+- Don't use MD5 digest from pam_ssh_agent_auth in FIPS mode (#1317952)
+
 * Wed Mar 16 2016 Jakub Jelen <jjelen@redhat.com> 6.6.1p1-25 + 0.9.3-9
 - CVE-2016-1908: possible fallback from untrusted to trusted X11 forwarding (#1298741)
 
 * Tue Mar 15 2016 Jakub Jelen <jjelen@redhat.com> 6.6.1p1-24 + 0.9.3-9
-- CVE-2016-3115: missing sanitisation of input for X11 forwarding (#1317818)
+- CVE-2016-3115: missing sanitisation of input for X11 forwarding (#1317819)
 
 * Wed Jan 13 2016 Jakub Jelen <jjelen@redhat.com> 6.6.1p1-23 + 0.9.3-9
 - Disable undocumented feauture Roaming for good (#1298218)