rpms/openssh/F-12 openssh-5.3p1-audit.patch, NONE, 1.1 openssh-5.3p1-fips.patch, NONE, 1.1 openssh-5.3p1-gsskex.patch, NONE, 1.1 openssh-5.3p1-mls.patch, NONE, 1.1 openssh-5.3p1-nss-keys.patch, NONE, 1.1 openssh-5.3p1-pka.patch, NONE, 1.1 openssh-5.3p1-selabel.patch, NONE, 1.1 openssh-5.3p1-skip-initial.patch, NONE, 1.1 pam_ssh_agent-rmheaders, NONE, 1.1 pam_ssh_agent_auth-0.9-build.patch, NONE, 1.1 openssh.spec, 1.172, 1.173 sources, 1.24, 1.25 openssh-3.8.1p1-krb5-config.patch, 1.1, NONE openssh-4.7p1-audit.patch, 1.2, NONE openssh-5.1p1-mls.patch, 1.1, NONE openssh-5.1p1-skip-initial.patch, 1.1, NONE openssh-5.2p1-fips.patch, 1.6, NONE openssh-5.2p1-nss-keys.patch, 1.3, NONE openssh-5.2p1-pathmax.patch, 1.2, NONE openssh-5.2p1-selabel.patch, 1.2, NONE

Jan F. Chadima jfch2222 at fedoraproject.org
Fri Nov 20 17:01:49 UTC 2009


Author: jfch2222

Update of /cvs/pkgs/rpms/openssh/F-12
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv11248

Modified Files:
	openssh.spec sources 
Added Files:
	openssh-5.3p1-audit.patch openssh-5.3p1-fips.patch 
	openssh-5.3p1-gsskex.patch openssh-5.3p1-mls.patch 
	openssh-5.3p1-nss-keys.patch openssh-5.3p1-pka.patch 
	openssh-5.3p1-selabel.patch openssh-5.3p1-skip-initial.patch 
	pam_ssh_agent-rmheaders pam_ssh_agent_auth-0.9-build.patch 
Removed Files:
	openssh-3.8.1p1-krb5-config.patch openssh-4.7p1-audit.patch 
	openssh-5.1p1-mls.patch openssh-5.1p1-skip-initial.patch 
	openssh-5.2p1-fips.patch openssh-5.2p1-nss-keys.patch 
	openssh-5.2p1-pathmax.patch openssh-5.2p1-selabel.patch 
Log Message:
bump version to 5.3p1


openssh-5.3p1-audit.patch:
 auth.c       |   10 ++++++
 config.h.in  |   13 ++++++++
 configure.ac |   13 ++++++++
 loginrec.c   |   92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 loginrec.h   |    4 ++
 5 files changed, 132 insertions(+)

--- NEW FILE openssh-5.3p1-audit.patch ---
diff -up openssh-5.3p1/auth.c.audit openssh-5.3p1/auth.c
--- openssh-5.3p1/auth.c.audit	2008-11-05 06:12:54.000000000 +0100
+++ openssh-5.3p1/auth.c	2009-10-11 13:02:47.000000000 +0200
@@ -287,6 +287,12 @@ auth_log(Authctxt *authctxt, int authent
 		    get_canonical_hostname(options.use_dns), "ssh", &loginmsg);
 # endif
 #endif
+#if HAVE_LINUX_AUDIT
+	if (authenticated == 0 && !authctxt->postponed) {
+		linux_audit_record_event(-1, authctxt->user, NULL,
+			get_remote_ipaddr(), "sshd", 0);
+	}
+#endif
 #ifdef SSH_AUDIT_EVENTS
 	if (authenticated == 0 && !authctxt->postponed)
 		audit_event(audit_classify_auth(method));
@@ -533,6 +539,10 @@ getpwnamallow(const char *user)
 		record_failed_login(user,
 		    get_canonical_hostname(options.use_dns), "ssh");
 #endif
+#ifdef HAVE_LINUX_AUDIT
+		linux_audit_record_event(-1, user, NULL, get_remote_ipaddr(),
+			"sshd", 0);
+#endif
 #ifdef SSH_AUDIT_EVENTS
 		audit_event(SSH_INVALID_USER);
 #endif /* SSH_AUDIT_EVENTS */
diff -up openssh-5.3p1/config.h.in.audit openssh-5.3p1/config.h.in
--- openssh-5.3p1/config.h.in.audit	2009-09-26 08:31:14.000000000 +0200
+++ openssh-5.3p1/config.h.in	2009-10-11 13:09:41.000000000 +0200
@@ -533,6 +533,9 @@
 /* Define to 1 if you have the <lastlog.h> header file. */
 #undef HAVE_LASTLOG_H
 
+/* Define to 1 if you have the <libaudit.h> header file. */
+#undef HAVE_LIBAUDIT_H
+
 /* Define to 1 if you have the `bsm' library (-lbsm). */
 #undef HAVE_LIBBSM
 
@@ -572,6 +575,9 @@
 /* Define to 1 if you have the <limits.h> header file. */
 #undef HAVE_LIMITS_H
 
+/* Define if you want Linux audit support. */
+#undef HAVE_LINUX_AUDIT
+
 /* Define to 1 if you have the <linux/if_tun.h> header file. */
 #undef HAVE_LINUX_IF_TUN_H
 
@@ -768,6 +774,9 @@
 /* Define to 1 if you have the `setgroups' function. */
 #undef HAVE_SETGROUPS
 
+/* Define to 1 if you have the `setkeycreatecon' function. */
+#undef HAVE_SETKEYCREATECON
+
 /* Define to 1 if you have the `setlogin' function. */
 #undef HAVE_SETLOGIN
 
@@ -1348,6 +1357,10 @@
 /* Prepend the address family to IP tunnel traffic */
 #undef SSH_TUN_PREPEND_AF
 
+/* Define to your vendor patch level, if it has been modified from the
+   upstream source release. */
+#undef SSH_VENDOR_PATCHLEVEL
+
 /* Define to 1 if you have the ANSI C header files. */
 #undef STDC_HEADERS
 
diff -up openssh-5.3p1/configure.ac.audit openssh-5.3p1/configure.ac
--- openssh-5.3p1/configure.ac.audit	2009-09-11 06:56:08.000000000 +0200
+++ openssh-5.3p1/configure.ac	2009-10-11 13:08:03.000000000 +0200
@@ -3407,6 +3407,18 @@ AC_ARG_WITH(selinux,
 	fi ]
 )
 
+# Check whether user wants Linux audit support
+LINUX_AUDIT_MSG="no"
+AC_ARG_WITH(linux-audit,
+	[  --with-linux-audit   Enable Linux audit support],
+	[ if test "x$withval" != "xno" ; then
+		AC_DEFINE(HAVE_LINUX_AUDIT,1,[Define if you want Linux audit support.])
+		LINUX_AUDIT_MSG="yes"
+		AC_CHECK_HEADERS(libaudit.h)
+		SSHDLIBS="$SSHDLIBS -laudit"
+	fi ]
+)
+
 # Check whether user wants Kerberos 5 support
 KRB5_MSG="no"
 AC_ARG_WITH(kerberos5,
@@ -4226,6 +4238,7 @@ echo "                       PAM support
 echo "                   OSF SIA support: $SIA_MSG"
 echo "                 KerberosV support: $KRB5_MSG"
 echo "                   SELinux support: $SELINUX_MSG"
+echo "               Linux audit support: $LINUX_AUDIT_MSG"
 echo "                 Smartcard support: $SCARD_MSG"
 echo "                     S/KEY support: $SKEY_MSG"
 echo "              TCP Wrappers support: $TCPW_MSG"
diff -up openssh-5.3p1/loginrec.c.audit openssh-5.3p1/loginrec.c
--- openssh-5.3p1/loginrec.c.audit	2009-02-12 03:12:22.000000000 +0100
+++ openssh-5.3p1/loginrec.c	2009-10-11 13:06:16.000000000 +0200
@@ -176,6 +176,10 @@
 #include "auth.h"
 #include "buffer.h"
 
+#ifdef HAVE_LINUX_AUDIT
+# include <libaudit.h>
+#endif
+
 #ifdef HAVE_UTIL_H
 # include <util.h>
 #endif
@@ -202,6 +206,9 @@ int utmp_write_entry(struct logininfo *l
 int utmpx_write_entry(struct logininfo *li);
 int wtmp_write_entry(struct logininfo *li);
 int wtmpx_write_entry(struct logininfo *li);
+#ifdef HAVE_LINUX_AUDIT
+int linux_audit_write_entry(struct logininfo *li);
+#endif
 int lastlog_write_entry(struct logininfo *li);
 int syslogin_write_entry(struct logininfo *li);
 
@@ -440,6 +447,10 @@ login_write(struct logininfo *li)
 
 	/* set the timestamp */
 	login_set_current_time(li);
+#ifdef HAVE_LINUX_AUDIT
+	if (linux_audit_write_entry(li) == 0)
+		fatal("linux_audit_write_entry failed: %s", strerror(errno));
+#endif
 #ifdef USE_LOGIN
 	syslogin_write_entry(li);
 #endif
@@ -1394,6 +1405,87 @@ wtmpx_get_entry(struct logininfo *li)
 }
 #endif /* USE_WTMPX */
 
+#ifdef HAVE_LINUX_AUDIT
+static void
+_audit_hexscape(const char *what, char *where, unsigned int size)
+{
+	const char *ptr = what;
+	const char *hex = "0123456789ABCDEF";
+
+	while (*ptr) {
+		if (*ptr == '"' || *ptr < 0x21 || *ptr > 0x7E) {
+			unsigned int i;
+			ptr = what;
+			for (i = 0; *ptr && i+2 < size; i += 2) {
+				where[i] = hex[((unsigned)*ptr & 0xF0)>>4]; /* Upper nibble */
+				where[i+1] = hex[(unsigned)*ptr & 0x0F];   /* Lower nibble */
+				ptr++;
+			}
+			where[i] = '\0';
+			return;
+		}
+		ptr++;
+	}
+	where[0] = '"';
+	if ((unsigned)(ptr - what) < size - 3)
+	{
+		size = ptr - what + 3;
+	}
+	strncpy(where + 1, what, size - 3);
+	where[size-2] = '"';
+	where[size-1] = '\0';
+}
+
+#define AUDIT_LOG_SIZE 128
+#define AUDIT_ACCT_SIZE (AUDIT_LOG_SIZE - 8)
+
+int
+linux_audit_record_event(int uid, const char *username,
+	const char *hostname, const char *ip, const char *ttyn, int success)
+{
+	char buf[AUDIT_LOG_SIZE];
+	int audit_fd, rc;
+
+	audit_fd = audit_open();
+	if (audit_fd < 0) {
+	 	if (errno == EINVAL || errno == EPROTONOSUPPORT ||
+					errno == EAFNOSUPPORT)
+			return 1; /* No audit support in kernel */
+		else
+			return 0; /* Must prevent login */
+	}
+	if (username == NULL)
+		snprintf(buf, sizeof(buf), "uid=%d", uid);
+	else {
+		char encoded[AUDIT_ACCT_SIZE];
+		_audit_hexscape(username, encoded, sizeof(encoded));
+		snprintf(buf, sizeof(buf), "acct=%s", encoded);
+	}
+	rc = audit_log_user_message(audit_fd, AUDIT_USER_LOGIN,
+		buf, hostname, ip, ttyn, success);
+	close(audit_fd);
+	if (rc >= 0)
+		return 1;
+	else
+		return 0;
+}
+
+int
+linux_audit_write_entry(struct logininfo *li)
+{
+	switch(li->type) {
+	case LTYPE_LOGIN:
+		return (linux_audit_record_event(li->uid, NULL, li->hostname,
+			NULL, li->line, 1));
+	case LTYPE_LOGOUT:
+		return (1);	/* We only care about logins */
+	default:
+		logit("%s: invalid type field", __func__);
+		return (0);
+	}
+}
+#endif /* HAVE_LINUX_AUDIT */
+
 /**
  ** Low-level libutil login() functions
  **/
diff -up openssh-5.3p1/loginrec.h.audit openssh-5.3p1/loginrec.h
--- openssh-5.3p1/loginrec.h.audit	2006-08-05 04:39:40.000000000 +0200
+++ openssh-5.3p1/loginrec.h	2009-10-11 13:04:28.000000000 +0200
@@ -127,5 +127,9 @@ char *line_stripname(char *dst, const ch
 char *line_abbrevname(char *dst, const char *src, int dstsize);
 
 void record_failed_login(const char *, const char *, const char *);
+#ifdef HAVE_LINUX_AUDIT
+int linux_audit_record_event(int uid, const char *username,
+	const char *hostname, const char *ip, const char *ttyn, int success);
+#endif /* HAVE_LINUX_AUDIT */
 
 #endif /* _HAVE_LOGINREC_H_ */

openssh-5.3p1-fips.patch:
 Makefile.in                     |   14 +++++++-------
 auth2-pubkey.c                  |    3 ++-
 authfile.c                      |   20 ++++++++++++++++----
 cipher-ctr.c                    |    3 ++-
 cipher.c                        |   29 ++++++++++++++++++++++++-----
 cipher.h                        |    2 +-
 mac.c                           |   12 ++++++++++--
 myproposal.h                    |    7 ++++++-
 nsskeys.c                       |    4 ++--
 openbsd-compat/bsd-arc4random.c |   27 +++++++++++++++++++++++++++
 ssh-add.c                       |    3 ++-
 ssh-agent.c                     |    7 ++++---
 ssh-keygen.c                    |   12 +++++++-----
 ssh.c                           |   20 +++++++++++++++++++-
 sshconnect.c                    |   27 ++++++++++++++++-----------
 sshconnect2.c                   |   14 ++++++++++++--
 sshd.c                          |   24 ++++++++++++++++++++++--
 17 files changed, 179 insertions(+), 49 deletions(-)

--- NEW FILE openssh-5.3p1-fips.patch ---
diff -up openssh-5.3p1/auth2-pubkey.c.fips openssh-5.3p1/auth2-pubkey.c
--- openssh-5.3p1/auth2-pubkey.c.fips	2009-10-02 14:12:00.000000000 +0200
+++ openssh-5.3p1/auth2-pubkey.c	2009-10-02 14:12:00.000000000 +0200
@@ -33,6 +33,7 @@
 #include <stdio.h>
 #include <stdarg.h>
 #include <unistd.h>
+#include <openssl/fips.h>
 
 #include "xmalloc.h"
 #include "ssh.h"
@@ -240,7 +241,7 @@ user_key_allowed2(struct passwd *pw, Key
 			found_key = 1;
 			debug("matching key found: file %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);
 			verbose("Found matching %s key: %s",
 			    key_type(found), fp);
 			xfree(fp);
diff -up openssh-5.3p1/authfile.c.fips openssh-5.3p1/authfile.c
--- openssh-5.3p1/authfile.c.fips	2006-09-01 07:38:36.000000000 +0200
+++ openssh-5.3p1/authfile.c	2009-10-02 14:12:00.000000000 +0200
@@ -143,8 +143,14 @@ key_save_private_rsa1(Key *key, const ch
 	/* Allocate space for the private part of the key in the buffer. */
 	cp = buffer_append_space(&encrypted, buffer_len(&buffer));
 
-	cipher_set_key_string(&ciphercontext, cipher, passphrase,
-	    CIPHER_ENCRYPT);
+	if (cipher_set_key_string(&ciphercontext, cipher, passphrase,
+	    CIPHER_ENCRYPT) < 0) {
+	    error("cipher_set_key_string failed.");
+	    buffer_free(&encrypted);
+	    buffer_free(&buffer);
+	    return 0;
+	}
+
 	cipher_crypt(&ciphercontext, cp,
 	    buffer_ptr(&buffer), buffer_len(&buffer));
 	cipher_cleanup(&ciphercontext);
@@ -414,8 +420,14 @@ key_load_private_rsa1(int fd, const char
 	cp = buffer_append_space(&decrypted, buffer_len(&buffer));
 
 	/* Rest of the buffer is encrypted.  Decrypt it using the passphrase. */
-	cipher_set_key_string(&ciphercontext, cipher, passphrase,
-	    CIPHER_DECRYPT);
+	if (cipher_set_key_string(&ciphercontext, cipher, passphrase,
+	    CIPHER_DECRYPT) < 0) {
+	    error("cipher_set_key_string failed.");
+	    buffer_free(&decrypted);
+	    buffer_free(&buffer);
+	    goto fail;
+	}
+
 	cipher_crypt(&ciphercontext, cp,
 	    buffer_ptr(&buffer), buffer_len(&buffer));
 	cipher_cleanup(&ciphercontext);
diff -up openssh-5.3p1/cipher.c.fips openssh-5.3p1/cipher.c
--- openssh-5.3p1/cipher.c.fips	2009-10-02 13:44:03.000000000 +0200
+++ openssh-5.3p1/cipher.c	2009-10-02 14:12:00.000000000 +0200
@@ -40,6 +40,7 @@
 #include <sys/types.h>
 
 #include <openssl/md5.h>
+#include <openssl/fips.h>
 
 #include <string.h>
 #include <stdarg.h>
@@ -93,6 +94,22 @@ struct Cipher {
 	{ NULL,			SSH_CIPHER_INVALID, 0, 0, 0, 0, NULL }
 };
 
+struct Cipher fips_ciphers[] = {
+	{ "none",		SSH_CIPHER_NONE, 8, 0, 0, 0, EVP_enc_null },
+	{ "3des",		SSH_CIPHER_3DES, 8, 16, 0, 1, evp_ssh1_3des },
+
+	{ "3des-cbc",		SSH_CIPHER_SSH2, 8, 24, 0, 1, EVP_des_ede3_cbc },
+	{ "aes128-cbc",		SSH_CIPHER_SSH2, 16, 16, 0, 1, EVP_aes_128_cbc },
+	{ "aes192-cbc",		SSH_CIPHER_SSH2, 16, 24, 0, 1, EVP_aes_192_cbc },
+	{ "aes256-cbc",		SSH_CIPHER_SSH2, 16, 32, 0, 1, EVP_aes_256_cbc },
+	{ "rijndael-cbc at lysator.liu.se",
+				SSH_CIPHER_SSH2, 16, 32, 0, 1, EVP_aes_256_cbc },
+	{ "aes128-ctr",		SSH_CIPHER_SSH2, 16, 16, 0, 0, evp_aes_128_ctr },
+	{ "aes192-ctr",		SSH_CIPHER_SSH2, 16, 24, 0, 0, evp_aes_128_ctr },
+	{ "aes256-ctr",		SSH_CIPHER_SSH2, 16, 32, 0, 0, evp_aes_128_ctr },
+	{ NULL,			SSH_CIPHER_INVALID, 0, 0, 0, 0, NULL }
+};
+
 /*--*/
 
 u_int
@@ -135,7 +152,7 @@ Cipher *
 cipher_by_name(const char *name)
 {
 	Cipher *c;
-	for (c = ciphers; c->name != NULL; c++)
+	for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++)
 		if (strcmp(c->name, name) == 0)
 			return c;
 	return NULL;
@@ -145,7 +162,7 @@ Cipher *
 cipher_by_number(int id)
 {
 	Cipher *c;
-	for (c = ciphers; c->name != NULL; c++)
+	for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++)
 		if (c->number == id)
 			return c;
 	return NULL;
@@ -189,7 +206,7 @@ cipher_number(const char *name)
 	Cipher *c;
 	if (name == NULL)
 		return -1;
-	for (c = ciphers; c->name != NULL; c++)
+	for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++)
 		if (strcasecmp(c->name, name) == 0)
 			return c->number;
 	return -1;
@@ -296,14 +313,15 @@ cipher_cleanup(CipherContext *cc)
  * passphrase and using the resulting 16 bytes as the key.
  */
 
-void
+int
 cipher_set_key_string(CipherContext *cc, Cipher *cipher,
     const char *passphrase, int do_encrypt)
 {
 	MD5_CTX md;
 	u_char digest[16];
 
-	MD5_Init(&md);
+	if (MD5_Init(&md) <= 0)
+		return -1;
 	MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase));
 	MD5_Final(digest, &md);
 
@@ -311,6 +329,7 @@ cipher_set_key_string(CipherContext *cc,
 
 	memset(digest, 0, sizeof(digest));
 	memset(&md, 0, sizeof(md));
+	return 0;
 }
 
 /*
diff -up openssh-5.3p1/cipher-ctr.c.fips openssh-5.3p1/cipher-ctr.c
--- openssh-5.3p1/cipher-ctr.c.fips	2007-06-14 15:21:33.000000000 +0200
+++ openssh-5.3p1/cipher-ctr.c	2009-10-02 14:12:00.000000000 +0200
@@ -140,7 +140,8 @@ evp_aes_128_ctr(void)
 	aes_ctr.do_cipher = ssh_aes_ctr;
 #ifndef SSH_OLD_EVP
 	aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
-	    EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV;
+	    EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV |
+	    EVP_CIPH_FLAG_FIPS;
 #endif
 	return (&aes_ctr);
 }
diff -up openssh-5.3p1/cipher.h.fips openssh-5.3p1/cipher.h
--- openssh-5.3p1/cipher.h.fips	2009-01-28 06:38:41.000000000 +0100
+++ openssh-5.3p1/cipher.h	2009-10-02 14:12:00.000000000 +0200
@@ -78,7 +78,7 @@ void	 cipher_init(CipherContext *, Ciphe
     const u_char *, u_int, int);
 void	 cipher_crypt(CipherContext *, u_char *, const u_char *, u_int);
 void	 cipher_cleanup(CipherContext *);
-void	 cipher_set_key_string(CipherContext *, Cipher *, const char *, int);
+int	 cipher_set_key_string(CipherContext *, Cipher *, const char *, int);
 u_int	 cipher_blocksize(const Cipher *);
 u_int	 cipher_keylen(const Cipher *);
 u_int	 cipher_is_cbc(const Cipher *);
diff -up openssh-5.3p1/mac.c.fips openssh-5.3p1/mac.c
--- openssh-5.3p1/mac.c.fips	2008-06-13 02:58:50.000000000 +0200
+++ openssh-5.3p1/mac.c	2009-10-02 14:12:00.000000000 +0200
@@ -28,6 +28,7 @@
 #include <sys/types.h>
 
 #include <openssl/hmac.h>
+#include <openssl/fips.h>
 
 #include <stdarg.h>
 #include <string.h>
@@ -47,14 +48,14 @@
 #define SSH_EVP		1	/* OpenSSL EVP-based MAC */
 #define SSH_UMAC	2	/* UMAC (not integrated with OpenSSL) */
 
-struct {
+struct Macs {
 	char		*name;
 	int		type;
 	const EVP_MD *	(*mdfunc)(void);
 	int		truncatebits;	/* truncate digest if != 0 */
 	int		key_len;	/* just for UMAC */
 	int		len;		/* just for UMAC */
-} macs[] = {
+} all_macs[] = {
 	{ "hmac-sha1",			SSH_EVP, EVP_sha1, 0, -1, -1 },
 	{ "hmac-sha1-96",		SSH_EVP, EVP_sha1, 96, -1, -1 },
 	{ "hmac-md5",			SSH_EVP, EVP_md5, 0, -1, -1 },
@@ -65,9 +66,15 @@ struct {
 	{ NULL,				0, NULL, 0, -1, -1 }
 };
 
+struct Macs fips_macs[] = {
+	{ "hmac-sha1",			SSH_EVP, EVP_sha1, 0, -1, -1 },
+	{ NULL,				0, NULL, 0, -1, -1 }
+};
+
 static void
 mac_setup_by_id(Mac *mac, int which)
 {
+	struct Macs *macs = FIPS_mode() ? fips_macs : all_macs;
 	int evp_len;
 	mac->type = macs[which].type;
 	if (mac->type == SSH_EVP) {
@@ -88,6 +95,7 @@ int
 mac_setup(Mac *mac, char *name)
 {
 	int i;
+	struct Macs *macs = FIPS_mode() ? fips_macs : all_macs;
 
 	for (i = 0; macs[i].name; i++) {
 		if (strcmp(name, macs[i].name) == 0) {
diff -up openssh-5.3p1/Makefile.in.fips openssh-5.3p1/Makefile.in
--- openssh-5.3p1/Makefile.in.fips	2009-10-02 14:12:00.000000000 +0200
+++ openssh-5.3p1/Makefile.in	2009-10-02 14:20:18.000000000 +0200
@@ -136,28 +136,28 @@ libssh.a: $(LIBSSH_OBJS)
 	$(RANLIB) $@
 
 ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS)
-	$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+	$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
 
 sshd$(EXEEXT): libssh.a	$(LIBCOMPAT) $(SSHDOBJS)
-	$(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS)
+	$(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHDLIBS) $(LIBS)
 
 scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o
 	$(LD) -o $@ scp.o progressmeter.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
 
 ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o
-	$(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+	$(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
 
 ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o
-	$(LD) -o $@ ssh-agent.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+	$(LD) -o $@ ssh-agent.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
 
 ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o
-	$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+	$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
 
 ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o
-	$(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+	$(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
 
 ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o
-	$(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
+	$(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS)
 
 sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o
 	$(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
diff -up openssh-5.3p1/myproposal.h.fips openssh-5.3p1/myproposal.h
--- openssh-5.3p1/myproposal.h.fips	2009-01-28 06:33:31.000000000 +0100
+++ openssh-5.3p1/myproposal.h	2009-10-02 14:12:00.000000000 +0200
@@ -53,7 +53,12 @@
 	"hmac-sha1-96,hmac-md5-96"
 #define	KEX_DEFAULT_COMP	"none,zlib at openssh.com,zlib"
 #define	KEX_DEFAULT_LANG	""
-
+#define	KEX_FIPS_ENCRYPT \
+	"aes128-ctr,aes192-ctr,aes256-ctr," \
+	"aes128-cbc,3des-cbc," \
+	"aes192-cbc,aes256-cbc,rijndael-cbc at lysator.liu.se"
+#define	KEX_FIPS_MAC \
+	"hmac-sha1"
 
 static char *myproposal[PROPOSAL_MAX] = {
 	KEX_DEFAULT_KEX,
diff -up openssh-5.3p1/nsskeys.c.fips openssh-5.3p1/nsskeys.c
--- openssh-5.3p1/nsskeys.c.fips	2009-10-02 14:12:00.000000000 +0200
+++ openssh-5.3p1/nsskeys.c	2009-10-02 14:12:00.000000000 +0200
@@ -183,8 +183,8 @@ nss_convert_pubkey(Key *k)
 			break;
 	}
 
-	p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
-	debug("fingerprint %u %s", key_size(k), p);
+	p = key_fingerprint(k, SSH_FP_SHA1, SSH_FP_HEX);
+	debug("SHA1 fingerprint %u %s", key_size(k), p);
 	xfree(p);
 
 	return 0;
diff -up openssh-5.3p1/openbsd-compat/bsd-arc4random.c.fips openssh-5.3p1/openbsd-compat/bsd-arc4random.c
--- openssh-5.3p1/openbsd-compat/bsd-arc4random.c.fips	2008-06-04 02:54:00.000000000 +0200
+++ openssh-5.3p1/openbsd-compat/bsd-arc4random.c	2009-10-02 14:12:00.000000000 +0200
@@ -39,6 +39,7 @@
 static int rc4_ready = 0;
 static RC4_KEY rc4;
 
+#if 0
 unsigned int
 arc4random(void)
 {
@@ -82,6 +83,32 @@ arc4random_stir(void)
 
 	rc4_ready = REKEY_BYTES;
 }
+#else
+unsigned int
+arc4random(void)
+{
+	unsigned int r = 0;
+	void *rp = &r;
+
+	if (!rc4_ready) {
+		arc4random_stir();
+	}
+	RAND_bytes(rp, sizeof(r));
+
+	return(r);
+}
+
+void
+arc4random_stir(void)
+{
+	unsigned char rand_buf[SEED_SIZE];
+
+	if (RAND_bytes(rand_buf, sizeof(rand_buf)) <= 0)
+		fatal("Couldn't obtain random bytes (error %ld)",
+		    ERR_get_error());
+	rc4_ready = 1;
+}
+#endif
 #endif /* !HAVE_ARC4RANDOM */
 
 #ifndef ARC4RANDOM_BUF
diff -up openssh-5.3p1/ssh-add.c.fips openssh-5.3p1/ssh-add.c
--- openssh-5.3p1/ssh-add.c.fips	2009-10-02 14:12:00.000000000 +0200
+++ openssh-5.3p1/ssh-add.c	2009-10-02 14:12:00.000000000 +0200
@@ -42,6 +42,7 @@
 #include <sys/param.h>
 
 #include <openssl/evp.h>
+#include <openssl/fips.h>
 #include "openbsd-compat/openssl-compat.h"
 
 #ifdef HAVE_LIBNSS
@@ -254,7 +255,7 @@ list_identities(AuthenticationConnection
 		    key = ssh_get_next_identity(ac, &comment, version)) {
 			had_identities = 1;
 			if (do_fp) {
-				fp = key_fingerprint(key, SSH_FP_MD5,
+				fp = key_fingerprint(key, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5,
 				    SSH_FP_HEX);
 				printf("%d %s %s (%s)\n",
 				    key_size(key), fp, comment, key_type(key));
diff -up openssh-5.3p1/ssh-agent.c.fips openssh-5.3p1/ssh-agent.c
--- openssh-5.3p1/ssh-agent.c.fips	2009-10-02 14:12:00.000000000 +0200
+++ openssh-5.3p1/ssh-agent.c	2009-10-02 14:12:00.000000000 +0200
@@ -51,6 +51,7 @@
 
 #include <openssl/evp.h>
 #include <openssl/md5.h>
+#include <openssl/fips.h>
 #include "openbsd-compat/openssl-compat.h"
 
 #include <errno.h>
@@ -200,9 +201,9 @@ confirm_key(Identity *id)
 	char *p;
 	int ret = -1;
 
-	p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
-	if (ask_permission("Allow use of key %s?\nKey fingerprint %s.",
-	    id->comment, p))
+	p = key_fingerprint(id->key, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
+	if (ask_permission("Allow use of key %s?\nKey %sfingerprint %s.",
+	    id->comment, FIPS_mode() ? "SHA1 " : "", p))
 		ret = 0;
 	xfree(p);
 
diff -up openssh-5.3p1/ssh.c.fips openssh-5.3p1/ssh.c
--- openssh-5.3p1/ssh.c.fips	2009-10-02 14:12:00.000000000 +0200
+++ openssh-5.3p1/ssh.c	2009-10-02 14:12:00.000000000 +0200
@@ -72,6 +72,8 @@
 
 #include <openssl/evp.h>
 #include <openssl/err.h>
+#include <openssl/fips.h>
+#include <fipscheck.h>
 #include "openbsd-compat/openssl-compat.h"
 #include "openbsd-compat/sys-queue.h"
 
@@ -221,6 +223,10 @@ main(int ac, char **av)
 	sanitise_stdfd();
 
 	__progname = ssh_get_progname(av[0]);
+        SSLeay_add_all_algorithms();
+        if (FIPS_mode() && !FIPSCHECK_verify(NULL, NULL)) {
+                fatal("FIPS integrity verification test failed.");
+        }
 	init_rng();
 
 	/*
@@ -281,6 +287,9 @@ main(int ac, char **av)
 	    "ACD:F:I:KL:MNO:PR:S:TVw:XYy")) != -1) {
 		switch (opt) {
 		case '1':
+			if (FIPS_mode()) {
+				fatal("Protocol 1 not allowed in the FIPS mode.");
+			}
 			options.protocol = SSH_PROTO_1;
 			break;
 		case '2':
@@ -552,7 +561,6 @@ main(int ac, char **av)
 	if (!host)
 		usage();
 
-	SSLeay_add_all_algorithms();
 	ERR_load_crypto_strings();
 
 	/* Initialize the command to execute on remote host. */
@@ -638,6 +646,10 @@ main(int ac, char **av)
 
 	seed_rng();
 
+	if (FIPS_mode()) {
+		logit("FIPS mode initialized");
+	}
+
 	if (options.user == NULL)
 		options.user = xstrdup(pw->pw_name);
 
@@ -704,6 +716,12 @@ main(int ac, char **av)
 
 	timeout_ms = options.connection_timeout * 1000;
 
+	if (FIPS_mode()) {
+		options.protocol &= SSH_PROTO_2;
+		if (options.protocol == 0)
+			fatal("Protocol 2 disabled by configuration but required in the FIPS mode.");
+	}
+
 	/* Open a connection to the remote host. */
 	if (ssh_connect(host, &hostaddr, options.port,
 	    options.address_family, options.connection_attempts, &timeout_ms,
diff -up openssh-5.3p1/sshconnect2.c.fips openssh-5.3p1/sshconnect2.c
--- openssh-5.3p1/sshconnect2.c.fips	2009-10-02 14:12:00.000000000 +0200
+++ openssh-5.3p1/sshconnect2.c	2009-10-02 14:12:00.000000000 +0200
@@ -44,6 +44,8 @@
 #include <vis.h>
 #endif
 
+#include <openssl/fips.h>
+
 #include "openbsd-compat/sys-queue.h"
 
 #include "xmalloc.h"
@@ -116,6 +118,10 @@ ssh_kex2(char *host, struct sockaddr *ho
 	if (options.ciphers != NULL) {
 		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
 		myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
+	} else if (FIPS_mode()) {
+		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+		myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT;
+
 	}
 	myproposal[PROPOSAL_ENC_ALGS_CTOS] =
 	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
@@ -131,7 +137,11 @@ ssh_kex2(char *host, struct sockaddr *ho
 	if (options.macs != NULL) {
 		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
 		myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
+	} else if (FIPS_mode()) {
+		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
+		myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC;
 	}
+
 	if (options.hostkeyalgorithms != NULL)
 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
 		    options.hostkeyalgorithms;
@@ -508,8 +518,8 @@ input_userauth_pk_ok(int type, u_int32_t
 		    key->type, pktype);
 		goto done;
 	}
-	fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
-	debug2("input_userauth_pk_ok: fp %s", fp);
+	fp = key_fingerprint(key, SSH_FP_SHA1, SSH_FP_HEX);
+	debug2("input_userauth_pk_ok: SHA1 fp %s", fp);
 	xfree(fp);
 
 	/*
diff -up openssh-5.3p1/sshconnect.c.fips openssh-5.3p1/sshconnect.c
--- openssh-5.3p1/sshconnect.c.fips	2009-10-02 14:12:00.000000000 +0200
+++ openssh-5.3p1/sshconnect.c	2009-10-02 14:12:00.000000000 +0200
@@ -40,6 +40,8 @@
 #include <unistd.h>
 #include <fcntl.h>
 
+#include <openssl/fips.h>
+
 #include "xmalloc.h"
 #include "key.h"
 #include "hostfile.h"
@@ -763,6 +765,7 @@ check_host_key(char *hostname, struct so
 			goto fail;
 		} else if (options.strict_host_key_checking == 2) {
 			char msg1[1024], msg2[1024];
+			int fips_on = FIPS_mode();
 
 			if (show_other_keys(host, host_key))
 				snprintf(msg1, sizeof(msg1),
@@ -771,8 +774,8 @@ check_host_key(char *hostname, struct so
 			else
 				snprintf(msg1, sizeof(msg1), ".");
 			/* The default */
-			fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
-			ra = key_fingerprint(host_key, SSH_FP_MD5,
+			fp = key_fingerprint(host_key, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
+			ra = key_fingerprint(host_key, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5,
 			    SSH_FP_RANDOMART);
 			msg2[0] = '\0';
 			if (options.verify_host_key_dns) {
@@ -788,10 +791,10 @@ check_host_key(char *hostname, struct so
 			snprintf(msg, sizeof(msg),
 			    "The authenticity of host '%.200s (%s)' can't be "
 			    "established%s\n"
-			    "%s key fingerprint is %s.%s%s\n%s"
+			    "%s key %sfingerprint is %s.%s%s\n%s"
 			    "Are you sure you want to continue connecting "
 			    "(yes/no)? ",
-			    host, ip, msg1, type, fp,
+			    host, ip, msg1, type, fips_on ? "SHA1 " : "", fp,
 			    options.visual_host_key ? "\n" : "",
 			    options.visual_host_key ? ra : "",
 			    msg2);
@@ -1079,17 +1082,18 @@ show_key_from_file(const char *file, con
 	Key *found;
 	char *fp, *ra;
 	int line, ret;
+	int fips_on = FIPS_mode();
 
 	found = key_new(keytype);
 	if ((ret = lookup_key_in_hostfile_by_type(file, host,
 	    keytype, found, &line))) {
-		fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
-		ra = key_fingerprint(found, SSH_FP_MD5, SSH_FP_RANDOMART);
+		fp = key_fingerprint(found, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
+		ra = key_fingerprint(found, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_RANDOMART);
 		logit("WARNING: %s key found for host %s\n"
 		    "in %s:%d\n"
-		    "%s key fingerprint %s.\n%s\n",
+		    "%s key %sfingerprint %s.\n%s\n",
 		    key_type(found), host, file, line,
-		    key_type(found), fp, ra);
+		    key_type(found), fips_on ? "SHA1 ":"", fp, ra);
 		xfree(ra);
 		xfree(fp);
 	}
@@ -1135,8 +1139,9 @@ warn_changed_key(Key *host_key)
 {
 	char *fp;
 	const char *type = key_type(host_key);
+	int fips_on = FIPS_mode();
 
-	fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+	fp = key_fingerprint(host_key, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
 
 	error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
 	error("@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @");
@@ -1144,8 +1149,8 @@ warn_changed_key(Key *host_key)
 	error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
 	error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
 	error("It is also possible that the %s host key has just been changed.", type);
-	error("The fingerprint for the %s key sent by the remote host is\n%s.",
-	    type, fp);
+	error("The %sfingerprint for the %s key sent by the remote host is\n%s.",
+	    fips_on ? "SHA1 ":"", type, fp);
 	error("Please contact your system administrator.");
 
 	xfree(fp);
diff -up openssh-5.3p1/sshd.c.fips openssh-5.3p1/sshd.c
--- openssh-5.3p1/sshd.c.fips	2009-10-02 14:12:00.000000000 +0200
+++ openssh-5.3p1/sshd.c	2009-10-02 14:12:00.000000000 +0200
@@ -76,6 +76,8 @@
 #include <openssl/bn.h>
 #include <openssl/md5.h>
 #include <openssl/rand.h>
+#include <openssl/fips.h>
+#include <fipscheck.h>
 #include "openbsd-compat/openssl-compat.h"
 
 #ifdef HAVE_SECUREWARE
@@ -1261,6 +1263,12 @@ main(int ac, char **av)
 	(void)set_auth_parameters(ac, av);
 #endif
 	__progname = ssh_get_progname(av[0]);
+
+        SSLeay_add_all_algorithms();
+        if (FIPS_mode() && !FIPSCHECK_verify(NULL, NULL)) {
+                fatal("FIPS integrity verification test failed.");
+        }
+
 	init_rng();
 
 	/* Save argv. Duplicate so setproctitle emulation doesn't clobber it */
@@ -1413,8 +1421,6 @@ main(int ac, char **av)
 	else
 		closefrom(REEXEC_DEVCRYPTO_RESERVED_FD);
 
-	SSLeay_add_all_algorithms();
-
 	/*
 	 * Force logging to stderr until we have loaded the private host
 	 * key (unless started from inetd)
@@ -1532,6 +1538,10 @@ main(int ac, char **av)
 		debug("private host key: #%d type %d %s", i, key->type,
 		    key_type(key));
 	}
+	if ((options.protocol & SSH_PROTO_1) && FIPS_mode()) {
+		logit("Disabling protocol version 1. Not allowed in the FIPS mode.");
+		options.protocol &= ~SSH_PROTO_1;
+	}
 	if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) {
 		logit("Disabling protocol version 1. Could not load host key");
 		options.protocol &= ~SSH_PROTO_1;
@@ -1656,6 +1666,10 @@ main(int ac, char **av)
 	/* Initialize the random number generator. */
 	arc4random_stir();
 
+	if (FIPS_mode()) {
+		logit("FIPS mode initialized");
+	}
+
 	/* Chdir to the root directory so that the current disk can be
 	   unmounted if desired. */
 	chdir("/");
@@ -2183,6 +2197,9 @@ do_ssh2_kex(void)
 	if (options.ciphers != NULL) {
 		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
 		myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
+	} else if (FIPS_mode()) {
+		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+		myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT;
 	}
 	myproposal[PROPOSAL_ENC_ALGS_CTOS] =
 	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
@@ -2192,6 +2209,9 @@ do_ssh2_kex(void)
 	if (options.macs != NULL) {
 		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
 		myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
+	} else if (FIPS_mode()) {
+		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
+		myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC;
 	}
 	if (options.compression == COMP_NONE) {
 		myproposal[PROPOSAL_COMP_ALGS_CTOS] =
diff -up openssh-5.3p1/ssh-keygen.c.fips openssh-5.3p1/ssh-keygen.c
--- openssh-5.3p1/ssh-keygen.c.fips	2009-10-02 14:12:00.000000000 +0200
+++ openssh-5.3p1/ssh-keygen.c	2009-10-02 14:12:00.000000000 +0200
@@ -21,6 +21,7 @@
 
 #include <openssl/evp.h>
 #include <openssl/pem.h>
+#include <openssl/fips.h>
 #include "openbsd-compat/openssl-compat.h"
 
 #include <errno.h>
@@ -537,7 +538,7 @@ do_fingerprint(struct passwd *pw)
 	enum fp_type fptype;
 	struct stat st;
 
-	fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
+	fptype = print_bubblebabble ? SSH_FP_SHA1 : FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5;
 	rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
 
 	if (!have_identity)
@@ -1506,14 +1507,15 @@ passphrase_again:
 	fclose(f);
 
 	if (!quiet) {
-		char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
-		char *ra = key_fingerprint(public, SSH_FP_MD5,
+		int fips_on = FIPS_mode();
+		char *fp = key_fingerprint(public, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
+		char *ra = key_fingerprint(public, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5,
 		    SSH_FP_RANDOMART);
 		printf("Your public key has been saved in %s.\n",
 		    identity_file);
-		printf("The key fingerprint is:\n");
+		printf("The key %sfingerprint is:\n", fips_on ? "SHA1 " : "");
 		printf("%s %s\n", fp, comment);
-		printf("The key's randomart image is:\n");
+		printf("The key's %srandomart image is:\n", fips_on ? "SHA1 " :"");
 		printf("%s\n", ra);
 		xfree(ra);
 		xfree(fp);

openssh-5.3p1-gsskex.patch:
 ChangeLog.gssapi |   95 +++++++++++++++
 Makefile.in      |    5 
 auth-krb5.c      |   17 ++
 auth.h           |    1 
 auth2-gss.c      |   50 +++++++-
 auth2.c          |    6 
 clientloop.c     |   11 +
 configure.ac     |   24 +++
 gss-genr.c       |  274 ++++++++++++++++++++++++++++++++++++++++++++-
 gss-serv-krb5.c  |   84 ++++++++++++-
 gss-serv.c       |  220 +++++++++++++++++++++++++++++++-----
 kex.c            |   18 ++
 kex.h            |   14 ++
 kexgssc.c        |  334 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 kexgsss.c        |  288 +++++++++++++++++++++++++++++++++++++++++++++++
 key.c            |    2 
 key.h            |    1 
 monitor.c        |  108 +++++++++++++++++
 monitor.h        |    2 
 monitor_wrap.c   |   47 +++++++
 monitor_wrap.h   |    4 
 readconf.c       |   35 +++++
 readconf.h       |    4 
 servconf.c       |   31 ++++-
 servconf.h       |    3 
 ssh-gss.h        |   39 +++++-
 ssh_config       |    2 
 ssh_config.5     |   29 ++++
 sshconnect2.c    |  119 ++++++++++++++++++-
 sshd.c           |  110 ++++++++++++++++++
 sshd_config      |    2 
 sshd_config.5    |   28 ++++
 32 files changed, 1949 insertions(+), 58 deletions(-)

--- NEW FILE openssh-5.3p1-gsskex.patch ---
diff -up openssh-5.3p1/auth2.c.gsskex openssh-5.3p1/auth2.c
--- openssh-5.3p1/auth2.c.gsskex	2009-11-20 14:38:55.000000000 +0100
+++ openssh-5.3p1/auth2.c	2009-11-20 14:39:04.000000000 +0100
@@ -69,6 +69,7 @@ extern Authmethod method_passwd;
 extern Authmethod method_kbdint;
 extern Authmethod method_hostbased;
 #ifdef GSSAPI
+extern Authmethod method_gsskeyex;
 extern Authmethod method_gssapi;
 #endif
 #ifdef JPAKE
@@ -79,6 +80,7 @@ Authmethod *authmethods[] = {
 	&method_none,
 	&method_pubkey,
 #ifdef GSSAPI
+	&method_gsskeyex,
 	&method_gssapi,
 #endif
 #ifdef JPAKE
@@ -289,6 +291,7 @@ input_userauth_request(int type, u_int32
 #endif
 
 	authctxt->postponed = 0;
+	authctxt->server_caused_failure = 0;
 
 	/* try to authenticate user */
 	m = authmethod_lookup(method);
@@ -361,7 +364,8 @@ userauth_finish(Authctxt *authctxt, int 
 	} else {
 
 		/* Allow initial try of "none" auth without failure penalty */
-		if (authctxt->attempt > 1 || strcmp(method, "none") != 0)
+		if (!authctxt->server_caused_failure &&
+		    (authctxt->attempt > 1 || strcmp(method, "none") != 0))
 			authctxt->failures++;
 		if (authctxt->failures >= options.max_authtries) {
 #ifdef SSH_AUDIT_EVENTS
diff -up openssh-5.3p1/auth2-gss.c.gsskex openssh-5.3p1/auth2-gss.c
--- openssh-5.3p1/auth2-gss.c.gsskex	2009-11-20 14:38:55.000000000 +0100
+++ openssh-5.3p1/auth2-gss.c	2009-11-20 14:39:04.000000000 +0100
@@ -1,7 +1,7 @@
 /* $OpenBSD: auth2-gss.c,v 1.16 2007/10/29 00:52:45 dtucker Exp $ */
 
 /*
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -52,6 +52,40 @@ static void input_gssapi_mic(int type, u
 static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
 static void input_gssapi_errtok(int, u_int32_t, void *);
 
+/* 
+ * The 'gssapi_keyex' userauth mechanism.
+ */
+static int
+userauth_gsskeyex(Authctxt *authctxt)
+{
+	int authenticated = 0;
+	Buffer b;
+	gss_buffer_desc mic, gssbuf;
+	u_int len;
+
+	mic.value = packet_get_string(&len);
+	mic.length = len;
+
+	packet_check_eom();
+
+	ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
+	    "gssapi-keyex");
+
+	gssbuf.value = buffer_ptr(&b);
+	gssbuf.length = buffer_len(&b);
+
+	/* gss_kex_context is NULL with privsep, so we can't check it here */
+	if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, 
+	    &gssbuf, &mic))))
+		authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
+		    authctxt->pw));
+	
+	buffer_free(&b);
+	xfree(mic.value);
+
+	return (authenticated);
+}
+
 /*
  * We only support those mechanisms that we know about (ie ones that we know
  * how to check local user kuserok and the like)
@@ -102,6 +136,7 @@ userauth_gssapi(Authctxt *authctxt)
 
 	if (!present) {
 		xfree(doid);
+		authctxt->server_caused_failure = 1;
 		return (0);
 	}
 
@@ -109,6 +144,7 @@ userauth_gssapi(Authctxt *authctxt)
 		if (ctxt != NULL)
 			ssh_gssapi_delete_ctx(&ctxt);
 		xfree(doid);
+		authctxt->server_caused_failure = 1;
 		return (0);
 	}
 
@@ -242,7 +278,8 @@ input_gssapi_exchange_complete(int type,
 
 	packet_check_eom();
 
-	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
+	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
+	    authctxt->pw));
 
 	authctxt->postponed = 0;
 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
@@ -284,7 +321,8 @@ input_gssapi_mic(int type, u_int32_t ple
 	gssbuf.length = buffer_len(&b);
 
 	if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
-		authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
+		authenticated = 
+		    PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
 	else
 		logit("GSSAPI MIC check failed");
 
@@ -301,6 +339,12 @@ input_gssapi_mic(int type, u_int32_t ple
 	userauth_finish(authctxt, authenticated, "gssapi-with-mic");
 }
 
+Authmethod method_gsskeyex = {
+	"gssapi-keyex",
+	userauth_gsskeyex,
+	&options.gss_authentication
+};
+
 Authmethod method_gssapi = {
 	"gssapi-with-mic",
 	userauth_gssapi,
diff -up openssh-5.3p1/auth.h.gsskex openssh-5.3p1/auth.h
--- openssh-5.3p1/auth.h.gsskex	2009-11-20 14:38:55.000000000 +0100
+++ openssh-5.3p1/auth.h	2009-11-20 14:39:04.000000000 +0100
@@ -53,6 +53,7 @@ struct Authctxt {
 	int		 valid;		/* user exists and is allowed to login */
 	int		 attempt;
 	int		 failures;
+	int		 server_caused_failure; 
 	int		 force_pwchange;
 	char		*user;		/* username sent by the client */
 	char		*service;
diff -up openssh-5.3p1/auth-krb5.c.gsskex openssh-5.3p1/auth-krb5.c
--- openssh-5.3p1/auth-krb5.c.gsskex	2006-08-05 04:39:39.000000000 +0200
+++ openssh-5.3p1/auth-krb5.c	2009-11-20 14:39:04.000000000 +0100
@@ -166,8 +166,13 @@ auth_krb5_password(Authctxt *authctxt, c
 
 	len = strlen(authctxt->krb5_ticket_file) + 6;
 	authctxt->krb5_ccname = xmalloc(len);
+#ifdef USE_CCAPI
+	snprintf(authctxt->krb5_ccname, len, "API:%s",
+	    authctxt->krb5_ticket_file);
+#else
 	snprintf(authctxt->krb5_ccname, len, "FILE:%s",
 	    authctxt->krb5_ticket_file);
+#endif
 
 #ifdef USE_PAM
 	if (options.use_pam)
@@ -219,15 +224,22 @@ krb5_cleanup_proc(Authctxt *authctxt)
 #ifndef HEIMDAL
 krb5_error_code
 ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
-	int tmpfd, ret;
+	int ret;
 	char ccname[40];
 	mode_t old_umask;
+#ifdef USE_CCAPI
+	char cctemplate[] = "API:krb5cc_%d";
+#else
+	char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX";
+	int tmpfd;
+#endif
 
 	ret = snprintf(ccname, sizeof(ccname),
-	    "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
+	    cctemplate, geteuid());
 	if (ret < 0 || (size_t)ret >= sizeof(ccname))
 		return ENOMEM;
 
+#ifndef USE_CCAPI
 	old_umask = umask(0177);
 	tmpfd = mkstemp(ccname + strlen("FILE:"));
 	umask(old_umask);
@@ -242,6 +254,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_c
 		return errno;
 	}
 	close(tmpfd);
+#endif
 
 	return (krb5_cc_resolve(ctx, ccname, ccache));
[...2530 lines suppressed...]
+
+	if (options.gss_keyex)
+		gss = ssh_gssapi_server_mechanisms();
+	else
+		gss = NULL;
+
+	if (gss && orig)
+		xasprintf(&newstr, "%s,%s", gss, orig);
+	else if (gss)
+		newstr = gss;
+	else if (orig)
+		newstr = orig;
+
+	/* 
+	 * If we've got GSSAPI mechanisms, then we've got the 'null' host
+	 * key alg, but we can't tell people about it unless its the only
+  	 * host key algorithm we support
+	 */
+	if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
+		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
+
+	if (newstr)
+		myproposal[PROPOSAL_KEX_ALGS] = newstr;
+	else
+		fatal("No supported key exchange algorithms");
+	}
+#endif
+
 	/* start key exchange */
 	kex = kex_setup(myproposal);
 	kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
 	kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
 	kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
 	kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
+#ifdef GSSAPI
+	if (options.gss_keyex) {
+		kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
+		kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
+		kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
+	}
+#endif
 	kex->server = 1;
 	kex->client_version_string=client_version_string;
 	kex->server_version_string=server_version_string;
diff -up openssh-5.3p1/sshd_config.5.gsskex openssh-5.3p1/sshd_config.5
--- openssh-5.3p1/sshd_config.5.gsskex	2009-11-20 14:39:03.000000000 +0100
+++ openssh-5.3p1/sshd_config.5	2009-11-20 14:39:06.000000000 +0100
@@ -379,12 +379,40 @@ Specifies whether user authentication ba
 The default is
 .Dq no .
 Note that this option applies to protocol version 2 only.
+.It Cm GSSAPIKeyExchange
+Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
+doesn't rely on ssh keys to verify host identity.
+The default is
+.Dq no .
+Note that this option applies to protocol version 2 only.
 .It Cm GSSAPICleanupCredentials
 Specifies whether to automatically destroy the user's credentials cache
 on logout.
 The default is
 .Dq yes .
 Note that this option applies to protocol version 2 only.
+.It Cm GSSAPIStrictAcceptorCheck
+Determines whether to be strict about the identity of the GSSAPI acceptor 
+a client authenticates against. If
+.Dq yes
+then the client must authenticate against the
+.Pa host
+service on the current hostname. If 
+.Dq no
+then the client may authenticate against any service key stored in the 
+machine's default store. This facility is provided to assist with operation 
+on multi homed machines. 
+The default is
+.Dq yes .
+Note that this option applies only to protocol version 2 GSSAPI connections,
+and setting it to 
+.Dq no
+may only work with recent Kerberos GSSAPI libraries.
+.It Cm GSSAPIStoreCredentialsOnRekey
+Controls whether the user's GSSAPI credentials should be updated following a 
+successful connection rekeying. This option can be used to accepted renewed 
+or updated credentials from a compatible client. The default is
+.Dq no .
 .It Cm HostbasedAuthentication
 Specifies whether rhosts or /etc/hosts.equiv authentication together
 with successful public key client host authentication is allowed
diff -up openssh-5.3p1/sshd_config.gsskex openssh-5.3p1/sshd_config
--- openssh-5.3p1/sshd_config.gsskex	2009-11-20 14:39:04.000000000 +0100
+++ openssh-5.3p1/sshd_config	2009-11-20 14:54:30.000000000 +0100
@@ -80,6 +80,8 @@ ChallengeResponseAuthentication no
 GSSAPIAuthentication yes
 #GSSAPICleanupCredentials yes
 GSSAPICleanupCredentials yes
+#GSSAPIStrictAcceptorCheck yes
+#GSSAPIKeyExchange no
 
 # Set this to 'yes' to enable PAM authentication, account processing, 
 # and session processing. If this is enabled, PAM authentication will 
diff -up openssh-5.3p1/ssh-gss.h.gsskex openssh-5.3p1/ssh-gss.h
--- openssh-5.3p1/ssh-gss.h.gsskex	2007-06-12 15:40:39.000000000 +0200
+++ openssh-5.3p1/ssh-gss.h	2009-11-20 14:39:06.000000000 +0100
@@ -1,6 +1,6 @@
 /* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */
 /*
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -60,10 +60,22 @@
 
 #define SSH_GSS_OIDTYPE 0x06
 
+#define SSH2_MSG_KEXGSS_INIT                            30
+#define SSH2_MSG_KEXGSS_CONTINUE                        31
+#define SSH2_MSG_KEXGSS_COMPLETE                        32
+#define SSH2_MSG_KEXGSS_HOSTKEY                         33
+#define SSH2_MSG_KEXGSS_ERROR                           34
+#define SSH2_MSG_KEXGSS_GROUPREQ			40
+#define SSH2_MSG_KEXGSS_GROUP				41
+#define KEX_GSS_GRP1_SHA1_ID				"gss-group1-sha1-"
+#define KEX_GSS_GRP14_SHA1_ID				"gss-group14-sha1-"
+#define KEX_GSS_GEX_SHA1_ID				"gss-gex-sha1-"
+
 typedef struct {
 	char *filename;
 	char *envvar;
 	char *envval;
+	struct passwd *owner;
 	void *data;
 } ssh_gssapi_ccache;
 
@@ -71,8 +83,11 @@ typedef struct {
 	gss_buffer_desc displayname;
 	gss_buffer_desc exportedname;
 	gss_cred_id_t creds;
+	gss_name_t name;
 	struct ssh_gssapi_mech_struct *mech;
 	ssh_gssapi_ccache store;
+	int used;
+	int updated;
 } ssh_gssapi_client;
 
 typedef struct ssh_gssapi_mech_struct {
@@ -83,6 +98,7 @@ typedef struct ssh_gssapi_mech_struct {
 	int (*userok) (ssh_gssapi_client *, char *);
 	int (*localname) (ssh_gssapi_client *, char **);
 	void (*storecreds) (ssh_gssapi_client *);
+	int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *);
 } ssh_gssapi_mech;
 
 typedef struct {
@@ -93,10 +109,11 @@ typedef struct {
 	gss_OID		oid; /* client */
 	gss_cred_id_t	creds; /* server */
 	gss_name_t	client; /* server */
-	gss_cred_id_t	client_creds; /* server */
+	gss_cred_id_t	client_creds; /* both */
 } Gssctxt;
 
 extern ssh_gssapi_mech *supported_mechs[];
+extern Gssctxt *gss_kex_context;
 
 int  ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
 void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
@@ -116,16 +133,30 @@ void ssh_gssapi_build_ctx(Gssctxt **);
 void ssh_gssapi_delete_ctx(Gssctxt **);
 OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
 void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
-int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *);
+int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *);
+OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
+int ssh_gssapi_credentials_updated(Gssctxt *);
 
 /* In the server */
+typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, 
+    const char *);
+char *ssh_gssapi_client_mechanisms(const char *, const char *);
+char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *,
+    const char *);
+gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int);
+int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, 
+    const char *);
 OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
-int ssh_gssapi_userok(char *name);
+int ssh_gssapi_userok(char *name, struct passwd *);
 OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
 void ssh_gssapi_do_child(char ***, u_int *);
 void ssh_gssapi_cleanup_creds(void);
 void ssh_gssapi_storecreds(void);
 
+char *ssh_gssapi_server_mechanisms(void);
+int ssh_gssapi_oid_table_ok();
+
+int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
 #endif /* GSSAPI */
 
 #endif /* _SSH_GSS_H */

openssh-5.3p1-mls.patch:
 configure.ac                |    1 
 misc.c                      |   10 +
 openbsd-compat/port-linux.c |  298 ++++++++++++++++++++++++++++++++++++++------
 session.c                   |    4 
 sshd.c                      |    3 
 5 files changed, 273 insertions(+), 43 deletions(-)

--- NEW FILE openssh-5.3p1-mls.patch ---
diff -up openssh-5.3p1/configure.ac.mls openssh-5.3p1/configure.ac
--- openssh-5.3p1/configure.ac.mls	2009-10-02 14:04:31.000000000 +0200
+++ openssh-5.3p1/configure.ac	2009-10-02 14:04:31.000000000 +0200
@@ -3404,6 +3404,7 @@ AC_ARG_WITH(selinux,
 		SSHDLIBS="$SSHDLIBS $LIBSELINUX"
 		LIBS="$LIBS $LIBSELINUX"
 		AC_CHECK_FUNCS(getseuserbyname get_default_context_with_level)
+		AC_CHECK_FUNCS(setkeycreatecon)
 		LIBS="$save_LIBS"
 	fi ]
 )
diff -up openssh-5.3p1/misc.c.mls openssh-5.3p1/misc.c
--- openssh-5.3p1/misc.c.mls	2009-02-21 22:47:02.000000000 +0100
+++ openssh-5.3p1/misc.c	2009-10-02 14:04:31.000000000 +0200
@@ -423,6 +423,7 @@ char *
 colon(char *cp)
 {
 	int flag = 0;
+	int start = 1;
 
 	if (*cp == ':')		/* Leading colon is part of file name. */
 		return (0);
@@ -436,8 +437,13 @@ colon(char *cp)
 			return (cp+1);
 		if (*cp == ':' && !flag)
 			return (cp);
-		if (*cp == '/')
-			return (0);
+		if (start) {
+		/* Slash on beginning or after dots only denotes file name. */
+			if (*cp == '/')
+				return (0);
+			if (*cp != '.')
+				start = 0;
+		}
 	}
 	return (0);
 }
diff -up openssh-5.3p1/openbsd-compat/port-linux.c.mls openssh-5.3p1/openbsd-compat/port-linux.c
--- openssh-5.3p1/openbsd-compat/port-linux.c.mls	2009-10-02 14:04:31.000000000 +0200
+++ openssh-5.3p1/openbsd-compat/port-linux.c	2009-10-02 14:04:31.000000000 +0200
@@ -33,12 +33,23 @@
 #include "key.h"
 #include "hostfile.h"
 #include "auth.h"
+#include "xmalloc.h"
 
 #include <selinux/selinux.h>
 #include <selinux/flask.h>
+#include <selinux/context.h>
 #include <selinux/get_context_list.h>
+#include <selinux/get_default_type.h>
+#include <selinux/av_permissions.h>
+
+#ifdef HAVE_LINUX_AUDIT
+#include <libaudit.h>
+#include <unistd.h>
+#endif
 
 extern Authctxt *the_authctxt;
+extern int inetd_flag;
+extern int rexeced_flag;
 
 /* Wrapper around is_selinux_enabled() to log its return value once only */
 int
@@ -54,17 +65,173 @@ ssh_selinux_enabled(void)
 	return (enabled);
 }
 
+/* Send audit message */
+static int
+send_audit_message(int success, security_context_t default_context,
+		       security_context_t selected_context)
+{
+	int rc=0;
+#ifdef HAVE_LINUX_AUDIT
+	char *msg = NULL;
+	int audit_fd = audit_open();
+	security_context_t default_raw=NULL;
+	security_context_t selected_raw=NULL;
+	rc = -1;
+	if (audit_fd < 0) {
+		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
+                                        errno == EAFNOSUPPORT)
+                        return 0; /* No audit support in kernel */
+		error("Error connecting to audit system.");
+		return rc;
+	}
+	if (selinux_trans_to_raw_context(default_context, &default_raw) < 0) {
+		error("Error translating default context.");
+		default_raw = NULL;
+	}
+	if (selinux_trans_to_raw_context(selected_context, &selected_raw) < 0) {
+		error("Error translating selected context.");
+		selected_raw = NULL;
+	}
+	if (asprintf(&msg, "sshd: default-context=%s selected-context=%s",
+		     default_raw ? default_raw : (default_context ? default_context: "?"),
+		     selected_context ? selected_raw : (selected_context ? selected_context :"?")) < 0) {
+		error("Error allocating memory.");
+		goto out;
+	}
+	if (audit_log_user_message(audit_fd, AUDIT_USER_ROLE_CHANGE,
+				   msg, NULL, NULL, NULL, success) <= 0) {
+		error("Error sending audit message.");
+		goto out;
+	}
+	rc = 0;
+      out:
+	free(msg);
+	freecon(default_raw);
+	freecon(selected_raw);
+	close(audit_fd);
+#endif
+	return rc;
+}
+
+static int
+mls_range_allowed(security_context_t src, security_context_t dst)
+{
+	struct av_decision avd;
+	int retval;
+	unsigned int bit = CONTEXT__CONTAINS;
+
+	debug("%s: src:%s dst:%s", __func__, src, dst);
+	retval = security_compute_av(src, dst, SECCLASS_CONTEXT, bit, &avd);
+	if (retval || ((bit & avd.allowed) != bit))
+		return 0;
+
+	return 1;
+}
+
+static int
+get_user_context(const char *sename, const char *role, const char *lvl,
+	security_context_t *sc) {
+#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
+	if (lvl == NULL || lvl[0] == '\0' || get_default_context_with_level(sename, lvl, NULL, sc) != 0) {
+	        /* User may have requested a level completely outside of his 
+	           allowed range. We get a context just for auditing as the
+	           range check below will certainly fail for default context. */
+#endif
+		if (get_default_context(sename, NULL, sc) != 0) {
+			*sc = NULL;
+			return -1;
+		}
+#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
+	}
+#endif
+	if (role != NULL && role[0]) {
+		context_t con;
+		char *type=NULL;
+		if (get_default_type(role, &type) != 0) {
+			error("get_default_type: failed to get default type for '%s'",
+				role);
+			goto out;
+		}
+		con = context_new(*sc);
+		if (!con) {
+			goto out;
+		}
+		context_role_set(con, role);
+		context_type_set(con, type);
+		freecon(*sc);
+		*sc = strdup(context_str(con));
+		context_free(con);
+		if (!*sc) 
+			return -1;
+	}
+#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
+	if (lvl != NULL && lvl[0]) {
+		/* verify that the requested range is obtained */
+		context_t con;
+		security_context_t obtained_raw;
+		security_context_t requested_raw;
+		con = context_new(*sc);
+		if (!con) {
+			goto out;
+		}
+		context_range_set(con, lvl);
+		if (selinux_trans_to_raw_context(*sc, &obtained_raw) < 0) {
+			context_free(con);
+			goto out;
+		}
+		if (selinux_trans_to_raw_context(context_str(con), &requested_raw) < 0) {
+			freecon(obtained_raw);
+			context_free(con);
+			goto out;
+		}
+
+		debug("get_user_context: obtained context '%s' requested context '%s'",
+			obtained_raw, requested_raw);
+		if (strcmp(obtained_raw, requested_raw)) {
+			/* set the context to the real requested one but fail */
+			freecon(requested_raw);
+			freecon(obtained_raw);
+			freecon(*sc);
+			*sc = strdup(context_str(con));
+			context_free(con);
+			return -1;
+		}
+		freecon(requested_raw);
+		freecon(obtained_raw);
+		context_free(con);
+	}
+#endif
+	return 0;
+      out:
+        freecon(*sc);
+        *sc = NULL;
+        return -1;
+}
+
 /* Return the default security context for the given username */
-static security_context_t
-ssh_selinux_getctxbyname(char *pwname)
+static int
+ssh_selinux_getctxbyname(char *pwname,
+	security_context_t *default_sc, security_context_t *user_sc)
 {
-	security_context_t sc = NULL;
 	char *sename, *lvl;
+	const char *reqlvl = NULL;
 	char *role = NULL;
-	int r = 0;
+	int r = -1;
+	context_t con = NULL;
+
+	*default_sc = NULL;
+	*user_sc = NULL;
+	if (the_authctxt) {
+		if (the_authctxt->role != NULL) {
+			char *slash;
+			role = xstrdup(the_authctxt->role);
+			if ((slash = strchr(role, '/')) != NULL) {
+				*slash = '\0';
+				reqlvl = slash + 1;
+			}
+		}
+	}
 
-	if (the_authctxt) 
-		role=the_authctxt->role;
 #ifdef HAVE_GETSEUSERBYNAME
 	if ((r=getseuserbyname(pwname, &sename, &lvl)) != 0) {
 		sename = NULL;
@@ -72,38 +239,63 @@ ssh_selinux_getctxbyname(char *pwname)
 	}
 #else
 	sename = pwname;
-	lvl = NULL;
+	lvl = "";
 #endif
 
 	if (r == 0) {
 #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
-		if (role != NULL && role[0])
-			r = get_default_context_with_rolelevel(sename, role, lvl, NULL, &sc);
-		else
-			r = get_default_context_with_level(sename, lvl, NULL, &sc);
+		r = get_default_context_with_level(sename, lvl, NULL, default_sc);
 #else
-		if (role != NULL && role[0])
-			r = get_default_context_with_role(sename, role, NULL, &sc);
-		else
-			r = get_default_context(sename, NULL, &sc);
+		r = get_default_context(sename, NULL, default_sc);
 #endif
 	}
 
-	if (r != 0) {
-		switch (security_getenforce()) {
-		case -1:
-			fatal("%s: ssh_selinux_getctxbyname: "
-			    "security_getenforce() failed", __func__);
-		case 0:
-			error("%s: Failed to get default SELinux security "
-			    "context for %s", __func__, pwname);
-			break;
-		default:
-			fatal("%s: Failed to get default SELinux security "
-			    "context for %s (in enforcing mode)",
-			    __func__, pwname);
+	if (r == 0) {
+		/* If launched from xinetd, we must use current level */
+		if (inetd_flag && !rexeced_flag) {
+			security_context_t sshdsc=NULL;
+
+			if (getcon_raw(&sshdsc) < 0)
+				fatal("failed to allocate security context");
+
+			if ((con=context_new(sshdsc)) == NULL)
+				fatal("failed to allocate selinux context");
+			reqlvl = context_range_get(con);
+			freecon(sshdsc);
+			if (reqlvl !=NULL && lvl != NULL && strcmp(reqlvl, lvl) == 0)
+			    /* we actually don't change level */
+			    reqlvl = "";
+
+			debug("%s: current connection level '%s'", __func__, reqlvl);
+		}
+		
+		if ((reqlvl != NULL && reqlvl[0]) || (role != NULL && role[0])) {
+			r = get_user_context(sename, role, reqlvl, user_sc);
+		
+			if (r == 0 && reqlvl != NULL && reqlvl[0]) {
+				security_context_t default_level_sc = *default_sc;
+				if (role != NULL && role[0]) {
+					if (get_user_context(sename, role, lvl, &default_level_sc) < 0)
+						default_level_sc = *default_sc;
+				}
+				/* verify that the requested range is contained in the user range */
+				if (mls_range_allowed(default_level_sc, *user_sc)) {
+					logit("permit MLS level %s (user range %s)", reqlvl, lvl);
+				} else {
+					r = -1;
+					error("deny MLS level %s (user range %s)", reqlvl, lvl);
+				}
+				if (default_level_sc != *default_sc)
+					freecon(default_level_sc);
+			}
+		} else {
+			*user_sc = *default_sc;
 		}
 	}
+	if (r != 0) {
+		error("%s: Failed to get default SELinux security "
+		    "context for %s", __func__, pwname);
+	}
 
 #ifdef HAVE_GETSEUSERBYNAME
 	if (sename != NULL)
@@ -111,14 +303,20 @@ ssh_selinux_getctxbyname(char *pwname)
 	if (lvl != NULL)
 		xfree(lvl);
 #endif
+	if (role != NULL)
+		xfree(role);
+	if (con)
+		context_free(con);
 
-	return (sc);
+	return (r);
 }
 
 /* Set the execution context to the default for the specified user */
 void
 ssh_selinux_setup_exec_context(char *pwname)
 {
+	int r = 0;
+	security_context_t default_ctx = NULL;
 	security_context_t user_ctx = NULL;
 
 	if (!ssh_selinux_enabled())
@@ -126,22 +324,45 @@ ssh_selinux_setup_exec_context(char *pwn
 
 	debug3("%s: setting execution context", __func__);
 
-	user_ctx = ssh_selinux_getctxbyname(pwname);
-	if (setexeccon(user_ctx) != 0) {
+	r = ssh_selinux_getctxbyname(pwname, &default_ctx, &user_ctx);
+	if (r >= 0) {
+		r = setexeccon(user_ctx);
+		if (r < 0) {
+			error("%s: Failed to set SELinux execution context %s for %s",
+			    __func__, user_ctx, pwname);
+		} 
+#ifdef HAVE_SETKEYCREATECON
+		else if (setkeycreatecon(user_ctx) < 0) {
+			error("%s: Failed to set SELinux keyring creation context %s for %s",
+			    __func__, user_ctx, pwname);
+		}
+#endif
+	}
+	if (user_ctx == NULL) {
+		user_ctx = default_ctx;
+	}
+	if (r < 0 || user_ctx != default_ctx) {
+		/* audit just the case when user changed a role or there was
+		   a failure */
+		send_audit_message(r >= 0, default_ctx, user_ctx);
+	}
+	if (r < 0) {
 		switch (security_getenforce()) {
 		case -1:
 			fatal("%s: security_getenforce() failed", __func__);
 		case 0:
-			error("%s: Failed to set SELinux execution "
-			    "context for %s", __func__, pwname);
+			error("%s: SELinux failure. Continuing in permissive mode.",
+			    __func__);
 			break;
 		default:
-			fatal("%s: Failed to set SELinux execution context "
-			    "for %s (in enforcing mode)", __func__, pwname);
+			fatal("%s: SELinux failure. Aborting connection.",
+			    __func__);
 		}
 	}
-	if (user_ctx != NULL)
+	if (user_ctx != NULL && user_ctx != default_ctx)
 		freecon(user_ctx);
+	if (default_ctx != NULL)
+		freecon(default_ctx);
 
 	debug3("%s: done", __func__);
 }
@@ -159,7 +380,10 @@ ssh_selinux_setup_pty(char *pwname, cons
 
 	debug3("%s: setting TTY context on %s", __func__, tty);
 
-	user_ctx = ssh_selinux_getctxbyname(pwname);
+	if (getexeccon(&user_ctx) < 0) {
+		error("%s: getexeccon: %s", __func__, strerror(errno));
+		goto out;
+	}
 
 	/* XXX: should these calls fatal() upon failure in enforcing mode? */
 
diff -up openssh-5.3p1/session.c.mls openssh-5.3p1/session.c
--- openssh-5.3p1/session.c.mls	2009-08-20 08:20:50.000000000 +0200
+++ openssh-5.3p1/session.c	2009-10-02 14:06:12.000000000 +0200
@@ -1550,10 +1550,6 @@ do_setusercontext(struct passwd *pw)
 
 	if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
 		fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
-
-#ifdef WITH_SELINUX
-	ssh_selinux_setup_exec_context(pw->pw_name);
-#endif
 }
 
 static void
diff -up openssh-5.3p1/sshd.c.mls openssh-5.3p1/sshd.c
--- openssh-5.3p1/sshd.c.mls	2009-10-02 14:04:31.000000000 +0200
+++ openssh-5.3p1/sshd.c	2009-10-02 14:04:31.000000000 +0200
@@ -1896,6 +1896,9 @@ main(int ac, char **av)
 		restore_uid();
 	}
 #endif
+#ifdef WITH_SELINUX
+	ssh_selinux_setup_exec_context(authctxt->pw->pw_name);
+#endif
 #ifdef USE_PAM
 	if (options.use_pam) {
 		do_pam_setcred(1);

openssh-5.3p1-nss-keys.patch:
 openssh-5.2p1/README.nss   |   36 ++++
 openssh-5.3p1/Makefile.in  |    2 
 openssh-5.3p1/authfd.c     |   39 +++++
 openssh-5.3p1/authfd.h     |    8 +
 openssh-5.3p1/configure.ac |   15 ++
 openssh-5.3p1/key.c        |   61 ++++++++
 openssh-5.3p1/key.h        |   20 ++
 openssh-5.3p1/nsskeys.c    |  327 +++++++++++++++++++++++++++++++++++++++++++++
 openssh-5.3p1/nsskeys.h    |   39 +++++
 openssh-5.3p1/readconf.c   |   20 ++
 openssh-5.3p1/readconf.h   |    2 
 openssh-5.3p1/ssh-add.c    |  181 ++++++++++++++++++++++++
 openssh-5.3p1/ssh-agent.c  |  121 ++++++++++++++++
 openssh-5.3p1/ssh-dss.c    |   36 ++++
 openssh-5.3p1/ssh-keygen.c |   51 ++++++-
 openssh-5.3p1/ssh-rsa.c    |   42 +++++
 openssh-5.3p1/ssh.c        |   28 +++
 17 files changed, 1016 insertions(+), 12 deletions(-)

--- NEW FILE openssh-5.3p1-nss-keys.patch ---
diff -up openssh-5.3p1/authfd.c.nss-keys openssh-5.3p1/authfd.c
--- openssh-5.3p1/authfd.c.nss-keys	2006-09-01 07:38:36.000000000 +0200
+++ openssh-5.3p1/authfd.c	2009-10-02 14:09:01.000000000 +0200
@@ -626,6 +626,45 @@ ssh_update_card(AuthenticationConnection
 	return decode_reply(type);
 }
 
+int
+ssh_update_nss_key(AuthenticationConnection *auth, int add,
+    const char *tokenname, const char *keyname,
+    const char *pass, u_int life, u_int confirm)
+{
+	Buffer msg;
+	int type, constrained = (life || confirm);
+
+	if (add) {
+		type = constrained ?
+		    SSH_AGENTC_ADD_NSS_KEY_CONSTRAINED :
+		    SSH_AGENTC_ADD_NSS_KEY;
+	} else
+		type = SSH_AGENTC_REMOVE_NSS_KEY;
+
+	buffer_init(&msg);
+	buffer_put_char(&msg, type);
+	buffer_put_cstring(&msg, tokenname);
+	buffer_put_cstring(&msg, keyname);
+	buffer_put_cstring(&msg, pass);
+
+	if (constrained) {
+		if (life != 0) {
+			buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME);
+			buffer_put_int(&msg, life);
+		}
+		if (confirm != 0)
+			buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM);
+	}
+
+	if (ssh_request_reply(auth, &msg, &msg) == 0) {
+		buffer_free(&msg);
+		return 0;
+	}
+	type = buffer_get_char(&msg);
+	buffer_free(&msg);
+	return decode_reply(type);
+}
+
 /*
  * Removes all identities from the agent.  This call is not meant to be used
  * by normal applications.
diff -up openssh-5.3p1/authfd.h.nss-keys openssh-5.3p1/authfd.h
--- openssh-5.3p1/authfd.h.nss-keys	2006-08-05 04:39:39.000000000 +0200
+++ openssh-5.3p1/authfd.h	2009-10-02 14:09:01.000000000 +0200
@@ -49,6 +49,12 @@
 #define SSH2_AGENTC_ADD_ID_CONSTRAINED		25
 #define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26
 
+/* nss */
+#define SSH_AGENTC_ADD_NSS_KEY			30
+#define SSH_AGENTC_REMOVE_NSS_KEY		31
+#define SSH_AGENTC_ADD_NSS_KEY_CONSTRAINED	32
+
+
 #define	SSH_AGENT_CONSTRAIN_LIFETIME		1
 #define	SSH_AGENT_CONSTRAIN_CONFIRM		2
 
@@ -83,6 +89,8 @@ int	 ssh_remove_all_identities(Authentic
 int	 ssh_lock_agent(AuthenticationConnection *, int, const char *);
 int	 ssh_update_card(AuthenticationConnection *, int, const char *,
     const char *, u_int, u_int);
+int	 ssh_update_nss_key(AuthenticationConnection *, int, const char *,
+    const char *, const char *, u_int, u_int);
 
 int
 ssh_decrypt_challenge(AuthenticationConnection *, Key *, BIGNUM *, u_char[16],
diff -up openssh-5.3p1/configure.ac.nss-keys openssh-5.3p1/configure.ac
--- openssh-5.3p1/configure.ac.nss-keys	2009-10-02 14:09:01.000000000 +0200
+++ openssh-5.3p1/configure.ac	2009-10-02 14:09:01.000000000 +0200
@@ -3514,6 +3514,20 @@ AC_ARG_WITH(kerberos5,
 	]
 )
 
+# Check whether user wants NSS support
+LIBNSS_MSG="no"
+AC_ARG_WITH(nss,
+	[  --with-nss   Enable NSS support],
+	[ if test "x$withval" != "xno" ; then
+		AC_DEFINE(HAVE_LIBNSS,1,[Define if you want NSS support.])
+		LIBNSS_MSG="yes"
+		CPPFLAGS="$CPPFLAGS -I/usr/include/nss3 -I/usr/include/nspr4"
+		AC_CHECK_HEADERS(pk11pub.h)
+		LIBS="$LIBS -lnss3"
+	fi
+	])
+AC_SUBST(LIBNSS)
+
 # Looking for programs, paths and files
 
 PRIVSEP_PATH=/var/empty
@@ -4240,6 +4254,7 @@ echo "              TCP Wrappers support
 echo "              MD5 password support: $MD5_MSG"
 echo "                   libedit support: $LIBEDIT_MSG"
 echo "  Solaris process contract support: $SPC_MSG"
+echo "                       NSS support: $LIBNSS_MSG"
 echo "       IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
 echo "           Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
 echo "                  BSD Auth support: $BSD_AUTH_MSG"
diff -up openssh-5.3p1/key.c.nss-keys openssh-5.3p1/key.c
--- openssh-5.3p1/key.c.nss-keys	2008-11-03 09:24:17.000000000 +0100
+++ openssh-5.3p1/key.c	2009-10-02 14:09:01.000000000 +0200
@@ -96,6 +96,54 @@ key_new(int type)
 	return k;
 }
 
+#ifdef HAVE_LIBNSS
+Key *
+key_new_nss(int type)
+{
+	Key *k = key_new(type);
+
+	k->nss = xcalloc(1, sizeof(*k->nss));
+	k->flags = KEY_FLAG_EXT | KEY_FLAG_NSS;
+
+	return k;
+}
+
+Key *
+key_new_nss_copy(int type, const Key *c)
+{
+	Key *k = key_new_nss(type);
+
+	switch (k->type) {
+		case KEY_RSA:
+			if ((BN_copy(k->rsa->n, c->rsa->n) == NULL) ||
+				(BN_copy(k->rsa->e, c->rsa->e) == NULL))
+				fatal("key_new_nss_copy: BN_copy failed");
+			break;
+		case KEY_DSA:
+			if ((BN_copy(k->dsa->p, c->rsa->p) == NULL) ||
+				(BN_copy(k->dsa->q, c->dsa->q) == NULL) ||
+				(BN_copy(k->dsa->g, c->dsa->g) == NULL) ||
+				(BN_copy(k->dsa->pub_key, c->dsa->pub_key) == NULL))
+				fatal("key_new_nss_copy: BN_copy failed");
+			break;
+	}
+		
+	k->nss->privk = SECKEY_CopyPrivateKey(c->nss->privk);
+	if (k->nss->privk == NULL)
+		fatal("key_new_nss_copy: SECKEY_CopyPrivateKey failed");
+
+	k->nss->pubk = SECKEY_CopyPublicKey(c->nss->pubk);
+	if (k->nss->pubk == NULL)
+		fatal("key_new_nss_copy: SECKEY_CopyPublicKey failed");
+	
+	if (c->nss->privk->wincx)
+		k->nss->privk->wincx = xstrdup(c->nss->privk->wincx);
+
+	return k;
+}
+#endif
+
+
 Key *
 key_new_private(int type)
 {
@@ -151,6 +199,19 @@ key_free(Key *k)
 		fatal("key_free: bad key type %d", k->type);
 		break;
 	}
+#ifdef HAVE_LIBNSS
+	if (k->flags & KEY_FLAG_NSS) {
+		if (k->nss->privk != NULL && k->nss->privk->wincx != NULL) {
+			memset(k->nss->privk->wincx, 0,
+				strlen(k->nss->privk->wincx));
+			xfree(k->nss->privk->wincx);
+			k->nss->privk->wincx = NULL;
+		}
+		SECKEY_DestroyPrivateKey(k->nss->privk);
+		SECKEY_DestroyPublicKey(k->nss->pubk);
+		xfree(k->nss);
+	}
+#endif
 	xfree(k);
 }
 
diff -up openssh-5.3p1/key.h.nss-keys openssh-5.3p1/key.h
--- openssh-5.3p1/key.h.nss-keys	2008-06-12 20:40:35.000000000 +0200
+++ openssh-5.3p1/key.h	2009-10-02 14:09:01.000000000 +0200
@@ -29,11 +29,17 @@
 #include <openssl/rsa.h>
 #include <openssl/dsa.h>
 
+#ifdef HAVE_LIBNSS
+#include <nss.h>
+#include <keyhi.h>
+#endif
+
 typedef struct Key Key;
 enum types {
 	KEY_RSA1,
 	KEY_RSA,
 	KEY_DSA,
+	KEY_NSS,
 	KEY_UNSPEC
 };
 enum fp_type {
@@ -48,16 +54,30 @@ enum fp_rep {
 
 /* key is stored in external hardware */
 #define KEY_FLAG_EXT		0x0001
+#define KEY_FLAG_NSS		0x0002
+
+#ifdef HAVE_LIBNSS
+typedef struct NSSKey NSSKey;
+struct NSSKey {
+	SECKEYPrivateKey *privk;
+	SECKEYPublicKey *pubk;
+};
+#endif
 
 struct Key {
 	int	 type;
 	int	 flags;
 	RSA	*rsa;
 	DSA	*dsa;
+#ifdef HAVE_LIBNSS
+	NSSKey  *nss;
+#endif
 };
 
 Key		*key_new(int);
 Key		*key_new_private(int);
+Key 		*key_new_nss(int);
+Key		*key_new_nss_copy(int, const Key *);
 void		 key_free(Key *);
 Key		*key_demote(const Key *);
 int		 key_equal(const Key *, const Key *);
diff -up openssh-5.3p1/Makefile.in.nss-keys openssh-5.3p1/Makefile.in
--- openssh-5.3p1/Makefile.in.nss-keys	2009-08-28 02:47:38.000000000 +0200
+++ openssh-5.3p1/Makefile.in	2009-10-02 14:09:53.000000000 +0200
@@ -71,7 +71,7 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o b
 	atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
 	monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \
 	kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \
-	entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o
+	entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o nsskeys.o
 
 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
 	sshconnect.o sshconnect1.o sshconnect2.o mux.o \
diff -up /dev/null openssh-5.3p1/nsskeys.c
--- /dev/null	2009-09-11 09:35:58.778798825 +0200
+++ openssh-5.3p1/nsskeys.c	2009-10-02 14:09:01.000000000 +0200
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2007 Red Hat, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+#ifdef HAVE_LIBNSS
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/evp.h>
+
+#include <nss.h>
+#include <keyhi.h>
+#include <pk11pub.h>
+#include <cert.h>
+
+#include "xmalloc.h"
+#include "key.h"
+#include "log.h"
+#include "misc.h"
+#include "nsskeys.h"
+#include "pathnames.h"
+
+static char *
+password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
+{
+	char *password = arg;
+	if (retry || password == NULL)
+		return NULL;
+	
+	return PL_strdup(password);
+}
+
+int
+nss_init(PK11PasswordFunc pwfn)
+{
+	char *dbpath;
+	char buf[MAXPATHLEN];
+
+	if (NSS_IsInitialized())
+		return 0;
+
+	if ((dbpath=getenv("NSS_DB_PATH")) == NULL) {
+		struct passwd *pw;
+		if ((pw = getpwuid(getuid())) == NULL ||
+			pw->pw_dir == NULL) {
+			return -1;
+		}
+		snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir,
+			    _PATH_SSH_USER_DIR);
+		dbpath = buf;
+	}
+
+	if (NSS_Init(dbpath) != SECSuccess)
+		return -1;
+
+	if (pwfn == NULL) {
+		pwfn = password_cb;
+	}
+
+	PK11_SetPasswordFunc(pwfn);
+	
+	return 0;
+}
+
+static Key *
+make_key_from_privkey(SECKEYPrivateKey *privk, char *password)
+{
+	Key *k;
+	switch (SECKEY_GetPrivateKeyType(privk)) {
+		case rsaKey:
+			k = key_new_nss(KEY_RSA);
+			break;
+		case dsaKey:
+			k = key_new_nss(KEY_DSA);
+			break;
+		default:
+			return NULL;
+	}
+	k->nss->pubk = SECKEY_ConvertToPublicKey(privk);
+	if (k->nss->pubk != NULL) {
+		k->nss->privk = SECKEY_CopyPrivateKey(privk);
+	}
+	if (k->nss->privk != NULL) {
+		if (password != NULL) {
+			k->nss->privk->wincx = xstrdup(password);
+		}
+		return k;
+	}
+	key_free(k);
+	return NULL;
+}
+
+static Key **
+add_key_to_list(Key *k, Key **keys, size_t *i, size_t *allocated)
+{
+	if (*allocated < *i + 2) {
+		*allocated += 16;
+		keys = xrealloc(keys, *allocated, sizeof(k));
+	}
+	keys[*i] = k;
+	(*i)++;
+	keys[*i] = NULL;
+	return keys;
+}
+
+static int
+nss_convert_pubkey(Key *k)
+{
+	u_char *n;
+	unsigned int len;
+	char *p;
+
+	switch (k->type) {
+		case KEY_RSA:
+			n = k->nss->pubk->u.rsa.modulus.data;
+			len = k->nss->pubk->u.rsa.modulus.len;
+
+			if (BN_bin2bn(n, len, k->rsa->n) == NULL) {
+				fatal("nss_convert_pubkey: BN_bin2bn failed");
+			}
+
+			n = k->nss->pubk->u.rsa.publicExponent.data;
+			len = k->nss->pubk->u.rsa.publicExponent.len;
+
+			if (BN_bin2bn(n, len, k->rsa->e) == NULL) {
+				fatal("nss_convert_pubkey: BN_bin2bn failed");
+			}
+			break;
+		case KEY_DSA:
+			n = k->nss->pubk->u.dsa.params.prime.data;
+			len = k->nss->pubk->u.dsa.params.prime.len;
+
+			if (BN_bin2bn(n, len, k->dsa->p) == NULL) {
+				fatal("nss_convert_pubkey: BN_bin2bn failed");
+			}
+
+			n = k->nss->pubk->u.dsa.params.subPrime.data;
+			len = k->nss->pubk->u.dsa.params.subPrime.len;
+
+			if (BN_bin2bn(n, len, k->dsa->q) == NULL) {
+				fatal("nss_convert_pubkey: BN_bin2bn failed");
+			}
+
+			n = k->nss->pubk->u.dsa.params.base.data;
+			len = k->nss->pubk->u.dsa.params.base.len;
+
+			if (BN_bin2bn(n, len, k->dsa->g) == NULL) {
+				fatal("nss_convert_pubkey: BN_bin2bn failed");
+			}
+
+			n = k->nss->pubk->u.dsa.publicValue.data;
+			len = k->nss->pubk->u.dsa.publicValue.len;
+
+			if (BN_bin2bn(n, len, k->dsa->pub_key) == NULL) {
+				fatal("nss_convert_pubkey: BN_bin2bn failed");
+			}
+			break;
+	}
+
+	p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
+	debug("fingerprint %u %s", key_size(k), p);
+	xfree(p);
+
+	return 0;
+}
+
+static Key **
+nss_find_privkeys(const char *tokenname, const char *keyname,
+    char *password)
+{
+	Key *k = NULL;
+	Key **keys = NULL;
+	PK11SlotList *slots;
+	PK11SlotListElement *sle;
+	size_t allocated = 0;
+	size_t i = 0;
+
+	if ((slots=PK11_FindSlotsByNames(NULL, NULL, tokenname, PR_TRUE)) == NULL) {
+		if (tokenname == NULL) {
+			debug("No NSS token found");
+		} else {
+			debug("NSS token not found: %s", tokenname);
+		}
+		return NULL;
+	}
+	
+	for (sle = slots->head; sle; sle = sle->next) {
+		SECKEYPrivateKeyList *list;
+		SECKEYPrivateKeyListNode *node;
+		char *tmppass = password;
+				
+		if (PK11_NeedLogin(sle->slot)) {
+			if (password == NULL) {
+				char *prompt;
+				if (asprintf(&prompt, "Enter passphrase for token %s: ",
+					PK11_GetTokenName(sle->slot)) < 0)
+					fatal("password_cb: asprintf failed");
+				tmppass = read_passphrase(prompt, RP_ALLOW_STDIN);
+			}
+			PK11_Authenticate(sle->slot, PR_TRUE, tmppass);
+		}
+
+		debug("Looking for: %s:%s", tokenname, keyname);
+		list = PK11_ListPrivKeysInSlot(sle->slot, (char *)keyname,
+			tmppass);
+		if (list == NULL && keyname != NULL) {
+			char *fooname;
+			/* NSS bug workaround */
+			if (asprintf(&fooname, "%s~", keyname) < 0) {
+				error("nss_find_privkey: asprintf failed");
+				PK11_FreeSlotList(slots);
+				return NULL;
+			}
+			list = PK11_ListPrivKeysInSlot(sle->slot, fooname,
+			tmppass);
+			free(fooname);
+		}
+		if (list == NULL && keyname != NULL) {
+			CERTCertificate *cert;
+			SECKEYPrivateKey *privk;
+			cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(),
+				(char *)keyname);
+			if (cert == NULL)
+				goto cleanup;
+			privk = PK11_FindPrivateKeyFromCert(sle->slot, cert, tmppass);
+			CERT_DestroyCertificate(cert);
+			if (privk == NULL)
+				goto cleanup;
+			if ((k=make_key_from_privkey(privk, tmppass)) != NULL) {
+				nss_convert_pubkey(k);
+				keys = add_key_to_list(k, keys, &i, &allocated);
+			}
+			SECKEY_DestroyPrivateKey(privk);
+		} else {
+			if (list == NULL)
+				goto cleanup;
+			for (node=PRIVKEY_LIST_HEAD(list); !PRIVKEY_LIST_END(node, list);
+				node=PRIVKEY_LIST_NEXT(node))
+				if ((k=make_key_from_privkey(node->key, tmppass)) != NULL) {
+					nss_convert_pubkey(k);
+					keys = add_key_to_list(k, keys, &i, &allocated);
+				}
+			SECKEY_DestroyPrivateKeyList(list);
+		}
+cleanup:
+		if (password == NULL && tmppass != NULL) {
+			memset(tmppass, 0, strlen(tmppass));
+			xfree(tmppass);
+		}
+	}
+	PK11_FreeSlotList(slots);
+
+	return keys;
+}
+
+Key **
+nss_get_keys(const char *tokenname, const char *keyname,
+    char *password)
+{
+	Key **keys;
+
+	if (nss_init(NULL) == -1) {
+		error("Failed to initialize NSS library");
+		return NULL;
+	}
+
+	keys = nss_find_privkeys(tokenname, keyname, password);
+	if (keys == NULL && keyname != NULL) {
+		error("Cannot find key in nss, token removed");
+		return NULL;
+	}
+#if 0
+	keys = xcalloc(3, sizeof(Key *));
+
+	if (k->type == KEY_RSA) {
+		n = key_new_nss_copy(KEY_RSA1, k);
+
+		keys[0] = n;
+		keys[1] = k;
+		keys[2] = NULL;
+	} else {
+		keys[0] = k;
+		keys[1] = NULL;
+	}
+#endif
+	return keys;
+}
+
+char *
+nss_get_key_label(Key *key)
+{
+	char *label, *nickname;
+	
+	nickname = PK11_GetPrivateKeyNickname(key->nss->privk);
+	label = xstrdup(nickname);
+	PORT_Free(nickname);
+
+	return label;
+}
+
+#endif /* HAVE_LIBNSS */
diff -up /dev/null openssh-5.3p1/nsskeys.h
--- /dev/null	2009-09-11 09:35:58.778798825 +0200
+++ openssh-5.3p1/nsskeys.h	2009-10-02 14:09:01.000000000 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2007 Red Hat, Inc.  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 NSSKEYS_H
+#define NSSKEYS_H
+#ifdef HAVE_LIBNSS
+#include <pk11func.h>
+#include <prtypes.h>
+
+int	nss_init(PK11PasswordFunc);
+Key	**nss_get_keys(const char *, const char *, char *);
+char	*nss_get_key_label(Key *);
+/*void	 sc_close(void);*/
+/*int	 sc_put_key(Key *, const char *);*/
+
+#endif
+#endif
diff -up openssh-5.3p1/readconf.c.nss-keys openssh-5.3p1/readconf.c
--- openssh-5.3p1/readconf.c.nss-keys	2009-07-05 23:12:27.000000000 +0200
+++ openssh-5.3p1/readconf.c	2009-10-02 14:09:01.000000000 +0200
@@ -124,6 +124,7 @@ typedef enum {
 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
+	oUseNSS, oNSSToken,
 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
@@ -210,6 +211,13 @@ static struct {
 #else
 	{ "smartcarddevice", oUnsupported },
 #endif
+#ifdef HAVE_LIBNSS
+	{ "usenss", oUseNSS },
+	{ "nsstoken", oNSSToken },
+#else
+	{ "usenss", oUnsupported },
+	{ "nsstoken", oNSSToken },
+#endif
 	{ "clearallforwardings", oClearAllForwardings },
 	{ "enablesshkeysign", oEnableSSHKeysign },
 	{ "verifyhostkeydns", oVerifyHostKeyDNS },
@@ -613,6 +621,14 @@ parse_string:
 		charptr = &options->smartcard_device;
 		goto parse_string;
 
+	case oUseNSS:
+		intptr = &options->use_nss;
+		goto parse_flag;
+
+	case oNSSToken:
+		charptr = &options->nss_token;
+		goto parse_command;
+
 	case oProxyCommand:
 		charptr = &options->proxy_command;
 parse_command:
@@ -1052,6 +1068,8 @@ initialize_options(Options * options)
 	options->preferred_authentications = NULL;
 	options->bind_address = NULL;
 	options->smartcard_device = NULL;
+	options->use_nss = -1;
+	options->nss_token = NULL;
 	options->enable_ssh_keysign = - 1;
 	options->no_host_authentication_for_localhost = - 1;
 	options->identities_only = - 1;
@@ -1183,6 +1201,8 @@ fill_default_options(Options * options)
 		options->no_host_authentication_for_localhost = 0;
 	if (options->identities_only == -1)
 		options->identities_only = 0;
+	if (options->use_nss == -1)
+		options->use_nss = 0;
 	if (options->enable_ssh_keysign == -1)
 		options->enable_ssh_keysign = 0;
 	if (options->rekey_limit == -1)
diff -up openssh-5.3p1/readconf.h.nss-keys openssh-5.3p1/readconf.h
--- openssh-5.3p1/readconf.h.nss-keys	2009-07-05 23:12:27.000000000 +0200
+++ openssh-5.3p1/readconf.h	2009-10-02 14:09:01.000000000 +0200
@@ -85,6 +85,8 @@ typedef struct {
 	char   *preferred_authentications;
 	char   *bind_address;	/* local socket address for connection to sshd */
 	char   *smartcard_device; /* Smartcard reader device */
+	int     use_nss;        /* Use NSS library for keys */
+	char   *nss_token;      /* Look for NSS keys on token */
 	int	verify_host_key_dns;	/* Verify host key using DNS */
 
 	int     num_identity_files;	/* Number of files for RSA/DSA identities. */
diff -up openssh-5.3p1/ssh-add.c.nss-keys openssh-5.3p1/ssh-add.c
--- openssh-5.3p1/ssh-add.c.nss-keys	2008-02-28 09:13:52.000000000 +0100
+++ openssh-5.3p1/ssh-add.c	2009-10-02 14:09:01.000000000 +0200
@@ -44,6 +44,14 @@
 #include <openssl/evp.h>
 #include "openbsd-compat/openssl-compat.h"
 
+#ifdef HAVE_LIBNSS
+#include <nss.h>
+#include <secmod.h>
+#include <pk11pub.h>
+#include <keyhi.h>
+#include <cert.h>
+#endif
+
 #include <fcntl.h>
 #include <pwd.h>
 #include <stdarg.h>
@@ -57,6 +65,7 @@
 #include "rsa.h"
 #include "log.h"
 #include "key.h"
+#include "nsskeys.h"
 #include "buffer.h"
 #include "authfd.h"
 #include "authfile.h"
@@ -307,6 +316,128 @@ do_file(AuthenticationConnection *ac, in
 	return 0;
 }
 
+#ifdef HAVE_LIBNSS
+static char *
+password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
+{
+	char **passcache = arg;
+	char *password, *p2 = NULL;
+	char *prompt;
+	
+	if (retry)
+		return NULL;
+	
+	if (asprintf(&prompt, "Enter passphrase for token %s: ",
+		PK11_GetTokenName(slot)) < 0)
+		fatal("password_cb: asprintf failed");
+
+	password = read_passphrase(prompt, RP_ALLOW_STDIN);
+	
+	if (password != NULL && (p2=PL_strdup(password)) == NULL) {
+		memset(password, 0, strlen(password));
+		fatal("password_cb: PL_strdup failed");
+	}
+
+	if (passcache != NULL) {
+		if (*passcache != NULL) {
+			memset(*passcache, 0, strlen(*passcache));
+			xfree(*passcache);
+		}
+		*passcache = password;
+	} else {
+		memset(password, 0, strlen(password));
+		xfree(password);
+	}
+	
+	return p2;
+}
+
+static int
+add_slot_keys(AuthenticationConnection *ac, PK11SlotInfo *slot, int add)
+{
+	SECKEYPrivateKeyList *list;
+	SECKEYPrivateKeyListNode *node;
+	char *passcache = NULL;
+	char *tokenname;
+	char **xkeyname = NULL;
+	
+	int count = 0;
+	int i;
+	
+	if (PK11_NeedLogin(slot))
+		PK11_Authenticate(slot, PR_TRUE, &passcache);
+		
+	if ((list=PK11_ListPrivKeysInSlot(slot, NULL, NULL)) == NULL) {
+		return 0;
+	}
+	
+	tokenname = PK11_GetTokenName(slot);
+	
+	for (node=PRIVKEY_LIST_HEAD(list); !PRIVKEY_LIST_END(node, list);
+		node=PRIVKEY_LIST_NEXT(node)) {
+		char *keyname;
+		SECKEYPublicKey *pub;
+		
+		keyname = PK11_GetPrivateKeyNickname(node->key);
+		if (keyname == NULL || *keyname == '\0') {
+			/* no nickname to refer to */
+			CERTCertificate *cert;
+			char *kn;
+			cert = PK11_GetCertFromPrivateKey(node->key);
+			if (cert == NULL)
+				continue;
+			kn = strchr(cert->nickname, ':');
+			if (kn == NULL)
+				kn = cert->nickname;
+			else
+				kn++;
+			keyname = PORT_Strdup(kn);
+			CERT_DestroyCertificate(cert);
+			if (keyname == NULL)
+				continue;
+		}
+		pub = SECKEY_ConvertToPublicKey(node->key);
+		if (pub == NULL) {
+			fprintf(stderr, "No public key for: %s:%s\n",
+				tokenname, keyname);
+			continue; /* not possible to obtain public key */
+		}
+		SECKEY_DestroyPublicKey(pub);
+	
+		if ((count % 10) == 0)	
+			xkeyname = xrealloc (xkeyname, count + 10, sizeof (char *));
+		
+		xkeyname[count++] = keyname;
+	}
+
+	PK11_Logout(slot);
+
+	for (i = 0; i < count; i++) {
+		if (ssh_update_nss_key(ac, add, tokenname, xkeyname[i],
+			passcache?passcache:"",	lifetime, confirm)) {
+			fprintf(stderr, "Key %s: %s:%s\n",
+				add?"added":"removed", tokenname, xkeyname[i]);
+		} else {
+			fprintf(stderr, "Could not %s key: %s:%s\n",
+				add?"add":"remove", tokenname, xkeyname[i]);
+		}
+		PORT_Free(xkeyname[i]);
+	}
+
+	if (xkeyname != NULL)
+		free (xkeyname);
+
+	if (passcache != NULL) {
+		memset(passcache, 0, strlen(passcache));
+		xfree(passcache);
+	}
+	
+	SECKEY_DestroyPrivateKeyList(list);
+	
+	return count;
+}
+#endif
+
 static void
 usage(void)
 {
@@ -334,6 +465,10 @@ main(int argc, char **argv)
 	AuthenticationConnection *ac = NULL;
 	char *sc_reader_id = NULL;
 	int i, ch, deleting = 0, ret = 0;
+#ifdef HAVE_LIBNSS
+	char *token_id = NULL;
+	int use_nss = 0;
+#endif
 
 	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
 	sanitise_stdfd();
@@ -351,7 +486,7 @@ main(int argc, char **argv)
 		    "Could not open a connection to your authentication agent.\n");
 		exit(2);
 	}
-	while ((ch = getopt(argc, argv, "lLcdDxXe:s:t:")) != -1) {
+	while ((ch = getopt(argc, argv, "lLcdDnxXe:s:t:T:")) != -1) {
 		switch (ch) {
 		case 'l':
 		case 'L':
@@ -373,6 +508,11 @@ main(int argc, char **argv)
 			if (delete_all(ac) == -1)
 				ret = 1;
 			goto done;
+#ifdef HAVE_LIBNSS
+		case 'n':
+			use_nss = 1;
+			break;
+#endif
 		case 's':
 			sc_reader_id = optarg;
 			break;
@@ -387,6 +527,11 @@ main(int argc, char **argv)
 				goto done;
 			}
 			break;
+#ifdef HAVE_LIBNSS
+		case 'T':
+			token_id = optarg;
+			break;
+#endif
 		default:
 			usage();
 			ret = 1;
@@ -400,6 +545,40 @@ main(int argc, char **argv)
 			ret = 1;
 		goto done;
 	}
+#ifdef HAVE_LIBNSS
+	if (use_nss) {
+		PK11SlotList *slots;
+		PK11SlotListElement *sle;
+		int count = 0;
+		if (nss_init(password_cb) == -1) {
+			fprintf(stderr, "Failed to initialize NSS library\n");
+			ret = 1;
+			goto done;
+		}
+		
+		if ((slots=PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE,
+			NULL)) == NULL) {
+			fprintf(stderr, "No tokens found\n");
+			ret = 1;
+			goto nss_done;
+		}
+
+		for (sle = slots->head; sle; sle = sle->next) {
+			int rv;
+			if ((rv=add_slot_keys(ac, sle->slot, !deleting)) == -1) {
+				ret = 1;
+			}
+			count += rv;
+		}
+		if (count == 0) {
+			ret = 1;
+		}
+nss_done:		
+		NSS_Shutdown();
+		clear_pass();
+		goto done;
+	}
+#endif
 	if (argc == 0) {
 		char buf[MAXPATHLEN];
 		struct passwd *pw;
diff -up openssh-5.3p1/ssh-agent.c.nss-keys openssh-5.3p1/ssh-agent.c
--- openssh-5.3p1/ssh-agent.c.nss-keys	2009-06-21 09:50:15.000000000 +0200
+++ openssh-5.3p1/ssh-agent.c	2009-10-02 14:09:01.000000000 +0200
@@ -80,6 +80,10 @@
 #include "scard.h"
 #endif
 
+#ifdef HAVE_LIBNSS
+#include "nsskeys.h"
+#endif
+
 #if defined(HAVE_SYS_PRCTL_H)
 #include <sys/prctl.h>	/* For prctl() and PR_SET_DUMPABLE */
 #endif
@@ -714,6 +718,114 @@ send:
 }
 #endif /* SMARTCARD */
 
+#ifdef HAVE_LIBNSS
+static void
+process_add_nss_key (SocketEntry *e)
+{
+	char *tokenname = NULL, *keyname = NULL, *password = NULL;
+	int i, version, success = 0, death = 0, confirm = 0;
+	Key **keys, *k;
+	Identity *id;
+	Idtab *tab;
+
+	tokenname = buffer_get_string(&e->request, NULL);
+	keyname = buffer_get_string(&e->request, NULL);
+	password = buffer_get_string(&e->request, NULL);
+
+	while (buffer_len(&e->request)) {
+		switch (buffer_get_char(&e->request)) {
+		case SSH_AGENT_CONSTRAIN_LIFETIME:
+			death = time(NULL) + buffer_get_int(&e->request);
+			break;
+		case SSH_AGENT_CONSTRAIN_CONFIRM:
+			confirm = 1;
+			break;
+		default:
+			break;
+		}
+	}
+	if (lifetime && !death)
+		death = time(NULL) + lifetime;
+
+	keys = nss_get_keys(tokenname, keyname, password);
+	/* password is owned by keys[0] now */
+	xfree(tokenname);
+	xfree(keyname);
+
+	if (keys == NULL) {
+		memset(password, 0, strlen(password));
+		xfree(password);
+		error("nss_get_keys failed");
+		goto send;
+	}
+	for (i = 0; keys[i] != NULL; i++) {
+		k = keys[i];
+		version = k->type == KEY_RSA1 ? 1 : 2;
+		tab = idtab_lookup(version);
+		if (lookup_identity(k, version) == NULL) {
+			id = xmalloc(sizeof(Identity));
+			id->key = k;
+			id->comment = nss_get_key_label(k);
+			id->death = death;
+			id->confirm = confirm;
+			TAILQ_INSERT_TAIL(&tab->idlist, id, next);
+			tab->nentries++;
+			success = 1;
+		} else {
+			key_free(k);
+		}
+		keys[i] = NULL;
+	}
+	xfree(keys);
+send:
+	buffer_put_int(&e->output, 1);
+	buffer_put_char(&e->output,
+	    success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+
+static void
+process_remove_nss_key(SocketEntry *e)
+{
+	char *tokenname = NULL, *keyname = NULL, *password = NULL;
+	int i, version, success = 0;
+	Key **keys, *k = NULL;
+	Identity *id;
+	Idtab *tab;
+
+	tokenname = buffer_get_string(&e->request, NULL);
+	keyname = buffer_get_string(&e->request, NULL);
+	password = buffer_get_string(&e->request, NULL);
+
+	keys = nss_get_keys(tokenname, keyname, password);
+	xfree(tokenname);
+	xfree(keyname);
+	xfree(password);
+
+	if (keys == NULL || keys[0] == NULL) {
+		error("nss_get_keys failed");
+		goto send;
+	}
+	for (i = 0; keys[i] != NULL; i++) {
+		k = keys[i];
+		version = k->type == KEY_RSA1 ? 1 : 2;
+		if ((id = lookup_identity(k, version)) != NULL) {
+			tab = idtab_lookup(version);
+			TAILQ_REMOVE(&tab->idlist, id, next);
+			tab->nentries--;
+			free_identity(id);
+			success = 1;
+		}
+		key_free(k);
+		keys[i] = NULL;
+	}
+	xfree(keys);
+send:
+	buffer_put_int(&e->output, 1);
+	buffer_put_char(&e->output,
+	    success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+#endif /* HAVE_LIBNSS */
+
 /* dispatch incoming messages */
 
 static void
@@ -806,6 +918,15 @@ process_message(SocketEntry *e)
 		process_remove_smartcard_key(e);
 		break;
 #endif /* SMARTCARD */
+#ifdef HAVE_LIBNSS
+	case SSH_AGENTC_ADD_NSS_KEY:
+	case SSH_AGENTC_ADD_NSS_KEY_CONSTRAINED:
+		process_add_nss_key(e);
+		break;
+	case SSH_AGENTC_REMOVE_NSS_KEY:
+		process_remove_nss_key(e);
+		break;
+#endif /* SMARTCARD */
 	default:
 		/* Unknown message.  Respond with failure. */
 		error("Unknown message %d", type);
diff -up openssh-5.3p1/ssh.c.nss-keys openssh-5.3p1/ssh.c
--- openssh-5.3p1/ssh.c.nss-keys	2009-07-05 23:16:56.000000000 +0200
+++ openssh-5.3p1/ssh.c	2009-10-02 14:09:01.000000000 +0200
@@ -105,6 +105,9 @@
 #ifdef SMARTCARD
 #include "scard.h"
 #endif
+#ifdef HAVE_LIBNSS
+#include "nsskeys.h"
+#endif
 
 extern char *__progname;
 
@@ -1234,9 +1237,11 @@ load_public_identity_files(void)
 	int i = 0;
 	Key *public;
 	struct passwd *pw;
-#ifdef SMARTCARD
+#if defined(SMARTCARD) || defined(HAVE_LIBNSS)
 	Key **keys;
+#endif
 
+#ifdef SMARTCARD
 	if (options.smartcard_device != NULL &&
 	    options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
 	    (keys = sc_get_keys(options.smartcard_device, NULL)) != NULL) {
@@ -1259,6 +1264,27 @@ load_public_identity_files(void)
 		xfree(keys);
 	}
 #endif /* SMARTCARD */
+#ifdef HAVE_LIBNSS
+	if (options.use_nss &&
+	    options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
+	    (keys = nss_get_keys(options.nss_token, NULL, NULL)) != NULL) {
+		int count;
+		for (count = 0; keys[count] != NULL; count++) {
+			memmove(&options.identity_files[1], &options.identity_files[0],
+			    sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1));
+			memmove(&options.identity_keys[1], &options.identity_keys[0],
+			    sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1));
+			options.num_identity_files++;
+			options.identity_keys[0] = keys[count];
+			options.identity_files[0] = nss_get_key_label(keys[count]);
+		}
+		if (options.num_identity_files > SSH_MAX_IDENTITY_FILES)
+			options.num_identity_files = SSH_MAX_IDENTITY_FILES;
+		i += count;
+		xfree(keys);
+	}
+#endif /* HAVE_LIBNSS */
+
 	if ((pw = getpwuid(original_real_uid)) == NULL)
 		fatal("load_public_identity_files: getpwuid failed");
 	pwname = xstrdup(pw->pw_name);
diff -up openssh-5.3p1/ssh-dss.c.nss-keys openssh-5.3p1/ssh-dss.c
--- openssh-5.3p1/ssh-dss.c.nss-keys	2006-11-07 13:14:42.000000000 +0100
+++ openssh-5.3p1/ssh-dss.c	2009-10-02 14:09:01.000000000 +0200
@@ -39,6 +39,10 @@
 #include "log.h"
 #include "key.h"
 
+#ifdef HAVE_LIBNSS
+#include <cryptohi.h>
+#endif
+
 #define INTBLOB_LEN	20
 #define SIGBLOB_LEN	(2*INTBLOB_LEN)
 
@@ -57,6 +61,34 @@ ssh_dss_sign(const Key *key, u_char **si
 		error("ssh_dss_sign: no DSA key");
 		return -1;
 	}
+#ifdef HAVE_LIBNSS
+	if (key->flags & KEY_FLAG_NSS) {
+		SECItem sigitem;
+		SECItem *rawsig;
+
+		memset(&sigitem, 0, sizeof(sigitem));
+		if (SEC_SignData(&sigitem, (u_char *)data, datalen, key->nss->privk,
+			SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) != SECSuccess) {
+			error("ssh_dss_sign: sign failed");
+			return -1;
+		}
+		
+		if ((rawsig=DSAU_DecodeDerSig(&sigitem)) == NULL) {
+			error("ssh_dss_sign: der decode failed");
+			SECITEM_ZfreeItem(&sigitem, PR_FALSE);
+			return -1;
+		}
+		SECITEM_ZfreeItem(&sigitem, PR_FALSE);
+		if (rawsig->len != SIGBLOB_LEN) {
+			error("ssh_dss_sign: unsupported signature length %d",
+				rawsig->len);
+			SECITEM_ZfreeItem(rawsig, PR_TRUE);
+			return -1;
+		}
+		memcpy(sigblob, rawsig->data, SIGBLOB_LEN);
+		SECITEM_ZfreeItem(rawsig, PR_TRUE);
+	} else {
+#endif
 	EVP_DigestInit(&md, evp_md);
 	EVP_DigestUpdate(&md, data, datalen);
 	EVP_DigestFinal(&md, digest, &dlen);
@@ -80,7 +112,9 @@ ssh_dss_sign(const Key *key, u_char **si
 	BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);
 	BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);
 	DSA_SIG_free(sig);
-
+#ifdef HAVE_LIBNSS
+	}
+#endif
 	if (datafellows & SSH_BUG_SIGBLOB) {
 		if (lenp != NULL)
 			*lenp = SIGBLOB_LEN;
diff -up openssh-5.3p1/ssh-keygen.c.nss-keys openssh-5.3p1/ssh-keygen.c
--- openssh-5.3p1/ssh-keygen.c.nss-keys	2009-06-22 08:11:07.000000000 +0200
+++ openssh-5.3p1/ssh-keygen.c	2009-10-02 14:09:01.000000000 +0200
@@ -53,6 +53,11 @@
 #include "scard.h"
 #endif
 
+#ifdef HAVE_LIBNSS
+#include <nss.h>
+#include "nsskeys.h"
+#endif
+
 /* Number of bits in the RSA/DSA key.  This value can be set on the command line. */
 #define DEFAULT_BITS		2048
 #define DEFAULT_BITS_DSA	1024
@@ -501,6 +506,26 @@ do_download(struct passwd *pw, const cha
 }
 #endif /* SMARTCARD */
 
+#ifdef HAVE_LIBNSS
+static void
+do_nss_download(struct passwd *pw, const char *tokenname, const char *keyname)
+{
+	Key **keys = NULL;
+	int i;
+	
+	keys = nss_get_keys(tokenname, keyname, NULL);
+	if (keys == NULL)
+		fatal("cannot find public key in NSS");
+	for (i = 0; keys[i]; i++) {
+		key_write(keys[i], stdout);
+		key_free(keys[i]);
+		fprintf(stdout, "\n");
+	}
+	xfree(keys);
+	exit(0);
+}
+#endif /* HAVE_LIBNSS */
+
 static void
 do_fingerprint(struct passwd *pw)
 {
@@ -1083,7 +1108,8 @@ main(int argc, char **argv)
 	Key *private, *public;
 	struct passwd *pw;
 	struct stat st;
-	int opt, type, fd, download = 0;
+	int opt, type, fd, download = 1;
+	int use_nss = 0;
 	u_int32_t memory = 0, generator_wanted = 0, trials = 100;
 	int do_gen_candidates = 0, do_screen_candidates = 0;
 	BIGNUM *start = NULL;
@@ -1116,7 +1142,7 @@ main(int argc, char **argv)
 	}
 
 	while ((opt = getopt(argc, argv,
-	    "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) {
+	    "degiqpclnBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) {
 		switch (opt) {
 		case 'b':
 			bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr);
@@ -1156,6 +1182,10 @@ main(int argc, char **argv)
 		case 'g':
 			print_generic = 1;
 			break;
+		case 'n':
+			use_nss = 1;
+			download = 1;
+			break;
 		case 'P':
 			identity_passphrase = optarg;
 			break;
@@ -1187,10 +1217,10 @@ main(int argc, char **argv)
 		case 't':
 			key_type_name = optarg;
 			break;
-		case 'D':
-			download = 1;
-			/*FALLTHROUGH*/
 		case 'U':
+			download = 0;
+			/*FALLTHROUGH*/
+		case 'D':
 			reader_id = optarg;
 			break;
 		case 'v':
@@ -1299,6 +1329,17 @@ main(int argc, char **argv)
 			exit(0);
 		}
 	}
+
+	if (use_nss) {
+#ifdef HAVE_LIBNSS
+		if (download)
+			do_nss_download(pw, reader_id, identity_file);
+		else
+			fatal("no support for NSS key upload.");
+#else
+		fatal("no support for NSS keys.");
+#endif
+	}
 	if (reader_id != NULL) {
 #ifdef SMARTCARD
 		if (download)
diff -up openssh-5.3p1/ssh-rsa.c.nss-keys openssh-5.3p1/ssh-rsa.c
--- openssh-5.3p1/ssh-rsa.c.nss-keys	2006-09-01 07:38:37.000000000 +0200
+++ openssh-5.3p1/ssh-rsa.c	2009-10-02 14:09:01.000000000 +0200
@@ -32,6 +32,10 @@
 #include "compat.h"
 #include "ssh.h"
 
+#ifdef HAVE_LIBNSS
+#include <cryptohi.h>
+#endif
+
 static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *);
 
 /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
@@ -50,6 +54,38 @@ ssh_rsa_sign(const Key *key, u_char **si
 		error("ssh_rsa_sign: no RSA key");
 		return -1;
 	}
+
+	slen = RSA_size(key->rsa);
+	sig = xmalloc(slen);
+
+#ifdef HAVE_LIBNSS
+	if (key->flags & KEY_FLAG_NSS) {
+		SECItem sigitem;
+		SECOidTag alg;
+
+		memset(&sigitem, 0, sizeof(sigitem));
+		alg = (datafellows & SSH_BUG_RSASIGMD5) ?
+			SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION :
+			SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
+
+		if (SEC_SignData(&sigitem, (u_char *)data, datalen, key->nss->privk,
+			alg) != SECSuccess) {
+			error("ssh_rsa_sign: sign failed");
+			return -1;
+		}
+		if (sigitem.len > slen) {
+			error("ssh_rsa_sign: slen %u slen2 %u", slen, sigitem.len);
+			xfree(sig);
+			SECITEM_ZfreeItem(&sigitem, PR_FALSE);
+			return -1;
+		}
+		if (sigitem.len < slen) {
+			memset(sig, 0, slen - sigitem.len);
+		}
+		memcpy(sig+slen-sigitem.len, sigitem.data, sigitem.len);
+		SECITEM_ZfreeItem(&sigitem, PR_FALSE);
+	} else {
+#endif
 	nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
 	if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
 		error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid);
@@ -59,9 +95,6 @@ ssh_rsa_sign(const Key *key, u_char **si
 	EVP_DigestUpdate(&md, data, datalen);
 	EVP_DigestFinal(&md, digest, &dlen);
 
-	slen = RSA_size(key->rsa);
-	sig = xmalloc(slen);
-
 	ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa);
 	memset(digest, 'd', sizeof(digest));
 
@@ -83,6 +116,9 @@ ssh_rsa_sign(const Key *key, u_char **si
 		xfree(sig);
 		return -1;
 	}
+#ifdef HAVE_LIBNSS
+	}
+#endif
 	/* encode signature */
 	buffer_init(&b);
 	buffer_put_cstring(&b, "ssh-rsa");
diff -up /dev/null openssh-5.2p1/README.nss
--- /dev/null	2008-11-17 17:51:52.160001870 +0100
+++ openssh-5.2p1/README.nss	2008-11-18 19:11:41.000000000 +0100
@@ -0,0 +1,36 @@
+How to use NSS tokens with OpenSSH?
+
+This version of OpenSSH contains experimental support for authentication using
+keys stored in tokens stored in NSS database. This for example includes any
+PKCS#11 tokens which are installed in your NSS database.
+
+As the code is experimental and preliminary only SSH protocol 2 is supported.
+The NSS certificate and token databases are looked for in the ~/.ssh
+directory or in a directory specified by environment variable NSS_DB_PATH.
+
+Common operations:
+
+(1) tell the ssh client to use the NSS keys:
+
+	$ ssh -o 'UseNSS yes' otherhost
+	
+	if you want to use a specific token:
+	
+	$ ssh -o 'UseNSS yes' -o 'NSS Token My PKCS11 Token' otherhost
+
+(2) or tell the agent to use the NSS keys:
+
+	$ ssh-add -n
+	
+	if you want to use a specific token:
+	
+	$ ssh-add -n -T 'My PKCS11 Token'
+
+(3) extract the public key from token so it can be added to the
+server:
+
+	$ ssh-keygen -n
+	
+	if you want to use a specific token and/or key:
+	
+	$ ssh-keygen -n -D 'My PKCS11 Token' 'My Key ID'

openssh-5.3p1-pka.patch:
 auth2-pubkey.c |  159 +++++++++++++++++++++++++++++++++++++++++++++++++++------
 configure      |   22 +++++++
 configure.ac   |   13 ++++
 servconf.c     |   26 +++++++++
 servconf.h     |    2 
 sshd_config    |    2 
 sshd_config.0  |   20 +++++--
 sshd_config.5  |   13 ++++
 8 files changed, 237 insertions(+), 20 deletions(-)

--- NEW FILE openssh-5.3p1-pka.patch ---
diff -up openssh-5.3p1/auth2-pubkey.c.pka openssh-5.3p1/auth2-pubkey.c
--- openssh-5.3p1/auth2-pubkey.c.pka	2009-10-15 06:26:25.000000000 +0200
+++ openssh-5.3p1/auth2-pubkey.c	2009-10-15 06:44:32.000000000 +0200
@@ -184,26 +184,14 @@ done:
 
 /* return 1 if user allows given key */
 static int
-user_key_allowed2(struct passwd *pw, Key *key, char *file)
+user_search_key_in_file(FILE *f, char *file, Key* key, struct passwd *pw)
 {
 	char line[SSH_MAX_PUBKEY_BYTES];
 	int found_key = 0;
-	FILE *f;
 	u_long linenum = 0;
 	Key *found;
 	char *fp;
 
-	/* Temporarily use the user's uid. */
-	temporarily_use_uid(pw);
-
-	debug("trying public key file %s", file);
-	f = auth_openkeyfile(file, pw, options.strict_modes);
-
-	if (!f) {
-		restore_uid();
-		return 0;
-	}
-
 	found_key = 0;
 	found = key_new(key->type);
 
@@ -248,21 +236,160 @@ user_key_allowed2(struct passwd *pw, Key
 			break;
 		}
 	}
-	restore_uid();
-	fclose(f);
 	key_free(found);
 	if (!found_key)
 		debug2("key not found");
 	return found_key;
 }
 
-/* check whether given key is in .ssh/authorized_keys* */
+
+/* return 1 if user allows given key */
+static int
+user_key_allowed2(struct passwd *pw, Key *key, char *file)
+{
+	FILE *f;
+	int found_key = 0;
+
+	/* Temporarily use the user's uid. */
+	temporarily_use_uid(pw);
+
+	debug("trying public key file %s", file);
+	f = auth_openkeyfile(file, pw, options.strict_modes);
+
+ 	if (f) {
+ 		found_key = user_search_key_in_file (f, file, key, pw);
+		fclose(f);
+	}
+
+	restore_uid();
+	return found_key;
+}
+
+#ifdef WITH_PUBKEY_AGENT
+
+#define WHITESPACE " \t\r\n"
+
+/* return 1 if user allows given key */
+static int
+user_key_via_agent_allowed2(struct passwd *pw, Key *key)
+{
+	FILE *f;
+	int found_key = 0;
+	char *pubkey_agent_string = NULL;
+	char *tmp_pubkey_agent_string = NULL;
+	char *progname;
+	char *cp;
+	struct passwd *runas_pw;
+	struct stat st;
+
+	if (options.pubkey_agent == NULL || options.pubkey_agent[0] != '/')
+		return -1;
+
+	/* get the run as identity from config */
+	runas_pw = (options.pubkey_agent_runas == NULL)? pw
+	    : getpwnam (options.pubkey_agent_runas);
+	if (!runas_pw) {
+		error("%s: getpwnam(\"%s\"): %s", __func__,
+		    options.pubkey_agent_runas, strerror(errno));
+		return 0;
+	}
+
+	/* Temporarily use the specified uid. */
+	if (runas_pw->pw_uid != 0)
+		temporarily_use_uid(runas_pw);
+
+	pubkey_agent_string = percent_expand(options.pubkey_agent,
+	    "h", pw->pw_dir, "u", pw->pw_name, (char *)NULL);
+
+	/* Test whether agent can be modified by non root user */
+	tmp_pubkey_agent_string = xstrdup (pubkey_agent_string);
+	progname = strtok (tmp_pubkey_agent_string, WHITESPACE);
+
+	debug3("%s: checking program '%s'", __func__, progname);
+
+	if (stat (progname, &st) < 0) {
+		error("%s: stat(\"%s\"): %s", __func__,
+		    progname, strerror(errno));
+		goto go_away;
+	}
+
+	if (st.st_uid != 0 || (st.st_mode & 022) != 0) {
+		error("bad ownership or modes for pubkey agent \"%s\"",
+		    progname);
+		goto go_away;
+	}
+
+	if (!S_ISREG(st.st_mode)) {
+		error("pubkey agent \"%s\" is not a regular file",
+		    progname);
+		goto go_away;
+	}
+
+	/*
+	 * Descend the path, checking that each component is a
+	 * root-owned directory with strict permissions.
+	 */
+	do {
+		if ((cp = strrchr(progname, '/')) == NULL)
+			break;
+		else 
+			*cp = '\0';
+	
+		debug3("%s: checking component '%s'", __func__, progname);
+
+		if (stat(progname, &st) != 0) {
+			error("%s: stat(\"%s\"): %s", __func__,
+			    progname, strerror(errno));
+			goto go_away;
+		}
+		if (st.st_uid != 0 || (st.st_mode & 022) != 0) {
+			error("bad ownership or modes for pubkey agent path component \"%s\"",
+			    progname);
+			goto go_away;
+		}
+		if (!S_ISDIR(st.st_mode)) {
+			error("pubkey agent path component \"%s\" is not a directory",
+			    progname);
+			goto go_away;
+		}
+	} while (0);
+
+	/* open the pipe and read the keys */
+	f = popen (pubkey_agent_string, "r");
+	if (!f) {
+		error("%s: popen (\"%s\", \"r\"): %s", __func__,
+		    pubkey_agent_string, strerror (errno));
+		goto go_away;
+	}
+
+	found_key = user_search_key_in_file (f, options.pubkey_agent, key, pw);
+	pclose (f);
+
+go_away:
+	if (tmp_pubkey_agent_string)
+		xfree (tmp_pubkey_agent_string);
+	if (pubkey_agent_string)
+		xfree (pubkey_agent_string);
+
+	if (runas_pw->pw_uid != 0)
+		restore_uid();
+	return found_key;
+}
+#endif
+
+/* check whether given key is in <pkey_agent or .ssh/authorized_keys* */
 int
 user_key_allowed(struct passwd *pw, Key *key)
 {
 	int success;
 	char *file;
 
+#ifdef WITH_PUBKEY_AGENT
+	success = user_key_via_agent_allowed2(pw, key);
+	if (success >= 0)
+		return success;
+#endif
+
 	file = authorized_keys_file(pw);
 	success = user_key_allowed2(pw, key, file);
 	xfree(file);
diff -up openssh-5.3p1/configure.ac.pka openssh-5.3p1/configure.ac
--- openssh-5.3p1/configure.ac.pka	2009-10-15 06:26:25.000000000 +0200
+++ openssh-5.3p1/configure.ac	2009-10-15 06:26:26.000000000 +0200
@@ -1319,6 +1319,18 @@ AC_ARG_WITH(audit,
 	esac ]
 )
 
+# Check whether user wants pubkey agent support
+PKA_MSG="no"
+AC_ARG_WITH(pka,
+	[  --with-pka      Enable pubkey agent support],
+	[
+		if test "x$withval" != "xno" ; then
+			AC_DEFINE([WITH_PUBKEY_AGENT], 1, [Enable pubkey agent support])
+			PKA_MSG="yes"
+		fi
+	]
+)
+
 dnl    Checks for library functions. Please keep in alphabetical order
 AC_CHECK_FUNCS( \
 	arc4random \
@@ -4264,6 +4276,7 @@ echo "               Linux audit support
 echo "                 Smartcard support: $SCARD_MSG"
 echo "                     S/KEY support: $SKEY_MSG"
 echo "              TCP Wrappers support: $TCPW_MSG"
+echo "                       PKA support: $PKA_MSG"
 echo "              MD5 password support: $MD5_MSG"
 echo "                   libedit support: $LIBEDIT_MSG"
 echo "  Solaris process contract support: $SPC_MSG"
diff -up openssh-5.3p1/configure.pka openssh-5.3p1/configure
--- openssh-5.3p1/configure.pka	2009-10-13 19:27:51.000000000 +0200
+++ openssh-5.3p1/configure	2009-10-15 06:26:33.000000000 +0200
@@ -769,6 +769,7 @@ with_skey
 with_tcp_wrappers
 with_libedit
 with_audit
+with_pka
 with_ssl_dir
 with_openssl_header_check
 with_ssl_engine
@@ -1473,6 +1474,7 @@ Optional Packages:
   --with-tcp-wrappers[=PATH] Enable tcpwrappers support (optionally in PATH)
   --with-libedit[=PATH]   Enable libedit support for sftp
   --with-audit=module     Enable EXPERIMENTAL audit support (modules=debug,bsm)
+  --with-pka      Enable pubkey agent support
   --with-ssl-dir=PATH     Specify path to OpenSSL installation
   --without-openssl-header-check Disable OpenSSL version consistency check
   --with-ssl-engine       Enable OpenSSL (hardware) ENGINE support
@@ -13443,6 +13445,25 @@ $as_echo "$as_me: error: Unknown audit m
 fi
 
 
+# Check whether user wants pubkey agent support
+PKA_MSG="no"
+
+# Check whether --with-pka was given.
+if test "${with_pka+set}" = set; then
+  withval=$with_pka;
+		if test "x$withval" != "xno" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define WITH_PUBKEY_AGENT 1
+_ACEOF
+
+			PKA_MSG="yes"
+		fi
+
+
+fi
+
+
 
 
 
@@ -32772,6 +32793,7 @@ echo "               Linux audit support
 echo "                 Smartcard support: $SCARD_MSG"
 echo "                     S/KEY support: $SKEY_MSG"
 echo "              TCP Wrappers support: $TCPW_MSG"
+echo "                       PKA support: $PKA_MSG"
 echo "              MD5 password support: $MD5_MSG"
 echo "                   libedit support: $LIBEDIT_MSG"
 echo "  Solaris process contract support: $SPC_MSG"
diff -up openssh-5.3p1/servconf.c.pka openssh-5.3p1/servconf.c
--- openssh-5.3p1/servconf.c.pka	2009-10-15 06:26:24.000000000 +0200
+++ openssh-5.3p1/servconf.c	2009-10-15 06:26:26.000000000 +0200
@@ -128,6 +128,8 @@ initialize_server_options(ServerOptions 
 	options->num_permitted_opens = -1;
 	options->adm_forced_command = NULL;
 	options->chroot_directory = NULL;
+	options->pubkey_agent = NULL;
+	options->pubkey_agent_runas = NULL;
 	options->zero_knowledge_password_authentication = -1;
 }
 
@@ -310,6 +312,7 @@ typedef enum {
 	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
 	sUsePrivilegeSeparation, sAllowAgentForwarding,
 	sZeroKnowledgePasswordAuthentication,
+	sPubkeyAgent, sPubkeyAgentRunAs,
 	sDeprecated, sUnsupported
 } ServerOpCodes;
 
@@ -429,6 +432,13 @@ static struct {
 	{ "permitopen", sPermitOpen, SSHCFG_ALL },
 	{ "forcecommand", sForceCommand, SSHCFG_ALL },
 	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
+#ifdef WITH_PUBKEY_AGENT
+	{ "pubkeyagent", sPubkeyAgent, SSHCFG_ALL },
+	{ "pubkeyagentrunas", sPubkeyAgentRunAs, SSHCFG_ALL },
+#else
+	{ "pubkeyagent", sUnsupported, SSHCFG_ALL },
+	{ "pubkeyagentrunas", sUnsupported, SSHCFG_ALL },
+#endif
 	{ NULL, sBadOption, 0 }
 };
 
@@ -1303,6 +1313,16 @@ process_server_config_line(ServerOptions
 			*charptr = xstrdup(arg);
 		break;
 
+	case sPubkeyAgent:
+		len = strspn(cp, WHITESPACE);
+		if (*activep && options->pubkey_agent == NULL)
+			options->pubkey_agent = xstrdup(cp + len);
+		return 0;
+
+	case sPubkeyAgentRunAs:
+		charptr = &options->pubkey_agent_runas;
+		break;
+
 	case sDeprecated:
 		logit("%s line %d: Deprecated option %s",
 		    filename, linenum, arg);
@@ -1396,6 +1416,8 @@ copy_set_server_options(ServerOptions *d
 	M_CP_INTOPT(gss_authentication);
 	M_CP_INTOPT(rsa_authentication);
 	M_CP_INTOPT(pubkey_authentication);
+	M_CP_STROPT(pubkey_agent);
+	M_CP_STROPT(pubkey_agent_runas);
 	M_CP_INTOPT(kerberos_authentication);
 	M_CP_INTOPT(hostbased_authentication);
 	M_CP_INTOPT(kbd_interactive_authentication);
@@ -1636,6 +1658,10 @@ dump_config(ServerOptions *o)
 	dump_cfg_string(sAuthorizedKeysFile, o->authorized_keys_file);
 	dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2);
 	dump_cfg_string(sForceCommand, o->adm_forced_command);
+#ifdef WITH_PUBKEY_AGENT
+	dump_cfg_string(sPubkeyAgent, o->pubkey_agent);
+	dump_cfg_string(sPubkeyAgentRunAs, o->pubkey_agent_runas);
+#endif
 
 	/* string arguments requiring a lookup */
 	dump_cfg_string(sLogLevel, log_level_name(o->log_level));
diff -up openssh-5.3p1/servconf.h.pka openssh-5.3p1/servconf.h
--- openssh-5.3p1/servconf.h.pka	2009-10-15 06:26:24.000000000 +0200
+++ openssh-5.3p1/servconf.h	2009-10-15 06:26:26.000000000 +0200
@@ -152,6 +152,8 @@ typedef struct {
 	int	num_permitted_opens;
 
 	char   *chroot_directory;
+	char   *pubkey_agent;
+	char   *pubkey_agent_runas;
 }       ServerOptions;
 
 void	 initialize_server_options(ServerOptions *);
diff -up openssh-5.3p1/sshd_config.0.pka openssh-5.3p1/sshd_config.0
--- openssh-5.3p1/sshd_config.0.pka	2009-10-15 06:26:24.000000000 +0200
+++ openssh-5.3p1/sshd_config.0	2009-10-15 06:26:26.000000000 +0200
@@ -344,10 +344,11 @@ DESCRIPTION
              AllowTcpForwarding, Banner, ChrootDirectory, ForceCommand,
              GatewayPorts, GSSAPIAuthentication, HostbasedAuthentication,
              KbdInteractiveAuthentication, KerberosAuthentication,
-             MaxAuthTries, MaxSessions, PasswordAuthentication,
-             PermitEmptyPasswords, PermitOpen, PermitRootLogin,
-             RhostsRSAAuthentication, RSAAuthentication, X11DisplayOffset,
-             X11Forwarding and X11UseLocalHost.
+             MaxAuthTries, MaxSessions, PubkeyAuthentication, PubkeyAgent,
+             PubkeyAgentRunAs, PasswordAuthentication, PermitEmptyPasswords,
+             PermitOpen, PermitRootLogin, RhostsRSAAuthentication,
+             RSAAuthentication, X11DisplayOffset, X11Forwarding and
+             X11UseLocalHost.
 
      MaxAuthTries
              Specifies the maximum number of authentication attempts permitted
@@ -455,6 +456,17 @@ DESCRIPTION
              fault is ``yes''.  Note that this option applies to protocol ver-
              sion 2 only.
 
+     PubkeyAgent
+             Specifies which agent is used for lookup of the user's public
+             keys. Empty string means to use the authorized_keys file.  By
+             default there is no PubkeyAgent set.  Note that this option has
+             an effect only with PubkeyAuthentication switched on.
+
+     PubkeyAgentRunAs
+             Specifies the user under whose account the PubkeyAgent is run.
+             Empty string (the default value) means the user being authorized
+             is used.
+
      RhostsRSAAuthentication
              Specifies whether rhosts or /etc/hosts.equiv authentication to-
              gether with successful RSA host authentication is allowed.  The
diff -up openssh-5.3p1/sshd_config.5.pka openssh-5.3p1/sshd_config.5
--- openssh-5.3p1/sshd_config.5.pka	2009-10-15 06:26:24.000000000 +0200
+++ openssh-5.3p1/sshd_config.5	2009-10-15 06:26:26.000000000 +0200
@@ -610,6 +610,9 @@ Available keywords are
 .Cm KerberosAuthentication ,
 .Cm MaxAuthTries ,
 .Cm MaxSessions ,
+.Cm PubkeyAuthentication ,
+.Cm PubkeyAgent ,
+.Cm PubkeyAgentRunAs ,
 .Cm PasswordAuthentication ,
 .Cm PermitEmptyPasswords ,
 .Cm PermitOpen ,
@@ -805,6 +808,16 @@ Specifies whether public key authenticat
 The default is
 .Dq yes .
 Note that this option applies to protocol version 2 only.
+.It Cm PubkeyAgent
+Specifies which agent is used for lookup of the user's public
+keys. Empty string means to use the authorized_keys file.
+By default there is no PubkeyAgent set.
+Note that this option has an effect only with PubkeyAuthentication
+switched on.
+.It Cm PubkeyAgentRunAs
+Specifies the user under whose account the PubkeyAgent is run. Empty
+string (the default value) means the user being authorized is used.
+.Dq 
 .It Cm RhostsRSAAuthentication
 Specifies whether rhosts or /etc/hosts.equiv authentication together
 with successful RSA host authentication is allowed.
diff -up openssh-5.3p1/sshd_config.pka openssh-5.3p1/sshd_config
--- openssh-5.3p1/sshd_config.pka	2009-10-15 06:26:24.000000000 +0200
+++ openssh-5.3p1/sshd_config	2009-10-15 06:26:26.000000000 +0200
@@ -47,6 +47,8 @@ SyslogFacility AUTHPRIV
 #RSAAuthentication yes
 #PubkeyAuthentication yes
 #AuthorizedKeysFile	.ssh/authorized_keys
+#PubkeyAgent none
+#PubkeyAgentRunAs nobody
 
 # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
 #RhostsRSAAuthentication no

openssh-5.3p1-selabel.patch:
 Makefile.in         |    2 +-
 contrib/ssh-copy-id |    2 +-
 ssh.c               |   10 ++++++++--
 3 files changed, 10 insertions(+), 4 deletions(-)

--- NEW FILE openssh-5.3p1-selabel.patch ---
diff -up openssh-5.3p1/contrib/ssh-copy-id.selabel openssh-5.3p1/contrib/ssh-copy-id
--- openssh-5.3p1/contrib/ssh-copy-id.selabel	2009-01-21 10:29:21.000000000 +0100
+++ openssh-5.3p1/contrib/ssh-copy-id	2009-10-02 14:21:54.000000000 +0200
@@ -38,7 +38,7 @@ if [ "$#" -lt 1 ] || [ "$1" = "-h" ] || 
   exit 1
 fi
 
-{ eval "$GET_ID" ; } | ssh $1 "umask 077; test -d .ssh || mkdir .ssh ; cat >> .ssh/authorized_keys" || exit 1
+{ eval "$GET_ID" ; } | ssh $1 "umask 077; test -d .ssh || mkdir .ssh ; cat >> .ssh/authorized_keys; test -x /sbin/restorecon && /sbin/restorecon .ssh .ssh/authorized_keys" || exit 1
 
 cat <<EOF
 Now try logging into the machine, with "ssh '$1'", and check in:
diff -up openssh-5.3p1/Makefile.in.selabel openssh-5.3p1/Makefile.in
--- openssh-5.3p1/Makefile.in.selabel	2009-10-02 14:21:54.000000000 +0200
+++ openssh-5.3p1/Makefile.in	2009-10-02 14:23:23.000000000 +0200
@@ -136,7 +136,7 @@ libssh.a: $(LIBSSH_OBJS)
 	$(RANLIB) $@
 
 ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS)
-	$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
+	$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck -lselinux $(LIBS)
 
 sshd$(EXEEXT): libssh.a	$(LIBCOMPAT) $(SSHDOBJS)
 	$(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHDLIBS) $(LIBS)
diff -up openssh-5.3p1/ssh.c.selabel openssh-5.3p1/ssh.c
--- openssh-5.3p1/ssh.c.selabel	2009-10-02 14:21:54.000000000 +0200
+++ openssh-5.3p1/ssh.c	2009-10-02 14:21:54.000000000 +0200
@@ -74,6 +74,7 @@
 #include <openssl/err.h>
 #include <openssl/fips.h>
 #include <fipscheck.h>
+#include <selinux/selinux.h>
 #include "openbsd-compat/openssl-compat.h"
 #include "openbsd-compat/sys-queue.h"
 
@@ -792,10 +793,15 @@ main(int ac, char **av)
 	 */
 	r = snprintf(buf, sizeof buf, "%s%s%s", pw->pw_dir,
 	    strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR);
-	if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0)
+	if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0) {
+		char *scon;
+
+		matchpathcon(buf, 0700, &scon);
+		setfscreatecon(scon);
 		if (mkdir(buf, 0700) < 0)
 			error("Could not create directory '%.200s'.", buf);
-
+		setfscreatecon(NULL);
+	}
 	/* load options.identity_files */
 	load_public_identity_files();
 

openssh-5.3p1-skip-initial.patch:
 auth1.c      |    2 +-
 auth2-none.c |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

--- NEW FILE openssh-5.3p1-skip-initial.patch ---
diff -up openssh-5.3p1/auth1.c.skip-initial openssh-5.3p1/auth1.c
--- openssh-5.3p1/auth1.c.skip-initial	2009-03-08 01:40:28.000000000 +0100
+++ openssh-5.3p1/auth1.c	2009-10-02 13:55:00.000000000 +0200
@@ -244,7 +244,7 @@ do_authloop(Authctxt *authctxt)
 	    authctxt->valid ? "" : "invalid user ", authctxt->user);
 
 	/* If the user has no password, accept authentication immediately. */
-	if (options.password_authentication &&
+	if (options.permit_empty_passwd && options.password_authentication &&
 #ifdef KRB5
 	    (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
 #endif
diff -up openssh-5.3p1/auth2-none.c.skip-initial openssh-5.3p1/auth2-none.c
--- openssh-5.3p1/auth2-none.c.skip-initial	2009-03-08 01:40:28.000000000 +0100
+++ openssh-5.3p1/auth2-none.c	2009-10-02 13:56:21.000000000 +0200
@@ -61,7 +61,7 @@ userauth_none(Authctxt *authctxt)
 {
 	none_enabled = 0;
 	packet_check_eom();
-	if (options.password_authentication)
+	if (options.permit_empty_passwd && options.password_authentication)
 		return (PRIVSEP(auth_password(authctxt, "")));
 	return (0);
 }


--- NEW FILE pam_ssh_agent-rmheaders ---
atomicio.h
authfd.h
buffer.h
cipher.h
compat.h
defines.h
entropy.h
includes.h
kex.h
key.h
log.h
match.h
misc.h
pathnames.h
platform.h
rsa.h
ssh.h
ssh2.h
uuencode.h
xmalloc.h

pam_ssh_agent_auth-0.9-build.patch:
 Makefile.in                |   12 ++---
 iterate_ssh_agent_keys.c   |  102 ++++++++++++++++++++++++++++++++++++++++++++-
 pam_user_authorized_keys.c |    2 
 3 files changed, 108 insertions(+), 8 deletions(-)

--- NEW FILE pam_ssh_agent_auth-0.9-build.patch ---
diff -up pam_ssh_agent_auth-0.9/iterate_ssh_agent_keys.c.psaa-build pam_ssh_agent_auth-0.9/iterate_ssh_agent_keys.c
--- pam_ssh_agent_auth-0.9/iterate_ssh_agent_keys.c.psaa-build	2009-08-08 11:51:04.000000000 +0200
+++ pam_ssh_agent_auth-0.9/iterate_ssh_agent_keys.c	2009-10-16 15:20:55.000000000 +0200
@@ -41,7 +41,16 @@
 #include "buffer.h"
 #include "key.h"
 #include "authfd.h"
+#include "ssh.h"
 #include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <openssl/evp.h>
 
 #include "userauth_pubkey_from_id.h"
@@ -73,6 +82,96 @@ session_id2_gen()
     return cookie;
 }
 
+/* 
+ * Added by Jamie Beverly, ensure socket fd points to a socket owned by the user 
+ * A cursory check is done, but to avoid race conditions, it is necessary 
+ * to drop effective UID when connecting to the socket. 
+ *
+ * If the cause of error is EACCES, because we verified we would not have that 
+ * problem initially, we can safely assume that somebody is attempting to find a 
+ * race condition; so a more "direct" log message is generated.
+ */
+
+int
+ssh_get_authentication_socket_for_uid(uid_t uid)
+{
+	const char *authsocket;
+	int sock;
+	struct sockaddr_un sunaddr;
+	struct stat sock_st;
+
+	authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
+	if (!authsocket)
+		return -1;
+
+	/* Advisory only; seteuid ensures no race condition; but will only log if we see EACCES */
+	if( stat(authsocket,&sock_st) == 0) {
+		if(uid != 0 && sock_st.st_uid != uid) {
+			fatal("uid %lu attempted to open an agent socket owned by uid %lu", (unsigned long) uid, (unsigned long) sock_st.st_uid);
+			return -1;
+		}
+	}
+
+	/* 
+	 * Ensures that the EACCES tested for below can _only_ happen if somebody 
+	 * is attempting to race the stat above to bypass authentication.
+	 */
+	if( (sock_st.st_mode & S_IWUSR) != S_IWUSR || (sock_st.st_mode & S_IRUSR) != S_IRUSR) {
+		error("ssh-agent socket has incorrect permissions for owner");
+		return -1;
+	}
+
+	sunaddr.sun_family = AF_UNIX;
+	strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
+
+	sock = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (sock < 0)
+		return -1;
+
+	/* close on exec */
+	if (fcntl(sock, F_SETFD, 1) == -1) {
+		close(sock);
+		return -1;
+	}
+
+	errno = 0; 
+	seteuid(uid); /* To ensure a race condition is not used to circumvent the stat
+	             above, we will temporarily drop UID to the caller */
+	if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) {
+		close(sock);
+        if(errno == EACCES)
+		fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid);
+		return -1;
+	}
+
+	seteuid(0); /* we now continue the regularly scheduled programming */
+
+	return sock;
+}
+
+AuthenticationConnection *
+ssh_get_authentication_connection_for_uid(uid_t uid)
+{
+	AuthenticationConnection *auth;
+	int sock;
+
+	sock = ssh_get_authentication_socket_for_uid(uid);
+
+	/*
+	 * Fail if we couldn't obtain a connection.  This happens if we
+	 * exited due to a timeout.
+	 */
+	if (sock < 0)
+		return NULL;
+
+	auth = xmalloc(sizeof(*auth));
+	auth->fd = sock;
+	buffer_init(&auth->identities);
+	auth->howmany = 0;
+
+	return auth;
+}
+
 int
 find_authorized_keys(uid_t uid)
 {
@@ -85,7 +184,7 @@ find_authorized_keys(uid_t uid)
     OpenSSL_add_all_digests();
     session_id2 = session_id2_gen();
 
-    if ((ac = ssh_get_authentication_connection(uid))) {
+    if ((ac = ssh_get_authentication_connection_for_uid(uid))) {
         verbose("Contacted ssh-agent of user %s (%u)", getpwuid(uid)->pw_name, uid);
         for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) 
         {
@@ -113,3 +212,4 @@ find_authorized_keys(uid_t uid)
     EVP_cleanup();
     return retval;
 }
+
diff -up pam_ssh_agent_auth-0.9/Makefile.in.psaa-build pam_ssh_agent_auth-0.9/Makefile.in
--- pam_ssh_agent_auth-0.9/Makefile.in.psaa-build	2009-08-06 07:40:16.000000000 +0200
+++ pam_ssh_agent_auth-0.9/Makefile.in	2009-10-16 15:20:55.000000000 +0200
@@ -28,7 +28,7 @@ PATHS=
 CC=@CC@
 LD=@LD@
 CFLAGS=@CFLAGS@
-CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@
+CPPFLAGS=-I.. -I$(srcdir) -I/usr/include/nss3 -I/usr/include/nspr4 @CPPFLAGS@ $(PATHS) @DEFS@
 LIBS=@LIBS@
 AR=@AR@
 AWK=@AWK@
@@ -37,7 +37,7 @@ INSTALL=@INSTALL@
 PERL=@PERL@
 SED=@SED@
 ENT=@ENT@
-LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@
+LDFLAGS=-L.. -L../openbsd-compat/ @LDFLAGS@
 LDFLAGS_SHARED = @LDFLAGS_SHARED@
 EXEEXT=@EXEEXT@
 
@@ -48,7 +48,7 @@ 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
 
-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
+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
 
 
 MANPAGES_IN	= pam_ssh_agent_auth.pod
@@ -67,13 +67,13 @@ $(PAM_MODULES): Makefile.in config.h
 .c.o:
 	$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
 
-LIBCOMPAT=openbsd-compat/libopenbsd-compat.a
+LIBCOMPAT=../openbsd-compat/libopenbsd-compat.a
 $(LIBCOMPAT): always
 	(cd openbsd-compat && $(MAKE))
 always:
 
-pam_ssh_agent_auth.so: $(LIBCOMPAT) $(SSHOBJS) $(PAM_SSH_AGENT_AUTH_OBJS)  pam_ssh_agent_auth.o
-	$(LD) $(LDFLAGS_SHARED) -o $@ $(SSHOBJS) $(PAM_SSH_AGENT_AUTH_OBJS) $(LDFLAGS) -lopenbsd-compat $(LIBS) -lpam pam_ssh_agent_auth.o
+pam_ssh_agent_auth.so: $(PAM_SSH_AGENT_AUTH_OBJS)  pam_ssh_agent_auth.o
+	$(LD) $(LDFLAGS_SHARED) -o $@ $(PAM_SSH_AGENT_AUTH_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -lpam -lnss3 pam_ssh_agent_auth.o
 
 $(MANPAGES): $(MANPAGES_IN)
 	pod2man --section=8 --release=v0.8 --name=pam_ssh_agent_auth --official --center "PAM" pam_ssh_agent_auth.pod > pam_ssh_agent_auth.8
diff -up pam_ssh_agent_auth-0.9/pam_user_authorized_keys.c.psaa-build pam_ssh_agent_auth-0.9/pam_user_authorized_keys.c
--- pam_ssh_agent_auth-0.9/pam_user_authorized_keys.c.psaa-build	2009-07-29 02:46:38.000000000 +0200
+++ pam_ssh_agent_auth-0.9/pam_user_authorized_keys.c	2009-10-16 15:50:36.000000000 +0200
@@ -94,7 +94,7 @@ parse_authorized_key_file(const char *us
     /*
      * temporary copy, so that both tilde expansion and percent expansion both get to apply to the path
      */
-    strncat(auth_keys_file_buf, authorized_keys_file_input, 4096);
+    strncat(auth_keys_file_buf, authorized_keys_file_input, sizeof(auth_keys_file_buf)-1);
 
     if(allow_user_owned_authorized_keys_file)
         authorized_keys_file_allowed_owner_uid = getpwnam(user)->pw_uid;


Index: openssh.spec
===================================================================
RCS file: /cvs/pkgs/rpms/openssh/F-12/openssh.spec,v
retrieving revision 1.172
retrieving revision 1.173
diff -u -p -r1.172 -r1.173
--- openssh.spec	2 Nov 2009 12:56:26 -0000	1.172
+++ openssh.spec	20 Nov 2009 17:01:48 -0000	1.173
@@ -32,6 +32,9 @@
 # Whether or not /sbin/nologin exists.
 %define nologin 1
 
+# Whether to build pam_ssh_agent_auth
+%define pam_ssh_agent 1
+
 # Reserve options to override askpass settings with:
 # rpm -ba|--rebuild --define 'skip_xxx 1'
 %{?skip_gnome_askpass:%define no_gnome_askpass 1}
@@ -58,13 +61,17 @@
 %if %{rescue}
 %define kerberos5 0
 %define libedit 0
+%define pam_ssh_agent 0
 %endif
 
+%define pam_ssh_agent_ver 0.9
+
 Summary: An open source implementation of SSH protocol versions 1 and 2
 Name: openssh
-Version: 5.2p1
-Release: 31%{?dist}%{?rescue_rel}
+Version: 5.3p1
+Release: 9%{?dist}%{?rescue_rel}
 URL: http://www.openssh.com/portable.html
+#URL1: http://pamsshauth.sourceforge.net
 #Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz
 #Source1: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz.asc
 # This package differs from the upstream OpenSSH tarball in that
@@ -74,13 +81,15 @@ Source0: openssh-%{version}-noacss.tar.b
 Source1: openssh-nukeacss.sh
 Source2: sshd.pam
 Source3: sshd.init
+Source4: http://prdownloads.sourceforge.net/pamsshagentauth/pam_ssh_agent_auth/pam_ssh_agent_auth-%{pam_ssh_agent_ver}.tar.bz2
+Source5: pam_ssh_agent-rmheaders
 Patch0: openssh-5.2p1-redhat.patch
-Patch2: openssh-5.1p1-skip-initial.patch
-Patch3: openssh-3.8.1p1-krb5-config.patch
+Patch2: openssh-5.3p1-skip-initial.patch
 Patch4: openssh-5.2p1-vendor.patch
+Patch10: pam_ssh_agent_auth-0.9-build.patch
 Patch12: openssh-5.2p1-selinux.patch
-Patch13: openssh-5.1p1-mls.patch
-Patch16: openssh-4.7p1-audit.patch
+Patch13: openssh-5.3p1-mls.patch
+Patch16: openssh-5.3p1-audit.patch
 Patch18: openssh-5.0p1-pam_selinux.patch
 Patch19: openssh-5.2p1-sesftp.patch
 Patch22: openssh-3.9p1-askpass-keep-above.patch
@@ -92,13 +101,14 @@ Patch38: openssh-4.3p2-askpass-grab-info
 Patch39: openssh-4.3p2-no-v6only.patch
 Patch44: openssh-5.2p1-allow-ip-opts.patch
 Patch49: openssh-4.3p2-gssapi-canohost.patch
-Patch51: openssh-5.2p1-nss-keys.patch
+Patch51: openssh-5.3p1-nss-keys.patch
 Patch55: openssh-5.1p1-cloexec.patch
 Patch62: openssh-5.1p1-scp-manpage.patch
-Patch65: openssh-5.2p1-fips.patch
-Patch68: openssh-5.2p1-pathmax.patch
-Patch69: openssh-5.2p1-selabel.patch
+Patch65: openssh-5.3p1-fips.patch
+Patch69: openssh-5.3p1-selabel.patch
 Patch71: openssh-5.2p1-edns.patch
+Patch72: openssh-5.3p1-pka.patch
+Patch73: openssh-5.3p1-gsskex.patch
 
 License: BSD
 Group: Applications/Internet
@@ -170,6 +180,14 @@ Requires: openssh = %{version}-%{release
 Obsoletes: openssh-askpass-gnome
 Provides: openssh-askpass-gnome
 
+%package -n pam_ssh_agent_auth
+Summary: PAM module for authentication with ssh-agent
+Group: System Environment/Base
+Version: %{pam_ssh_agent_ver}
+# There is special exception added to the GPLv3+ license to
+# permit linking with OpenSSL licensed code
+License: GPLv3+ and OpenSSL and BSD
+
 %description
 SSH (Secure SHell) is a program for logging into and executing
 commands on a remote machine. SSH is intended to replace rlogin and
@@ -200,13 +218,28 @@ OpenSSH is a free version of SSH (Secure
 into and executing commands on a remote machine. This package contains
 an X11 passphrase dialog for OpenSSH.
 
+%description -n pam_ssh_agent_auth
+This package contains a PAM module which can be used to authenticate
+users using ssh keys stored in a ssh-agent. Through the use of the
+forwarding of ssh-agent connection it also allows to authenticate with
+remote ssh-agent instance.
+
+The module is most useful for su and sudo service stacks.
+
 %prep
-%setup -q
+%setup -q -a 4
 %patch0 -p1 -b .redhat
 %patch2 -p1 -b .skip-initial
-%patch3 -p1 -b .krb5-config
 %patch4 -p1 -b .vendor
 
+%if %{pam_ssh_agent}
+pushd pam_ssh_agent_auth-%{pam_ssh_agent_ver}
+%patch10 -p1 -b .psaa-build
+# Remove duplicate headers
+rm -f $(cat %{SOURCE5})
+popd
+%endif
+
 %if %{WITH_SELINUX}
 #SELinux
 %patch12 -p1 -b .selinux
@@ -229,9 +262,10 @@ an X11 passphrase dialog for OpenSSH.
 %patch55 -p1 -b .cloexec
 %patch62 -p1 -b .manpage
 %patch65 -p1 -b .fips
-%patch68 -p1 -b .pathmax
 %patch69 -p1 -b .selabel
 %patch71 -p1 -b .edns
+%patch72 -p1 -b .pka
+%patch73 -p1 -b .gsskex
 
 autoreconf
 
@@ -242,11 +276,12 @@ CFLAGS="$CFLAGS -Os"
 %endif
 %if %{pie}
 %ifarch s390 s390x sparc sparcv9 sparc64
-CFLAGS="$CFLAGS -fPIE"
+CFLAGS="$CFLAGS -fPIC"
 %else
-CFLAGS="$CFLAGS -fpie"
+CFLAGS="$CFLAGS -fpic"
 %endif
 export CFLAGS
+SAVE_LDFLAGS="$LDFLAGS"
 LDFLAGS="$LDFLAGS -pie"; export LDFLAGS
 %endif
 %if %{kerberos5}
@@ -326,6 +361,14 @@ fi
 popd
 %endif
 
+%if %{pam_ssh_agent}
+pushd pam_ssh_agent_auth-%{pam_ssh_agent_ver}
+LDFLAGS="$SAVE_LDFLAGS"
+%configure --with-selinux --libexecdir=/%{_lib}/security
+make
+popd
+%endif
+
 # Add generation of HMAC checksums of the final stripped binaries
 %define __spec_install_post \
     %{?__debug_package:%{__debug_install_post}} \
@@ -375,6 +418,12 @@ rm -f README.nss.nss-keys
 %if ! %{nss}
 rm -f README.nss
 %endif
+
+%if %{pam_ssh_agent}
+pushd pam_ssh_agent_auth-%{pam_ssh_agent_ver}
+make install DESTDIR=$RPM_BUILD_ROOT
+popd
+%endif
 %clean
 rm -rf $RPM_BUILD_ROOT
 
@@ -465,14 +514,42 @@ fi
 %attr(0755,root,root) %{_libexecdir}/openssh/ssh-askpass
 %endif
 
+%if %{pam_ssh_agent}
+%files -n pam_ssh_agent_auth
+%defattr(-,root,root)
+%doc pam_ssh_agent_auth-%{pam_ssh_agent_ver}/GPL_LICENSE
+%doc pam_ssh_agent_auth-%{pam_ssh_agent_ver}/OPENSSH_LICENSE
+%doc pam_ssh_agent_auth-%{pam_ssh_agent_ver}/LICENSE.OpenSSL
+%attr(0755,root,root) /%{_lib}/security/pam_ssh_agent_auth.so
+%attr(0644,root,root) %{_mandir}/man8/pam_ssh_agent_auth.8*
+%endif
+
 %changelog
-* Mon Nov  2 2009 Jan F. Chadima <jchadima at redhat.com> - 5.2p1-31
+* Fri Nov 20 2009 Jan F. Chadima <jchadima at redhat.com> - 5.3p1-8
+- Add gssapi key exchange patch (#455351)
+
+* Fri Nov 20 2009 Jan F. Chadima <jchadima at redhat.com> - 5.3p1-8
+- Add public key agent patch (#455350)
+
+* Mon Nov  2 2009 Jan F. Chadima <jchadima at redhat.com> - 5.3p1-7
 - Repair canohost patch to allow gssapi to work when host is acessed via pipe proxy (#531849)
 
-* Thu Oct 29 2009 Jan F. Chadima <jchadima at redhat.com> - 5.2p1-30
+* Thu Oct 29 2009 Jan F. Chadima <jchadima at redhat.com> - 5.3p1-6
 - Modify the init script to prevent it to hang during generating the keys (#515145)
 
-* Tue Oct 27 2009 Jan F. Chadima <jchadima at redhat.com> - 5.2p1-29
+* Tue Oct 27 2009 Jan F. Chadima <jchadima at redhat.com> - 5.3p1-5
+- Add README.nss
+
+* Mon Oct 19 2009 Tomas Mraz <tmraz at redhat.com> - 5.3p1-4
+- Add pam_ssh_agent_auth module to a subpackage.
+
+* Fri Oct 16 2009 Jan F. Chadima <jchadima at redhat.com> - 5.3p1-3
+- Reenable audit.
+
+* Fri Oct  2 2009 Jan F. Chadima <jchadima at redhat.com> - 5.3p1-2
+- Upgrade to new wersion 5.3p1
+
+* Tue Sep 29 2009 Jan F. Chadima <jchadima at redhat.com> - 5.2p1-29
 - Resolve locking in ssh-add (#491312)
 
 * Thu Sep 24 2009 Jan F. Chadima <jchadima at redhat.com> - 5.2p1-28


Index: sources
===================================================================
RCS file: /cvs/pkgs/rpms/openssh/F-12/sources,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -p -r1.24 -r1.25
--- sources	10 Mar 2009 12:21:29 -0000	1.24
+++ sources	20 Nov 2009 17:01:48 -0000	1.25
@@ -1 +1,2 @@
-41c61b5e2c2cddfd53897582b114ffe1  openssh-5.2p1-noacss.tar.bz2
+89f85c1da83c24ca0b10c05344f7c93c  openssh-5.3p1-noacss.tar.bz2
+1868cb825393678489b1d48c97819f76  pam_ssh_agent_auth-0.9.tar.bz2


--- openssh-3.8.1p1-krb5-config.patch DELETED ---


--- openssh-4.7p1-audit.patch DELETED ---


--- openssh-5.1p1-mls.patch DELETED ---


--- openssh-5.1p1-skip-initial.patch DELETED ---


--- openssh-5.2p1-fips.patch DELETED ---


--- openssh-5.2p1-nss-keys.patch DELETED ---


--- openssh-5.2p1-pathmax.patch DELETED ---


--- openssh-5.2p1-selabel.patch DELETED ---




More information about the scm-commits mailing list