[gsi-openssh/el6] Change package name gsissh → gsi-openssh Based on openssh-5.3p1-52.el6_1.2

Mattias Ellert ellert at fedoraproject.org
Thu Nov 17 19:30:39 UTC 2011


commit 16d39817519e0908ebe28f6e98e19af9005d349d
Author: Mattias Ellert <mattias.ellert at fysast.uu.se>
Date:   Thu Nov 17 19:56:13 2011 +0100

    Change package name gsissh → gsi-openssh
    Based on openssh-5.3p1-52.el6_1.2

 .gitignore                                  |    1 +
 README.sshd-and-gsisshd                     |   12 +
 gsi-openssh.spec                            |  457 +++++
 gsisshd.init                                |  235 +++
 gsisshd.old.pam                             |   13 +
 gsisshd.sysconfig                           |   16 +
 openssh-3.9p1-askpass-keep-above.patch      |   11 +
 openssh-4.0p1-exit-deadlock.patch           |   13 +
 openssh-4.3p1-fromto-remote.patch           |   15 +
 openssh-4.3p2-askpass-grab-info.patch       |   18 +
 openssh-4.3p2-gssapi-canohost.patch         |   25 +
 openssh-4.3p2-no-v6only.patch               |   11 +
 openssh-5.0p1-pam_selinux.patch             |  156 ++
 openssh-5.1p1-askpass-progress.patch        |   79 +
 openssh-5.1p1-cloexec.patch                 |   87 +
 openssh-5.1p1-log-in-chroot.patch           |  116 ++
 openssh-5.1p1-scp-manpage.patch             |   18 +
 openssh-5.2p1-allow-ip-opts.patch           |   37 +
 openssh-5.2p1-edns.patch                    |   72 +
 openssh-5.2p1-redhat.patch                  |   99 +
 openssh-5.2p1-selinux.patch                 |  394 ++++
 openssh-5.2p1-sesftp.patch                  |   64 +
 openssh-5.2p1-vendor.patch                  |  158 ++
 openssh-5.3p1-595935.patch                  |   22 +
 openssh-5.3p1-audit.patch                   | 2472 ++++++++++++++++++++++
 openssh-5.3p1-authorized-keys-command.patch |  435 ++++
 openssh-5.3p1-biguid.patch                  |   99 +
 openssh-5.3p1-clientloop.patch              |   12 +
 openssh-5.3p1-engine.patch                  |    9 +
 openssh-5.3p1-entropy.patch                 |  244 +++
 openssh-5.3p1-fips.patch                    |  695 +++++++
 openssh-5.3p1-gsissh.patch                  | 2950 +++++++++++++++++++++++++++
 openssh-5.3p1-gsskex.patch                  | 2930 ++++++++++++++++++++++++++
 openssh-5.3p1-keycat.patch                  |  371 ++++
 openssh-5.3p1-kuserok.patch                 |  167 ++
 openssh-5.3p1-ldap.patch                    | 2587 +++++++++++++++++++++++
 openssh-5.3p1-mls.patch                     |  445 ++++
 openssh-5.3p1-multiple-sighup.patch         |   11 +
 openssh-5.3p1-nss-keys.patch                | 1627 +++++++++++++++
 openssh-5.3p1-randclean.patch               |   13 +
 openssh-5.3p1-selabel.patch                 |   55 +
 openssh-5.3p1-sftp-chroot.patch             |  205 ++
 openssh-5.3p1-sftp_umask.patch              |   68 +
 openssh-5.3p1-skip-initial.patch            |   24 +
 openssh-5.3p1-stderr.patch                  |  157 ++
 openssh-5.3p1-strictalias.patch             |   12 +
 openssh-5.3p1-unblock-signals.patch         |   76 +
 openssh-5.3p1-x11.patch                     |   54 +
 openssh-nukeacss.sh                         |   19 +
 sources                                     |    1 +
 50 files changed, 17867 insertions(+), 0 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index e69de29..e931757 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/*.tar.bz2
diff --git a/README.sshd-and-gsisshd b/README.sshd-and-gsisshd
new file mode 100644
index 0000000..15f6d87
--- /dev/null
+++ b/README.sshd-and-gsisshd
@@ -0,0 +1,12 @@
+The regular sshd daemon and the gsi enabled gsisshd daemon can not
+both listen for connections on the same port.
+
+You can either deactivate the regular sshd before starting gsisshd or
+change the configuration of gsisshd to use a different port than the
+standard ssh port number 22. Common choices for an alternative port
+number are 23, 222 or 2222.
+
+If you configure gsisshd to only accept gsi connections and not accept
+other types of connections that require the existence of the ssh host
+keys, you can turn off the generation of these keys in
+/etc/sysconfig/gsisshd.
diff --git a/gsi-openssh.spec b/gsi-openssh.spec
new file mode 100644
index 0000000..f01c52d
--- /dev/null
+++ b/gsi-openssh.spec
@@ -0,0 +1,457 @@
+# gsissh is openssh with support for GSI authentication
+# This gsissh specfile is based on the openssh specfile
+
+# Do we want SELinux & Audit
+%global WITH_SELINUX 1
+
+# OpenSSH privilege separation requires a user & group ID
+%global sshd_uid    74
+%global sshd_gid    74
+
+# Build position-independent executables (requires toolchain support)?
+%global pie 1
+
+# Do we want kerberos5 support (1=yes 0=no)
+# It is not possible to support kerberos5 and GSI at the same time
+%global kerberos5 0
+
+# Do we want GSI support (1=yes 0=no)
+%global gsi 1
+
+# Do we want LDAP support
+%global ldap 1
+
+# Do we want libedit support
+%global libedit 1
+
+# Do we want NSS tokens support
+%global nss 1
+
+# Whether or not /sbin/nologin exists.
+%global nologin 1
+
+Summary: An implementation of the SSH protocol with GSI authentication
+Name: gsi-openssh
+Version: 5.3p1
+Release: 3%{?dist}
+Provides: gsissh = %{version}-%{release}
+Obsoletes: gsissh < 5.3p1-3
+URL: http://www.openssh.com/portable.html
+#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
+# the ACSS cipher is removed by running openssh-nukeacss.sh in
+# the unpacked source directory.
+Source0: openssh-%{version}-noacss.tar.bz2
+Source1: openssh-nukeacss.sh
+Source2: gsisshd.old.pam
+Source3: gsisshd.init
+Source7: gsisshd.sysconfig
+Source99: README.sshd-and-gsisshd
+Patch0: openssh-5.2p1-redhat.patch
+Patch2: openssh-5.3p1-skip-initial.patch
+Patch4: openssh-5.2p1-vendor.patch
+Patch5: openssh-5.3p1-engine.patch
+Patch12: openssh-5.2p1-selinux.patch
+Patch13: openssh-5.3p1-mls.patch
+Patch18: openssh-5.0p1-pam_selinux.patch
+Patch19: openssh-5.2p1-sesftp.patch
+Patch22: openssh-3.9p1-askpass-keep-above.patch
+Patch24: openssh-4.3p1-fromto-remote.patch
+Patch27: openssh-5.1p1-log-in-chroot.patch
+Patch30: openssh-4.0p1-exit-deadlock.patch
+Patch35: openssh-5.1p1-askpass-progress.patch
+Patch38: openssh-4.3p2-askpass-grab-info.patch
+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.3p1-nss-keys.patch
+Patch55: openssh-5.1p1-cloexec.patch
+Patch62: openssh-5.1p1-scp-manpage.patch
+Patch65: openssh-5.3p1-fips.patch
+Patch69: openssh-5.3p1-selabel.patch
+Patch71: openssh-5.2p1-edns.patch
+Patch73: openssh-5.3p1-gsskex.patch
+Patch74: openssh-5.3p1-randclean.patch
+Patch75: openssh-5.3p1-strictalias.patch
+Patch76: openssh-5.3p1-595935.patch
+Patch77: openssh-5.3p1-x11.patch
+Patch78: openssh-5.3p1-authorized-keys-command.patch
+Patch79: openssh-5.3p1-stderr.patch
+Patch80: openssh-5.3p1-audit.patch
+Patch81: openssh-5.3p1-biguid.patch
+Patch82: openssh-5.3p1-kuserok.patch
+Patch83: openssh-5.3p1-sftp_umask.patch
+Patch84: openssh-5.3p1-clientloop.patch
+Patch85: openssh-5.3p1-ldap.patch
+Patch86: openssh-5.3p1-keycat.patch
+Patch87: openssh-5.3p1-sftp-chroot.patch
+Patch88: openssh-5.3p1-entropy.patch
+Patch89: openssh-5.3p1-multiple-sighup.patch
+
+# This is the patch that adds GSI support
+# Based on http://grid.ncsa.illinois.edu/ssh/dl/patch/openssh-5.3p1.patch
+Patch98: openssh-5.3p1-gsissh.patch
+
+# The gsissh server has problems with blocked signals in threaded globus libs
+# This patch from OSG resolves these problems
+Patch99: openssh-5.3p1-unblock-signals.patch
+
+License: BSD
+Group: Applications/Internet
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+%if %{nologin}
+Requires: /sbin/nologin
+%endif
+
+Requires: initscripts >= 5.20
+
+BuildRequires: autoconf, automake, perl, zlib-devel
+BuildRequires: audit-libs-devel >= 2.0.5
+BuildRequires: util-linux, groff, man
+BuildRequires: pam-devel
+BuildRequires: tcp_wrappers-devel
+BuildRequires: fipscheck-devel
+BuildRequires: openssl-devel >= 0.9.8j
+%if %{ldap}
+BuildRequires: openldap-devel
+%endif
+
+%if %{kerberos5}
+BuildRequires: krb5-devel
+%endif
+
+%if %{gsi}
+BuildRequires: globus-gss-assist-devel
+BuildRequires: globus-usage-devel
+%endif
+
+%if %{libedit}
+BuildRequires: libedit-devel ncurses-devel
+%endif
+
+%if %{nss}
+BuildRequires: nss-devel
+%endif
+
+%if %{WITH_SELINUX}
+Requires: libselinux >= 1.27.7
+BuildRequires: libselinux-devel >= 1.27.7
+Requires: audit-libs >= 1.0.8
+BuildRequires: audit-libs >= 1.0.8
+%endif
+
+BuildRequires: xauth
+
+%package clients
+Summary: SSH client applications with GSI authentication
+Requires: %{name} = %{version}-%{release}
+Provides: gsissh-clients = %{version}-%{release}
+Obsoletes: gsissh-clients < 5.3p1-3
+Group: Applications/Internet
+
+%package server
+Summary: SSH server daemon with GSI authentication
+Provides: gsissh-server = %{version}-%{release}
+Obsoletes: gsissh-server < 5.3p1-3
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+Requires(post): chkconfig >= 0.9, /sbin/service
+Requires(pre): /usr/sbin/useradd
+Requires: pam >= 1.0.1-3
+
+%description
+SSH (Secure SHell) is a program for logging into and executing
+commands on a remote machine. SSH is intended to replace rlogin and
+rsh, and to provide secure encrypted communications between two
+untrusted hosts over an insecure network. X11 connections and
+arbitrary TCP/IP ports can also be forwarded over the secure channel.
+
+OpenSSH is OpenBSD's version of the last free version of SSH, bringing
+it up to date in terms of security and features.
+
+This version of OpenSSH has been modified to support GSI authentication.
+
+This package includes the core files necessary for both the gsissh
+client and server. To make this package useful, you should also
+install gsi-openssh-clients, gsi-openssh-server, or both.
+
+%description clients
+OpenSSH is a free version of SSH (Secure SHell), a program for logging
+into and executing commands on a remote machine. This package includes
+the clients necessary to make encrypted connections to SSH servers.
+
+This version of OpenSSH has been modified to support GSI authentication.
+
+%description server
+OpenSSH is a free version of SSH (Secure SHell), a program for logging
+into and executing commands on a remote machine. This package contains
+the secure shell daemon (sshd). The sshd daemon allows SSH clients to
+securely connect to your SSH server.
+
+This version of OpenSSH has been modified to support GSI authentication.
+
+%prep
+%setup -q -n openssh-%{version}
+%patch0 -p1 -b .redhat
+%patch2 -p1 -b .skip-initial
+%patch4 -p1 -b .vendor
+%patch5 -p1 -b .engine
+
+%if %{WITH_SELINUX}
+#SELinux
+%patch12 -p1 -b .selinux
+%patch13 -p1 -b .mls
+%patch18 -p1 -b .pam_selinux
+%patch19 -p1 -b .sesftp
+%endif
+
+%patch22 -p1 -b .keep-above
+%patch24 -p1 -b .fromto-remote
+%patch27 -p1 -b .log-chroot
+%patch30 -p1 -b .exit-deadlock
+%patch35 -p1 -b .progress
+%patch38 -p1 -b .grab-info
+%patch39 -p1 -b .no-v6only
+%patch44 -p1 -b .ip-opts
+%patch49 -p1 -b .canohost
+%patch51 -p1 -b .nss-keys
+%patch55 -p1 -b .cloexec
+%patch62 -p1 -b .manpage
+%patch65 -p1 -b .fips
+%patch69 -p1 -b .selabel
+%patch71 -p1 -b .edns
+%patch73 -p1 -b .gsskex
+%patch74 -p1 -b .randclean
+%patch75 -p1 -b .strictalias
+%patch76 -p1 -b .bz595935
+%patch77 -p1 -b .x11
+%patch78 -p1 -b .akc
+%patch79 -p1 -b .stderr
+%patch80 -p1 -b .audit
+%patch81 -p1 -b .biguid
+%patch82 -p1 -b .kuserok
+%patch83 -p1 -b .sftp-umask
+%patch84 -p1 -b .clientloop
+%if %{ldap}
+%patch85 -p1 -b .ldap
+%endif
+%patch86 -p1 -b .keycat
+%patch87 -p1 -b .sftp-chroot
+%patch88 -p1 -b .entropy
+%patch89 -p1 -b .multiple-sighhup
+%patch98 -p1 -b .gsi
+%patch99 -p1 -b .signals
+
+sed 's/sshd.pid/gsisshd.pid/' -i pathnames.h
+sed 's!$(piddir)/sshd.pid!$(piddir)/gsisshd.pid!' -i Makefile.in
+
+cp -p %{SOURCE99} .
+
+autoreconf
+
+%build
+CFLAGS="$RPM_OPT_FLAGS"; export CFLAGS
+%if %{pie}
+%ifarch s390 s390x sparc sparcv9 sparc64
+CFLAGS="$CFLAGS -fPIC"
+%else
+CFLAGS="$CFLAGS -fpic"
+%endif
+export CFLAGS
+LDFLAGS="$LDFLAGS -pie"; export LDFLAGS
+LDFLAGS="$LDFLAGS -Wl,-z,relro -Wl,-z,now"; export LDFLAGS
+%endif
+%if %{kerberos5}
+if test -r /etc/profile.d/krb5-devel.sh ; then
+	source /etc/profile.d/krb5-devel.sh
+fi
+krb5_prefix=`krb5-config --prefix`
+if test "$krb5_prefix" != "%{_prefix}" ; then
+	CPPFLAGS="$CPPFLAGS -I${krb5_prefix}/include -I${krb5_prefix}/include/gssapi"; export CPPFLAGS
+	CFLAGS="$CFLAGS -I${krb5_prefix}/include -I${krb5_prefix}/include/gssapi"
+	LDFLAGS="$LDFLAGS -L${krb5_prefix}/%{_lib}"; export LDFLAGS
+else
+	krb5_prefix=
+	CPPFLAGS="-I%{_includedir}/gssapi"; export CPPFLAGS
+	CFLAGS="$CFLAGS -I%{_includedir}/gssapi"
+fi
+%endif
+
+%configure \
+	--sysconfdir=%{_sysconfdir}/gsissh \
+	--libexecdir=%{_libexecdir}/gsissh \
+	--datadir=%{_datadir}/gsissh \
+	--with-tcp-wrappers \
+	--with-default-path=/usr/local/bin:/bin:/usr/bin \
+	--with-superuser-path=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin \
+	--with-privsep-path=%{_var}/empty/gsisshd \
+	--enable-vendor-patchlevel="FC-%{version}-%{release}" \
+	--disable-strip \
+	--without-zlib-version-check \
+	--with-ssl-engine \
+	--with-authorized-keys-command \
+%if %{ldap}
+	--with-ldap \
+%endif
+%if %{nss}
+	--with-nss \
+%endif
+	--with-pam \
+%if %{WITH_SELINUX}
+	--with-selinux --with-audit=linux \
+%endif
+%if %{kerberos5}
+	--with-kerberos5${krb5_prefix:+=${krb5_prefix}} \
+%else
+	--without-kerberos5 \
+%endif
+%if %{gsi}
+	--with-gsi \
+%else
+	--without-gsi \
+%endif
+%if %{libedit}
+	--with-libedit
+%else
+	--without-libedit
+%endif
+
+make SSH_PROGRAM=%{_bindir}/gsissh \
+     ASKPASS_PROGRAM=%{_libexecdir}/openssh/ssh-askpass
+
+# Add generation of HMAC checksums of the final stripped binaries
+%define __spec_install_post \
+    %{?__debug_package:%{__debug_install_post}} \
+    %{__arch_install_post} \
+    %{__os_install_post} \
+    fipshmac $RPM_BUILD_ROOT%{_bindir}/gsissh \
+    fipshmac $RPM_BUILD_ROOT%{_sbindir}/gsisshd \
+%{nil}
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p -m755 $RPM_BUILD_ROOT%{_sysconfdir}/gsissh
+mkdir -p -m755 $RPM_BUILD_ROOT%{_libexecdir}/gsissh
+mkdir -p -m755 $RPM_BUILD_ROOT%{_var}/empty/gsisshd
+make install DESTDIR=$RPM_BUILD_ROOT
+%if %{ldap}
+rm -f $RPM_BUILD_ROOT%{_sysconfdir}/gsissh/ldap.conf
+%endif
+
+install -d $RPM_BUILD_ROOT/etc/pam.d/
+install -d $RPM_BUILD_ROOT/etc/sysconfig/
+install -d $RPM_BUILD_ROOT/etc/rc.d/init.d
+install -d $RPM_BUILD_ROOT%{_libexecdir}/gsissh
+install -m644 %{SOURCE2} $RPM_BUILD_ROOT/etc/pam.d/gsisshd
+install -m755 %{SOURCE3} $RPM_BUILD_ROOT/etc/rc.d/init.d/gsisshd
+install -m644 %{SOURCE7} $RPM_BUILD_ROOT/etc/sysconfig/gsisshd
+
+rm $RPM_BUILD_ROOT%{_bindir}/ssh-add
+rm $RPM_BUILD_ROOT%{_bindir}/ssh-agent
+rm $RPM_BUILD_ROOT%{_bindir}/ssh-keyscan
+rm $RPM_BUILD_ROOT%{_libexecdir}/gsissh/ssh-keycat
+rm $RPM_BUILD_ROOT%{_libexecdir}/gsissh/ssh-ldap-helper
+rm $RPM_BUILD_ROOT%{_libexecdir}/gsissh/ssh-ldap-wrapper
+rm $RPM_BUILD_ROOT%{_mandir}/man1/ssh-add.1*
+rm $RPM_BUILD_ROOT%{_mandir}/man1/ssh-agent.1*
+rm $RPM_BUILD_ROOT%{_mandir}/man1/ssh-keyscan.1*
+rm $RPM_BUILD_ROOT%{_mandir}/man5/ssh-ldap.conf.5*
+rm $RPM_BUILD_ROOT%{_mandir}/man8/ssh-ldap-helper.8*
+rm $RPM_BUILD_ROOT%{_datadir}/gsissh/Ssh.bin
+
+for f in $RPM_BUILD_ROOT%{_bindir}/* \
+	 $RPM_BUILD_ROOT%{_sbindir}/* \
+	 $RPM_BUILD_ROOT%{_mandir}/man*/* ; do
+    mv $f `dirname $f`/gsi`basename $f`
+done
+ln -sf gsissh $RPM_BUILD_ROOT%{_bindir}/gsislogin
+ln -sf gsissh.1 $RPM_BUILD_ROOT%{_mandir}/man1/gsislogin.1
+
+perl -pi -e "s|$RPM_BUILD_ROOT||g" $RPM_BUILD_ROOT%{_mandir}/man*/*
+
+rm -f README.nss.nss-keys
+%if ! %{nss}
+rm -f README.nss
+%endif
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%pre server
+getent group sshd >/dev/null || groupadd -g %{sshd_uid} -r sshd || :
+%if %{nologin}
+getent passwd sshd >/dev/null || \
+  useradd -c "Privilege-separated SSH" -u %{sshd_uid} -g sshd \
+  -s /sbin/nologin -r -d /var/empty/sshd sshd 2> /dev/null || :
+%else
+getent passwd sshd >/dev/null || \
+  useradd -c "Privilege-separated SSH" -u %{sshd_uid} -g sshd \
+  -s /dev/null -r -d /var/empty/sshd sshd 2> /dev/null || :
+%endif
+
+%post server
+/sbin/chkconfig --add gsisshd
+
+%postun server
+/sbin/service gsisshd condrestart > /dev/null 2>&1 || :
+
+%preun server
+if [ "$1" = 0 ]
+then
+	/sbin/service gsisshd stop > /dev/null 2>&1 || :
+	/sbin/chkconfig --del gsisshd
+fi
+
+%files
+%defattr(-,root,root)
+%doc CREDITS ChangeLog INSTALL LICENCE LICENSE.globus_usage OVERVIEW PROTOCOL* README* TODO WARNING*
+%attr(0755,root,root) %dir %{_sysconfdir}/gsissh
+%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/gsissh/moduli
+%attr(0755,root,root) %{_bindir}/gsissh-keygen
+%attr(0644,root,root) %{_mandir}/man1/gsissh-keygen.1*
+%attr(0755,root,root) %dir %{_libexecdir}/gsissh
+%attr(4755,root,root) %{_libexecdir}/gsissh/ssh-keysign
+%attr(0644,root,root) %{_mandir}/man8/gsissh-keysign.8*
+
+%files clients
+%defattr(-,root,root)
+%attr(0755,root,root) %{_bindir}/gsissh
+%attr(0644,root,root) %{_bindir}/.gsissh.hmac
+%attr(0644,root,root) %{_mandir}/man1/gsissh.1*
+%attr(0755,root,root) %{_bindir}/gsiscp
+%attr(0644,root,root) %{_mandir}/man1/gsiscp.1*
+%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/gsissh/ssh_config
+%attr(0755,root,root) %{_bindir}/gsislogin
+%attr(0644,root,root) %{_mandir}/man1/gsislogin.1*
+%attr(0644,root,root) %{_mandir}/man5/gsissh_config.5*
+%attr(0755,root,root) %{_bindir}/gsisftp
+%attr(0644,root,root) %{_mandir}/man1/gsisftp.1*
+
+%files server
+%defattr(-,root,root)
+%dir %attr(0711,root,root) %{_var}/empty/gsisshd
+%attr(0755,root,root) %{_sbindir}/gsisshd
+%attr(0644,root,root) %{_sbindir}/.gsisshd.hmac
+%attr(0755,root,root) %{_libexecdir}/gsissh/sftp-server
+%attr(0644,root,root) %{_mandir}/man5/gsisshd_config.5*
+%attr(0644,root,root) %{_mandir}/man5/gsimoduli.5*
+%attr(0644,root,root) %{_mandir}/man8/gsisshd.8*
+%attr(0644,root,root) %{_mandir}/man8/gsisftp-server.8*
+%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/gsissh/sshd_config
+%attr(0644,root,root) %config(noreplace) /etc/pam.d/gsisshd
+%attr(0755,root,root) /etc/rc.d/init.d/gsisshd
+%attr(0640,root,root) %config(noreplace) /etc/sysconfig/gsisshd
+
+%changelog
+* Thu Oct 06 2011 Mattias Ellert <mattias.ellert at fysast.uu.se> - 5.3p1-3
+- Change package name gsissh → gsi-openssh
+- Based on openssh-5.3p1-52.el6_1.2
+
+* Wed Aug 10 2011 Mattias Ellert <mattias.ellert at fysast.uu.se> - 5.3p1-2
+- Add patch from OSG to resolve threading problems in the server
+- Based on openssh-5.3p1-52.el6_1.2
+
+* Tue Mar 08 2011 Mattias Ellert <mattias.ellert at fysast.uu.se> - 5.3p1-1
+- Initial packaging
+- Based on openssh-5.3p1-20.el6_0.3
diff --git a/gsisshd.init b/gsisshd.init
new file mode 100755
index 0000000..9c3d5df
--- /dev/null
+++ b/gsisshd.init
@@ -0,0 +1,235 @@
+#!/bin/bash
+#
+# gsisshd		Start up the gsissh server daemon
+#
+# chkconfig: - 55 25
+# description: SSH is a protocol for secure remote shell access. \
+#              This service starts up the gsissh server daemon.
+#
+# processname: gsisshd
+# config: /etc/gsissh/ssh_host_key
+# config: /etc/gsissh/ssh_host_key.pub
+# config: /etc/gsissh/ssh_random_seed
+# config: /etc/gsissh/sshd_config
+# pidfile: /var/run/gsisshd.pid
+
+### BEGIN INIT INFO
+# Provides: gsisshd
+# Required-Start: $local_fs $network $syslog
+# Required-Stop: $local_fs $syslog
+# Should-Start: $syslog
+# Should-Stop: $network $syslog
+# Default-Stop: 0 1 2 3 4 5 6
+# Short-Description: Start up the gsissh server daemon
+# Description:       SSH is a protocol for secure remote shell access.
+#		     This service starts up the gsissh server daemon.
+### END INIT INFO
+
+# source function library
+. /etc/rc.d/init.d/functions
+
+# pull in sysconfig settings
+[ -f /etc/sysconfig/gsisshd ] && . /etc/sysconfig/gsisshd
+
+RETVAL=0
+prog="gsisshd"
+lockfile=/var/lock/subsys/$prog
+
+# Some functions to make the below more readable
+KEYGEN=/usr/bin/gsissh-keygen
+SSHD=/usr/sbin/gsisshd
+RSA1_KEY=/etc/gsissh/ssh_host_key
+RSA_KEY=/etc/gsissh/ssh_host_rsa_key
+DSA_KEY=/etc/gsissh/ssh_host_dsa_key
+PID_FILE=/var/run/gsisshd.pid
+
+runlevel=$(set -- $(runlevel); eval "echo \$$#" )
+
+do_rsa1_keygen() {
+	if [ ! -s $RSA1_KEY ]; then
+		echo -n $"Generating SSH1 RSA host key: "
+		rm -f $RSA1_KEY
+		if test ! -f $RSA1_KEY && $KEYGEN -q -t rsa1 -f $RSA1_KEY -C '' -N '' >&/dev/null; then
+			chmod 600 $RSA1_KEY
+			chmod 644 $RSA1_KEY.pub
+			if [ -x /sbin/restorecon ]; then
+			    /sbin/restorecon $RSA1_KEY.pub
+			fi
+			success $"RSA1 key generation"
+			echo
+		else
+			failure $"RSA1 key generation"
+			echo
+			exit 1
+		fi
+	fi
+}
+
+do_rsa_keygen() {
+	if [ ! -s $RSA_KEY ]; then
+		echo -n $"Generating SSH2 RSA host key: "
+		rm -f $RSA_KEY
+		if test ! -f $RSA_KEY && $KEYGEN -q -t rsa -f $RSA_KEY -C '' -N '' >&/dev/null; then
+			chmod 600 $RSA_KEY
+			chmod 644 $RSA_KEY.pub
+			if [ -x /sbin/restorecon ]; then
+			    /sbin/restorecon $RSA_KEY.pub
+			fi
+			success $"RSA key generation"
+			echo
+		else
+			failure $"RSA key generation"
+			echo
+			exit 1
+		fi
+	fi
+}
+
+do_dsa_keygen() {
+	if [ ! -s $DSA_KEY ]; then
+		echo -n $"Generating SSH2 DSA host key: "
+		rm -f $DSA_KEY
+		if test ! -f $DSA_KEY && $KEYGEN -q -t dsa -f $DSA_KEY -C '' -N '' >&/dev/null; then
+			chmod 600 $DSA_KEY
+			chmod 644 $DSA_KEY.pub
+			if [ -x /sbin/restorecon ]; then
+			    /sbin/restorecon $DSA_KEY.pub
+			fi
+			success $"DSA key generation"
+			echo
+		else
+			failure $"DSA key generation"
+			echo
+			exit 1
+		fi
+	fi
+}
+
+do_restart_sanity_check()
+{
+	$SSHD -t
+	RETVAL=$?
+	if [ $RETVAL -ne  0 ]; then
+		failure $"Configuration file or keys are invalid"
+		echo
+	fi
+}
+
+start()
+{
+	[ -x $SSHD ] || exit 5
+	[ -f /etc/gsissh/sshd_config ] || exit 6
+	# Create keys if necessary
+	if [ "x${AUTOCREATE_SERVER_KEYS}" != xNO ]; then
+		do_rsa_keygen
+		if [ "x${AUTOCREATE_SERVER_KEYS}" != xRSAONLY ]; then
+			do_rsa1_keygen
+			do_dsa_keygen
+		fi
+	fi
+
+	echo -n $"Starting $prog: "
+	$SSHD $OPTIONS && success || failure
+	RETVAL=$?
+	[ $RETVAL -eq 0 ] && touch $lockfile
+	echo
+	return $RETVAL
+}
+
+stop()
+{
+	echo -n $"Stopping $prog: "
+	if [ -n "`pidfileofproc $SSHD`" ] ; then
+	    killproc $SSHD
+	else
+	    failure $"Stopping $prog"
+	fi
+	RETVAL=$?
+	# if we are in halt or reboot runlevel kill all running sessions
+	# so the TCP connections are closed cleanly
+	if [ "x$runlevel" = x0 -o "x$runlevel" = x6 ] ; then
+	    trap '' TERM
+	    killall $prog 2>/dev/null
+	    trap TERM
+	fi
+	[ $RETVAL -eq 0 ] && rm -f $lockfile
+	echo
+}
+
+reload()
+{
+	echo -n $"Reloading $prog: "
+	if [ -n "`pidfileofproc $SSHD`" ] ; then
+	    killproc $SSHD -HUP
+	else
+	    failure $"Reloading $prog"
+	fi
+	RETVAL=$?
+	echo
+}
+
+restart() {
+	stop
+	start
+}
+
+force_reload() {
+	restart
+}
+
+rh_status() {
+	status -p $PID_FILE gsissh-daemon
+}
+
+rh_status_q() {
+	rh_status >/dev/null 2>&1
+}
+
+case "$1" in
+	start)
+		rh_status_q && exit 0
+		start
+		;;
+	stop)
+		if ! rh_status_q; then
+			rm -f $lockfile
+			exit 0
+		fi
+		stop
+		;;
+	restart)
+		restart
+		;;
+	reload)
+		rh_status_q || exit 7
+		reload
+		;;
+	force-reload)
+		force_reload
+		;;
+	condrestart|try-restart)
+		rh_status_q || exit 0
+		if [ -f $lockfile ] ; then
+			do_restart_sanity_check
+			if [ $RETVAL -eq 0 ] ; then
+				stop
+				# avoid race
+				sleep 3
+				start
+			else
+				RETVAL=6
+			fi
+		fi
+		;;
+	status)
+		rh_status
+		RETVAL=$?
+		if [ $RETVAL -eq 3 -a -f $lockfile ] ; then
+			RETVAL=2
+		fi
+		;;
+	*)
+		echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}"
+		RETVAL=2
+esac
+exit $RETVAL
diff --git a/gsisshd.old.pam b/gsisshd.old.pam
new file mode 100644
index 0000000..0369433
--- /dev/null
+++ b/gsisshd.old.pam
@@ -0,0 +1,13 @@
+#%PAM-1.0
+auth       required     pam_sepermit.so
+auth       include      password-auth
+account    required     pam_nologin.so
+account    include      password-auth
+password   include      password-auth
+# pam_selinux.so close should be the first session rule
+session    required     pam_selinux.so close
+session    required     pam_loginuid.so
+# pam_selinux.so open should only be followed by sessions to be executed in the user context
+session    required     pam_selinux.so open env_params
+session    optional     pam_keyinit.so force revoke
+session    include      password-auth
diff --git a/gsisshd.sysconfig b/gsisshd.sysconfig
new file mode 100644
index 0000000..cdc3d39
--- /dev/null
+++ b/gsisshd.sysconfig
@@ -0,0 +1,16 @@
+# Configuration file for the sshd service.
+
+# The server keys are automatically generated if they ommited
+# to change the automatic creation uncomment the approprite 
+# line.
+
+# AUTOCREATE_SERVER_KEYS=RSAONLY
+# AUTOCREATE_SERVER_KEYS=NO
+AUTOCREATE_SERVER_KEYS=YES
+
+# Do not change this option unless you have hardware random
+# generator and you REALLY know what you are doing/
+
+export SSH_USE_STRONG_RNG=0
+# export SSH_USE_STRONG_RNG=1
+ 
diff --git a/openssh-3.9p1-askpass-keep-above.patch b/openssh-3.9p1-askpass-keep-above.patch
new file mode 100644
index 0000000..1b9f48c
--- /dev/null
+++ b/openssh-3.9p1-askpass-keep-above.patch
@@ -0,0 +1,11 @@
+--- openssh-3.9p1/contrib/gnome-ssh-askpass2.c.keep-above	2003-11-21 13:48:56.000000000 +0100
++++ openssh-3.9p1/contrib/gnome-ssh-askpass2.c	2005-02-08 08:44:02.099739294 +0100
+@@ -119,6 +119,8 @@
+ 	g_signal_connect(G_OBJECT(entry), "activate",
+ 			 G_CALLBACK(ok_dialog), dialog);
+ 
++	gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
++
+ 	/* Grab focus */
+ 	gtk_widget_show_now(dialog);
+ 	if (grab_pointer) {
diff --git a/openssh-4.0p1-exit-deadlock.patch b/openssh-4.0p1-exit-deadlock.patch
new file mode 100644
index 0000000..66246d3
--- /dev/null
+++ b/openssh-4.0p1-exit-deadlock.patch
@@ -0,0 +1,13 @@
+--- openssh-4.0p1/channels.c.exit-deadlock	2005-03-01 11:24:33.000000000 +0100
++++ openssh-4.0p1/channels.c	2005-04-05 22:25:15.197226237 +0200
+@@ -1403,6 +1403,10 @@
+ 	u_int dlen;
+ 	int len;
+ 
++	if(c->wfd != -1 && buffer_len(&c->output) > 0 && c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
++		debug("channel %d: forcing write", c->self);
++		FD_SET(c->wfd, writeset);
++	}
+ 	/* Send buffered output data to the socket. */
+ 	if (c->wfd != -1 &&
+ 	    FD_ISSET(c->wfd, writeset) &&
diff --git a/openssh-4.3p1-fromto-remote.patch b/openssh-4.3p1-fromto-remote.patch
new file mode 100644
index 0000000..ccb3d6e
--- /dev/null
+++ b/openssh-4.3p1-fromto-remote.patch
@@ -0,0 +1,15 @@
+--- openssh-4.3p2/scp.c.fromto-remote	2006-01-31 12:11:38.000000000 +0100
++++ openssh-4.3p2/scp.c	2006-04-14 10:09:56.000000000 +0200
+@@ -446,7 +446,11 @@
+ 				addargs(&alist, "-v");
+ 			addargs(&alist, "-x");
+ 			addargs(&alist, "-oClearAllForwardings yes");
+-			addargs(&alist, "-n");
++			if (isatty(fileno(stdin))) {
++				addargs(&alist, "-t");
++			} else {
++				addargs(&alist, "-n");
++			}
+ 
+ 			*src++ = 0;
+ 			if (*src == 0)
diff --git a/openssh-4.3p2-askpass-grab-info.patch b/openssh-4.3p2-askpass-grab-info.patch
new file mode 100644
index 0000000..e9dc835
--- /dev/null
+++ b/openssh-4.3p2-askpass-grab-info.patch
@@ -0,0 +1,18 @@
+--- openssh-4.3p2/contrib/gnome-ssh-askpass2.c.grab-info	2006-07-17 15:10:11.000000000 +0200
++++ openssh-4.3p2/contrib/gnome-ssh-askpass2.c	2006-07-17 15:25:04.000000000 +0200
+@@ -65,9 +65,12 @@
+ 	err = gtk_message_dialog_new(NULL, 0,
+ 				     GTK_MESSAGE_ERROR,
+ 				     GTK_BUTTONS_CLOSE,
+-				     "Could not grab %s. "
+-				     "A malicious client may be eavesdropping "
+-				     "on your session.", what);
++				     "SSH password dialog could not grab the %s input.\n"
++				     "This might be caused by application such as screensaver, "
++				     "however it could also mean that someone may be eavesdropping "
++				     "on your session.\n"
++				     "Either close the application which grabs the %s or "
++				     "log out and log in again to prevent this from happening.", what, what);
+ 	gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER);
+ 	gtk_label_set_line_wrap(GTK_LABEL((GTK_MESSAGE_DIALOG(err))->label),
+ 				TRUE);
diff --git a/openssh-4.3p2-gssapi-canohost.patch b/openssh-4.3p2-gssapi-canohost.patch
new file mode 100644
index 0000000..2ad07d5
--- /dev/null
+++ b/openssh-4.3p2-gssapi-canohost.patch
@@ -0,0 +1,25 @@
+diff -up openssh-5.3p1/sshconnect2.c.canohost openssh-5.3p1/sshconnect2.c
+--- openssh-5.3p1/sshconnect2.c.canohost	2009-03-05 14:58:22.000000000 +0100
++++ openssh-5.3p1/sshconnect2.c	2009-11-02 11:55:00.000000000 +0100
+@@ -542,6 +542,12 @@ userauth_gssapi(Authctxt *authctxt)
+ 	static u_int mech = 0;
+ 	OM_uint32 min;
+ 	int ok = 0;
++	char* remotehost = NULL;
++	const char* canonicalhost = get_canonical_hostname(1);
++	if ( strcmp( canonicalhost, "UNKNOWN" )  == 0 )
++		remotehost = authctxt->host;
++	else
++		remotehost = canonicalhost;
+ 
+ 	/* Try one GSSAPI method at a time, rather than sending them all at
+ 	 * once. */
+@@ -554,7 +560,7 @@ userauth_gssapi(Authctxt *authctxt)
+ 		/* My DER encoding requires length<128 */
+ 		if (gss_supported->elements[mech].length < 128 &&
+ 		    ssh_gssapi_check_mechanism(&gssctxt, 
+-		    &gss_supported->elements[mech], authctxt->host)) {
++		    &gss_supported->elements[mech], remotehost)) {
+ 			ok = 1; /* Mechanism works */
+ 		} else {
+ 			mech++;
diff --git a/openssh-4.3p2-no-v6only.patch b/openssh-4.3p2-no-v6only.patch
new file mode 100644
index 0000000..a789812
--- /dev/null
+++ b/openssh-4.3p2-no-v6only.patch
@@ -0,0 +1,11 @@
+--- openssh-4.3p2/channels.c.no-v6only	2006-07-17 15:39:31.000000000 +0200
++++ openssh-4.3p2/channels.c	2006-08-08 12:44:51.000000000 +0200
+@@ -2794,7 +2794,7 @@
+ 				}
+ 			}
+ #ifdef IPV6_V6ONLY
+-			if (ai->ai_family == AF_INET6) {
++			if (x11_use_localhost && ai->ai_family == AF_INET6) {
+ 				int on = 1;
+ 				if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
+ 					error("setsockopt IPV6_V6ONLY: %.100s", strerror(errno));
diff --git a/openssh-5.0p1-pam_selinux.patch b/openssh-5.0p1-pam_selinux.patch
new file mode 100644
index 0000000..acd1611
--- /dev/null
+++ b/openssh-5.0p1-pam_selinux.patch
@@ -0,0 +1,156 @@
+diff -up openssh-5.0p1/auth-pam.h.pam_selinux openssh-5.0p1/auth-pam.h
+--- openssh-5.0p1/auth-pam.h.pam_selinux	2004-09-11 14:17:26.000000000 +0200
++++ openssh-5.0p1/auth-pam.h	2008-04-30 14:25:28.000000000 +0200
+@@ -38,7 +38,7 @@ void do_pam_session(void);
+ void do_pam_set_tty(const char *);
+ void do_pam_setcred(int );
+ void do_pam_chauthtok(void);
+-int do_pam_putenv(char *, char *);
++int do_pam_putenv(char *, const char *);
+ char ** fetch_pam_environment(void);
+ char ** fetch_pam_child_environment(void);
+ void free_pam_environment(char **);
+diff -up openssh-5.0p1/auth-pam.c.pam_selinux openssh-5.0p1/auth-pam.c
+--- openssh-5.0p1/auth-pam.c.pam_selinux	2008-03-11 12:58:25.000000000 +0100
++++ openssh-5.0p1/auth-pam.c	2008-04-30 14:25:21.000000000 +0200
+@@ -1069,7 +1069,7 @@ is_pam_session_open(void)
+  * during the ssh authentication process.
+  */
+ int
+-do_pam_putenv(char *name, char *value)
++do_pam_putenv(char *name, const char *value)
+ {
+ 	int ret = 1;
+ #ifdef HAVE_PAM_PUTENV
+diff -up openssh-5.0p1/openbsd-compat/port-linux.c.pam_selinux openssh-5.0p1/openbsd-compat/port-linux.c
+--- openssh-5.0p1/openbsd-compat/port-linux.c.pam_selinux	2008-04-07 22:01:37.000000000 +0200
++++ openssh-5.0p1/openbsd-compat/port-linux.c	2008-04-30 14:26:17.000000000 +0200
+@@ -34,6 +34,7 @@
+ #include "hostfile.h"
+ #include "auth.h"
+ #include "xmalloc.h"
++#include "servconf.h"
+ 
+ #include <selinux/selinux.h>
+ #include <selinux/flask.h>
+@@ -47,6 +48,7 @@
+ #include <unistd.h>
+ #endif
+ 
++extern ServerOptions options;
+ extern Authctxt *the_authctxt;
+ extern int inetd_flag;
+ extern int rexeced_flag;
+@@ -208,29 +210,38 @@ get_user_context(const char *sename, con
+         return -1;
+ }
+ 
++static void
++ssh_selinux_get_role_level(char **role, const char **level)
++{
++	*role = NULL;
++	*level = NULL;
++	if (the_authctxt) {
++		if (the_authctxt->role != NULL) {
++			char *slash;
++			*role = xstrdup(the_authctxt->role);
++			if ((slash = strchr(*role, '/')) != NULL) {
++				*slash = '\0';
++				*level = slash + 1;
++			}
++		}
++	}
++}
++
+ /* Return the default security context for the given username */
+ static int
+ ssh_selinux_getctxbyname(char *pwname,
+ 	security_context_t *default_sc, security_context_t *user_sc)
+ {
+ 	char *sename, *lvl;
+-	const char *reqlvl = NULL;
+-	char *role = NULL;
++	const char *reqlvl;
++	char *role;
+ 	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;
+-			}
+-		}
+-	}
++
++	ssh_selinux_get_role_level(&role, &reqlvl);
+ 
+ #ifdef HAVE_GETSEUSERBYNAME
+ 	if ((r=getseuserbyname(pwname, &sename, &lvl)) != 0) {
+@@ -311,6 +322,36 @@ ssh_selinux_getctxbyname(char *pwname,
+ 	return (r);
+ }
+ 
++/* Setup environment variables for pam_selinux */
++static int
++ssh_selinux_setup_pam_variables(void)
++{
++	const char *reqlvl;
++	char *role;
++	char *use_current;
++	int rv;
++
++	debug3("%s: setting execution context", __func__);
++
++	ssh_selinux_get_role_level(&role, &reqlvl);
++
++	rv = do_pam_putenv("SELINUX_ROLE_REQUESTED", role ? role : "");
++	
++	if (inetd_flag && !rexeced_flag) {
++		use_current = "1";
++	} else {
++		use_current = "";
++		rv = rv || do_pam_putenv("SELINUX_LEVEL_REQUESTED", reqlvl ? reqlvl: "");
++	}
++
++	rv = rv || do_pam_putenv("SELINUX_USE_CURRENT_RANGE", use_current);
++
++	if (role != NULL)
++		xfree(role);
++	
++	return rv;
++}
++
+ /* Set the execution context to the default for the specified user */
+ void
+ ssh_selinux_setup_exec_context(char *pwname)
+@@ -322,6 +363,24 @@ ssh_selinux_setup_exec_context(char *pwn
+ 	if (!ssh_selinux_enabled())
+ 		return;
+ 
++	if (options.use_pam) {
++		/* do not compute context, just setup environment for pam_selinux */
++		if (ssh_selinux_setup_pam_variables()) {
++			switch (security_getenforce()) {
++			case -1:
++				fatal("%s: security_getenforce() failed", __func__);
++			case 0:
++				error("%s: SELinux PAM variable setup failure. Continuing in permissive mode.",
++				    __func__);
++			break;
++			default:
++				fatal("%s: SELinux PAM variable setup failure. Aborting connection.",
++				    __func__);
++			}
++		}
++		return;
++	}
++
+ 	debug3("%s: setting execution context", __func__);
+ 
+ 	r = ssh_selinux_getctxbyname(pwname, &default_ctx, &user_ctx);
diff --git a/openssh-5.1p1-askpass-progress.patch b/openssh-5.1p1-askpass-progress.patch
new file mode 100644
index 0000000..ec93b87
--- /dev/null
+++ b/openssh-5.1p1-askpass-progress.patch
@@ -0,0 +1,79 @@
+diff -up openssh-5.1p1/contrib/gnome-ssh-askpass2.c.progress openssh-5.1p1/contrib/gnome-ssh-askpass2.c
+--- openssh-5.1p1/contrib/gnome-ssh-askpass2.c.progress	2008-07-23 19:05:26.000000000 +0200
++++ openssh-5.1p1/contrib/gnome-ssh-askpass2.c	2008-07-23 19:05:26.000000000 +0200
+@@ -53,6 +53,7 @@
+ #include <string.h>
+ #include <unistd.h>
+ #include <X11/Xlib.h>
++#include <glib.h>
+ #include <gtk/gtk.h>
+ #include <gdk/gdkx.h>
+ 
+@@ -83,13 +84,24 @@ ok_dialog(GtkWidget *entry, gpointer dia
+ 	gtk_dialog_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+ }
+ 
++static void
++move_progress(GtkWidget *entry, gpointer progress)
++{
++	gdouble step;
++	g_return_if_fail(GTK_IS_PROGRESS_BAR(progress));
++	
++	step = g_random_double_range(0.03, 0.1);
++	gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(progress), step);
++	gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progress));
++}
++
+ static int
+ passphrase_dialog(char *message)
+ {
+ 	const char *failed;
+ 	char *passphrase, *local;
+ 	int result, grab_tries, grab_server, grab_pointer;
+-	GtkWidget *dialog, *entry;
++	GtkWidget *dialog, *entry, *progress, *hbox;
+ 	GdkGrabStatus status;
+ 
+ 	grab_server = (getenv("GNOME_SSH_ASKPASS_GRAB_SERVER") != NULL);
+@@ -102,13 +114,31 @@ passphrase_dialog(char *message)
+ 					"%s",
+ 					message);
+ 
++	hbox = gtk_hbox_new(FALSE, 0);
++	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, FALSE,
++	    FALSE, 0);
++	gtk_widget_show(hbox);
++
+ 	entry = gtk_entry_new();
+-	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), entry, FALSE,
++	gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE,
+ 	    FALSE, 0);
++	gtk_entry_set_width_chars(GTK_ENTRY(entry), 2);
+ 	gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+ 	gtk_widget_grab_focus(entry);
+ 	gtk_widget_show(entry);
+ 
++	hbox = gtk_hbox_new(FALSE, 0);
++	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, FALSE,
++	    FALSE, 8);
++	gtk_widget_show(hbox);
++
++	progress = gtk_progress_bar_new();
++	
++	gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), "Passphrase length hidden intentionally");
++	gtk_box_pack_start(GTK_BOX(hbox), progress, TRUE,
++	    TRUE, 5);
++	gtk_widget_show(progress);
++
+ 	gtk_window_set_title(GTK_WINDOW(dialog), "OpenSSH");
+ 	gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
+ 	gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
+@@ -119,6 +149,8 @@ passphrase_dialog(char *message)
+ 	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+ 	g_signal_connect(G_OBJECT(entry), "activate",
+ 			 G_CALLBACK(ok_dialog), dialog);
++	g_signal_connect(G_OBJECT(entry), "changed",
++			 G_CALLBACK(move_progress), progress);
+ 
+ 	gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
+ 
diff --git a/openssh-5.1p1-cloexec.patch b/openssh-5.1p1-cloexec.patch
new file mode 100644
index 0000000..3d88be5
--- /dev/null
+++ b/openssh-5.1p1-cloexec.patch
@@ -0,0 +1,87 @@
+diff -up openssh-5.3p1/channels.c.cloexec openssh-5.3p1/channels.c
+--- openssh-5.3p1/channels.c.cloexec	2010-01-25 17:25:58.000000000 +0100
++++ openssh-5.3p1/channels.c	2010-01-25 17:26:01.000000000 +0100
+@@ -60,6 +60,7 @@
+ #include <termios.h>
+ #include <unistd.h>
+ #include <stdarg.h>
++#include <fcntl.h>
+ 
+ #include "openbsd-compat/sys-queue.h"
+ #include "xmalloc.h"
+@@ -230,6 +231,18 @@ channel_register_fds(Channel *c, int rfd
+ 
+ 	/* XXX set close-on-exec -markus */
+ 
++	if (rfd != -1) {
++		fcntl(rfd, F_SETFD, FD_CLOEXEC);
++	}
++
++	if (wfd != -1 && wfd != rfd) {
++		fcntl(wfd, F_SETFD, FD_CLOEXEC);
++	}
++
++	if (efd != -1 && efd != rfd && efd != wfd) {
++		fcntl(efd, F_SETFD, FD_CLOEXEC);
++	}
++
+ 	c->rfd = rfd;
+ 	c->wfd = wfd;
+ 	c->sock = (rfd == wfd) ? rfd : -1;
+diff -up openssh-5.3p1/sshconnect2.c.cloexec openssh-5.3p1/sshconnect2.c
+--- openssh-5.3p1/sshconnect2.c.cloexec	2010-01-25 17:25:58.000000000 +0100
++++ openssh-5.3p1/sshconnect2.c	2010-01-25 17:26:01.000000000 +0100
+@@ -39,6 +39,7 @@
+ #include <stdio.h>
+ #include <string.h>
+ #include <unistd.h>
++#include <fcntl.h>
+ #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H)
+ #include <vis.h>
+ #endif
+@@ -1512,6 +1513,7 @@ ssh_keysign(Key *key, u_char **sigp, u_i
+ 		return -1;
+ 	}
+ 	if (pid == 0) {
++		fcntl(packet_get_connection_in(), F_SETFD, 0); /* keep the socket on exec */
+ 		permanently_drop_suid(getuid());
+ 		close(from[0]);
+ 		if (dup2(from[1], STDOUT_FILENO) < 0)
+diff -up openssh-5.3p1/sshconnect.c.cloexec openssh-5.3p1/sshconnect.c
+--- openssh-5.3p1/sshconnect.c.cloexec	2009-06-21 10:53:53.000000000 +0200
++++ openssh-5.3p1/sshconnect.c	2010-01-25 17:26:01.000000000 +0100
+@@ -38,6 +38,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
++#include <fcntl.h>
+ 
+ #include "xmalloc.h"
+ #include "key.h"
+@@ -191,8 +192,11 @@ ssh_create_socket(int privileged, struct
+ 		return sock;
+ 	}
+ 	sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+-	if (sock < 0)
++	if (sock < 0) {
+ 		error("socket: %.100s", strerror(errno));
++		return -1;
++	}
++	fcntl(sock, F_SETFD, FD_CLOEXEC);
+ 
+ 	/* Bind the socket to an alternative local IP address */
+ 	if (options.bind_address == NULL)
+diff -up openssh-5.3p1/sshd.c.cloexec openssh-5.3p1/sshd.c
+--- openssh-5.3p1/sshd.c.cloexec	2010-01-25 17:25:55.000000000 +0100
++++ openssh-5.3p1/sshd.c	2010-01-25 18:29:23.000000000 +0100
+@@ -1756,6 +1756,10 @@ main(int ac, char **av)
+ 		    sock_in, sock_out, newsock, startup_pipe, config_s[0]);
+ 	}
+ 
++	/* set fd cloexec on io/sockets to avoid to forward them to childern */
++	fcntl(sock_out, F_SETFD, FD_CLOEXEC);
++	fcntl(sock_in, F_SETFD, FD_CLOEXEC);
++
+ 	/*
+ 	 * Disable the key regeneration alarm.  We will not regenerate the
+ 	 * key since we are no longer in a position to give it to anyone. We
diff --git a/openssh-5.1p1-log-in-chroot.patch b/openssh-5.1p1-log-in-chroot.patch
new file mode 100644
index 0000000..197fdb9
--- /dev/null
+++ b/openssh-5.1p1-log-in-chroot.patch
@@ -0,0 +1,116 @@
+diff -up openssh-5.1p1/sshd.c.log-chroot openssh-5.1p1/sshd.c
+--- openssh-5.1p1/sshd.c.log-chroot	2008-07-23 15:18:52.000000000 +0200
++++ openssh-5.1p1/sshd.c	2008-07-23 15:18:52.000000000 +0200
+@@ -591,6 +591,10 @@ privsep_preauth_child(void)
+ 	/* Demote the private keys to public keys. */
+ 	demote_sensitive_data();
+ 
++	/* Open the syslog permanently so the chrooted process still
++	   can write to syslog. */
++	open_log();
++	
+ 	/* Change our root directory */
+ 	if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1)
+ 		fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR,
+diff -up openssh-5.1p1/log.c.log-chroot openssh-5.1p1/log.c
+--- openssh-5.1p1/log.c.log-chroot	2008-06-10 15:01:51.000000000 +0200
++++ openssh-5.1p1/log.c	2008-07-23 15:18:52.000000000 +0200
+@@ -45,6 +45,7 @@
+ #include <syslog.h>
+ #include <unistd.h>
+ #include <errno.h>
++#include <fcntl.h>
+ #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H)
+ # include <vis.h>
+ #endif
+@@ -56,6 +57,7 @@
+ static int log_on_stderr = 1;
+ static int log_facility = LOG_AUTH;
+ static char *argv0;
++int log_fd_keep = 0;
+ 
+ extern char *__progname;
+ 
+@@ -310,6 +312,8 @@
+ 		exit(1);
+ 	}
+ 
++	if (log_fd_keep != 0)
++		return;
+ 	/*
+ 	 * If an external library (eg libwrap) attempts to use syslog
+ 	 * immediately after reexec, syslog may be pointing to the wrong
+@@ -392,10 +396,33 @@
+ 		syslog_r(pri, &sdata, "%.500s", fmtbuf);
+ 		closelog_r(&sdata);
+ #else
++	    if (!log_fd_keep) {
+ 		openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
++	    }
+ 		syslog(pri, "%.500s", fmtbuf);
++	    if (!log_fd_keep) {
+ 		closelog();
++	    }
+ #endif
+ 	}
+ 	errno = saved_errno;
+ }
++
++void
++open_log(void)
++{
++	int temp1, temp2;
++
++	temp1 = open("/dev/null", O_RDONLY);
++	openlog(argv0 ? argv0 : __progname, LOG_PID|LOG_NDELAY, log_facility);
++	temp2 = open("/dev/null", O_RDONLY);
++	if (temp1 + 2 ==  temp2)
++		log_fd_keep = temp1 + 1;
++	else 
++		log_fd_keep = -1;
++
++	if (temp1 != -1)
++		close(temp1);
++	if (temp2 != -1)
++		close(temp2);
++}
+diff -up openssh-5.1p1/log.h.log-chroot openssh-5.1p1/log.h
+--- openssh-5.1p1/log.h.log-chroot	2008-06-13 02:22:54.000000000 +0200
++++ openssh-5.1p1/log.h	2008-07-23 15:20:11.000000000 +0200
+@@ -46,6 +46,9 @@
+ 	SYSLOG_LEVEL_NOT_SET = -1
+ }       LogLevel;
+ 
++
++extern int log_fd_keep;
++
+ void     log_init(char *, LogLevel, SyslogFacility, int);
+ 
+ SyslogFacility	log_facility_number(char *);
+@@ -66,4 +69,6 @@
+ 
+ void	 do_log(LogLevel, const char *, va_list);
+ void	 cleanup_exit(int) __attribute__((noreturn));
++
++void     open_log(void);
+ #endif
+--- openssh-5.2p1/session.c.	2009-03-20 18:32:01.004151364 +0100
++++ openssh-5.2p1/session.c	2009-03-20 19:00:28.328742384 +0100
+@@ -1445,6 +1456,7 @@
+ 	if (chdir(path) == -1)
+ 		fatal("Unable to chdir to chroot path \"%s\": "
+ 		    "%s", path, strerror(errno));
++	open_log ();
+ 	if (chroot(path) == -1)
+ 		fatal("chroot(\"%s\"): %s", path, strerror(errno));
+ 	if (chdir("/") == -1)
+@@ -1632,7 +1644,8 @@
+ 	 * descriptors open.
+ 	 */
+ 	for (i = 3; i < 64; i++)
+-		close(i);
++		if (i != log_fd_keep)
++			close(i);
+ }
+ 
+ /*
diff --git a/openssh-5.1p1-scp-manpage.patch b/openssh-5.1p1-scp-manpage.patch
new file mode 100644
index 0000000..e314a05
--- /dev/null
+++ b/openssh-5.1p1-scp-manpage.patch
@@ -0,0 +1,18 @@
+diff -up openssh-5.1p1/scp.1.manpage openssh-5.1p1/scp.1
+--- openssh-5.1p1/scp.1.manpage	2008-07-12 09:12:49.000000000 +0200
++++ openssh-5.1p1/scp.1	2008-07-23 19:18:15.000000000 +0200
+@@ -66,6 +66,14 @@ treating file names containing
+ as host specifiers.
+ Copies between two remote hosts are also permitted.
+ .Pp
++When copying a source file to a target file which already exists,
++.Nm 
++will replace the contents of the target file (keeping the inode).
++.Pp
++If the target file does not yet exist, an empty file with the target
++file name is created, then filled with the source file contents.
++No attempt is made at "near-atomic" transfer using temporary files.
++.Pp
+ The options are as follows:
+ .Bl -tag -width Ds
+ .It Fl 1
diff --git a/openssh-5.2p1-allow-ip-opts.patch b/openssh-5.2p1-allow-ip-opts.patch
new file mode 100644
index 0000000..96aaab1
--- /dev/null
+++ b/openssh-5.2p1-allow-ip-opts.patch
@@ -0,0 +1,37 @@
+diff -up openssh-5.2p1/canohost.c.ip-opts openssh-5.2p1/canohost.c
+--- openssh-5.2p1/canohost.c.ip-opts	2009-02-14 06:28:21.000000000 +0100
++++ openssh-5.2p1/canohost.c	2009-09-01 15:31:29.000000000 +0200
+@@ -169,12 +169,27 @@ check_ip_options(int sock, char *ipaddr)
+ 	option_size = sizeof(options);
+ 	if (getsockopt(sock, ipproto, IP_OPTIONS, options,
+ 	    &option_size) >= 0 && option_size != 0) {
+-		text[0] = '\0';
+-		for (i = 0; i < option_size; i++)
+-			snprintf(text + i*3, sizeof(text) - i*3,
+-			    " %2.2x", options[i]);
+-		fatal("Connection from %.100s with IP options:%.800s",
+-		    ipaddr, text);
++		i = 0;
++		do {
++			switch (options[i]) {
++				case 0:
++				case 1:
++					++i;
++					break;
++				case 131:
++				case 137:
++				/* Fail, fatally, if we detect either loose or strict
++			 	 * source routing options. */
++					text[0] = '\0';
++					for (i = 0; i < option_size; i++)
++						snprintf(text + i*3, sizeof(text) - i*3,
++							" %2.2x", options[i]);
++					fatal("Connection from %.100s with IP options:%.800s",
++						ipaddr, text);
++				default:
++					i += options[i + 1];
++			}
++		} while (i < option_size);
+ 	}
+ #endif /* IP_OPTIONS */
+ }
diff --git a/openssh-5.2p1-edns.patch b/openssh-5.2p1-edns.patch
new file mode 100644
index 0000000..f3e431e
--- /dev/null
+++ b/openssh-5.2p1-edns.patch
@@ -0,0 +1,72 @@
+diff -up openssh-5.2p1/dns.c.rh205842 openssh-5.2p1/dns.c
+--- openssh-5.2p1/dns.c.rh205842	2009-07-27 16:25:28.000000000 +0200
++++ openssh-5.2p1/dns.c	2009-07-27 16:40:59.000000000 +0200
+@@ -176,6 +176,7 @@ verify_host_key_dns(const char *hostname
+ {
+ 	u_int counter;
+ 	int result;
++	unsigned int rrset_flags = 0;
+ 	struct rrsetinfo *fingerprints = NULL;
+ 
+ 	u_int8_t hostkey_algorithm;
+@@ -199,8 +200,19 @@ verify_host_key_dns(const char *hostname
+ 		return -1;
+ 	}
+ 
++	/*
++	 * Original getrrsetbyname function, found on OpenBSD for example,
++	 * doesn't accept any flag and prerequisite for obtaining AD bit in
++	 * DNS response is set by "options edns0" in resolv.conf.
++	 *
++	 * Our version is more clever and use RRSET_FORCE_EDNS0 flag.
++	 */
++#ifndef HAVE_GETRRSETBYNAME
++	rrset_flags |= RRSET_FORCE_EDNS0;
++#endif
+ 	result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
+-	    DNS_RDATATYPE_SSHFP, 0, &fingerprints);
++	    DNS_RDATATYPE_SSHFP, rrset_flags, &fingerprints);
++
+ 	if (result) {
+ 		verbose("DNS lookup error: %s", dns_result_totext(result));
+ 		return -1;
+diff -up openssh-5.2p1/openbsd-compat/getrrsetbyname.c.rh205842 openssh-5.2p1/openbsd-compat/getrrsetbyname.c
+--- openssh-5.2p1/openbsd-compat/getrrsetbyname.c.rh205842	2009-07-27 16:22:23.000000000 +0200
++++ openssh-5.2p1/openbsd-compat/getrrsetbyname.c	2009-07-27 16:41:55.000000000 +0200
+@@ -209,8 +209,8 @@ getrrsetbyname(const char *hostname, uns
+ 		goto fail;
+ 	}
+ 
+-	/* don't allow flags yet, unimplemented */
+-	if (flags) {
++	/* Allow RRSET_FORCE_EDNS0 flag only. */
++	if ((flags & !RRSET_FORCE_EDNS0) != 0) {
+ 		result = ERRSET_INVAL;
+ 		goto fail;
+ 	}
+@@ -226,9 +226,9 @@ getrrsetbyname(const char *hostname, uns
+ #endif /* DEBUG */
+ 
+ #ifdef RES_USE_DNSSEC
+-	/* turn on DNSSEC if EDNS0 is configured */
+-	if (_resp->options & RES_USE_EDNS0)
+-		_resp->options |= RES_USE_DNSSEC;
++	/* turn on DNSSEC if required  */
++	if (flags & RRSET_FORCE_EDNS0)
++		_resp->options |= (RES_USE_EDNS0|RES_USE_DNSSEC);
+ #endif /* RES_USE_DNSEC */
+ 
+ 	/* make query */
+diff -up openssh-5.2p1/openbsd-compat/getrrsetbyname.h.rh205842 openssh-5.2p1/openbsd-compat/getrrsetbyname.h
+--- openssh-5.2p1/openbsd-compat/getrrsetbyname.h.rh205842	2009-07-27 16:35:02.000000000 +0200
++++ openssh-5.2p1/openbsd-compat/getrrsetbyname.h	2009-07-27 16:36:09.000000000 +0200
+@@ -72,6 +72,9 @@
+ #ifndef RRSET_VALIDATED
+ # define RRSET_VALIDATED	1
+ #endif
++#ifndef RRSET_FORCE_EDNS0
++# define RRSET_FORCE_EDNS0	0x0001
++#endif
+ 
+ /*
+  * Return codes for getrrsetbyname()
diff --git a/openssh-5.2p1-redhat.patch b/openssh-5.2p1-redhat.patch
new file mode 100644
index 0000000..4304065
--- /dev/null
+++ b/openssh-5.2p1-redhat.patch
@@ -0,0 +1,99 @@
+diff -up openssh-5.2p1/ssh_config.redhat openssh-5.2p1/ssh_config
+--- openssh-5.2p1/ssh_config.redhat	2009-02-21 02:45:02.000000000 +0100
++++ openssh-5.2p1/ssh_config	2009-08-09 08:45:11.302092427 +0200
+@@ -44,3 +44,14 @@
+ #   TunnelDevice any:any
+ #   PermitLocalCommand no
+ #   VisualHostKey no
++Host *
++	GSSAPIAuthentication yes
++# If this option is set to yes then remote X11 clients will have full access
++# to the original X11 display. As virtually no X11 client supports the untrusted
++# mode correctly we set this to yes.
++	ForwardX11Trusted yes
++# Send locale-related environment variables
++	SendEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES 
++	SendEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT 
++	SendEnv LC_IDENTIFICATION LC_ALL LANGUAGE
++	SendEnv XMODIFIERS
+diff -up openssh-5.2p1/sshd_config.0.redhat openssh-5.2p1/sshd_config.0
+--- openssh-5.2p1/sshd_config.0.redhat	2009-02-23 01:18:15.000000000 +0100
++++ openssh-5.2p1/sshd_config.0	2009-08-09 08:45:11.276555108 +0200
+@@ -491,9 +491,9 @@ DESCRIPTION
+ 
+      SyslogFacility
+              Gives the facility code that is used when logging messages from
+-             sshd(8).  The possible values are: DAEMON, USER, AUTH, LOCAL0,
+-             LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.  The de-
+-             fault is AUTH.
++             sshd(8).  The possible values are: DAEMON, USER, AUTH, AUTHPRIV,
++             LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
++             The default is AUTH.
+ 
+      TCPKeepAlive
+              Specifies whether the system should send TCP keepalive messages
+diff -up openssh-5.2p1/sshd_config.5.redhat openssh-5.2p1/sshd_config.5
+--- openssh-5.2p1/sshd_config.5.redhat	2009-02-23 01:00:24.000000000 +0100
++++ openssh-5.2p1/sshd_config.5	2009-08-09 08:45:11.278927203 +0200
+@@ -848,7 +848,7 @@ Note that this option applies to protoco
+ .It Cm SyslogFacility
+ Gives the facility code that is used when logging messages from
+ .Xr sshd 8 .
+-The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2,
++The possible values are: DAEMON, USER, AUTH, AUTHPRIV, LOCAL0, LOCAL1, LOCAL2,
+ LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
+ The default is AUTH.
+ .It Cm TCPKeepAlive
+diff -up openssh-5.2p1/sshd_config.redhat openssh-5.2p1/sshd_config
+--- openssh-5.2p1/sshd_config.redhat	2008-07-02 14:35:43.000000000 +0200
++++ openssh-5.2p1/sshd_config	2009-08-09 08:47:40.850857227 +0200
+@@ -33,6 +33,7 @@ Protocol 2
+ # Logging
+ # obsoletes QuietMode and FascistLogging
+ #SyslogFacility AUTH
++SyslogFacility AUTHPRIV
+ #LogLevel INFO
+ 
+ # Authentication:
+@@ -60,9 +61,11 @@ Protocol 2
+ # To disable tunneled clear text passwords, change to no here!
+ #PasswordAuthentication yes
+ #PermitEmptyPasswords no
++PasswordAuthentication yes
+ 
+ # Change to no to disable s/key passwords
+ #ChallengeResponseAuthentication yes
++ChallengeResponseAuthentication no
+ 
+ # Kerberos options
+ #KerberosAuthentication no
+@@ -72,7 +75,9 @@ Protocol 2
+ 
+ # GSSAPI options
+ #GSSAPIAuthentication no
++GSSAPIAuthentication yes
+ #GSSAPICleanupCredentials yes
++GSSAPICleanupCredentials yes
+ 
+ # Set this to 'yes' to enable PAM authentication, account processing, 
+ # and session processing. If this is enabled, PAM authentication will 
+@@ -84,11 +89,19 @@ Protocol 2
+ # PAM authentication, then enable this but set PasswordAuthentication
+ # and ChallengeResponseAuthentication to 'no'.
+ #UsePAM no
++UsePAM yes
++
++# Accept locale-related environment variables
++AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
++AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
++AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
++AcceptEnv XMODIFIERS
+ 
+ #AllowAgentForwarding yes
+ #AllowTcpForwarding yes
+ #GatewayPorts no
+ #X11Forwarding no
++X11Forwarding yes
+ #X11DisplayOffset 10
+ #X11UseLocalhost yes
+ #PrintMotd yes
diff --git a/openssh-5.2p1-selinux.patch b/openssh-5.2p1-selinux.patch
new file mode 100644
index 0000000..19cea68
--- /dev/null
+++ b/openssh-5.2p1-selinux.patch
@@ -0,0 +1,394 @@
+diff -up openssh-5.2p1/auth1.c.selinux openssh-5.2p1/auth1.c
+--- openssh-5.2p1/auth1.c.selinux	2008-07-09 12:54:05.000000000 +0200
++++ openssh-5.2p1/auth1.c	2009-08-11 22:43:07.918183730 +0200
+@@ -392,6 +392,9 @@ do_authentication(Authctxt *authctxt)
+ {
+ 	u_int ulen;
+ 	char *user, *style = NULL;
++#ifdef WITH_SELINUX
++	char *role=NULL;
++#endif
+ 
+ 	/* Get the name of the user that we wish to log in as. */
+ 	packet_read_expect(SSH_CMSG_USER);
+@@ -400,11 +403,25 @@ do_authentication(Authctxt *authctxt)
+ 	user = packet_get_string(&ulen);
+ 	packet_check_eom();
+ 
++#ifdef WITH_SELINUX
++	if ((role = strchr(user, '/')) != NULL)
++		*role++ = '\0';
++#endif
++
+ 	if ((style = strchr(user, ':')) != NULL)
+ 		*style++ = '\0';
++#ifdef WITH_SELINUX
++	else
++		if (role && (style = strchr(role, ':')) != NULL)
++			*style++ = '\0';
++#endif
++			
+ 
+ 	authctxt->user = user;
+ 	authctxt->style = style;
++#ifdef WITH_SELINUX
++	authctxt->role = role;
++#endif
+ 
+ 	/* Verify that the user is a valid user. */
+ 	if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
+diff -up openssh-5.2p1/auth2.c.selinux openssh-5.2p1/auth2.c
+--- openssh-5.2p1/auth2.c.selinux	2008-11-05 06:20:46.000000000 +0100
++++ openssh-5.2p1/auth2.c	2009-08-11 22:43:07.919756192 +0200
+@@ -216,6 +216,9 @@ input_userauth_request(int type, u_int32
+ 	Authctxt *authctxt = ctxt;
+ 	Authmethod *m = NULL;
+ 	char *user, *service, *method, *style = NULL;
++#ifdef WITH_SELINUX
++	char *role = NULL;
++#endif
+ 	int authenticated = 0;
+ 
+ 	if (authctxt == NULL)
+@@ -227,6 +230,11 @@ input_userauth_request(int type, u_int32
+ 	debug("userauth-request for user %s service %s method %s", user, service, method);
+ 	debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
+ 
++#ifdef WITH_SELINUX
++	if ((role = strchr(user, '/')) != NULL)
++		*role++ = 0;
++#endif
++
+ 	if ((style = strchr(user, ':')) != NULL)
+ 		*style++ = 0;
+ 
+@@ -252,8 +260,15 @@ input_userauth_request(int type, u_int32
+ 		    use_privsep ? " [net]" : "");
+ 		authctxt->service = xstrdup(service);
+ 		authctxt->style = style ? xstrdup(style) : NULL;
+-		if (use_privsep)
++#ifdef WITH_SELINUX
++		authctxt->role = role ? xstrdup(role) : NULL;
++#endif
++		if (use_privsep) {
+ 			mm_inform_authserv(service, style);
++#ifdef WITH_SELINUX
++			mm_inform_authrole(role);
++#endif
++		}
+ 		userauth_banner();
+ 	} else if (strcmp(user, authctxt->user) != 0 ||
+ 	    strcmp(service, authctxt->service) != 0) {
+diff -up openssh-5.2p1/auth2-gss.c.selinux openssh-5.2p1/auth2-gss.c
+--- openssh-5.2p1/auth2-gss.c.selinux	2007-12-02 12:59:45.000000000 +0100
++++ openssh-5.2p1/auth2-gss.c	2009-08-11 22:43:07.921723295 +0200
+@@ -258,6 +258,7 @@ input_gssapi_mic(int type, u_int32_t ple
+ 	Authctxt *authctxt = ctxt;
+ 	Gssctxt *gssctxt;
+ 	int authenticated = 0;
++	char *micuser;
+ 	Buffer b;
+ 	gss_buffer_desc mic, gssbuf;
+ 	u_int len;
+@@ -270,7 +271,13 @@ input_gssapi_mic(int type, u_int32_t ple
+ 	mic.value = packet_get_string(&len);
+ 	mic.length = len;
+ 
+-	ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
++#ifdef WITH_SELINUX
++	if (authctxt->role && (strlen(authctxt->role) > 0))
++		xasprintf(&micuser, "%s/%s", authctxt->user, authctxt->role);
++	else
++#endif
++		micuser = authctxt->user;
++	ssh_gssapi_buildmic(&b, micuser, authctxt->service,
+ 	    "gssapi-with-mic");
+ 
+ 	gssbuf.value = buffer_ptr(&b);
+@@ -282,6 +289,8 @@ input_gssapi_mic(int type, u_int32_t ple
+ 		logit("GSSAPI MIC check failed");
+ 
+ 	buffer_free(&b);
++	if (micuser != authctxt->user)
++		xfree(micuser);
+ 	xfree(mic.value);
+ 
+ 	authctxt->postponed = 0;
+diff -up openssh-5.2p1/auth2-hostbased.c.selinux openssh-5.2p1/auth2-hostbased.c
+--- openssh-5.2p1/auth2-hostbased.c.selinux	2008-07-17 10:57:19.000000000 +0200
++++ openssh-5.2p1/auth2-hostbased.c	2009-08-11 22:43:07.923721059 +0200
+@@ -106,7 +106,15 @@ userauth_hostbased(Authctxt *authctxt)
+ 	buffer_put_string(&b, session_id2, session_id2_len);
+ 	/* reconstruct packet */
+ 	buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+-	buffer_put_cstring(&b, authctxt->user);
++#ifdef WITH_SELINUX
++	if (authctxt->role) {
++		buffer_put_int(&b, strlen(authctxt->user)+strlen(authctxt->role)+1);
++		buffer_append(&b, authctxt->user, strlen(authctxt->user));
++		buffer_put_char(&b, '/');
++		buffer_append(&b, authctxt->role, strlen(authctxt->role));
++	} else 
++#endif
++		buffer_put_cstring(&b, authctxt->user);
+ 	buffer_put_cstring(&b, service);
+ 	buffer_put_cstring(&b, "hostbased");
+ 	buffer_put_string(&b, pkalg, alen);
+diff -up openssh-5.2p1/auth2-pubkey.c.selinux openssh-5.2p1/auth2-pubkey.c
+--- openssh-5.2p1/auth2-pubkey.c.selinux	2008-07-04 04:54:25.000000000 +0200
++++ openssh-5.2p1/auth2-pubkey.c	2009-08-11 22:43:07.925704588 +0200
+@@ -117,7 +117,15 @@ userauth_pubkey(Authctxt *authctxt)
+ 		}
+ 		/* reconstruct packet */
+ 		buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+-		buffer_put_cstring(&b, authctxt->user);
++#ifdef WITH_SELINUX
++		if (authctxt->role) {
++			buffer_put_int(&b, strlen(authctxt->user)+strlen(authctxt->role)+1);
++			buffer_append(&b, authctxt->user, strlen(authctxt->user));
++			buffer_put_char(&b, '/');
++			buffer_append(&b, authctxt->role, strlen(authctxt->role));
++		} else 
++#endif
++			buffer_put_cstring(&b, authctxt->user);
+ 		buffer_put_cstring(&b,
+ 		    datafellows & SSH_BUG_PKSERVICE ?
+ 		    "ssh-userauth" :
+diff -up openssh-5.2p1/auth.h.selinux openssh-5.2p1/auth.h
+--- openssh-5.2p1/auth.h.selinux	2008-11-05 06:20:46.000000000 +0100
++++ openssh-5.2p1/auth.h	2009-08-11 22:43:07.927199901 +0200
+@@ -58,6 +58,9 @@ struct Authctxt {
+ 	char		*service;
+ 	struct passwd	*pw;		/* set if 'valid' */
+ 	char		*style;
++#ifdef WITH_SELINUX
++	char		*role;
++#endif
+ 	void		*kbdintctxt;
+ 	void		*jpake_ctx;
+ #ifdef BSD_AUTH
+diff -up openssh-5.2p1/configure.ac.selinux openssh-5.2p1/configure.ac
+--- openssh-5.2p1/configure.ac.selinux	2009-02-16 05:37:03.000000000 +0100
++++ openssh-5.2p1/configure.ac	2009-08-11 22:43:07.930259052 +0200
+@@ -3335,6 +3335,7 @@ AC_ARG_WITH(selinux,
+ 		AC_CHECK_LIB(selinux, setexeccon, [ LIBSELINUX="-lselinux" ],
+ 		    AC_MSG_ERROR(SELinux support requires libselinux library))
+ 		SSHDLIBS="$SSHDLIBS $LIBSELINUX"
++		LIBS="$LIBS $LIBSELINUX"
+ 		AC_CHECK_FUNCS(getseuserbyname get_default_context_with_level)
+ 		LIBS="$save_LIBS"
+ 	fi ]
+diff -up openssh-5.2p1/monitor.c.selinux openssh-5.2p1/monitor.c
+--- openssh-5.2p1/monitor.c.selinux	2009-02-14 06:33:31.000000000 +0100
++++ openssh-5.2p1/monitor.c	2009-08-11 22:43:07.933623092 +0200
+@@ -135,6 +135,9 @@ int mm_answer_sign(int, Buffer *);
+ int mm_answer_pwnamallow(int, Buffer *);
+ int mm_answer_auth2_read_banner(int, Buffer *);
+ int mm_answer_authserv(int, Buffer *);
++#ifdef WITH_SELINUX
++int mm_answer_authrole(int, Buffer *);
++#endif
+ int mm_answer_authpassword(int, Buffer *);
+ int mm_answer_bsdauthquery(int, Buffer *);
+ int mm_answer_bsdauthrespond(int, Buffer *);
+@@ -211,6 +214,9 @@ struct mon_table mon_dispatch_proto20[] 
+     {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
+     {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
+     {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
++#ifdef WITH_SELINUX
++    {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole},
++#endif
+     {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
+     {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
+ #ifdef USE_PAM
+@@ -680,6 +686,9 @@ mm_answer_pwnamallow(int sock, Buffer *m
+ 	else {
+ 		/* Allow service/style information on the auth context */
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
++#ifdef WITH_SELINUX
++		monitor_permit(mon_dispatch, MONITOR_REQ_AUTHROLE, 1);
++#endif
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1);
+ 	}
+ 
+@@ -724,6 +733,25 @@ mm_answer_authserv(int sock, Buffer *m)
+ 	return (0);
+ }
+ 
++#ifdef WITH_SELINUX
++int
++mm_answer_authrole(int sock, Buffer *m)
++{
++	monitor_permit_authentications(1);
++
++	authctxt->role = buffer_get_string(m, NULL);
++	debug3("%s: role=%s",
++	    __func__, authctxt->role);
++
++	if (strlen(authctxt->role) == 0) {
++		xfree(authctxt->role);
++		authctxt->role = NULL;
++	}
++
++	return (0);
++}
++#endif
++
+ int
+ mm_answer_authpassword(int sock, Buffer *m)
+ {
+@@ -1102,7 +1130,7 @@ static int
+ monitor_valid_userblob(u_char *data, u_int datalen)
+ {
+ 	Buffer b;
+-	char *p;
++	char *p, *r;
+ 	u_int len;
+ 	int fail = 0;
+ 
+@@ -1128,6 +1156,8 @@ monitor_valid_userblob(u_char *data, u_i
+ 	if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
+ 		fail++;
+ 	p = buffer_get_string(&b, NULL);
++	if ((r = strchr(p, '/')) != NULL)
++		*r = '\0';
+ 	if (strcmp(authctxt->user, p) != 0) {
+ 		logit("wrong user name passed to monitor: expected %s != %.100s",
+ 		    authctxt->user, p);
+@@ -1159,7 +1189,7 @@ monitor_valid_hostbasedblob(u_char *data
+     char *chost)
+ {
+ 	Buffer b;
+-	char *p;
++	char *p, *r;
+ 	u_int len;
+ 	int fail = 0;
+ 
+@@ -1176,6 +1206,8 @@ monitor_valid_hostbasedblob(u_char *data
+ 	if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
+ 		fail++;
+ 	p = buffer_get_string(&b, NULL);
++	if ((r = strchr(p, '/')) != NULL)
++		*r = '\0';
+ 	if (strcmp(authctxt->user, p) != 0) {
+ 		logit("wrong user name passed to monitor: expected %s != %.100s",
+ 		    authctxt->user, p);
+diff -up openssh-5.2p1/monitor.h.selinux openssh-5.2p1/monitor.h
+--- openssh-5.2p1/monitor.h.selinux	2008-11-05 06:20:46.000000000 +0100
++++ openssh-5.2p1/monitor.h	2009-08-11 22:43:07.935612930 +0200
+@@ -31,6 +31,9 @@
+ enum monitor_reqtype {
+ 	MONITOR_REQ_MODULI, MONITOR_ANS_MODULI,
+ 	MONITOR_REQ_FREE, MONITOR_REQ_AUTHSERV,
++#ifdef WITH_SELINUX
++	MONITOR_REQ_AUTHROLE,
++#endif
+ 	MONITOR_REQ_SIGN, MONITOR_ANS_SIGN,
+ 	MONITOR_REQ_PWNAM, MONITOR_ANS_PWNAM,
+ 	MONITOR_REQ_AUTH2_READ_BANNER, MONITOR_ANS_AUTH2_READ_BANNER,
+diff -up openssh-5.2p1/monitor_wrap.c.selinux openssh-5.2p1/monitor_wrap.c
+--- openssh-5.2p1/monitor_wrap.c.selinux	2008-11-05 06:20:47.000000000 +0100
++++ openssh-5.2p1/monitor_wrap.c	2009-08-11 22:43:07.937212340 +0200
+@@ -297,6 +297,25 @@ mm_inform_authserv(char *service, char *
+ 	buffer_free(&m);
+ }
+ 
++/* Inform the privileged process about role */
++
++#ifdef WITH_SELINUX
++void
++mm_inform_authrole(char *role)
++{
++	Buffer m;
++
++	debug3("%s entering", __func__);
++
++	buffer_init(&m);
++	buffer_put_cstring(&m, role ? role : "");
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHROLE, &m);
++
++	buffer_free(&m);
++}
++#endif
++
+ /* Do the password authentication */
+ int
+ mm_auth_password(Authctxt *authctxt, char *password)
+diff -up openssh-5.2p1/monitor_wrap.h.selinux openssh-5.2p1/monitor_wrap.h
+--- openssh-5.2p1/monitor_wrap.h.selinux	2008-11-05 06:20:47.000000000 +0100
++++ openssh-5.2p1/monitor_wrap.h	2009-08-11 22:43:07.938268752 +0200
+@@ -41,6 +41,9 @@ int mm_is_monitor(void);
+ DH *mm_choose_dh(int, int, int);
+ int mm_key_sign(Key *, u_char **, u_int *, u_char *, u_int);
+ void mm_inform_authserv(char *, char *);
++#ifdef WITH_SELINUX
++void mm_inform_authrole(char *);
++#endif
+ struct passwd *mm_getpwnamallow(const char *);
+ char *mm_auth2_read_banner(void);
+ int mm_auth_password(struct Authctxt *, char *);
+diff -up openssh-5.2p1/openbsd-compat/port-linux.c.selinux openssh-5.2p1/openbsd-compat/port-linux.c
+--- openssh-5.2p1/openbsd-compat/port-linux.c.selinux	2008-03-26 21:27:21.000000000 +0100
++++ openssh-5.2p1/openbsd-compat/port-linux.c	2009-08-11 22:44:14.529196220 +0200
+@@ -30,11 +30,16 @@
+ #ifdef WITH_SELINUX
+ #include "log.h"
+ #include "port-linux.h"
++#include "key.h"
++#include "hostfile.h"
++#include "auth.h"
+ 
+ #include <selinux/selinux.h>
+ #include <selinux/flask.h>
+ #include <selinux/get_context_list.h>
+ 
++extern Authctxt *the_authctxt;
++
+ /* Wrapper around is_selinux_enabled() to log its return value once only */
+ int
+ ssh_selinux_enabled(void)
+@@ -53,23 +58,36 @@ ssh_selinux_enabled(void)
+ static security_context_t
+ ssh_selinux_getctxbyname(char *pwname)
+ {
+-	security_context_t sc;
+-	char *sename = NULL, *lvl = NULL;
+-	int r;
++	security_context_t sc = NULL;
++	char *sename, *lvl;
++	char *role = NULL;
++	int r = 0;
+ 
++	if (the_authctxt) 
++		role=the_authctxt->role;
+ #ifdef HAVE_GETSEUSERBYNAME
+-	if (getseuserbyname(pwname, &sename, &lvl) != 0)
+-		return NULL;
++	if ((r=getseuserbyname(pwname, &sename, &lvl)) != 0) {
++		sename = NULL;
++		lvl = NULL;
++	}
+ #else
+ 	sename = pwname;
+ 	lvl = NULL;
+ #endif
+ 
++	if (r == 0) {
+ #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
+-	r = get_default_context_with_level(sename, lvl, NULL, &sc);
++		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);
+ #else
+-	r = get_default_context(sename, NULL, &sc);
++		if (role != NULL && role[0])
++			r = get_default_context_with_role(sename, role, NULL, &sc);
++		else
++			r = get_default_context(sename, NULL, &sc);
+ #endif
++	}
+ 
+ 	if (r != 0) {
+ 		switch (security_getenforce()) {
diff --git a/openssh-5.2p1-sesftp.patch b/openssh-5.2p1-sesftp.patch
new file mode 100644
index 0000000..3470e8f
--- /dev/null
+++ b/openssh-5.2p1-sesftp.patch
@@ -0,0 +1,64 @@
+diff -up openssh-5.2p1/openbsd-compat/port-linux.c.sesftp openssh-5.2p1/openbsd-compat/port-linux.c
+--- openssh-5.2p1/openbsd-compat/port-linux.c.sesftp	2009-08-12 00:29:37.712368892 +0200
++++ openssh-5.2p1/openbsd-compat/port-linux.c	2009-08-12 00:29:37.732544890 +0200
+@@ -469,4 +469,36 @@ ssh_selinux_setup_pty(char *pwname, cons
+ 		freecon(user_ctx);
+ 	debug3("%s: done", __func__);
+ }
++
++void
++ssh_selinux_change_context(const char *newname)
++{
++	int len, newlen;
++	char *oldctx, *newctx, *cx;
++
++	if (!ssh_selinux_enabled())
++		return;
++
++	if (getcon((security_context_t *)&oldctx) < 0) {
++		logit("%s: getcon failed with %s", __func__, strerror (errno));
++		return;
++	}
++	if ((cx = index(oldctx, ':')) == NULL || (cx = index(cx + 1, ':')) == NULL) {
++		logit ("%s: unparseable context %s", __func__, oldctx);
++		return;
++	}
++
++	newlen = strlen(oldctx) + strlen(newname) + 1;
++	newctx = xmalloc(newlen);
++	len = cx - oldctx + 1;
++	memcpy(newctx, oldctx, len);
++	strlcpy(newctx + len, newname, newlen - len);
++	if ((cx = index(cx + 1, ':')))
++		strlcat(newctx, cx, newlen);
++	debug3("%s: setting context from '%s' to '%s'", __func__, oldctx, newctx);
++	if (setcon(newctx) < 0)
++		logit("%s: setcon failed with %s", __func__, strerror (errno));
++	xfree(oldctx);
++	xfree(newctx);
++}
+ #endif /* WITH_SELINUX */
+diff -up openssh-5.2p1/openbsd-compat/port-linux.h.sesftp openssh-5.2p1/openbsd-compat/port-linux.h
+--- openssh-5.2p1/openbsd-compat/port-linux.h.sesftp	2008-03-26 21:27:21.000000000 +0100
++++ openssh-5.2p1/openbsd-compat/port-linux.h	2009-08-12 00:29:37.733388083 +0200
+@@ -23,6 +23,7 @@
+ int ssh_selinux_enabled(void);
+ void ssh_selinux_setup_pty(char *, const char *);
+ void ssh_selinux_setup_exec_context(char *);
++void ssh_selinux_change_context(const char *);
+ #endif
+ 
+ #endif /* ! _PORT_LINUX_H */
+diff -up openssh-5.2p1/session.c.sesftp openssh-5.2p1/session.c
+--- openssh-5.2p1/session.c.sesftp	2009-08-12 00:29:37.659250161 +0200
++++ openssh-5.2p1/session.c	2009-08-12 00:29:37.729578695 +0200
+@@ -1798,6 +1798,9 @@ do_child(Session *s, const char *command
+ 		argv[i] = NULL;
+ 		optind = optreset = 1;
+ 		__progname = argv[0];
++#ifdef WITH_SELINUX
++		ssh_selinux_change_context("sftpd_t");
++#endif
+ 		exit(sftp_server_main(i, argv, s->pw));
+ 	}
+ 
diff --git a/openssh-5.2p1-vendor.patch b/openssh-5.2p1-vendor.patch
new file mode 100644
index 0000000..f6db132
--- /dev/null
+++ b/openssh-5.2p1-vendor.patch
@@ -0,0 +1,158 @@
+diff -up openssh-5.2p1/configure.ac.vendor openssh-5.2p1/configure.ac
+--- openssh-5.2p1/configure.ac.vendor	2008-07-23 14:13:22.000000000 +0200
++++ openssh-5.2p1/configure.ac	2008-07-23 14:13:22.000000000 +0200
+@@ -3890,6 +3890,12 @@ AC_ARG_WITH(lastlog,
+ 		fi
+ 	]
+ )
++AC_ARG_ENABLE(vendor-patchlevel,
++  [  --enable-vendor-patchlevel=TAG  specify a vendor patch level],
++  [AC_DEFINE_UNQUOTED(SSH_VENDOR_PATCHLEVEL,[SSH_RELEASE "-" "$enableval"],[Define to your vendor patch level, if it has been modified from the upstream source release.])
++   SSH_VENDOR_PATCHLEVEL="$enableval"],
++  [AC_DEFINE(SSH_VENDOR_PATCHLEVEL,SSH_RELEASE,[Define to your vendor patch level, if it has been modified from the upstream source release.])
++   SSH_VENDOR_PATCHLEVEL=none])
+ 
+ dnl lastlog, [uw]tmpx? detection
+ dnl  NOTE: set the paths in the platform section to avoid the
+@@ -4146,6 +4152,7 @@ echo "       IP address in \$DISPLAY hac
+ echo "           Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
+ echo "                  BSD Auth support: $BSD_AUTH_MSG"
+ echo "              Random number source: $RAND_MSG"
++echo "                Vendor patch level: $SSH_VENDOR_PATCHLEVEL"
+ if test ! -z "$USE_RAND_HELPER" ; then
+ echo "     ssh-rand-helper collects from: $RAND_HELPER_MSG"
+ fi
+diff -up openssh-5.2p1/sshd_config.5.vendor openssh-5.2p1/sshd_config.5
+--- openssh-5.2p1/sshd_config.5.vendor	2008-07-23 14:13:22.000000000 +0200
++++ openssh-5.2p1/sshd_config.5	2008-07-23 14:19:23.000000000 +0200
+@@ -812,6 +812,14 @@ This option applies to protocol version 
+ .It Cm ServerKeyBits
+ Defines the number of bits in the ephemeral protocol version 1 server key.
+ The minimum value is 512, and the default is 1024.
++.It Cm ShowPatchLevel 
++Specifies whether 
++.Nm sshd 
++will display the patch level of the binary in the identification string. 
++The patch level is set at compile-time. 
++The default is 
++.Dq no . 
++This option applies to protocol version 1 only. 
+ .It Cm StrictModes
+ Specifies whether
+ .Xr sshd 8
+diff -up openssh-5.2p1/servconf.h.vendor openssh-5.2p1/servconf.h
+--- openssh-5.2p1/servconf.h.vendor	2008-06-10 15:01:51.000000000 +0200
++++ openssh-5.2p1/servconf.h	2008-07-23 14:13:22.000000000 +0200
+@@ -126,6 +126,7 @@ typedef struct {
+ 	int	max_authtries;
+ 	int	max_sessions;
+ 	char   *banner;			/* SSH-2 banner message */
++	int	show_patchlevel;	/* Show vendor patch level to clients */
+ 	int	use_dns;
+ 	int	client_alive_interval;	/*
+ 					 * poke the client this often to
+diff -up openssh-5.2p1/servconf.c.vendor openssh-5.2p1/servconf.c
+--- openssh-5.2p1/servconf.c.vendor	2008-07-04 05:51:12.000000000 +0200
++++ openssh-5.2p1/servconf.c	2008-07-23 14:32:27.000000000 +0200
+@@ -117,6 +117,7 @@ initialize_server_options(ServerOptions 
+ 	options->max_authtries = -1;
+ 	options->max_sessions = -1;
+ 	options->banner = NULL;
++	options->show_patchlevel = -1;
+ 	options->use_dns = -1;
+ 	options->client_alive_interval = -1;
+ 	options->client_alive_count_max = -1;
+@@ -262,6 +263,9 @@ fill_default_server_options(ServerOption
+ 	if (options->zero_knowledge_password_authentication == -1)
+ 		options->zero_knowledge_password_authentication = 0;
+ 
++	if (options->show_patchlevel == -1)
++ 		options->show_patchlevel = 0;
++ 
+ 	/* Turn privilege separation on by default */
+ 	if (use_privsep == -1)
+ 		use_privsep = 1;
+@@ -299,7 +303,7 @@ typedef enum {
+ 	sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
+ 	sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
+ 	sMaxStartups, sMaxAuthTries, sMaxSessions,
+-	sBanner, sUseDNS, sHostbasedAuthentication,
++	sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication,
+ 	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
+ 	sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
+ 	sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
+@@ -410,6 +414,7 @@ static struct {
+ 	{ "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
+ 	{ "maxsessions", sMaxSessions, SSHCFG_ALL },
+ 	{ "banner", sBanner, SSHCFG_ALL },
++	{ "showpatchlevel", sShowPatchLevel, SSHCFG_GLOBAL },
+ 	{ "usedns", sUseDNS, SSHCFG_GLOBAL },
+ 	{ "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
+ 	{ "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
+@@ -1033,6 +1038,10 @@ process_server_config_line(ServerOptions
+ 		intptr = &use_privsep;
+ 		goto parse_flag;
+ 
++	case sShowPatchLevel:
++		intptr = &options->show_patchlevel;
++		goto parse_flag;
++
+ 	case sAllowUsers:
+ 		while ((arg = strdelim(&cp)) && *arg != '\0') {
+ 			if (options->num_allow_users >= MAX_ALLOW_USERS)
+@@ -1613,6 +1622,7 @@ dump_config(ServerOptions *o)
+ 	dump_cfg_fmtint(sUseLogin, o->use_login);
+ 	dump_cfg_fmtint(sCompression, o->compression);
+ 	dump_cfg_fmtint(sGatewayPorts, o->gateway_ports);
++	dump_cfg_fmtint(sShowPatchLevel, o->show_patchlevel);
+ 	dump_cfg_fmtint(sUseDNS, o->use_dns);
+ 	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
+ 	dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
+diff -up openssh-5.2p1/sshd_config.0.vendor openssh-5.2p1/sshd_config.0
+--- openssh-5.2p1/sshd_config.0.vendor	2008-07-23 14:13:22.000000000 +0200
++++ openssh-5.2p1/sshd_config.0	2008-07-23 14:13:22.000000000 +0200
+@@ -466,6 +466,11 @@ DESCRIPTION
+              Defines the number of bits in the ephemeral protocol version 1
+              server key.  The minimum value is 512, and the default is 1024.
+ 
++     ShowPatchLevel
++	     Specifies whether sshd will display the specific patch level of
++	     the binary in the server identification string.  The patch level
++	     is set at compile-time.  The default is M-bM-^@M-^\noM-bM-^@M-^].
++
+      StrictModes
+              Specifies whether sshd(8) should check file modes and ownership
+              of the user's files and home directory before accepting login.
+diff -up openssh-5.2p1/sshd_config.vendor openssh-5.2p1/sshd_config
+--- openssh-5.2p1/sshd_config.vendor	2008-07-23 14:13:22.000000000 +0200
++++ openssh-5.2p1/sshd_config	2008-07-23 14:13:22.000000000 +0200
+@@ -112,6 +112,7 @@ X11Forwarding yes
+ #Compression delayed
+ #ClientAliveInterval 0
+ #ClientAliveCountMax 3
++#ShowPatchLevel no
+ #UseDNS yes
+ #PidFile /var/run/sshd.pid
+ #MaxStartups 10
+diff -up openssh-5.2p1/sshd.c.vendor openssh-5.2p1/sshd.c
+--- openssh-5.2p1/sshd.c.vendor	2008-07-11 09:36:49.000000000 +0200
++++ openssh-5.2p1/sshd.c	2008-07-23 14:35:43.000000000 +0200
+@@ -416,7 +416,7 @@ sshd_exchange_identification(int sock_in
+ 		minor = PROTOCOL_MINOR_1;
+ 	}
+ 	snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s%s", major, minor,
+-	    SSH_VERSION, newline);
++	   (options.show_patchlevel == 1) ? SSH_VENDOR_PATCHLEVEL : SSH_VERSION, newline);
+ 	server_version_string = xstrdup(buf);
+ 
+ 	/* Send our protocol version identification. */
+@@ -1484,7 +1484,8 @@ main(int ac, char **av)
+ 		exit(1);
+ 	}
+ 
+-	debug("sshd version %.100s", SSH_RELEASE);
++	debug("sshd version %.100s",
++	      (options.show_patchlevel == 1) ? SSH_VENDOR_PATCHLEVEL : SSH_RELEASE);
+ 
+ 	/* Store privilege separation user for later use if required. */
+ 	if ((privsep_pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) {
diff --git a/openssh-5.3p1-595935.patch b/openssh-5.3p1-595935.patch
new file mode 100644
index 0000000..0b915a4
--- /dev/null
+++ b/openssh-5.3p1-595935.patch
@@ -0,0 +1,22 @@
+diff -urN openssh-5.4p1/servconf.c /repo/openssh/595935/openssh/devel/openssh-5.5p1/servconf.c
+--- openssh-5.4p1/servconf.c	2010-05-31 09:55:22.000000000 +0200
++++ /repo/openssh/595935/openssh/devel/openssh-5.5p1/servconf.c	2010-05-31 09:56:13.000000000 +0200
+@@ -1271,7 +1270,17 @@
+ 		charptr = (opcode == sAuthorizedKeysFile) ?
+ 		    &options->authorized_keys_file :
+ 		    &options->authorized_keys_file2;
+-		goto parse_filename;
++		arg = strdelim(&cp);
++		if (!arg || *arg == '\0')
++			fatal("%s line %d: missing file name.",
++			    filename, linenum);
++		if (*activep && *charptr == NULL) {
++			*charptr = tilde_expand_filename(arg, getuid());
++			/* increase optional counter */
++			if (intptr != NULL)
++				*intptr = *intptr + 1;
++		}
++		break;
+ 
+ 	case sClientAliveInterval:
+ 		intptr = &options->client_alive_interval;
diff --git a/openssh-5.3p1-audit.patch b/openssh-5.3p1-audit.patch
new file mode 100644
index 0000000..6c9c981
--- /dev/null
+++ b/openssh-5.3p1-audit.patch
@@ -0,0 +1,2472 @@
+diff -up openssh-5.3p1/audit-bsm.c.audit openssh-5.3p1/audit-bsm.c
+--- openssh-5.3p1/audit-bsm.c.audit	2008-02-25 11:05:04.000000000 +0100
++++ openssh-5.3p1/audit-bsm.c	2011-04-04 20:10:08.112649127 +0200
+@@ -298,20 +298,45 @@ audit_connection_from(const char *host, 
+ #endif
+ }
+ 
+-void
++int
+ audit_run_command(const char *command)
+ {
+ 	/* not implemented */
++	return 0;
+ }
+ 
+ void
+-audit_session_open(const char *ttyn)
++audit_end_command(int handle, const char *command)
+ {
+ 	/* not implemented */
+ }
+ 
+ void
+-audit_session_close(const char *ttyn)
++audit_count_session_open(void)
++{
++	/* not necessary */
++}
++
++void
++audit_session_open(struct logininfo *li)
++{
++	/* not implemented */
++}
++
++void
++audit_session_close(struct logininfo *li)
++{
++	/* not implemented */
++}
++
++int
++audit_keyusage(int host_user, const char *type, unsigned len, char *fp, int rv)
++{
++	/* not implemented */
++}
++
++int
++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv)
+ {
+ 	/* not implemented */
+ }
+@@ -377,4 +402,64 @@ audit_event(ssh_audit_event_t event)
+ 		debug("%s: unhandled event %d", __func__, event);
+ 	}
+ }
++
++void
++audit_unsupported_body(int what)
++{
++	/* not implemented */
++}
++
++void
++audit_kex_body(int ctos, char *enc, char *mac, char *compress)
++{
++	/* not implemented */
++}
++
++void
++audit_session_key_free_body(int ctos)
++{
++	/* not implemented */
++}
++
++void
++audit_destroy_sensitive_data(void)
++{
++	/* not implemented */
++}
++
++void
++audit_unsupported_body(int what)
++{
++	/* not implemented */
++}
++
++void
++audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, uid_t uid)
++{
++	/* not implemented */
++}
++
++void
++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
++{
++	/* not implemented */
++}
++
++void
++audit_destroy_sensitive_data(const char *fp)
++{
++	/* not implemented */
++}
++
++void
++audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid)
++{
++	/* not implemented */
++}
++
++void
++audit_generate_ephemeral_server_key(const char *fp)
++{
++	/* not implemented */
++}
+ #endif /* BSM */
+diff -up openssh-5.3p1/audit.c.audit openssh-5.3p1/audit.c
+--- openssh-5.3p1/audit.c.audit	2006-09-01 07:38:36.000000000 +0200
++++ openssh-5.3p1/audit.c	2011-04-04 20:10:08.158649007 +0200
+@@ -28,6 +28,8 @@
+ 
+ #include <stdarg.h>
+ #include <string.h>
++#include <unistd.h>
++#include <openssl/fips.h>
+ 
+ #ifdef SSH_AUDIT_EVENTS
+ 
+@@ -36,6 +38,11 @@
+ #include "key.h"
+ #include "hostfile.h"
+ #include "auth.h"
++#include "ssh-gss.h"
++#include "monitor_wrap.h"
++#include "xmalloc.h"
++#include "ssh-gss.h"
++#include "monitor_wrap.h"
+ 
+ /*
+  * Care must be taken when using this since it WILL NOT be initialized when
+@@ -111,6 +118,40 @@ audit_event_lookup(ssh_audit_event_t ev)
+ 	return(event_lookup[i].name);
+ }
+ 
++void
++audit_key(int host_user, int *rv, const Key *key)
++{
++	char *fp;
++	const char *crypto_name;
++
++	fp = key_fingerprint(key, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
++	if (key->type == KEY_RSA1)
++		crypto_name = "ssh-rsa1";
++	else
++		crypto_name = key_ssh_name(key);
++	if (audit_keyusage(host_user, crypto_name, key_size(key), fp, *rv) == 0)
++		*rv = 0;
++	xfree(fp);
++}
++
++void
++audit_unsupported(int what)
++{
++	PRIVSEP(audit_unsupported_body(what));
++}
++
++void
++audit_kex(int ctos, char *enc, char *mac, char *comp)
++{
++	PRIVSEP(audit_kex_body(ctos, enc, mac, comp, getpid(), getuid()));
++}
++
++void
++audit_session_key_free(int ctos)
++{
++	PRIVSEP(audit_session_key_free_body(ctos, getpid(), getuid()));
++}
++
+ # ifndef CUSTOM_SSH_AUDIT_EVENTS
+ /*
+  * Null implementations of audit functions.
+@@ -140,6 +181,17 @@ audit_event(ssh_audit_event_t event)
+ }
+ 
+ /*
++ * Called when a child process has called, or will soon call,
++ * audit_session_open.
++ */
++void
++audit_count_session_open(void)
++{
++	debug("audit count session open euid %d user %s", geteuid(),
++	      audit_username());
++}
++
++/*
+  * Called when a user session is started.  Argument is the tty allocated to
+  * the session, or NULL if no tty was allocated.
+  *
+@@ -147,9 +199,9 @@ audit_event(ssh_audit_event_t event)
+  * within a single connection.
+  */
+ void
+-audit_session_open(const char *ttyn)
++audit_session_open(struct logininfo *li)
+ {
+-	const char *t = ttyn ? ttyn : "(no tty)";
++	const char *t = li->line ? li->line : "(no tty)";
+ 
+ 	debug("audit session open euid %d user %s tty name %s", geteuid(),
+ 	    audit_username(), t);
+@@ -163,9 +215,9 @@ audit_session_open(const char *ttyn)
+  * within a single connection.
+  */
+ void
+-audit_session_close(const char *ttyn)
++audit_session_close(struct logininfo *li)
+ {
+-	const char *t = ttyn ? ttyn : "(no tty)";
++	const char *t = li->line ? li->line : "(no tty)";
+ 
+ 	debug("audit session close euid %d user %s tty name %s", geteuid(),
+ 	    audit_username(), t);
+@@ -174,13 +226,138 @@ audit_session_close(const char *ttyn)
+ /*
+  * This will be called when a user runs a non-interactive command.  Note that
+  * it may be called multiple times for a single connection since SSH2 allows
+- * multiple sessions within a single connection.
++ * multiple sessions within a single connection.  Returns a "handle" for
++ * audit_end_command.
+  */
+-void
++int
+ audit_run_command(const char *command)
+ {
+ 	debug("audit run command euid %d user %s command '%.200s'", geteuid(),
+ 	    audit_username(), command);
++	return 0;
++}
++
++/*
++ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key.
++ *
++ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key.
++ */
++int
++audit_keyusage(int host_user, const char *type, unsigned len, char *fp, int rv)
++{
++	debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s, result %d", 
++		host_user ? "hostbased" : "pubkey", geteuid(), audit_username(), type, len, fp, rv);
++}
++
++/*
++ * This will be called when the protocol negotiation fails.
++ */
++void
++audit_unsupported_body(int what)
++{
++	debug("audit unsupported protocol ieuid %d type %d", geteuid(), what);
++
++
++/*
++ * This will be called on succesfull protocol negotiation.
++ */
++void
++audit_kex_body(int ctos, char *enc, char *mac, char *compress)
++{
++	debug("audit procol negotiation euid %d direction %d cipher %s mac %s compresion %s",
++		geteuid(), ctos, enc, mac, compress);
++}
++
++/*
++ * This will be called on succesfull session key discard
++ */
++audit_session_key_free_body(int ctos)
++{
++	debug("audit session key discard euid %d direction %d", geteuid(), ctos);
++}
++
++/*
++ * This will be called on destroy private part of the server key
++ */
++void
++audit_destroy_sensitive_data(void)
++{
++	debug("audit destroy sensitive data euid %d", geteuid());
++}
++
++/*
++ * This will be called when the non-interactive command finishes.  Note that
++ * it may be called multiple times for a single connection since SSH2 allows
++ * multiple sessions within a single connection.  "handle" should come from
++ * the corresponding audit_run_command.
++ */
++void
++audit_end_command(int handle, const char *command)
++{
++	debug("audit end nopty exec  euid %d user %s command '%.200s'", geteuid(),
++	    audit_username(), command);
++}
++
++/*
++ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key.
++ *
++ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key.
++ */
++int
++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv)
++{
++	debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s, result %d", 
++		host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), type, bits, fp, rv);
++}
++
++/*
++ * This will be called when the protocol negotiation fails.
++ */
++void
++audit_unsupported_body(int what)
++{
++	debug("audit unsupported protocol ieuid %d type %d", geteuid(), what);
++}
++
++/*
++ * This will be called on succesfull protocol negotiation.
++ */
++void
++audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid,
++	       uid_t uid)
++{
++	debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s from pid %ld uid %u",
++		(unsigned)geteuid(), ctos, enc, mac, compress, (long)pid,
++	        (unsigned)uid);
++}
++
++/*
++ * This will be called on succesfull session key discard
++ */
++void
++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
++{
++	debug("audit session key discard euid %u direction %d from pid %ld uid %u",
++		(unsigned)geteuid(), ctos, (long)pid, (unsigned)uid);
++}
++
++/*
++ * This will be called on destroy private part of the server key
++ */
++void
++audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid)
++{
++	debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u",
++		geteuid(), fp, (long)pid, (unsigned)uid);
++}
++
++/*
++ * This will be called on generation of the ephemeral server key
++ */
++void
++audit_generate_ephemeral_server_key(const char *)
++{
++	debug("audit create ephemeral server key euid %d fingerprint %s", geteuid(), fp);
+ }
+ # endif  /* !defined CUSTOM_SSH_AUDIT_EVENTS */
+ #endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-5.3p1/audit.h.audit openssh-5.3p1/audit.h
+--- openssh-5.3p1/audit.h.audit	2006-08-05 16:05:10.000000000 +0200
++++ openssh-5.3p1/audit.h	2011-04-04 20:10:08.196649127 +0200
+@@ -26,6 +26,10 @@
+ 
+ #ifndef _SSH_AUDIT_H
+ # define _SSH_AUDIT_H
++
++#include "loginrec.h"
++#include "key.h"
++
+ enum ssh_audit_event_type {
+ 	SSH_LOGIN_EXCEED_MAXTRIES,
+ 	SSH_LOGIN_ROOT_DENIED,
+@@ -44,11 +48,30 @@ enum ssh_audit_event_type {
+ };
+ typedef enum ssh_audit_event_type ssh_audit_event_t;
+ 
++int	listening_for_clients(void);
++
+ void	audit_connection_from(const char *, int);
+ void	audit_event(ssh_audit_event_t);
+-void	audit_session_open(const char *);
+-void	audit_session_close(const char *);
+-void	audit_run_command(const char *);
++void	audit_count_session_open(void);
++void	audit_session_open(struct logininfo *);
++void	audit_session_close(struct logininfo *);
++int	audit_run_command(const char *);
++void 	audit_end_command(int, const char *);
+ ssh_audit_event_t audit_classify_auth(const char *);
++int	audit_keyusage(int, const char *, unsigned, char *, int);
++void	audit_unsupported(int);
++void	audit_kex(int, char *, char *, char *);
++void	audit_unsupported_body(int);
++void	audit_session_key_free(int ctos);
++int	audit_keyusage(int, const char *, unsigned, char *, int);
++void	audit_key(int, int *, const Key *);
++void	audit_unsupported(int);
++void	audit_kex(int, char *, char *, char *);
++void	audit_unsupported_body(int);
++void	audit_kex_body(int, char *, char *, char *, pid_t, uid_t);
++void	audit_session_key_free(int ctos);
++void	audit_session_key_free_body(int ctos, pid_t, uid_t);
++void	audit_destroy_sensitive_data(const char *, pid_t, uid_t);
++void	audit_generate_ephemeral_server_key(const char *);
+ 
+ #endif /* _SSH_AUDIT_H */
+diff -up openssh-5.3p1/audit-linux.c.audit openssh-5.3p1/audit-linux.c
+--- openssh-5.3p1/audit-linux.c.audit	2011-04-04 20:10:08.218648913 +0200
++++ openssh-5.3p1/audit-linux.c	2011-04-04 20:10:09.610648556 +0200
+@@ -0,0 +1,405 @@
++/* $Id: audit-linux.c,v 1.1 2011/01/17 10:15:30 dtucker Exp $ */
++
++/*
++ * Copyright 2010 Red Hat, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * Red Hat author: Jan F. Chadima <jchadima at redhat.com>
++ */
++
++#include "includes.h"
++#if defined(USE_LINUX_AUDIT)
++#include <libaudit.h>
++#include <unistd.h>
++#include <string.h>
++
++#include "log.h"
++#include "audit.h"
++#include "key.h"
++#include "hostfile.h"
++#include "auth.h"
++#include "servconf.h"
++#include "canohost.h"
++#include "packet.h"
++#include "cipher.h"
++
++#define AUDIT_LOG_SIZE 128
++
++extern ServerOptions options;
++extern Authctxt *the_authctxt;
++extern u_int utmp_len;
++const char* audit_username(void);
++
++static void
++linux_audit_user_logxxx(int uid, const char *username,
++    const char *hostname, const char *ip, const char *ttyn, int success, int event)
++{
++	int audit_fd, rc, saved_errno;
++
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
++		    errno == EAFNOSUPPORT)
++			return; /* No audit support in kernel */
++		else
++			goto fatal_report; /* Must prevent login */
++	}
++	rc = audit_log_acct_message(audit_fd, event,
++	    NULL, "login", username ? username : "(unknown)",
++	    username == NULL ? uid : -1, hostname, ip, ttyn, success);
++	saved_errno = errno;
++	close(audit_fd);
++	/*
++	 * Do not report error if the error is EPERM and sshd is run as non
++	 * root user.
++	 */
++	if ((rc == -EPERM) && (geteuid() != 0))
++		rc = 0;
++	errno = saved_errno;
++	if (rc < 0) {
++fatal_report:
++		fatal("linux_audit_write_entry failed: %s", strerror(errno));
++	}
++}
++
++static void
++linux_audit_user_auth(int uid, const char *username,
++    const char *hostname, const char *ip, const char *ttyn, int success, int event)
++{
++	int audit_fd, rc, saved_errno;
++	static const char *event_name[] = {
++		"maxtries exceeded",
++		"root denied",
++		"success",
++		"none",
++		"password",
++		"challenge-response",
++		"pubkey",
++		"hostbased",
++		"gssapi",
++		"invalid user",
++		"nologin",
++		"connection closed",
++		"connection abandoned",
++		"unknown"
++	};
++
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
++		    errno == EAFNOSUPPORT)
++			return; /* No audit support in kernel */
++		else
++			goto fatal_report; /* Must prevent login */
++	}
++	
++	if ((event < 0) || (event > SSH_AUDIT_UNKNOWN))
++		event = SSH_AUDIT_UNKNOWN;
++
++	rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH,
++	    NULL, event_name[event], username ? username : "(unknown)",
++	    username == NULL ? uid : -1, hostname, ip, ttyn, success);
++	saved_errno = errno;
++	close(audit_fd);
++	/*
++	 * Do not report error if the error is EPERM and sshd is run as non
++	 * root user.
++	 */
++	if ((rc == -EPERM) && (geteuid() != 0))
++		rc = 0;
++	errno = saved_errno;
++	if (rc < 0) {
++fatal_report:
++		fatal("linux_audit_write_entry failed: %s", strerror(errno));
++	}
++}
++
++static const char *
++_get_remote_ipaddr()
++{
++	return packet_is_active() ? get_remote_ipaddr() : "?";
++}
++
++int
++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv)
++{
++	char buf[AUDIT_LOG_SIZE];
++	int audit_fd, rc, saved_errno;
++
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
++					 errno == EAFNOSUPPORT)
++			return 1; /* No audit support in kernel */
++		else                                                                                                                                       
++			return 0; /* Must prevent login */
++	}
++	snprintf(buf, sizeof(buf), "%s_auth rport=%d", host_user ? "pubkey" : "hostbased", get_remote_port());
++	rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
++		buf, audit_username(), -1, NULL, _get_remote_ipaddr(), NULL, rv);
++	if ((rc < 0) && ((rc != -1) || (getuid() == 0)))
++		goto out;
++	snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s rport=%d",
++			type, bits, fp, get_remote_port());
++	rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
++		buf, audit_username(), -1, NULL, _get_remote_ipaddr(), NULL, rv);
++out:
++	saved_errno = errno;
++	audit_close(audit_fd);
++	errno = saved_errno;
++	/* do not report error if the error is EPERM and sshd is run as non root user */
++	return (rc >= 0) || ((rc == -EPERM) && (getuid() != 0));
++}
++
++static int user_login_count = 0;
++
++/* Below is the sshd audit API code */
++
++void
++audit_connection_from(const char *host, int port)
++{
++	/* not implemented */
++}
++
++int
++audit_run_command(const char *command)
++{
++	if (!user_login_count++) 
++		linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++		    NULL, "ssh", 1, AUDIT_USER_LOGIN);
++	linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++	    NULL, "ssh", 1, AUDIT_USER_START);
++	return 0;
++}
++
++void
++audit_end_command(int handle, const char *command)
++{
++	linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++	    NULL, "ssh", 1, AUDIT_USER_END);
++	if (user_login_count && !--user_login_count) 
++		linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++		    NULL, "ssh", 1, AUDIT_USER_LOGOUT);
++}
++
++void
++audit_count_session_open(void)
++{
++	user_login_count++;
++}
++
++void
++audit_session_open(struct logininfo *li)
++{
++	if (!user_login_count++) 
++		linux_audit_user_logxxx(li->uid, NULL, li->hostname,
++		    NULL, li->line, 1, AUDIT_USER_LOGIN);
++	linux_audit_user_logxxx(li->uid, NULL, li->hostname,
++	    NULL, li->line, 1, AUDIT_USER_START);
++}
++
++void
++audit_session_close(struct logininfo *li)
++{
++	linux_audit_user_logxxx(li->uid, NULL, li->hostname,
++	    NULL, li->line, 1, AUDIT_USER_END);
++	if (user_login_count && !--user_login_count) 
++		linux_audit_user_logxxx(li->uid, NULL, li->hostname,
++		    NULL, li->line, 1, AUDIT_USER_LOGOUT);
++}
++
++void
++audit_event(ssh_audit_event_t event)
++{
++	switch(event) {
++	case SSH_AUTH_SUCCESS:
++		linux_audit_user_auth(-1, audit_username(), NULL,
++			_get_remote_ipaddr(), "ssh", 1, event);
++		break;
++
++	case SSH_NOLOGIN:
++	case SSH_LOGIN_ROOT_DENIED:
++		linux_audit_user_auth(-1, audit_username(), NULL,
++			_get_remote_ipaddr(), "ssh", 0, event);
++		linux_audit_user_logxxx(-1, audit_username(), NULL,
++			_get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN);
++		break;
++
++	case SSH_LOGIN_EXCEED_MAXTRIES:
++	case SSH_AUTH_FAIL_NONE:
++	case SSH_AUTH_FAIL_PASSWD:
++	case SSH_AUTH_FAIL_KBDINT:
++	case SSH_AUTH_FAIL_PUBKEY:
++	case SSH_AUTH_FAIL_HOSTBASED:
++	case SSH_AUTH_FAIL_GSSAPI:
++		linux_audit_user_auth(-1, audit_username(), NULL,
++			_get_remote_ipaddr(), "ssh", 0, event);
++		break;
++
++	case SSH_CONNECTION_CLOSE:
++		if (user_login_count) {
++			while (user_login_count--)
++				linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++				    NULL, "ssh", 1, AUDIT_USER_END);
++			linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++			    NULL, "ssh", 1, AUDIT_USER_LOGOUT);
++		}
++		break;
++
++	case SSH_CONNECTION_ABANDON:
++	case SSH_INVALID_USER:
++		linux_audit_user_logxxx(-1, audit_username(), NULL,
++			_get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN);
++		break;
++
++	default:
++		debug("%s: unhandled event %d", __func__, event);
++	}
++}
++
++void
++audit_unsupported_body(int what)
++{
++#ifdef AUDIT_CRYPTO_SESSION
++	char buf[AUDIT_LOG_SIZE];
++	const static char *name[] = { "cipher", "mac", "comp" };
++	int audit_fd;
++
++	snprintf(buf, sizeof(buf), "op=unsupported-%s direction=? cipher=? ksize=? rport=%d laddr=%s lport=%d ",
++		name[what], get_remote_port(), get_local_ipaddr(packet_get_connection_in()),
++		get_local_port());
++	audit_fd = audit_open();
++	if (audit_fd < 0)
++		/* no problem, the next instruction will be fatal() */
++		return;
++	audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION,
++			buf, NULL, _get_remote_ipaddr(), NULL, 0);
++	audit_close(audit_fd);
++#endif
++}
++
++const static char *direction[] = { "from-server", "from-client", "both" };
++
++void
++audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid,
++	       uid_t uid)
++{
++#ifdef AUDIT_CRYPTO_SESSION
++	char buf[AUDIT_LOG_SIZE];
++	int audit_fd, audit_ok;
++	Cipher *cipher = cipher_by_name(enc);
++
++	snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d spid=%jd suid=%jd rport=%d laddr=%s lport=%d ",
++		direction[ctos], enc, cipher ? 8 * cipher->key_len : 0,
++		(intmax_t)pid, (intmax_t)uid,
++		get_remote_port(), get_local_ipaddr(packet_get_connection_in()), get_local_port());
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
++					 errno == EAFNOSUPPORT)
++			return; /* No audit support in kernel */
++		else                                                                                                                                       
++			fatal("cannot open audit"); /* Must prevent login */
++	}
++	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION,
++			buf, NULL, _get_remote_ipaddr(), NULL, 1);
++	audit_close(audit_fd);
++	/* do not abort if the error is EPERM and sshd is run as non root user */
++	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
++		fatal("cannot write into audit"); /* Must prevent login */
++#endif
++}
++
++void
++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
++{
++	char buf[AUDIT_LOG_SIZE];
++	int audit_fd, audit_ok;
++
++	snprintf(buf, sizeof(buf), "op=destroy kind=session fp=? direction=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ",
++		 direction[ctos], (intmax_t)pid, (intmax_t)uid,
++		 get_remote_port(),
++		 get_local_ipaddr(packet_get_connection_in()),
++		 get_local_port());
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno != EINVAL && errno != EPROTONOSUPPORT &&
++					 errno != EAFNOSUPPORT)
++			error("cannot open audit");
++		return;
++	}
++	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER,
++			buf, NULL, _get_remote_ipaddr(), NULL, 1);
++	audit_close(audit_fd);
++	/* do not abort if the error is EPERM and sshd is run as non root user */
++	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
++		error("cannot write into audit");
++}
++
++void
++audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid)
++{
++	char buf[AUDIT_LOG_SIZE];
++	int audit_fd, audit_ok;
++
++	snprintf(buf, sizeof(buf), "op=destroy kind=server fp=%s direction=? spid=%jd suid=%jd ",
++		fp, (intmax_t)pid, (intmax_t)uid);
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno != EINVAL && errno != EPROTONOSUPPORT &&
++					 errno != EAFNOSUPPORT)
++			error("cannot open audit");
++		return;
++	}
++	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER,
++			buf, NULL,
++			listening_for_clients() ? NULL : _get_remote_ipaddr(),
++			NULL, 1);
++	audit_close(audit_fd);
++	/* do not abort if the error is EPERM and sshd is run as non root user */
++	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
++		error("cannot write into audit");
++}
++
++void
++audit_generate_ephemeral_server_key(const char *fp)
++{
++	char buf[AUDIT_LOG_SIZE];
++	int audit_fd, audit_ok;
++
++	snprintf(buf, sizeof(buf), "op=create kind=server fp=%s direction=? ", fp);
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno != EINVAL && errno != EPROTONOSUPPORT &&
++					 errno != EAFNOSUPPORT)
++			error("cannot open audit");
++		return;
++	}
++	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER,
++			buf, NULL, 0, NULL, 1);
++	audit_close(audit_fd);
++	/* do not abort if the error is EPERM and sshd is run as non root user */
++	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
++		error("cannot write into audit");
++}
++#endif /* USE_LINUX_AUDIT */
+diff -up openssh-5.3p1/auditstub.c.audit openssh-5.3p1/auditstub.c
+--- openssh-5.3p1/auditstub.c.audit	2011-04-04 20:10:08.241649015 +0200
++++ openssh-5.3p1/auditstub.c	2011-04-04 20:10:08.249648985 +0200
+@@ -0,0 +1,50 @@
++/* $Id: auditstub.c,v 1.1 jfch Exp $ */
++
++/*
++ * Copyright 2010 Red Hat, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * Red Hat author: Jan F. Chadima <jchadima at redhat.com>
++ */
++
++#include <sys/types.h>
++
++void
++audit_unsupported(int n)
++{
++}
++
++void
++audit_kex(int ctos, char *enc, char *mac, char *comp)
++{
++}
++
++void
++audit_session_key_free(int ctos)
++{
++}
++
++void
++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
++{
++}
+diff -up openssh-5.3p1/auth2.c.audit openssh-5.3p1/auth2.c
+--- openssh-5.3p1/auth2.c.audit	2011-04-04 20:10:05.292648615 +0200
++++ openssh-5.3p1/auth2.c	2011-04-04 20:10:08.283648602 +0200
+@@ -250,9 +250,6 @@ input_userauth_request(int type, u_int32
+ 		} else {
+ 			logit("input_userauth_request: invalid user %s", user);
+ 			authctxt->pw = fakepw();
+-#ifdef SSH_AUDIT_EVENTS
+-			PRIVSEP(audit_event(SSH_INVALID_USER));
+-#endif
+ 		}
+ #ifdef USE_PAM
+ 		if (options.use_pam)
+diff -up openssh-5.3p1/auth2-hostbased.c.audit openssh-5.3p1/auth2-hostbased.c
+--- openssh-5.3p1/auth2-hostbased.c.audit	2011-04-04 20:09:56.936648555 +0200
++++ openssh-5.3p1/auth2-hostbased.c	2011-04-04 20:10:08.322648890 +0200
+@@ -127,7 +127,7 @@ userauth_hostbased(Authctxt *authctxt)
+ 	/* test for allowed key and correct signature */
+ 	authenticated = 0;
+ 	if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) &&
+-	    PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
++	    PRIVSEP(hostbased_key_verify(key, sig, slen, buffer_ptr(&b),
+ 			buffer_len(&b))) == 1)
+ 		authenticated = 1;
+ 
+@@ -144,6 +144,18 @@ done:
+ 	return authenticated;
+ }
+ 
++int
++hostbased_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen)
++{
++	int rv;
++
++	rv = key_verify(key, sig, slen, data, datalen);
++#ifdef SSH_AUDIT_EVENTS
++	audit_key(0, &rv, key);
++#endif
++	return rv;
++}
++
+ /* return 1 if given hostkey is allowed */
+ int
+ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
+diff -up openssh-5.3p1/auth2-pubkey.c.audit openssh-5.3p1/auth2-pubkey.c
+--- openssh-5.3p1/auth2-pubkey.c.audit	2011-04-04 20:10:07.492648810 +0200
++++ openssh-5.3p1/auth2-pubkey.c	2011-04-04 20:10:08.370648809 +0200
+@@ -146,7 +146,7 @@ userauth_pubkey(Authctxt *authctxt)
+ 		/* test for correct signature */
+ 		authenticated = 0;
+ 		if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
+-		    PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
++		    PRIVSEP(user_key_verify(key, sig, slen, buffer_ptr(&b),
+ 		    buffer_len(&b))) == 1)
+ 			authenticated = 1;
+ 		buffer_free(&b);
+@@ -183,6 +183,18 @@ done:
+ 	return authenticated;
+ }
+ 
++int
++user_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen)
++{
++	int rv;
++
++	rv = key_verify(key, sig, slen, data, datalen);
++#ifdef SSH_AUDIT_EVENTS
++	audit_key(1, &rv, key);
++#endif
++	return rv;
++}
++
+ /* return 1 if user allows given key */
+ static int
+ user_search_key_in_file(FILE *f, char *file, Key* key, struct passwd *pw)
+diff -up openssh-5.3p1/auth.h.audit openssh-5.3p1/auth.h
+--- openssh-5.3p1/auth.h.audit	2011-04-04 20:10:05.390648642 +0200
++++ openssh-5.3p1/auth.h	2011-04-04 20:10:08.414648880 +0200
+@@ -173,6 +173,7 @@ void	abandon_challenge_response(Authctxt
+ 
+ char	*authorized_keys_file(struct passwd *);
+ char	*authorized_keys_file2(struct passwd *);
++int	 user_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
+ 
+ FILE	*auth_openkeyfile(const char *, struct passwd *, int);
+ 
+@@ -185,6 +186,7 @@ Key	*get_hostkey_by_index(int);
+ Key	*get_hostkey_by_type(int);
+ int	 get_hostkey_index(Key *);
+ int	 ssh1_session_key(BIGNUM *);
++int	 hostbased_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
+ 
+ /* debug messages during authentication */
+ void	 auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+diff -up openssh-5.3p1/auth-rsa.c.audit openssh-5.3p1/auth-rsa.c
+--- openssh-5.3p1/auth-rsa.c.audit	2008-07-02 14:37:30.000000000 +0200
++++ openssh-5.3p1/auth-rsa.c	2011-04-04 20:10:08.460659359 +0200
+@@ -92,7 +92,10 @@ auth_rsa_verify_response(Key *key, BIGNU
+ {
+ 	u_char buf[32], mdbuf[16];
+ 	MD5_CTX md;
+-	int len;
++	int len, rv;
++#ifdef SSH_AUDIT_EVENTS
++	char *fp;
++#endif
+ 
+ 	/* don't allow short keys */
+ 	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
+@@ -113,12 +116,18 @@ auth_rsa_verify_response(Key *key, BIGNU
+ 	MD5_Final(mdbuf, &md);
+ 
+ 	/* Verify that the response is the original challenge. */
+-	if (memcmp(response, mdbuf, 16) != 0) {
+-		/* Wrong answer. */
+-		return (0);
++	rv = memcmp(response, mdbuf, 16) == 0;
++
++#ifdef SSH_AUDIT_EVENTS
++	fp = key_fingerprint(key, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
++	if (audit_keyusage(1, "ssh-rsa1", RSA_size(key->rsa) * 8, fp, rv) == 0) {
++		debug("unsuccessful audit");
++		rv = 0;
+ 	}
+-	/* Correct answer. */
+-	return (1);
++	xfree(fp);
++#endif
++
++	return rv;
+ }
+ 
+ /*
+diff -up openssh-5.3p1/cipher.c.audit openssh-5.3p1/cipher.c
+--- openssh-5.3p1/cipher.c.audit	2011-04-04 20:10:03.982648668 +0200
++++ openssh-5.3p1/cipher.c	2011-04-04 20:10:08.505648940 +0200
+@@ -60,15 +60,7 @@ extern void ssh1_3des_iv(EVP_CIPHER_CTX 
+ extern const EVP_CIPHER *evp_aes_128_ctr(void);
+ extern void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, u_int);
+ 
+-struct Cipher {
+-	char	*name;
+-	int	number;		/* for ssh1 only */
+-	u_int	block_size;
+-	u_int	key_len;
+-	u_int	discard_len;
+-	u_int	cbc_mode;
+-	const EVP_CIPHER	*(*evptype)(void);
+-} ciphers[] = {
++struct Cipher ciphers[] = {
+ 	{ "none",		SSH_CIPHER_NONE, 8, 0, 0, 0, EVP_enc_null },
+ 	{ "des",		SSH_CIPHER_DES, 8, 8, 0, 1, EVP_des_cbc },
+ 	{ "3des",		SSH_CIPHER_3DES, 8, 16, 0, 1, evp_ssh1_3des },
+diff -up openssh-5.3p1/cipher.h.audit openssh-5.3p1/cipher.h
+--- openssh-5.3p1/cipher.h.audit	2011-04-04 20:10:04.066648691 +0200
++++ openssh-5.3p1/cipher.h	2011-04-04 20:10:08.545648949 +0200
+@@ -61,7 +61,16 @@
+ typedef struct Cipher Cipher;
+ typedef struct CipherContext CipherContext;
+ 
+-struct Cipher;
++struct Cipher {
++	char	*name;
++	int	number;		/* for ssh1 only */
++	u_int	block_size;
++	u_int	key_len;
++	u_int	discard_len;
++	u_int	cbc_mode;
++	const EVP_CIPHER	*(*evptype)(void);
++};
++
+ struct CipherContext {
+ 	int	plaintext;
+ 	EVP_CIPHER_CTX evp;
+diff -up openssh-5.3p1/configure.ac.audit openssh-5.3p1/configure.ac
+--- openssh-5.3p1/configure.ac.audit	2011-04-04 20:10:07.562701539 +0200
++++ openssh-5.3p1/configure.ac	2011-04-04 20:10:08.618707290 +0200
+@@ -1305,7 +1305,7 @@ int main(void)
+ 
+ AUDIT_MODULE=none
+ AC_ARG_WITH(audit,
+-	[  --with-audit=module     Enable EXPERIMENTAL audit support (modules=debug,bsm)],
++	[  --with-audit=module     Enable audit support (modules=debug,bsm,linux)],
+ 	[
+ 	  AC_MSG_CHECKING(for supported audit module)
+ 	  case "$withval" in
+@@ -1329,10 +1329,18 @@ AC_ARG_WITH(audit,
+ 		AC_CHECK_FUNCS(getaudit_addr aug_get_machine)
+ 		AC_DEFINE(USE_BSM_AUDIT, 1, [Use BSM audit module])
+ 		;;
++	  linux)
++		AC_MSG_RESULT(linux)
++		AUDIT_MODULE=linux
++		dnl    Checks for headers, libs and functions
++		AC_CHECK_HEADERS(libaudit.h)
++		SSHDLIBS="$SSHDLIBS -laudit"
++		AC_DEFINE(USE_LINUX_AUDIT, 1, [Use Linux audit module])
++		;;
+ 	  debug)
+ 		AUDIT_MODULE=debug
+ 		AC_MSG_RESULT(debug)
+-		AC_DEFINE(SSH_AUDIT_EVENTS, 1, Use audit debugging module)
++		AC_DEFINE(SSH_AUDIT_EVENTS, 1, [Use audit debugging module])
+ 		;;
+ 	  no)
+ 		AC_MSG_RESULT(no)
+diff -up openssh-5.3p1/defines.h.audit openssh-5.3p1/defines.h
+--- openssh-5.3p1/defines.h.audit	2009-08-28 03:21:07.000000000 +0200
++++ openssh-5.3p1/defines.h	2011-04-04 20:10:08.662649032 +0200
+@@ -566,6 +566,11 @@ struct winsize {
+ # define CUSTOM_SSH_AUDIT_EVENTS
+ #endif
+ 
++#ifdef USE_LINUX_AUDIT
++# define SSH_AUDIT_EVENTS
++# define CUSTOM_SSH_AUDIT_EVENTS
++#endif
++
+ #if !defined(HAVE___func__) && defined(HAVE___FUNCTION__)
+ #  define __func__ __FUNCTION__
+ #elif !defined(HAVE___func__)
+diff -up openssh-5.3p1/kex.c.audit openssh-5.3p1/kex.c
+--- openssh-5.3p1/kex.c.audit	2011-04-04 20:10:05.795648638 +0200
++++ openssh-5.3p1/kex.c	2011-04-04 20:10:08.704648754 +0200
+@@ -48,6 +48,7 @@
+ #include "match.h"
+ #include "dispatch.h"
+ #include "monitor.h"
++#include "audit.h"
+ 
+ #ifdef GSSAPI
+ #include "ssh-gss.h"
+@@ -261,9 +262,13 @@ static void
+ choose_enc(Enc *enc, char *client, char *server)
+ {
+ 	char *name = match_list(client, server, NULL);
+-	if (name == NULL)
++	if (name == NULL) {
++#ifdef SSH_AUDIT_EVENTS
++		audit_unsupported(0);
++#endif
+ 		fatal("no matching cipher found: client %s server %s",
+ 		    client, server);
++	}
+ 	if ((enc->cipher = cipher_by_name(name)) == NULL)
+ 		fatal("matching cipher is not supported: %s", name);
+ 	enc->name = name;
+@@ -278,9 +283,13 @@ static void
+ choose_mac(Mac *mac, char *client, char *server)
+ {
+ 	char *name = match_list(client, server, NULL);
+-	if (name == NULL)
++	if (name == NULL) {
++#ifdef SSH_AUDIT_EVENTS
++		audit_unsupported(1);
++#endif
+ 		fatal("no matching mac found: client %s server %s",
+ 		    client, server);
++	}
+ 	if (mac_setup(mac, name) < 0)
+ 		fatal("unsupported mac %s", name);
+ 	/* truncate the key */
+@@ -295,8 +304,12 @@ static void
+ choose_comp(Comp *comp, char *client, char *server)
+ {
+ 	char *name = match_list(client, server, NULL);
+-	if (name == NULL)
++	if (name == NULL) {
++#ifdef SSH_AUDIT_EVENTS
++		audit_unsupported(2);
++#endif
+ 		fatal("no matching comp found: client %s server %s", client, server);
++	}
+ 	if (strcmp(name, "zlib at openssh.com") == 0) {
+ 		comp->type = COMP_DELAYED;
+ 	} else if (strcmp(name, "zlib") == 0) {
+@@ -421,6 +434,9 @@ kex_choose_conf(Kex *kex)
+ 		    newkeys->enc.name,
+ 		    newkeys->mac.name,
+ 		    newkeys->comp.name);
++#ifdef SSH_AUDIT_EVENTS
++		audit_kex(ctos, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name);
++#endif
+ 	}
+ 	choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
+ 	choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
+@@ -583,3 +599,34 @@ dump_digest(char *msg, u_char *digest, i
+ 	fprintf(stderr, "\n");
+ }
+ #endif
++
++static void
++enc_destroy(Enc *enc)
++{
++	if (enc == NULL)
++		return;
++
++	if (enc->key) {
++		memset(enc->key, 0, enc->key_len);
++		xfree(enc->key);
++	}
++
++	if (enc->iv) {
++		memset(enc->iv,  0, enc->block_size);
++		xfree(enc->iv);
++	}
++
++	memset(enc, 0, sizeof(*enc));
++}
++
++void
++newkeys_destroy(Newkeys *newkeys)
++{
++	if (newkeys == NULL)
++		return;
++
++	enc_destroy(&newkeys->enc);
++	mac_destroy(&newkeys->mac);
++	memset(&newkeys->comp, 0, sizeof(newkeys->comp));
++}
++
+diff -up openssh-5.3p1/kex.h.audit openssh-5.3p1/kex.h
+--- openssh-5.3p1/kex.h.audit	2011-04-04 20:10:05.888648695 +0200
++++ openssh-5.3p1/kex.h	2011-04-04 20:10:08.743648972 +0200
+@@ -157,6 +157,8 @@ void	kexgss_client(Kex *);
+ void	kexgss_server(Kex *);
+ #endif
+ 
++void	newkeys_destroy(Newkeys *newkeys);
++
+ void
+ kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
+     BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *);
+diff -up openssh-5.3p1/key.c.audit openssh-5.3p1/key.c
+--- openssh-5.3p1/key.c.audit	2011-04-04 20:10:05.938648640 +0200
++++ openssh-5.3p1/key.c	2011-04-04 20:10:08.792648817 +0200
+@@ -1043,3 +1043,23 @@ key_demote(const Key *k)
+ 
+ 	return (pk);
+ }
++
++int
++key_is_private(const Key *k)
++{
++	switch (k->type) {
++	case KEY_RSA1:
++	case KEY_RSA:
++		return k->rsa->d != NULL;
++	case KEY_DSA:
++		return k->dsa->priv_key != NULL;
++#ifdef OPENSSL_HAS_ECC
++	case KEY_ECDSA_CERT:
++	case KEY_ECDSA:
++		return EC_KEY_get0_private_key(k->ecdsa) != NULL;
++#endif
++	default:
++		fatal("key_is_private: bad key type %d", k->type);
++		return 1;
++	}
++}
+diff -up openssh-5.3p1/key.h.audit openssh-5.3p1/key.h
+--- openssh-5.3p1/key.h.audit	2011-04-04 20:10:05.986648703 +0200
++++ openssh-5.3p1/key.h	2011-04-04 20:10:08.831649090 +0200
+@@ -106,4 +106,5 @@ int	 ssh_dss_verify(const Key *, const u
+ int	 ssh_rsa_sign(const Key *, u_char **, u_int *, const u_char *, u_int);
+ int	 ssh_rsa_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
+ 
++int	 key_is_private(const Key *k);
+ #endif
+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	2011-04-04 20:10:08.881649016 +0200
+@@ -467,9 +467,9 @@ login_write(struct logininfo *li)
+ #endif
+ #ifdef SSH_AUDIT_EVENTS
+ 	if (li->type == LTYPE_LOGIN)
+-		audit_session_open(li->line);
++		audit_session_open(li);
+ 	else if (li->type == LTYPE_LOGOUT)
+-		audit_session_close(li->line);
++		audit_session_close(li);
+ #endif
+ 	return (0);
+ }
+diff -up openssh-5.3p1/mac.c.audit openssh-5.3p1/mac.c
+--- openssh-5.3p1/mac.c.audit	2011-04-04 20:10:04.110648696 +0200
++++ openssh-5.3p1/mac.c	2011-04-04 20:10:08.921649116 +0200
+@@ -170,6 +170,20 @@ mac_clear(Mac *mac)
+ 	mac->umac_ctx = NULL;
+ }
+ 
++void
++mac_destroy(Mac *mac)
++{
++	if (mac == NULL)
++		return;
++
++	if (mac->key) {
++		memset(mac->key, 0, mac->key_len);
++		xfree(mac->key);
++	}
++
++	memset(mac, 0, sizeof(*mac));
++}
++
+ /* XXX copied from ciphers_valid */
+ #define	MAC_SEP	","
+ int
+diff -up openssh-5.3p1/mac.h.audit openssh-5.3p1/mac.h
+--- openssh-5.3p1/mac.h.audit	2007-06-11 06:01:42.000000000 +0200
++++ openssh-5.3p1/mac.h	2011-04-04 20:10:08.958649014 +0200
+@@ -28,3 +28,4 @@ int	 mac_setup(Mac *, char *);
+ int	 mac_init(Mac *);
+ u_char	*mac_compute(Mac *, u_int32_t, u_char *, int);
+ void	 mac_clear(Mac *);
++void	 mac_destroy(Mac *);
+diff -up openssh-5.3p1/Makefile.in.audit openssh-5.3p1/Makefile.in
+--- openssh-5.3p1/Makefile.in.audit	2011-04-04 20:10:06.029773867 +0200
++++ openssh-5.3p1/Makefile.in	2011-04-04 20:10:09.000648989 +0200
+@@ -72,7 +72,7 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o b
+ 	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 nsskeys.o \
+-	kexgssc.o
++	kexgssc.o auditstub.o
+ 
+ SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
+ 	sshconnect.o sshconnect1.o sshconnect2.o mux.o \
+@@ -85,7 +85,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw
+ 	auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \
+ 	auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-jpake.o \
+ 	monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \
+-	auth-krb5.o \
++	auth-krb5.o audit-linux.o \
+  	auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\
+ 	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
+ 	audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \
+diff -up openssh-5.3p1/monitor.c.audit openssh-5.3p1/monitor.c
+--- openssh-5.3p1/monitor.c.audit	2011-04-04 20:10:06.089649076 +0200
++++ openssh-5.3p1/monitor.c	2011-04-04 20:10:09.065721978 +0200
+@@ -89,6 +89,7 @@
+ #include "ssh2.h"
+ #include "jpake.h"
+ #include "roaming.h"
++#include "audit.h"
+ 
+ #ifdef GSSAPI
+ static Gssctxt *gsscontext = NULL;
+@@ -105,6 +106,8 @@ extern Buffer auth_debug;
+ extern int auth_debug_init;
+ extern Buffer loginmsg;
+ 
++extern void destroy_sensitive_data(int);
++
+ /* State exported from the child */
+ 
+ struct {
+@@ -182,6 +185,11 @@ int mm_answer_gss_updatecreds(int, Buffe
+ #ifdef SSH_AUDIT_EVENTS
+ int mm_answer_audit_event(int, Buffer *);
+ int mm_answer_audit_command(int, Buffer *);
++int mm_answer_audit_end_command(int, Buffer *);
++int mm_answer_audit_unsupported_body(int, Buffer *);
++int mm_answer_audit_kex_body(int, Buffer *);
++int mm_answer_audit_session_key_free_body(int, Buffer *);
++int mm_answer_audit_server_key_free(int, Buffer *);
+ #endif
+ 
+ static Authctxt *authctxt;
+@@ -233,6 +241,10 @@ struct mon_table mon_dispatch_proto20[] 
+ #endif
+ #ifdef SSH_AUDIT_EVENTS
+     {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
++    {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body},
++    {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body},
++    {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body},
++    {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free},
+ #endif
+ #ifdef BSD_AUTH
+     {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
+@@ -276,6 +288,11 @@ struct mon_table mon_dispatch_postauth20
+ #ifdef SSH_AUDIT_EVENTS
+     {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
+     {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command},
++    {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command},
++    {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body},
++    {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body},
++    {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body},
++    {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free},
+ #endif
+     {0, 0, NULL}
+ };
+@@ -307,6 +324,10 @@ struct mon_table mon_dispatch_proto15[] 
+ #endif
+ #ifdef SSH_AUDIT_EVENTS
+     {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
++    {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body},
++    {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body},
++    {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body},
++    {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free},
+ #endif
+     {0, 0, NULL}
+ };
+@@ -318,6 +339,11 @@ struct mon_table mon_dispatch_postauth15
+ #ifdef SSH_AUDIT_EVENTS
+     {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
+     {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command},
++    {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command},
++    {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body},
++    {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body},
++    {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body},
++    {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free},
+ #endif
+     {0, 0, NULL}
+ };
+@@ -1267,9 +1293,11 @@ mm_answer_keyverify(int sock, Buffer *m)
+ 	Key *key;
+ 	u_char *signature, *data, *blob;
+ 	u_int signaturelen, datalen, bloblen;
++	int type = 0;
+ 	int verified = 0;
+ 	int valid_data = 0;
+ 
++	type = buffer_get_int(m);
+ 	blob = buffer_get_string(m, &bloblen);
+ 	signature = buffer_get_string(m, &signaturelen);
+ 	data = buffer_get_string(m, &datalen);
+@@ -1277,6 +1305,8 @@ mm_answer_keyverify(int sock, Buffer *m)
+ 	if (hostbased_cuser == NULL || hostbased_chost == NULL ||
+ 	  !monitor_allowed_key(blob, bloblen))
+ 		fatal("%s: bad key, not previously allowed", __func__);
++	if (type != key_blobtype)
++		fatal("%s: bad key type", __func__);
+ 
+ 	key = key_from_blob(blob, bloblen);
+ 	if (key == NULL)
+@@ -1297,7 +1327,17 @@ mm_answer_keyverify(int sock, Buffer *m)
+ 	if (!valid_data)
+ 		fatal("%s: bad signature data blob", __func__);
+ 
+-	verified = key_verify(key, signature, signaturelen, data, datalen);
++	switch (key_blobtype) {
++	case MM_USERKEY:
++		verified = user_key_verify(key, signature, signaturelen, data, datalen);
++		break;
++	case MM_HOSTKEY:
++		verified = hostbased_key_verify(key, signature, signaturelen, data, datalen);
++		break;
++	default:
++		verified = 0;
++		break;
++	}
+ 	debug3("%s: key %p signature %s",
+ 	    __func__, key, (verified == 1) ? "verified" : "unverified");
+ 
+@@ -1350,6 +1390,12 @@ mm_session_close(Session *s)
+ 		debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd);
+ 		session_pty_cleanup2(s);
+ 	}
++#ifdef SSH_AUDIT_EVENTS
++	if (s->command != NULL) {
++		debug3("%s: command %d", __func__, s->command_handle);
++		session_end_command2(s);
++	}
++#endif
+ 	session_unused(s->self);
+ }
+ 
+@@ -1632,6 +1678,8 @@ mm_answer_term(int sock, Buffer *req)
+ 		sshpam_cleanup();
+ #endif
+ 
++	destroy_sensitive_data(0);
++
+ 	while (waitpid(pmonitor->m_pid, &status, 0) == -1)
+ 		if (errno != EINTR)
+ 			exit(1);
+@@ -1674,11 +1722,44 @@ mm_answer_audit_command(int socket, Buff
+ {
+ 	u_int len;
+ 	char *cmd;
++	Session *s;
+ 
+ 	debug3("%s entering", __func__);
+ 	cmd = buffer_get_string(m, &len);
++
+ 	/* sanity check command, if so how? */
+-	audit_run_command(cmd);
++	s = session_new();
++	if (s == NULL)
++		fatal("%s: error allocating a session", __func__);
++	s->command = cmd;
++	s->command_handle = audit_run_command(cmd);
++
++	buffer_clear(m);
++	buffer_put_int(m, s->self);
++
++	mm_request_send(socket, MONITOR_ANS_AUDIT_COMMAND, m);
++
++	return (0);
++}
++
++int
++mm_answer_audit_end_command(int socket, Buffer *m)
++{
++	int handle;
++	u_int len;
++	char *cmd;
++	Session *s;
++
++	debug3("%s entering", __func__);
++	handle = buffer_get_int(m);
++	cmd = buffer_get_string(m, &len);
++
++	s = session_by_id(handle);
++	if (s == NULL || s->ttyfd != -1 || s->command == NULL ||
++	    strcmp(s->command, cmd) != 0)
++		fatal("%s: invalid handle", __func__);
++	mm_session_close(s);
++
+ 	xfree(cmd);
+ 	return (0);
+ }
+@@ -1814,11 +1895,13 @@ mm_get_keystate(struct monitor *pmonitor
+ 
+ 	blob = buffer_get_string(&m, &bloblen);
+ 	current_keys[MODE_OUT] = mm_newkeys_from_blob(blob, bloblen);
++	memset(blob, 0, bloblen);
+ 	xfree(blob);
+ 
+ 	debug3("%s: Waiting for second key", __func__);
+ 	blob = buffer_get_string(&m, &bloblen);
+ 	current_keys[MODE_IN] = mm_newkeys_from_blob(blob, bloblen);
++	memset(blob, 0, bloblen);
+ 	xfree(blob);
+ 
+ 	/* Now get sequence numbers for the packets */
+@@ -1864,6 +1947,16 @@ mm_get_keystate(struct monitor *pmonitor
+ 	}
+ 
+ 	buffer_free(&m);
++
++#ifdef SSH_AUDIT_EVENTS
++	if (compat20) {
++		buffer_init(&m);
++		mm_request_receive_expect(pmonitor->m_sendfd,
++					  MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m);
++		mm_answer_audit_session_key_free_body(pmonitor->m_sendfd, &m);
++		buffer_free(&m);
++	}
++#endif
+ }
+ 
+ 
+@@ -2347,3 +2440,82 @@ mm_answer_jpake_check_confirm(int sock, 
+ }
+ 
+ #endif /* JPAKE */
++
++#ifdef SSH_AUDIT_EVENTS
++int
++mm_answer_audit_unsupported_body(int sock, Buffer *m)
++{
++	int what;
++
++	what = buffer_get_int(m);
++
++	audit_unsupported_body(what);
++
++	buffer_clear(m);
++
++	mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m);
++	return 0;
++}
++
++int
++mm_answer_audit_kex_body(int sock, Buffer *m)
++{
++	int ctos, len;
++	char *cipher, *mac, *compress;
++	pid_t pid;
++	uid_t uid;
++
++	ctos = buffer_get_int(m);
++	cipher = buffer_get_string(m, &len);
++	mac = buffer_get_string(m, &len);
++	compress = buffer_get_string(m, &len);
++	pid = buffer_get_int64(m);
++	uid = buffer_get_int64(m);
++
++	audit_kex_body(ctos, cipher, mac, compress, pid, uid);
++
++	buffer_clear(m);
++
++	mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m);
++	return 0;
++}
++
++int
++mm_answer_audit_session_key_free_body(int sock, Buffer *m)
++{
++	int ctos;
++	pid_t pid;
++	uid_t uid;
++
++	ctos = buffer_get_int(m);
++	pid = buffer_get_int64(m);
++	uid = buffer_get_int64(m);
++
++	audit_session_key_free_body(ctos, pid, uid);
++
++	buffer_clear(m);
++
++	mm_request_send(sock, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, m);
++	return 0;
++}
++
++int
++mm_answer_audit_server_key_free(int sock, Buffer *m)
++{
++	int len;
++	char *fp;
++	pid_t pid;
++	uid_t uid;
++
++	fp = buffer_get_string(m, &len);
++	pid = buffer_get_int64(m);
++	uid = buffer_get_int64(m);
++
++	audit_destroy_sensitive_data(fp, pid, uid);
++
++	buffer_clear(m);
++
++	mm_request_send(sock, MONITOR_ANS_AUDIT_SERVER_KEY_FREE, m);
++	return 0;
++}
++#endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-5.3p1/monitor.h.audit openssh-5.3p1/monitor.h
+--- openssh-5.3p1/monitor.h.audit	2011-04-04 20:10:06.130648217 +0200
++++ openssh-5.3p1/monitor.h	2011-04-04 20:10:09.119649070 +0200
+@@ -65,12 +65,17 @@ enum monitor_reqtype {
+ 	MONITOR_REQ_PAM_RESPOND, MONITOR_ANS_PAM_RESPOND,
+ 	MONITOR_REQ_PAM_FREE_CTX, MONITOR_ANS_PAM_FREE_CTX,
+ 	MONITOR_REQ_AUDIT_EVENT, MONITOR_REQ_AUDIT_COMMAND,
++	MONITOR_ANS_AUDIT_COMMAND, MONITOR_REQ_AUDIT_END_COMMAND,
+ 	MONITOR_REQ_TERM,
+ 	MONITOR_REQ_JPAKE_STEP1, MONITOR_ANS_JPAKE_STEP1,
+ 	MONITOR_REQ_JPAKE_GET_PWDATA, MONITOR_ANS_JPAKE_GET_PWDATA,
+ 	MONITOR_REQ_JPAKE_STEP2, MONITOR_ANS_JPAKE_STEP2,
+ 	MONITOR_REQ_JPAKE_KEY_CONFIRM, MONITOR_ANS_JPAKE_KEY_CONFIRM,
+ 	MONITOR_REQ_JPAKE_CHECK_CONFIRM, MONITOR_ANS_JPAKE_CHECK_CONFIRM,
++	MONITOR_REQ_AUDIT_UNSUPPORTED, MONITOR_ANS_AUDIT_UNSUPPORTED,
++	MONITOR_REQ_AUDIT_KEX, MONITOR_ANS_AUDIT_KEX,
++	MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MONITOR_ANS_AUDIT_SESSION_KEY_FREE,
++	MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MONITOR_ANS_AUDIT_SERVER_KEY_FREE,
+ };
+ 
+ struct mm_master;
+diff -up openssh-5.3p1/monitor_wrap.c.audit openssh-5.3p1/monitor_wrap.c
+--- openssh-5.3p1/monitor_wrap.c.audit	2011-04-04 20:10:06.196649469 +0200
++++ openssh-5.3p1/monitor_wrap.c	2011-04-04 20:10:09.173648975 +0200
+@@ -427,7 +427,7 @@ mm_key_allowed(enum mm_keytype type, cha
+  */
+ 
+ int
+-mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
++mm_key_verify(enum mm_keytype type, Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
+ {
+ 	Buffer m;
+ 	u_char *blob;
+@@ -441,6 +441,7 @@ mm_key_verify(Key *key, u_char *sig, u_i
+ 		return (0);
+ 
+ 	buffer_init(&m);
++	buffer_put_int(&m, type);
+ 	buffer_put_string(&m, blob, len);
+ 	buffer_put_string(&m, sig, siglen);
+ 	buffer_put_string(&m, data, datalen);
+@@ -458,6 +459,19 @@ mm_key_verify(Key *key, u_char *sig, u_i
+ 	return (verified);
+ }
+ 
++int
++mm_hostbased_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
++{
++	return mm_key_verify(MM_HOSTKEY, key, sig, siglen, data, datalen);
++}
++
++int
++mm_user_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
++{
++	return mm_key_verify(MM_USERKEY, key, sig, siglen, data, datalen);
++}
++
++
+ /* Export key state after authentication */
+ Newkeys *
+ mm_newkeys_from_blob(u_char *blob, int blen)
+@@ -635,12 +649,14 @@ mm_send_keystate(struct monitor *monitor
+ 		fatal("%s: conversion of newkeys failed", __func__);
+ 
+ 	buffer_put_string(&m, blob, bloblen);
++	memset(blob, 0, bloblen);
+ 	xfree(blob);
+ 
+ 	if (!mm_newkeys_to_blob(MODE_IN, &blob, &bloblen))
+ 		fatal("%s: conversion of newkeys failed", __func__);
+ 
+ 	buffer_put_string(&m, blob, bloblen);
++	memset(blob, 0, bloblen);
+ 	xfree(blob);
+ 
+ 	packet_get_state(MODE_OUT, &seqnr, &blocks, &packets, &bytes);
+@@ -1185,10 +1201,11 @@ mm_audit_event(ssh_audit_event_t event)
+ 	buffer_free(&m);
+ }
+ 
+-void
++int
+ mm_audit_run_command(const char *command)
+ {
+ 	Buffer m;
++	int handle;
+ 
+ 	debug3("%s entering command %s", __func__, command);
+ 
+@@ -1196,6 +1213,62 @@ mm_audit_run_command(const char *command
+ 	buffer_put_cstring(&m, command);
+ 
+ 	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, &m);
++
++	handle = buffer_get_int(&m);
++	buffer_free(&m);
++
++	return (handle);
++}
++
++void
++mm_audit_end_command(int handle, const char *command)
++{
++	Buffer m;
++
++	debug3("%s entering command %s", __func__, command);
++
++	buffer_init(&m);
++	buffer_put_int(&m, handle);
++	buffer_put_cstring(&m, command);
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, &m);
++	buffer_free(&m);
++}
++
++void
++mm_audit_unsupported_body(int what)
++{
++	Buffer m;
++
++	buffer_init(&m);
++	buffer_put_int(&m, what);
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED,
++				  &m);
++
++	buffer_free(&m);
++}
++
++void
++mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, pid_t pid,
++		  uid_t uid)
++{
++	Buffer m;
++
++	buffer_init(&m);
++	buffer_put_int(&m, ctos);
++	buffer_put_cstring(&m, cipher);
++	buffer_put_cstring(&m, mac);
++	buffer_put_cstring(&m, compress);
++	buffer_put_int64(&m, pid);
++	buffer_put_int64(&m, uid);
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX,
++				  &m);
++
+ 	buffer_free(&m);
+ }
+ #endif /* SSH_AUDIT_EVENTS */
+@@ -1492,3 +1565,36 @@ mm_jpake_check_confirm(const BIGNUM *k,
+ 	return success;
+ }
+ #endif /* JPAKE */
++
++#ifdef SSH_AUDIT_EVENTS
++void
++mm_audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
++{
++	Buffer m;
++
++	buffer_init(&m);
++	buffer_put_int(&m, ctos);
++	buffer_put_int64(&m, pid);
++	buffer_put_int64(&m, uid);
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE,
++				  &m);
++	buffer_free(&m);
++}
++
++void
++mm_audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid)
++{
++	Buffer m;
++
++	buffer_init(&m);
++	buffer_put_cstring(&m, fp);
++	buffer_put_int64(&m, pid);
++	buffer_put_int64(&m, uid);
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SERVER_KEY_FREE,
++				  &m);
++	buffer_free(&m);
++}
++#endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-5.3p1/monitor_wrap.h.audit openssh-5.3p1/monitor_wrap.h
+--- openssh-5.3p1/monitor_wrap.h.audit	2011-04-04 20:10:06.235648705 +0200
++++ openssh-5.3p1/monitor_wrap.h	2011-04-04 20:10:09.217649113 +0200
+@@ -51,7 +51,8 @@ int mm_key_allowed(enum mm_keytype, char
+ int mm_user_key_allowed(struct passwd *, Key *);
+ int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *);
+ int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *);
+-int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int);
++int mm_hostbased_key_verify(Key *, u_char *, u_int, u_char *, u_int);
++int mm_user_key_verify(Key *, u_char *, u_int, u_char *, u_int);
+ int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **);
+ int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *);
+ BIGNUM *mm_auth_rsa_generate_challenge(Key *);
+@@ -78,7 +79,12 @@ void mm_sshpam_free_ctx(void *);
+ #ifdef SSH_AUDIT_EVENTS
+ #include "audit.h"
+ void mm_audit_event(ssh_audit_event_t);
+-void mm_audit_run_command(const char *);
++int mm_audit_run_command(const char *);
++void mm_audit_end_command(int, const char *);
++void mm_audit_unsupported_body(int);
++void mm_audit_kex_body(int, char *, char *, char *, pid_t, uid_t);
++void mm_audit_session_key_free_body(int, pid_t, uid_t);
++void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t);
+ #endif
+ 
+ struct Session;
+diff -up openssh-5.3p1/packet.c.audit openssh-5.3p1/packet.c
+--- openssh-5.3p1/packet.c.audit	2009-09-26 06:54:00.000000000 +0200
++++ openssh-5.3p1/packet.c	2011-04-04 20:10:09.665651480 +0200
+@@ -60,6 +60,7 @@
+ #include <signal.h>
+ 
+ #include "xmalloc.h"
++#include "audit.h"
+ #include "buffer.h"
+ #include "packet.h"
+ #include "crc32.h"
+@@ -194,7 +195,7 @@ struct session_state {
+ 	TAILQ_HEAD(, packet) outgoing;
+ };
+ 
+-static struct session_state *active_state, *backup_state;
++static struct session_state *active_state = NULL, *backup_state = NULL;
+ 
+ static struct session_state *
+ alloc_session_state(void)
+@@ -208,6 +209,12 @@ alloc_session_state(void)
+     return s;
+ }
+ 
++int
++packet_is_active(void)
++{
++	return active_state != NULL;
++}
++
+ /*
+  * Sets the descriptors used for communication.  Disables encryption until
+  * packet_set_encryption_key is called.
+@@ -472,6 +479,13 @@ packet_get_connection_out(void)
+ 	return active_state->connection_out;
+ }
+ 
++static int
++packet_state_has_keys (const struct session_state *state)
++{
++	return state != NULL &&
++		(state->newkeys[MODE_IN] != NULL || state->newkeys[MODE_OUT] != NULL);
++}
++
+ /* Closes the connection and clears and frees internal data structures. */
+ 
+ void
+@@ -480,13 +494,6 @@ packet_close(void)
+ 	if (!active_state->initialized)
+ 		return;
+ 	active_state->initialized = 0;
+-	if (active_state->connection_in == active_state->connection_out) {
+-		shutdown(active_state->connection_out, SHUT_RDWR);
+-		close(active_state->connection_out);
+-	} else {
+-		close(active_state->connection_in);
+-		close(active_state->connection_out);
+-	}
+ 	buffer_free(&active_state->input);
+ 	buffer_free(&active_state->output);
+ 	buffer_free(&active_state->outgoing_packet);
+@@ -495,8 +502,18 @@ packet_close(void)
+ 		buffer_free(&active_state->compression_buffer);
+ 		buffer_compress_uninit();
+ 	}
+-	cipher_cleanup(&active_state->send_context);
+-	cipher_cleanup(&active_state->receive_context);
++	if (packet_state_has_keys(active_state)) {
++		cipher_cleanup(&active_state->send_context);
++		cipher_cleanup(&active_state->receive_context);
++		audit_session_key_free(2);
++	}
++	if (active_state->connection_in == active_state->connection_out) {
++		shutdown(active_state->connection_out, SHUT_RDWR);
++		close(active_state->connection_out);
++	} else {
++		close(active_state->connection_in);
++		close(active_state->connection_out);
++	}
+ }
+ 
+ /* Sets remote side protocol flags. */
+@@ -724,6 +741,23 @@ packet_send1(void)
+ 	 */
+ }
+ 
++static void
++newkeys_destroy_and_free(Newkeys *newkeys)
++{
++	if (newkeys == NULL)
++		return;
++
++	xfree(newkeys->enc.name);
++
++	mac_clear(&newkeys->mac);
++	xfree(newkeys->mac.name);
++
++	xfree(newkeys->comp.name);
++
++	newkeys_destroy(newkeys);
++	xfree(newkeys);
++}
++
+ void
+ set_newkeys(int mode)
+ {
+@@ -749,18 +783,9 @@ set_newkeys(int mode)
+ 	}
+ 	if (active_state->newkeys[mode] != NULL) {
+ 		debug("set_newkeys: rekeying");
++		audit_session_key_free(mode);
+ 		cipher_cleanup(cc);
+-		enc  = &active_state->newkeys[mode]->enc;
+-		mac  = &active_state->newkeys[mode]->mac;
+-		comp = &active_state->newkeys[mode]->comp;
+-		mac_clear(mac);
+-		xfree(enc->name);
+-		xfree(enc->iv);
+-		xfree(enc->key);
+-		xfree(mac->name);
+-		xfree(mac->key);
+-		xfree(comp->name);
+-		xfree(active_state->newkeys[mode]);
++		newkeys_destroy_and_free(active_state->newkeys[mode]);
+ 	}
+ 	active_state->newkeys[mode] = kex_get_newkeys(mode);
+ 	if (active_state->newkeys[mode] == NULL)
+@@ -1891,6 +1916,47 @@ packet_get_newkeys(int mode)
+ 	return (void *)active_state->newkeys[mode];
+ }
+ 
++static void
++packet_destroy_state(struct session_state *state)
++{
++	if (state == NULL)
++		return;
++
++	cipher_cleanup(&state->receive_context);
++	cipher_cleanup(&state->send_context);
++
++	buffer_free(&state->input);
++	buffer_free(&state->output);
++	buffer_free(&state->outgoing_packet);
++	buffer_free(&state->incoming_packet);
++	buffer_free(&state->compression_buffer);
++	newkeys_destroy_and_free(state->newkeys[MODE_IN]);
++	state->newkeys[MODE_IN] = NULL;
++	newkeys_destroy_and_free(state->newkeys[MODE_OUT]);
++	state->newkeys[MODE_OUT] = NULL;
++	mac_destroy(state->packet_discard_mac);
++//	TAILQ_HEAD(, packet) outgoing;
++//	memset(state, 0, sizeof(state));
++}
++
++void
++packet_destroy_all(int audit_it, int privsep)
++{
++	if (audit_it)
++		audit_it = packet_state_has_keys (active_state) ||
++			packet_state_has_keys (backup_state);
++	packet_destroy_state(active_state);
++	packet_destroy_state(backup_state);
++	if (audit_it) {
++#ifdef SSH_AUDIT_EVENTS
++		if (privsep)
++			audit_session_key_free(2);
++		else
++			audit_session_key_free_body(2, getpid(), getuid());
++#endif
++	}
++}
++
+ /*
+  * Save the state for the real connection, and use a separate state when
+  * resuming a suspended connection.
+@@ -1898,18 +1964,12 @@ packet_get_newkeys(int mode)
+ void
+ packet_backup_state(void)
+ {
+-	struct session_state *tmp;
+-
+ 	close(active_state->connection_in);
+ 	active_state->connection_in = -1;
+ 	close(active_state->connection_out);
+ 	active_state->connection_out = -1;
+-	if (backup_state)
+-		tmp = backup_state;
+-	else
+-		tmp = alloc_session_state();
+ 	backup_state = active_state;
+-	active_state = tmp;
++	active_state = alloc_session_state();
+ }
+ 
+ /*
+@@ -1926,9 +1986,7 @@ packet_restore_state(void)
+ 	backup_state = active_state;
+ 	active_state = tmp;
+ 	active_state->connection_in = backup_state->connection_in;
+-	backup_state->connection_in = -1;
+ 	active_state->connection_out = backup_state->connection_out;
+-	backup_state->connection_out = -1;
+ 	len = buffer_len(&backup_state->input);
+ 	if (len > 0) {
+ 		buf = buffer_ptr(&backup_state->input);
+@@ -1936,4 +1994,10 @@ packet_restore_state(void)
+ 		buffer_clear(&backup_state->input);
+ 		add_recv_bytes(len);
+ 	}
++	backup_state->connection_in = -1;
++	backup_state->connection_out = -1;
++	packet_destroy_state(backup_state);
++	xfree(backup_state);
++	backup_state = NULL;
+ }
++
+diff -up openssh-5.3p1/packet.h.audit openssh-5.3p1/packet.h
+--- openssh-5.3p1/packet.h.audit	2009-07-05 23:11:13.000000000 +0200
++++ openssh-5.3p1/packet.h	2011-04-04 20:10:09.714648537 +0200
+@@ -20,6 +20,7 @@
+ 
+ #include <openssl/bn.h>
+ 
++int	 packet_is_active(void);
+ void     packet_set_connection(int, int);
+ void     packet_set_timeout(int, int);
+ void     packet_set_nonblocking(void);
+@@ -115,4 +116,5 @@ void	 packet_restore_state(void);
+ void	*packet_get_input(void);
+ void	*packet_get_output(void);
+ 
++void	 packet_destroy_all(int, int);
+ #endif				/* PACKET_H */
+diff -up openssh-5.3p1/session.c.audit openssh-5.3p1/session.c
+--- openssh-5.3p1/session.c.audit	2011-04-04 20:10:07.976659477 +0200
++++ openssh-5.3p1/session.c	2011-04-04 20:10:09.369648287 +0200
+@@ -132,7 +132,7 @@ extern int log_stderr;
+ extern int debug_flag;
+ extern u_int utmp_len;
+ extern int startup_pipe;
+-extern void destroy_sensitive_data(void);
++extern void destroy_sensitive_data(int);
+ extern Buffer loginmsg;
+ 
+ /* original command from peer. */
+@@ -760,6 +760,14 @@ do_exec_pty(Session *s, const char *comm
+ 	/* Parent.  Close the slave side of the pseudo tty. */
+ 	close(ttyfd);
+ 
++#ifndef HAVE_OSF_SIA
++	/* do_login in the child did not affect state in this process,
++	   compensate.  From an architectural standpoint, this is extremely
++	   ugly. */
++	if (!(options.use_login && command == NULL))
++		audit_count_session_open();
++#endif
++
+ 	/* Enter interactive session. */
+ 	s->ptymaster = ptymaster;
+ 	packet_set_interactive(1);
+@@ -828,15 +836,19 @@ do_exec(Session *s, const char *command)
+ 	}
+ 
+ #ifdef SSH_AUDIT_EVENTS
++	if (s->command != NULL || s->command_handle != -1)
++		fatal("do_exec: command already set");
+ 	if (command != NULL)
+-		PRIVSEP(audit_run_command(command));
++		s->command = xstrdup(command);
+ 	else if (s->ttyfd == -1) {
+ 		char *shell = s->pw->pw_shell;
+ 
+ 		if (shell[0] == '\0')	/* empty shell means /bin/sh */
+ 			shell =_PATH_BSHELL;
+-		PRIVSEP(audit_run_command(shell));
++		s->command = xstrdup(shell);
+ 	}
++	if (s->command != NULL)
++		s->command_handle = PRIVSEP(audit_run_command(s->command));
+ #endif
+ 	if (s->ttyfd != -1)
+ 		ret = do_exec_pty(s, command);
+@@ -1675,7 +1687,10 @@ do_child(Session *s, const char *command
+ 	int r = 0;
+ 
+ 	/* remove hostkey from the child's memory */
+-	destroy_sensitive_data();
++	destroy_sensitive_data(1);
++	/* Don't audit this - both us and the parent would be talking to the
++	   monitor over a single socket, with no synchronization. */
++	packet_destroy_all(0, 1);
+ 
+ 	/* Force a password change */
+ 	if (s->authctxt->force_pwchange) {
+@@ -1895,6 +1910,7 @@ session_unused(int id)
+ 	sessions[id].ttyfd = -1;
+ 	sessions[id].ptymaster = -1;
+ 	sessions[id].x11_chanids = NULL;
++	sessions[id].command_handle = -1;
+ 	sessions[id].next_unused = sessions_first_unused;
+ 	sessions_first_unused = id;
+ }
+@@ -1977,6 +1993,19 @@ session_open(Authctxt *authctxt, int cha
+ }
+ 
+ Session *
++session_by_id(int id)
++{
++	if (id >= 0 && id < sessions_nalloc) {
++		Session *s = &sessions[id];
++		if (s->used)
++			return s;
++	}
++	debug("session_by_id: unknown id %d", id);
++	session_dump();
++	return NULL;
++}
++
++Session *
+ session_by_tty(char *tty)
+ {
+ 	int i;
+@@ -2500,6 +2529,30 @@ session_exit_message(Session *s, int sta
+ 		chan_write_failed(c);
+ }
+ 
++#ifdef SSH_AUDIT_EVENTS
++void
++session_end_command2(Session *s)
++{
++	if (s->command != NULL) {
++		audit_end_command(s->command_handle, s->command);
++		xfree(s->command);
++		s->command = NULL;
++		s->command_handle = -1;
++	}
++}
++
++static void
++session_end_command(Session *s)
++{
++	if (s->command != NULL) {
++		PRIVSEP(audit_end_command(s->command_handle, s->command));
++		xfree(s->command);
++		s->command = NULL;
++		s->command_handle = -1;
++	}
++}
++#endif
++
+ void
+ session_close(Session *s)
+ {
+@@ -2508,6 +2561,10 @@ session_close(Session *s)
+ 	debug("session_close: session %d pid %ld", s->self, (long)s->pid);
+ 	if (s->ttyfd != -1)
+ 		session_pty_cleanup(s);
++#ifdef SSH_AUDIT_EVENTS
++	if (s->command)
++		session_end_command(s);
++#endif
+ 	if (s->term)
+ 		xfree(s->term);
+ 	if (s->display)
+@@ -2727,6 +2784,15 @@ do_authenticated2(Authctxt *authctxt)
+ 	server_loop2(authctxt);
+ }
+ 
++static void
++do_cleanup_one_session(Session *s)
++{
++	session_pty_cleanup2(s);
++#ifdef SSH_AUDIT_EVENTS
++	session_end_command2(s);
++#endif
++}
++
+ void
+ do_cleanup(Authctxt *authctxt)
+ {
+@@ -2775,5 +2841,5 @@ do_cleanup(Authctxt *authctxt)
+ 	 * or if running in monitor.
+ 	 */
+ 	if (!use_privsep || mm_is_monitor())
+-		session_destroy_all(session_pty_cleanup2);
++		session_destroy_all(do_cleanup_one_session);
+ }
+diff -up openssh-5.3p1/session.h.audit openssh-5.3p1/session.h
+--- openssh-5.3p1/session.h.audit	2008-05-19 07:34:50.000000000 +0200
++++ openssh-5.3p1/session.h	2011-04-04 20:10:09.408649077 +0200
+@@ -60,6 +60,12 @@ struct Session {
+ 		char	*name;
+ 		char	*val;
+ 	} *env;
++
++	/* exec */
++#ifdef SSH_AUDIT_EVENTS
++	int	command_handle;
++	char	*command;
++#endif
+ };
+ 
+ void	 do_authenticated(Authctxt *);
+@@ -72,8 +78,10 @@ void	 session_close_by_pid(pid_t, int);
+ void	 session_close_by_channel(int, void *);
+ void	 session_destroy_all(void (*)(Session *));
+ void	 session_pty_cleanup2(Session *);
++void	 session_end_command2(Session *);
+ 
+ Session	*session_new(void);
++Session *session_by_id(int);
+ Session	*session_by_tty(char *);
+ void	 session_close(Session *);
+ void	 do_setusercontext(struct passwd *);
+diff -up openssh-5.3p1/sshd.c.audit openssh-5.3p1/sshd.c
+--- openssh-5.3p1/sshd.c.audit	2011-04-04 20:10:06.631648733 +0200
++++ openssh-5.3p1/sshd.c	2011-04-04 20:10:09.464661420 +0200
+@@ -120,6 +120,7 @@
+ #endif
+ #include "monitor_wrap.h"
+ #include "roaming.h"
++#include "audit.h"
+ #include "version.h"
+ 
+ #ifdef LIBWRAP
+@@ -257,7 +258,7 @@ Buffer loginmsg;
+ struct passwd *privsep_pw = NULL;
+ 
+ /* Prototypes for various functions defined later in this file. */
+-void destroy_sensitive_data(void);
++void destroy_sensitive_data(int);
+ void demote_sensitive_data(void);
+ 
+ static void do_ssh1_kex(void);
+@@ -276,6 +277,15 @@ close_listen_socks(void)
+ 	num_listen_socks = -1;
+ }
+ 
++/*
++ * Is this process listening for clients (i.e. not specific to any specific
++ * client connection?)
++ */
++int listening_for_clients(void)
++{
++	return num_listen_socks > 0;
++}
++
+ static void
+ close_startup_pipes(void)
+ {
+@@ -535,20 +545,44 @@ sshd_exchange_identification(int sock_in
+ 	}
+ }
+ 
+-/* Destroy the host and server keys.  They will no longer be needed. */
++/*
++ * Destroy the host and server keys.  They will no longer be needed.  Careful,
++ * this can be called from cleanup_exit() - i.e. from just about anywhere.
++ */
+ void
+-destroy_sensitive_data(void)
++destroy_sensitive_data(int privsep)
+ {
+ 	int i;
++	pid_t pid;
++	uid_t uid;
+ 
+ 	if (sensitive_data.server_key) {
+ 		key_free(sensitive_data.server_key);
+ 		sensitive_data.server_key = NULL;
+ 	}
++	pid = getpid();
++	uid = getuid();
+ 	for (i = 0; i < options.num_host_key_files; i++) {
+ 		if (sensitive_data.host_keys[i]) {
+-			key_free(sensitive_data.host_keys[i]);
+-			sensitive_data.host_keys[i] = NULL;
++			char *fp;
++
++			if (key_is_private(sensitive_data.host_keys[i]))
++				fp = key_fingerprint(sensitive_data.host_keys[i],
++					FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5,
++					SSH_FP_HEX);
++			else
++				fp = NULL;
++ 			key_free(sensitive_data.host_keys[i]);
++ 			sensitive_data.host_keys[i] = NULL;
++			if (fp != NULL) {
++				if (privsep)
++					PRIVSEP(audit_destroy_sensitive_data(fp,
++						pid, uid));
++				else
++					audit_destroy_sensitive_data(fp,
++						pid, uid);
++				xfree(fp);
++			}
+ 		}
+ 	}
+ 	sensitive_data.ssh1_host_key = NULL;
+@@ -560,6 +594,8 @@ void
+ demote_sensitive_data(void)
+ {
+ 	Key *tmp;
++	pid_t pid;
++	uid_t uid;
+ 	int i;
+ 
+ 	if (sensitive_data.server_key) {
+@@ -568,13 +604,27 @@ demote_sensitive_data(void)
+ 		sensitive_data.server_key = tmp;
+ 	}
+ 
++	pid = getpid();
++	uid = getuid();
+ 	for (i = 0; i < options.num_host_key_files; i++) {
+ 		if (sensitive_data.host_keys[i]) {
++			char *fp;
++
++			if (key_is_private(sensitive_data.host_keys[i]))
++				fp = key_fingerprint(sensitive_data.host_keys[i],
++					FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5,
++					SSH_FP_HEX);
++			else
++				fp = NULL;
+ 			tmp = key_demote(sensitive_data.host_keys[i]);
+ 			key_free(sensitive_data.host_keys[i]);
+ 			sensitive_data.host_keys[i] = tmp;
+ 			if (tmp->type == KEY_RSA1)
+ 				sensitive_data.ssh1_host_key = tmp;
++			if (fp != NULL) {
++				audit_destroy_sensitive_data(fp, pid, uid);
++				xfree(fp);
++			}
+ 		}
+ 	}
+ 
+@@ -665,6 +715,8 @@ privsep_preauth(Authctxt *authctxt)
+ 	return (0);
+ }
+ 
++extern Newkeys *current_keys[];
++
+ static void
+ privsep_postauth(Authctxt *authctxt)
+ {
+@@ -690,6 +742,10 @@ privsep_postauth(Authctxt *authctxt)
+ 		verbose("User child is on pid %ld", (long)pmonitor->m_pid);
+ 		close(pmonitor->m_recvfd);
+ 		buffer_clear(&loginmsg);
++		newkeys_destroy(current_keys[MODE_OUT]);
++		newkeys_destroy(current_keys[MODE_IN]);
++		audit_session_key_free_body(2, getpid(), getuid());
++		packet_destroy_all(0, 0);
+ 		monitor_child_postauth(pmonitor);
+ 
+ 		/* NEVERREACHED */
+@@ -1074,6 +1130,7 @@ server_accept_loop(int *sock_in, int *so
+ 		if (received_sigterm) {
+ 			logit("Received signal %d; terminating.",
+ 			    (int) received_sigterm);
++			destroy_sensitive_data(0);
+ 			close_listen_socks();
+ 			unlink(options.pid_file);
+ 			exit(255);
+@@ -1952,6 +2009,7 @@ main(int ac, char **av)
+ 	 */
+ 	if (use_privsep) {
+ 		mm_send_keystate(pmonitor);
++		packet_destroy_all(1, 1);
+ 		exit(0);
+ 	}
+ 
+@@ -1996,8 +2054,9 @@ main(int ac, char **av)
+ 	if (use_privsep) {
+ 		privsep_postauth(authctxt);
+ 		/* the monitor process [priv] will not return */
+-		if (!compat20)
+-			destroy_sensitive_data();
++		if (!compat20) {
++			destroy_sensitive_data(0);
++		}
+ 	}
+ 
+ 	packet_set_timeout(options.client_alive_interval,
+@@ -2007,6 +2066,9 @@ main(int ac, char **av)
+ 	do_authenticated(authctxt);
+ 
+ 	/* The connection has been terminated. */
++	packet_destroy_all(1, 1);
++	destroy_sensitive_data(1);
++
+ 	packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes);
+ 	packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes);
+ 	verbose("Transferred: sent %llu, received %llu bytes", obytes, ibytes);
+@@ -2163,6 +2225,10 @@ do_ssh1_kex(void)
+ 		if (cookie[i] != packet_get_char())
+ 			packet_disconnect("IP Spoofing check bytes do not match.");
+ 
++#ifdef SSH_AUDIT_EVENTS
++	audit_kex(2, cipher_name(cipher_type), "crc", "none");
++#endif
++
+ 	debug("Encryption type: %.200s", cipher_name(cipher_type));
+ 
+ 	/* Get the encrypted integer. */
+@@ -2229,7 +2295,7 @@ do_ssh1_kex(void)
+ 			session_id[i] = session_key[i] ^ session_key[i + 16];
+ 	}
+ 	/* Destroy the private and public keys. No longer. */
+-	destroy_sensitive_data();
++	destroy_sensitive_data(0);
+ 
+ 	if (use_privsep)
+ 		mm_ssh1_session_id(session_id);
+@@ -2370,11 +2436,27 @@ do_ssh2_kex(void)
+ void
+ cleanup_exit(int i)
+ {
++	static int in_cleanup;
++
++	int is_privsep_child;
++
++	/* cleanup_exit can be called at the very least from the privsep
++	   wrappers used for auditing.  Make sure we don't recurse
++	   indefinitely. */
++	if (in_cleanup)
++		_exit(i);
++	in_cleanup = 1;
++
+ 	if (the_authctxt)
+ 		do_cleanup(the_authctxt);
++	is_privsep_child = use_privsep && pmonitor != NULL && !mm_is_monitor();
++	if (sensitive_data.host_keys != NULL)
++		destroy_sensitive_data(is_privsep_child);
++	packet_destroy_all(1, is_privsep_child);
+ #ifdef SSH_AUDIT_EVENTS
+ 	/* done after do_cleanup so it can cancel the PAM auth 'thread' */
+-	if (!use_privsep || mm_is_monitor())
++	if ((the_authctxt == NULL || !the_authctxt->authenticated) &&
++	    (!use_privsep || mm_is_monitor()))
+ 		audit_event(SSH_CONNECTION_ABANDON);
+ #endif
+ 	_exit(i);
diff --git a/openssh-5.3p1-authorized-keys-command.patch b/openssh-5.3p1-authorized-keys-command.patch
new file mode 100644
index 0000000..4a16c80
--- /dev/null
+++ b/openssh-5.3p1-authorized-keys-command.patch
@@ -0,0 +1,435 @@
+diff -up openssh-5.3p1/auth2-pubkey.c.akc openssh-5.3p1/auth2-pubkey.c
+--- openssh-5.3p1/auth2-pubkey.c.akc	2010-07-12 22:46:23.000000000 +0200
++++ openssh-5.3p1/auth2-pubkey.c	2010-07-12 23:03:24.000000000 +0200
+@@ -27,6 +27,7 @@
+ 
+ #include <sys/types.h>
+ #include <sys/stat.h>
++#include <sys/wait.h>
+ 
+ #include <fcntl.h>
+ #include <pwd.h>
+@@ -183,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);
+ 
+@@ -247,21 +236,197 @@ 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_AUTHORIZED_KEYS_COMMAND
++
++#define WHITESPACE " \t\r\n"
++
++/* return 1 if user allows given key */
++static int
++user_key_via_command_allowed2(struct passwd *pw, Key *key)
++{
++	FILE *f;
++	int found_key = 0;
++	char *progname = NULL;
++	char *cp;
++	struct passwd *runas_pw;
++	struct stat st;
++	int childdescriptors[2], i;
++	pid_t pstat, pid, child;
++
++	if (options.authorized_keys_command == NULL || options.authorized_keys_command[0] != '/')
++		return -1;
++
++	/* get the run as identity from config */
++	runas_pw = (options.authorized_keys_command_runas == NULL)? pw
++	    : getpwnam (options.authorized_keys_command_runas);
++	if (!runas_pw) {
++		error("%s: getpwnam(\"%s\"): %s", __func__,
++		    options.authorized_keys_command_runas, strerror(errno));
++		return 0;
++	}
++
++	/* Temporarily use the specified uid. */
++	if (runas_pw->pw_uid != 0)
++		temporarily_use_uid(runas_pw);
++
++	progname = xstrdup(options.authorized_keys_command);
++
++	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 AuthorizedKeysCommand \"%s\"",
++		    progname);
++		goto go_away;
++	}
++
++	if (!S_ISREG(st.st_mode)) {
++		error("AuthorizedKeysCommand \"%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 == '\0' ? "/" : progname));
++
++		if (stat((*progname == '\0' ? "/" : 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 AuthorizedKeysCommand path component \"%s\"",
++			    progname);
++			goto go_away;
++		}
++		if (!S_ISDIR(st.st_mode)) {
++			error("AuthorizedKeysCommand path component \"%s\" is not a directory",
++			    progname);
++			goto go_away;
++		}
++	} while (1);
++
++	/* open the pipe and read the keys */
++	if (pipe(childdescriptors)) {
++		error("failed to pipe(2) for AuthorizedKeysCommand: %s",
++		    strerror(errno));
++		goto go_away;
++	}
++
++	child = fork();
++	if (child == -1) {
++		error("failed to fork(2) for AuthorizedKeysCommand: %s",
++		    strerror(errno));
++		goto go_away;
++	} else if (child == 0) {
++		/* we're in the child process here -- we should never return from this block. */
++		/* permanently drop privs in child process */
++		if (runas_pw->pw_uid != 0) {
++			restore_uid();
++			permanently_set_uid(runas_pw);
++	  	}
++
++		close(childdescriptors[0]);
++		/* put the write end of the pipe on stdout (FD 1) */
++		if (dup2(childdescriptors[1], 1) == -1) {
++			error("failed to dup2(2) from AuthorizedKeysCommand: %s",
++			    strerror(errno));
++			_exit(127);
++		}
++
++		debug3("about to execl() AuthorizedKeysCommand: \"%s\" \"%s\"", options.authorized_keys_command, pw->pw_name);
++		/* see session.c:child_close_fds() */
++		for (i = 3; i < 64; ++i) {
++			close(i);
++		}
++
++		execl(options.authorized_keys_command, options.authorized_keys_command, pw->pw_name, NULL);
++
++		/* if we got here, it didn't work */
++		error("failed to execl AuthorizedKeysCommand: %s", strerror(errno)); /* this won't work because we closed the fds above */
++		_exit(127);
++	}
++	
++	close(childdescriptors[1]);
++	f = fdopen(childdescriptors[0], "r");
++	if (!f) {
++		error("%s: could not buffer FDs from AuthorizedKeysCommand (\"%s\", \"r\"): %s", __func__,
++		    options.authorized_keys_command, strerror (errno));
++		goto go_away;
++	}
++
++	found_key = user_search_key_in_file (f, options.authorized_keys_command, key, pw);
++	fclose (f);
++	do {
++		pid = waitpid(child, &pstat, 0);
++	} while (pid == -1 && errno == EINTR);
++
++	/* what about the return value from the child process? */
++go_away:
++	if (progname)
++		xfree (progname);
++
++	if (runas_pw->pw_uid != 0)
++		restore_uid();
++	return found_key;
++}
++#endif
++
++/* check whether given key is in <AuthorizedKeysCommand or .ssh/authorized_keys* */
+ int
+ user_key_allowed(struct passwd *pw, Key *key)
+ {
+ 	int success;
+ 	char *file;
+ 
++#ifdef WITH_AUTHORIZED_KEYS_COMMAND
++	success = user_key_via_command_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.akc openssh-5.3p1/configure.ac
+--- openssh-5.3p1/configure.ac.akc	2010-07-12 22:46:23.000000000 +0200
++++ openssh-5.3p1/configure.ac	2010-07-12 22:46:24.000000000 +0200
+@@ -1319,6 +1319,18 @@ AC_ARG_WITH(audit,
+ 	esac ]
+ )
+ 
++# Check whether user wants AuthorizedKeysCommand support
++AKC_MSG="no"
++AC_ARG_WITH(authorized-keys-command,
++	[  --with-authorized-keys-command      Enable AuthorizedKeysCommand support],
++	[
++		if test "x$withval" != "xno" ; then
++			AC_DEFINE([WITH_AUTHORIZED_KEYS_COMMAND], 1, [Enable AuthorizedKeysCommand support])
++			AKC_MSG="yes"
++		fi
++	]
++)
++
+ dnl    Checks for library functions. Please keep in alphabetical order
+ AC_CHECK_FUNCS( \
+ 	arc4random \
+@@ -4250,6 +4262,7 @@ echo "               Linux audit support
+ echo "                 Smartcard support: $SCARD_MSG"
+ echo "                     S/KEY support: $SKEY_MSG"
+ echo "              TCP Wrappers support: $TCPW_MSG"
++echo "     AuthorizedKeysCommand support: $AKC_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.akc openssh-5.3p1/servconf.c
+--- openssh-5.3p1/servconf.c.akc	2010-07-12 22:46:22.000000000 +0200
++++ openssh-5.3p1/servconf.c	2010-07-12 23:09:30.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->authorized_keys_command = NULL;
++	options->authorized_keys_command_runas = NULL;
+ 	options->zero_knowledge_password_authentication = -1;
+ }
+ 
+@@ -310,6 +312,7 @@ typedef enum {
+ 	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
+ 	sUsePrivilegeSeparation, sAllowAgentForwarding,
+ 	sZeroKnowledgePasswordAuthentication,
++	sAuthorizedKeysCommand, sAuthorizedKeysCommandRunAs,
+ 	sDeprecated, sUnsupported
+ } ServerOpCodes;
+ 
+@@ -429,6 +432,13 @@ static struct {
+ 	{ "permitopen", sPermitOpen, SSHCFG_ALL },
+ 	{ "forcecommand", sForceCommand, SSHCFG_ALL },
+ 	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
++#ifdef WITH_AUTHORIZED_KEYS_COMMAND
++	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
++	{ "authorizedkeyscommandrunas", sAuthorizedKeysCommandRunAs, SSHCFG_ALL },
++#else
++	{ "authorizedkeyscommand", sUnsupported, SSHCFG_ALL },
++	{ "authorizedkeyscommandrunas", sUnsupported, SSHCFG_ALL },
++#endif
+ 	{ NULL, sBadOption, 0 }
+ };
+ 
+@@ -1303,6 +1313,20 @@ process_server_config_line(ServerOptions
+ 			*charptr = xstrdup(arg);
+ 		break;
+ 
++	case sAuthorizedKeysCommand:
++		len = strspn(cp, WHITESPACE);
++		if (*activep && options->authorized_keys_command == NULL)
++			options->authorized_keys_command = xstrdup(cp + len);
++		return 0;
++
++	case sAuthorizedKeysCommandRunAs:
++		charptr = &options->authorized_keys_command_runas;
++
++		arg = strdelim(&cp);
++		if (*activep && *charptr == NULL)
++			*charptr = xstrdup(arg);
++		break;
++
+ 	case sDeprecated:
+ 		logit("%s line %d: Deprecated option %s",
+ 		    filename, linenum, arg);
+@@ -1396,6 +1420,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(authorized_keys_command);
++	M_CP_STROPT(authorized_keys_command_runas);
+ 	M_CP_INTOPT(kerberos_authentication);
+ 	M_CP_INTOPT(hostbased_authentication);
+ 	M_CP_INTOPT(kbd_interactive_authentication);
+@@ -1636,6 +1662,8 @@ 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);
++	dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
++	dump_cfg_string(sAuthorizedKeysCommandRunAs, o->authorized_keys_command_runas);
+ 
+ 	/* string arguments requiring a lookup */
+ 	dump_cfg_string(sLogLevel, log_level_name(o->log_level));
+diff -up openssh-5.3p1/servconf.h.akc openssh-5.3p1/servconf.h
+--- openssh-5.3p1/servconf.h.akc	2010-07-12 22:46:22.000000000 +0200
++++ openssh-5.3p1/servconf.h	2010-07-12 23:10:38.000000000 +0200
+@@ -152,6 +152,8 @@ typedef struct {
+ 	int	num_permitted_opens;
+ 
+ 	char   *chroot_directory;
++	char   *authorized_keys_command;
++	char   *authorized_keys_command_runas;
+ }       ServerOptions;
+ 
+ void	 initialize_server_options(ServerOptions *);
+diff -up openssh-5.3p1/sshd_config.0.akc openssh-5.3p1/sshd_config.0
+--- openssh-5.3p1/sshd_config.0.akc	2010-07-12 22:46:22.000000000 +0200
++++ openssh-5.3p1/sshd_config.0	2010-07-12 23:16:19.000000000 +0200
+@@ -346,6 +346,7 @@ DESCRIPTION
+              KbdInteractiveAuthentication, KerberosAuthentication,
+              MaxAuthTries, MaxSessions, PasswordAuthentication,
+              PermitEmptyPasswords, PermitOpen, PermitRootLogin,
++             AuthorizedKeysCommand, AuthorizedKeysCommandRunAs,
+              RhostsRSAAuthentication, RSAAuthentication, X11DisplayOffset,
+              X11Forwarding and X11UseLocalHost.
+ 
+@@ -455,6 +456,22 @@ DESCRIPTION
+              fault is ``yes''.  Note that this option applies to protocol ver-
+              sion 2 only.
+ 
++     AuthorizedKeysCommand
++             Specifies a program to be used for lookup of the user's
++	      public keys.  The program will be invoked with its first
++	      argument the name of the user being authorized, and should produce 
++	      on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS 
++	      in sshd(8)).  By default (or when set to the empty string) there is no
++	      AuthorizedKeysCommand run.  If the AuthorizedKeysCommand does not successfully
++	      authorize the user, authorization falls through to the
++	      AuthorizedKeysFile.  Note that this option has an effect
++	      only with PubkeyAuthentication turned on.
++
++     AuthorizedKeysCommandRunAs
++             Specifies the user under whose account the AuthorizedKeysCommand 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.akc openssh-5.3p1/sshd_config.5
+--- openssh-5.3p1/sshd_config.5.akc	2010-07-12 22:46:22.000000000 +0200
++++ openssh-5.3p1/sshd_config.5	2010-07-12 23:17:33.000000000 +0200
+@@ -610,6 +610,9 @@ Available keywords are
+ .Cm KerberosAuthentication ,
+ .Cm MaxAuthTries ,
+ .Cm MaxSessions ,
++.Cm PubkeyAuthentication ,
++.Cm AuthorizedKeysCommand ,
++.Cm AuthorizedKeysCommandRunAs ,
+ .Cm PasswordAuthentication ,
+ .Cm PermitEmptyPasswords ,
+ .Cm PermitOpen ,
+@@ -805,6 +808,20 @@ Specifies whether public key authenticat
+ The default is
+ .Dq yes .
+ Note that this option applies to protocol version 2 only.
++.It Cm AuthorizedKeysCommand
++Specifies a program to be used for lookup of the user's
++public keys.  The program will be invoked with its first
++argument the name of the user being authorized, and should produce 
++on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS 
++in sshd(8)).  By default (or when set to the empty string) there is no
++AuthorizedKeysCommand run.  If the AuthorizedKeysCommand does not successfully
++authorize the user, authorization falls through to the
++AuthorizedKeysFile.  Note that this option has an effect
++only with PubkeyAuthentication turned on.
++.It Cm AuthorizedKeysCommandRunAs
++Specifies the user under whose account the AuthorizedKeysCommand 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.akc openssh-5.3p1/sshd_config
+--- openssh-5.3p1/sshd_config.akc	2010-07-12 22:46:22.000000000 +0200
++++ openssh-5.3p1/sshd_config	2010-07-12 22:46:24.000000000 +0200
+@@ -47,6 +47,8 @@ SyslogFacility AUTHPRIV
+ #RSAAuthentication yes
+ #PubkeyAuthentication yes
+ #AuthorizedKeysFile	.ssh/authorized_keys
++#AuthorizedKeysCommand none
++#AuthorizedKeysCommandRunAs nobody
+ 
+ # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
+ #RhostsRSAAuthentication no
diff --git a/openssh-5.3p1-biguid.patch b/openssh-5.3p1-biguid.patch
new file mode 100644
index 0000000..5892008
--- /dev/null
+++ b/openssh-5.3p1-biguid.patch
@@ -0,0 +1,99 @@
+diff -up openssh-5.6p1/loginrec.c.biguid openssh-5.6p1/loginrec.c
+--- openssh-5.6p1/loginrec.c.biguid	2010-11-15 13:19:35.000000000 +0100
++++ openssh-5.6p1/loginrec.c	2010-11-15 13:19:38.000000000 +0100
+@@ -273,7 +273,7 @@ login_logout(struct logininfo *li)
+  *                try to retrieve lastlog information from wtmp/wtmpx.
+  */
+ unsigned int
+-login_get_lastlog_time(const int uid)
++login_get_lastlog_time(const uid_t uid)
+ {
+ 	struct logininfo li;
+ 
+@@ -297,7 +297,7 @@ login_get_lastlog_time(const int uid)
+  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
+  */
+ struct logininfo *
+-login_get_lastlog(struct logininfo *li, const int uid)
++login_get_lastlog(struct logininfo *li, const uid_t uid)
+ {
+ 	struct passwd *pw;
+ 
+@@ -311,7 +311,8 @@ login_get_lastlog(struct logininfo *li, 
+ 	 */
+ 	pw = getpwuid(uid);
+ 	if (pw == NULL)
+-		fatal("%s: Cannot find account for uid %i", __func__, uid);
++		fatal("%s: Cannot find account for uid %ld", __func__,
++		    (long)uid);
+ 
+ 	/* No MIN_SIZEOF here - we absolutely *must not* truncate the
+ 	 * username (XXX - so check for trunc!) */
+@@ -335,7 +336,7 @@ login_get_lastlog(struct logininfo *li, 
+  * allocation fails, the program halts.
+  */
+ struct
+-logininfo *login_alloc_entry(int pid, const char *username,
++logininfo *login_alloc_entry(pid_t pid, const char *username,
+     const char *hostname, const char *line)
+ {
+ 	struct logininfo *newli;
+@@ -363,7 +364,7 @@ login_free_entry(struct logininfo *li)
+  * Returns: 1
+  */
+ int
+-login_init_entry(struct logininfo *li, int pid, const char *username,
++login_init_entry(struct logininfo *li, pid_t pid, const char *username,
+     const char *hostname, const char *line)
+ {
+ 	struct passwd *pw;
+@@ -1496,7 +1497,7 @@ lastlog_openseek(struct logininfo *li, i
+ 
+ 	if (S_ISREG(st.st_mode)) {
+ 		/* find this uid's offset in the lastlog file */
+-		offset = (off_t) ((long)li->uid * sizeof(struct lastlog));
++		offset = (off_t) ((u_long)li->uid * sizeof(struct lastlog));
+ 
+ 		if (lseek(*fd, offset, SEEK_SET) != offset) {
+ 			logit("%s: %s->lseek(): %s", __func__,
+diff -up openssh-5.6p1/loginrec.h.biguid openssh-5.6p1/loginrec.h
+--- openssh-5.6p1/loginrec.h.biguid	2010-06-22 07:02:39.000000000 +0200
++++ openssh-5.6p1/loginrec.h	2010-11-15 13:19:38.000000000 +0100
+@@ -63,8 +63,8 @@ struct logininfo {
+ 	char       progname[LINFO_PROGSIZE];     /* name of program (for PAM) */
+ 	int        progname_null;
+ 	short int  type;                         /* type of login (LTYPE_*) */
+-	int        pid;                          /* PID of login process */
+-	int        uid;                          /* UID of this user */
++	pid_t      pid;                          /* PID of login process */
++	uid_t      uid;                          /* UID of this user */
+ 	char       line[LINFO_LINESIZE];         /* tty/pty name */
+ 	char       username[LINFO_NAMESIZE];     /* login username */
+ 	char       hostname[LINFO_HOSTSIZE];     /* remote hostname */
+@@ -86,12 +86,12 @@ struct logininfo {
+ /** 'public' functions */
+ 
+ /* construct a new login entry */
+-struct logininfo *login_alloc_entry(int pid, const char *username,
++struct logininfo *login_alloc_entry(pid_t pid, const char *username,
+ 				    const char *hostname, const char *line);
+ /* free a structure */
+ void login_free_entry(struct logininfo *li);
+ /* fill out a pre-allocated structure with useful information */
+-int login_init_entry(struct logininfo *li, int pid, const char *username,
++int login_init_entry(struct logininfo *li, pid_t pid, const char *username,
+ 		     const char *hostname, const char *line);
+ /* place the current time in a logininfo struct */
+ void login_set_current_time(struct logininfo *li);
+@@ -117,9 +117,9 @@ void login_set_addr(struct logininfo *li
+  * lastlog retrieval functions
+  */
+ /* lastlog *entry* functions fill out a logininfo */
+-struct logininfo *login_get_lastlog(struct logininfo *li, const int uid);
++struct logininfo *login_get_lastlog(struct logininfo *li, const uid_t uid);
+ /* lastlog *time* functions return time_t equivalent (uint) */
+-unsigned int login_get_lastlog_time(const int uid);
++unsigned int login_get_lastlog_time(const uid_t uid);
+ 
+ /* produce various forms of the line filename */
+ char *line_fullname(char *dst, const char *src, u_int dstsize);
diff --git a/openssh-5.3p1-clientloop.patch b/openssh-5.3p1-clientloop.patch
new file mode 100644
index 0000000..7ccb1e3
--- /dev/null
+++ b/openssh-5.3p1-clientloop.patch
@@ -0,0 +1,12 @@
+diff -up openssh-5.6p1/clientloop.c.clientloop openssh-5.6p1/clientloop.c
+--- openssh-5.6p1/clientloop.c.clientloop	2010-11-24 08:18:10.000000000 +0100
++++ openssh-5.6p1/clientloop.c	2010-11-24 08:18:11.000000000 +0100
+@@ -1944,7 +1944,7 @@ client_input_channel_req(int type, u_int
+ 		}
+ 		packet_check_eom();
+ 	}
+-	if (reply) {
++	if (reply && c != NULL) {
+ 		packet_start(success ?
+ 		    SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
+ 		packet_put_int(c->remote_id);
diff --git a/openssh-5.3p1-engine.patch b/openssh-5.3p1-engine.patch
new file mode 100644
index 0000000..132653d
--- /dev/null
+++ b/openssh-5.3p1-engine.patch
@@ -0,0 +1,9 @@
+--- openssh-5.2p1/openbsd-compat/openssl-compat.c~	2010-01-27 17:36:29.000000000 -0500
++++ openssh-5.2p1/openbsd-compat/openssl-compat.c	2010-01-28 10:52:53.000000000 -0500
+@@ -58,5 +58,6 @@
+ 	/* Enable use of crypto hardware */
+ 	ENGINE_load_builtin_engines();
+ 	ENGINE_register_all_complete();
++	OPENSSL_config(NULL);
+ }
+ #endif
diff --git a/openssh-5.3p1-entropy.patch b/openssh-5.3p1-entropy.patch
new file mode 100644
index 0000000..c3d52d6
--- /dev/null
+++ b/openssh-5.3p1-entropy.patch
@@ -0,0 +1,244 @@
+diff -up openssh-5.3p1/entropy.c.entropy openssh-5.3p1/entropy.c
+--- openssh-5.3p1/entropy.c.entropy	2011-05-28 01:28:18.077919647 +0200
++++ openssh-5.3p1/entropy.c	2011-05-28 01:28:29.995856823 +0200
+@@ -144,6 +144,9 @@ seed_rng(void)
+ 	memset(buf, '\0', sizeof(buf));
+ 
+ #endif /* OPENSSL_PRNG_ONLY */
++#ifdef __linux__
++	linux_seed();
++#endif /* __linux__ */
+ 	if (RAND_status() != 1)
+ 		fatal("PRNG is not seeded");
+ }
+diff -up openssh-5.3p1/openbsd-compat/Makefile.in.entropy openssh-5.3p1/openbsd-compat/Makefile.in
+--- openssh-5.3p1/openbsd-compat/Makefile.in.entropy	2008-06-08 19:32:29.000000000 +0200
++++ openssh-5.3p1/openbsd-compat/Makefile.in	2011-05-28 01:28:30.129865665 +0200
+@@ -20,7 +20,7 @@ OPENBSD=base64.o basename.o bindresvport
+ 
+ COMPAT=bsd-arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o
+ 
+-PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o
++PORTS=port-aix.o port-irix.o port-linux.o port-linux-prng.o port-solaris.o port-tun.o port-uw.o
+ 
+ .c.o:
+ 	$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
+diff -up openssh-5.3p1/openbsd-compat/port-linux-prng.c.entropy openssh-5.3p1/openbsd-compat/port-linux-prng.c
+--- openssh-5.3p1/openbsd-compat/port-linux-prng.c.entropy	2011-05-28 01:28:30.227856700 +0200
++++ openssh-5.3p1/openbsd-compat/port-linux-prng.c	2011-05-28 01:37:20.449856847 +0200
+@@ -0,0 +1,59 @@
++/* $Id: port-linux.c,v 1.11.4.2 2011/02/04 00:43:08 djm Exp $ */
++
++/*
++ * Copyright (c) 2011 Jan F. Chadima <jchadima at redhat.com>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Linux-specific portability code - prng support
++ */
++
++#include "includes.h"
++
++#include <errno.h>
++#include <stdarg.h>
++#include <string.h>
++#include <stdio.h>
++#include <openssl/rand.h>
++
++#include "log.h"
++#include "xmalloc.h"
++#include "servconf.h"
++#include "port-linux.h"
++#include "key.h"
++#include "hostfile.h"
++#include "auth.h"
++
++void
++linux_seed(void)
++{
++	int len;
++	char *env = getenv("SSH_USE_STRONG_RNG");
++	char *random = "/dev/random";
++	size_t ienv, randlen = 6;
++
++	if (!env || !strcmp(env, "0"))
++		random = "/dev/urandom";
++	else if ((ienv = atoi(env)) > 6)
++		randlen = ienv;
++
++	errno = 0;
++	if ((len = RAND_load_file(random, randlen)) != randlen) {
++		if (errno)
++			fatal ("cannot read from %s, %s", random, strerror(errno));
++		else
++			fatal ("EOF reading %s", random);
++	}
++}
+diff -up openssh-5.3p1/ssh.1.entropy openssh-5.3p1/ssh.1
+--- openssh-5.3p1/ssh.1.entropy	2009-06-21 09:48:52.000000000 +0200
++++ openssh-5.3p1/ssh.1	2011-05-28 01:28:30.341858350 +0200
+@@ -1252,6 +1252,20 @@ For more information, see the
+ .Cm PermitUserEnvironment
+ option in
+ .Xr sshd_config 5 .
++.It Ev SSH_USE_STRONG_RNG
++The reseeding of the OpenSSL random generator is usually done from
++.Cm /dev/urandom .
++If the 
++.Cm SSH_USE_STRONG_RNG
++environment variable is set to value other than
++.Cm 0
++the OpenSSL random generator is reseeded from
++.Cm /dev/random .
++The number of bytes read is defined by the SSH_USE_STRONG_RNG value. 
++Minimum is 6 bytes.
++This setting is not recommended on the computers without the hardware
++random generator because insufficient entropy causes the connection to 
++be blocked until enough entropy is available.
+ .Sh FILES
+ .Bl -tag -width Ds -compact
+ .It ~/.rhosts
+diff -up openssh-5.3p1/ssh-add.1.entropy openssh-5.3p1/ssh-add.1
+--- openssh-5.3p1/ssh-add.1.entropy	2011-05-28 01:28:07.412857036 +0200
++++ openssh-5.3p1/ssh-add.1	2011-05-28 01:28:30.478856207 +0200
+@@ -155,6 +155,20 @@ to make this work.)
+ .It Ev SSH_AUTH_SOCK
+ Identifies the path of a unix-domain socket used to communicate with the
+ agent.
++.It Ev SSH_USE_STRONG_RNG
++The reseeding of the OpenSSL random generator is usually done from
++.Cm /dev/urandom .
++If the 
++.Cm SSH_USE_STRONG_RNG
++environment variable is set to value other than
++.Cm 0
++the OpenSSL random generator is reseeded from
++.Cm /dev/random .
++The number of bytes read is defined by the SSH_USE_STRONG_RNG value. 
++Minimum is 6 bytes.
++This setting is not recommended on the computers without the hardware
++random generator because insufficient entropy causes the connection to 
++be blocked until enough entropy is available.
+ .El
+ .Sh FILES
+ .Bl -tag -width Ds
+diff -up openssh-5.3p1/ssh-agent.1.entropy openssh-5.3p1/ssh-agent.1
+--- openssh-5.3p1/ssh-agent.1.entropy	2009-06-21 09:52:28.000000000 +0200
++++ openssh-5.3p1/ssh-agent.1	2011-05-28 01:28:30.592856618 +0200
+@@ -191,6 +191,23 @@ authentication agent.
+ These sockets should only be readable by the owner.
+ The sockets should get automatically removed when the agent exits.
+ .El
++.Sh ENVIRONMENT
++.Bl -tag -width Ds -compact
++.Pp
++.It Pa SSH_USE_STRONG_RNG
++The reseeding of the OpenSSL random generator is usually done from
++.Cm /dev/urandom .
++If the 
++.Cm SSH_USE_STRONG_RNG
++environment variable is set to value other than
++.Cm 0
++the OpenSSL random generator is reseeded from
++.Cm /dev/random .
++The number of bytes read is defined by the SSH_USE_STRONG_RNG value. 
++Minimum is 6 bytes.
++This setting is not recommended on the computers without the hardware
++random generator because insufficient entropy causes the connection to 
++be blocked until enough entropy is available.
+ .Sh SEE ALSO
+ .Xr ssh 1 ,
+ .Xr ssh-add 1 ,
+diff -up openssh-5.3p1/sshd.8.entropy openssh-5.3p1/sshd.8
+--- openssh-5.3p1/sshd.8.entropy	2009-06-21 09:52:28.000000000 +0200
++++ openssh-5.3p1/sshd.8	2011-05-28 01:28:30.716858123 +0200
+@@ -863,6 +863,23 @@ concurrently for different ports, this c
+ started last).
+ The content of this file is not sensitive; it can be world-readable.
+ .El
++.Sh ENVIRONMENT
++.Bl -tag -width Ds -compact
++.Pp
++.It Pa SSH_USE_STRONG_RNG
++The reseeding of the OpenSSL random generator is usually done from
++.Cm /dev/urandom .
++If the 
++.Cm SSH_USE_STRONG_RNG
++environment variable is set to value other than
++.Cm 0
++the OpenSSL random generator is reseeded from
++.Cm /dev/random .
++The number of bytes read is defined by the SSH_USE_STRONG_RNG value. 
++Minimum is 6 bytes.
++This setting is not recommended on the computers without the hardware
++random generator because insufficient entropy causes the connection to 
++be blocked until enough entropy is available.
+ .Sh SEE ALSO
+ .Xr scp 1 ,
+ .Xr sftp 1 ,
+diff -up openssh-5.3p1/ssh-keygen.1.entropy openssh-5.3p1/ssh-keygen.1
+--- openssh-5.3p1/ssh-keygen.1.entropy	2011-05-28 01:28:08.141857715 +0200
++++ openssh-5.3p1/ssh-keygen.1	2011-05-28 01:28:30.843857051 +0200
+@@ -452,6 +452,23 @@ Contains Diffie-Hellman groups used for 
+ The file format is described in
+ .Xr moduli 5 .
+ .El
++.Sh ENVIRONMENT
++.Bl -tag -width Ds -compact
++.Pp
++.It Pa SSH_USE_STRONG_RNG
++The reseeding of the OpenSSL random generator is usually done from
++.Cm /dev/urandom .
++If the 
++.Cm SSH_USE_STRONG_RNG
++environment variable is set to value other than
++.Cm 0
++the OpenSSL random generator is reseeded from
++.Cm /dev/random .
++The number of bytes read is defined by the SSH_USE_STRONG_RNG value. 
++Minimum is 6 bytes.
++This setting is not recommended on the computers without the hardware
++random generator because insufficient entropy causes the connection to 
++be blocked until enough entropy is available.
+ .Sh SEE ALSO
+ .Xr ssh 1 ,
+ .Xr ssh-add 1 ,
+diff -up openssh-5.3p1/ssh-keysign.8.entropy openssh-5.3p1/ssh-keysign.8
+--- openssh-5.3p1/ssh-keysign.8.entropy	2007-06-05 10:27:13.000000000 +0200
++++ openssh-5.3p1/ssh-keysign.8	2011-05-28 01:28:30.954857427 +0200
+@@ -69,6 +69,23 @@ Since they are readable only by root,
+ .Nm
+ must be set-uid root if host-based authentication is used.
+ .El
++.Sh ENVIRONMENT
++.Bl -tag -width Ds -compact
++.Pp
++.It Pa SSH_USE_STRONG_RNG
++The reseeding of the OpenSSL random generator is usually done from
++.Cm /dev/urandom .
++If the 
++.Cm SSH_USE_STRONG_RNG
++environment variable is set to value other than
++.Cm 0
++the OpenSSL random generator is reseeded from
++.Cm /dev/random .
++The number of bytes read is defined by the SSH_USE_STRONG_RNG value. 
++Minimum is 6 bytes.
++This setting is not recommended on the computers without the hardware
++random generator because insufficient entropy causes the connection to 
++be blocked until enough entropy is available.
+ .Sh SEE ALSO
+ .Xr ssh 1 ,
+ .Xr ssh-keygen 1 ,
diff --git a/openssh-5.3p1-fips.patch b/openssh-5.3p1-fips.patch
new file mode 100644
index 0000000..01a715c
--- /dev/null
+++ b/openssh-5.3p1-fips.patch
@@ -0,0 +1,695 @@
+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);
diff --git a/openssh-5.3p1-gsissh.patch b/openssh-5.3p1-gsissh.patch
new file mode 100644
index 0000000..d63bd2a
--- /dev/null
+++ b/openssh-5.3p1-gsissh.patch
@@ -0,0 +1,2950 @@
+diff -Nur openssh-5.3p1.orig/auth2.c openssh-5.3p1/auth2.c
+--- openssh-5.3p1.orig/auth2.c	2011-08-12 08:52:47.301701689 +0200
++++ openssh-5.3p1/auth2.c	2011-08-12 08:53:52.205703508 +0200
+@@ -229,7 +229,27 @@
+ 	user = packet_get_string(NULL);
+ 	service = packet_get_string(NULL);
+ 	method = packet_get_string(NULL);
+-	debug("userauth-request for user %s service %s method %s", user, service, method);
++
++#ifdef GSSAPI
++	if (user[0] == '\0') {
++		debug("received empty username for %s", method);
++		if (strcmp(method, "gssapi-keyex") == 0) {
++			char *lname = NULL;
++			PRIVSEP(ssh_gssapi_localname(&lname));
++			if (lname && lname[0] != '\0') {
++				xfree(user);
++				user = lname;
++				debug("set username to %s from gssapi context", user);
++			} else {
++				debug("failed to set username from gssapi context");
++				packet_send_debug("failed to set username from gssapi context");
++			}
++		}
++	}
++#endif
++
++	debug("userauth-request for user %s service %s method %s",
++	    user[0] ? user : "<implicit>", service, method);
+ 	debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
+ 
+ #ifdef WITH_SELINUX
+@@ -240,23 +260,48 @@
+ 	if ((style = strchr(user, ':')) != NULL)
+ 		*style++ = 0;
+ 
+-	if (authctxt->attempt++ == 0) {
+-		/* setup auth context */
++	/* If first time or username changed or empty username,
++	   setup/reset authentication context. */
++	if ((authctxt->attempt++ == 0) ||
++	    (strcmp(user, authctxt->user) != 0) ||
++	    (strcmp(user, "") == 0)) {
++		if (authctxt->user) {
++			xfree(authctxt->user);
++			authctxt->user = NULL;
++		}
++		authctxt->valid = 0;
++		if (strcmp(service, "ssh-connection") != 0) {
++			packet_disconnect("Unsupported service %s", service);
++		}
++#ifdef GSSAPI
++		/* If we're going to set the username based on the
++		   GSSAPI context later, then wait until then to
++		   verify it. Just put in placeholders for now. */
++		if ((strcmp(user, "") == 0) &&
++		    (strcmp(method, "gssapi-with-mic") == 0)) {
++			authctxt->pw = fakepw();
++			authctxt->user = xstrdup(user);
++		} else {
++#endif
+ 		authctxt->pw = PRIVSEP(getpwnamallow(user));
+ 		authctxt->user = xstrdup(user);
+-		if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
++		if (authctxt->pw) {
+ 			authctxt->valid = 1;
+ 			debug2("input_userauth_request: setting up authctxt for %s", user);
+ 		} else {
+ 			logit("input_userauth_request: invalid user %s", user);
+ 			authctxt->pw = fakepw();
+ 		}
++#ifdef GSSAPI
++		} /* endif for setting username based on GSSAPI context */
++#endif
+ #ifdef USE_PAM
+ 		if (options.use_pam)
+ 			PRIVSEP(start_pam(authctxt));
+ #endif
+ 		setproctitle("%s%s", authctxt->valid ? user : "unknown",
+ 		    use_privsep ? " [net]" : "");
++		if (authctxt->attempt == 1) {
+ 		authctxt->service = xstrdup(service);
+ 		authctxt->style = style ? xstrdup(style) : NULL;
+ #ifdef WITH_SELINUX
+@@ -269,9 +314,10 @@
+ #endif
+ 		}
+ 		userauth_banner();
+-	} else if (strcmp(user, authctxt->user) != 0 ||
+-	    strcmp(service, authctxt->service) != 0) {
+-		packet_disconnect("Change of username or service not allowed: "
++		}
++	}
++	if (strcmp(service, authctxt->service) != 0) {
++		packet_disconnect("Change of service not allowed: "
+ 		    "(%s,%s) -> (%s,%s)",
+ 		    authctxt->user, authctxt->service, user, service);
+ 	}
+diff -Nur openssh-5.3p1.orig/auth2-gss.c openssh-5.3p1/auth2-gss.c
+--- openssh-5.3p1.orig/auth2-gss.c	2011-08-12 08:52:47.223701687 +0200
++++ openssh-5.3p1/auth2-gss.c	2011-08-12 08:53:52.205703508 +0200
+@@ -47,6 +47,7 @@
+ 
+ extern ServerOptions options;
+ 
++static void ssh_gssapi_userauth_error(Gssctxt *ctxt);
+ static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
+ static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
+ static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
+@@ -59,8 +60,8 @@
+ userauth_gsskeyex(Authctxt *authctxt)
+ {
+ 	int authenticated = 0;
+-	Buffer b;
+-	gss_buffer_desc mic, gssbuf;
++	Buffer b, b2;
++	gss_buffer_desc mic, gssbuf, gssbuf2;
+ 	u_int len;
+ 
+ 	mic.value = packet_get_string(&len);
+@@ -74,13 +75,27 @@
+ 	gssbuf.value = buffer_ptr(&b);
+ 	gssbuf.length = buffer_len(&b);
+ 
++	/* client may have used empty username to determine target
++	   name from GSSAPI context */
++	ssh_gssapi_buildmic(&b2, "", authctxt->service, "gssapi-keyex");
++
++	gssbuf2.value = buffer_ptr(&b2);
++	gssbuf2.length = buffer_len(&b2);
++
+ 	/* gss_kex_context is NULL with privsep, so we can't check it here */
+ 	if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, 
+-	    &gssbuf, &mic))))
+-		authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
+-		    authctxt->pw));
++						   &gssbuf, &mic))) ||
++	    !GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, 
++						   &gssbuf2, &mic)))) {
++		if (authctxt->valid && authctxt->user && authctxt->user[0]) {
++			authenticated =
++			    PRIVSEP(ssh_gssapi_userok(authctxt->user,
++				    authctxt->pw, 1 /* gssapi-keyex */));
++		}
++	}
+ 	
+ 	buffer_free(&b);
++	buffer_free(&b2);
+ 	xfree(mic.value);
+ 
+ 	return (authenticated);
+@@ -102,7 +117,10 @@
+ 	u_int len;
+ 	u_char *doid = NULL;
+ 
+-	if (!authctxt->valid || authctxt->user == NULL)
++	/* authctxt->valid may be 0 if we haven't yet determined
++	   username from gssapi context. */
++
++	if (authctxt->user == NULL)
+ 		return (0);
+ 
+ 	mechs = packet_get_int();
+@@ -172,7 +190,7 @@
+ 	Gssctxt *gssctxt;
+ 	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+ 	gss_buffer_desc recv_tok;
+-	OM_uint32 maj_status, min_status, flags;
++	OM_uint32 maj_status, min_status, flags = 0;
+ 	u_int len;
+ 
+ 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
+@@ -190,6 +208,7 @@
+ 	xfree(recv_tok.value);
+ 
+ 	if (GSS_ERROR(maj_status)) {
++		ssh_gssapi_userauth_error(gssctxt);
+ 		if (send_tok.length != 0) {
+ 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+ 			packet_put_string(send_tok.value, send_tok.length);
+@@ -253,6 +272,32 @@
+ 	gss_release_buffer(&maj_status, &send_tok);
+ }
+ 
++static void
++gssapi_set_username(Authctxt *authctxt)
++{
++	char *lname = NULL;
++
++	if ((authctxt->user == NULL) || (authctxt->user[0] == '\0')) {
++		PRIVSEP(ssh_gssapi_localname(&lname));
++		if (lname && lname[0] != '\0') {
++			if (authctxt->user) xfree(authctxt->user);
++			authctxt->user = lname;
++			debug("set username to %s from gssapi context", lname);
++			authctxt->pw = PRIVSEP(getpwnamallow(authctxt->user));
++			if (authctxt->pw) {
++				authctxt->valid = 1;
++#ifdef USE_PAM
++				if (options.use_pam)
++					PRIVSEP(start_pam(authctxt));
++#endif
++			}
++		} else {
++			debug("failed to set username from gssapi context");
++			packet_send_debug("failed to set username from gssapi context");
++		}
++	}
++}
++
+ /*
+  * This is called when the client thinks we've completed authentication.
+  * It should only be enabled in the dispatch handler by the function above,
+@@ -269,6 +314,8 @@
+ 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
+ 		fatal("No authentication or GSSAPI context");
+ 
++	gssapi_set_username(authctxt);
++
+ 	gssctxt = authctxt->methoddata;
+ 
+ 	/*
+@@ -278,8 +325,13 @@
+ 
+ 	packet_check_eom();
+ 
+-	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
+-	    authctxt->pw));
++	/* user should be set if valid but we double-check here */
++	if (authctxt->valid && authctxt->user && authctxt->user[0]) {
++		authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
++					authctxt->pw, 0 /* !gssapi-keyex */));
++	} else {
++		authenticated = 0;
++	}
+ 
+ 	authctxt->postponed = 0;
+ 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+@@ -320,9 +372,16 @@
+ 	gssbuf.value = buffer_ptr(&b);
+ 	gssbuf.length = buffer_len(&b);
+ 
++	gssapi_set_username(authctxt);
++
+ 	if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
+-		authenticated = 
+-		    PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
++		if (authctxt->valid && authctxt->user && authctxt->user[0]) {
++			authenticated =
++			    PRIVSEP(ssh_gssapi_userok(authctxt->user,
++				    authctxt->pw, 0 /* !gssapi-keyex */));
++		} else {
++			authenticated = 0;
++		}
+ 	else
+ 		logit("GSSAPI MIC check failed");
+ 
+@@ -339,6 +398,23 @@
+ 	userauth_finish(authctxt, authenticated, "gssapi-with-mic");
+ }
+ 
++static void ssh_gssapi_userauth_error(Gssctxt *ctxt) {
++	char *errstr;
++	OM_uint32 maj,min;
++	
++	errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
++	if (errstr) {
++		packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR);
++		packet_put_int(maj);
++		packet_put_int(min);
++		packet_put_cstring(errstr);
++		packet_put_cstring("");
++		packet_send();
++		packet_write_wait();
++		xfree(errstr);
++	}
++}
++
+ Authmethod method_gsskeyex = {
+ 	"gssapi-keyex",
+ 	userauth_gsskeyex,
+diff -Nur openssh-5.3p1.orig/auth.c openssh-5.3p1/auth.c
+--- openssh-5.3p1.orig/auth.c	2008-11-05 06:12:54.000000000 +0100
++++ openssh-5.3p1/auth.c	2011-08-12 08:53:52.251703501 +0200
+@@ -71,6 +71,9 @@
+ #endif
+ #include "monitor_wrap.h"
+ 
++#include "version.h"
++#include "ssh-globus-usage.h"
++
+ /* import */
+ extern ServerOptions options;
+ extern int use_privsep;
+@@ -269,7 +272,8 @@
+ 	    authmsg,
+ 	    method,
+ 	    authctxt->valid ? "" : "invalid user ",
+-	    authctxt->user,
++	    (authctxt->user && authctxt->user[0]) ?
++		authctxt->user : "unknown",
+ 	    get_remote_ipaddr(),
+ 	    get_remote_port(),
+ 	    info);
+@@ -291,6 +295,21 @@
+ 	if (authenticated == 0 && !authctxt->postponed)
+ 		audit_event(audit_classify_auth(method));
+ #endif
++	if (authenticated) {
++		char *userdn = NULL;
++		char *mech_name = NULL;
++		ssh_gssapi_get_client_info(&userdn, &mech_name);
++		debug("REPORTING (%s) (%s) (%s) (%s) (%s) (%s) (%s)",
++			 SSH_RELEASE, SSLeay_version(SSLEAY_VERSION),
++			 method, mech_name?mech_name:"NULL", get_remote_ipaddr(),
++			 (authctxt->user && authctxt->user[0])?
++				authctxt->user : "unknown",
++			userdn?userdn:"NULL");
++		ssh_globus_send_usage_metrics(SSH_RELEASE,
++					SSLeay_version(SSLEAY_VERSION),
++					method, mech_name, get_remote_ipaddr(),
++					authctxt->user, userdn);
++	}
+ }
+ 
+ /*
+@@ -325,7 +344,7 @@
+  *
+  * This returns a buffer allocated by xmalloc.
+  */
+-static char *
++char *
+ expand_authorized_keys(const char *filename, struct passwd *pw)
+ {
+ 	char *file, ret[MAXPATHLEN];
+@@ -526,9 +545,14 @@
+ 	    get_canonical_hostname(options.use_dns), get_remote_ipaddr());
+ 
+ 	pw = getpwnam(user);
++#ifdef USE_PAM
++	if (options.use_pam && options.permit_pam_user_change && pw == NULL)
++		pw = sshpam_getpw(user);
++#endif
+ 	if (pw == NULL) {
+ 		logit("Invalid user %.100s from %.100s",
+-		    user, get_remote_ipaddr());
++		      (user && user[0]) ? user : "unknown",
++		      get_remote_ipaddr());
+ #ifdef CUSTOM_FAILED_LOGIN
+ 		record_failed_login(user,
+ 		    get_canonical_hostname(options.use_dns), "ssh");
+diff -Nur openssh-5.3p1.orig/auth.h openssh-5.3p1/auth.h
+--- openssh-5.3p1.orig/auth.h	2011-08-12 08:52:47.303701689 +0200
++++ openssh-5.3p1/auth.h	2011-08-12 08:53:52.251703501 +0200
+@@ -149,6 +149,7 @@
+ void	userauth_finish(Authctxt *, int, char *);
+ void	userauth_send_banner(const char *);
+ int	auth_root_allowed(char *);
++char	*expand_authorized_keys(const char *filename, struct passwd *pw);
+ 
+ char	*auth2_read_banner(void);
+ 
+diff -Nur openssh-5.3p1.orig/auth-pam.c openssh-5.3p1/auth-pam.c
+--- openssh-5.3p1.orig/auth-pam.c	2011-08-12 08:52:47.099701683 +0200
++++ openssh-5.3p1/auth-pam.c	2011-08-12 08:53:52.252703501 +0200
+@@ -122,6 +122,10 @@
+  */
+ typedef pthread_t sp_pthread_t;
+ #else
++#define pthread_create openssh_pthread_create
++#define pthread_exit openssh_pthread_exit
++#define pthread_cancel openssh_pthread_cancel
++#define pthread_join openssh_pthread_join
+ typedef pid_t sp_pthread_t;
+ #endif
+ 
+@@ -272,6 +276,49 @@
+ # define pam_chauthtok(a,b)	(sshpam_chauthtok_ruid((a), (b)))
+ #endif
+ 
++struct passwd *
++sshpam_getpw(const char *user)
++{
++	struct passwd *pw;
++
++	if ((pw = getpwnam(user)) != NULL)
++		return(pw);
++
++	debug("PAM: faking passwd struct for user '%.100s'", user);
++	if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL)
++		return NULL;
++	pw->pw_name = xstrdup(user);	/* XXX leak */
++	pw->pw_shell = "/bin/true";
++	pw->pw_gecos = "sshd fake PAM user";
++	return (pw);
++}
++
++void
++sshpam_check_userchanged(void)
++{
++	int sshpam_err;
++	struct passwd *pw;
++	const char *user;
++
++	debug("sshpam_check_userchanged");
++	sshpam_err = pam_get_item(sshpam_handle, PAM_USER, &user);
++	if (sshpam_err != PAM_SUCCESS)
++		fatal("PAM: could not get PAM_USER: %s",
++		    pam_strerror(sshpam_handle, sshpam_err));
++	if (strcmp(user, sshpam_authctxt->pw->pw_name) != 0) {
++		debug("PAM: user mapped from '%.100s' to '%.100s'",
++		    sshpam_authctxt->pw->pw_name, user);
++		if ((pw = getpwnam(user)) == NULL)
++			fatal("PAM: could not get passwd entry for user "
++			    "'%.100s' provided by PAM_USER", user);
++		pwfree(sshpam_authctxt->pw);
++		sshpam_authctxt->pw = pw;
++		sshpam_authctxt->valid = allowed_user(pw);
++		debug("PAM: user '%.100s' now %svalid", user,
++		    sshpam_authctxt->valid ? "" : "in");
++	}
++}
++
+ void
+ sshpam_password_change_required(int reqd)
+ {
+@@ -294,7 +341,7 @@
+ static void
+ import_environments(Buffer *b)
+ {
+-	char *env;
++	char *env, *user;
+ 	u_int i, num_env;
+ 	int err;
+ 
+@@ -304,6 +351,15 @@
+ 	/* Import variables set by do_pam_account */
+ 	sshpam_account_status = buffer_get_int(b);
+ 	sshpam_password_change_required(buffer_get_int(b));
++	if (options.permit_pam_user_change) {
++		user = buffer_get_string(b, NULL);
++		debug("PAM: got username '%.100s' from thread", user);
++		if ((err = pam_set_item(sshpam_handle, PAM_USER, user)) != PAM_SUCCESS)
++			fatal("PAM: failed to set PAM_USER: %s",
++			      pam_strerror(sshpam_handle, err));
++		pwfree(sshpam_authctxt->pw);
++		sshpam_authctxt->pw = pwcopy(sshpam_getpw(user));
++	}
+ 
+ 	/* Import environment from subprocess */
+ 	num_env = buffer_get_int(b);
+@@ -469,6 +525,9 @@
+ 	if (sshpam_err != PAM_SUCCESS)
+ 		goto auth_fail;
+ 
++	if (options.permit_pam_user_change) {
++		sshpam_check_userchanged();
++	}
+ 	if (compat20) {
+ 		if (!do_pam_account()) {
+ 			sshpam_err = PAM_ACCT_EXPIRED;
+@@ -489,6 +548,9 @@
+ 	/* Export variables set by do_pam_account */
+ 	buffer_put_int(&buffer, sshpam_account_status);
+ 	buffer_put_int(&buffer, sshpam_authctxt->force_pwchange);
++	if (options.permit_pam_user_change) {
++		buffer_put_cstring(&buffer, sshpam_authctxt->pw->pw_name);
++	}
+ 
+ 	/* Export any environment strings set in child */
+ 	for(i = 0; environ[i] != NULL; i++)
+@@ -907,6 +969,12 @@
+ 	debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
+ 	    pam_strerror(sshpam_handle, sshpam_err));
+ 
++	if (options.permit_pam_user_change) {
++		sshpam_check_userchanged();
++		if (getpwnam(sshpam_authctxt->pw->pw_name) == NULL)
++		    fatal("PAM: completed authentication but PAM account invalid");
++	}
++
+ 	if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) {
+ 		sshpam_account_status = 0;
+ 		return (sshpam_account_status);
+@@ -1206,6 +1274,9 @@
+ 		    pam_strerror(sshpam_handle, sshpam_err));
+ 
+ 	sshpam_err = pam_authenticate(sshpam_handle, flags);
++	if (options.permit_pam_user_change) {
++		sshpam_check_userchanged();
++	}
+ 	sshpam_password = NULL;
+ 	if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
+ 		debug("PAM: password authentication accepted for %.100s",
+diff -Nur openssh-5.3p1.orig/auth-pam.h openssh-5.3p1/auth-pam.h
+--- openssh-5.3p1.orig/auth-pam.h	2011-08-12 08:52:47.098701683 +0200
++++ openssh-5.3p1/auth-pam.h	2011-08-12 08:53:52.252703501 +0200
+@@ -46,5 +46,6 @@
+ void sshpam_cleanup(void);
+ int sshpam_auth_passwd(Authctxt *, const char *);
+ int is_pam_session_open(void);
++struct passwd *sshpam_getpw(const char *);
+ 
+ #endif /* USE_PAM */
+diff -Nur openssh-5.3p1.orig/canohost.c openssh-5.3p1/canohost.c
+--- openssh-5.3p1.orig/canohost.c	2011-08-12 08:52:47.143701685 +0200
++++ openssh-5.3p1/canohost.c	2011-08-12 08:53:52.253703501 +0200
+@@ -16,6 +16,7 @@
+ 
+ #include <sys/types.h>
+ #include <sys/socket.h>
++#include <sys/param.h>          /* for MAXHOSTNAMELEN */
+ 
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+@@ -439,3 +440,33 @@
+ {
+ 	return get_port(1);
+ }
++
++void
++resolve_localhost(char **host)
++{
++	struct hostent *hostinfo;
++
++	hostinfo = gethostbyname(*host);
++	if (hostinfo == NULL || hostinfo->h_name == NULL) {
++		debug("gethostbyname(%s) failed", *host);
++		return;
++	}
++	if (hostinfo->h_addrtype == AF_INET) {
++		struct in_addr addr;
++		addr = *(struct in_addr *)(hostinfo->h_addr);
++		if (ntohl(addr.s_addr) == INADDR_LOOPBACK) {
++			char buf[MAXHOSTNAMELEN];
++			if (gethostname(buf, sizeof(buf)) < 0) {
++				debug("gethostname() failed");
++				return;
++			}
++			hostinfo = gethostbyname(buf);
++			xfree(*host);
++			if (hostinfo == NULL || hostinfo->h_name == NULL) {
++				*host = xstrdup(buf);
++			} else {
++				*host = xstrdup(hostinfo->h_name);
++			}
++		}
++	}
++}
+diff -Nur openssh-5.3p1.orig/canohost.h openssh-5.3p1/canohost.h
+--- openssh-5.3p1.orig/canohost.h	2009-06-21 11:50:08.000000000 +0200
++++ openssh-5.3p1/canohost.h	2011-08-12 08:53:52.253703501 +0200
+@@ -26,4 +26,6 @@
+ int		 get_sock_port(int, int);
+ void		 clear_cached_addr(void);
+ 
++void		 resolve_localhost(char **host);
++
+ void		 ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *);
+diff -Nur openssh-5.3p1.orig/configure.ac openssh-5.3p1/configure.ac
+--- openssh-5.3p1.orig/configure.ac	2011-08-12 08:52:47.361701691 +0200
++++ openssh-5.3p1/configure.ac	2011-08-12 08:53:52.254703501 +0200
+@@ -3642,6 +3642,14 @@
+ 			AC_CHECK_HEADER(gssapi_krb5.h, ,
+ 					[ CPPFLAGS="$oldCPP" ])
+ 
++			# If we're using some other GSSAPI
++			if test -n "$GSSAPI" ; then
++				AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Kerberos GSI.])
++			fi
++
++			if test -z "$GSSAPI"; then
++				GSSAPI="KRB5";
++			fi
+ 		fi
+ 		if test ! -z "$need_dash_r" ; then
+ 			LDFLAGS="$LDFLAGS -R${KRB5ROOT}/lib"
+@@ -3661,6 +3669,50 @@
+ 	]
+ )
+ 
++# Check whether the user wants GSI (Globus) support
++gsi="no"
++AC_ARG_WITH(gsi,
++	[  --with-gsi              Enable Globus GSI authentication support],
++	[
++		gsi="$withval"
++	]
++)
++
++if test "x$gsi" != "xno" ; then
++	# Globus GSSAPI configuration
++	AC_MSG_CHECKING(for Globus GSI)
++	AC_DEFINE(GSI, 1, [Define if you want GSI/Globus authentication support.])
++
++	if test -n "$GSSAPI" ; then
++		AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Globus GSI.])
++	fi
++
++	if test -z "$GSSAPI" ; then	
++		GSSAPI="GSI"
++	fi
++
++	LIBS="$LIBS `pkg-config --libs globus-gss-assist`"
++	CPPFLAGS="$CPPFLAGS `pkg-config --cflags globus-gss-assist`"
++
++	AC_DEFINE(GSSAPI)
++	AC_DEFINE(HAVE_GSSAPI_H)
++
++	AC_CHECK_FUNCS(globus_gss_assist_map_and_authorize)
++
++	dnl
++	dnl Check for globus_usage_stats_send
++	dnl
++	AC_SEARCH_LIBS(globus_usage_stats_send,
++	               globus_usage,
++	               AC_DEFINE([HAVE_GLOBUS_USAGE], 1, [Have Globus Usage]))
++	dnl
++	dnl Check for globus_usage_stats_send_array
++	dnl
++	AC_SEARCH_LIBS(globus_usage_stats_send_array,
++		       globus_usage,
++	               AC_DEFINE([HAVE_GLOBUS_USAGE_SEND_ARRAY], 1, [Have Globus Usage send_array]))
++fi
++
+ # Check whether user wants NSS support
+ LIBNSS_MSG="no"
+ AC_ARG_WITH(nss,
+@@ -3670,7 +3722,7 @@
+ 		LIBNSS_MSG="yes"
+ 		CPPFLAGS="$CPPFLAGS -I/usr/include/nss3 -I/usr/include/nspr4"
+ 		AC_CHECK_HEADERS(pk11pub.h)
+-		LIBS="$LIBS -lnss3"
++		LIBS="$LIBS -lnss3 -lplc4"
+ 		AC_CHECK_DECLS([SEC_ERROR_LOCKED_PASSWORD], [], [], [#include <secerr.h>])
+ 	fi
+ 	])
+diff -Nur openssh-5.3p1.orig/gss-genr.c openssh-5.3p1/gss-genr.c
+--- openssh-5.3p1.orig/gss-genr.c	2011-08-12 08:52:47.231701687 +0200
++++ openssh-5.3p1/gss-genr.c	2011-08-12 08:53:52.256703501 +0200
+@@ -38,6 +38,7 @@
+ #include "xmalloc.h"
+ #include "buffer.h"
+ #include "log.h"
++#include "canohost.h"
+ #include "ssh2.h"
+ #include "cipher.h"
+ #include "key.h"
+@@ -367,9 +368,18 @@
+ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
+ {
+ 	gss_buffer_desc gssbuf;
++	char *xhost;
+ 	char *val;
+ 
+-	xasprintf(&val, "host@%s", host);
++	/* Make a copy of the host name, in case it was returned by a
++	 * previous call to gethostbyname(). */	
++	xhost = xstrdup(host);
++
++	/* Make sure we have the FQDN. Some GSSAPI implementations don't do
++	 * this for us themselves */
++	resolve_localhost(&xhost);
++	
++	xasprintf(&val, "host@%s", xhost);
+ 	gssbuf.value = val;
+ 	gssbuf.length = strlen(gssbuf.value);
+ 
+@@ -377,6 +387,7 @@
+ 	    &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name)))
+ 		ssh_gssapi_error(ctx);
+ 
++	xfree(xhost);
+ 	xfree(gssbuf.value);
+ 	return (ctx->major);
+ }
+diff -Nur openssh-5.3p1.orig/gss-serv.c openssh-5.3p1/gss-serv.c
+--- openssh-5.3p1.orig/gss-serv.c	2011-08-12 08:52:47.232701687 +0200
++++ openssh-5.3p1/gss-serv.c	2011-08-12 08:53:52.257703501 +0200
+@@ -52,6 +52,7 @@
+ #include "monitor_wrap.h"
+ 
+ extern ServerOptions options;
++extern Authctxt *the_authctxt;
+ 
+ static ssh_gssapi_client gssapi_client =
+     { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
+@@ -63,14 +64,23 @@
+ #ifdef KRB5
+ extern ssh_gssapi_mech gssapi_kerberos_mech;
+ #endif
++#ifdef GSI
++extern ssh_gssapi_mech gssapi_gsi_mech;
++#endif
+ 
+ ssh_gssapi_mech* supported_mechs[]= {
+ #ifdef KRB5
+ 	&gssapi_kerberos_mech,
+ #endif
++#ifdef GSI
++	&gssapi_gsi_mech,
++#endif
+ 	&gssapi_null_mech,
+ };
+ 
++#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
++static int limited = 0;
++#endif
+ 
+ /*
+  * Acquire credentials for a server running on the current host.
+@@ -159,7 +169,8 @@
+ 
+ 	gss_create_empty_oid_set(&min_status, oidset);
+ 
+-	if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
++	/* Ask privileged process what mechanisms it supports. */
++	if (GSS_ERROR(PRIVSEP(gss_indicate_mechs(&min_status, &supported))))
+ 		return;
+ 
+ 	while (supported_mechs[i]->name != NULL) {
+@@ -212,6 +223,10 @@
+ 	    (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) {
+ 		if (ssh_gssapi_getclient(ctx, &gssapi_client))
+ 			fatal("Couldn't convert client name");
++#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
++		if (flags && (*flags & GSS_C_GLOBUS_LIMITED_PROXY_FLAG))
++			limited=1;
++#endif
+ 	}
+ 
+ 	return (status);
+@@ -231,6 +246,17 @@
+ 
+ 	tok = ename->value;
+ 
++#ifdef GSI /* GSI gss_export_name() is broken. */
++	if ((ctx->oid->length == gssapi_gsi_mech.oid.length) &&
++	    (memcmp(ctx->oid->elements, gssapi_gsi_mech.oid.elements,
++		    gssapi_gsi_mech.oid.length) == 0)) {
++		name->length = ename->length;
++		name->value = xmalloc(ename->length+1);
++		memcpy(name->value, ename->value, ename->length);
++		return GSS_S_COMPLETE;
++	}
++#endif
++
+ 	/*
+ 	 * Check that ename is long enough for all of the fixed length
+ 	 * header, and that the initial ID bytes are correct
+@@ -296,8 +322,11 @@
+ 			return GSS_S_COMPLETE;
+ 		}
+ 
+-		if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, 
+-		    ctx->client_creds, ctx->oid, &new_name, 
++		/* Call gss_inquire_cred rather than gss_inquire_cred_by_mech
++		   because GSI doesn't support the latter. -jbasney */
++
++		if ((ctx->major = gss_inquire_cred(&ctx->minor, 
++		    ctx->client_creds, &new_name, 
+ 		    NULL, NULL, NULL))) {
+ 			ssh_gssapi_error(ctx);
+ 			return (ctx->major);
+@@ -340,9 +369,12 @@
+ 	if (client->mech == NULL)
+ 		return GSS_S_FAILURE;
+ 
++	/* Call gss_inquire_cred rather than gss_inquire_cred_by_mech
++	   because GSI doesn't support the latter. -jbasney */
++
+ 	if (ctx->client_creds &&
+-	    (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
+-	     ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
++	    (ctx->major = gss_inquire_cred(&ctx->minor,
++	     ctx->client_creds, &client->name, NULL, NULL, NULL))) {
+ 		ssh_gssapi_error(ctx);
+ 		return (ctx->major);
+ 	}
+@@ -369,6 +401,10 @@
+ 	/* We can't copy this structure, so we just move the pointer to it */
+ 	client->creds = ctx->client_creds;
+ 	ctx->client_creds = GSS_C_NO_CREDENTIAL;
++
++	/* needed for globus_gss_assist_map_and_authorize() */
++	client->context = ctx->context;
++
+ 	return (ctx->major);
+ }
+ 
+@@ -389,6 +425,11 @@
+ ssh_gssapi_storecreds(void)
+ {
+ 	if (gssapi_client.mech && gssapi_client.mech->storecreds) {
++		if (options.gss_creds_path) {
++			gssapi_client.store.filename =
++				expand_authorized_keys(options.gss_creds_path,
++						       the_authctxt->pw);
++		}
+ 		(*gssapi_client.mech->storecreds)(&gssapi_client);
+ 	} else
+ 		debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
+@@ -413,7 +454,7 @@
+ 
+ /* Privileged */
+ int
+-ssh_gssapi_userok(char *user, struct passwd *pw)
++ssh_gssapi_userok(char *user, struct passwd *pw, int gssapi_keyex)
+ {
+ 	OM_uint32 lmin;
+ 
+@@ -422,6 +463,12 @@
+ 		debug("No suitable client data");
+ 		return 0;
+ 	}
++#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
++	if (limited && options.gsi_allow_limited_proxy != 1) {
++		debug("limited proxy not acceptable for remote login");
++		return 0;
++	}
++#endif
+ 	if (gssapi_client.mech && gssapi_client.mech->userok)
+ 		if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
+ 			gssapi_client.used = 1;
+@@ -440,6 +487,24 @@
+ 	return (0);
+ }
+ 
++/* Priviledged */
++int
++ssh_gssapi_localname(char **user)
++{
++    	*user = NULL;
++	if (gssapi_client.displayname.length == 0 || 
++	    gssapi_client.displayname.value == NULL) {
++		debug("No suitable client data");
++		return(0);
++	}
++	if (gssapi_client.mech && gssapi_client.mech->localname) {
++		return((*gssapi_client.mech->localname)(&gssapi_client,user));
++	} else {
++		debug("Unknown client authentication type");
++	}
++	return(0);
++}
++
+ /* These bits are only used for rekeying. The unpriviledged child is running 
+  * as the user, the monitor is root.
+  *
+@@ -466,6 +531,7 @@
+ 	pam_handle_t *pamh = NULL;
+ 	struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
+ 	char *envstr;
++	char **p; char **pw;
+ #endif
+ 
+ 	if (gssapi_client.store.filename == NULL && 
+@@ -495,6 +561,18 @@
+ 	if (ret)
+ 		return;
+ 
++	/* Put ssh pam stack env variables in this new pam stack env 
++	 * Using pam-pkinit, KRB5CCNAME is set during do_pam_session
++	 * this addition enables pam-pkinit to access KRB5CCNAME if used 
++	 * in sshd-rekey stack too
++	 */
++	pw = p = fetch_pam_environment();
++	while ( *pw != NULL ) {
++	        pam_putenv(pamh, *pw);
++		pw++;
++	}
++	free_pam_environment(p);
++
+ 	xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, 
+ 	    gssapi_client.store.envval);
+ 
+@@ -526,4 +604,12 @@
+ 	return ok;
+ }
+ 
++void
++ssh_gssapi_get_client_info(char **userdn, char **mech) {
++	*userdn = gssapi_client.displayname.value;
++
++	if (gssapi_client.mech)
++		*mech = gssapi_client.mech->name;
++}
++
+ #endif
+diff -Nur openssh-5.3p1.orig/gss-serv-gsi.c openssh-5.3p1/gss-serv-gsi.c
+--- openssh-5.3p1.orig/gss-serv-gsi.c	1970-01-01 01:00:00.000000000 +0100
++++ openssh-5.3p1/gss-serv-gsi.c	2011-08-12 08:53:52.257703501 +0200
+@@ -0,0 +1,238 @@
++/*
++ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "includes.h"
++
++#ifdef GSSAPI
++#ifdef GSI
++
++#include <sys/types.h>
++
++#include <stdarg.h>
++#include <string.h>
++
++#include "xmalloc.h"
++#include "key.h"
++#include "hostfile.h"
++#include "auth.h"
++#include "log.h"
++#include "servconf.h"
++
++#include "buffer.h"
++#include "ssh-gss.h"
++
++extern ServerOptions options;
++
++#include <globus_gss_assist.h>
++
++static int ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name);
++static int ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user);
++static void ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client);
++static int ssh_gssapi_gsi_updatecreds(ssh_gssapi_ccache *store,
++				       ssh_gssapi_client *client);
++
++ssh_gssapi_mech gssapi_gsi_mech = {
++	"dZuIebMjgUqaxvbF7hDbAw==",
++	"GSI",
++	{9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"},
++	NULL,
++	&ssh_gssapi_gsi_userok,
++	&ssh_gssapi_gsi_localname,
++	&ssh_gssapi_gsi_storecreds,
++	&ssh_gssapi_gsi_updatecreds
++};
++
++/*
++ * Check if this user is OK to login under GSI. User has been authenticated
++ * as identity in global 'client_name.value' and is trying to log in as passed
++ * username in 'name'.
++ *
++ * Returns non-zero if user is authorized, 0 otherwise.
++ */
++static int
++ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name)
++{
++    int authorized = 0;
++    globus_result_t res;
++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
++    char lname[256] = "";
++#endif
++    
++#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
++    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
++	return 0;
++    }
++#endif
++
++/* use new globus_gss_assist_map_and_authorize() interface if available */
++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
++    debug("calling globus_gss_assist_map_and_authorize()");
++    if (GLOBUS_SUCCESS !=
++        (res = globus_gss_assist_map_and_authorize(client->context, "ssh",
++                                                   name, lname, 256))) {
++        debug("%s", globus_error_print_chain(globus_error_get(res)));
++    } else if (lname && lname[0] && strcmp(name, lname) != 0) {
++        debug("GSI user maps to %s, not %s", lname, name);
++    } else {
++        authorized = 1;
++    }
++#else
++    debug("calling globus_gss_assist_userok()");
++    if (GLOBUS_SUCCESS !=
++        (res = (globus_gss_assist_userok(client->displayname.value,
++                                         name)))) {
++        debug("%s", globus_error_print_chain(globus_error_get(res)));
++    } else {
++        authorized = 1;
++    }
++#endif
++    
++    logit("GSI user %s is%s authorized as target user %s",
++	(char *) client->displayname.value, (authorized ? "" : " not"), name);
++    
++    return authorized;
++}
++
++/*
++ * Return the local username associated with the GSI credentials.
++ */
++int
++ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user)
++{
++    globus_result_t res;
++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
++    char lname[256] = "";
++#endif
++
++#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
++    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
++	return 0;
++    }
++#endif
++
++/* use new globus_gss_assist_map_and_authorize() interface if available */
++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
++    debug("calling globus_gss_assist_map_and_authorize()");
++    if (GLOBUS_SUCCESS !=
++        (res = globus_gss_assist_map_and_authorize(client->context, "ssh",
++                                                   NULL, lname, 256))) {
++        debug("%s", globus_error_print_chain(globus_error_get(res)));
++        logit("failed to map GSI user %s", (char *)client->displayname.value);
++        return 0;
++    }
++    *user = strdup(lname);
++#else
++    debug("calling globus_gss_assist_gridmap()");
++    if (GLOBUS_SUCCESS !=
++        (res = globus_gss_assist_gridmap(client->displayname.value, user))) {
++        debug("%s", globus_error_print_chain(globus_error_get(res)));
++        logit("failed to map GSI user %s", (char *)client->displayname.value);
++        return 0;
++    }
++#endif
++
++    logit("GSI user %s mapped to target user %s",
++          (char *) client->displayname.value, *user);
++
++    return 1;
++}
++
++/*
++ * Export GSI credentials to disk.
++ */
++static void
++ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client)
++{
++	OM_uint32	major_status;
++	OM_uint32	minor_status;
++	gss_buffer_desc	export_cred = GSS_C_EMPTY_BUFFER;
++	char *		p;
++	
++	if (!client || !client->creds) {
++	    return;
++	}
++
++	major_status = gss_export_cred(&minor_status,
++				       client->creds,
++				       GSS_C_NO_OID,
++				       1,
++				       &export_cred);
++	if (GSS_ERROR(major_status) && major_status != GSS_S_UNAVAILABLE) {
++	    Gssctxt *ctx;
++	    ssh_gssapi_build_ctx(&ctx);
++	    ctx->major = major_status;
++	    ctx->minor = minor_status;
++	    ssh_gssapi_set_oid(ctx, &gssapi_gsi_mech.oid);
++	    ssh_gssapi_error(ctx);
++	    ssh_gssapi_delete_ctx(&ctx);
++	    return;
++	}
++	
++	p = strchr((char *) export_cred.value, '=');
++	if (p == NULL) {
++	    logit("Failed to parse exported credentials string '%.100s'",
++		(char *)export_cred.value);
++	    gss_release_buffer(&minor_status, &export_cred);
++	    return;
++	}
++	*p++ = '\0';
++	if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0) {
++	    client->store.envvar = strdup("X509_USER_PROXY");
++	} else {
++	    client->store.envvar = strdup((char *)export_cred.value);
++	}
++	if (access(p, R_OK) == 0) {
++        if (client->store.filename) {
++            if (rename(p, client->store.filename) < 0) {
++                logit("Failed to rename %s to %s: %s", p,
++                      client->store.filename, strerror(errno));
++                xfree(client->store.filename);
++                client->store.filename = strdup(p);
++            } else {
++                p = client->store.filename;
++            }
++        } else {
++            client->store.filename = strdup(p);
++        }
++	}
++	client->store.envval = strdup(p);
++#ifdef USE_PAM
++	if (options.use_pam)
++	    do_pam_putenv(client->store.envvar, client->store.envval);
++#endif
++	gss_release_buffer(&minor_status, &export_cred);
++}
++
++/*
++ * Export updated GSI credentials to disk.
++ */
++static int
++ssh_gssapi_gsi_updatecreds(ssh_gssapi_ccache *store,ssh_gssapi_client *client)
++{
++	ssh_gssapi_gsi_storecreds(client);
++	return 1;
++}
++
++#endif /* GSI */
++#endif /* GSSAPI */
+diff -Nur openssh-5.3p1.orig/gss-serv-krb5.c openssh-5.3p1/gss-serv-krb5.c
+--- openssh-5.3p1.orig/gss-serv-krb5.c	2011-08-12 08:52:47.340701691 +0200
++++ openssh-5.3p1/gss-serv-krb5.c	2011-08-12 08:53:52.258703501 +0200
+@@ -109,7 +109,35 @@
+ 	return retval;
+ }
+ 
++/* Retrieve the local username associated with a set of Kerberos 
++ * credentials. Hopefully we can use this for the 'empty' username
++ * logins discussed in the draft  */
++static int
++ssh_gssapi_krb5_localname(ssh_gssapi_client *client, char **user) {
++	krb5_principal princ;
++	int retval;
++
++	if (ssh_gssapi_krb5_init() == 0)
++		return 0;
++
++	if ((retval=krb5_parse_name(krb_context, client->displayname.value, 
++				    &princ))) {
++		logit("krb5_parse_name(): %.100s", 
++			krb5_get_err_text(krb_context,retval));
++		return 0;
++	}
++
++	/* We've got to return a malloc'd string */
++	*user = (char *)xmalloc(256);
++	if (krb5_aname_to_localname(krb_context, princ, 256, *user)) {
++		xfree(*user);
++		*user = NULL;
++		return(0);
++	}
+ 
++	return(1);
++}
++	
+ /* This writes out any forwarded credentials from the structure populated
+  * during userauth. Called after we have setuid to the user */
+ 
+@@ -191,7 +219,7 @@
+ 	return;
+ }
+ 
+-int
++static int
+ ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, 
+     ssh_gssapi_client *client)
+ {
+@@ -262,7 +290,7 @@
+ 	{9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"},
+ 	NULL,
+ 	&ssh_gssapi_krb5_userok,
+-	NULL,
++	&ssh_gssapi_krb5_localname,
+ 	&ssh_gssapi_krb5_storecreds,
+ 	&ssh_gssapi_krb5_updatecreds
+ };
+diff -Nur openssh-5.3p1.orig/kexgsss.c openssh-5.3p1/kexgsss.c
+--- openssh-5.3p1.orig/kexgsss.c	2011-08-12 08:52:47.236701687 +0200
++++ openssh-5.3p1/kexgsss.c	2011-08-12 08:53:52.259703501 +0200
+@@ -44,6 +44,7 @@
+ #include "monitor_wrap.h"
+ #include "servconf.h"
+ 
++static void kex_gss_send_error(Gssctxt *ctxt);
+ extern ServerOptions options;
+ 
+ void
+@@ -89,8 +90,10 @@
+ 
+ 	debug2("%s: Acquiring credentials", __func__);
+ 
+-	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
++	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) {
++		kex_gss_send_error(ctxt);
+ 		fatal("Unable to acquire credentials for the server");
++	}
+ 
+ 	switch (kex->kex_type) {
+ 	case KEX_GSS_GRP1_SHA1:
+@@ -176,12 +179,13 @@
+ 	} while (maj_status & GSS_S_CONTINUE_NEEDED);
+ 
+ 	if (GSS_ERROR(maj_status)) {
++		kex_gss_send_error(ctxt);
+ 		if (send_tok.length > 0) {
+ 			packet_start(SSH2_MSG_KEXGSS_CONTINUE);
+ 			packet_put_string(send_tok.value, send_tok.length);
+ 			packet_send();
+ 		}
+-		fatal("accept_ctx died");
++		packet_disconnect("GSSAPI Key Exchange handshake failed");
+ 	}
+ 
+ 	if (!(ret_flags & GSS_C_MUTUAL_FLAG))
+@@ -285,4 +289,23 @@
+ 	if (options.gss_store_rekey)
+ 		ssh_gssapi_rekey_creds();
+ }
++
++static void 
++kex_gss_send_error(Gssctxt *ctxt) {
++	char *errstr;
++	OM_uint32 maj,min;
++		
++	errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
++	if (errstr) {
++		packet_start(SSH2_MSG_KEXGSS_ERROR);
++		packet_put_int(maj);
++		packet_put_int(min);
++		packet_put_cstring(errstr);
++		packet_put_cstring("");
++		packet_send();
++		packet_write_wait();
++		/* XXX - We should probably log the error locally here */
++		xfree(errstr);
++	}
++}
+ #endif /* GSSAPI */
+diff -Nur openssh-5.3p1.orig/LICENSE.globus_usage openssh-5.3p1/LICENSE.globus_usage
+--- openssh-5.3p1.orig/LICENSE.globus_usage	1970-01-01 01:00:00.000000000 +0100
++++ openssh-5.3p1/LICENSE.globus_usage	2011-08-12 08:53:52.260703501 +0200
+@@ -0,0 +1,18 @@
++/*
++ * Portions of the Usage Metrics suport code are derived from the
++ * Globus project's GridFTP subject to the following license.
++ *
++ * Copyright 2010 University of Chicago
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
+diff -Nur openssh-5.3p1.orig/Makefile.in openssh-5.3p1/Makefile.in
+--- openssh-5.3p1.orig/Makefile.in	2011-08-12 08:52:47.381701691 +0200
++++ openssh-5.3p1/Makefile.in	2011-08-12 08:53:52.262703501 +0200
+@@ -91,8 +91,10 @@
+ 	monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \
+ 	auth-krb5.o audit-linux.o \
+  	auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\
++	gss-serv-gsi.o \
+ 	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
+ 	audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \
++	ssh-globus-usage.o \
+ 	roaming_common.o
+ 
+ MANPAGES	= moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out ssh-ldap-helper.8.out sshd_config.5.out ssh_config.5.out ssh-ldap.conf.5.out
+diff -Nur openssh-5.3p1.orig/misc.c openssh-5.3p1/misc.c
+--- openssh-5.3p1.orig/misc.c	2011-08-12 08:52:47.089701683 +0200
++++ openssh-5.3p1/misc.c	2011-08-12 08:53:52.263703501 +0200
+@@ -155,11 +155,14 @@
+ #define WHITESPACE " \t\r\n"
+ #define QUOTE	"\""
+ 
++/* Characters considered as quotations. */
++#define QUOTES "'\""
++
+ /* return next token in configuration line */
+ char *
+ strdelim(char **s)
+ {
+-	char *old;
++	char *old, *p, *q;
+ 	int wspace = 0;
+ 
+ 	if (*s == NULL)
+@@ -167,6 +170,21 @@
+ 
+ 	old = *s;
+ 
++	if ((q=strchr(QUOTES, (int) *old)) && *q)
++	{
++		/* find next quote character, point old to start of quoted
++		 * string */
++		for (p = ++old; *p && *p != *q; p++)
++			;
++
++		/* find start of next token */
++		*s = (*p) ? p + strspn(p + 1, WHITESPACE) + 1 : NULL;
++
++		/* terminate 'old' token */
++		*p = '\0';
++		return (old);
++	}
++
+ 	*s = strpbrk(*s, WHITESPACE QUOTE "=");
+ 	if (*s == NULL)
+ 		return (old);
+@@ -219,6 +237,20 @@
+ 	return copy;
+ }
+ 
++void
++pwfree(struct passwd *pw)
++{
++	xfree(pw->pw_name);
++	xfree(pw->pw_passwd);
++	xfree(pw->pw_gecos);
++#ifdef HAVE_PW_CLASS_IN_PASSWD
++	xfree(pw->pw_class);
++#endif
++	xfree(pw->pw_dir);
++	xfree(pw->pw_shell);
++	xfree(pw);
++}
++
+ /*
+  * Convert ASCII string to TCP/IP port number.
+  * Port must be >=0 and <=65535.
+diff -Nur openssh-5.3p1.orig/misc.h openssh-5.3p1/misc.h
+--- openssh-5.3p1.orig/misc.h	2008-06-12 22:42:45.000000000 +0200
++++ openssh-5.3p1/misc.h	2011-08-12 08:53:52.263703501 +0200
+@@ -37,6 +37,7 @@
+ void	 ms_to_timeval(struct timeval *, int);
+ 
+ struct passwd *pwcopy(struct passwd *);
++void pwfree(struct passwd *);
+ const char *ssh_gai_strerror(int);
+ 
+ typedef struct arglist arglist;
+diff -Nur openssh-5.3p1.orig/monitor.c openssh-5.3p1/monitor.c
+--- openssh-5.3p1.orig/monitor.c	2011-08-12 08:52:47.320701689 +0200
++++ openssh-5.3p1/monitor.c	2011-08-12 08:53:52.266703501 +0200
+@@ -179,6 +179,9 @@
+ int mm_answer_gss_userok(int, Buffer *);
+ int mm_answer_gss_checkmic(int, Buffer *);
+ int mm_answer_gss_sign(int, Buffer *);
++int mm_answer_gss_error(int, Buffer *);
++int mm_answer_gss_indicate_mechs(int, Buffer *);
++int mm_answer_gss_localname(int, Buffer *);
+ int mm_answer_gss_updatecreds(int, Buffer *);
+ #endif
+ 
+@@ -224,7 +227,7 @@
+ struct mon_table mon_dispatch_proto20[] = {
+     {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli},
+     {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
+-    {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
++    {MONITOR_REQ_PWNAM, MON_AUTH, mm_answer_pwnamallow},
+     {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
+ #ifdef WITH_SELINUX
+     {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole},
+@@ -232,7 +235,7 @@
+     {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
+     {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
+ #ifdef USE_PAM
+-    {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
++    {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start},
+     {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
+     {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
+     {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
+@@ -262,6 +265,9 @@
+     {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
+     {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
+     {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
++    {MONITOR_REQ_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error},
++    {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs},
++    {MONITOR_REQ_GSSLOCALNAME, MON_ISAUTH, mm_answer_gss_localname},
+ #endif
+ #ifdef JPAKE
+     {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata},
+@@ -278,6 +284,8 @@
+     {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
+     {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
+     {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
++    {MONITOR_REQ_GSSERR, 0, mm_answer_gss_error},
++    {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs},
+     {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
+ #endif
+     {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
+@@ -315,7 +323,7 @@
+     {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond},
+ #endif
+ #ifdef USE_PAM
+-    {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
++    {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start},
+     {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
+     {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
+     {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
+@@ -401,6 +409,8 @@
+ #ifdef GSSAPI
+ 		/* and for the GSSAPI key exchange */
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
++		monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
++		monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1);
+ #endif
+ 	} else {
+ 		mon_dispatch = mon_dispatch_proto15;
+@@ -491,6 +501,8 @@
+ #ifdef GSSAPI
+ 		/* and for the GSSAPI key exchange */
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
++		monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
++		monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1);
+ #endif		
+ 	} else {
+ 		mon_dispatch = mon_dispatch_postauth15;
+@@ -684,14 +696,17 @@
+ 
+ 	debug3("%s", __func__);
+ 
+-	if (authctxt->attempt++ != 0)
+-		fatal("%s: multiple attempts for getpwnam", __func__);
+-
+ 	username = buffer_get_string(m, NULL);
+ 
+ 	pwent = getpwnamallow(username);
+ 
++	if (authctxt->user) xfree(authctxt->user);
+ 	authctxt->user = xstrdup(username);
++#ifdef USE_PAM
++	if (options.permit_pam_user_change)
++		setproctitle("%s [priv]", pwent ? "[pam]" : "unknown");
++	else
++#endif
+ 	setproctitle("%s [priv]", pwent ? username : "unknown");
+ 	xfree(username);
+ 
+@@ -2150,12 +2165,15 @@
+ mm_answer_gss_userok(int sock, Buffer *m)
+ {
+ 	int authenticated;
++	int gssapi_keyex;
+ 
+ 	if (!options.gss_authentication && !options.gss_keyex)
+ 		fatal("In GSSAPI monitor when GSSAPI is disabled");
+ 
++	gssapi_keyex = buffer_get_int(m);
++
+ 	authenticated = authctxt->valid && 
+-	    ssh_gssapi_userok(authctxt->user, authctxt->pw);
++	    ssh_gssapi_userok(authctxt->user, authctxt->pw, gssapi_keyex);
+ 
+ 	buffer_clear(m);
+ 	buffer_put_int(m, authenticated);
+@@ -2163,12 +2181,77 @@
+ 	debug3("%s: sending result %d", __func__, authenticated);
+ 	mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m);
+ 
+-	auth_method = "gssapi-with-mic";
++	if (gssapi_keyex)
++		auth_method = "gssapi-keyex";
++	else
++		auth_method = "gssapi-with-mic";
+ 
+ 	/* Monitor loop will terminate if authenticated */
+ 	return (authenticated);
+ }
+ 
++int
++mm_answer_gss_error(int socket, Buffer *m) {
++	OM_uint32 major, minor;
++	char *msg;
++
++	msg=ssh_gssapi_last_error(gsscontext, &major, &minor);
++	buffer_clear(m);
++	buffer_put_int(m, major);
++	buffer_put_int(m, minor);
++	buffer_put_cstring(m, msg);
++
++	mm_request_send(socket, MONITOR_ANS_GSSERR, m);
++
++	xfree(msg);
++
++	return(0);
++}
++
++int
++mm_answer_gss_indicate_mechs(int socket, Buffer *m) {
++	OM_uint32 major, minor;
++	gss_OID_set mech_set;
++	size_t i;
++
++	major=gss_indicate_mechs(&minor, &mech_set);
++
++	buffer_clear(m);
++	buffer_put_int(m, major);
++	buffer_put_int(m, mech_set->count);
++	for (i = 0; i < mech_set->count; i++) {
++		buffer_put_string(m, mech_set->elements[i].elements,
++				  mech_set->elements[i].length);
++	}
++
++	gss_release_oid_set(&minor, &mech_set);
++
++	mm_request_send(socket, MONITOR_ANS_GSSMECHS, m);
++
++	return(0);
++}
++
++int
++mm_answer_gss_localname(int socket, Buffer *m) {
++	char *name;
++
++	ssh_gssapi_localname(&name);
++
++	buffer_clear(m);
++	if (name) {
++		buffer_put_cstring(m, name);
++		debug3("%s: sending result %s", __func__, name);
++		xfree(name);
++	} else {
++		buffer_put_cstring(m, "");
++		debug3("%s: sending result \"\"", __func__);
++	}
++
++	mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m);
++
++	return(0);
++}
++
+ int 
+ mm_answer_gss_sign(int socket, Buffer *m)
+ {
+diff -Nur openssh-5.3p1.orig/monitor.h openssh-5.3p1/monitor.h
+--- openssh-5.3p1.orig/monitor.h	2011-08-12 08:52:47.321701689 +0200
++++ openssh-5.3p1/monitor.h	2011-08-12 08:53:52.267703501 +0200
+@@ -55,6 +55,9 @@
+ 	MONITOR_REQ_GSSSETUP, MONITOR_ANS_GSSSETUP,
+ 	MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP,
+ 	MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK,
++	MONITOR_REQ_GSSMECHS, MONITOR_ANS_GSSMECHS,
++	MONITOR_REQ_GSSLOCALNAME, MONITOR_ANS_GSSLOCALNAME,
++	MONITOR_REQ_GSSERR, MONITOR_ANS_GSSERR,
+ 	MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC,
+ 	MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN,
+ 	MONITOR_REQ_GSSUPCREDS, MONITOR_ANS_GSSUPCREDS,
+diff -Nur openssh-5.3p1.orig/monitor_wrap.c openssh-5.3p1/monitor_wrap.c
+--- openssh-5.3p1.orig/monitor_wrap.c	2011-08-12 08:52:47.322701689 +0200
++++ openssh-5.3p1/monitor_wrap.c	2011-08-12 08:53:52.268703501 +0200
+@@ -1340,12 +1340,13 @@
+ }
+ 
+ int
+-mm_ssh_gssapi_userok(char *user, struct passwd *pw)
++mm_ssh_gssapi_userok(char *user, struct passwd *pw, int gssapi_keyex)
+ {
+ 	Buffer m;
+ 	int authenticated = 0;
+ 
+ 	buffer_init(&m);
++	buffer_put_int(&m, gssapi_keyex);
+ 
+ 	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m);
+ 	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK,
+@@ -1358,6 +1359,83 @@
+ 	return (authenticated);
+ }
+ 
++char *
++mm_ssh_gssapi_last_error(Gssctxt *ctx, OM_uint32 *major, OM_uint32 *minor) {
++	Buffer m;
++	OM_uint32 maj,min;
++	char *errstr;
++
++	buffer_init(&m);
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSERR, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSERR, &m);
++
++	maj = buffer_get_int(&m);
++	min = buffer_get_int(&m);
++
++	if (major) *major=maj;
++	if (minor) *minor=min;
++
++	errstr=buffer_get_string(&m,NULL);
++
++	buffer_free(&m);
++
++	return(errstr);
++}
++
++OM_uint32
++mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set)
++{
++	Buffer m;
++	OM_uint32 major,minor;
++	int count;
++	gss_OID_desc oid;
++	u_int length;
++
++	buffer_init(&m);
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSMECHS, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSMECHS,
++				  &m);
++	major=buffer_get_int(&m);
++	count=buffer_get_int(&m);
++	
++	gss_create_empty_oid_set(&minor,mech_set);
++	while(count-->0) {
++	    oid.elements=buffer_get_string(&m,&length);
++	    oid.length=length;
++	    gss_add_oid_set_member(&minor,&oid,mech_set);
++	}
++
++	buffer_free(&m);
++	
++	return(major);
++}
++
++int
++mm_ssh_gssapi_localname(char **lname)
++{
++	Buffer m;
++
++	buffer_init(&m);
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, &m);
++
++	debug3("%s: waiting for MONITOR_ANS_GSSLOCALNAME", __func__);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME,
++				  &m);
++
++	*lname = buffer_get_string(&m, NULL);
++
++	buffer_free(&m);
++	if (lname[0] == '\0') {
++	    debug3("%s: gssapi identity mapping failed", __func__);
++	} else {
++	    debug3("%s: gssapi identity mapped to %s", __func__, *lname);
++	}
++
++	return(0);
++}
++
+ OM_uint32
+ mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
+ {
+diff -Nur openssh-5.3p1.orig/monitor_wrap.h openssh-5.3p1/monitor_wrap.h
+--- openssh-5.3p1.orig/monitor_wrap.h	2011-08-12 08:52:47.323701689 +0200
++++ openssh-5.3p1/monitor_wrap.h	2011-08-12 08:53:52.268703501 +0200
+@@ -61,9 +61,13 @@
+ OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
+ OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
+    gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
+-int mm_ssh_gssapi_userok(char *user, struct passwd *);
++int mm_ssh_gssapi_userok(char *user, struct passwd *, int gssapi_keyex);
+ OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
+ OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
++int mm_ssh_gssapi_localname(char **user);
++OM_uint32 mm_gss_indicate_mechs(OM_uint32 *minor_status,
++				gss_OID_set *mech_set);
++char *mm_ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min);
+ int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
+ #endif
+ 
+diff -Nur openssh-5.3p1.orig/readconf.c openssh-5.3p1/readconf.c
+--- openssh-5.3p1.orig/readconf.c	2011-08-12 08:52:47.244701687 +0200
++++ openssh-5.3p1/readconf.c	2011-08-12 08:53:52.269703501 +0200
+@@ -1168,13 +1168,13 @@
+ 	if (options->challenge_response_authentication == -1)
+ 		options->challenge_response_authentication = 1;
+ 	if (options->gss_authentication == -1)
+-		options->gss_authentication = 0;
++		options->gss_authentication = 1;
+ 	if (options->gss_keyex == -1)
+-		options->gss_keyex = 0;
++		options->gss_keyex = 1;
+ 	if (options->gss_deleg_creds == -1)
+-		options->gss_deleg_creds = 0;
++		options->gss_deleg_creds = 1;
+ 	if (options->gss_trust_dns == -1)
+-		options->gss_trust_dns = 0;
++		options->gss_trust_dns = 1;
+ 	if (options->gss_renewal_rekey == -1)
+ 		options->gss_renewal_rekey = 0;
+ 	if (options->password_authentication == -1)
+diff -Nur openssh-5.3p1.orig/readconf.h openssh-5.3p1/readconf.h
+--- openssh-5.3p1.orig/readconf.h	2011-08-12 08:52:47.245701687 +0200
++++ openssh-5.3p1/readconf.h	2011-08-12 08:53:52.269703501 +0200
+@@ -80,6 +80,8 @@
+ 	char   *host_key_alias;	/* hostname alias for .ssh/known_hosts */
+ 	char   *proxy_command;	/* Proxy command for connecting the host. */
+ 	char   *user;		/* User to log in as. */
++	int     implicit;	/* Login user was not specified.
++				   Server may choose based on authctxt. */
+ 	int     escape_char;	/* Escape character; -2 = none */
+ 
+ 	char   *system_hostfile;/* Path for /etc/ssh/ssh_known_hosts. */
+diff -Nur openssh-5.3p1.orig/servconf.c openssh-5.3p1/servconf.c
+--- openssh-5.3p1.orig/servconf.c	2011-08-12 08:52:47.341701691 +0200
++++ openssh-5.3p1/servconf.c	2011-08-12 08:53:52.271703501 +0200
+@@ -58,6 +58,7 @@
+ 
+ 	/* Portable-specific options */
+ 	options->use_pam = -1;
++	options->permit_pam_user_change = -1;
+ 
+ 	/* Standard Options */
+ 	options->num_ports = 0;
+@@ -92,9 +93,11 @@
+ 	options->kerberos_ticket_cleanup = -1;
+ 	options->kerberos_get_afs_token = -1;
+ 	options->gss_authentication=-1;
++	options->gss_deleg_creds = -1;
+ 	options->gss_keyex = -1;
+ 	options->gss_cleanup_creds = -1;
+ 	options->gss_strict_acceptor = -1;
++	options->gsi_allow_limited_proxy = -1;
+ 	options->gss_store_rekey = -1;
+ 	options->password_authentication = -1;
+ 	options->kbd_interactive_authentication = -1;
+@@ -135,6 +138,8 @@
+ 	options->authorized_keys_command_runas = NULL;
+ 	options->zero_knowledge_password_authentication = -1;
+ 	options->use_kuserok = -1;
++	options->disable_usage_stats = 0;
++	options->usage_stats_targets = NULL;
+ }
+ 
+ void
+@@ -143,6 +148,8 @@
+ 	/* Portable-specific options */
+ 	if (options->use_pam == -1)
+ 		options->use_pam = 0;
++	if (options->permit_pam_user_change == -1)
++		options->permit_pam_user_change = 0;
+ 
+ 	/* Standard Options */
+ 	if (options->protocol == SSH_PROTO_UNKNOWN)
+@@ -216,13 +223,17 @@
+ 	if (options->kerberos_get_afs_token == -1)
+ 		options->kerberos_get_afs_token = 0;
+ 	if (options->gss_authentication == -1)
+-		options->gss_authentication = 0;
++		options->gss_authentication = 1;
++	if (options->gss_deleg_creds == -1)
++		options->gss_deleg_creds = 1;
+ 	if (options->gss_keyex == -1)
+-		options->gss_keyex = 0;
++		options->gss_keyex = 1;
+ 	if (options->gss_cleanup_creds == -1)
+ 		options->gss_cleanup_creds = 1;
+ 	if (options->gss_strict_acceptor == -1)
+ 		options->gss_strict_acceptor = 1;
++	if (options->gsi_allow_limited_proxy == -1)
++		options->gsi_allow_limited_proxy = 0;
+ 	if (options->gss_store_rekey == -1)
+ 		options->gss_store_rekey = 0;
+ 	if (options->password_authentication == -1)
+@@ -299,7 +310,7 @@
+ typedef enum {
+ 	sBadOption,		/* == unknown option */
+ 	/* Portable-specific options */
+-	sUsePAM,
++	sUsePAM, sPermitPAMUserChange,
+ 	/* Standard Options */
+ 	sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
+ 	sPermitRootLogin, sLogFacility, sLogLevel,
+@@ -320,11 +331,15 @@
+ 	sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication,
+ 	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
+ 	sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
++	sGssDelegateCreds,
++	sGssCredsPath,
++	sGsiAllowLimitedProxy,
+ 	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
+ 	sGssKeyEx, sGssStoreRekey,
+ 	sAcceptEnv, sPermitTunnel,
+ 	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
+ 	sUsePrivilegeSeparation, sAllowAgentForwarding,
++	sDisUsageStats, sUsageStatsTarg,
+ 	sZeroKnowledgePasswordAuthentication,
+ 	sAuthorizedKeysCommand, sAuthorizedKeysCommandRunAs,
+ 	sDeprecated, sUnsupported
+@@ -343,8 +358,10 @@
+ 	/* Portable-specific options */
+ #ifdef USE_PAM
+ 	{ "usepam", sUsePAM, SSHCFG_GLOBAL },
++	{ "permitpamuserchange", sPermitPAMUserChange, SSHCFG_GLOBAL },
+ #else
+ 	{ "usepam", sUnsupported, SSHCFG_GLOBAL },
++	{ "permitpamuserchange", sUnsupported, SSHCFG_GLOBAL },
+ #endif
+ 	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
+ 	/* Standard Options */
+@@ -386,13 +403,23 @@
+ 	{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
+ #ifdef GSSAPI
+ 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
++	{ "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_ALL },
+ 	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
++	{ "gssapicredentialspath", sGssCredsPath, SSHCFG_GLOBAL },
++#ifdef GSI
++	{ "gsiallowlimitedproxy", sGsiAllowLimitedProxy, SSHCFG_GLOBAL },
++#else
++	{ "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL },
++#endif
+ 	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
+ 	{ "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
+ 	{ "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
+ #else
+ 	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
++	{ "gssapidelegatecredentials", sUnsupported, SSHCFG_ALL },
+ 	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
++	{ "gssapicredentialspath", sUnsupported, SSHCFG_GLOBAL },
++	{ "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL },
+ 	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
+ 	{ "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
+ 	{ "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
+@@ -454,6 +481,8 @@
+ 	{ "permitopen", sPermitOpen, SSHCFG_ALL },
+ 	{ "forcecommand", sForceCommand, SSHCFG_ALL },
+ 	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
++	{ "disableusagestats", sDisUsageStats, SSHCFG_GLOBAL},
++	{ "usagestatstargets", sUsageStatsTarg, SSHCFG_GLOBAL},
+ #ifdef WITH_AUTHORIZED_KEYS_COMMAND
+ 	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
+ 	{ "authorizedkeyscommandrunas", sAuthorizedKeysCommandRunAs, SSHCFG_ALL },
+@@ -718,6 +747,10 @@
+ 		intptr = &options->use_pam;
+ 		goto parse_flag;
+ 
++	case sPermitPAMUserChange:
++		intptr = &options->permit_pam_user_change;
++		goto parse_flag;
++
+ 	/* Standard Options */
+ 	case sBadOption:
+ 		return -1;
+@@ -928,6 +961,10 @@
+ 		intptr = &options->gss_authentication;
+ 		goto parse_flag;
+ 
++	case sGssDelegateCreds:
++		intptr = &options->gss_deleg_creds;
++		goto parse_flag;
++
+ 	case sGssKeyEx:
+ 		intptr = &options->gss_keyex;
+ 		goto parse_flag;
+@@ -936,6 +973,10 @@
+ 		intptr = &options->gss_cleanup_creds;
+ 		goto parse_flag;
+ 
++	case sGssCredsPath:
++		charptr = &options->gss_creds_path;
++		goto parse_filename;
++
+ 	case sGssStrictAcceptor:
+ 		intptr = &options->gss_strict_acceptor;
+ 		goto parse_flag;
+@@ -944,6 +985,12 @@
+ 		intptr = &options->gss_store_rekey;
+ 		goto parse_flag;
+ 
++#ifdef GSI
++	case sGsiAllowLimitedProxy:
++		intptr = &options->gsi_allow_limited_proxy;
++		goto parse_flag;
++#endif
++
+ 	case sPasswordAuthentication:
+ 		intptr = &options->password_authentication;
+ 		goto parse_flag;
+@@ -1361,6 +1408,18 @@
+ 			*charptr = xstrdup(arg);
+ 		break;
+ 
++	case sDisUsageStats:
++		intptr = &options->disable_usage_stats;
++		goto parse_flag;
++
++	case sUsageStatsTarg:
++		arg = strdelim(&cp);
++		if (!arg || *arg == '\0')
++			fatal("%s line %d: missing value.",
++			    filename, linenum);
++		options->usage_stats_targets = xstrdup(arg);
++		break;
++
+ 	case sAuthorizedKeysCommand:
+ 		len = strspn(cp, WHITESPACE);
+ 		if (*activep && options->authorized_keys_command == NULL)
+@@ -1466,6 +1525,7 @@
+ {
+ 	M_CP_INTOPT(password_authentication);
+ 	M_CP_INTOPT(gss_authentication);
++	M_CP_INTOPT(gss_deleg_creds);
+ 	M_CP_INTOPT(rsa_authentication);
+ 	M_CP_INTOPT(pubkey_authentication);
+ 	M_CP_STROPT(authorized_keys_command);
+diff -Nur openssh-5.3p1.orig/servconf.h openssh-5.3p1/servconf.h
+--- openssh-5.3p1.orig/servconf.h	2011-08-12 08:52:47.344701691 +0200
++++ openssh-5.3p1/servconf.h	2011-08-12 08:53:52.272703501 +0200
+@@ -90,9 +90,12 @@
+ 						 * file on logout. */
+ 	int     kerberos_get_afs_token;		/* If true, try to get AFS token if
+ 						 * authenticated with Kerberos. */
++	int     gsi_allow_limited_proxy;	/* If true, accept limited proxies */
+ 	int     gss_authentication;	/* If true, permit GSSAPI authentication */
++	int     gss_deleg_creds;	/* If true, store delegated GSSAPI credentials*/
+ 	int     gss_keyex;		/* If true, permit GSSAPI key exchange */
+ 	int     gss_cleanup_creds;	/* If true, destroy cred cache on logout */
++	char   *gss_creds_path;		/* Use non-default credentials path */
+ 	int 	gss_strict_acceptor;	/* If true, restrict the GSSAPI acceptor name */
+ 	int 	gss_store_rekey;
+ 	int     password_authentication;	/* If true, permit password
+@@ -149,6 +152,7 @@
+ 	char   *adm_forced_command;
+ 
+ 	int	use_pam;		/* Enable auth via PAM */
++	int	permit_pam_user_change;	/* Allow PAM to change user name */
+ 
+ 	int	permit_tun;
+ 
+@@ -156,6 +160,10 @@
+ 	int	use_kuserok;
+ 
+ 	char   *chroot_directory;
++
++	int	disable_usage_stats;
++	char   *usage_stats_targets;
++
+ 	char   *authorized_keys_command;
+ 	char   *authorized_keys_command_runas;
+ }       ServerOptions;
+diff -Nur openssh-5.3p1.orig/ssh.1 openssh-5.3p1/ssh.1
+--- openssh-5.3p1.orig/ssh.1	2011-08-12 08:52:47.405701693 +0200
++++ openssh-5.3p1/ssh.1	2011-08-12 08:53:52.273703501 +0200
+@@ -1238,6 +1238,18 @@
+ on to new connections).
+ .It Ev USER
+ Set to the name of the user logging in.
++.It Ev X509_CERT_DIR
++Used for GSI authentication. Specifies a non-standard location for the
++CA certificates directory.
++.It Ev X509_USER_CERT
++Used for GSI authentication. Specifies a non-standard location for the
++certificate to be used for authentication to the server.
++.It Ev X509_USER_KEY
++Used for GSI authentication. Specifies a non-standard location for the
++private key to be used for authentication to the server.
++.It Ev X509_USER_PROXY
++Used for GSI authentication. Specifies a non-standard location for the
++proxy credential to be used for authentication to the server.
+ .El
+ .Pp
+ Additionally,
+diff -Nur openssh-5.3p1.orig/ssh.c openssh-5.3p1/ssh.c
+--- openssh-5.3p1.orig/ssh.c	2011-08-12 08:52:47.213701687 +0200
++++ openssh-5.3p1/ssh.c	2011-08-12 08:53:52.274703501 +0200
+@@ -627,6 +627,32 @@
+ 			fatal("Can't open user config file %.100s: "
+ 			    "%.100s", config, strerror(errno));
+ 	} else {
++	    /*
++	     * Since the config file parsing code aborts if it sees
++	     * options it doesn't recognize, allow users to put
++	     * options specific to compile-time add-ons in alternate
++	     * config files so their primary config file will
++	     * interoperate SSH versions that don't support those
++	     * options.
++	     */
++#ifdef GSSAPI
++		r = snprintf(buf, sizeof buf, "%s/%s.gssapi", pw->pw_dir,
++		    _PATH_SSH_USER_CONFFILE);
++		if (r > 0 && (size_t)r < sizeof(buf))
++			(void)read_config_file(buf, host, &options, 1);
++#ifdef GSI
++		r = snprintf(buf, sizeof buf, "%s/%s.gsi", pw->pw_dir,
++		    _PATH_SSH_USER_CONFFILE);
++		if (r > 0 && (size_t)r < sizeof(buf))
++			(void)read_config_file(buf, host, &options, 1);
++#endif
++#if defined(KRB5)
++		r = snprintf(buf, sizeof buf, "%s/%s.krb", pw->pw_dir,
++		    _PATH_SSH_USER_CONFFILE);
++		if (r > 0 && (size_t)r < sizeof(buf))
++			(void)read_config_file(buf, host, &options, 1);
++#endif
++#endif
+ 		r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
+ 		    _PATH_SSH_USER_CONFFILE);
+ 		if (r > 0 && (size_t)r < sizeof(buf))
+@@ -651,8 +677,12 @@
+ 		logit("FIPS mode initialized");
+ 	}
+ 
+-	if (options.user == NULL)
++	if (options.user == NULL) {
+ 		options.user = xstrdup(pw->pw_name);
++		options.implicit = 1;
++	} else {
++		options.implicit = 0;
++	}
+ 
+ 	/* Get default port if port has not been set. */
+ 	if (options.port == 0) {
+diff -Nur openssh-5.3p1.orig/ssh_config openssh-5.3p1/ssh_config
+--- openssh-5.3p1.orig/ssh_config	2011-08-12 08:52:47.251701687 +0200
++++ openssh-5.3p1/ssh_config	2011-08-12 08:53:52.275703501 +0200
+@@ -24,10 +24,10 @@
+ #   RSAAuthentication yes
+ #   PasswordAuthentication yes
+ #   HostbasedAuthentication no
+-#   GSSAPIAuthentication no
+-#   GSSAPIDelegateCredentials no
+-#   GSSAPIKeyExchange no
+-#   GSSAPITrustDNS no
++#   GSSAPIAuthentication yes
++#   GSSAPIDelegateCredentials yes
++#   GSSAPIKeyExchange yes
++#   GSSAPITrustDNS yes
+ #   BatchMode no
+ #   CheckHostIP yes
+ #   AddressFamily any
+diff -Nur openssh-5.3p1.orig/ssh_config.5 openssh-5.3p1/ssh_config.5
+--- openssh-5.3p1.orig/ssh_config.5	2011-08-12 08:52:47.250701687 +0200
++++ openssh-5.3p1/ssh_config.5	2011-08-12 08:53:52.275703501 +0200
+@@ -56,6 +56,12 @@
+ user's configuration file
+ .Pq Pa ~/.ssh/config
+ .It
++GSSAPI configuration file
++.Pq Pa $HOME/.ssh/config.gssapi
++.It
++Kerberos configuration file
++.Pq Pa $HOME/.ssh/config.krb
++.It
+ system-wide configuration file
+ .Pq Pa /etc/ssh/ssh_config
+ .El
+diff -Nur openssh-5.3p1.orig/sshconnect2.c openssh-5.3p1/sshconnect2.c
+--- openssh-5.3p1.orig/sshconnect2.c	2011-08-12 08:52:47.253701687 +0200
++++ openssh-5.3p1/sshconnect2.c	2011-08-12 08:53:52.277703501 +0200
+@@ -615,6 +615,11 @@
+ 	const char* canonicalhost = get_canonical_hostname(1);
+ 	const char *gss_host;
+ 
++	if (!options.gss_authentication) {
++		verbose("GSSAPI authentication disabled.");
++		return 0;
++	}
++
+ 	if ( strcmp( canonicalhost, "UNKNOWN" )  == 0 )
+ 		remotehost = authctxt->host;
+ 	else
+@@ -850,6 +855,15 @@
+ 	xfree(lang);
+ }
+ 
++#ifdef GSI
++extern
++const gss_OID_desc * const gss_mech_globus_gssapi_openssl;
++#define is_gsi_oid(oid) \
++  (oid->length == gss_mech_globus_gssapi_openssl->length && \
++   (memcmp(oid->elements, gss_mech_globus_gssapi_openssl->elements, \
++	   oid->length) == 0))
++#endif
++
+ int
+ userauth_gsskeyex(Authctxt *authctxt)
+ {
+@@ -867,8 +881,16 @@
+ 		return (0);
+ 	}
+ 
++#ifdef GSI
++	if (options.implicit && is_gsi_oid(gss_kex_context->oid)) {
++		ssh_gssapi_buildmic(&b, "", authctxt->service, "gssapi-keyex");
++	} else {
++#endif
+ 	ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
+ 	    "gssapi-keyex");
++#ifdef GSI
++	}
++#endif
+ 
+ 	gssbuf.value = buffer_ptr(&b);
+ 	gssbuf.length = buffer_len(&b);
+@@ -879,7 +901,15 @@
+ 	}
+ 
+ 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
++#ifdef GSI
++	if (options.implicit && is_gsi_oid(gss_kex_context->oid)) {
++		packet_put_cstring("");
++	} else {
++#endif
+ 	packet_put_cstring(authctxt->server_user);
++#ifdef GSI
++	}
++#endif
+ 	packet_put_cstring(authctxt->service);
+ 	packet_put_cstring(authctxt->method->name);
+ 	packet_put_string(mic.value, mic.length);
+diff -Nur openssh-5.3p1.orig/sshd.8 openssh-5.3p1/sshd.8
+--- openssh-5.3p1.orig/sshd.8	2011-08-12 08:52:47.407701693 +0200
++++ openssh-5.3p1/sshd.8	2011-08-12 08:53:52.278703501 +0200
+@@ -682,6 +682,43 @@
+ |1|JfKTdBh7rNbXkVAQCRp4OQoPfmI=|USECr3SWf1JUPsms5AqfD5QfxkM= ssh-rsa
+ AAAA1234.....=
+ .Ed
++.Sh ENVIRONMENT
++.Nm
++will normally set the following environment variables:
++.Bl -tag -width "SSH_ORIGINAL_COMMAND"
++.It Ev GLOBUS_USAGE_OPTOUT
++Setting this environment variable to "1" will disable the reporting
++of usage metrics. Usage metrics can also be disabled using the
++.Cm DisableUsageStats
++setting in
++.Xr sshd_config 5 .
++.It Ev GLOBUS_USAGE_TARGETS
++If
++.Cm UsageStatsTargets
++is not specified in
++.Xr sshd_config 5 ,
++a comma-separated list of targets (without any tags specified) if
++specified in the environment variable
++.Ev GLOBUS_USAGE_TARGETS
++will be used.
++.It Ev GRIDMAP
++Applies to GSI authentication/authorization. Specifies the location of the
++gridmapfile. If not specified, the gridmap file is assumed to be available at
++/etc/grid-security/grid-mapfile for services running as root and at
++HOME/.gridmap for services running as non-root where HOME is the home directory
++of the effective user from the password file entry.
++.It Ev X509_CERT_DIR
++Used for GSI authentication. Specifies a non-standard location for the
++CA certificates directory.
++.It Ev X509_USER_CERT
++Used for GSI authentication. Specifies a non-standard location for the
++certificate to be used for authentication to the client.
++.It Ev X509_USER_KEY
++Used for GSI authentication. Specifies a non-standard location for the
++private key to be used for authentication to the client.
++.It Ev X509_USER_PROXY
++Used for GSI authentication. Specifies a non-standard location for the
++proxy credential to be used for authentication to the client.
+ .Sh FILES
+ .Bl -tag -width Ds -compact
+ .It ~/.hushlogin
+diff -Nur openssh-5.3p1.orig/sshd.c openssh-5.3p1/sshd.c
+--- openssh-5.3p1.orig/sshd.c	2011-08-12 08:52:47.414701693 +0200
++++ openssh-5.3p1/sshd.c	2011-08-12 08:53:52.281703501 +0200
+@@ -122,6 +122,7 @@
+ #include "roaming.h"
+ #include "audit.h"
+ #include "version.h"
++#include "ssh-globus-usage.h"
+ 
+ #ifdef LIBWRAP
+ #include <tcpd.h>
+@@ -1543,6 +1544,13 @@
+ 	/* Fill in default values for those options not explicitly set. */
+ 	fill_default_server_options(&options);
+ 
++#ifdef HAVE_GLOBUS_USAGE
++	if (ssh_usage_stats_init(options.disable_usage_stats,
++			options.usage_stats_targets) != GLOBUS_SUCCESS) {
++		error("Error initializing Globus Usage Metrics, but continuing ...");
++	}
++#endif /* HAVE_GLOBUS_USAGE */
++
+ 	/* challenge-response is implemented via keyboard interactive */
+ 	if (options.challenge_response_authentication)
+ 		options.kbd_interactive_authentication = 1;
+@@ -2032,7 +2040,7 @@
+ #endif
+ 
+ #ifdef GSSAPI
+-	if (options.gss_authentication) {
++	if (options.gss_authentication && options.gss_deleg_creds) {
+ 		temporarily_use_uid(authctxt->pw);
+ 		ssh_gssapi_storecreds();
+ 		restore_uid();
+diff -Nur openssh-5.3p1.orig/sshd_config openssh-5.3p1/sshd_config
+--- openssh-5.3p1.orig/sshd_config	2011-08-12 08:52:47.346701691 +0200
++++ openssh-5.3p1/sshd_config	2011-08-12 08:53:52.281703501 +0200
+@@ -77,12 +77,11 @@
+ #KerberosUseKuserok yes
+ 
+ # GSSAPI options
+-#GSSAPIAuthentication no
+-GSSAPIAuthentication yes
++#GSSAPIAuthentication yes
++#GSSAPIDelegateCredentials yes
+ #GSSAPICleanupCredentials yes
+-GSSAPICleanupCredentials yes
+ #GSSAPIStrictAcceptorCheck yes
+-#GSSAPIKeyExchange no
++#GSSAPIKeyExchange yes
+ 
+ # Set this to 'yes' to enable PAM authentication, account processing, 
+ # and session processing. If this is enabled, PAM authentication will 
+@@ -102,6 +101,10 @@
+ AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
+ AcceptEnv XMODIFIERS
+ 
++# Set to 'yes' to allow the PAM stack to change the user name during
++# calls to authentication
++#PermitPAMUserChange no
++
+ #AllowAgentForwarding yes
+ #AllowTcpForwarding yes
+ #GatewayPorts no
+@@ -136,3 +139,7 @@
+ #	X11Forwarding no
+ #	AllowTcpForwarding no
+ #	ForceCommand cvs server
++
++# Usage Metrics
++#UsageStatsTargets usage-stats.cilogon.org:4810
++#DisableUsageStats no
+diff -Nur openssh-5.3p1.orig/sshd_config.5 openssh-5.3p1/sshd_config.5
+--- openssh-5.3p1.orig/sshd_config.5	2011-08-12 08:52:47.345701691 +0200
++++ openssh-5.3p1/sshd_config.5	2011-08-12 08:53:52.283703501 +0200
+@@ -335,6 +335,15 @@
+ in
+ .Xr ssh_config 5
+ for more information on patterns.
++.It Cm DisableUsageStats
++This keyword can be followed by the keyword "yes" to disable reporting of
++usage metrics. Or it can be set to "no" to enable reporting of usage metrics,
++which is the default. Setting the
++.Cm GLOBUS_USAGE_OPTOUT
++environment variable to "1" will also disable the reporting of usage metrics.
++Disabling reporting of usage metrics will cause the
++.Cm UsageStatsTargets
++setting to be ignored.
+ .It Cm ForceCommand
+ Forces the execution of the command specified by
+ .Cm ForceCommand ,
+@@ -379,6 +388,10 @@
+ The default is
+ .Dq no .
+ Note that this option applies to protocol version 2 only.
++.It Cm GSSAPIDelegateCredentials
++Specifies whether delegated credentials are stored in the user's environment.
++The default is
++.Dq yes .
+ .It Cm GSSAPIKeyExchange
+ Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
+ doesn't rely on ssh keys to verify host identity.
+@@ -391,6 +404,22 @@
+ The default is
+ .Dq yes .
+ Note that this option applies to protocol version 2 only.
++.It Cm GSSAPICredentialsPath
++If specified, the delegated GSSAPI credential is stored in the
++given path, overwriting any existing credentials.  
++Paths can be specified with syntax similar to the AuthorizedKeysFile 
++option (i.e., accepting %h and %u tokens).  
++When using this option,
++setting 'GssapiCleanupCredentials no' is recommended,
++so logging out of one session
++doesn't remove the credentials in use by another session of
++the same user.
++Currently only implemented for the GSI mechanism.
++.It Cm GSIAllowLimitedProxy
++Specifies whether to accept limited proxy credentials for
++authentication.
++The default is
++.Dq no .
+ .It Cm GSSAPIStrictAcceptorCheck
+ Determines whether to be strict about the identity of the GSSAPI acceptor 
+ a client authenticates against. If
+@@ -935,6 +964,121 @@
+ .Pp
+ To disable TCP keepalive messages, the value should be set to
+ .Dq no .
++.It Cm UsageStatsTargets
++This option can be used to specify the target collector hosts to which usage
++metrics should be reported. This setting will be ignored if
++.Cm DisableUsageStats
++is enabled. Multiple targets can be specified separated by comma(s), but no
++space(s). Each target specification is of the format
++.Pa host:port[!tags].
++Tags control what data elements are reported. The following list specifies
++the tags for the corresponding data elements.
++.Pp
++.Bl -item -offset indent -compact
++.It
++.Cm V
++.Sm off
++- OpenSSH version, reported by default.
++.Sm on
++.It
++.Cm v
++.Sm off
++- SSL version, reported by default.
++.Sm on
++.It
++.Cm M
++.Sm off
++- User authentication method used such as "gssapi-keyex", "gssapi-with-mic", etc. Reported by default.
++.Sm on
++.It
++.Cm m
++.Sm off
++- User authentication mechanism used such as "GSI", "Kerberos", etc. Reported by default.
++.Sm on
++.It
++.Cm I
++.Sm off
++- Client IP address. Not reported by default.
++.Sm on
++.It
++.Cm u
++.Sm off
++- User name. Not reported by default.
++.Sm on
++.It
++.Cm U
++.Sm off
++- User DN. Not reported by default.
++.Sm on
++.Pp
++In addition to the above selected information, the following data are
++reported to ALL the specified/default target collectors. There's no way to
++exclude these from being reported other than by disabling the reporting of
++usage metrics altogether:
++.Pp
++.It
++.Cm Component code
++.Sm off
++- 12 for GSI OpenSSH
++.Sm on
++.It
++.Cm Component Data Format version
++.Sm off
++- 0 currently
++.Sm on
++.It
++.Cm IP Address
++.Sm off
++- IP address of reporting server
++.Sm on
++.It
++.Cm Timestamp
++.It
++.Cm Hostname
++.Sm off
++- Host name of reporting server
++.Sm on
++.Pp
++If no tags are specified in a host spec, or the special string
++.Dq default
++is specified, the tags
++.Dq VvMm
++are assumed. A site could choose to allow a
++different set of data to be reported by specifying a different tag set. The
++last 3 tags
++.Dq I ,
++.Dq u
++and
++.Dq U
++above are more meant for a local collector that a
++site might like to deploy since they could be construed as private information.
++The special string
++.Dq all
++denotes all tags.
++.El
++.Pp
++By default, Usage Metrics reporting is sent to
++.Dq usage-stats.cilogon.org:4810 .
++This can be made explicit by specifying
++.Dq default
++(all by itself) for the
++target specification as in:
++.Pp
++.Bl -item -offset indent -compact
++.It
++.Cm UsageStatsTargets
++.Sm off
++default
++.Sm on
++.El
++.Pp
++If
++.Cm UsageStatsTargets
++is not specified, a comma-separated list of targets
++(without any tags specified) if specified in the environment variable
++.Cm GLOBUS_USAGE_TARGETS
++will be used.
++.Pp
+ .It Cm UseDNS
+ Specifies whether
+ .Xr sshd 8
+@@ -986,6 +1130,12 @@
+ as a non-root user.
+ The default is
+ .Dq no .
++.It Cm PermitPAMUserChange
++If set to
++.Dq yes
++this will enable PAM authentication to change the name of the user being
++authenticated.  The default is
++.Dq no .
+ .It Cm UsePrivilegeSeparation
+ Specifies whether
+ .Xr sshd 8
+diff -Nur openssh-5.3p1.orig/ssh-globus-usage.c openssh-5.3p1/ssh-globus-usage.c
+--- openssh-5.3p1.orig/ssh-globus-usage.c	1970-01-01 01:00:00.000000000 +0100
++++ openssh-5.3p1/ssh-globus-usage.c	2011-08-12 08:53:52.284703501 +0200
+@@ -0,0 +1,389 @@
++/*
++ * Copyright 2009 The Board of Trustees of the University
++ * of Illinois.  See the LICENSE file for detailed license information.
++ *
++ * Portions, specifically log_usage_stats(), ssh_usage_stats_init(),
++ * ssh_usage_stats_close(), ssh_usage_ent_s, ssh_usage_tag_e and
++ * TAG #defines were based on those from Usage Metrics portions of:
++ * gridftp/server/source/globus_i_gfs_log.c
++ *
++ * Copyright 1999-2006 University of Chicago
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdarg.h>
++
++#include "log.h"
++#include "ssh-globus-usage.h"
++
++#ifdef HAVE_GLOBUS_USAGE
++
++static globus_list_t *usage_handle_list = NULL;
++
++#define SSH_GLOBUS_USAGE_ID 12
++#define SSH_GLOBUS_USAGE_VER 0
++
++#define SSH_GLOBUS_DEFAULT_TAGLIST "VvMm"
++#define SSH_GLOBUS_ALL_TAGLIST     "VvMmIuU"
++#define SSH_GLOBUS_TAGCOUNT 25
++
++typedef enum ssh_usage_tag_e
++{
++    SSH_GLOBUS_USAGE_SSH_VER        = 'V',
++    SSH_GLOBUS_USAGE_SSL_VER        = 'v',
++    SSH_GLOBUS_USAGE_METHOD         = 'M',
++    SSH_GLOBUS_USAGE_MECHANISM      = 'm',
++    SSH_GLOBUS_USAGE_CLIENTIP       = 'I',
++    SSH_GLOBUS_USAGE_USERNAME       = 'u',
++    SSH_GLOBUS_USAGE_USERDN         = 'U'
++    /* !! ADD to ALL_TAGLIST above and to globus_usage_stats_send()
++          invocation below when adding here */
++} ssh_usage_tag_t;
++
++typedef struct ssh_usage_ent_s
++{
++    globus_usage_stats_handle_t         handle;
++    char *                              target;
++    char *                              taglist;
++} ssh_usage_ent_t;
++
++
++globus_result_t
++ssh_usage_stats_init(int disable_usage_stats, char *usage_stats_targets)
++{
++    globus_result_t                     result;
++    char *                              target_str = NULL;
++    char *                              ptr = ptr;
++    char *                              target = NULL;
++    char *                              entry = NULL;
++    globus_list_t *                     list = NULL;
++    ssh_usage_ent_t *               usage_ent = NULL;
++
++    if (disable_usage_stats)
++	return GLOBUS_SUCCESS;
++
++    result = globus_module_activate(GLOBUS_USAGE_MODULE);
++    if (result != GLOBUS_SUCCESS)
++    {
++        error("ERROR: couldn't activate USAGE module");
++        return result;
++    }
++
++    if (!usage_stats_targets ||
++        !strcasecmp(usage_stats_targets, "default"))
++        target_str = strdup(CILOGON_COLLECTOR);
++    else
++        target_str = strdup(usage_stats_targets);
++
++    if (target_str == NULL)
++    {
++        error("ERROR: strdup failure for target_str");
++        goto error;
++    }
++    debug("Processing usage_stats_target (%s)\n", target_str);
++
++    if(target_str && (strchr(target_str, ',') || strchr(target_str, '!')))
++    {
++        target = target_str;
++
++        do {
++            usage_ent = (ssh_usage_ent_t *) malloc(sizeof(ssh_usage_ent_t));
++            if (usage_ent == NULL)
++            {
++                error("ERROR: couldn't allocate for ssh_usage_ent_t");
++                goto error;
++            }
++
++            if ((ptr = strchr(target, ',')) != NULL)
++                *ptr = '\0';
++
++            entry = strdup(target);
++            if (entry == NULL)
++            {
++                error("ERROR: strdup failure for target");
++                goto error;
++            }
++
++            if (ptr)
++                target = ptr + 1;
++            else
++                target = NULL;
++
++            if((ptr = strchr(entry, '!')) != NULL)
++            {
++                *ptr = '\0';
++                usage_ent->taglist = strdup(ptr + 1);
++                if (usage_ent->taglist == NULL)
++                {
++                    error("ERROR: strdup failure for taglist");
++                    goto error;
++                }
++                if(strlen(usage_ent->taglist) > SSH_GLOBUS_TAGCOUNT)
++                {
++                    usage_ent->taglist[SSH_GLOBUS_TAGCOUNT + 1] = '\0';
++                }
++            }
++            else
++            {
++                usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST);
++                if (usage_ent->taglist == NULL)
++                {
++                    error("ERROR: couldn't allocate for taglist");
++                    goto error;
++                }
++            }
++            
++            if(strcasecmp(usage_ent->taglist, "default") == 0)
++            {
++                free(usage_ent->taglist);
++                usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST);
++                if (usage_ent->taglist == NULL)
++                {
++                    error("ERROR: couldn't allocate for taglist");
++                    goto error;
++                }
++            }                
++            else if(strcasecmp(usage_ent->taglist, "all") == 0)
++            {
++                free(usage_ent->taglist);
++                usage_ent->taglist = strdup(SSH_GLOBUS_ALL_TAGLIST);
++                if (usage_ent->taglist == NULL)
++                {
++                    error("ERROR: couldn't allocate for taglist");
++                    goto error;
++                }
++            }
++            
++            usage_ent->target = entry;
++
++            globus_list_insert(&usage_handle_list, usage_ent);
++        }
++        while(target != NULL);
++
++        free(target_str);
++    }
++    else
++    {
++        usage_ent = (ssh_usage_ent_t *) malloc(sizeof(ssh_usage_ent_t));
++        if (usage_ent == NULL)
++        {
++             error("ERROR: couldn't allocate for usage_ent");
++             goto error;
++        }
++
++        usage_ent->target = target_str;
++        usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST);
++        if (usage_ent->taglist == NULL)
++        {
++             error("ERROR: couldn't allocate for taglist");
++             goto error;
++        }
++
++        globus_list_insert(&usage_handle_list, usage_ent);
++    }
++
++    result = GLOBUS_SUCCESS;
++    for(list = usage_handle_list;
++        !globus_list_empty(list);
++        list = globus_list_rest(list))
++    {
++        usage_ent = (ssh_usage_ent_t *) globus_list_first(list);
++
++        usage_ent->handle = NULL;
++        debug("USAGE: Initializing (%s) (%s)", usage_ent->target?:"NULL",
++                     usage_ent->taglist?:"NULL");
++        if (globus_usage_stats_handle_init(
++            &usage_ent->handle,
++            SSH_GLOBUS_USAGE_ID,
++            SSH_GLOBUS_USAGE_VER,
++            usage_ent->target) != GLOBUS_SUCCESS)
++        {
++            result = GLOBUS_FAILURE;
++        }
++    }
++
++    return result;
++
++error:
++    if (target_str)
++    {
++        free(target_str); 
++        target_str = NULL;
++    }
++    if (entry)
++    {
++        free(target_str); 
++        target_str = NULL;
++    }
++    return GLOBUS_FAILURE;
++}
++
++void
++ssh_usage_stats_close(int disable_usage_stats)
++{
++    globus_list_t *list;
++
++    if (disable_usage_stats)
++	return;
++
++    list = usage_handle_list;
++    
++    while(!globus_list_empty(list))
++    {
++        ssh_usage_ent_t *usage_ent;
++        
++        usage_ent = (ssh_usage_ent_t *) 
++            globus_list_remove(&list, list);
++    
++        if(usage_ent)
++        {
++            if(usage_ent->handle)
++            {
++                globus_usage_stats_handle_destroy(usage_ent->handle);
++            }
++            if(usage_ent->target)
++            {
++                free(usage_ent->target);
++            }
++            if(usage_ent->taglist)
++            {
++                free(usage_ent->taglist);
++            }
++            free(usage_ent);
++        }
++    }
++    usage_handle_list = NULL;
++}
++
++static void
++log_usage_stats(char *ssh_release, const char *ssl_release,
++                char *method, char *mechanism, const char *clientip,
++                char *username, char *userdn)
++{
++    globus_result_t                     result;
++    globus_list_t *                     list;
++    ssh_usage_ent_t *                   usage_ent;
++    char *                              keys[SSH_GLOBUS_TAGCOUNT];
++    char *                              values[SSH_GLOBUS_TAGCOUNT];
++    char *                              ptr;
++    char *                              key;
++    char *                              value;
++    int                                 i = 0;
++    char *                              save_taglist = NULL;
++
++    for(list = usage_handle_list;
++        !globus_list_empty(list);
++        list = globus_list_rest(list))
++    {
++        usage_ent = (ssh_usage_ent_t *) globus_list_first(list);
++
++        if(!usage_ent || usage_ent->handle == NULL)
++            continue;
++        
++        if(save_taglist == NULL || 
++            strcmp(save_taglist, usage_ent->taglist) != 0)
++        {
++            save_taglist = usage_ent->taglist;
++            
++            ptr = usage_ent->taglist;
++            i = 0;
++            while(ptr && *ptr)
++            {
++                switch(*ptr)
++                {
++                  case SSH_GLOBUS_USAGE_SSH_VER:
++                    key = "SSH_VER";
++                    value = ssh_release;
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_SSL_VER:
++                    key = "SSL_VER";
++                    value = (char *) ssl_release;
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_METHOD:
++                    key = "METHOD";
++                    value = method;
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_MECHANISM:
++                    key = "MECH";
++                    value = mechanism?:"";
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_CLIENTIP:
++                    key = "CLIENTIP";
++                    value = (char *) clientip?:"";
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_USERNAME:
++                    key = "USER";
++                    value = username?:"";
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_USERDN:
++                    key = "USERDN";
++                    value = userdn?:"";
++                    break;
++    
++                  default:
++                    key = NULL;
++                    value = NULL;
++                    break;
++                }
++                
++                if(key != NULL && value != NULL)
++                {
++                    keys[i] = key;
++                    values[i] = value;
++                    i++;
++                }
++                
++                ptr++;
++            }
++        }
++
++#ifdef HAVE_GLOBUS_USAGE_SEND_ARRAY
++        result = globus_usage_stats_send_array(
++            usage_ent->handle, i, keys, values);
++#else
++        if (i)
++            result = globus_usage_stats_send(
++                usage_ent->handle, i,
++                i>0?keys[0]:NULL, i>0?values[0]:NULL,
++                i>1?keys[1]:NULL, i>1?values[1]:NULL,
++                i>2?keys[2]:NULL, i>2?values[2]:NULL,
++                i>3?keys[3]:NULL, i>3?values[3]:NULL,
++                i>4?keys[4]:NULL, i>4?values[4]:NULL,
++                i>5?keys[5]:NULL, i>5?values[5]:NULL,
++                i>6?keys[6]:NULL, i>6?values[6]:NULL);
++#endif /* HAVE_GLOBUS_USAGE_SEND_ARRAY */
++    }
++    
++    return;
++}
++#endif /* HAVE_GLOBUS_USAGE */
++
++void
++ssh_globus_send_usage_metrics(char *ssh_release, const char *ssl_release,
++                              char *method, char *mechanism, const char *client_ip,
++                              char *username, char *userdn)
++{
++#ifdef HAVE_GLOBUS_USAGE
++
++    log_usage_stats(ssh_release, ssl_release, method, mechanism,
++                    client_ip, username, userdn);
++
++#endif /* HAVE_GLOBUS_USAGE */
++}
+diff -Nur openssh-5.3p1.orig/ssh-globus-usage.h openssh-5.3p1/ssh-globus-usage.h
+--- openssh-5.3p1.orig/ssh-globus-usage.h	1970-01-01 01:00:00.000000000 +0100
++++ openssh-5.3p1/ssh-globus-usage.h	2011-08-12 08:53:52.284703501 +0200
+@@ -0,0 +1,46 @@
++/*
++ * Copyright 2009 The Board of Trustees of the University
++ * of Illinois.  See the LICENSE file for detailed license information.
++ *
++ * Portions, specifically ssh_usage_stats_init(), ssh_usage_stats_close()
++ * were based on those from: gridftp/server/source/globus_i_gfs_log.h
++ * Copyright 1999-2006 University of Chicago
++ * 
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ * 
++ * http://www.apache.org/licenses/LICENSE-2.0
++ * 
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef __SSH_GLOBUS_USAGE_H
++#define __SSH_GLOBUS_USAGE_H
++
++#include "includes.h"
++
++#ifdef HAVE_GLOBUS_USAGE
++
++#include "globus_usage.h"
++
++#define CILOGON_COLLECTOR "usage-stats.cilogon.org:4810"
++
++globus_result_t
++ssh_usage_stats_init(int disable_usage_stats, char *usage_stats_targets);
++
++void
++ssh_usage_stats_close(int disable_usage_stats);
++
++#endif /* HAVE_GLOBUS_USAGE */
++
++void
++ssh_globus_send_usage_metrics(char *ssh_release, const char *ssl_release,
++                           char *method, char *mechanism, const char *client_ip,
++                           char *username, char *userdn);
++
++#endif /* __SSH_GLOBUS_USAGE_H */
+diff -Nur openssh-5.3p1.orig/ssh-gss.h openssh-5.3p1/ssh-gss.h
+--- openssh-5.3p1.orig/ssh-gss.h	2011-08-12 08:52:47.258701687 +0200
++++ openssh-5.3p1/ssh-gss.h	2011-08-12 08:53:52.285703501 +0200
+@@ -86,6 +86,7 @@
+ 	gss_name_t name;
+ 	struct ssh_gssapi_mech_struct *mech;
+ 	ssh_gssapi_ccache store;
++	gss_ctx_id_t context;
+ 	int used;
+ 	int updated;
+ } ssh_gssapi_client;
+@@ -106,7 +107,7 @@
+ 	OM_uint32	minor; /* both */
+ 	gss_ctx_id_t	context; /* both */
+ 	gss_name_t	name; /* both */
+-	gss_OID		oid; /* client */
++	gss_OID		oid; /* both */
+ 	gss_cred_id_t	creds; /* server */
+ 	gss_name_t	client; /* server */
+ 	gss_cred_id_t	client_creds; /* both */
+@@ -137,6 +138,9 @@
+ OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
+ int ssh_gssapi_credentials_updated(Gssctxt *);
+ 
++int ssh_gssapi_localname(char **name);
++void ssh_gssapi_rekey_creds();
++
+ /* In the server */
+ typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, 
+     const char *);
+@@ -147,7 +151,7 @@
+ int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, 
+     const char *);
+ OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
+-int ssh_gssapi_userok(char *name, struct passwd *);
++int ssh_gssapi_userok(char *name, struct passwd *, int gssapi_keyex);
+ OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
+ void ssh_gssapi_do_child(char ***, u_int *);
+ void ssh_gssapi_cleanup_creds(void);
+@@ -157,6 +161,7 @@
+ int ssh_gssapi_oid_table_ok();
+ 
+ int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
++void ssh_gssapi_get_client_info(char **userdn, char **mech);
+ #endif /* GSSAPI */
+ 
+ #endif /* _SSH_GSS_H */
+diff -Nur openssh-5.3p1.orig/version.h openssh-5.3p1/version.h
+--- openssh-5.3p1.orig/version.h	2009-07-05 23:13:04.000000000 +0200
++++ openssh-5.3p1/version.h	2011-08-12 08:53:52.285703501 +0200
+@@ -1,6 +1,21 @@
+ /* $OpenBSD: version.h,v 1.56 2009/06/30 14:54:40 markus Exp $ */
+ 
++#ifdef GSI
++#define GSI_VERSION	" GSI"
++#else
++#define GSI_VERSION	""
++#endif
++
++#ifdef KRB5
++#define KRB5_VERSION	" KRB5"
++#else
++#define KRB5_VERSION	""
++#endif
++
++#define NCSA_VERSION	" GLOBUS_GSSAPI_20100106"
++
+ #define SSH_VERSION	"OpenSSH_5.3"
+ 
+ #define SSH_PORTABLE	"p1"
+-#define SSH_RELEASE	SSH_VERSION SSH_PORTABLE
++#define SSH_RELEASE	SSH_VERSION SSH_PORTABLE \
++			NCSA_VERSION GSI_VERSION KRB5_VERSION
diff --git a/openssh-5.3p1-gsskex.patch b/openssh-5.3p1-gsskex.patch
new file mode 100644
index 0000000..21db632
--- /dev/null
+++ b/openssh-5.3p1-gsskex.patch
@@ -0,0 +1,2930 @@
+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));
+ }
+diff -up /dev/null openssh-5.3p1/ChangeLog.gssapi
+--- /dev/null	2009-11-13 11:29:57.672908570 +0100
++++ openssh-5.3p1/ChangeLog.gssapi	2009-11-20 14:39:04.000000000 +0100
+@@ -0,0 +1,95 @@
++20090615
++  - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c
++      sshd.c ]
++    Fix issues identified by Greg Hudson following a code review
++	Check return value of gss_indicate_mechs
++	Protect GSSAPI calls in monitor, so they can only be used if enabled
++	Check return values of bignum functions in key exchange
++	Use BN_clear_free to clear other side's DH value
++	Make ssh_gssapi_id_kex more robust
++	Only configure kex table pointers if GSSAPI is enabled
++	Don't leak mechanism list, or gss mechanism list
++	Cast data.length before printing
++	If serverkey isn't provided, use an empty string, rather than NULL
++
++20090201
++  - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h
++      ssh_config.5 sshconnet2.c ]
++    Add support for the GSSAPIClientIdentity option, which allows the user
++    to specify which GSSAPI identity to use to contact a given server
++
++20080404
++  - [ gss-serv.c ]
++    Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow
++    been omitted from a previous version of this patch. Reported by Borislav
++    Stoichkov
++
++20070317
++  - [ gss-serv-krb5.c ]
++    Remove C99ism, where new_ccname was being declared in the middle of a 
++    function
++
++20061220
++  - [ servconf.c ]
++    Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and 
++    documented, behaviour. Reported by Dan Watson.
++
++20060910
++  - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c
++      ssh-gss.h ]
++    add support for gss-group14-sha1 key exchange mechanisms
++  - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ]
++    Add GSSAPIStrictAcceptorCheck option to allow the disabling of
++    acceptor principal checking on multi-homed machines.
++    <Bugzilla #928>
++  - [ sshd_config ssh_config ]
++    Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample
++    configuration files
++  - [ kexgss.c kegsss.c sshconnect2.c sshd.c ]
++    Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf()
++    Limit length of error messages displayed by client
++
++20060909
++  - [ gss-genr.c gss-serv.c ]
++    move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server
++    only, where they belong 
++    <Bugzilla #1225>
++
++20060829
++  - [ gss-serv-krb5.c ]
++    Fix CCAPI credentials cache name when creating KRB5CCNAME environment 
++    variable
++
++20060828
++  - [ gss-genr.c ]
++    Avoid Heimdal context freeing problem
++    <Fixed upstream 20060829>
++
++20060818
++  - [ gss-genr.c ssh-gss.h sshconnect2.c ]
++    Make sure that SPENGO is disabled 
++    <Bugzilla #1218 - Fixed upstream 20060818>
++
++20060421
++  - [ gssgenr.c, sshconnect2.c ]
++    a few type changes (signed versus unsigned, int versus size_t) to
++    fix compiler errors/warnings 
++    (from jbasney AT ncsa.uiuc.edu)
++  - [ kexgssc.c, sshconnect2.c ]
++    fix uninitialized variable warnings
++    (from jbasney AT ncsa.uiuc.edu)
++  - [ gssgenr.c ]
++    pass oid to gss_display_status (helpful when using GSSAPI mechglue)
++    (from jbasney AT ncsa.uiuc.edu)
++    <Bugzilla #1220 >
++  - [ gss-serv-krb5.c ]
++    #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H
++    (from jbasney AT ncsa.uiuc.edu)
++    <Fixed upstream 20060304>
++  - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c 
++    add client-side GssapiKeyExchange option
++    (from jbasney AT ncsa.uiuc.edu)
++  - [ sshconnect2.c ]
++    add support for GssapiTrustDns option for gssapi-with-mic
++    (from jbasney AT ncsa.uiuc.edu)
++    <gssapi-with-mic support is Bugzilla #1008>
+diff -up openssh-5.3p1/clientloop.c.gsskex openssh-5.3p1/clientloop.c
+--- openssh-5.3p1/clientloop.c.gsskex	2009-08-28 03:21:07.000000000 +0200
++++ openssh-5.3p1/clientloop.c	2009-11-20 14:48:53.000000000 +0100
+@@ -111,6 +111,10 @@
+ #include "msg.h"
+ #include "roaming.h"
+ 
++#ifdef GSSAPI
++#include "ssh-gss.h"
++#endif
++
+ /* import options */
+ extern Options options;
+ 
+@@ -1430,6 +1434,13 @@ client_loop(int have_pty, int escape_cha
+ 		/* Do channel operations unless rekeying in progress. */
+ 		if (!rekeying) {
+ 			channel_after_select(readset, writeset);
++
++			if (options.gss_renewal_rekey &&
++			    ssh_gssapi_credentials_updated(GSS_C_NO_CONTEXT)) {
++				debug("credentials updated - forcing rekey");
++				need_rekeying = 1;
++			}
++
+ 			if (need_rekeying || packet_need_rekeying()) {
+ 				debug("need rekeying");
+ 				xxx_kex->done = 0;
+diff -up openssh-5.3p1/configure.ac.gsskex openssh-5.3p1/configure.ac
+--- openssh-5.3p1/configure.ac.gsskex	2009-11-20 14:39:02.000000000 +0100
++++ openssh-5.3p1/configure.ac	2009-11-20 14:39:04.000000000 +0100
+@@ -477,6 +477,30 @@ main() { if (NSVersionOfRunTimeLibrary("
+ 	    [Use tunnel device compatibility to OpenBSD])
+ 	AC_DEFINE(SSH_TUN_PREPEND_AF, 1,
+ 	    [Prepend the address family to IP tunnel traffic])
++	AC_MSG_CHECKING(if we have the Security Authorization Session API)
++	AC_TRY_COMPILE([#include <Security/AuthSession.h>],
++		[SessionCreate(0, 0);],
++		[ac_cv_use_security_session_api="yes"
++		 AC_DEFINE(USE_SECURITY_SESSION_API, 1, 
++			[platform has the Security Authorization Session API])
++		 LIBS="$LIBS -framework Security"
++		 AC_MSG_RESULT(yes)],
++		[ac_cv_use_security_session_api="no"
++		 AC_MSG_RESULT(no)])
++	AC_MSG_CHECKING(if we have an in-memory credentials cache)
++	AC_TRY_COMPILE(
++		[#include <Kerberos/Kerberos.h>],
++		[cc_context_t c;
++		 (void) cc_initialize (&c, 0, NULL, NULL);],
++		[AC_DEFINE(USE_CCAPI, 1, 
++			[platform uses an in-memory credentials cache])
++		 LIBS="$LIBS -framework Security"
++		 AC_MSG_RESULT(yes)
++		 if test "x$ac_cv_use_security_session_api" = "xno"; then
++			AC_MSG_ERROR(*** Need a security framework to use the credentials cache API ***)
++		fi],
++		[AC_MSG_RESULT(no)]
++	)
+ 	m4_pattern_allow(AU_IPv)
+ 	AC_CHECK_DECL(AU_IPv4, [], 
+ 	    AC_DEFINE(AU_IPv4, 0, [System only supports IPv4 audit records])
+diff -up openssh-5.3p1/gss-genr.c.gsskex openssh-5.3p1/gss-genr.c
+--- openssh-5.3p1/gss-genr.c.gsskex	2009-06-22 08:11:07.000000000 +0200
++++ openssh-5.3p1/gss-genr.c	2009-11-20 14:39:04.000000000 +0100
+@@ -39,12 +39,167 @@
+ #include "buffer.h"
+ #include "log.h"
+ #include "ssh2.h"
++#include "cipher.h"
++#include "key.h"
++#include "kex.h"
++#include <openssl/evp.h>
+ 
+ #include "ssh-gss.h"
+ 
+ extern u_char *session_id2;
+ extern u_int session_id2_len;
+ 
++typedef struct {
++	char *encoded;
++	gss_OID oid;
++} ssh_gss_kex_mapping;
++
++/*
++ * XXX - It would be nice to find a more elegant way of handling the
++ * XXX   passing of the key exchange context to the userauth routines
++ */
++
++Gssctxt *gss_kex_context = NULL;
++
++static ssh_gss_kex_mapping *gss_enc2oid = NULL;
++
++int 
++ssh_gssapi_oid_table_ok() {
++	return (gss_enc2oid != NULL);
++}
++
++/*
++ * Return a list of the gss-group1-sha1 mechanisms supported by this program
++ *
++ * We test mechanisms to ensure that we can use them, to avoid starting
++ * a key exchange with a bad mechanism
++ */
++
++char *
++ssh_gssapi_client_mechanisms(const char *host, const char *client) {
++	gss_OID_set gss_supported;
++	OM_uint32 min_status;
++
++	if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
++		return NULL;
++
++	return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
++	    host, client));
++}
++
++char *
++ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
++    const char *host, const char *client) {
++	Buffer buf;
++	size_t i;
++	int oidpos, enclen;
++	char *mechs, *encoded;
++	u_char digest[EVP_MAX_MD_SIZE];
++	char deroid[2];
++	const EVP_MD *evp_md = EVP_md5();
++	EVP_MD_CTX md;
++
++	if (gss_enc2oid != NULL) {
++		for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
++			xfree(gss_enc2oid[i].encoded);
++		xfree(gss_enc2oid);
++	}
++
++	gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
++	    (gss_supported->count + 1));
++
++	buffer_init(&buf);
++
++	oidpos = 0;
++	for (i = 0; i < gss_supported->count; i++) {
++		if (gss_supported->elements[i].length < 128 &&
++		    (*check)(NULL, &(gss_supported->elements[i]), host, client)) {
++
++			deroid[0] = SSH_GSS_OIDTYPE;
++			deroid[1] = gss_supported->elements[i].length;
++
++			EVP_DigestInit(&md, evp_md);
++			EVP_DigestUpdate(&md, deroid, 2);
++			EVP_DigestUpdate(&md,
++			    gss_supported->elements[i].elements,
++			    gss_supported->elements[i].length);
++			EVP_DigestFinal(&md, digest, NULL);
++
++			encoded = xmalloc(EVP_MD_size(evp_md) * 2);
++			enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
++			    encoded, EVP_MD_size(evp_md) * 2);
++
++			if (oidpos != 0)
++				buffer_put_char(&buf, ',');
++
++			buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
++			    sizeof(KEX_GSS_GEX_SHA1_ID) - 1);
++			buffer_append(&buf, encoded, enclen);
++			buffer_put_char(&buf, ',');
++			buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, 
++			    sizeof(KEX_GSS_GRP1_SHA1_ID) - 1);
++			buffer_append(&buf, encoded, enclen);
++			buffer_put_char(&buf, ',');
++			buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID,
++			    sizeof(KEX_GSS_GRP14_SHA1_ID) - 1);
++			buffer_append(&buf, encoded, enclen);
++
++			gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
++			gss_enc2oid[oidpos].encoded = encoded;
++			oidpos++;
++		}
++	}
++	gss_enc2oid[oidpos].oid = NULL;
++	gss_enc2oid[oidpos].encoded = NULL;
++
++	buffer_put_char(&buf, '\0');
++
++	mechs = xmalloc(buffer_len(&buf));
++	buffer_get(&buf, mechs, buffer_len(&buf));
++	buffer_free(&buf);
++
++	if (strlen(mechs) == 0) {
++		xfree(mechs);
++		mechs = NULL;
++	}
++	
++	return (mechs);
++}
++
++gss_OID
++ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
++	int i = 0;
++	
++	switch (kex_type) {
++	case KEX_GSS_GRP1_SHA1:
++		if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID))
++			return GSS_C_NO_OID;
++		name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
++		break;
++	case KEX_GSS_GRP14_SHA1:
++		if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID))
++			return GSS_C_NO_OID;
++		name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
++		break;
++	case KEX_GSS_GEX_SHA1:
++		if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID))
++			return GSS_C_NO_OID;
++		name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
++		break;
++	default:
++		return GSS_C_NO_OID;
++	}
++
++	while (gss_enc2oid[i].encoded != NULL &&
++	    strcmp(name, gss_enc2oid[i].encoded) != 0)
++		i++;
++
++	if (gss_enc2oid[i].oid != NULL && ctx != NULL)
++		ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
++
++	return gss_enc2oid[i].oid;
++}
++
+ /* Check that the OID in a data stream matches that in the context */
+ int
+ ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
+@@ -197,7 +352,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int de
+ 	}
+ 
+ 	ctx->major = gss_init_sec_context(&ctx->minor,
+-	    GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid,
++	    ctx->client_creds, &ctx->context, ctx->name, ctx->oid,
+ 	    GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
+ 	    0, NULL, recv_tok, NULL, send_tok, flags, NULL);
+ 
+@@ -227,8 +382,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, con
+ }
+ 
+ OM_uint32
++ssh_gssapi_client_identity(Gssctxt *ctx, const char *name)
++{
++	gss_buffer_desc gssbuf;
++	gss_name_t gssname;
++	OM_uint32 status;
++	gss_OID_set oidset;
++
++	gssbuf.value = (void *) name;
++	gssbuf.length = strlen(gssbuf.value);
++
++	gss_create_empty_oid_set(&status, &oidset);
++	gss_add_oid_set_member(&status, ctx->oid, &oidset);
++
++	ctx->major = gss_import_name(&ctx->minor, &gssbuf,
++	    GSS_C_NT_USER_NAME, &gssname);
++
++	if (!ctx->major)
++		ctx->major = gss_acquire_cred(&ctx->minor, 
++		    gssname, 0, oidset, GSS_C_INITIATE, 
++		    &ctx->client_creds, NULL, NULL);
++
++	gss_release_name(&status, &gssname);
++	gss_release_oid_set(&status, &oidset);
++
++	if (ctx->major)
++		ssh_gssapi_error(ctx);
++
++	return(ctx->major);
++}
++
++OM_uint32
+ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
+ {
++	if (ctx == NULL) 
++		return -1;
++
+ 	if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
+ 	    GSS_C_QOP_DEFAULT, buffer, hash)))
+ 		ssh_gssapi_error(ctx);
+@@ -236,6 +425,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer
+ 	return (ctx->major);
+ }
+ 
++/* Priviledged when used by server */
++OM_uint32
++ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
++{
++	if (ctx == NULL)
++		return -1;
++
++	ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
++	    gssbuf, gssmic, NULL);
++
++	return (ctx->major);
++}
++
+ void
+ ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
+     const char *context)
+@@ -249,11 +451,16 @@ ssh_gssapi_buildmic(Buffer *b, const cha
+ }
+ 
+ int
+-ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
++ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host, 
++    const char *client)
+ {
+ 	gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
+ 	OM_uint32 major, minor;
+ 	gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
++	Gssctxt *intctx = NULL;
++
++	if (ctx == NULL)
++		ctx = &intctx;
+ 
+ 	/* RFC 4462 says we MUST NOT do SPNEGO */
+ 	if (oid->length == spnego_oid.length && 
+@@ -263,6 +470,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx
+ 	ssh_gssapi_build_ctx(ctx);
+ 	ssh_gssapi_set_oid(*ctx, oid);
+ 	major = ssh_gssapi_import_name(*ctx, host);
++
++	if (!GSS_ERROR(major) && client)
++		major = ssh_gssapi_client_identity(*ctx, client);
++
+ 	if (!GSS_ERROR(major)) {
+ 		major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, 
+ 		    NULL);
+@@ -272,10 +483,67 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx
+ 			    GSS_C_NO_BUFFER);
+ 	}
+ 
+-	if (GSS_ERROR(major)) 
++	if (GSS_ERROR(major) || intctx != NULL) 
+ 		ssh_gssapi_delete_ctx(ctx);
+ 
+ 	return (!GSS_ERROR(major));
+ }
+ 
++int
++ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
++	static gss_name_t saved_name = GSS_C_NO_NAME;
++	static OM_uint32 saved_lifetime = 0;
++	static gss_OID saved_mech = GSS_C_NO_OID;
++	static gss_name_t name;
++	static OM_uint32 last_call = 0;
++	OM_uint32 lifetime, now, major, minor;
++	int equal;
++	gss_cred_usage_t usage = GSS_C_INITIATE;
++	
++	now = time(NULL);
++
++	if (ctxt) {
++		debug("Rekey has happened - updating saved versions");
++
++		if (saved_name != GSS_C_NO_NAME)
++			gss_release_name(&minor, &saved_name);
++
++		major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
++		    &saved_name, &saved_lifetime, NULL, NULL);
++
++		if (!GSS_ERROR(major)) {
++			saved_mech = ctxt->oid;
++		        saved_lifetime+= now;
++		} else {
++			/* Handle the error */
++		}
++		return 0;
++	}
++
++	if (now - last_call < 10)
++		return 0;
++
++	last_call = now;
++
++	if (saved_mech == GSS_C_NO_OID)
++		return 0;
++	
++	major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, 
++	    &name, &lifetime, NULL, NULL);
++	if (major == GSS_S_CREDENTIALS_EXPIRED)
++		return 0;
++	else if (GSS_ERROR(major))
++		return 0;
++
++	major = gss_compare_name(&minor, saved_name, name, &equal);
++	gss_release_name(&minor, &name);
++	if (GSS_ERROR(major))
++		return 0;
++
++	if (equal && (saved_lifetime < lifetime + now - 10))
++		return 1;
++
++	return 0;
++}
++
+ #endif /* GSSAPI */
+diff -up openssh-5.3p1/gss-serv.c.gsskex openssh-5.3p1/gss-serv.c
+--- openssh-5.3p1/gss-serv.c.gsskex	2008-05-19 07:05:07.000000000 +0200
++++ openssh-5.3p1/gss-serv.c	2009-11-20 14:39:05.000000000 +0100
+@@ -1,7 +1,7 @@
+ /* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 djm Exp $ */
+ 
+ /*
+- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
++ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+@@ -45,15 +45,20 @@
+ #include "channels.h"
+ #include "session.h"
+ #include "misc.h"
++#include "servconf.h"
++#include "uidswap.h"
+ 
+ #include "ssh-gss.h"
++#include "monitor_wrap.h"
++
++extern ServerOptions options;
+ 
+ static ssh_gssapi_client gssapi_client =
+     { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
+-    GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}};
++    GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME,  NULL, {NULL, NULL, NULL}, 0, 0};
+ 
+ ssh_gssapi_mech gssapi_null_mech =
+-    { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
++    { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
+ 
+ #ifdef KRB5
+ extern ssh_gssapi_mech gssapi_kerberos_mech;
+@@ -81,25 +86,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx)
+ 	char lname[MAXHOSTNAMELEN];
+ 	gss_OID_set oidset;
+ 
+-	gss_create_empty_oid_set(&status, &oidset);
+-	gss_add_oid_set_member(&status, ctx->oid, &oidset);
++	if (options.gss_strict_acceptor) {
++		gss_create_empty_oid_set(&status, &oidset);
++		gss_add_oid_set_member(&status, ctx->oid, &oidset);
++
++		if (gethostname(lname, MAXHOSTNAMELEN)) {
++			gss_release_oid_set(&status, &oidset);
++			return (-1);
++		}
+ 
+-	if (gethostname(lname, MAXHOSTNAMELEN)) {
+-		gss_release_oid_set(&status, &oidset);
+-		return (-1);
+-	}
++		if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
++			gss_release_oid_set(&status, &oidset);
++			return (ctx->major);
++		}
++
++		if ((ctx->major = gss_acquire_cred(&ctx->minor,
++		    ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, 
++		    NULL, NULL)))
++			ssh_gssapi_error(ctx);
+ 
+-	if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
+ 		gss_release_oid_set(&status, &oidset);
+ 		return (ctx->major);
++	} else {
++		ctx->name = GSS_C_NO_NAME;
++		ctx->creds = GSS_C_NO_CREDENTIAL;
+ 	}
+-
+-	if ((ctx->major = gss_acquire_cred(&ctx->minor,
+-	    ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
+-		ssh_gssapi_error(ctx);
+-
+-	gss_release_oid_set(&status, &oidset);
+-	return (ctx->major);
++	return GSS_S_COMPLETE;
+ }
+ 
+ /* Privileged */
+@@ -114,6 +126,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss
+ }
+ 
+ /* Unprivileged */
++char *
++ssh_gssapi_server_mechanisms() {
++	gss_OID_set	supported;
++
++	ssh_gssapi_supported_oids(&supported);
++	return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
++	    NULL, NULL));
++}
++
++/* Unprivileged */
++int
++ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
++    const char *dummy) {
++	Gssctxt *ctx = NULL;
++	int res;
++ 
++	res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
++	ssh_gssapi_delete_ctx(&ctx);
++
++	return (res);
++}
++
++/* Unprivileged */
+ void
+ ssh_gssapi_supported_oids(gss_OID_set *oidset)
+ {
+@@ -123,7 +158,9 @@ ssh_gssapi_supported_oids(gss_OID_set *o
+ 	gss_OID_set supported;
+ 
+ 	gss_create_empty_oid_set(&min_status, oidset);
+-	gss_indicate_mechs(&min_status, &supported);
++
++	if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
++		return;
+ 
+ 	while (supported_mechs[i]->name != NULL) {
+ 		if (GSS_ERROR(gss_test_oid_set_member(&min_status,
+@@ -247,8 +284,48 @@ OM_uint32
+ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
+ {
+ 	int i = 0;
++	int equal = 0;
++	gss_name_t new_name = GSS_C_NO_NAME;
++	gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
++
++	if (options.gss_store_rekey && client->used && ctx->client_creds) {
++		if (client->mech->oid.length != ctx->oid->length ||
++		    (memcmp(client->mech->oid.elements,
++		     ctx->oid->elements, ctx->oid->length) !=0)) {
++			debug("Rekeyed credentials have different mechanism");
++			return GSS_S_COMPLETE;
++		}
++
++		if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, 
++		    ctx->client_creds, ctx->oid, &new_name, 
++		    NULL, NULL, NULL))) {
++			ssh_gssapi_error(ctx);
++			return (ctx->major);
++		}
++
++		ctx->major = gss_compare_name(&ctx->minor, client->name, 
++		    new_name, &equal);
+ 
+-	gss_buffer_desc ename;
++		if (GSS_ERROR(ctx->major)) {
++			ssh_gssapi_error(ctx);
++			return (ctx->major);
++		}
++ 
++		if (!equal) {
++			debug("Rekeyed credentials have different name");
++			return GSS_S_COMPLETE;
++		}
++
++		debug("Marking rekeyed credentials for export");
++
++		gss_release_name(&ctx->minor, &client->name);
++		gss_release_cred(&ctx->minor, &client->creds);
++		client->name = new_name;
++		client->creds = ctx->client_creds;
++        	ctx->client_creds = GSS_C_NO_CREDENTIAL;
++		client->updated = 1;
++		return GSS_S_COMPLETE;
++	}
+ 
+ 	client->mech = NULL;
+ 
+@@ -263,6 +340,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
+ 	if (client->mech == NULL)
+ 		return GSS_S_FAILURE;
+ 
++	if (ctx->client_creds &&
++	    (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
++	     ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
++		ssh_gssapi_error(ctx);
++		return (ctx->major);
++	}
++
+ 	if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
+ 	    &client->displayname, NULL))) {
+ 		ssh_gssapi_error(ctx);
+@@ -280,6 +364,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
+ 		return (ctx->major);
+ 	}
+ 
++	gss_release_buffer(&ctx->minor, &ename);
++
+ 	/* We can't copy this structure, so we just move the pointer to it */
+ 	client->creds = ctx->client_creds;
+ 	ctx->client_creds = GSS_C_NO_CREDENTIAL;
+@@ -327,7 +413,7 @@ ssh_gssapi_do_child(char ***envp, u_int 
+ 
+ /* Privileged */
+ int
+-ssh_gssapi_userok(char *user)
++ssh_gssapi_userok(char *user, struct passwd *pw)
+ {
+ 	OM_uint32 lmin;
+ 
+@@ -337,9 +423,11 @@ ssh_gssapi_userok(char *user)
+ 		return 0;
+ 	}
+ 	if (gssapi_client.mech && gssapi_client.mech->userok)
+-		if ((*gssapi_client.mech->userok)(&gssapi_client, user))
++		if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
++			gssapi_client.used = 1;
++			gssapi_client.store.owner = pw;
+ 			return 1;
+-		else {
++		} else {
+ 			/* Destroy delegated credentials if userok fails */
+ 			gss_release_buffer(&lmin, &gssapi_client.displayname);
+ 			gss_release_buffer(&lmin, &gssapi_client.exportedname);
+@@ -352,14 +440,90 @@ ssh_gssapi_userok(char *user)
+ 	return (0);
+ }
+ 
+-/* Privileged */
+-OM_uint32
+-ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
++/* These bits are only used for rekeying. The unpriviledged child is running 
++ * as the user, the monitor is root.
++ *
++ * In the child, we want to :
++ *    *) Ask the monitor to store our credentials into the store we specify
++ *    *) If it succeeds, maybe do a PAM update
++ */
++
++/* Stuff for PAM */
++
++#ifdef USE_PAM
++static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, 
++    struct pam_response **resp, void *data)
+ {
+-	ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
+-	    gssbuf, gssmic, NULL);
++	return (PAM_CONV_ERR);
++}
++#endif
+ 
+-	return (ctx->major);
++void
++ssh_gssapi_rekey_creds() {
++	int ok;
++	int ret;
++#ifdef USE_PAM
++	pam_handle_t *pamh = NULL;
++	struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
++	char *envstr;
++#endif
++
++	if (gssapi_client.store.filename == NULL && 
++	    gssapi_client.store.envval == NULL &&
++	    gssapi_client.store.envvar == NULL)
++		return;
++ 
++	ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
++
++	if (!ok)
++		return;
++
++	debug("Rekeyed credentials stored successfully");
++
++	/* Actually managing to play with the ssh pam stack from here will
++	 * be next to impossible. In any case, we may want different options
++	 * for rekeying. So, use our own :)
++	 */
++#ifdef USE_PAM	
++	if (!use_privsep) {
++		debug("Not even going to try and do PAM with privsep disabled");
++		return;
++	}
++
++	ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
++ 	    &pamconv, &pamh);
++	if (ret)
++		return;
++
++	xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, 
++	    gssapi_client.store.envval);
++
++	ret = pam_putenv(pamh, envstr);
++	if (!ret)
++		pam_setcred(pamh, PAM_REINITIALIZE_CRED);
++	pam_end(pamh, PAM_SUCCESS);
++#endif
++}
++
++int 
++ssh_gssapi_update_creds(ssh_gssapi_ccache *store) {
++	int ok = 0;
++
++	/* Check we've got credentials to store */
++	if (!gssapi_client.updated)
++		return 0;
++
++	gssapi_client.updated = 0;
++
++	temporarily_use_uid(gssapi_client.store.owner);
++	if (gssapi_client.mech && gssapi_client.mech->updatecreds)
++		ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client);
++	else
++		debug("No update function for this mechanism");
++
++	restore_uid();
++
++	return ok;
+ }
+ 
+ #endif
+diff -up openssh-5.3p1/gss-serv-krb5.c.gsskex openssh-5.3p1/gss-serv-krb5.c
+--- openssh-5.3p1/gss-serv-krb5.c.gsskex	2006-09-01 07:38:36.000000000 +0200
++++ openssh-5.3p1/gss-serv-krb5.c	2009-11-20 14:39:04.000000000 +0100
+@@ -1,7 +1,7 @@
+ /* $OpenBSD: gss-serv-krb5.c,v 1.7 2006/08/03 03:34:42 deraadt 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
+@@ -120,6 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
+ 	krb5_principal princ;
+ 	OM_uint32 maj_status, min_status;
+ 	int len;
++	const char *new_ccname;
+ 
+ 	if (client->creds == NULL) {
+ 		debug("No credentials stored");
+@@ -168,11 +169,16 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
+ 		return;
+ 	}
+ 
+-	client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache));
++	new_ccname = krb5_cc_get_name(krb_context, ccache);
++
+ 	client->store.envvar = "KRB5CCNAME";
+-	len = strlen(client->store.filename) + 6;
+-	client->store.envval = xmalloc(len);
+-	snprintf(client->store.envval, len, "FILE:%s", client->store.filename);
++#ifdef USE_CCAPI
++	xasprintf(&client->store.envval, "API:%s", new_ccname);
++	client->store.filename = NULL;
++#else
++	xasprintf(&client->store.envval, "FILE:%s", new_ccname);
++	client->store.filename = xstrdup(new_ccname);
++#endif
+ 
+ #ifdef USE_PAM
+ 	if (options.use_pam)
+@@ -184,6 +190,71 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
+ 	return;
+ }
+ 
++int
++ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, 
++    ssh_gssapi_client *client)
++{
++	krb5_ccache ccache = NULL;
++	krb5_principal principal = NULL;
++	char *name = NULL;
++	krb5_error_code problem;
++	OM_uint32 maj_status, min_status;
++
++   	if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) {
++                logit("krb5_cc_resolve(): %.100s",
++                    krb5_get_err_text(krb_context, problem));
++                return 0;
++       	}
++	
++	/* Find out who the principal in this cache is */
++	if ((problem = krb5_cc_get_principal(krb_context, ccache, 
++	    &principal))) {
++		logit("krb5_cc_get_principal(): %.100s",
++		    krb5_get_err_text(krb_context, problem));
++		krb5_cc_close(krb_context, ccache);
++		return 0;
++	}
++
++	if ((problem = krb5_unparse_name(krb_context, principal, &name))) {
++		logit("krb5_unparse_name(): %.100s",
++		    krb5_get_err_text(krb_context, problem));
++		krb5_free_principal(krb_context, principal);
++		krb5_cc_close(krb_context, ccache);
++		return 0;
++	}
++
++
++	if (strcmp(name,client->exportedname.value)!=0) {
++		debug("Name in local credentials cache differs. Not storing");
++		krb5_free_principal(krb_context, principal);
++		krb5_cc_close(krb_context, ccache);
++		krb5_free_unparsed_name(krb_context, name);
++		return 0;
++	}
++	krb5_free_unparsed_name(krb_context, name);
++
++	/* Name matches, so lets get on with it! */
++
++	if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) {
++		logit("krb5_cc_initialize(): %.100s",
++		    krb5_get_err_text(krb_context, problem));
++		krb5_free_principal(krb_context, principal);
++		krb5_cc_close(krb_context, ccache);
++		return 0;
++	}
++
++	krb5_free_principal(krb_context, principal);
++
++	if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds,
++	    ccache))) {
++		logit("gss_krb5_copy_ccache() failed. Sorry!");
++		krb5_cc_close(krb_context, ccache);
++		return 0;
++	}
++
++	return 1;
++}
++
+ ssh_gssapi_mech gssapi_kerberos_mech = {
+ 	"toWM5Slw5Ew8Mqkay+al2g==",
+ 	"Kerberos",
+@@ -191,7 +262,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = {
+ 	NULL,
+ 	&ssh_gssapi_krb5_userok,
+ 	NULL,
+-	&ssh_gssapi_krb5_storecreds
++	&ssh_gssapi_krb5_storecreds,
++	&ssh_gssapi_krb5_updatecreds
+ };
+ 
+ #endif /* KRB5 */
+diff -up openssh-5.3p1/kex.c.gsskex openssh-5.3p1/kex.c
+--- openssh-5.3p1/kex.c.gsskex	2009-06-21 10:15:25.000000000 +0200
++++ openssh-5.3p1/kex.c	2009-11-20 14:50:11.000000000 +0100
+@@ -49,6 +49,10 @@
+ #include "dispatch.h"
+ #include "monitor.h"
+ 
++#ifdef GSSAPI
++#include "ssh-gss.h"
++#endif
++
+ #if OPENSSL_VERSION_NUMBER >= 0x00907000L
+ # if defined(HAVE_EVP_SHA256)
+ # define evp_ssh_sha256 EVP_sha256
+@@ -325,6 +329,20 @@ choose_kex(Kex *k, char *client, char *s
+ 		k->kex_type = KEX_DH_GEX_SHA256;
+ 		k->evp_md = evp_ssh_sha256();
+ #endif
++#ifdef GSSAPI
++	} else if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID,
++	    sizeof(KEX_GSS_GEX_SHA1_ID) - 1) == 0) {
++		k->kex_type = KEX_GSS_GEX_SHA1;
++		k->evp_md = EVP_sha1();
++	} else if (strncmp(k->name, KEX_GSS_GRP1_SHA1_ID,
++	    sizeof(KEX_GSS_GRP1_SHA1_ID) - 1) == 0) {
++		k->kex_type = KEX_GSS_GRP1_SHA1;
++		k->evp_md = EVP_sha1();
++	} else if (strncmp(k->name, KEX_GSS_GRP14_SHA1_ID,
++	    sizeof(KEX_GSS_GRP14_SHA1_ID) - 1) == 0) {
++		k->kex_type = KEX_GSS_GRP14_SHA1;
++		k->evp_md = EVP_sha1();
++#endif
+ 	} else
+ 		fatal("bad kex alg %s", k->name);
+ }
+diff -up /dev/null openssh-5.3p1/kexgssc.c
+--- /dev/null	2009-11-13 11:29:57.672908570 +0100
++++ openssh-5.3p1/kexgssc.c	2009-11-20 14:39:05.000000000 +0100
+@@ -0,0 +1,334 @@
++/*
++ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "includes.h"
++
++#ifdef GSSAPI
++
++#include "includes.h"
++
++#include <openssl/crypto.h>
++#include <openssl/bn.h>
++
++#include <string.h>
++
++#include "xmalloc.h"
++#include "buffer.h"
++#include "ssh2.h"
++#include "key.h"
++#include "cipher.h"
++#include "kex.h"
++#include "log.h"
++#include "packet.h"
++#include "dh.h"
++
++#include "ssh-gss.h"
++
++void
++kexgss_client(Kex *kex) {
++	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
++	gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
++	Gssctxt *ctxt;
++	OM_uint32 maj_status, min_status, ret_flags;
++	u_int klen, kout, slen = 0, hashlen, strlen;
++	DH *dh; 
++	BIGNUM *dh_server_pub = NULL;
++	BIGNUM *shared_secret = NULL;
++	BIGNUM *p = NULL;
++	BIGNUM *g = NULL;	
++	u_char *kbuf, *hash;
++	u_char *serverhostkey = NULL;
++	u_char *empty = "";
++	char *msg;
++	char *lang;
++	int type = 0;
++	int first = 1;
++	int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
++
++	/* Initialise our GSSAPI world */	
++	ssh_gssapi_build_ctx(&ctxt);
++	if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) 
++	    == GSS_C_NO_OID)
++		fatal("Couldn't identify host exchange");
++
++	if (ssh_gssapi_import_name(ctxt, kex->gss_host))
++		fatal("Couldn't import hostname");
++
++	if (kex->gss_client && 
++	    ssh_gssapi_client_identity(ctxt, kex->gss_client))
++		fatal("Couldn't acquire client credentials");
++
++	switch (kex->kex_type) {
++	case KEX_GSS_GRP1_SHA1:
++		dh = dh_new_group1();
++		break;
++	case KEX_GSS_GRP14_SHA1:
++		dh = dh_new_group14();
++		break;
++	case KEX_GSS_GEX_SHA1:
++		debug("Doing group exchange\n");
++		nbits = dh_estimate(kex->we_need * 8);
++		packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
++		packet_put_int(min);
++		packet_put_int(nbits);
++		packet_put_int(max);
++
++		packet_send();
++
++		packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
++
++		if ((p = BN_new()) == NULL)
++			fatal("BN_new() failed");
++		packet_get_bignum2(p);
++		if ((g = BN_new()) == NULL)
++			fatal("BN_new() failed");
++		packet_get_bignum2(g);
++		packet_check_eom();
++
++		if (BN_num_bits(p) < min || BN_num_bits(p) > max)
++			fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
++			    min, BN_num_bits(p), max);
++
++		dh = dh_new_group(g, p);
++		break;
++	default:
++		fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
++	}
++	
++	/* Step 1 - e is dh->pub_key */
++	dh_gen_key(dh, kex->we_need * 8);
++
++	/* This is f, we initialise it now to make life easier */
++	dh_server_pub = BN_new();
++	if (dh_server_pub == NULL)
++		fatal("dh_server_pub == NULL");
++
++	token_ptr = GSS_C_NO_BUFFER;
++			 
++	do {
++		debug("Calling gss_init_sec_context");
++		
++		maj_status = ssh_gssapi_init_ctx(ctxt,
++		    kex->gss_deleg_creds, token_ptr, &send_tok,
++		    &ret_flags);
++
++		if (GSS_ERROR(maj_status)) {
++			if (send_tok.length != 0) {
++				packet_start(SSH2_MSG_KEXGSS_CONTINUE);
++				packet_put_string(send_tok.value,
++				    send_tok.length);
++			}
++			fatal("gss_init_context failed");
++		}
++
++		/* If we've got an old receive buffer get rid of it */
++		if (token_ptr != GSS_C_NO_BUFFER)
++			xfree(recv_tok.value);
++
++		if (maj_status == GSS_S_COMPLETE) {
++			/* If mutual state flag is not true, kex fails */
++			if (!(ret_flags & GSS_C_MUTUAL_FLAG))
++				fatal("Mutual authentication failed");
++
++			/* If integ avail flag is not true kex fails */
++			if (!(ret_flags & GSS_C_INTEG_FLAG))
++				fatal("Integrity check failed");
++		}
++
++		/* 
++		 * If we have data to send, then the last message that we
++		 * received cannot have been a 'complete'. 
++		 */
++		if (send_tok.length != 0) {
++			if (first) {
++				packet_start(SSH2_MSG_KEXGSS_INIT);
++				packet_put_string(send_tok.value,
++				    send_tok.length);
++				packet_put_bignum2(dh->pub_key);
++				first = 0;
++			} else {
++				packet_start(SSH2_MSG_KEXGSS_CONTINUE);
++				packet_put_string(send_tok.value,
++				    send_tok.length);
++			}
++			packet_send();
++			gss_release_buffer(&min_status, &send_tok);
++
++			/* If we've sent them data, they should reply */
++			do {	
++				type = packet_read();
++				if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
++					debug("Received KEXGSS_HOSTKEY");
++					if (serverhostkey)
++						fatal("Server host key received more than once");
++					serverhostkey = 
++					    packet_get_string(&slen);
++				}
++			} while (type == SSH2_MSG_KEXGSS_HOSTKEY);
++
++			switch (type) {
++			case SSH2_MSG_KEXGSS_CONTINUE:
++				debug("Received GSSAPI_CONTINUE");
++				if (maj_status == GSS_S_COMPLETE) 
++					fatal("GSSAPI Continue received from server when complete");
++				recv_tok.value = packet_get_string(&strlen);
++				recv_tok.length = strlen; 
++				break;
++			case SSH2_MSG_KEXGSS_COMPLETE:
++				debug("Received GSSAPI_COMPLETE");
++				packet_get_bignum2(dh_server_pub);
++				msg_tok.value =  packet_get_string(&strlen);
++				msg_tok.length = strlen; 
++
++				/* Is there a token included? */
++				if (packet_get_char()) {
++					recv_tok.value=
++					    packet_get_string(&strlen);
++					recv_tok.length = strlen;
++					/* If we're already complete - protocol error */
++					if (maj_status == GSS_S_COMPLETE)
++						packet_disconnect("Protocol error: received token when complete");
++					} else {
++						/* No token included */
++						if (maj_status != GSS_S_COMPLETE)
++							packet_disconnect("Protocol error: did not receive final token");
++				}
++				break;
++			case SSH2_MSG_KEXGSS_ERROR:
++				debug("Received Error");
++				maj_status = packet_get_int();
++				min_status = packet_get_int();
++				msg = packet_get_string(NULL);
++				lang = packet_get_string(NULL);
++				fatal("GSSAPI Error: \n%.400s",msg);
++			default:
++				packet_disconnect("Protocol error: didn't expect packet type %d",
++		    		type);
++			}
++			token_ptr = &recv_tok;
++		} else {
++			/* No data, and not complete */
++			if (maj_status != GSS_S_COMPLETE)
++				fatal("Not complete, and no token output");
++		}
++	} while (maj_status & GSS_S_CONTINUE_NEEDED);
++
++	/* 
++	 * We _must_ have received a COMPLETE message in reply from the 
++	 * server, which will have set dh_server_pub and msg_tok 
++	 */
++
++	if (type != SSH2_MSG_KEXGSS_COMPLETE)
++		fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
++
++	/* Check f in range [1, p-1] */
++	if (!dh_pub_is_valid(dh, dh_server_pub))
++		packet_disconnect("bad server public DH value");
++
++	/* compute K=f^x mod p */
++	klen = DH_size(dh);
++	kbuf = xmalloc(klen);
++	kout = DH_compute_key(kbuf, dh_server_pub, dh);
++	if (kout < 0)
++		fatal("DH_compute_key: failed");
++
++	shared_secret = BN_new();
++	if (shared_secret == NULL)
++		fatal("kexgss_client: BN_new failed");
++
++	if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
++		fatal("kexdh_client: BN_bin2bn failed");
++
++	memset(kbuf, 0, klen);
++	xfree(kbuf);
++
++	switch (kex->kex_type) {
++	case KEX_GSS_GRP1_SHA1:
++	case KEX_GSS_GRP14_SHA1:
++		kex_dh_hash( kex->client_version_string, 
++		    kex->server_version_string,
++		    buffer_ptr(&kex->my), buffer_len(&kex->my),
++		    buffer_ptr(&kex->peer), buffer_len(&kex->peer),
++		    (serverhostkey ? serverhostkey : empty), slen,
++		    dh->pub_key,	/* e */
++		    dh_server_pub,	/* f */
++		    shared_secret,	/* K */
++		    &hash, &hashlen
++		);
++		break;
++	case KEX_GSS_GEX_SHA1:
++		kexgex_hash(
++		    kex->evp_md,
++		    kex->client_version_string,
++		    kex->server_version_string,
++		    buffer_ptr(&kex->my), buffer_len(&kex->my),
++		    buffer_ptr(&kex->peer), buffer_len(&kex->peer),
++		    (serverhostkey ? serverhostkey : empty), slen,
++ 		    min, nbits, max,
++		    dh->p, dh->g,
++		    dh->pub_key,
++		    dh_server_pub,
++		    shared_secret,
++		    &hash, &hashlen
++		);
++		break;
++	default:
++		fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
++	}
++
++	gssbuf.value = hash;
++	gssbuf.length = hashlen;
++
++	/* Verify that the hash matches the MIC we just got. */
++	if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
++		packet_disconnect("Hash's MIC didn't verify");
++
++	xfree(msg_tok.value);
++
++	DH_free(dh);
++	if (serverhostkey)
++		xfree(serverhostkey);
++	BN_clear_free(dh_server_pub);
++
++	/* save session id */
++	if (kex->session_id == NULL) {
++		kex->session_id_len = hashlen;
++		kex->session_id = xmalloc(kex->session_id_len);
++		memcpy(kex->session_id, hash, kex->session_id_len);
++	}
++
++	if (kex->gss_deleg_creds)
++		ssh_gssapi_credentials_updated(ctxt);
++
++	if (gss_kex_context == NULL)
++		gss_kex_context = ctxt;
++	else
++		ssh_gssapi_delete_ctx(&ctxt);
++
++	kex_derive_keys(kex, hash, hashlen, shared_secret);
++	BN_clear_free(shared_secret);
++	kex_finish(kex);
++}
++
++#endif /* GSSAPI */
+diff -up /dev/null openssh-5.3p1/kexgsss.c
+--- /dev/null	2009-11-13 11:29:57.672908570 +0100
++++ openssh-5.3p1/kexgsss.c	2009-11-20 14:39:05.000000000 +0100
+@@ -0,0 +1,288 @@
++/*
++ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "includes.h"
++
++#ifdef GSSAPI
++
++#include <string.h>
++
++#include <openssl/crypto.h>
++#include <openssl/bn.h>
++
++#include "xmalloc.h"
++#include "buffer.h"
++#include "ssh2.h"
++#include "key.h"
++#include "cipher.h"
++#include "kex.h"
++#include "log.h"
++#include "packet.h"
++#include "dh.h"
++#include "ssh-gss.h"
++#include "monitor_wrap.h"
++#include "servconf.h"
++
++extern ServerOptions options;
++
++void
++kexgss_server(Kex *kex)
++{
++	OM_uint32 maj_status, min_status;
++	
++	/* 
++	 * Some GSSAPI implementations use the input value of ret_flags (an
++ 	 * output variable) as a means of triggering mechanism specific 
++ 	 * features. Initializing it to zero avoids inadvertently 
++ 	 * activating this non-standard behaviour.
++	 */
++
++	OM_uint32 ret_flags = 0;
++	gss_buffer_desc gssbuf, recv_tok, msg_tok;
++	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
++	Gssctxt *ctxt = NULL;
++	u_int slen, klen, kout, hashlen;
++	u_char *kbuf, *hash;
++	DH *dh;
++	int min = -1, max = -1, nbits = -1;
++	BIGNUM *shared_secret = NULL;
++	BIGNUM *dh_client_pub = NULL;
++	int type = 0;
++	gss_OID oid;
++	char *mechs;
++
++	/* Initialise GSSAPI */
++
++	/* If we're rekeying, privsep means that some of the private structures
++	 * in the GSSAPI code are no longer available. This kludges them back
++	 * into life
++	 */
++	if (!ssh_gssapi_oid_table_ok()) 
++		if ((mechs = ssh_gssapi_server_mechanisms()))
++			xfree(mechs);
++
++	debug2("%s: Identifying %s", __func__, kex->name);
++	oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type);
++	if (oid == GSS_C_NO_OID)
++	   fatal("Unknown gssapi mechanism");
++
++	debug2("%s: Acquiring credentials", __func__);
++
++	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
++		fatal("Unable to acquire credentials for the server");
++
++	switch (kex->kex_type) {
++	case KEX_GSS_GRP1_SHA1:
++		dh = dh_new_group1();
++		break;
++	case KEX_GSS_GRP14_SHA1:
++		dh = dh_new_group14();
++		break;
++	case KEX_GSS_GEX_SHA1:
++		debug("Doing group exchange");
++		packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ);
++		min = packet_get_int();
++		nbits = packet_get_int();
++		max = packet_get_int();
++		min = MAX(DH_GRP_MIN, min);
++		max = MIN(DH_GRP_MAX, max);
++		packet_check_eom();
++		if (max < min || nbits < min || max < nbits)
++			fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
++			    min, nbits, max);
++		dh = PRIVSEP(choose_dh(min, nbits, max));
++		if (dh == NULL)
++			packet_disconnect("Protocol error: no matching group found");
++
++		packet_start(SSH2_MSG_KEXGSS_GROUP);
++		packet_put_bignum2(dh->p);
++		packet_put_bignum2(dh->g);
++		packet_send();
++
++		packet_write_wait();
++		break;
++	default:
++		fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
++	}
++
++	dh_gen_key(dh, kex->we_need * 8);
++
++	do {
++		debug("Wait SSH2_MSG_GSSAPI_INIT");
++		type = packet_read();
++		switch(type) {
++		case SSH2_MSG_KEXGSS_INIT:
++			if (dh_client_pub != NULL) 
++				fatal("Received KEXGSS_INIT after initialising");
++			recv_tok.value = packet_get_string(&slen);
++			recv_tok.length = slen; 
++
++			if ((dh_client_pub = BN_new()) == NULL)
++				fatal("dh_client_pub == NULL");
++
++			packet_get_bignum2(dh_client_pub);
++
++			/* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
++			break;
++		case SSH2_MSG_KEXGSS_CONTINUE:
++			recv_tok.value = packet_get_string(&slen);
++			recv_tok.length = slen; 
++			break;
++		default:
++			packet_disconnect(
++			    "Protocol error: didn't expect packet type %d",
++			    type);
++		}
++
++		maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, 
++		    &send_tok, &ret_flags));
++
++		xfree(recv_tok.value);
++
++		if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
++			fatal("Zero length token output when incomplete");
++
++		if (dh_client_pub == NULL)
++			fatal("No client public key");
++		
++		if (maj_status & GSS_S_CONTINUE_NEEDED) {
++			debug("Sending GSSAPI_CONTINUE");
++			packet_start(SSH2_MSG_KEXGSS_CONTINUE);
++			packet_put_string(send_tok.value, send_tok.length);
++			packet_send();
++			gss_release_buffer(&min_status, &send_tok);
++		}
++	} while (maj_status & GSS_S_CONTINUE_NEEDED);
++
++	if (GSS_ERROR(maj_status)) {
++		if (send_tok.length > 0) {
++			packet_start(SSH2_MSG_KEXGSS_CONTINUE);
++			packet_put_string(send_tok.value, send_tok.length);
++			packet_send();
++		}
++		fatal("accept_ctx died");
++	}
++
++	if (!(ret_flags & GSS_C_MUTUAL_FLAG))
++		fatal("Mutual Authentication flag wasn't set");
++
++	if (!(ret_flags & GSS_C_INTEG_FLAG))
++		fatal("Integrity flag wasn't set");
++	
++	if (!dh_pub_is_valid(dh, dh_client_pub))
++		packet_disconnect("bad client public DH value");
++
++	klen = DH_size(dh);
++	kbuf = xmalloc(klen); 
++	kout = DH_compute_key(kbuf, dh_client_pub, dh);
++	if (kout < 0)
++		fatal("DH_compute_key: failed");
++
++	shared_secret = BN_new();
++	if (shared_secret == NULL)
++		fatal("kexgss_server: BN_new failed");
++
++	if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
++		fatal("kexgss_server: BN_bin2bn failed");
++
++	memset(kbuf, 0, klen);
++	xfree(kbuf);
++
++	switch (kex->kex_type) {
++	case KEX_GSS_GRP1_SHA1:
++	case KEX_GSS_GRP14_SHA1:
++		kex_dh_hash(
++		    kex->client_version_string, kex->server_version_string,
++		    buffer_ptr(&kex->peer), buffer_len(&kex->peer),
++		    buffer_ptr(&kex->my), buffer_len(&kex->my),
++		    NULL, 0, /* Change this if we start sending host keys */
++		    dh_client_pub, dh->pub_key, shared_secret,
++		    &hash, &hashlen
++		);
++		break;
++	case KEX_GSS_GEX_SHA1:
++		kexgex_hash(
++		    kex->evp_md,
++		    kex->client_version_string, kex->server_version_string,
++		    buffer_ptr(&kex->peer), buffer_len(&kex->peer),
++		    buffer_ptr(&kex->my), buffer_len(&kex->my),
++		    NULL, 0,
++		    min, nbits, max,
++		    dh->p, dh->g,
++		    dh_client_pub,
++		    dh->pub_key,
++		    shared_secret,
++		    &hash, &hashlen
++		);
++		break;
++	default:
++		fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
++	}
++
++	BN_clear_free(dh_client_pub);
++
++	if (kex->session_id == NULL) {
++		kex->session_id_len = hashlen;
++		kex->session_id = xmalloc(kex->session_id_len);
++		memcpy(kex->session_id, hash, kex->session_id_len);
++	}
++
++	gssbuf.value = hash;
++	gssbuf.length = hashlen;
++
++	if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok))))
++		fatal("Couldn't get MIC");
++
++	packet_start(SSH2_MSG_KEXGSS_COMPLETE);
++	packet_put_bignum2(dh->pub_key);
++	packet_put_string(msg_tok.value,msg_tok.length);
++
++	if (send_tok.length != 0) {
++		packet_put_char(1); /* true */
++		packet_put_string(send_tok.value, send_tok.length);
++	} else {
++		packet_put_char(0); /* false */
++	}
++	packet_send();
++
++	gss_release_buffer(&min_status, &send_tok);
++	gss_release_buffer(&min_status, &msg_tok);
++
++	if (gss_kex_context == NULL)
++		gss_kex_context = ctxt;
++	else 
++		ssh_gssapi_delete_ctx(&ctxt);
++
++	DH_free(dh);
++
++	kex_derive_keys(kex, hash, hashlen, shared_secret);
++	BN_clear_free(shared_secret);
++	kex_finish(kex);
++
++	/* If this was a rekey, then save out any delegated credentials we
++	 * just exchanged.  */
++	if (options.gss_store_rekey)
++		ssh_gssapi_rekey_creds();
++}
++#endif /* GSSAPI */
+diff -up openssh-5.3p1/kex.h.gsskex openssh-5.3p1/kex.h
+--- openssh-5.3p1/kex.h.gsskex	2009-06-21 10:15:25.000000000 +0200
++++ openssh-5.3p1/kex.h	2009-11-20 14:39:05.000000000 +0100
+@@ -66,6 +66,9 @@ enum kex_exchange {
+ 	KEX_DH_GRP14_SHA1,
+ 	KEX_DH_GEX_SHA1,
+ 	KEX_DH_GEX_SHA256,
++	KEX_GSS_GRP1_SHA1,
++	KEX_GSS_GRP14_SHA1,
++	KEX_GSS_GEX_SHA1,
+ 	KEX_MAX
+ };
+ 
+@@ -121,6 +124,12 @@ struct Kex {
+ 	sig_atomic_t done;
+ 	int	flags;
+ 	const EVP_MD *evp_md;
++#ifdef GSSAPI
++	int	gss_deleg_creds;
++	int	gss_trust_dns;
++	char    *gss_host;
++	char	*gss_client;
++#endif
+ 	char	*client_version_string;
+ 	char	*server_version_string;
+ 	int	(*verify_host_key)(Key *);
+@@ -143,6 +152,11 @@ void	 kexdh_server(Kex *);
+ void	 kexgex_client(Kex *);
+ void	 kexgex_server(Kex *);
+ 
++#ifdef GSSAPI
++void	kexgss_client(Kex *);
++void	kexgss_server(Kex *);
++#endif
++
+ void
+ kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
+     BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *);
+diff -up openssh-5.3p1/key.c.gsskex openssh-5.3p1/key.c
+--- openssh-5.3p1/key.c.gsskex	2009-11-20 14:38:59.000000000 +0100
++++ openssh-5.3p1/key.c	2009-11-20 14:39:05.000000000 +0100
+@@ -825,6 +825,8 @@ key_type_from_name(char *name)
+ 		return KEY_RSA;
+ 	} else if (strcmp(name, "ssh-dss") == 0) {
+ 		return KEY_DSA;
++	} else if (strcmp(name, "null") == 0) {
++		return KEY_NULL;
+ 	}
+ 	debug2("key_type_from_name: unknown key type '%s'", name);
+ 	return KEY_UNSPEC;
+diff -up openssh-5.3p1/key.h.gsskex openssh-5.3p1/key.h
+--- openssh-5.3p1/key.h.gsskex	2009-11-20 14:38:59.000000000 +0100
++++ openssh-5.3p1/key.h	2009-11-20 14:50:59.000000000 +0100
+@@ -40,6 +40,7 @@ enum types {
+ 	KEY_RSA,
+ 	KEY_DSA,
+ 	KEY_NSS,
++	KEY_NULL,
+ 	KEY_UNSPEC
+ };
+ enum fp_type {
+diff -up openssh-5.3p1/Makefile.in.gsskex openssh-5.3p1/Makefile.in
+--- openssh-5.3p1/Makefile.in.gsskex	2009-11-20 14:39:02.000000000 +0100
++++ openssh-5.3p1/Makefile.in	2009-11-20 15:06:44.000000000 +0100
+@@ -71,7 +71,8 @@ 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 nsskeys.o
++	entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o nsskeys.o \
++	kexgssc.o
+ 
+ SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
+ 	sshconnect.o sshconnect1.o sshconnect2.o mux.o \
+@@ -85,7 +86,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw
+ 	auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-jpake.o \
+ 	monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \
+ 	auth-krb5.o \
+-	auth2-gss.o gss-serv.o gss-serv-krb5.o \
++ 	auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\
+ 	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
+ 	audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \
+ 	roaming_common.o
+diff -up openssh-5.3p1/monitor.c.gsskex openssh-5.3p1/monitor.c
+--- openssh-5.3p1/monitor.c.gsskex	2009-11-20 14:38:55.000000000 +0100
++++ openssh-5.3p1/monitor.c	2009-11-20 14:39:05.000000000 +0100
+@@ -175,6 +175,8 @@ int mm_answer_gss_setup_ctx(int, Buffer 
+ int mm_answer_gss_accept_ctx(int, Buffer *);
+ int mm_answer_gss_userok(int, Buffer *);
+ int mm_answer_gss_checkmic(int, Buffer *);
++int mm_answer_gss_sign(int, Buffer *);
++int mm_answer_gss_updatecreds(int, Buffer *);
+ #endif
+ 
+ #ifdef SSH_AUDIT_EVENTS
+@@ -247,6 +249,7 @@ struct mon_table mon_dispatch_proto20[] 
+     {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
+     {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
+     {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
++    {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
+ #endif
+ #ifdef JPAKE
+     {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata},
+@@ -259,6 +262,12 @@ struct mon_table mon_dispatch_proto20[] 
+ };
+ 
+ struct mon_table mon_dispatch_postauth20[] = {
++#ifdef GSSAPI
++    {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
++    {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
++    {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
++    {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
++#endif
+     {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
+     {MONITOR_REQ_SIGN, 0, mm_answer_sign},
+     {MONITOR_REQ_PTY, 0, mm_answer_pty},
+@@ -363,6 +372,10 @@ monitor_child_preauth(Authctxt *_authctx
+ 		/* Permit requests for moduli and signatures */
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
++#ifdef GSSAPI
++		/* and for the GSSAPI key exchange */
++		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
++#endif
+ 	} else {
+ 		mon_dispatch = mon_dispatch_proto15;
+ 
+@@ -449,6 +462,10 @@ monitor_child_postauth(struct monitor *p
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
++#ifdef GSSAPI
++		/* and for the GSSAPI key exchange */
++		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
++#endif		
+ 	} else {
+ 		mon_dispatch = mon_dispatch_postauth15;
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
+@@ -1738,6 +1755,13 @@ mm_get_kex(Buffer *m)
+ 	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->hostkey_type = buffer_get_int(m);
+ 	kex->kex_type = buffer_get_int(m);
+@@ -1943,6 +1967,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer
+ 	OM_uint32 major;
+ 	u_int len;
+ 
++	if (!options.gss_authentication && !options.gss_keyex)
++		fatal("In GSSAPI monitor when GSSAPI is disabled");
++
+ 	goid.elements = buffer_get_string(m, &len);
+ 	goid.length = len;
+ 
+@@ -1970,6 +1997,9 @@ mm_answer_gss_accept_ctx(int sock, Buffe
+ 	OM_uint32 flags = 0; /* GSI needs this */
+ 	u_int len;
+ 
++	if (!options.gss_authentication && !options.gss_keyex)
++		fatal("In GSSAPI monitor when GSSAPI is disabled");
++
+ 	in.value = buffer_get_string(m, &len);
+ 	in.length = len;
+ 	major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
+@@ -1987,6 +2017,7 @@ mm_answer_gss_accept_ctx(int sock, Buffe
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
+ 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
++		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
+ 	}
+ 	return (0);
+ }
+@@ -1998,6 +2029,9 @@ mm_answer_gss_checkmic(int sock, Buffer 
+ 	OM_uint32 ret;
+ 	u_int len;
+ 
++	if (!options.gss_authentication && !options.gss_keyex)
++		fatal("In GSSAPI monitor when GSSAPI is disabled");
++
+ 	gssbuf.value = buffer_get_string(m, &len);
+ 	gssbuf.length = len;
+ 	mic.value = buffer_get_string(m, &len);
+@@ -2024,7 +2058,11 @@ mm_answer_gss_userok(int sock, Buffer *m
+ {
+ 	int authenticated;
+ 
+-	authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
++	if (!options.gss_authentication && !options.gss_keyex)
++		fatal("In GSSAPI monitor when GSSAPI is disabled");
++
++	authenticated = authctxt->valid && 
++	    ssh_gssapi_userok(authctxt->user, authctxt->pw);
+ 
+ 	buffer_clear(m);
+ 	buffer_put_int(m, authenticated);
+@@ -2037,6 +2075,74 @@ mm_answer_gss_userok(int sock, Buffer *m
+ 	/* Monitor loop will terminate if authenticated */
+ 	return (authenticated);
+ }
++
++int 
++mm_answer_gss_sign(int socket, Buffer *m)
++{
++	gss_buffer_desc data;
++	gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
++	OM_uint32 major, minor;
++	u_int len;
++
++	if (!options.gss_authentication && !options.gss_keyex)
++		fatal("In GSSAPI monitor when GSSAPI is disabled");
++
++	data.value = buffer_get_string(m, &len);
++	data.length = len;
++	if (data.length != 20) 
++		fatal("%s: data length incorrect: %d", __func__, 
++		    (int) data.length);
++
++	/* Save the session ID on the first time around */
++	if (session_id2_len == 0) {
++		session_id2_len = data.length;
++		session_id2 = xmalloc(session_id2_len);
++		memcpy(session_id2, data.value, session_id2_len);
++	}
++	major = ssh_gssapi_sign(gsscontext, &data, &hash);
++
++	xfree(data.value);
++
++	buffer_clear(m);
++	buffer_put_int(m, major);
++	buffer_put_string(m, hash.value, hash.length);
++
++	mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
++
++	gss_release_buffer(&minor, &hash);
++
++	/* Turn on getpwnam permissions */
++	monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
++	
++	/* And credential updating, for when rekeying */
++	monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1);
++
++	return (0);
++}
++
++int
++mm_answer_gss_updatecreds(int socket, Buffer *m) {
++	ssh_gssapi_ccache store;
++	int ok;
++
++	store.filename = buffer_get_string(m, NULL);
++	store.envvar   = buffer_get_string(m, NULL);
++	store.envval   = buffer_get_string(m, NULL);
++
++	ok = ssh_gssapi_update_creds(&store);
++
++	xfree(store.filename);
++	xfree(store.envvar);
++	xfree(store.envval);
++
++	buffer_clear(m);
++	buffer_put_int(m, ok);
++
++	mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m);
++
++	return(0);
++}
++
+ #endif /* GSSAPI */
+ 
+ #ifdef JPAKE
+diff -up openssh-5.3p1/monitor.h.gsskex openssh-5.3p1/monitor.h
+--- openssh-5.3p1/monitor.h.gsskex	2009-11-20 14:38:55.000000000 +0100
++++ openssh-5.3p1/monitor.h	2009-11-20 14:39:05.000000000 +0100
+@@ -56,6 +56,8 @@ enum monitor_reqtype {
+ 	MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP,
+ 	MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK,
+ 	MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC,
++	MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN,
++	MONITOR_REQ_GSSUPCREDS, MONITOR_ANS_GSSUPCREDS,
+ 	MONITOR_REQ_PAM_START,
+ 	MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT,
+ 	MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX,
+diff -up openssh-5.3p1/monitor_wrap.c.gsskex openssh-5.3p1/monitor_wrap.c
+--- openssh-5.3p1/monitor_wrap.c.gsskex	2009-11-20 14:38:55.000000000 +0100
++++ openssh-5.3p1/monitor_wrap.c	2009-11-20 14:39:05.000000000 +0100
+@@ -1267,7 +1267,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss
+ }
+ 
+ int
+-mm_ssh_gssapi_userok(char *user)
++mm_ssh_gssapi_userok(char *user, struct passwd *pw)
+ {
+ 	Buffer m;
+ 	int authenticated = 0;
+@@ -1284,6 +1284,51 @@ mm_ssh_gssapi_userok(char *user)
+ 	debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
+ 	return (authenticated);
+ }
++
++OM_uint32
++mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
++{
++	Buffer m;
++	OM_uint32 major;
++	u_int len;
++
++	buffer_init(&m);
++	buffer_put_string(&m, data->value, data->length);
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
++
++	major = buffer_get_int(&m);
++	hash->value = buffer_get_string(&m, &len);
++	hash->length = len;
++
++	buffer_free(&m);
++
++	return(major);
++}
++
++int
++mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store)
++{
++	Buffer m;
++	int ok;
++
++	buffer_init(&m);
++
++	buffer_put_cstring(&m, store->filename ? store->filename : "");
++	buffer_put_cstring(&m, store->envvar ? store->envvar : "");
++	buffer_put_cstring(&m, store->envval ? store->envval : "");
++	
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m);
++
++	ok = buffer_get_int(&m);
++
++	buffer_free(&m);
++	
++	return (ok);
++}
++
+ #endif /* GSSAPI */
+ 
+ #ifdef JPAKE
+diff -up openssh-5.3p1/monitor_wrap.h.gsskex openssh-5.3p1/monitor_wrap.h
+--- openssh-5.3p1/monitor_wrap.h.gsskex	2009-11-20 14:38:55.000000000 +0100
++++ openssh-5.3p1/monitor_wrap.h	2009-11-20 14:39:05.000000000 +0100
+@@ -60,8 +60,10 @@ BIGNUM *mm_auth_rsa_generate_challenge(K
+ OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
+ OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
+    gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
+-int mm_ssh_gssapi_userok(char *user);
++int mm_ssh_gssapi_userok(char *user, struct passwd *);
+ OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
++OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
++int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
+ #endif
+ 
+ #ifdef USE_PAM
+diff -up openssh-5.3p1/readconf.c.gsskex openssh-5.3p1/readconf.c
+--- openssh-5.3p1/readconf.c.gsskex	2009-11-20 14:38:59.000000000 +0100
++++ openssh-5.3p1/readconf.c	2009-11-20 14:39:06.000000000 +0100
+@@ -128,6 +128,7 @@ typedef enum {
+ 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
+ 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
+ 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
++	oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey,
+ 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
+ 	oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
+ 	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
+@@ -165,10 +166,18 @@ static struct {
+ 	{ "afstokenpassing", oUnsupported },
+ #if defined(GSSAPI)
+ 	{ "gssapiauthentication", oGssAuthentication },
++	{ "gssapikeyexchange", oGssKeyEx },
+ 	{ "gssapidelegatecredentials", oGssDelegateCreds },
++	{ "gssapitrustdns", oGssTrustDns },
++	{ "gssapiclientidentity", oGssClientIdentity },
++	{ "gssapirenewalforcesrekey", oGssRenewalRekey },
+ #else
+ 	{ "gssapiauthentication", oUnsupported },
++	{ "gssapikeyexchange", oUnsupported },
+ 	{ "gssapidelegatecredentials", oUnsupported },
++	{ "gssapitrustdns", oUnsupported },
++	{ "gssapiclientidentity", oUnsupported },
++	{ "gssapirenewalforcesrekey", oUnsupported },
+ #endif
+ 	{ "fallbacktorsh", oDeprecated },
+ 	{ "usersh", oDeprecated },
+@@ -462,10 +471,26 @@ parse_flag:
+ 		intptr = &options->gss_authentication;
+ 		goto parse_flag;
+ 
++	case oGssKeyEx:
++		intptr = &options->gss_keyex;
++		goto parse_flag;
++
+ 	case oGssDelegateCreds:
+ 		intptr = &options->gss_deleg_creds;
+ 		goto parse_flag;
+ 
++	case oGssTrustDns:
++		intptr = &options->gss_trust_dns;
++		goto parse_flag;
++
++	case oGssClientIdentity:
++		charptr = &options->gss_client_identity;
++		goto parse_string;
++
++	case oGssRenewalRekey:
++		intptr = &options->gss_renewal_rekey;
++		goto parse_flag;
++
+ 	case oBatchMode:
+ 		intptr = &options->batch_mode;
+ 		goto parse_flag;
+@@ -1029,7 +1054,11 @@ initialize_options(Options * options)
+ 	options->pubkey_authentication = -1;
+ 	options->challenge_response_authentication = -1;
+ 	options->gss_authentication = -1;
++	options->gss_keyex = -1;
+ 	options->gss_deleg_creds = -1;
++	options->gss_trust_dns = -1;
++	options->gss_renewal_rekey = -1;
++	options->gss_client_identity = NULL;
+ 	options->password_authentication = -1;
+ 	options->kbd_interactive_authentication = -1;
+ 	options->kbd_interactive_devices = NULL;
+@@ -1123,8 +1152,14 @@ fill_default_options(Options * options)
+ 		options->challenge_response_authentication = 1;
+ 	if (options->gss_authentication == -1)
+ 		options->gss_authentication = 0;
++	if (options->gss_keyex == -1)
++		options->gss_keyex = 0;
+ 	if (options->gss_deleg_creds == -1)
+ 		options->gss_deleg_creds = 0;
++	if (options->gss_trust_dns == -1)
++		options->gss_trust_dns = 0;
++	if (options->gss_renewal_rekey == -1)
++		options->gss_renewal_rekey = 0;
+ 	if (options->password_authentication == -1)
+ 		options->password_authentication = 1;
+ 	if (options->kbd_interactive_authentication == -1)
+diff -up openssh-5.3p1/readconf.h.gsskex openssh-5.3p1/readconf.h
+--- openssh-5.3p1/readconf.h.gsskex	2009-11-20 14:38:59.000000000 +0100
++++ openssh-5.3p1/readconf.h	2009-11-20 14:39:06.000000000 +0100
+@@ -44,7 +44,11 @@ typedef struct {
+ 	int     challenge_response_authentication;
+ 					/* Try S/Key or TIS, authentication. */
+ 	int     gss_authentication;	/* Try GSS authentication */
++	int     gss_keyex;		/* Try GSS key exchange */
+ 	int     gss_deleg_creds;	/* Delegate GSS credentials */
++	int	gss_trust_dns;		/* Trust DNS for GSS canonicalization */
++	int	gss_renewal_rekey;	/* Credential renewal forces rekey */
++	char    *gss_client_identity;   /* Principal to initiate GSSAPI with */
+ 	int     password_authentication;	/* Try password
+ 						 * authentication. */
+ 	int     kbd_interactive_authentication; /* Try keyboard-interactive auth. */
+diff -up openssh-5.3p1/servconf.c.gsskex openssh-5.3p1/servconf.c
+--- openssh-5.3p1/servconf.c.gsskex	2009-11-20 14:39:03.000000000 +0100
++++ openssh-5.3p1/servconf.c	2009-11-20 14:52:27.000000000 +0100
+@@ -92,7 +92,10 @@ initialize_server_options(ServerOptions 
+ 	options->kerberos_ticket_cleanup = -1;
+ 	options->kerberos_get_afs_token = -1;
+ 	options->gss_authentication=-1;
++	options->gss_keyex = -1;
+ 	options->gss_cleanup_creds = -1;
++	options->gss_strict_acceptor = -1;
++	options->gss_store_rekey = -1;
+ 	options->password_authentication = -1;
+ 	options->kbd_interactive_authentication = -1;
+ 	options->challenge_response_authentication = -1;
+@@ -213,8 +216,14 @@ fill_default_server_options(ServerOption
+ 		options->kerberos_get_afs_token = 0;
+ 	if (options->gss_authentication == -1)
+ 		options->gss_authentication = 0;
++	if (options->gss_keyex == -1)
++		options->gss_keyex = 0;
+ 	if (options->gss_cleanup_creds == -1)
+ 		options->gss_cleanup_creds = 1;
++	if (options->gss_strict_acceptor == -1)
++		options->gss_strict_acceptor = 1;
++	if (options->gss_store_rekey == -1)
++		options->gss_store_rekey = 0;
+ 	if (options->password_authentication == -1)
+ 		options->password_authentication = 1;
+ 	if (options->kbd_interactive_authentication == -1)
+@@ -308,7 +317,9 @@ typedef enum {
+ 	sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication,
+ 	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
+ 	sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
+-	sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
++	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
++	sGssKeyEx, sGssStoreRekey,
++	sAcceptEnv, sPermitTunnel,
+ 	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
+ 	sUsePrivilegeSeparation, sAllowAgentForwarding,
+ 	sZeroKnowledgePasswordAuthentication,
+@@ -371,9 +382,15 @@ static struct {
+ #ifdef GSSAPI
+ 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
+ 	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
++	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
++	{ "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
++	{ "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
+ #else
+ 	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
+ 	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
++	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
++	{ "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
++	{ "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
+ #endif
+ 	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
+ 	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
+@@ -906,10 +923,22 @@ process_server_config_line(ServerOptions
+ 		intptr = &options->gss_authentication;
+ 		goto parse_flag;
+ 
++	case sGssKeyEx:
++		intptr = &options->gss_keyex;
++		goto parse_flag;
++
+ 	case sGssCleanupCreds:
+ 		intptr = &options->gss_cleanup_creds;
+ 		goto parse_flag;
+ 
++	case sGssStrictAcceptor:
++		intptr = &options->gss_strict_acceptor;
++		goto parse_flag;
++
++	case sGssStoreRekey:
++		intptr = &options->gss_store_rekey;
++		goto parse_flag;
++
+ 	case sPasswordAuthentication:
+ 		intptr = &options->password_authentication;
+ 		goto parse_flag;
+diff -up openssh-5.3p1/servconf.h.gsskex openssh-5.3p1/servconf.h
+--- openssh-5.3p1/servconf.h.gsskex	2009-11-20 14:39:03.000000000 +0100
++++ openssh-5.3p1/servconf.h	2009-11-20 14:39:06.000000000 +0100
+@@ -91,7 +91,10 @@ typedef struct {
+ 	int     kerberos_get_afs_token;		/* If true, try to get AFS token if
+ 						 * authenticated with Kerberos. */
+ 	int     gss_authentication;	/* If true, permit GSSAPI authentication */
++	int     gss_keyex;		/* If true, permit GSSAPI key exchange */
+ 	int     gss_cleanup_creds;	/* If true, destroy cred cache on logout */
++	int 	gss_strict_acceptor;	/* If true, restrict the GSSAPI acceptor name */
++	int 	gss_store_rekey;
+ 	int     password_authentication;	/* If true, permit password
+ 						 * authentication. */
+ 	int     kbd_interactive_authentication;	/* If true, permit */
+diff -up openssh-5.3p1/ssh_config.5.gsskex openssh-5.3p1/ssh_config.5
+--- openssh-5.3p1/ssh_config.5.gsskex	2009-02-23 00:53:58.000000000 +0100
++++ openssh-5.3p1/ssh_config.5	2009-11-20 14:39:06.000000000 +0100
+@@ -478,11 +478,38 @@ 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 may be used. When using
++GSSAPI key exchange the server need not have a host key.
++The default is
++.Dq no .
++Note that this option applies to protocol version 2 only.
++.It Cm GSSAPIClientIdentity
++If set, specifies the GSSAPI client identity that ssh should use when 
++connecting to the server. The default is unset, which means that the default 
++identity will be used.
+ .It Cm GSSAPIDelegateCredentials
+ Forward (delegate) credentials to the server.
+ The default is
+ .Dq no .
+-Note that this option applies to protocol version 2 only.
++Note that this option applies to protocol version 2 connections using GSSAPI.
++.It Cm GSSAPIRenewalForcesRekey
++If set to 
++.Dq yes
++then renewal of the client's GSSAPI credentials will force the rekeying of the
++ssh connection. With a compatible server, this can delegate the renewed 
++credentials to a session on the server.
++The default is
++.Dq no .
++.It Cm GSSAPITrustDns
++Set to 
++.Dq yes to indicate that the DNS is trusted to securely canonicalize
++the name of the host being connected to. If 
++.Dq no, the hostname entered on the
++command line will be passed untouched to the GSSAPI library.
++The default is
++.Dq no .
++This option only applies to protocol version 2 connections using GSSAPI.
+ .It Cm HashKnownHosts
+ Indicates that
+ .Xr ssh 1
+diff -up openssh-5.3p1/ssh_config.gsskex openssh-5.3p1/ssh_config
+--- openssh-5.3p1/ssh_config.gsskex	2009-11-20 14:38:53.000000000 +0100
++++ openssh-5.3p1/ssh_config	2009-11-20 14:39:06.000000000 +0100
+@@ -26,6 +26,8 @@
+ #   HostbasedAuthentication no
+ #   GSSAPIAuthentication no
+ #   GSSAPIDelegateCredentials no
++#   GSSAPIKeyExchange no
++#   GSSAPITrustDNS no
+ #   BatchMode no
+ #   CheckHostIP yes
+ #   AddressFamily any
+diff -up openssh-5.3p1/sshconnect2.c.gsskex openssh-5.3p1/sshconnect2.c
+--- openssh-5.3p1/sshconnect2.c.gsskex	2009-11-20 14:39:01.000000000 +0100
++++ openssh-5.3p1/sshconnect2.c	2009-11-20 15:05:03.000000000 +0100
+@@ -108,9 +108,34 @@ ssh_kex2(char *host, struct sockaddr *ho
+ {
+ 	Kex *kex;
+ 
++#ifdef GSSAPI
++	char *orig = NULL, *gss = NULL;
++	char *gss_host = NULL;
++#endif
++
+ 	xxx_host = host;
+ 	xxx_hostaddr = hostaddr;
+ 
++#ifdef GSSAPI
++	if (options.gss_keyex) {
++		/* Add the GSSAPI mechanisms currently supported on this 
++		 * client to the key exchange algorithm proposal */
++		orig = myproposal[PROPOSAL_KEX_ALGS];
++
++		if (options.gss_trust_dns)
++			gss_host = (char *)get_canonical_hostname(1);
++		else
++			gss_host = host;
++
++		gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity);
++		if (gss) {
++			debug("Offering GSSAPI proposal: %s", gss);
++			xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
++			    "%s,%s", gss, orig);
++		}
++	}
++#endif
++
+ 	if (options.ciphers == (char *)-1) {
+ 		logit("No valid ciphers for protocol version 2 given, using defaults.");
+ 		options.ciphers = NULL;
+@@ -146,6 +171,17 @@ ssh_kex2(char *host, struct sockaddr *ho
+ 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
+ 		    options.hostkeyalgorithms;
+ 
++#ifdef GSSAPI
++	/* If we've got GSSAPI algorithms, then we also support the
++	 * 'null' hostkey, as a last resort */
++	if (options.gss_keyex && gss) {
++		orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
++		xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], 
++		    "%s,null", orig);
++		xfree(gss);
++	}
++#endif
++
+ 	if (options.rekey_limit)
+ 		packet_set_rekey_limit((u_int32_t)options.rekey_limit);
+ 
+@@ -155,10 +191,26 @@ ssh_kex2(char *host, struct sockaddr *ho
+ 	kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
+ 	kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
+ 	kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
++#ifdef GSSAPI
++	if (options.gss_keyex) {
++		kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
++		kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
++		kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
++	}
++#endif
+ 	kex->client_version_string=client_version_string;
+ 	kex->server_version_string=server_version_string;
+ 	kex->verify_host_key=&verify_host_key_callback;
+ 
++#ifdef GSSAPI
++	if (options.gss_keyex) {
++		kex->gss_deleg_creds = options.gss_deleg_creds;
++		kex->gss_trust_dns = options.gss_trust_dns;
++		kex->gss_client = options.gss_client_identity;
++		kex->gss_host = gss_host;
++	}
++#endif
++
+ 	xxx_kex = kex;
+ 
+ 	dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
+@@ -247,6 +299,7 @@ void	input_gssapi_token(int type, u_int3
+ void	input_gssapi_hash(int type, u_int32_t, void *);
+ void	input_gssapi_error(int, u_int32_t, void *);
+ void	input_gssapi_errtok(int, u_int32_t, void *);
++int	userauth_gsskeyex(Authctxt *authctxt);
+ #endif
+ 
+ void	userauth(Authctxt *, char *);
+@@ -262,6 +315,11 @@ static char *authmethods_get(void);
+ 
+ Authmethod authmethods[] = {
+ #ifdef GSSAPI
++	{"gssapi-keyex",
++		userauth_gsskeyex,
++		NULL,
++		&options.gss_authentication,
++		NULL},
+ 	{"gssapi-with-mic",
+ 		userauth_gssapi,
+ 		NULL,
+@@ -555,23 +612,35 @@ userauth_gssapi(Authctxt *authctxt)
+ 	int ok = 0;
+ 	char* remotehost = NULL;
+ 	const char* canonicalhost = get_canonical_hostname(1);
++	const char *gss_host;
++
+ 	if ( strcmp( canonicalhost, "UNKNOWN" )  == 0 )
+ 		remotehost = authctxt->host;
+ 	else
+ 		remotehost = canonicalhost;
+ 
++	if (options.gss_trust_dns)
++//		gss_host = get_canonical_hostname(1);
++		gss_host = remotehost;
++	else
++		gss_host = authctxt->host;
++
+ 	/* Try one GSSAPI method at a time, rather than sending them all at
+ 	 * once. */
+ 
+ 	if (gss_supported == NULL)
+-		gss_indicate_mechs(&min, &gss_supported);
++		if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
++			gss_supported = NULL;
++			return 0;
++		}
+ 
+ 	/* Check to see if the mechanism is usable before we offer it */
+ 	while (mech < gss_supported->count && !ok) {
+ 		/* My DER encoding requires length<128 */
+ 		if (gss_supported->elements[mech].length < 128 &&
+ 		    ssh_gssapi_check_mechanism(&gssctxt, 
+-		    &gss_supported->elements[mech], remotehost)) {
++		    &gss_supported->elements[mech], gss_host, 
++		    options.gss_client_identity)) {
+ 			ok = 1; /* Mechanism works */
+ 		} else {
+ 			mech++;
+@@ -668,8 +737,8 @@ input_gssapi_response(int type, u_int32_
+ {
+ 	Authctxt *authctxt = ctxt;
+ 	Gssctxt *gssctxt;
+-	int oidlen;
+-	char *oidv;
++	u_int oidlen;
++	u_char *oidv;
+ 
+ 	if (authctxt == NULL)
+ 		fatal("input_gssapi_response: no authentication context");
+@@ -779,6 +848,48 @@ input_gssapi_error(int type, u_int32_t p
+ 	xfree(msg);
+ 	xfree(lang);
+ }
++
++int
++userauth_gsskeyex(Authctxt *authctxt)
++{
++	Buffer b;
++	gss_buffer_desc gssbuf;
++	gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
++	OM_uint32 ms;
++
++	static int attempt = 0;
++	if (attempt++ >= 1)
++		return (0);
++
++	if (gss_kex_context == NULL) {
++		debug("No valid Key exchange context"); 
++		return (0);
++	}
++
++	ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
++	    "gssapi-keyex");
++
++	gssbuf.value = buffer_ptr(&b);
++	gssbuf.length = buffer_len(&b);
++
++	if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
++		buffer_free(&b);
++		return (0);
++	}
++
++	packet_start(SSH2_MSG_USERAUTH_REQUEST);
++	packet_put_cstring(authctxt->server_user);
++	packet_put_cstring(authctxt->service);
++	packet_put_cstring(authctxt->method->name);
++	packet_put_string(mic.value, mic.length);
++	packet_send();
++
++	buffer_free(&b);
++	gss_release_buffer(&ms, &mic);
++
++	return (1);
++}
++
+ #endif /* GSSAPI */
+ 
+ int
+diff -up openssh-5.3p1/sshd.c.gsskex openssh-5.3p1/sshd.c
+--- openssh-5.3p1/sshd.c.gsskex	2009-11-20 14:39:01.000000000 +0100
++++ openssh-5.3p1/sshd.c	2009-11-20 14:53:31.000000000 +0100
+@@ -129,6 +129,10 @@ int allow_severity;
+ int deny_severity;
+ #endif /* LIBWRAP */
+ 
++#ifdef USE_SECURITY_SESSION_API
++#include <Security/AuthSession.h>
++#endif
++
+ #ifndef O_NOCTTY
+ #define O_NOCTTY	0
+ #endif
+@@ -1546,10 +1550,13 @@ main(int ac, char **av)
+ 		logit("Disabling protocol version 1. Could not load host key");
+ 		options.protocol &= ~SSH_PROTO_1;
+ 	}
++#ifndef GSSAPI
++	/* The GSSAPI key exchange can run without a host key */
+ 	if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
+ 		logit("Disabling protocol version 2. Could not load host key");
+ 		options.protocol &= ~SSH_PROTO_2;
+ 	}
++#endif
+ 	if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
+ 		logit("sshd: no hostkeys available -- exiting.");
+ 		exit(1);
+@@ -1837,6 +1844,60 @@ main(int ac, char **av)
+ 	/* Log the connection. */
+ 	verbose("Connection from %.500s port %d", remote_ip, remote_port);
+ 
++#ifdef USE_SECURITY_SESSION_API
++	/*
++	 * Create a new security session for use by the new user login if
++	 * the current session is the root session or we are not launched
++	 * by inetd (eg: debugging mode or server mode).  We do not
++	 * necessarily need to create a session if we are launched from
++	 * inetd because Panther xinetd will create a session for us.
++	 *
++	 * The only case where this logic will fail is if there is an
++	 * inetd running in a non-root session which is not creating
++	 * new sessions for us.  Then all the users will end up in the
++	 * same session (bad).
++	 *
++	 * When the client exits, the session will be destroyed for us
++	 * automatically.
++	 *
++	 * We must create the session before any credentials are stored
++	 * (including AFS pags, which happens a few lines below).
++	 */
++	{
++		OSStatus err = 0;
++		SecuritySessionId sid = 0;
++		SessionAttributeBits sattrs = 0;
++
++		err = SessionGetInfo(callerSecuritySession, &sid, &sattrs);
++		if (err)
++			error("SessionGetInfo() failed with error %.8X",
++			    (unsigned) err);
++		else
++			debug("Current Session ID is %.8X / Session Attributes are %.8X",
++			    (unsigned) sid, (unsigned) sattrs);
++
++		if (inetd_flag && !(sattrs & sessionIsRoot))
++			debug("Running in inetd mode in a non-root session... "
++			    "assuming inetd created the session for us.");
++		else {
++			debug("Creating new security session...");
++			err = SessionCreate(0, sessionHasTTY | sessionIsRemote);
++			if (err)
++				error("SessionCreate() failed with error %.8X",
++				    (unsigned) err);
++
++			err = SessionGetInfo(callerSecuritySession, &sid, 
++			    &sattrs);
++			if (err)
++				error("SessionGetInfo() failed with error %.8X",
++				    (unsigned) err);
++			else
++				debug("New Session ID is %.8X / Session Attributes are %.8X",
++				    (unsigned) sid, (unsigned) sattrs);
++		}
++	}
++#endif
++
+ 	/*
+ 	 * We don't want to listen forever unless the other side
+ 	 * successfully authenticates itself.  So we set up an alarm which is
+@@ -2223,12 +2284,61 @@ do_ssh2_kex(void)
+ 
+ 	myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
+ 
++#ifdef GSSAPI
++	{
++	char *orig;
++	char *gss = NULL;
++	char *newstr = NULL;
++	orig = myproposal[PROPOSAL_KEX_ALGS];
++
++	/* 
++	 * If we don't have a host key, then there's no point advertising
++	 * the other key exchange algorithms
++	 */
++
++	if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
++		orig = NULL;
++
++	if (options.gss_keyex)
++		gss = ssh_gssapi_server_mechanisms();
++	else
++		gss = NULL;
++
++	if (gss && orig)
++		xasprintf(&newstr, "%s,%s", gss, orig);
++	else if (gss)
++		newstr = gss;
++	else if (orig)
++		newstr = orig;
++
++	/* 
++	 * If we've got GSSAPI mechanisms, then we've got the 'null' host
++	 * key alg, but we can't tell people about it unless its the only
++  	 * host key algorithm we support
++	 */
++	if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
++		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
++
++	if (newstr)
++		myproposal[PROPOSAL_KEX_ALGS] = newstr;
++	else
++		fatal("No supported key exchange algorithms");
++	}
++#endif
++
+ 	/* start key exchange */
+ 	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 */
diff --git a/openssh-5.3p1-keycat.patch b/openssh-5.3p1-keycat.patch
new file mode 100644
index 0000000..7d774c0
--- /dev/null
+++ b/openssh-5.3p1-keycat.patch
@@ -0,0 +1,371 @@
+diff -up openssh-5.3p1/auth2-pubkey.c.keycat openssh-5.3p1/auth2-pubkey.c
+--- openssh-5.3p1/auth2-pubkey.c.keycat	2011-03-08 12:12:06.000000000 +0100
++++ openssh-5.3p1/auth2-pubkey.c	2011-03-08 12:12:10.000000000 +0100
+@@ -395,6 +395,14 @@ user_key_via_command_allowed2(struct pas
+ 			close(i);
+ 		}
+ 
++#ifdef WITH_SELINUX
++		if (ssh_selinux_setup_env_variables() < 0) {
++			error ("failed to copy environment:  %s",
++			    strerror(errno));
++			_exit(127);
++		}
++#endif
++
+ 		execl(options.authorized_keys_command, options.authorized_keys_command, pw->pw_name, NULL);
+ 
+ 		/* if we got here, it didn't work */
+diff -up openssh-5.3p1/HOWTO.ssh-keycat.keycat openssh-5.3p1/HOWTO.ssh-keycat
+--- openssh-5.3p1/HOWTO.ssh-keycat.keycat	2011-03-08 12:12:10.000000000 +0100
++++ openssh-5.3p1/HOWTO.ssh-keycat	2011-03-08 12:13:19.000000000 +0100
+@@ -0,0 +1,12 @@
++The ssh-keycat retrieves the content of the ~/.ssh/authorized_keys
++of an user in any environment. This includes environments with
++polyinstantiation of home directories and SELinux MLS policy enabled.
++
++To use ssh-keycat, set these options in /etc/ssh/sshd_config file:
++        AuthorizedKeysCommand /usr/libexec/openssh/ssh-keycat
++        AuthorizedKeysCommandRunAs root
++
++Do not forget to enable public key authentication:
++        PubkeyAuthentication yes
++
++
+diff -up openssh-5.3p1/Makefile.in.keycat openssh-5.3p1/Makefile.in
+--- openssh-5.3p1/Makefile.in.keycat	2011-03-08 12:12:09.000000000 +0100
++++ openssh-5.3p1/Makefile.in	2011-03-08 12:12:10.000000000 +0100
+@@ -27,6 +27,7 @@ SFTP_SERVER=$(libexecdir)/sftp-server
+ SSH_KEYSIGN=$(libexecdir)/ssh-keysign
+ SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper
+ SSH_LDAP_WRAPPER=$(libexecdir)/ssh-ldap-wrapper
++SSH_KEYCAT=$(libexecdir)/ssh-keycat
+ RAND_HELPER=$(libexecdir)/ssh-rand-helper
+ PRIVSEP_PATH=@PRIVSEP_PATH@
+ SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
+@@ -63,7 +64,7 @@ INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_
+ INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
+ INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@
+ 
+-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT)
++TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT)
+ 
+ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
+ 	canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \
+@@ -166,6 +167,9 @@ ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libss
+ ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o
+ 	$(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck -lldap -llber $(LIBS)
+ 
++ssh-keycat$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keycat.o
++	$(LD) -o $@ ssh-keycat.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(SSHDLIBS)
++
+ 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)
+ 
+@@ -276,6 +280,7 @@ install-files: scard-install
+ 		$(INSTALL) -m 0700 $(STRIP_OPT) ssh-ldap-helper $(DESTDIR)$(SSH_LDAP_HELPER) ; \
+ 		$(INSTALL) -m 0700 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \
+ 	fi
++	$(INSTALL) -m 0755 $(STRIP_OPT) ssh-keycat$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-keycat$(EXEEXT)
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) sftp $(DESTDIR)$(bindir)/sftp
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) sftp-server $(DESTDIR)$(SFTP_SERVER)
+ 	$(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
+diff -up openssh-5.3p1/openbsd-compat/port-linux.c.keycat openssh-5.3p1/openbsd-compat/port-linux.c
+--- openssh-5.3p1/openbsd-compat/port-linux.c.keycat	2011-03-08 12:12:00.000000000 +0100
++++ openssh-5.3p1/openbsd-compat/port-linux.c	2011-03-08 12:12:10.000000000 +0100
+@@ -324,7 +324,7 @@ ssh_selinux_getctxbyname(char *pwname,
+ 
+ /* Setup environment variables for pam_selinux */
+ static int
+-ssh_selinux_setup_pam_variables(void)
++ssh_selinux_setup_variables(int(*set_it)(const char *, const char *))
+ {
+ 	const char *reqlvl;
+ 	char *role;
+@@ -335,16 +335,16 @@ ssh_selinux_setup_pam_variables(void)
+ 
+ 	ssh_selinux_get_role_level(&role, &reqlvl);
+ 
+-	rv = do_pam_putenv("SELINUX_ROLE_REQUESTED", role ? role : "");
++	rv = set_it("SELINUX_ROLE_REQUESTED", role ? role : "");
+ 	
+ 	if (inetd_flag && !rexeced_flag) {
+ 		use_current = "1";
+ 	} else {
+ 		use_current = "";
+-		rv = rv || do_pam_putenv("SELINUX_LEVEL_REQUESTED", reqlvl ? reqlvl: "");
++		rv = rv || set_it("SELINUX_LEVEL_REQUESTED", reqlvl ? reqlvl: "");
+ 	}
+ 
+-	rv = rv || do_pam_putenv("SELINUX_USE_CURRENT_RANGE", use_current);
++	rv = rv || set_it("SELINUX_USE_CURRENT_RANGE", use_current);
+ 
+ 	if (role != NULL)
+ 		xfree(role);
+@@ -352,6 +352,24 @@ ssh_selinux_setup_pam_variables(void)
+ 	return rv;
+ }
+ 
++static int
++ssh_selinux_setup_pam_variables(void)
++{
++	return ssh_selinux_setup_variables(do_pam_putenv);
++}
++
++static int
++do_setenv(char *name, char *value)
++{
++	return setenv(name, value, 1);
++}
++
++int
++ssh_selinux_setup_env_variables(void)
++{
++	return ssh_selinux_setup_variables(do_setenv);
++}
++
+ /* Set the execution context to the default for the specified user */
+ void
+ ssh_selinux_setup_exec_context(char *pwname)
+diff -up openssh-5.3p1/ssh-keycat.c.keycat openssh-5.3p1/ssh-keycat.c
+--- openssh-5.3p1/ssh-keycat.c.keycat	2011-03-08 12:12:10.000000000 +0100
++++ openssh-5.3p1/ssh-keycat.c	2011-03-08 12:12:10.000000000 +0100
+@@ -0,0 +1,238 @@
++/*
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ *
++ * ALTERNATIVELY, this product may be distributed under the terms of
++ * the GNU Public License, in which case the provisions of the GPL are
++ * required INSTEAD OF the above restrictions.  (This clause is
++ * necessary due to a potential bad interaction between the GPL and
++ * the restrictions contained in a BSD-style copyright.)
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++ */
++
++/*
++ * Copyright (c) 2011 Red Hat, Inc.
++ * Written by Tomas Mraz <tmraz at redhat.com>
++*/
++
++#define _GNU_SOURCE
++
++#include "config.h"
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <pwd.h>
++#include <fcntl.h>
++#include <unistd.h>
++
++#include <security/pam_appl.h>
++
++#include "uidswap.h"
++#include "misc.h"
++
++#define ERR_USAGE 1
++#define ERR_PAM_START 2
++#define ERR_OPEN_SESSION 3
++#define ERR_CLOSE_SESSION 4
++#define ERR_PAM_END 5
++#define ERR_GETPWNAM 6
++#define ERR_MEMORY 7
++#define ERR_OPEN 8
++#define ERR_FILE_MODE 9
++#define ERR_FDOPEN 10
++#define ERR_STAT 11
++#define ERR_WRITE 12
++#define ERR_PAM_PUTENV 13
++#define BUFLEN 4096
++
++/* Just ignore the messages in the conversation function */
++static int
++dummy_conv(int num_msg, const struct pam_message **msgm,
++	   struct pam_response **response, void *appdata_ptr)
++{
++	struct pam_response *rsp;
++
++	(void)msgm;
++	(void)appdata_ptr;
++
++	if (num_msg <= 0)
++		return PAM_CONV_ERR;
++
++	/* Just allocate the array as empty responses */
++	rsp = calloc (num_msg, sizeof (struct pam_response));
++	if (rsp == NULL)
++		return PAM_CONV_ERR;
++
++	*response = rsp;
++	return PAM_SUCCESS;
++}
++
++static struct pam_conv conv = {
++	dummy_conv,
++	NULL
++};
++
++char *
++make_auth_keys_name(const struct passwd *pwd)
++{
++	char *fname;
++
++	if (asprintf(&fname, "%s/.ssh/authorized_keys", pwd->pw_dir) < 0)
++		return NULL;
++
++	return fname;
++}
++
++int
++dump_keys(const char *user)
++{
++	struct passwd *pwd;
++	int fd = -1;
++	FILE *f = NULL;
++	char *fname = NULL;
++	int rv = 0;
++	char buf[BUFLEN];
++	size_t len;
++	struct stat st;
++
++	if ((pwd = getpwnam(user)) == NULL) {
++		return ERR_GETPWNAM;
++	}
++
++	if ((fname = make_auth_keys_name(pwd)) == NULL) {
++		return ERR_MEMORY;
++	}
++
++	temporarily_use_uid(pwd);
++
++	if ((fd = open(fname, O_RDONLY|O_NONBLOCK|O_NOFOLLOW, 0)) < 0) {
++		rv = ERR_OPEN;
++		goto fail;
++	}
++
++	if (fstat(fd, &st) < 0) {
++		rv = ERR_STAT;
++		goto fail;
++	}
++
++	if (!S_ISREG(st.st_mode) || 
++		(st.st_uid != pwd->pw_uid && st.st_uid != 0)) {
++		rv = ERR_FILE_MODE;
++		goto fail;
++	}
++
++	unset_nonblock(fd);
++
++	if ((f = fdopen(fd, "r")) == NULL) {
++		rv = ERR_FDOPEN;
++		goto fail;
++	}
++
++	fd = -1;
++
++	while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
++		rv = fwrite(buf, 1, len, stdout) != len ? ERR_WRITE : 0;
++	}
++
++fail:
++	if (fd != -1)
++		close(fd);
++	if (f != NULL)
++		fclose(f);
++	free(fname);
++	restore_uid();
++	return rv;
++}
++
++static const char *env_names[] = { "SELINUX_ROLE_REQUESTED",
++	"SELINUX_LEVEL_REQUESTED",
++	"SELINUX_USE_CURRENT_RANGE"
++};
++
++extern char **environ;
++
++int
++set_pam_environment(pam_handle_t *pamh)
++{
++	int i;
++	size_t j;
++
++	for (j = 0; j < sizeof(env_names)/sizeof(env_names[0]); ++j) {
++		int len = strlen(env_names[j]);
++
++		for (i = 0; environ[i] != NULL; ++i) {
++			if (strncmp(env_names[j], environ[i], len) == 0 &&
++			    environ[i][len] == '=') {
++				if (pam_putenv(pamh, environ[i]) != PAM_SUCCESS)
++					return ERR_PAM_PUTENV;
++			}
++		}
++	}
++
++	return 0;
++}
++
++int
++main(int argc, char *argv[])
++{
++	pam_handle_t *pamh = NULL;
++	int retval;
++	int ev = 0;
++
++	if (argc != 2) {
++		fprintf(stderr, "Usage: %s <user-name>\n", argv[0]);
++		return ERR_USAGE;
++	}
++
++	retval = pam_start("ssh-keycat", argv[1], &conv, &pamh);
++	if (retval != PAM_SUCCESS) {
++		return ERR_PAM_START;
++	}
++
++	ev = set_pam_environment(pamh);
++	if (ev != 0)
++		goto finish;
++
++	retval = pam_open_session(pamh, PAM_SILENT);
++	if (retval != PAM_SUCCESS) {
++		ev = ERR_OPEN_SESSION;
++		goto finish;
++	}
++
++	ev = dump_keys(argv[1]);
++
++	retval = pam_close_session(pamh, PAM_SILENT);
++	if (retval != PAM_SUCCESS) {
++		ev = ERR_CLOSE_SESSION;
++	}
++
++finish:
++	retval = pam_end (pamh,retval);
++	if (retval != PAM_SUCCESS) {
++		ev = ERR_PAM_END;
++	}
++	return ev;
++}
diff --git a/openssh-5.3p1-kuserok.patch b/openssh-5.3p1-kuserok.patch
new file mode 100644
index 0000000..27b71f4
--- /dev/null
+++ b/openssh-5.3p1-kuserok.patch
@@ -0,0 +1,167 @@
+diff -up openssh-5.3p1/auth-krb5.c.kuserok openssh-5.3p1/auth-krb5.c
+--- openssh-5.3p1/auth-krb5.c.kuserok	2010-11-15 12:08:51.000000000 +0100
++++ openssh-5.3p1/auth-krb5.c	2010-11-15 12:10:24.000000000 +0100
+@@ -54,6 +54,20 @@
+ 
+ extern ServerOptions	 options;
+ 
++int
++ssh_krb5_kuserok(krb5_context krb5_ctx, krb5_principal krb5_user, const char *client)
++{
++	if (options.use_kuserok)
++		return krb5_kuserok(krb5_ctx, krb5_user, client);
++	else {
++		char kuser[65];
++
++		if (krb5_aname_to_localname(krb5_ctx, krb5_user, sizeof(kuser), kuser))
++			return 0;
++		return strcmp(kuser, client) == 0;
++	}
++}
++
+ static int
+ krb5_init(void *context)
+ {
+@@ -141,7 +155,7 @@ auth_krb5_password(Authctxt *authctxt, c
+ 	if (problem)
+ 		goto out;
+ 
+-	if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user,
++	if (!ssh_krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user,
+ 			  authctxt->pw->pw_name)) {
+ 		problem = -1;
+ 		goto out;
+diff -up openssh-5.3p1/gss-serv-krb5.c.kuserok openssh-5.3p1/gss-serv-krb5.c
+--- openssh-5.3p1/gss-serv-krb5.c.kuserok	2010-11-15 12:08:51.000000000 +0100
++++ openssh-5.3p1/gss-serv-krb5.c	2010-11-15 12:08:52.000000000 +0100
+@@ -57,6 +57,7 @@ extern ServerOptions options;
+ #endif
+ 
+ static krb5_context krb_context = NULL;
++extern int ssh_krb5_kuserok(krb5_context, krb5_principal, const char *);
+ 
+ /* Initialise the krb5 library, for the stuff that GSSAPI won't do */
+ 
+@@ -97,7 +98,7 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client
+ 		    krb5_get_err_text(krb_context, retval));
+ 		return 0;
+ 	}
+-	if (krb5_kuserok(krb_context, princ, name)) {
++	if (ssh_krb5_kuserok(krb_context, princ, name)) {
+ 		retval = 1;
+ 		logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
+ 		    name, (char *)client->displayname.value);
+diff -up openssh-5.3p1/servconf.c.kuserok openssh-5.3p1/servconf.c
+--- openssh-5.3p1/servconf.c.kuserok	2010-11-15 12:08:51.000000000 +0100
++++ openssh-5.3p1/servconf.c	2010-11-15 12:11:41.000000000 +0100
+@@ -134,6 +134,7 @@ initialize_server_options(ServerOptions 
+ 	options->authorized_keys_command = NULL;
+ 	options->authorized_keys_command_runas = NULL;
+ 	options->zero_knowledge_password_authentication = -1;
++	options->use_kuserok = -1;
+ }
+ 
+ void
+@@ -281,6 +282,8 @@ fill_default_server_options(ServerOption
+ 	if (use_privsep == -1)
+ 		use_privsep = 1;
+ 
++	if (options->use_kuserok == -1)
++		options->use_kuserok = 1;
+ #ifndef HAVE_MMAP
+ 	if (use_privsep && options->compression == 1) {
+ 		error("This platform does not support both privilege "
+@@ -302,7 +305,7 @@ typedef enum {
+ 	sPermitRootLogin, sLogFacility, sLogLevel,
+ 	sRhostsRSAAuthentication, sRSAAuthentication,
+ 	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
+-	sKerberosGetAFSToken,
++	sKerberosGetAFSToken, sKerberosUseKuserok,
+ 	sKerberosTgtPassing, sChallengeResponseAuthentication,
+ 	sPasswordAuthentication, sKbdInteractiveAuthentication,
+ 	sListenAddress, sAddressFamily,
+@@ -371,11 +374,13 @@ static struct {
+ #else
+ 	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
+ #endif
++	{ "kerberosusekuserok", sKerberosUseKuserok, SSHCFG_ALL },
+ #else
+ 	{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
+ 	{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
+ 	{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
+ 	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
++	{ "kerberosusekuserok", sUnsupported, SSHCFG_ALL },
+ #endif
+ 	{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
+ 	{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
+@@ -1302,6 +1307,10 @@ process_server_config_line(ServerOptions
+ 		*activep = value;
+ 		break;
+ 
++	case sKerberosUseKuserok:
++		intptr = &options->use_kuserok;
++		goto parse_flag;
++
+ 	case sPermitOpen:
+ 		arg = strdelim(&cp);
+ 		if (!arg || *arg == '\0')
+@@ -1476,6 +1485,7 @@ copy_set_server_options(ServerOptions *d
+ 	M_CP_INTOPT(x11_use_localhost);
+ 	M_CP_INTOPT(max_sessions);
+ 	M_CP_INTOPT(max_authtries);
++	M_CP_INTOPT(use_kuserok);
+ 
+ 	M_CP_STROPT(banner);
+ 	if (preauth)
+@@ -1691,6 +1701,7 @@ dump_config(ServerOptions *o)
+ 	dump_cfg_fmtint(sUseDNS, o->use_dns);
+ 	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
+ 	dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
++	dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok);
+ 
+ 	/* string arguments */
+ 	dump_cfg_string(sPidFile, o->pid_file);
+diff -up openssh-5.3p1/servconf.h.kuserok openssh-5.3p1/servconf.h
+--- openssh-5.3p1/servconf.h.kuserok	2010-11-15 12:08:51.000000000 +0100
++++ openssh-5.3p1/servconf.h	2010-11-15 12:12:08.000000000 +0100
+@@ -153,6 +153,7 @@ typedef struct {
+ 	int	permit_tun;
+ 
+ 	int	num_permitted_opens;
++	int	use_kuserok;
+ 
+ 	char   *chroot_directory;
+ 	char   *authorized_keys_command;
+diff -up openssh-5.3p1/sshd_config.5.kuserok openssh-5.3p1/sshd_config.5
+--- openssh-5.3p1/sshd_config.5.kuserok	2010-11-15 12:08:51.000000000 +0100
++++ openssh-5.3p1/sshd_config.5	2010-11-15 12:13:14.000000000 +0100
+@@ -511,6 +511,10 @@ Specifies whether to automatically destr
+ file on logout.
+ The default is
+ .Dq yes .
++.It Cm KerberosUseKuserok
++Specifies whether to look at .k5login file for user's aliases.
++The default is
++.Dq yes .
+ .It Cm KeyRegenerationInterval
+ In protocol version 1, the ephemeral server key is automatically regenerated
+ after this many seconds (if it has been used).
+@@ -636,6 +640,7 @@ Available keywords are
+ .Cm HostbasedAuthentication ,
+ .Cm KbdInteractiveAuthentication ,
+ .Cm KerberosAuthentication ,
++.Cm KerberosUseKuserok ,
+ .Cm MaxAuthTries ,
+ .Cm MaxSessions ,
+ .Cm PubkeyAuthentication ,
+diff -up openssh-5.3p1/sshd_config.kuserok openssh-5.3p1/sshd_config
+--- openssh-5.3p1/sshd_config.kuserok	2010-11-15 12:08:51.000000000 +0100
++++ openssh-5.3p1/sshd_config	2010-11-15 12:08:52.000000000 +0100
+@@ -74,6 +74,7 @@ ChallengeResponseAuthentication no
+ #KerberosOrLocalPasswd yes
+ #KerberosTicketCleanup yes
+ #KerberosGetAFSToken no
++#KerberosUseKuserok yes
+ 
+ # GSSAPI options
+ #GSSAPIAuthentication no
diff --git a/openssh-5.3p1-ldap.patch b/openssh-5.3p1-ldap.patch
new file mode 100644
index 0000000..316909b
--- /dev/null
+++ b/openssh-5.3p1-ldap.patch
@@ -0,0 +1,2587 @@
+diff -up openssh-5.3p1/configure.ac.ldap openssh-5.3p1/configure.ac
+--- openssh-5.3p1/configure.ac.ldap	2011-03-10 22:39:33.204854859 +0100
++++ openssh-5.3p1/configure.ac	2011-03-10 22:39:34.913980413 +0100
+@@ -1363,6 +1363,109 @@ AC_ARG_WITH(authorized-keys-command,
+ 	]
+ )
+ 
++# Check whether user wants LDAP support
++LDAP_MSG="no"
++INSTALL_SSH_LDAP_HELPER=""
++AC_ARG_WITH(ldap,
++	[  --with-ldap[[=PATH]]      Enable LDAP pubkey support (optionally in PATH)],
++	[
++		if test "x$withval" != "xno" ; then
++
++			save2_LIBS="$LIBS"
++			INSTALL_SSH_LDAP_HELPER="yes"
++			CPPFLAGS="$CPPFLAGS -DLDAP_DEPRECATED"
++
++			if test "x$withval" != "xyes" ; then
++				CPPFLAGS="$CPPFLAGS -I${withval}/include"
++				LDFLAGS="$LDFLAGS -L${withval}/lib"
++			fi
++
++			AC_DEFINE([WITH_LDAP_PUBKEY], 1, [Enable LDAP pubkey support])
++			LDAP_MSG="yes"
++
++			AC_CHECK_HEADERS(lber.h)
++			AC_CHECK_HEADERS(ldap.h, , AC_MSG_ERROR(could not locate <ldap.h>))
++			AC_CHECK_HEADERS(ldap_ssl.h)
++
++			AC_ARG_WITH(ldap-lib,
++				[  --with-ldap-lib=type    select ldap library [auto|netscape5|netscape4|netscape3|umich|openldap]])
++
++			if test -z "$with_ldap_lib"; then
++				with_ldap_lib=auto
++			fi
++
++			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = umich -o $with_ldap_lib = openldap \); then
++				AC_CHECK_LIB(lber, main, LIBS="-llber $LIBS" found_ldap_lib=yes)
++				AC_CHECK_LIB(ldap, main, LIBS="-lldap $LIBS" found_ldap_lib=yes)
++			fi
++
++			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape5 \); then
++				AC_CHECK_LIB(ldap50, main, LIBS="-lldap50 -lssldap50 -lssl3 -lnss3 -lnspr4 -lprldap50 -lplc4 -lplds4 $LIBS" found_ldap_lib=yes)
++			fi
++
++			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape4 \); then
++				AC_CHECK_LIB(ldapssl41, main, LIBS="-lldapssl41 -lplc3 -lplds3 -lnspr3 $LIBS" found_ldap_lib=yes)
++				if test -z "$found_ldap_lib"; then
++					AC_CHECK_LIB(ldapssl40, main, LIBS="-lldapssl40 $LIBS" found_ldap_lib=yes)
++				fi
++				if test -z "$found_ldap_lib"; then
++					AC_CHECK_LIB(ldap41, main, LIBS="-lldap41 $LIBS" found_ldap_lib=yes)
++				fi
++				if test -z "$found_ldap_lib"; then
++					AC_CHECK_LIB(ldap40, main, LIBS="-lldap40 $LIBS" found_ldap_lib=yes)
++				fi
++			fi
++
++			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape3 \); then
++				AC_CHECK_LIB(ldapssl30, main, LIBS="-lldapssl30 $LIBS" found_ldap_lib=yes)
++			fi
++
++			if test -z "$found_ldap_lib"; then
++				AC_MSG_ERROR(could not locate a valid LDAP library)
++			fi
++
++			AC_MSG_CHECKING([for working LDAP support])
++			AC_TRY_COMPILE(
++				[#include <sys/types.h>
++				 #include <ldap.h>],
++				[(void)ldap_init(0, 0);],
++				[AC_MSG_RESULT(yes)],
++				[
++				    AC_MSG_RESULT(no) 
++					AC_MSG_ERROR([** Incomplete or missing ldap libraries **])
++				])
++			AC_CHECK_FUNCS( \
++				ldap_init \
++				ldap_get_lderrno \
++				ldap_set_lderrno \
++				ldap_parse_result \
++				ldap_memfree \
++				ldap_controls_free \
++				ldap_set_option \
++				ldap_get_option \
++				ldapssl_init \
++				ldap_start_tls_s \
++				ldap_pvt_tls_set_option \
++				ldap_initialize \
++			)
++			AC_CHECK_FUNCS(ldap_set_rebind_proc,
++				AC_MSG_CHECKING([number arguments of ldap_set_rebind_proc])
++				AC_TRY_COMPILE(
++					[#include <lber.h>
++					#include <ldap.h>],
++					[ldap_set_rebind_proc(0, 0, 0);],
++					[ac_cv_ldap_set_rebind_proc=3],
++					[ac_cv_ldap_set_rebind_proc=2])
++				AC_MSG_RESULT($ac_cv_ldap_set_rebind_proc)
++				AC_DEFINE(LDAP_SET_REBIND_PROC_ARGS, $ac_cv_ldap_set_rebind_proc, [number arguments of ldap_set_rebind_proc])
++			)
++
++			LIBS="$save2_LIBS"
++		fi
++	]
++)
++AC_SUBST(INSTALL_SSH_LDAP_HELPER)
++
+ dnl    Checks for library functions. Please keep in alphabetical order
+ AC_CHECK_FUNCS( \
+ 	arc4random \
+diff -up openssh-5.3p1/HOWTO.ldap-keys.ldap openssh-5.3p1/HOWTO.ldap-keys
+--- openssh-5.3p1/HOWTO.ldap-keys.ldap	2011-03-10 22:39:34.940854648 +0100
++++ openssh-5.3p1/HOWTO.ldap-keys	2011-03-10 22:39:34.952854376 +0100
+@@ -0,0 +1,108 @@
++
++HOW TO START
++
++1) configure LDAP server
++  * Use LDAP server documentation
++2) add appropriate LDAP schema
++  * For OpenLDAP or SunONE Use attached schema, otherwise you have to create it. 
++  * LDAP user entry
++        User entry:
++	- attached to the 'ldapPublicKey' objectclass
++	- attached to the 'posixAccount' objectclass
++	- with a filled 'sshPublicKey' attribute 
++3) insert users into LDAP
++  * Use LDAP Tree management tool as useful
++  * Entry in the LDAP server must respect 'posixAccount' and 'ldapPublicKey' which are defined in core.schema and the additionnal lpk.schema.
++  * Example:
++	dn: uid=captain,ou=commanders,dc=enterprise,dc=universe
++	objectclass: top
++	objectclass: person
++	objectclass: organizationalPerson
++	objectclass: posixAccount
++	objectclass: ldapPublicKey
++	description: Jonathan Archer
++	userPassword: Porthos
++	cn: onathan Archer
++	sn: onathan Archer
++	uid: captain
++	uidNumber: 1001
++	gidNumber: 1001
++	homeDirectory: /home/captain
++	sshPublicKey: ssh-rss AAAAB3.... =captain at universe
++	sshPublicKey: command="kill -9 1" ssh-rss AAAAM5...
++4) on the ssh side set in sshd_config
++  * Set up the backend
++	AuthorizedKeysCommand "/usr/libexec/openssh/ssh-ldap-wrapper"
++	AuthorizedKeysCommandRunAs <appropriate user to run LDAP>
++  * Do not forget to set
++	PubkeyAuthentication yes
++  * Swith off unnecessary auth methods
++5) confugure ldap.conf
++  * Default ldap.conf is placed in /etc/ssh
++  * The configuration style is the same as other ldap based aplications
++6) if necessary edit ssh-ldap-wrapper
++  * There is a possibility to change ldap.conf location
++  * There are some debug options
++  * Example
++	/usr/libexec/openssh -s -f /etc/ldap.conf -w -d >> /tmp/ldapdebuglog.txt
++
++HOW TO MIGRATE FROM LPK
++
++1) goto HOW TO START 4) .... the ldap schema is the same
++
++2) convert the group requests to the appropriate LDAP requests
++
++HOW TO SOLVE PROBLEMS
++
++1) use debug in sshd
++  * /usr/sbin/sshd -d -d -d -d
++2) use debug in ssh-ldap-helper
++  * ssh-ldap-helper -d -d -d -d -s <username>
++3) use tcpdump ... other ldap client etc.
++
++ADVANTAGES
++
++1) Blocking an user account can be done directly from LDAP (if sshd is using PubkeyAuthentication + AuthorizedKeysCommand with ldap only).
++
++DISADVANTAGES
++
++1)  LDAP must be well configured, getting the public key of some user is not a problem, but if anonymous LDAP 
++  allows write to users dn, somebody could replace some user's public key by his own and impersonate some 
++  of your users in all your server farm -- be VERY CAREFUL.
++2) With incomplete PKI the MITM attack when sshd is requesting the public key, could lead to a compromise of your servers allowing login 
++  as the impersonated user.
++3) If LDAP server is down there may be no fallback on passwd auth.
++  
++MISC.
++  
++1) todo
++  * Possibility to reuse the ssh-ldap-helper.
++  * Tune the LDAP part to accept  all possible LDAP configurations.
++
++2) differences from original lpk
++  * No LDAP code in sshd.
++  * Support for various LDAP platforms and configurations.
++  * LDAP is configured in separate ldap.conf file.
++
++3) docs/link 
++  * http://pacsec.jp/core05/psj05-barisani-en.pdf
++  * http://fritz.potsdam.edu/projects/openssh-lpk/
++  * http://fritz.potsdam.edu/projects/sshgate/
++  * http://dev.inversepath.com/trac/openssh-lpk
++  * http://lam.sf.net/ ( http://lam.sourceforge.net/documentation/supportedSchemas.htm )
++
++4) contributors/ideas/greets
++  - Eric AUGE <eau at phear.org>
++  - Andrea Barisani <andrea at inversepath.com>
++  - Falk Siemonsmeier.
++  - Jacob Rief.
++  - Michael Durchgraf.
++  - frederic peters.
++  - Finlay dobbie.
++  - Stefan Fisher.
++  - Robin H. Johnson.
++  - Adrian Bridgett.
++
++5) Author
++    Jan F. Chadima <jchadima at redhat.com>
++
+diff -up openssh-5.3p1/ldapbody.c.ldap openssh-5.3p1/ldapbody.c
+--- openssh-5.3p1/ldapbody.c.ldap	2011-03-10 22:39:34.982980062 +0100
++++ openssh-5.3p1/ldapbody.c	2011-03-10 22:39:34.995855141 +0100
+@@ -0,0 +1,494 @@
++/* $OpenBSD: ldapbody.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "ldapincludes.h"
++#include "log.h"
++#include "xmalloc.h"
++#include "ldapconf.h"
++#include "ldapmisc.h"
++#include "ldapbody.h"
++#include <stdio.h>
++#include <unistd.h>
++
++#define LDAPSEARCH_FORMAT "(&(objectclass=posixAccount)(objectclass=ldapPublicKey)(uid=%s)%s)"
++#define PUBKEYATTR "sshPublicKey"
++#define LDAP_LOGFILE	"%s/ldap.%d"
++
++static FILE *logfile = NULL;
++static LDAP *ld;
++
++static char *attrs[] = {
++    PUBKEYATTR,
++    NULL
++};
++
++void
++ldap_checkconfig (void)
++{
++#ifdef HAVE_LDAP_INITIALIZE
++		if (options.host == NULL && options.uri == NULL)
++#else
++		if (options.host == NULL)
++#endif
++		    fatal ("missing  \"host\" in config file");
++}
++
++#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
++static int
++_rebind_proc (LDAP * ld, LDAP_CONST char *url, int request, ber_int_t msgid)
++{
++	struct timeval timeout;
++	int rc;
++#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE)
++	LDAPMessage *result;
++#endif /* HAVE_LDAP_PARSE_RESULT && HAVE_LDAP_CONTROLS_FREE */
++
++	debug2 ("Doing LDAP rebind to %s", options.binddn);
++	if (options.ssl == SSL_START_TLS) {
++		if ((rc = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS) {
++			error ("ldap_starttls_s: %s", ldap_err2string (rc));
++			return LDAP_OPERATIONS_ERROR;
++		}
++	}
++
++#if !defined(HAVE_LDAP_PARSE_RESULT) || !defined(HAVE_LDAP_CONTROLS_FREE)
++	return ldap_simple_bind_s (ld, options.binddn, options.bindpw);
++#else
++	if (ldap_simple_bind(ld, options.binddn, options.bindpw) < 0)
++	    fatal ("ldap_simple_bind %s", ldap_err2string (ldap_get_lderrno (ld, 0, 0)));
++
++	timeout.tv_sec = options.bind_timelimit;
++	timeout.tv_usec = 0;
++	result = NULL;
++	if ((rc = ldap_result (ld, msgid, FALSE, &timeout, &result)) < 1) {
++		error ("ldap_result %s", ldap_err2string (ldap_get_lderrno (ld, 0, 0)));
++		ldap_msgfree (result);
++		return LDAP_OPERATIONS_ERROR;
++	}
++	debug3 ("LDAP rebind to %s succesfull", options.binddn);
++	return rc;
++#endif
++}
++#else
++
++static int
++_rebind_proc (LDAP * ld, char **whop, char **credp, int *methodp, int freeit)
++{
++	if (freeit)
++	    return LDAP_SUCCESS;
++
++	*whop = strdup (options.binddn);
++	*credp = strdup (options.bindpw);
++	*methodp = LDAP_AUTH_SIMPLE;
++	debug2 ("Doing LDAP rebind for %s", *whop);
++	return LDAP_SUCCESS;
++}
++#endif
++
++void
++ldap_do_connect(void)
++{
++	int rc, msgid, ld_errno = 0;
++	struct timeval timeout;
++#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE)
++	int parserc;
++	LDAPMessage *result;
++	LDAPControl **controls;
++	int reconnect = 0;
++#endif /* HAVE_LDAP_PARSE_RESULT && HAVE_LDAP_CONTROLS_FREE */
++
++	debug ("LDAP do connect");
++
++retry:
++	if (reconnect) {
++		debug3 ("Reconnecting with ld_errno %d", ld_errno);
++		if (options.bind_policy == 0 ||
++		    (ld_errno != LDAP_SERVER_DOWN && ld_errno != LDAP_TIMEOUT) ||
++			reconnect > 5)
++			    fatal ("Cannot connect to LDAP server");
++	
++		if (reconnect > 1)
++			sleep (reconnect - 1);
++
++		if (ld != NULL) {
++			ldap_unbind (ld);
++			ld = NULL;
++		}
++		logit("reconnecting to LDAP server...");
++	}
++
++	if (ld == NULL) {
++		int rc;
++		struct timeval tv;
++
++#ifdef HAVE_LDAP_SET_OPTION
++		if (options.debug > 0) {
++#ifdef LBER_OPT_LOG_PRINT_FILE
++			if (options.logdir) {
++				char *logfilename;
++				int logfilenamelen;
++
++				logfilenamelen = strlen (LDAP_LOGFILE) + strlen ("000000") + strlen (options.logdir);
++				logfilename = xmalloc (logfilenamelen);
++				snprintf (logfilename, logfilenamelen, LDAP_LOGFILE, options.logdir, (int) getpid ());
++				logfilename[logfilenamelen - 1] = 0;
++				if ((logfile = fopen (logfilename, "a")) == NULL)
++				    fatal ("cannot append to %s: %s", logfilename, strerror (errno));
++				debug3 ("LDAP debug into %s", logfilename);
++				xfree (logfilename);
++				ber_set_option (NULL, LBER_OPT_LOG_PRINT_FILE, logfile);
++			}
++#endif
++			if (options.debug) {
++#ifdef LBER_OPT_DEBUG_LEVEL
++				ber_set_option (NULL, LBER_OPT_DEBUG_LEVEL, &options.debug);
++#endif /* LBER_OPT_DEBUG_LEVEL */
++#ifdef LDAP_OPT_DEBUG_LEVEL
++				ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &options.debug);
++#endif /* LDAP_OPT_DEBUG_LEVEL */
++				debug3 ("Set LDAP debug to %d", options.debug);
++			}
++		}
++#endif /* HAVE_LDAP_SET_OPTION */
++
++		ld = NULL;
++#ifdef HAVE_LDAPSSL_INIT
++		if (options.host != NULL) {
++			if (options.ssl_on == SSL_LDAPS) {
++				if ((rc = ldapssl_client_init (options.sslpath, NULL)) != LDAP_SUCCESS)
++				    fatal ("ldapssl_client_init %s", ldap_err2string (rc));
++				debug3 ("LDAPssl client init");
++			}
++
++			if (options.ssl_on != SSL_OFF) {
++				if ((ld = ldapssl_init (options.host, options.port, TRUE)) == NULL)
++				    fatal ("ldapssl_init failed");
++				debug3 ("LDAPssl init");
++			}
++		}
++#endif /* HAVE_LDAPSSL_INIT */
++
++		/* continue with opening */
++		if (ld == NULL) {
++#if defined (HAVE_LDAP_START_TLS_S) || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS))
++			/* Some global TLS-specific options need to be set before we create our
++			 * session context, so we set them here. */
++
++#ifdef LDAP_OPT_X_TLS_RANDOM_FILE
++			/* rand file */
++			if (options.tls_randfile != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
++				    options.tls_randfile)) != LDAP_SUCCESS)
++					fatal ("ldap_set_option(LDAP_OPT_X_TLS_RANDOM_FILE): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS random file %s", options.tls_randfile);
++			}
++#endif /* LDAP_OPT_X_TLS_RANDOM_FILE */
++
++			/* ca cert file */
++			if (options.tls_cacertfile != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE,
++				    options.tls_cacertfile)) != LDAP_SUCCESS)
++					error ("ldap_set_option(LDAP_OPT_X_TLS_CACERTFILE): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS CA cert file %s ", options.tls_cacertfile);
++			}
++
++			/* ca cert directory */
++			if (options.tls_cacertdir != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR,
++				    options.tls_cacertdir)) != LDAP_SUCCESS)
++					fatal ("ldap_set_option(LDAP_OPT_X_TLS_CACERTDIR): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS CA cert dir %s ", options.tls_cacertdir);
++			}
++
++			/* require cert? */
++			if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
++			    &options.tls_checkpeer)) != LDAP_SUCCESS)
++				fatal ("ldap_set_option(LDAP_OPT_X_TLS_REQUIRE_CERT): %s",
++				    ldap_err2string (rc));
++			debug3 ("Set TLS check peer to %d ", options.tls_checkpeer);
++
++			/* set cipher suite, certificate and private key: */
++			if (options.tls_ciphers != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
++				    options.tls_ciphers)) != LDAP_SUCCESS)
++					fatal ("ldap_set_option(LDAP_OPT_X_TLS_CIPHER_SUITE): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS ciphers to %s ", options.tls_ciphers);
++			}
++
++			/* cert file */
++			if (options.tls_cert != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE,
++				    options.tls_cert)) != LDAP_SUCCESS)
++					fatal ("ldap_set_option(LDAP_OPT_X_TLS_CERTFILE): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS cert file %s ", options.tls_cert);
++			}
++
++			/* key file */
++			if (options.tls_key != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE,
++				    options.tls_key)) != LDAP_SUCCESS)
++					fatal ("ldap_set_option(LDAP_OPT_X_TLS_KEYFILE): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS key file %s ", options.tls_key);
++			}
++#endif
++#ifdef HAVE_LDAP_INITIALIZE
++			if (options.uri != NULL) {
++				if ((rc = ldap_initialize (&ld, options.uri)) != LDAP_SUCCESS)
++					fatal ("ldap_initialize %s", ldap_err2string (rc));
++				debug3 ("LDAP initialize %s", options.uri);
++			}
++	}
++#endif /* HAVE_LDAP_INTITIALIZE */
++
++		/* continue with opening */
++		if ((ld == NULL) && (options.host != NULL)) {
++#ifdef HAVE_LDAP_INIT
++			if ((ld = ldap_init (options.host, options.port)) == NULL)
++			    fatal ("ldap_init failed");
++			debug3 ("LDAP init %s:%d", options.host, options.port);
++#else
++			if ((ld = ldap_open (options.host, options.port)) == NULL)
++			    fatal ("ldap_open failed");
++			debug3 ("LDAP open %s:%d", options.host, options.port);
++#endif /* HAVE_LDAP_INIT */
++		}
++
++		if (ld == NULL)
++			fatal ("no way to open ldap");
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
++		if (options.ssl == SSL_LDAPS) {
++			if ((rc = ldap_set_option (ld, LDAP_OPT_X_TLS, &options.tls_checkpeer)) != LDAP_SUCCESS)
++				fatal ("ldap_set_option(LDAP_OPT_X_TLS) %s", ldap_err2string (rc));
++			debug3 ("LDAP set LDAP_OPT_X_TLS_%d", options.tls_checkpeer);
++		}
++#endif /* LDAP_OPT_X_TLS */
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_PROTOCOL_VERSION)
++		(void) ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION,
++		    &options.ldap_version);
++#else
++		ld->ld_version = options.ldap_version;
++#endif
++		debug3 ("LDAP set version to %d", options.ldap_version);
++
++#if LDAP_SET_REBIND_PROC_ARGS == 3
++		ldap_set_rebind_proc (ld, _rebind_proc, NULL);
++#elif LDAP_SET_REBIND_PROC_ARGS == 2
++		ldap_set_rebind_proc (ld, _rebind_proc);
++#else
++#warning unknown LDAP_SET_REBIND_PROC_ARGS
++#endif
++		debug3 ("LDAP set rebind proc");
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_DEREF)
++		(void) ldap_set_option (ld, LDAP_OPT_DEREF, &options.deref);
++#else
++		ld->ld_deref = options.deref;
++#endif
++		debug3 ("LDAP set deref to %d", options.deref);
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_TIMELIMIT)
++		(void) ldap_set_option (ld, LDAP_OPT_TIMELIMIT,
++		    &options.timelimit);
++#else
++		ld->ld_timelimit = options.timelimit;
++#endif
++		debug3 ("LDAP set timelimit to %d", options.timelimit);
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_X_OPT_CONNECT_TIMEOUT)
++		/*
++		 * This is a new option in the Netscape SDK which sets 
++		 * the TCP connect timeout. For want of a better value,
++		 * we use the bind_timelimit to control this.
++		 */
++		timeout = options.bind_timelimit * 1000;
++		(void) ldap_set_option (ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout);
++		debug3 ("LDAP set opt connect timeout to %d", timeout);
++#endif
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_NETWORK_TIMEOUT)
++		tv.tv_sec = options.bind_timelimit;
++		tv.tv_usec = 0;
++		(void) ldap_set_option (ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
++		debug3 ("LDAP set opt network timeout to %ld.0", tv.tv_sec);
++#endif
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_REFERRALS)
++		(void) ldap_set_option (ld, LDAP_OPT_REFERRALS,
++		    options.referrals ? LDAP_OPT_ON : LDAP_OPT_OFF);
++		debug3 ("LDAP set referrals to %d", options.referrals);
++#endif
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_RESTART)
++		(void) ldap_set_option (ld, LDAP_OPT_RESTART,
++		    options.restart ? LDAP_OPT_ON : LDAP_OPT_OFF);
++		debug3 ("LDAP set restart to %d", options.restart);
++#endif
++
++#ifdef HAVE_LDAP_START_TLS_S
++		if (options.ssl == SSL_START_TLS) {
++			int version;
++
++			if (ldap_get_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version)
++			    == LDAP_SUCCESS) {
++				if (version < LDAP_VERSION3) {
++					version = LDAP_VERSION3;
++					(void) ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION,
++					    &version);
++					debug3 ("LDAP set version to %d", version);
++				}
++			}
++
++			if ((rc = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS)
++			    fatal ("ldap_starttls_s: %s", ldap_err2string (rc));
++			debug3 ("LDAP start TLS");
++		}
++#endif /* HAVE_LDAP_START_TLS_S */
++	}
++
++	if ((msgid = ldap_simple_bind (ld, options.binddn,
++	    options.bindpw)) == -1) {
++		ld_errno = ldap_get_lderrno (ld, 0, 0);
++
++		error ("ldap_simple_bind %s", ldap_err2string (ld_errno));
++		reconnect++;
++		goto retry;
++	}
++	debug3 ("LDAP simple bind (%s)", options.binddn);
++
++	timeout.tv_sec = options.bind_timelimit;
++	timeout.tv_usec = 0;
++	if ((rc = ldap_result (ld, msgid, FALSE, &timeout, &result)) < 1) {
++		ld_errno = ldap_get_lderrno (ld, 0, 0);
++
++		error ("ldap_result %s", ldap_err2string (ld_errno));
++		reconnect++;
++		goto retry;
++	}
++	debug3 ("LDAP result in time");
++
++#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE)
++	controls = NULL;
++	if ((parserc = ldap_parse_result (ld, result, &rc, 0, 0, 0, &controls, TRUE)) != LDAP_SUCCESS)
++	    fatal ("ldap_parse_result %s", ldap_err2string (parserc));
++	debug3 ("LDAP parse result OK");
++
++	if (controls != NULL) {
++		ldap_controls_free (controls);
++	}
++#else
++	rc = ldap_result2error (session->ld, result, TRUE);
++#endif
++	if (rc != LDAP_SUCCESS)
++	    fatal ("error trying to bind as user \"%s\" (%s)",
++		options.binddn, ldap_err2string (rc));
++
++	debug2 ("LDAP do connect OK");
++}
++
++void
++process_user (const char *user, FILE *output)
++{
++	LDAPMessage *res, *e;
++	char *buffer;
++	int bufflen, rc, i;
++	struct timeval timeout;
++
++	debug ("LDAP process user");
++
++	/* quick check for attempts to be evil */
++	if ((strchr(user, '(') != NULL) || (strchr(user, ')') != NULL) ||
++	    (strchr(user, '*') != NULL) || (strchr(user, '\\') != NULL)) {
++		logit ("illegal user name %s not processed", user);
++		return;
++	}
++
++	/* build  filter for LDAP request */
++	bufflen = strlen (LDAPSEARCH_FORMAT) + strlen (user);
++	if (options.ssh_filter != NULL)
++	    bufflen += strlen (options.ssh_filter);
++	buffer = xmalloc (bufflen);
++	snprintf(buffer, bufflen, LDAPSEARCH_FORMAT, user, (options.ssh_filter != NULL) ? options.ssh_filter : NULL);
++	buffer[bufflen - 1] = 0;
++
++	debug3 ("LDAP search scope = %d %s", options.scope, buffer);
++
++	timeout.tv_sec = options.timelimit;
++	timeout.tv_usec = 0;
++	if ((rc = ldap_search_st(ld, options.base, options.scope, buffer, attrs, 0, &timeout, &res)) != LDAP_SUCCESS) {
++		error ("ldap_search_st(): %s", ldap_err2string (rc));
++		xfree (buffer);
++		return;
++	}
++
++	/* free */
++	xfree (buffer);
++
++	for (e = ldap_first_entry(ld, res); e != NULL; e = ldap_next_entry(ld, e)) {
++		int num;
++		struct berval **keys;
++
++		keys = ldap_get_values_len(ld, e, PUBKEYATTR);
++		num = ldap_count_values_len(keys);
++		for (i = 0 ; i < num ; i++) {
++			char *cp; //, *options = NULL;
++
++			for (cp = keys[i]->bv_val; *cp == ' ' || *cp == '\t'; cp++);
++			if (!*cp || *cp == '\n' || *cp == '#')
++			    continue;
++
++			/* We have found the desired key. */
++			fprintf (output, "%s\n", keys[i]->bv_val);
++		}
++
++		ldap_value_free_len(keys);
++	}
++
++	ldap_msgfree(res);
++	debug2 ("LDAP process user finished");
++}
++
++void
++ldap_do_close(void)
++{
++	int rc;
++
++	debug ("LDAP do close");
++	if ((rc = ldap_unbind_ext(ld, NULL, NULL)) != LDAP_SUCCESS)
++	    fatal ("ldap_unbind_ext: %s",
++                                    ldap_err2string (rc));
++
++	ld = NULL;
++	debug2 ("LDAP do close OK");
++	return;
++}
++
+diff -up openssh-5.3p1/ldapbody.h.ldap openssh-5.3p1/ldapbody.h
+--- openssh-5.3p1/ldapbody.h.ldap	2011-03-10 22:39:35.008854699 +0100
++++ openssh-5.3p1/ldapbody.h	2011-03-10 22:39:35.016854649 +0100
+@@ -0,0 +1,37 @@
++/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef LDAPBODY_H
++#define LDAPBODY_H
++
++#include <stdio.h>
++
++void ldap_checkconfig(void);
++void ldap_do_connect(void);
++void process_user(const char *, FILE *);
++void ldap_do_close(void);
++
++#endif /* LDAPBODY_H */
++
+diff -up openssh-5.3p1/ldapconf.c.ldap openssh-5.3p1/ldapconf.c
+--- openssh-5.3p1/ldapconf.c.ldap	2011-03-10 22:39:35.030979743 +0100
++++ openssh-5.3p1/ldapconf.c	2011-03-10 22:39:35.039854544 +0100
+@@ -0,0 +1,682 @@
++/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "ldapincludes.h"
++#include "ldap-helper.h"
++#include "log.h"
++#include "misc.h"
++#include "xmalloc.h"
++#include "ldapconf.h"
++#include <unistd.h>
++#include <string.h>
++
++/* Keyword tokens. */
++
++typedef enum {
++	lBadOption,
++	lHost, lURI, lBase, lBindDN, lBindPW, lRootBindDN,
++	lScope, lDeref, lPort, lTimeLimit, lBind_TimeLimit,
++	lLdap_Version, lBind_Policy, lSSLPath, lSSL, lReferrals,
++	lRestart, lTLS_CheckPeer, lTLS_CaCertFile,
++	lTLS_CaCertDir, lTLS_Ciphers, lTLS_Cert, lTLS_Key,
++	lTLS_RandFile, lLogDir, lDebug, lSSH_Filter,
++	lDeprecated, lUnsupported
++} OpCodes;
++
++/* Textual representations of the tokens. */
++
++static struct {
++	const char *name;
++	OpCodes opcode;
++} keywords[] = {
++	{ "URI", lURI },
++	{ "Base", lBase },
++	{ "BindDN", lBindDN },
++	{ "BindPW", lBindPW },
++	{ "RootBindDN", lRootBindDN },
++	{ "Host", lHost },
++	{ "Port", lPort },
++	{ "Scope", lScope },
++	{ "Deref", lDeref },
++	{ "TimeLimit", lTimeLimit },
++	{ "TimeOut", lTimeLimit },
++	{ "Bind_Timelimit", lBind_TimeLimit },
++	{ "Network_TimeOut", lBind_TimeLimit },
++/*
++ * Todo
++ * SIZELIMIT
++ */
++	{ "Ldap_Version", lLdap_Version },
++	{ "Version", lLdap_Version },
++	{ "Bind_Policy", lBind_Policy },
++	{ "SSLPath", lSSLPath },
++	{ "SSL", lSSL },
++	{ "Referrals", lReferrals },
++	{ "Restart", lRestart },
++	{ "TLS_CheckPeer", lTLS_CheckPeer },
++	{ "TLS_ReqCert", lTLS_CheckPeer },
++	{ "TLS_CaCertFile", lTLS_CaCertFile },
++	{ "TLS_CaCert", lTLS_CaCertFile },
++	{ "TLS_CaCertDir", lTLS_CaCertDir },
++	{ "TLS_Ciphers", lTLS_Ciphers },
++	{ "TLS_Cipher_Suite", lTLS_Ciphers },
++	{ "TLS_Cert", lTLS_Cert },
++	{ "TLS_Certificate", lTLS_Cert },
++	{ "TLS_Key", lTLS_Key },
++	{ "TLS_RandFile", lTLS_RandFile },
++/*
++ * Todo
++ * TLS_CRLCHECK
++ * TLS_CRLFILE
++ */
++	{ "LogDir", lLogDir },
++	{ "Debug", lDebug },
++	{ "SSH_Filter", lSSH_Filter },
++	{ NULL, lBadOption }
++};
++
++/* Configuration ptions. */
++
++Options options;
++
++/*
++ * Returns the number of the token pointed to by cp or oBadOption.
++ */
++
++static OpCodes
++parse_token(const char *cp, const char *filename, int linenum)
++{
++	u_int i;
++
++	for (i = 0; keywords[i].name; i++)
++		if (strcasecmp(cp, keywords[i].name) == 0)
++			return keywords[i].opcode;
++
++	if (config_warning_config_file) 
++	    logit("%s: line %d: Bad configuration option: %s",
++		filename, linenum, cp);
++	return lBadOption;
++}
++
++/*
++ * Processes a single option line as used in the configuration files. This
++ * only sets those values that have not already been set.
++ */
++#define WHITESPACE " \t\r\n"
++
++static int
++process_config_line(char *line, const char *filename, int linenum)
++{
++	char *s, **charptr, **xstringptr, *endofnumber, *keyword, *arg;
++	char *rootbinddn = NULL;
++	int opcode, *intptr, value;
++	size_t len;
++
++	/* Strip trailing whitespace */
++	for (len = strlen(line) - 1; len > 0; len--) {
++		if (strchr(WHITESPACE, line[len]) == NULL)
++			break;
++		line[len] = '\0';
++	}
++
++	s = line;
++	/* Get the keyword. (Each line is supposed to begin with a keyword). */
++	if ((keyword = strdelim(&s)) == NULL)
++		return 0;
++	/* Ignore leading whitespace. */
++	if (*keyword == '\0')
++		keyword = strdelim(&s);
++	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
++		return 0;
++
++	opcode = parse_token(keyword, filename, linenum);
++
++	switch (opcode) {
++	case lBadOption:
++		/* don't panic, but count bad options */
++		return -1;
++		/* NOTREACHED */
++
++	case lHost:
++		xstringptr = &options.host;
++parse_xstring:
++		if (!s || *s == '\0')
++		    fatal("%s line %d: missing dn",filename,linenum);
++		if (*xstringptr == NULL)
++		    *xstringptr = xstrdup(s);
++		return 0;
++
++	case lURI:
++		xstringptr = &options.uri;
++		goto parse_xstring;
++
++	case lBase:
++		xstringptr = &options.base;
++		goto parse_xstring;
++
++	case lBindDN:
++		xstringptr = &options.binddn;
++		goto parse_xstring;
++
++	case lBindPW:
++		charptr = &options.bindpw;
++parse_string:
++		arg = strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing argument.", filename, linenum);
++		if (*charptr == NULL)
++			*charptr = xstrdup(arg);
++		break;
++
++	case lRootBindDN:
++		xstringptr = &rootbinddn;
++		goto parse_xstring;
++
++	case lScope:
++		intptr = &options.scope;
++		arg = strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing sub/one/base argument.", filename, linenum);
++		value = 0;	/* To avoid compiler warning... */
++		if (strcasecmp (arg, "sub") == 0 || strcasecmp (arg, "subtree") == 0)
++			value = LDAP_SCOPE_SUBTREE;
++		else if (strcasecmp (arg, "one") == 0)
++			value = LDAP_SCOPE_ONELEVEL;
++		else if (strcasecmp (arg, "base") == 0)
++			value = LDAP_SCOPE_BASE;
++		else
++			fatal("%.200s line %d: Bad sub/one/base argument.", filename, linenum);
++		if (*intptr == -1)
++			*intptr = value;
++		break;
++
++	case lDeref:
++		intptr = &options.scope;
++		arg = strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing never/searching/finding/always argument.", filename, linenum);
++		value = 0;	/* To avoid compiler warning... */
++		if (!strcasecmp (arg, "never"))
++			value = LDAP_DEREF_NEVER;
++		else if (!strcasecmp (arg, "searching"))
++			value = LDAP_DEREF_SEARCHING;
++		else if (!strcasecmp (arg, "finding"))
++			value = LDAP_DEREF_FINDING;
++		else if (!strcasecmp (arg, "always"))
++			value = LDAP_DEREF_ALWAYS;
++		else
++			fatal("%.200s line %d: Bad never/searching/finding/always argument.", filename, linenum);
++		if (*intptr == -1)
++			*intptr = value;
++		break;
++
++	case lPort:
++		intptr = &options.port;
++parse_int:
++		arg = strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing argument.", filename, linenum);
++		if (arg[0] < '0' || arg[0] > '9')
++			fatal("%.200s line %d: Bad number.", filename, linenum);
++
++		/* Octal, decimal, or hex format? */
++		value = strtol(arg, &endofnumber, 0);
++		if (arg == endofnumber)
++			fatal("%.200s line %d: Bad number.", filename, linenum);
++		if (*intptr == -1)
++			*intptr = value;
++		break;
++
++	case lTimeLimit:
++		intptr = &options.timelimit;
++parse_time:
++		arg = strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%s line %d: missing time value.",
++			    filename, linenum);
++		if ((value = convtime(arg)) == -1)
++			fatal("%s line %d: invalid time value.",
++			    filename, linenum);
++		if (*intptr == -1)
++			*intptr = value;
++		break;
++
++	case lBind_TimeLimit:
++		intptr = &options.bind_timelimit;
++		goto parse_time;
++
++	case lLdap_Version:
++		intptr = &options.ldap_version;
++		goto parse_int;
++
++	case lBind_Policy:
++		intptr = &options.bind_policy;
++		arg = strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing soft/hard argument.", filename, linenum);
++		value = 0;	/* To avoid compiler warning... */
++		if (strcasecmp(arg, "hard") == 0 || strcasecmp(arg, "hard_open") == 0 || strcasecmp(arg, "hard_init") == 0)
++			value = 1;
++		else if (strcasecmp(arg, "soft") == 0)
++			value = 0;
++		else
++			fatal("%.200s line %d: Bad soft/hard argument.", filename, linenum);
++		if (*intptr == -1)
++		break;
++
++	case lSSLPath:
++		charptr = &options.sslpath;
++		goto parse_string;
++
++	case lSSL:
++		intptr = &options.ssl;
++		arg = strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing yes/no/start_tls argument.", filename, linenum);
++		value = 0;	/* To avoid compiler warning... */
++		if (strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0 || strcasecmp(arg, "on") == 0)
++			value = SSL_LDAPS;
++		else if (strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0 || strcasecmp(arg, "off") == 0)
++			value = SSL_OFF;
++		else if (!strcasecmp (arg, "start_tls"))
++			value = SSL_START_TLS;
++		else
++			fatal("%.200s line %d: Bad yes/no/start_tls argument.", filename, linenum);
++		if (*intptr == -1)
++			*intptr = value;
++		break;
++
++	case lReferrals:
++		intptr = &options.referrals;
++parse_flag:
++		arg = strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
++		value = 0;	/* To avoid compiler warning... */
++		if (strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0 || strcasecmp(arg, "on") == 0)
++			value = 1;
++		else if (strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0 || strcasecmp(arg, "off") == 0)
++			value = 0;
++		else
++			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
++		if (*intptr == -1)
++			*intptr = value;
++		break;
++
++	case lRestart:
++		intptr = &options.restart;
++		goto parse_flag;
++
++	case lTLS_CheckPeer:
++		intptr = &options.tls_checkpeer;
++		arg = strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing never/hard/demand/alow/try argument.", filename, linenum);
++		value = 0;	/* To avoid compiler warning... */
++		if (strcasecmp(arg, "never") == 0 || strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0 || strcasecmp(arg, "off") == 0)
++			value = LDAP_OPT_X_TLS_NEVER;
++		else if (strcasecmp(arg, "hard") == 0 || strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0 || strcasecmp(arg, "on") == 0)
++			value = LDAP_OPT_X_TLS_HARD;
++		else if (strcasecmp(arg, "demand") == 0)
++			value = LDAP_OPT_X_TLS_DEMAND;
++		else if (strcasecmp(arg, "allow") == 0)
++			value = LDAP_OPT_X_TLS_ALLOW;
++		else if (strcasecmp(arg, "try") == 0)
++			value = LDAP_OPT_X_TLS_TRY;
++		else
++			fatal("%.200s line %d: Bad never/hard/demand/alow/try argument.", filename, linenum);
++		if (*intptr == -1)
++		break;
++
++	case lTLS_CaCertFile:
++		charptr = &options.tls_cacertfile;
++		goto parse_string;
++
++	case lTLS_CaCertDir:
++		charptr = &options.tls_cacertdir;
++		goto parse_string;
++
++	case lTLS_Ciphers:
++		xstringptr = &options.tls_ciphers;
++		goto parse_xstring;
++
++	case lTLS_Cert:
++		charptr = &options.tls_cert;
++		goto parse_string;
++
++	case lTLS_Key:
++		charptr = &options.tls_key;
++		goto parse_string;
++
++	case lTLS_RandFile:
++		charptr = &options.tls_randfile;
++		goto parse_string;
++
++	case lLogDir:
++		charptr = &options.logdir;
++		goto parse_string;
++
++	case lDebug:
++		intptr = &options.debug;
++		goto parse_int;
++
++	case lSSH_Filter:
++		xstringptr = &options.ssh_filter;
++		goto parse_xstring;
++
++	case lDeprecated:
++		debug("%s line %d: Deprecated option \"%s\"",
++		    filename, linenum, keyword);
++		return 0;
++
++	case lUnsupported:
++		error("%s line %d: Unsupported option \"%s\"",
++		    filename, linenum, keyword);
++		return 0;
++
++	default:
++		fatal("process_config_line: Unimplemented opcode %d", opcode);
++	}
++
++	/* Check that there is no garbage at end of line. */
++	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
++		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
++		    filename, linenum, arg);
++	}
++	return 0;
++}
++
++/*
++ * Reads the config file and modifies the options accordingly.  Options
++ * should already be initialized before this call.  This never returns if
++ * there is an error.  If the file does not exist, this returns 0.
++ */
++
++void
++read_config_file(const char *filename)
++{
++	FILE *f;
++	char line[1024];
++	int active, linenum;
++	int bad_options = 0;
++	struct stat sb;
++
++	if ((f = fopen(filename, "r")) == NULL)
++		fatal("fopen %s: %s", filename, strerror(errno));
++
++	if (fstat(fileno(f), &sb) == -1)
++		fatal("fstat %s: %s", filename, strerror(errno));
++	if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
++	    (sb.st_mode & 022) != 0))
++		fatal("Bad owner or permissions on %s", filename);
++
++	debug("Reading configuration data %.200s", filename);
++
++	/*
++	 * Mark that we are now processing the options.  This flag is turned
++	 * on/off by Host specifications.
++	 */
++	active = 1;
++	linenum = 0;
++	while (fgets(line, sizeof(line), f)) {
++		/* Update line number counter. */
++		linenum++;
++		if (process_config_line(line, filename, linenum) != 0)
++			bad_options++;
++	}
++	fclose(f);
++	if ((bad_options > 0) && config_exclusive_config_file) 
++		fatal("%s: terminating, %d bad configuration options",
++		    filename, bad_options);
++}
++
++/*
++ * Initializes options to special values that indicate that they have not yet
++ * been set.  Read_config_file will only set options with this value. Options
++ * are processed in the following order: command line, user config file,
++ * system config file.  Last, fill_default_options is called.
++ */
++
++void
++initialize_options(void)
++{
++	memset(&options, 'X', sizeof(options));
++	options.host = NULL;
++	options.uri = NULL;
++	options.base = NULL;
++	options.binddn = NULL;
++	options.bindpw = NULL;
++	options.scope = -1;
++	options.deref = -1;
++	options.port = -1;
++	options.timelimit = -1;
++	options.bind_timelimit = -1;
++	options.ldap_version = -1;
++	options.bind_policy = -1;
++	options.sslpath = NULL;
++	options.ssl = -1;
++	options.referrals = -1;
++	options.restart = -1;
++	options.tls_checkpeer = -1;
++	options.tls_cacertfile = NULL;
++	options.tls_cacertdir = NULL;
++	options.tls_ciphers = NULL;
++	options.tls_cert = NULL;
++	options.tls_key = NULL;
++	options.tls_randfile = NULL;
++	options.logdir = NULL;
++	options.debug = -1;
++	options.ssh_filter = NULL;
++}
++
++/*
++ * Called after processing other sources of option data, this fills those
++ * options for which no value has been specified with their default values.
++ */
++
++void
++fill_default_options(void)
++{
++	if (options.uri != NULL) {
++		LDAPURLDesc *ludp;
++
++		if (ldap_url_parse(options.uri, &ludp) == LDAP_SUCCESS) {
++			if (options.ssl == -1) {
++				if (strcmp (ludp->lud_scheme, "ldap") == 0)
++				    options.ssl = 2;
++				if (strcmp (ludp->lud_scheme, "ldapi") == 0)
++				    options.ssl = 0;
++				else if (strcmp (ludp->lud_scheme, "ldaps") == 0)
++				    options.ssl = 1;
++			}
++			if (options.host == NULL)
++			    options.host = xstrdup (ludp->lud_host);
++			if (options.port == -1)
++			    options.port = ludp->lud_port;
++
++			ldap_free_urldesc (ludp);
++		}
++	} 
++	if (options.ssl == -1)
++	    options.ssl = SSL_START_TLS;
++	if (options.port == -1)
++	    options.port = (options.ssl == 0) ? 389 : 636;
++	if (options.uri == NULL) {
++		int len;
++#define MAXURILEN 4096
++
++		options.uri = xmalloc (MAXURILEN);
++		len = snprintf (options.uri, MAXURILEN, "ldap%s://%s:%d",
++		    (options.ssl == 0) ? "" : "s", options.host, options.port);
++		options.uri[MAXURILEN - 1] = 0;
++		options.uri = xrealloc (options.uri, len + 1, 1);
++	}
++	if (options.binddn == NULL)
++	    options.binddn = "";
++	if (options.bindpw == NULL)
++	    options.bindpw = "";
++	if (options.scope == -1)
++	    options.scope = LDAP_SCOPE_SUBTREE;
++	if (options.deref == -1)
++	    options.deref = LDAP_DEREF_NEVER;
++	if (options.timelimit == -1)
++	    options.timelimit = 10;
++	if (options.bind_timelimit == -1)
++	    options.bind_timelimit = 10;
++	if (options.ldap_version == -1)
++	    options.ldap_version = 3;
++	if (options.bind_policy == -1)
++	    options.bind_policy = 1;
++	if (options.referrals == -1)
++	    options.referrals = 1;
++	if (options.restart == -1)
++	    options.restart = 1;
++	if (options.tls_checkpeer == -1)
++	    options.tls_checkpeer = LDAP_OPT_X_TLS_HARD;
++	if (options.debug == -1)
++	    options.debug = 0;
++	if (options.ssh_filter == NULL)
++	    options.ssh_filter = "";
++}
++
++static const char *
++lookup_opcode_name(OpCodes code)
++{
++	u_int i;
++
++	for (i = 0; keywords[i].name != NULL; i++)
++	    if (keywords[i].opcode == code)
++		return(keywords[i].name);
++	return "UNKNOWN";
++}
++
++static void
++dump_cfg_string(OpCodes code, const char *val)
++{
++	if (val == NULL)
++	    debug3("%s <UNDEFINED>", lookup_opcode_name(code));
++	else
++	    debug3("%s %s", lookup_opcode_name(code), val);
++}
++
++static void
++dump_cfg_int(OpCodes code, int val)
++{
++	if (val == -1)
++	    debug3("%s <UNDEFINED>", lookup_opcode_name(code));
++	else
++	    debug3("%s %d", lookup_opcode_name(code), val);
++}
++
++struct names {
++	int value;
++	char *name;
++};
++
++static void
++dump_cfg_namedint(OpCodes code, int val, struct names *names)
++{
++	u_int i;
++
++	if (val == -1)
++	    debug3("%s <UNDEFINED>", lookup_opcode_name(code));
++	else {
++		for (i = 0; names[i].value != -1; i++)
++	 	    if (names[i].value == val) {
++	    		debug3("%s %s", lookup_opcode_name(code), names[i].name);
++			    return;
++		}
++		debug3("%s unknown: %d", lookup_opcode_name(code), val);
++	}
++}
++
++static struct names _yesnotls[] = {
++	{ 0, "No" },
++	{ 1, "Yes" },
++	{ 2, "Start_TLS" },
++	{ -1, NULL }};
++
++static struct names _scope[] = {
++	{ LDAP_SCOPE_BASE, "Base" },
++	{ LDAP_SCOPE_ONELEVEL, "One" },
++	{ LDAP_SCOPE_SUBTREE, "Sub"},
++	{ -1, NULL }};
++
++static struct names _deref[] = {
++	{ LDAP_DEREF_NEVER, "Never" },
++	{ LDAP_DEREF_SEARCHING, "Searching" },
++	{ LDAP_DEREF_FINDING, "Finding" },
++	{ LDAP_DEREF_ALWAYS, "Always" },
++	{ -1, NULL }};
++
++static struct names _yesno[] = {
++	{ 0, "No" },
++	{ 1, "Yes" },
++	{ -1, NULL }};
++
++static struct names _bindpolicy[] = {
++	{ 0, "Soft" },
++	{ 1, "Hard" },
++	{ -1, NULL }};
++
++static struct names _checkpeer[] = {
++	{ LDAP_OPT_X_TLS_NEVER, "Never" },
++	{ LDAP_OPT_X_TLS_HARD, "Hard" },
++	{ LDAP_OPT_X_TLS_DEMAND, "Demand" },
++	{ LDAP_OPT_X_TLS_ALLOW, "Allow" },
++	{ LDAP_OPT_X_TLS_TRY, "TRY" },
++	{ -1, NULL }};
++
++void
++dump_config(void)
++{
++	dump_cfg_string(lURI, options.uri);
++	dump_cfg_string(lHost, options.host);
++	dump_cfg_int(lPort, options.port);
++	dump_cfg_namedint(lSSL, options.ssl, _yesnotls);
++	dump_cfg_int(lLdap_Version, options.ldap_version);
++	dump_cfg_int(lTimeLimit, options.timelimit);
++	dump_cfg_int(lBind_TimeLimit, options.bind_timelimit);
++	dump_cfg_string(lBase, options.base);
++	dump_cfg_string(lBindDN, options.binddn);
++	dump_cfg_string(lBindPW, options.bindpw);
++	dump_cfg_namedint(lScope, options.scope, _scope);
++	dump_cfg_namedint(lDeref, options.deref, _deref);
++	dump_cfg_namedint(lReferrals, options.referrals, _yesno);
++	dump_cfg_namedint(lRestart, options.restart, _yesno);
++	dump_cfg_namedint(lBind_Policy, options.bind_policy, _bindpolicy);
++	dump_cfg_string(lSSLPath, options.sslpath);
++	dump_cfg_namedint(lTLS_CheckPeer, options.tls_checkpeer, _checkpeer);
++	dump_cfg_string(lTLS_CaCertFile, options.tls_cacertfile);
++	dump_cfg_string(lTLS_CaCertDir, options.tls_cacertdir);
++	dump_cfg_string(lTLS_Ciphers, options.tls_ciphers);
++	dump_cfg_string(lTLS_Cert, options.tls_cert);
++	dump_cfg_string(lTLS_Key, options.tls_key);
++	dump_cfg_string(lTLS_RandFile, options.tls_randfile);
++	dump_cfg_string(lLogDir, options.logdir);
++	dump_cfg_int(lDebug, options.debug);
++	dump_cfg_string(lSSH_Filter, options.ssh_filter);
++}
++
+diff -up openssh-5.3p1/ldapconf.h.ldap openssh-5.3p1/ldapconf.h
+--- openssh-5.3p1/ldapconf.h.ldap	2011-03-10 22:39:35.055854552 +0100
++++ openssh-5.3p1/ldapconf.h	2011-03-10 22:39:35.065855563 +0100
+@@ -0,0 +1,71 @@
++/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef LDAPCONF_H
++#define LDAPCONF_H
++
++#define SSL_OFF          0
++#define SSL_LDAPS        1
++#define SSL_START_TLS    2
++
++/* Data structure for representing option data. */
++
++typedef struct {
++	char *host;
++	char *uri;
++	char *base;
++	char *binddn;
++	char *bindpw;
++	int scope;
++	int deref;
++	int port;
++	int timelimit;
++	int bind_timelimit;
++	int ldap_version;
++	int bind_policy;
++	char *sslpath;
++	int ssl;
++	int referrals;
++	int restart;
++	int tls_checkpeer;
++	char *tls_cacertfile;
++	char *tls_cacertdir;
++	char *tls_ciphers;
++	char *tls_cert;
++	char *tls_key;
++	char *tls_randfile;
++	char *logdir;
++	int debug;
++	char *ssh_filter;
++}       Options;
++
++extern Options options;
++
++void read_config_file(const char *);
++void initialize_options(void);
++void fill_default_options(void);
++void dump_config(void);
++
++#endif /* LDAPCONF_H */
+diff -up openssh-5.3p1/ldap.conf.ldap openssh-5.3p1/ldap.conf
+--- openssh-5.3p1/ldap.conf.ldap	2011-03-10 22:39:35.079855199 +0100
++++ openssh-5.3p1/ldap.conf	2011-03-10 22:39:35.087979869 +0100
+@@ -0,0 +1,88 @@
++# $Id: openssh-5.5p1-ldap.patch,v 1.3 2010/07/07 13:48:36 jfch2222 Exp $
++#
++# This is the example configuration file for the OpenSSH
++# LDAP backend
++# 
++# see ssh-ldap.conf(5)
++#
++
++# URI with your LDAP server name. This allows to use
++# Unix Domain Sockets to connect to a local LDAP Server.
++#uri ldap://127.0.0.1/
++#uri ldaps://127.0.0.1/   
++#uri ldapi://%2fvar%2frun%2fldapi_sock/
++# Note: %2f encodes the '/' used as directory separator
++
++# Another way to specify your LDAP server is to provide an
++# host name and the port of our LDAP server. Host name
++# must be resolvable without using LDAP.
++# Multiple hosts may be specified, each separated by a 
++# space. How long nss_ldap takes to failover depends on
++# whether your LDAP client library supports configurable
++# network or connect timeouts (see bind_timelimit).
++#host 127.0.0.1
++
++# The port.
++# Optional: default is 389.
++#port 389
++
++# The distinguished name to bind to the server with.
++# Optional: default is to bind anonymously.
++#binddn cn=openssh_keys,dc=example,dc=org
++
++# The credentials to bind with. 
++# Optional: default is no credential.
++#bindpw TopSecret
++
++# The distinguished name of the search base.
++#base dc=example,dc=org
++
++# The LDAP version to use (defaults to 3
++# if supported by client library)
++#ldap_version 3
++
++# The search scope.
++#scope sub
++#scope one
++#scope base
++
++# Search timelimit
++#timelimit 30
++
++# Bind/connect timelimit
++#bind_timelimit 30
++
++# Reconnect policy: hard (default) will retry connecting to
++# the software with exponential backoff, soft will fail
++# immediately.
++#bind_policy hard
++
++# SSL setup, may be implied by URI also.
++#ssl no
++#ssl on
++#ssl start_tls
++
++# OpenLDAP SSL options
++# Require and verify server certificate (yes/no)
++# Default is to use libldap's default behavior, which can be configured in
++# /etc/openldap/ldap.conf using the TLS_REQCERT setting.  The default for
++# OpenLDAP 2.0 and earlier is "no", for 2.1 and later is "yes".
++#tls_checkpeer hard
++
++# CA certificates for server certificate verification
++# At least one of these are required if tls_checkpeer is "yes"
++#tls_cacertfile /etc/ssl/ca.cert
++#tls_cacertdir /etc/pki/tls/certs
++
++# Seed the PRNG if /dev/urandom is not provided
++#tls_randfile /var/run/egd-pool
++
++# SSL cipher suite
++# See man ciphers for syntax
++#tls_ciphers TLSv1
++
++# Client certificate and key
++# Use these, if your server requires client authentication.
++#tls_cert
++#tls_key
++
+diff -up openssh-5.3p1/ldap-helper.c.ldap openssh-5.3p1/ldap-helper.c
+--- openssh-5.3p1/ldap-helper.c.ldap	2011-03-10 22:39:35.102854543 +0100
++++ openssh-5.3p1/ldap-helper.c	2011-03-10 22:39:35.111854833 +0100
+@@ -0,0 +1,155 @@
++/* $OpenBSD: ssh-pka-ldap.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "ldapincludes.h"
++#include "log.h"
++#include "misc.h"
++#include "xmalloc.h"
++#include "ldapconf.h"
++#include "ldapbody.h"
++#include <string.h>
++#include <unistd.h>
++
++static int config_debug = 0;
++int config_exclusive_config_file = 0;
++static char *config_file_name = "/etc/ssh/ldap.conf";
++static char *config_single_user = NULL;
++static int config_verbose = SYSLOG_LEVEL_VERBOSE;
++int config_warning_config_file = 0;
++extern char *__progname;
++
++static void
++usage(void)
++{
++	fprintf(stderr, "usage: %s [options]\n",
++	    __progname);
++	fprintf(stderr, "Options:\n");
++	fprintf(stderr, "  -d          Output the log messages to stderr.\n");
++	fprintf(stderr, "  -e          Check the config file for unknown commands.\n");
++	fprintf(stderr, "  -f file     Use alternate config file (default is /etc/ssh/ldap.conf).\n");
++	fprintf(stderr, "  -s user     Do not demonize, send the user's key to stdout.\n");
++	fprintf(stderr, "  -v          Increase verbosity of the debug output (implies -d).\n");
++	fprintf(stderr, "  -w          Warn on unknown commands in the config file.\n");
++	exit(1);
++}
++
++/*
++ * Main program for the ssh pka ldap agent.
++ */
++
++int
++main(int ac, char **av)
++{
++	int opt;
++	FILE *outfile = NULL;
++
++	__progname = ssh_get_progname(av[0]);
++
++	log_init(__progname, SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0);
++
++	/*
++	 * Initialize option structure to indicate that no values have been
++	 * set.
++	 */
++	initialize_options();
++
++	/* Parse command-line arguments. */
++	while ((opt = getopt(ac, av, "def:s:vw")) != -1) {
++		switch (opt) {
++		case 'd':
++			config_debug = 1;
++			break;
++
++		case 'e':
++			config_exclusive_config_file = 1;
++			config_warning_config_file = 1;
++			break;
++
++		case 'f':
++			config_file_name = optarg;
++			break;
++
++		case 's':
++			config_single_user = optarg;
++			outfile = fdopen (dup (fileno (stdout)), "w");
++			break;
++
++		case 'v':
++			config_debug = 1;
++			if (config_verbose < SYSLOG_LEVEL_DEBUG3)
++			    config_verbose++;
++			break;
++
++		case 'w':
++			config_warning_config_file = 1;
++			break;
++
++		case '?':
++		default:
++			usage();
++			break;
++		}
++	}
++
++	/* Initialize loging */
++	log_init(__progname, config_verbose, SYSLOG_FACILITY_AUTH, config_debug);
++
++	if (ac != optind)
++	    fatal ("illegal extra parameter %s", av[1]);
++
++	/* Ensure that fds 0 and 2 are open or directed to /dev/null */
++	if (config_debug == 0)
++	    sanitise_stdfd();
++
++	/* Read config file */
++	read_config_file(config_file_name);
++	fill_default_options();
++	if (config_verbose == SYSLOG_LEVEL_DEBUG3) {
++		debug3 ("=== Configuration ===");
++		dump_config();
++		debug3 ("=== *** ===");
++	}
++
++	ldap_checkconfig();
++	ldap_do_connect();
++
++	if (config_single_user) {
++		process_user (config_single_user, outfile);
++	} else {
++		usage();
++		fatal ("Not yet implemented");
++/* TODO
++ * open unix socket a run the loop on it
++ */
++	}
++
++	ldap_do_close();
++	return 0;
++}
++
++/* Ugly hack */
++void   *buffer_get_string(Buffer *b, u_int *l) {}
++void    buffer_put_string(Buffer *b, const void *f, u_int l) {}
++
+diff -up openssh-5.3p1/ldap-helper.h.ldap openssh-5.3p1/ldap-helper.h
+--- openssh-5.3p1/ldap-helper.h.ldap	2011-03-10 22:39:35.126854639 +0100
++++ openssh-5.3p1/ldap-helper.h	2011-03-10 22:39:35.134854896 +0100
+@@ -0,0 +1,32 @@
++/* $OpenBSD: ldap-helper.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef LDAP_HELPER_H
++#define LDAP_HELPER_H
++
++extern int config_exclusive_config_file;
++extern int config_warning_config_file;
++
++#endif /* LDAP_HELPER_H */
+diff -up openssh-5.3p1/ldapincludes.h.ldap openssh-5.3p1/ldapincludes.h
+--- openssh-5.3p1/ldapincludes.h.ldap	2011-03-10 22:39:35.147854785 +0100
++++ openssh-5.3p1/ldapincludes.h	2011-03-10 22:39:35.155979595 +0100
+@@ -0,0 +1,41 @@
++/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef LDAPINCLUDES_H
++#define LDAPINCLUDES_H
++
++#include "includes.h"
++
++#ifdef HAVE_LBER_H
++#include <lber.h>
++#endif
++#ifdef HAVE_LDAP_H
++#include <ldap.h>
++#endif
++#ifdef HAVE_LDAP_SSL_H
++#include <ldap_ssl.h>
++#endif
++
++#endif /* LDAPINCLUDES_H */
+diff -up openssh-5.3p1/ldapmisc.c.ldap openssh-5.3p1/ldapmisc.c
+--- openssh-5.3p1/ldapmisc.c.ldap	2011-03-10 22:39:35.169854892 +0100
++++ openssh-5.3p1/ldapmisc.c	2011-03-10 22:39:35.177981004 +0100
+@@ -0,0 +1,79 @@
++
++#include "ldapincludes.h"
++#include "ldapmisc.h"
++
++#ifndef HAVE_LDAP_GET_LDERRNO
++int
++ldap_get_lderrno (LDAP * ld, char **m, char **s)
++{
++#ifdef HAVE_LDAP_GET_OPTION
++	int rc;
++#endif
++	int lderrno;
++
++#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
++	if ((rc = ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, &lderrno)) != LDAP_SUCCESS)
++	    return rc;
++#else
++	lderrno = ld->ld_errno;
++#endif
++
++	if (s != NULL) {
++#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_STRING)
++		if ((rc = ldap_get_option (ld, LDAP_OPT_ERROR_STRING, s)) != LDAP_SUCCESS)
++		    return rc;
++#else
++		*s = ld->ld_error;
++#endif
++	}
++
++	if (m != NULL) {
++#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_MATCHED_DN)
++		if ((rc = ldap_get_option (ld, LDAP_OPT_MATCHED_DN, m)) != LDAP_SUCCESS)
++		    return rc;
++#else
++		*m = ld->ld_matched;
++#endif
++	}
++
++	return lderrno;
++}
++#endif
++
++#ifndef HAVE_LDAP_SET_LDERRNO
++int
++ldap_set_lderrno (LDAP * ld, int lderrno, const char *m, const char *s)
++{
++#ifdef HAVE_LDAP_SET_OPTION
++	int rc;
++#endif
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
++	if ((rc = ldap_set_option (ld, LDAP_OPT_ERROR_NUMBER, &lderrno)) != LDAP_SUCCESS)
++	    return rc;
++#else
++	ld->ld_errno = lderrno;
++#endif
++
++	if (s != NULL) {
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_ERROR_STRING)
++		if ((rc = ldap_set_option (ld, LDAP_OPT_ERROR_STRING, s)) != LDAP_SUCCESS)
++		    return rc;
++#else
++		ld->ld_error = s;
++#endif
++	}
++
++	if (m != NULL) {
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_MATCHED_DN)
++		if ((rc = ldap_set_option (ld, LDAP_OPT_MATCHED_DN, m)) != LDAP_SUCCESS)
++		    return rc;
++#else
++		ld->ld_matched = m;
++#endif
++	}
++
++	return LDAP_SUCCESS;
++}
++#endif
++
+diff -up openssh-5.3p1/ldapmisc.h.ldap openssh-5.3p1/ldapmisc.h
+--- openssh-5.3p1/ldapmisc.h.ldap	2011-03-10 22:39:35.192855203 +0100
++++ openssh-5.3p1/ldapmisc.h	2011-03-10 22:39:35.201854926 +0100
+@@ -0,0 +1,35 @@
++/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef LDAPMISC_H
++#define LDAPMISC_H
++
++#include "ldapincludes.h"
++
++int ldap_get_lderrno (LDAP *, char **, char **);
++int ldap_set_lderrno (LDAP *, int, const char *, const char *);
++
++#endif /* LDAPMISC_H */
++
+diff -up openssh-5.3p1/Makefile.in.ldap openssh-5.3p1/Makefile.in
+--- openssh-5.3p1/Makefile.in.ldap	2011-03-10 22:39:33.602854839 +0100
++++ openssh-5.3p1/Makefile.in	2011-03-10 22:39:35.237854870 +0100
+@@ -25,6 +25,8 @@ SSH_PROGRAM=@bindir@/ssh
+ ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass
+ SFTP_SERVER=$(libexecdir)/sftp-server
+ SSH_KEYSIGN=$(libexecdir)/ssh-keysign
++SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper
++SSH_LDAP_WRAPPER=$(libexecdir)/ssh-ldap-wrapper
+ RAND_HELPER=$(libexecdir)/ssh-rand-helper
+ PRIVSEP_PATH=@PRIVSEP_PATH@
+ SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
+@@ -59,8 +61,9 @@ EXEEXT=@EXEEXT@
+ 
+ INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
+ INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
++INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@
+ 
+-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT)
++TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT)
+ 
+ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
+ 	canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \
+@@ -91,8 +94,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw
+ 	audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \
+ 	roaming_common.o
+ 
+-MANPAGES	= moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out sshd_config.5.out ssh_config.5.out
+-MANPAGES_IN	= moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 sshd_config.5 ssh_config.5
++MANPAGES	= moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out ssh-ldap-helper.8.out sshd_config.5.out ssh_config.5.out ssh-ldap.conf.5.out
++MANPAGES_IN	= moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 ssh-ldap-helper.8 sshd_config.5 ssh_config.5 ssh-ldap.conf.5
+ MANTYPE		= @MANTYPE@
+ 
+ CONFIGFILES=sshd_config.out ssh_config.out moduli.out
+@@ -160,6 +163,9 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libss
+ 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 -lfipscheck $(LIBS)
+ 
++ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o
++	$(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck -lldap -llber $(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)
+ 
+@@ -266,6 +272,10 @@ install-files: scard-install
+ 		$(INSTALL) -m 0755 $(STRIP_OPT) ssh-rand-helper $(DESTDIR)$(libexecdir)/ssh-rand-helper ; \
+ 	fi
+ 	$(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign $(DESTDIR)$(SSH_KEYSIGN)
++	if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \
++		$(INSTALL) -m 0700 $(STRIP_OPT) ssh-ldap-helper $(DESTDIR)$(SSH_LDAP_HELPER) ; \
++		$(INSTALL) -m 0700 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \
++	fi
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) sftp $(DESTDIR)$(bindir)/sftp
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) sftp-server $(DESTDIR)$(SFTP_SERVER)
+ 	$(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
+@@ -281,6 +291,10 @@ install-files: scard-install
+ 	if [ ! -z "$(INSTALL_SSH_RAND_HELPER)" ]; then \
+ 		$(INSTALL) -m 644 ssh-rand-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-rand-helper.8 ; \
+ 	fi
++	if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \
++		$(INSTALL) -m 644 ssh-ldap-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-ldap-helper.8 ; \
++		$(INSTALL) -m 644 ssh-ldap.conf.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/ssh-ldap.conf.5 ; \
++	fi
+ 	$(INSTALL) -m 644 sftp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1
+ 	$(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
+ 	$(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
+@@ -320,6 +334,13 @@ install-sysconf:
+ 	else \
+ 		echo "$(DESTDIR)$(sysconfdir)/moduli already exists, install will not overwrite"; \
+ 	fi
++	if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \
++		if [ ! -f $(DESTDIR)$(sysconfdir)/ldap.conf ]; then \
++			$(INSTALL) -m 644 ldap.conf $(DESTDIR)$(sysconfdir)/ldap.conf; \
++		else \
++			echo "$(DESTDIR)$(sysconfdir)/ldap.conf already exists, install will not overwrite"; \
++		fi ; \
++	fi
+ 
+ host-key: ssh-keygen$(EXEEXT)
+ 	@if [ -z "$(DESTDIR)" ] ; then \
+@@ -381,6 +402,7 @@ uninstall:
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-rand-helper.8
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
++	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-ldap-helper.8
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
+ 
+ tests interop-tests:	$(TARGETS)
+diff -up openssh-5.3p1/openssh-lpk-openldap.schema.ldap openssh-5.3p1/openssh-lpk-openldap.schema
+--- openssh-5.3p1/openssh-lpk-openldap.schema.ldap	2011-03-10 22:39:35.263854862 +0100
++++ openssh-5.3p1/openssh-lpk-openldap.schema	2011-03-10 22:39:35.271854845 +0100
+@@ -0,0 +1,21 @@
++#
++# LDAP Public Key Patch schema for use with openssh-ldappubkey
++#                              useful with PKA-LDAP also
++#
++# Author: Eric AUGE <eau at phear.org>
++# 
++# Based on the proposal of : Mark Ruijter
++#
++
++
++# octetString SYNTAX
++attributetype ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' 
++	DESC 'MANDATORY: OpenSSH Public key' 
++	EQUALITY octetStringMatch
++	SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
++
++# printableString SYNTAX yes|no
++objectclass ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
++	DESC 'MANDATORY: OpenSSH LPK objectclass'
++	MUST ( sshPublicKey $ uid ) 
++	)
+diff -up openssh-5.3p1/openssh-lpk-sun.schema.ldap openssh-5.3p1/openssh-lpk-sun.schema
+--- openssh-5.3p1/openssh-lpk-sun.schema.ldap	2011-03-10 22:39:35.285854812 +0100
++++ openssh-5.3p1/openssh-lpk-sun.schema	2011-03-10 22:39:35.295979788 +0100
+@@ -0,0 +1,23 @@
++#
++# LDAP Public Key Patch schema for use with openssh-ldappubkey
++#                              useful with PKA-LDAP also
++#
++# Author: Eric AUGE <eau at phear.org>
++# 
++# Schema for Sun Directory Server.
++# Based on the original schema, modified by Stefan Fischer.
++#
++
++dn: cn=schema
++
++# octetString SYNTAX
++attributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' 
++	DESC 'MANDATORY: OpenSSH Public key' 
++	EQUALITY octetStringMatch
++	SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
++
++# printableString SYNTAX yes|no
++objectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
++	DESC 'MANDATORY: OpenSSH LPK objectclass'
++	MUST ( sshPublicKey $ uid ) 
++	)
+diff -up openssh-5.3p1/ssh-ldap.conf.5.ldap openssh-5.3p1/ssh-ldap.conf.5
+--- openssh-5.3p1/ssh-ldap.conf.5.ldap	2011-03-10 22:39:35.310854926 +0100
++++ openssh-5.3p1/ssh-ldap.conf.5	2011-03-10 22:39:35.319854605 +0100
+@@ -0,0 +1,373 @@
++.\" $OpenBSD: ssh-ldap.conf.5,v 1.1 2010/02/10 23:20:38 markus Exp $
++.\"
++.\" Copyright (c) 2010 Jan F. Chadima.  All rights reserved.
++.\"
++.\" Permission to use, copy, modify, and distribute this software for any
++.\" purpose with or without fee is hereby granted, provided that the above
++.\" copyright notice and this permission notice appear in all copies.
++.\"
++.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++.\"
++.Dd $Mdocdate: may 12 2010 $
++.Dt SSH-LDAP.CONF 5
++.Os
++.Sh NAME
++.Nm ssh-ldap.conf
++.Nd configuration file for ssh-ldap-helper
++.Sh SYNOPSIS
++.Nm /etc/ssh/ldap.conf
++.Sh DESCRIPTION
++.Xr ssh-ldap-helper 8
++reads configuration data from
++.Pa /etc/ssh/ldap.conf
++(or the file specified with
++.Fl f
++on the command line).
++The file contains keyword-argument pairs, one per line.
++Lines starting with
++.Ql #
++and empty lines are interpreted as comments.
++.Pp
++The value starts with the first non-blank character after 
++the keyword's name, and terminates at the end of the line, 
++or at the last sequence of blanks before the end of the line.
++Quoting values that contain blanks 
++may be incorrect, as the quotes would become part of the value.
++The possible keywords and their meanings are as follows (note that
++keywords are case-insensitive, and arguments, on a case by case basis, may be case-sensitive).
++.It Cm URI
++The argument(s) are in the form
++.Pa ldap[si]://[name[:port]]
++and specify the URI(s) of an LDAP server(s) to which the
++.Xr ssh-ldap-helper 8 
++should connect. The URI scheme may be any of
++.Dq ldap ,
++.Dq ldaps 
++or
++.Dq ldapi ,
++which refer to LDAP over TCP, LDAP over SSL (TLS) and LDAP
++over IPC (UNIX domain sockets), respectively.
++Each server's name can be specified as a
++domain-style name or an IP address literal.  Optionally, the
++server's name can followed by a ':' and the port number the LDAP
++server is listening on.  If no port number is provided, the default
++port for the scheme is used (389 for ldap://, 636 for ldaps://).
++For LDAP over IPC, name is the name of the socket, and no port
++is required, nor allowed; note that directory separators must be 
++URL-encoded, like any other characters that are special to URLs; 
++A space separated list of URIs may be provided.
++There is no default.
++.It Cm Base
++Specifies the default base Distinguished Name (DN) to use when performing ldap operations.
++The base must be specified as a DN in LDAP format.
++There is no default.
++.It Cm BindDN
++Specifies the default BIND DN to use when connecting to the ldap server.
++The bind DN must be specified as a Distinguished Name in LDAP format.
++There is no default.
++.It Cm BindPW
++Specifies the default password to use when connecting to the ldap server via
++.Cm BindDN .
++There is no default.
++.It Cm RootBindDN
++Intentionaly does nothing. Recognized for compatibility reasons.
++.It Cm Host
++The argument(s) specifies the name(s) of an LDAP server(s) to which the
++.Xr ssh-ldap-helper 8
++should connect.  Each server's name can be specified as a
++domain-style name or an IP address and optionally followed by a ':' and
++the port number the ldap server is listening on.  A space-separated
++list of hosts may be provided.
++There is no default.
++.Cm Host
++is deprecated in favor of
++.Cm URI .
++.It Cm Port
++Specifies the default port used when connecting to LDAP servers(s).
++The port may be specified as a number.
++The default port is 389 for ldap:// or 636 for ldaps:// respectively.
++.Cm Port
++is deprecated in favor of
++.Cm URI .
++.It Cm Scope
++Specifies the starting point of an LDAP search and the depth from the base DN to which the search should descend.
++There are three options (values) that can be assigned to the
++.Cm Scope parameter:
++.Dq base ,
++.Dq one
++and
++.Dq subtree .
++Alias for the subtree is
++.Dq sub .
++The value
++.Dq base
++is used to indicate searching only the entry at the base DN, resulting in only that entry being returned (keeping in mind that it also has to meet the search filter criteria!).
++The value
++.Dq one
++is used to indicate searching all entries one level under the base DN, but not including the base DN and not including any entries under that one level under the base DN.
++The value
++.Dq subtree
++is used to indicate searching of all entries at all levels under and including the specified base DN.
++The default is
++.Dq subtree .
++.It Cm Deref
++Specifies how alias dereferencing is done when performing a search. There are four
++possible values that can be assigned to the
++.Cm Deref
++parameter:
++.Dq never ,
++.Dq searching ,
++.Dq finding ,
++and
++.Dq always .
++The value
++.Dq never
++means that the aliases are never dereferenced.
++The value
++.Dq searching
++means that the aliases are dereferenced in subordinates of the base object, but
++not in locating the base object of the search.
++The value
++.Dq finding
++means that the aliases are only dereferenced when locating the base object of the search.
++The value
++.Dq always
++means that the aliases are dereferenced both in searching and in locating the base object
++of the search.
++The default is
++.Dq never .
++.It Cm TimeLimit
++Specifies a time limit (in seconds) to use when performing searches.
++The number should be a non-negative integer. A
++.Cm TimeLimit
++of zero (0) specifies that the search time is unlimited. Please note that the server
++may still apply any server-side limit on the duration of a search operation.
++The default value is 10.
++.It Cm TimeOut
++Is an aliast to
++.Cm TimeLimit .
++.It Cm Bind_TimeLimit
++Specifies the timeout (in seconds) after which the poll(2)/select(2)
++following a connect(2) returns in case of no activity.
++The default value is 10.
++.It Cm Network_TimeOut
++Is an alias to
++.Cm Bind_TimeLimit .
++.It Cm Ldap_Version
++Specifies what version of the LDAP protocol should be used.
++The allowed values are 2 or 3. The default is 3.
++.It Cm Version
++Is an alias to
++.Cm Ldap_Version .
++.It Cm Bind_Policy
++Specifies the policy to use for reconnecting to an unavailable LDAP server. There are 2 available values:
++.Dq hard
++and
++.Dq soft.
++.Dq hard has 2 aliases
++.Dq hard_open
++and
++.Dq hard_init .
++The value
++.Dq hard
++means that reconects that the
++.Xr ssh-ldap-helper 8
++tries to reconnect to the LDAP server 5 times before failure. There is exponential backoff before retrying.
++The value
++.Dq soft
++means that
++.Xr ssh-ldap-helper 8
++fails immediately when it cannot connect to the LDAP seerver.
++The deault is
++.Dq hard .
++.It Cm SSLPath
++Specifies the path to the X.509 certificate database.
++There is no default.
++.It Cm SSL
++Specifies whether to use SSL/TLS or not.
++There are three allowed values:
++.Dq yes ,
++.Dq no
++and
++.Dq start_tls
++Both
++.Dq true
++and
++.Dq on
++are the aliases for
++.Dq yes .
++.Dq false
++and
++.Dq off
++are the aliases for
++.Dq no .
++If
++.Dqstart_tls
++is specified then StartTLS is used rather than raw LDAP over SSL.
++The default for ldap:// is
++.Dq start_tls ,
++for ldaps://
++.Dq yes
++and
++.Dq no
++for the ldapi:// .
++In case of host based configuration the default is
++.Dq start_tls .
++.It Cm Referrals
++Specifies if the client should automatically follow referrals returned
++by LDAP servers.
++The value can be or
++.Dq yes
++or
++.Dq no .
++.Dq true
++and
++.Dq on
++are the aliases for
++.Dq yes .
++.Dq false
++and
++.Dq off
++are the aliases for
++.Dq no .
++The default is yes.
++.It Cm Restart
++Specifies whether the LDAP client library should restart the select(2) system call when interrupted.
++The value can be or
++.Dq yes
++or
++.Dq no .
++.Dq true
++and
++.Dq on
++are the aliases for
++.Dq yes .
++.Dq false
++and
++.Dq off
++are the aliases for
++.Dq no .
++The default is yes.
++.It Cm TLS_CheckPeer
++Specifies what checks to perform on server certificates in a TLS session,
++if any. The value
++can be specified as one of the following keywords:
++.Dq never ,
++.Dq hard ,
++.Dq demand ,
++.Dq allow
++and
++.Dq try .
++.Dq true ,
++.Dq on
++and
++.Dq yes
++are aliases for
++.Dq hard .
++.Dq false ,
++.Dq off
++and
++.Dq no
++are the aliases for
++.Dq never .
++The value
++.Dq never
++means that the client will not request or check any server certificate.
++The value
++.Dq allow
++means that the server certificate is requested. If no certificate is provided,
++the session proceeds normally. If a bad certificate is provided, it will
++be ignored and the session proceeds normally.
++The value
++.Dq try
++means that the server certificate is requested. If no certificate is provided,
++the session proceeds normally. If a bad certificate is provided,
++the session is immediately terminated.
++The value
++.Dq demand
++means that the server certificate is requested. If no
++certificate is provided, or a bad certificate is provided, the session
++is immediately terminated.
++The value
++.Dq hard
++is the same as
++.Dq demand .
++It requires an SSL connection. In the case of the plain conection the
++session is immediately terminated.
++The default is
++.Dq hard .
++.It Cm TLS_ReqCert
++Is an alias for 
++.Cm TLS_CheckPeer .
++.It Cm TLS_CACertFile
++Specifies the file that contains certificates for all of the Certificate
++Authorities the client will recognize.
++There is no default.
++.It Cm TLS_CACert
++Is an alias for
++.Cm TLS_CACertFile .
++.It Cm TLS_CACertDIR
++Specifies the path of a directory that contains Certificate Authority
++certificates in separate individual files. The
++.Cm TLS_CACert
++is always used before
++.Cm TLS_CACertDir .
++The specified directory must be managed with the OpenSSL c_rehash utility.
++There is no default.
++.It Cm TLS_Ciphers
++Specifies acceptable cipher suite and preference order.
++The value should be a cipher specification for OpenSSL,
++e.g.,
++.Dq HIGH:MEDIUM:+SSLv2 .
++The default is
++.Dq ALL .
++.It Cm TLS_Cipher_Suite
++Is an alias for
++.Cm TLS_Ciphers .
++.It Cm TLS_Cert
++Specifies the file that contains the client certificate.
++There is no default.
++.It Cm TLS_Certificate
++Is an alias for
++.Cm TLS_Cert .
++.It Cm TLS_Key
++Specifies the file that contains the private key that matches the certificate
++stored in the
++.Cm TLS_Cert
++file. Currently, the private key must not be protected with a password, so
++it is of critical importance that the key file is protected carefully.
++There is no default.
++.It Cm TLS_RandFile
++Specifies the file to obtain random bits from when /dev/[u]random is
++not available. Generally set to the name of the EGD/PRNGD socket.
++The environment variable RANDFILE can also be used to specify the filename.
++There is no default.
++.It Cm LogDir
++Specifies the directory used for logging by the LDAP client library.
++There is no default.
++.It Cm Debug
++Specifies the debug level used for logging by the LDAP client library.
++There is no default.
++.It Cm SSH_Filter
++Specifies the user filter applied on the LDAP serch.
++The default is no filter.
++.Sh FILES
++.Bl -tag -width Ds
++.It Pa  /etc/ssh/ldap.conf
++Ldap configuration file for
++.Xr ssh-ldap-helper 8 .
++.Sh "SEE ALSO"
++.Xr ldap.conf 5 ,
++.Xr ssh-ldap-helper 8
++.Sh HISTORY
++.Nm
++first appeared in
++OpenSSH 5.5 + PKA-LDAP .
++.Sh AUTHORS
++.An Jan F. Chadima Aq jchadima at redhat.com
+diff -up openssh-5.3p1/ssh-ldap-helper.8.ldap openssh-5.3p1/ssh-ldap-helper.8
+--- openssh-5.3p1/ssh-ldap-helper.8.ldap	2011-03-10 22:39:35.333855077 +0100
++++ openssh-5.3p1/ssh-ldap-helper.8	2011-03-10 22:39:35.342854887 +0100
+@@ -0,0 +1,79 @@
++.\" $OpenBSD: ssh-ldap-helper.8,v 1.1 2010/02/10 23:20:38 markus Exp $
++.\"
++.\" Copyright (c) 2010 Jan F. Chadima.  All rights reserved.
++.\"
++.\" Permission to use, copy, modify, and distribute this software for any
++.\" purpose with or without fee is hereby granted, provided that the above
++.\" copyright notice and this permission notice appear in all copies.
++.\"
++.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++.\"
++.Dd $Mdocdate: April 29 2010 $
++.Dt SSH-LDAP-HELPER 8
++.Os
++.Sh NAME
++.Nm ssh-ldap-helper
++.Nd sshd helper program for ldap support
++.Sh SYNOPSIS
++.Nm ssh-ldap-helper
++.Op Fl devw
++.Op Fl f Ar file
++.Op Fl s Ar user
++.Sh DESCRIPTION
++.Nm
++is used by
++.Xr sshd 1
++to access keys provided by an LDAP.
++.Nm
++is disabled by default and can only be enabled in the
++sshd configuration file
++.Pa /etc/ssh/sshd_config
++by setting
++.Cm AuthorizedKeysCommand
++to
++.Dq /usr/libexec/ssh-ldap-wrapper .
++.Pp
++.Nm
++is not intended to be invoked by the user, but from
++.Xr sshd 8 via
++.Xr ssh-ldap-wrapper .
++.Pp
++The options are as follows:
++.Bl -tag -width Ds
++.It Fl d
++Set the debug mode; 
++.Nm
++prints all logs to stderr instead of syslog.
++.It Fl e
++Implies \-w;
++.Nm
++halts if it encounters an unknown item in the ldap.conf file.
++.It Fl f
++.Nm
++uses this file as the ldap configuration file instead of /etc/ssh/ldap.conf (default).
++.It Fl s
++.Nm
++prints out the user's keys to stdout and exits.
++.It Fl v
++Implies \-d;
++increases verbosity.
++.It Fl w
++.Nm
++writes warnings about unknown items in the ldap.conf configuration file.
++
++.Sh SEE ALSO
++.Xr sshd 8 ,
++.Xr sshd_config 5 ,
++.Xr ssh-ldap.conf 5 ,
++.Sh HISTORY
++.Nm
++first appeared in
++OpenSSH 5.5 + PKA-LDAP .
++.Sh AUTHORS
++.An Jan F. Chadima Aq jchadima at redhat.com
+diff -up openssh-5.3p1/ssh-ldap-wrapper.ldap openssh-5.3p1/ssh-ldap-wrapper
+--- openssh-5.3p1/ssh-ldap-wrapper.ldap	2011-03-10 22:39:35.356855153 +0100
++++ openssh-5.3p1/ssh-ldap-wrapper	2011-03-10 22:39:35.365854937 +0100
+@@ -0,0 +1,4 @@
++#!/bin/sh
++
++exec /usr/libexec/openssh/ssh-ldap-helper -s "$1"
++
diff --git a/openssh-5.3p1-mls.patch b/openssh-5.3p1-mls.patch
new file mode 100644
index 0000000..451b7e8
--- /dev/null
+++ b/openssh-5.3p1-mls.patch
@@ -0,0 +1,445 @@
+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);
diff --git a/openssh-5.3p1-multiple-sighup.patch b/openssh-5.3p1-multiple-sighup.patch
new file mode 100644
index 0000000..e775c9a
--- /dev/null
+++ b/openssh-5.3p1-multiple-sighup.patch
@@ -0,0 +1,11 @@
+--- openssh-5.3p1/sshd.c	2009-12-08 02:39:48 +0000
++++ openssh-5.3p1/sshd.c	2010-01-05 14:21:39 +0000
+@@ -306,6 +306,7 @@ static void
+ sighup_restart(void)
+ {
+ 	logit("Received SIGHUP; restarting.");
++	signal(SIGHUP, SIG_IGN); /* will be restored after exec */
+ 	close_listen_socks();
+ 	close_startup_pipes();
+ 	alarm(0);  /* alarm timer persists across exec */
+
diff --git a/openssh-5.3p1-nss-keys.patch b/openssh-5.3p1-nss-keys.patch
new file mode 100644
index 0000000..6a8c638
--- /dev/null
+++ b/openssh-5.3p1-nss-keys.patch
@@ -0,0 +1,1627 @@
+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	2011-01-20 11:30:34.000000000 +0100
+@@ -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	2011-01-20 11:30:34.000000000 +0100
+@@ -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	2011-01-20 11:30:33.000000000 +0100
++++ openssh-5.3p1/configure.ac	2011-01-20 11:30:34.000000000 +0100
+@@ -3514,6 +3514,21 @@ 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"
++		AC_CHECK_DECLS([SEC_ERROR_LOCKED_PASSWORD], [], [], [#include <secerr.h>])
++	fi
++	])
++AC_SUBST(LIBNSS)
++
+ # Looking for programs, paths and files
+ 
+ PRIVSEP_PATH=/var/empty
+@@ -4240,6 +4255,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	2011-01-20 11:30:34.000000000 +0100
+@@ -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	2011-01-20 11:30:34.000000000 +0100
+@@ -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	2011-01-20 11:30:34.000000000 +0100
+@@ -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 openssh-5.3p1/nsskeys.c.nss-keys openssh-5.3p1/nsskeys.c
+--- openssh-5.3p1/nsskeys.c.nss-keys	2011-01-20 11:30:34.000000000 +0100
++++ openssh-5.3p1/nsskeys.c	2011-01-20 11:30:34.000000000 +0100
+@@ -0,0 +1,443 @@
++/*
++ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
++ * Copyright (c) 2007 Red Hat, Inc. All rights reserved.
++ * Copyright (c) 2009 Pierre Ossman for Cendio AB
++ *
++ * 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 <secmod.h>
++#include <secerr.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) {
++		debug("Failed to initialize NSS library. Attempting without DB...");
++		if (NSS_NoDB_Init(NULL) != SECSuccess)
++			return -1;
++	}
++
++	if (pwfn == NULL) {
++		pwfn = password_cb;
++	}
++
++	PK11_SetPasswordFunc(pwfn);
++	
++	return 0;
++}
++
++int
++nss_load_module(const char *modpath)
++{
++	char spec[MAXPATHLEN + 40];
++	SECMODModule *module;
++
++	debug("loading PKCS#11 module '%s'", modpath);
++
++	snprintf(spec, sizeof(spec), "library=\"%s\" name=\"Foobar\"", modpath);
++	module = SECMOD_LoadUserModule(spec, NULL, PR_FALSE);
++	if (!module || !module->loaded) {
++		if (module)
++			SECMOD_DestroyModule(module);
++		return -1;
++	}
++
++	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 int
++nss_authenticate(PK11SlotInfo *slot, char *password, int pwprompts, char **output)
++{
++	int i, quit;
++
++	*output = NULL;
++
++	if (!PK11_NeedLogin(slot))
++		return 0;
++
++	for (i = 0; i < pwprompts; i++) {
++		SECStatus rv;
++		CK_TOKEN_INFO info;
++
++		rv = PK11_GetTokenInfo(slot, &info);
++		if (rv != SECSuccess) {
++			error("Failed to get information for token %s",
++				PK11_GetTokenName(slot));
++			return -1;
++		}
++
++		if (info.flags & CKF_USER_PIN_LOCKED) {
++			error("Passphrase for token %s is locked",
++				PK11_GetTokenName(slot));
++			return -1;
++		}
++
++		if (info.flags & CKF_USER_PIN_FINAL_TRY)
++			debug2("Final passphrase attempt for token %s",
++				PK11_GetTokenName(slot));
++		else if (info.flags & CKF_USER_PIN_COUNT_LOW)
++			debug2("Previous failed passphrase attempt for token %s",
++				PK11_GetTokenName(slot));
++
++		if (password != NULL)
++			*output = xstrdup(password);
++		else {
++			char *prompt;
++			if (asprintf(&prompt, "Enter passphrase for token %s: ",
++				PK11_GetTokenName(slot)) < 0)
++				fatal("password_cb: asprintf failed");
++			*output = read_passphrase(prompt, RP_ALLOW_STDIN);
++		}
++
++		if (strcmp(*output, "") == 0) {
++			debug2("no passphrase given, ignoring slot");
++			quit = 1;
++			goto cleanup;
++		}
++
++		quit = 0;
++
++		rv = PK11_Authenticate(slot, PR_TRUE, *output);
++		if (rv == SECSuccess)
++			return 0;
++
++		switch (PORT_GetError()) {
++		case SEC_ERROR_BAD_PASSWORD:
++			debug2("Incorrect passphrase, try again...");
++			break;
++		case SEC_ERROR_INVALID_ARGS:
++		case SEC_ERROR_BAD_DATA:
++			debug2("Invalid passphrase, try again...");
++			break;
++#if HAVE_SEC_ERROR_LOCKED_PASSWORD
++		case SEC_ERROR_LOCKED_PASSWORD:
++			error("Unable to authenticate, token passphrase is locked");
++			quit = 1;
++			break;
++#endif
++		default:
++			error("Failure while authenticating against token");
++			quit = 1;
++		}
++
++cleanup:
++		memset(*output, 0, strlen(*output));
++		xfree(*output);
++		*output = NULL;
++
++		/* No point in retrying the same password */
++		if (password != NULL)
++			break;
++
++		if (quit)
++			break;
++	}
++
++	return -1;
++}
++
++static Key **
++nss_find_privkeys(const char *tokenname, const char *keyname,
++    char *password, int pwprompts)
++{
++	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;
++
++		if (nss_authenticate(sle->slot, password, pwprompts, &tmppass) == -1)
++			break;
++
++		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 (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, int pwprompts, int num_modules, const char **modules)
++{
++	int i;
++	Key **keys;
++
++	if (nss_init(NULL) == -1) {
++		error("Failed to initialize NSS library");
++		return NULL;
++	}
++
++	for (i = 0;i < num_modules;i++) {
++		if (nss_load_module(modules[i]) == -1) {
++			error("Failed to load PKCS#11 module '%s'", modules[i]);
++			return NULL;
++		}
++	}
++
++	keys = nss_find_privkeys(tokenname, keyname, password, pwprompts);
++	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 openssh-5.3p1/nsskeys.h.nss-keys openssh-5.3p1/nsskeys.h
+--- openssh-5.3p1/nsskeys.h.nss-keys	2011-01-20 11:30:34.000000000 +0100
++++ openssh-5.3p1/nsskeys.h	2011-01-20 11:30:34.000000000 +0100
+@@ -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 *, int , int , const 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	2011-01-20 11:30:34.000000000 +0100
+@@ -124,6 +124,7 @@ typedef enum {
+ 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
+ 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
+ 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
++	oUseNSS, oNSSToken, oNSSModule,
+ 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
+ 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
+ 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
+@@ -210,6 +211,15 @@ static struct {
+ #else
+ 	{ "smartcarddevice", oUnsupported },
+ #endif
++#ifdef HAVE_LIBNSS
++	{ "usenss", oUseNSS },
++	{ "nsstoken", oNSSToken },
++	{ "nssmodule", oNSSModule },
++#else
++	{ "usenss", oUnsupported },
++	{ "nsstoken", oNSSToken },
++	{ "nssmodule", oUnsupported },
++#endif
+ 	{ "clearallforwardings", oClearAllForwardings },
+ 	{ "enablesshkeysign", oEnableSSHKeysign },
+ 	{ "verifyhostkeydns", oVerifyHostKeyDNS },
+@@ -613,6 +623,28 @@ 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 oNSSModule:
++		arg = strdelim(&s);
++		if (!arg || *arg == '\0')
++			fatal("%.200s line %d: Missing argument.", filename, linenum);
++		if (*activep) {
++			intptr = &options->num_nss_modules;
++			if (*intptr >= SSH_MAX_NSS_MODULES)
++				fatal("%.200s line %d: Too many PKCS#11 modules specified (max %d).",
++				    filename, linenum, SSH_MAX_NSS_MODULES);
++			charptr = &options->nss_modules[*intptr];
++			*charptr = xstrdup(arg);
++			*intptr = *intptr + 1;
++		}
++		break;
+ 	case oProxyCommand:
+ 		charptr = &options->proxy_command;
+ parse_command:
+@@ -1052,6 +1084,9 @@ 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->num_nss_modules = 0;
+ 	options->enable_ssh_keysign = - 1;
+ 	options->no_host_authentication_for_localhost = - 1;
+ 	options->identities_only = - 1;
+@@ -1183,6 +1218,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	2011-01-20 11:30:34.000000000 +0100
+@@ -85,6 +85,10 @@ 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     num_nss_modules; /* Number of PCKS#11 modules. */
++	char   *nss_modules[SSH_MAX_NSS_MODULES];
+ 	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/README.nss.nss-keys openssh-5.3p1/README.nss
+--- openssh-5.3p1/README.nss.nss-keys	2011-01-20 11:30:34.000000000 +0100
++++ openssh-5.3p1/README.nss	2011-01-20 11:30:34.000000000 +0100
+@@ -0,0 +1,38 @@
++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'
++
++Tomas Mraz, Red Hat, Inc.
+diff -up openssh-5.3p1/ssh-add.1.nss-keys openssh-5.3p1/ssh-add.1
+--- openssh-5.3p1/ssh-add.1.nss-keys	2011-01-20 13:42:22.000000000 +0100
++++ openssh-5.3p1/ssh-add.1	2011-01-20 14:28:29.000000000 +0100
+@@ -52,6 +52,9 @@
+ .Fl s Ar reader
+ .Nm ssh-add
+ .Fl e Ar reader
++.Nm ssh-add
++.Fl n
++.Op Fl T Ar token
+ .Sh DESCRIPTION
+ .Nm
+ adds RSA or DSA identities to the authentication agent,
+@@ -116,6 +119,8 @@ Add key in smartcard
+ Set a maximum lifetime when adding identities to an agent.
+ The lifetime may be specified in seconds or in a time format
+ specified in
++.It Fl T Ar token
++Explicitly set token name.
+ .Xr sshd_config 5 .
+ .It Fl X
+ Unlock the agent.
+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	2011-01-20 13:42:06.000000000 +0100
+@@ -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)
+ {
+@@ -323,6 +454,8 @@ usage(void)
+ #ifdef SMARTCARD
+ 	fprintf(stderr, "  -s reader   Add key in smartcard reader.\n");
+ 	fprintf(stderr, "  -e reader   Remove key in smartcard reader.\n");
++	fprintf(stderr, "  -n          Add keys in NSS key.\n");
++	fprintf(stderr, "  -T          Name NSS key explicitly.\n");
+ #endif
+ }
+ 
+@@ -334,6 +467,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 +488,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 +510,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 +529,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 +547,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	2011-01-20 11:30:34.000000000 +0100
+@@ -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, 1, 0, NULL);
++	/* 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, 1, 0, NULL);
++	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	2011-01-20 11:30:34.000000000 +0100
+@@ -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,29 @@ 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, 
++	    	options.number_of_password_prompts, options.num_nss_modules,
++	    	options.nss_modules)) != 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	2011-01-20 11:30:34.000000000 +0100
+@@ -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.h.nss-keys openssh-5.3p1/ssh.h
+--- openssh-5.3p1/ssh.h.nss-keys	2006-08-05 04:39:41.000000000 +0200
++++ openssh-5.3p1/ssh.h	2011-01-20 11:30:34.000000000 +0100
+@@ -28,6 +28,12 @@
+ #define SSH_MAX_IDENTITY_FILES		100
+ 
+ /*
++ * Maximum number of PKCS#11 modules that can be specified in configuration
++ * files or on the command line.
++ */
++#define SSH_MAX_NSS_MODULES			10
++
++/*
+  * Maximum length of lines in authorized_keys file.
+  * Current value permits 16kbit RSA and RSA1 keys and 8kbit DSA keys, with
+  * some room for options and comments.
+diff -up openssh-5.3p1/ssh-keygen.1.nss-keys openssh-5.3p1/ssh-keygen.1
+--- openssh-5.3p1/ssh-keygen.1.nss-keys	2011-01-20 11:32:31.000000000 +0100
++++ openssh-5.3p1/ssh-keygen.1	2011-01-20 12:14:53.000000000 +0100
+@@ -109,6 +109,9 @@
+ .Op Fl v
+ .Op Fl a Ar num_trials
+ .Op Fl W Ar generator
++.Nm ssh-keygen
++.Op Fl n
++.Op Fl D Ar smartcard
+ .Sh DESCRIPTION
+ .Nm
+ generates, manages and converts authentication keys for
+@@ -269,6 +272,8 @@ an ASCII art representation of the key i
+ .It Fl M Ar memory
+ Specify the amount of memory to use (in megabytes) when generating
+ candidate moduli for DH-GEX.
++.It Fl n
++Extract the public key from smartcard.
+ .It Fl N Ar new_passphrase
+ Provides the new passphrase.
+ .It Fl P Ar passphrase
+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	2011-01-20 12:18:23.000000000 +0100
+@@ -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, 1, 0, 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)
+ {
+@@ -1051,6 +1076,9 @@ usage(void)
+ 	fprintf(stderr, "  -H          Hash names in known_hosts file.\n");
+ 	fprintf(stderr, "  -i          Convert RFC 4716 to OpenSSH key file.\n");
+ 	fprintf(stderr, "  -l          Show fingerprint of key file.\n");
++#ifdef SMARTCARD
++	fprintf(stderr, "  -n          Extract the public key from smartcard.\n");
++#endif /* SMARTCARD */
+ 	fprintf(stderr, "  -M memory   Amount of memory (MB) to use for generating DH-GEX moduli.\n");
+ 	fprintf(stderr, "  -N phrase   Provide new passphrase.\n");
+ 	fprintf(stderr, "  -P phrase   Provide old passphrase.\n");
+@@ -1083,7 +1111,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 +1145,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 +1185,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 +1220,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 +1332,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	2011-01-20 11:30:34.000000000 +0100
+@@ -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 --git a/openssh-5.3p1-randclean.patch b/openssh-5.3p1-randclean.patch
new file mode 100644
index 0000000..61a56d1
--- /dev/null
+++ b/openssh-5.3p1-randclean.patch
@@ -0,0 +1,13 @@
+diff -up openssh-5.3p1/entropy.c.randclean openssh-5.3p1/entropy.c
+--- openssh-5.3p1/entropy.c.randclean	2010-01-21 09:26:30.000000000 +0100
++++ openssh-5.3p1/entropy.c	2010-01-21 09:26:37.000000000 +0100
+@@ -159,6 +159,9 @@ init_rng(void)
+ 		fatal("OpenSSL version mismatch. Built against %lx, you "
+ 		    "have %lx", OPENSSL_VERSION_NUMBER, SSLeay());
+ 
++	/* clean the PRNG status when exiting the program */
++	atexit(RAND_cleanup);
++
+ #ifndef OPENSSL_PRNG_ONLY
+ 	original_uid = getuid();
+ 	original_euid = geteuid();
diff --git a/openssh-5.3p1-selabel.patch b/openssh-5.3p1-selabel.patch
new file mode 100644
index 0000000..29e2984
--- /dev/null
+++ b/openssh-5.3p1-selabel.patch
@@ -0,0 +1,55 @@
+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,17 @@ 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;
++
++		if (matchpathcon(buf, 0700, &scon) != -1) {
++			setfscreatecon(scon);
++			matchpathcon_fini();
++		}
+ 		if (mkdir(buf, 0700) < 0)
+ 			error("Could not create directory '%.200s'.", buf);
+-
++		setfscreatecon(NULL);
++	}
+ 	/* load options.identity_files */
+ 	load_public_identity_files();
+ 
diff --git a/openssh-5.3p1-sftp-chroot.patch b/openssh-5.3p1-sftp-chroot.patch
new file mode 100644
index 0000000..109e8b3
--- /dev/null
+++ b/openssh-5.3p1-sftp-chroot.patch
@@ -0,0 +1,205 @@
+diff -up openssh-5.3p1/channels.c.sftp-chroot openssh-5.3p1/channels.c
+--- openssh-5.3p1/channels.c.sftp-chroot	2011-03-03 12:03:43.000000000 +0100
++++ openssh-5.3p1/channels.c	2011-03-03 12:03:48.000000000 +0100
+@@ -839,8 +839,9 @@ channel_pre_open(Channel *c, fd_set *rea
+ 		if (c->extended_usage == CHAN_EXTENDED_WRITE &&
+ 		    buffer_len(&c->extended) > 0)
+ 			FD_SET(c->efd, writeset);
+-		else if (!(c->flags & CHAN_EOF_SENT) &&
+-		    c->extended_usage == CHAN_EXTENDED_READ &&
++		else if (c->efd != -1 && !(c->flags & CHAN_EOF_SENT) &&
++		    (c->extended_usage == CHAN_EXTENDED_READ ||
++		    c->extended_usage == CHAN_EXTENDED_IGNORE) &&
+ 		    buffer_len(&c->extended) < c->remote_window)
+ 			FD_SET(c->efd, readset);
+ 	}
+@@ -1719,8 +1720,10 @@ channel_handle_efd(Channel *c, fd_set *r
+ 				buffer_consume(&c->extended, len);
+ 				c->local_consumed += len;
+ 			}
+-		} else if (c->extended_usage == CHAN_EXTENDED_READ &&
+-		    (c->detach_close || FD_ISSET(c->efd, readset))) {
++		} else if (c->efd != -1 &&
++		    (c->extended_usage == CHAN_EXTENDED_READ ||
++		    c->extended_usage == CHAN_EXTENDED_IGNORE) &&
++ 		    FD_ISSET(c->efd, readset)) {
+ 			len = read(c->efd, buf, sizeof(buf));
+ 			debug2("channel %d: read %d from efd %d",
+ 			    c->self, len, c->efd);
+@@ -1732,7 +1735,11 @@ channel_handle_efd(Channel *c, fd_set *r
+ 				    c->self, c->efd);
+ 				channel_close_fd(&c->efd);
+ 			} else {
+-				buffer_append(&c->extended, buf, len);
++				if (c->extended_usage == CHAN_EXTENDED_IGNORE) {
++					debug3("channel %d: discard efd",
++					    c->self);
++				} else
++					buffer_append(&c->extended, buf, len);
+ 			}
+ 		}
+ 	}
+diff -up openssh-5.3p1/session.c.sftp-chroot openssh-5.3p1/session.c
+--- openssh-5.3p1/session.c.sftp-chroot	2011-03-03 12:03:46.000000000 +0100
++++ openssh-5.3p1/session.c	2011-03-03 12:03:49.000000000 +0100
+@@ -105,7 +105,7 @@
+ /* func */
+ 
+ Session *session_new(void);
+-void	session_set_fds(Session *, int, int, int, int);
++void	session_set_fds(Session *, int, int, int, int, int);
+ void	session_pty_cleanup(Session *);
+ void	session_proctitle(Session *);
+ int	session_setup_x11fwd(Session *);
+@@ -459,27 +459,14 @@ do_exec_no_pty(Session *s, const char *c
+ 		close(pin[1]);
+ 		return -1;
+ 	}
+-	if (s->is_subsystem) {
+-	    	if ((perr[1] = open(_PATH_DEVNULL, O_WRONLY)) == -1) {
+-			error("%s: open(%s): %s", __func__, _PATH_DEVNULL,
+-			    strerror(errno));
+-			close(pin[0]);
+-			close(pin[1]);
+-			close(pout[0]);
+-			close(pout[1]);
+-			return -1;
+-		}
+-		perr[0] = -1;
+-	} else {
+-		if (pipe(perr) < 0) {
+-			error("%s: pipe err: %.100s", __func__,
+-			    strerror(errno));
+-			close(pin[0]);
+-			close(pin[1]);
+-			close(pout[0]);
+-			close(pout[1]);
+-			return -1;
+-		}
++	if (pipe(perr) < 0) {
++		error("%s: pipe err: %.100s", __func__,
++		    strerror(errno));
++		close(pin[0]);
++		close(pin[1]);
++		close(pout[0]);
++		close(pout[1]);
++		return -1;
+ 	}
+ #else
+ 	int inout[2], err[2];
+@@ -492,23 +479,12 @@ do_exec_no_pty(Session *s, const char *c
+ 		error("%s: socketpair #1: %.100s", __func__, strerror(errno));
+ 		return -1;
+ 	}
+-	if (s->is_subsystem) {
+-	    	if ((err[0] = open(_PATH_DEVNULL, O_WRONLY)) == -1) {
+-			error("%s: open(%s): %s", __func__, _PATH_DEVNULL,
+-			    strerror(errno));
+-			close(inout[0]);
+-			close(inout[1]);
+-			return -1;
+-		}
+-		err[1] = -1;
+-	} else {
+-		if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) {
+-			error("%s: socketpair #2: %.100s", __func__,
+-			    strerror(errno));
+-			close(inout[0]);
+-			close(inout[1]);
+-			return -1;
+-		}
++	if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) {
++		error("%s: socketpair #2: %.100s", __func__,
++		    strerror(errno));
++		close(inout[0]);
++		close(inout[1]);
++		return -1;
+ 	}
+ #endif
+ 
+@@ -523,15 +499,13 @@ do_exec_no_pty(Session *s, const char *c
+ 		close(pin[1]);
+ 		close(pout[0]);
+ 		close(pout[1]);
+-		if (perr[0] != -1)
+-			close(perr[0]);
++		close(perr[0]);
+ 		close(perr[1]);
+ #else
+ 		close(inout[0]);
+ 		close(inout[1]);
+ 		close(err[0]);
+-		if (err[1] != -1)
+-			close(err[1]);
++		close(err[1]);
+ #endif
+ 		return -1;
+ 	case 0:
+@@ -565,8 +539,7 @@ do_exec_no_pty(Session *s, const char *c
+ 		close(pout[1]);
+ 
+ 		/* Redirect stderr. */
+-		if (perr[0] != -1)
+-			close(perr[0]);
++		close(perr[0]);
+ 		if (dup2(perr[1], 2) < 0)
+ 			perror("dup2 stderr");
+ 		close(perr[1]);
+@@ -577,8 +550,7 @@ do_exec_no_pty(Session *s, const char *c
+ 		 * seem to depend on it.
+ 		 */
+ 		close(inout[1]);
+-		if (err[1] != -1)
+-			close(err[1]);
++		close(err[1]);
+ 		if (dup2(inout[0], 0) < 0)	/* stdin */
+ 			perror("dup2 stdin");
+ 		if (dup2(inout[0], 1) < 0)	/* stdout (same as stdin) */
+@@ -626,7 +598,8 @@ do_exec_no_pty(Session *s, const char *c
+ 	close(perr[1]);
+ 
+ 	if (compat20) {
+-		session_set_fds(s, pin[1], pout[0], perr[0], 0);
++		session_set_fds(s, pin[1], pout[0], perr[0],
++		    s->is_subsystem, 0);
+ 	} else {
+ 		/* Enter the interactive session. */
+ 		server_loop(pid, pin[1], pout[0], perr[0]);
+@@ -642,7 +615,8 @@ do_exec_no_pty(Session *s, const char *c
+ 	 * handle the case that fdin and fdout are the same.
+ 	 */
+ 	if (compat20) {
+-		session_set_fds(s, inout[1], inout[1], err[1], 0);
++		session_set_fds(s, inout[1], inout[1], err[1],
++		    s->is_subsystem, 0);
+ 	} else {
+ 		server_loop(pid, inout[1], inout[1], err[1]);
+ 		/* server_loop has closed inout[1] and err[1]. */
+@@ -772,7 +746,7 @@ do_exec_pty(Session *s, const char *comm
+ 	s->ptymaster = ptymaster;
+ 	packet_set_interactive(1);
+ 	if (compat20) {
+-		session_set_fds(s, ptyfd, fdout, -1, 1);
++		session_set_fds(s, ptyfd, fdout, -1, 1, 1);
+ 	} else {
+ 		server_loop(pid, ptyfd, fdout, -1);
+ 		/* server_loop _has_ closed ptyfd and fdout. */
+@@ -2342,7 +2316,8 @@ session_input_channel_req(Channel *c, co
+ }
+ 
+ void
+-session_set_fds(Session *s, int fdin, int fdout, int fderr, int is_tty)
++session_set_fds(Session *s, int fdin, int fdout, int fderr, int ignore_fderr,
++    int is_tty)
+ {
+ 	if (!compat20)
+ 		fatal("session_set_fds: called for proto != 2.0");
+@@ -2354,7 +2329,7 @@ session_set_fds(Session *s, int fdin, in
+ 		fatal("no channel for session %d", s->self);
+ 	channel_set_fds(s->chanid,
+ 	    fdout, fdin, fderr,
+-	    fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
++	    ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
+ 	    1, is_tty, CHAN_SES_WINDOW_DEFAULT);
+ }
+ 
diff --git a/openssh-5.3p1-sftp_umask.patch b/openssh-5.3p1-sftp_umask.patch
new file mode 100644
index 0000000..916a2b9
--- /dev/null
+++ b/openssh-5.3p1-sftp_umask.patch
@@ -0,0 +1,68 @@
+diff -up openssh-5.3p1/sftp-server.8.sftp-umask openssh-5.3p1/sftp-server.8
+--- openssh-5.3p1/sftp-server.8.sftp-umask	2009-06-21 09:52:28.000000000 +0200
++++ openssh-5.3p1/sftp-server.8	2011-03-15 20:33:09.006854831 +0100
+@@ -32,6 +32,7 @@
+ .Nm sftp-server
+ .Op Fl f Ar log_facility
+ .Op Fl l Ar log_level
++.Op Fl u Ar umask
+ .Sh DESCRIPTION
+ .Nm
+ is a program that speaks the server side of SFTP protocol
+@@ -71,6 +72,11 @@ performs on behalf of the client.
+ DEBUG and DEBUG1 are equivalent.
+ DEBUG2 and DEBUG3 each specify higher levels of debugging output.
+ The default is ERROR.
++.It Fl u Ar umask
++Sets an explicit
++.Xr umask 2
++to be applied to newly-created files and directories, instead of the
++user's default mask.
+ .El
+ .Pp
+ For logging to work,
+diff -up openssh-5.3p1/sftp-server.c.sftp-umask openssh-5.3p1/sftp-server.c
+--- openssh-5.3p1/sftp-server.c.sftp-umask	2009-08-28 02:43:13.000000000 +0200
++++ openssh-5.3p1/sftp-server.c	2011-03-15 20:35:52.733979858 +0100
+@@ -1322,7 +1322,8 @@ sftp_server_usage(void)
+ 	extern char *__progname;
+ 
+ 	fprintf(stderr,
+-	    "usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname);
++	    "usage: %s [-he] [-l log_level] [-f log_facility] [-u umask]\n",
++	    __progname);
+ 	exit(1);
+ }
+ 
+@@ -1334,6 +1335,7 @@ sftp_server_main(int argc, char **argv, 
+ 	ssize_t len, olen, set_size;
+ 	SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
+ 	char *cp, buf[4*4096];
++	long mask;
+ 
+ 	extern char *optarg;
+ 	extern char *__progname;
+@@ -1341,7 +1343,7 @@ sftp_server_main(int argc, char **argv, 
+ 	__progname = ssh_get_progname(argv[0]);
+ 	log_init(__progname, log_level, log_facility, log_stderr);
+ 
+-	while (!skipargs && (ch = getopt(argc, argv, "f:l:che")) != -1) {
++	while (!skipargs && (ch = getopt(argc, argv, "f:l:u:che")) != -1) {
+ 		switch (ch) {
+ 		case 'c':
+ 			/*
+@@ -1363,6 +1365,14 @@ sftp_server_main(int argc, char **argv, 
+ 			if (log_facility == SYSLOG_FACILITY_NOT_SET)
+ 				error("Invalid log facility \"%s\"", optarg);
+ 			break;
++		case 'u':
++			errno = 0;
++			mask = strtol(optarg, &cp, 8);
++			if (mask < 0 || mask > 0777 || *cp != '\0' ||
++			    cp == optarg || (mask == 0 && errno != 0))
++				fatal("Invalid umask \"%s\"", optarg);
++			(void)umask((mode_t)mask);
++			break;
+ 		case 'h':
+ 		default:
+ 			sftp_server_usage();
diff --git a/openssh-5.3p1-skip-initial.patch b/openssh-5.3p1-skip-initial.patch
new file mode 100644
index 0000000..d52962e
--- /dev/null
+++ b/openssh-5.3p1-skip-initial.patch
@@ -0,0 +1,24 @@
+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);
+ }
diff --git a/openssh-5.3p1-stderr.patch b/openssh-5.3p1-stderr.patch
new file mode 100644
index 0000000..ef35d80
--- /dev/null
+++ b/openssh-5.3p1-stderr.patch
@@ -0,0 +1,157 @@
+diff -up openssh-5.5p1/session.c.stderr openssh-5.5p1/session.c
+--- openssh-5.5p1/session.c.stderr	2010-04-26 10:35:35.000000000 +0200
++++ openssh-5.5p1/session.c	2010-04-26 10:41:11.000000000 +0200
+@@ -47,6 +47,7 @@
+ #include <arpa/inet.h>
+ 
+ #include <errno.h>
++#include <fcntl.h>
+ #include <grp.h>
+ #ifdef HAVE_PATHS_H
+ #include <paths.h>
+@@ -447,6 +448,9 @@ do_exec_no_pty(Session *s, const char *c
+ #ifdef USE_PIPES
+ 	int pin[2], pout[2], perr[2];
+ 
++	if (s == NULL)
++		fatal("do_exec_no_pty: no session");
++
+ 	/* Allocate pipes for communicating with the program. */
+ 	if (pipe(pin) < 0) {
+ 		error("%s: pipe in: %.100s", __func__, strerror(errno));
+@@ -458,33 +462,59 @@ do_exec_no_pty(Session *s, const char *c
+ 		close(pin[1]);
+ 		return -1;
+ 	}
+-	if (pipe(perr) < 0) {
+-		error("%s: pipe err: %.100s", __func__, strerror(errno));
+-		close(pin[0]);
+-		close(pin[1]);
+-		close(pout[0]);
+-		close(pout[1]);
+-		return -1;
++	if (s->is_subsystem) {
++	    	if ((perr[1] = open(_PATH_DEVNULL, O_WRONLY)) == -1) {
++			error("%s: open(%s): %s", __func__, _PATH_DEVNULL,
++			    strerror(errno));
++			close(pin[0]);
++			close(pin[1]);
++			close(pout[0]);
++			close(pout[1]);
++			return -1;
++		}
++		perr[0] = -1;
++	} else {
++		if (pipe(perr) < 0) {
++			error("%s: pipe err: %.100s", __func__,
++			    strerror(errno));
++			close(pin[0]);
++			close(pin[1]);
++			close(pout[0]);
++			close(pout[1]);
++			return -1;
++		}
+ 	}
+ #else
+ 	int inout[2], err[2];
+ 
++	if (s == NULL)
++		fatal("do_exec_no_pty: no session");
++
+ 	/* Uses socket pairs to communicate with the program. */
+ 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) {
+ 		error("%s: socketpair #1: %.100s", __func__, strerror(errno));
+ 		return -1;
+ 	}
+-	if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) {
+-		error("%s: socketpair #2: %.100s", __func__, strerror(errno));
+-		close(inout[0]);
+-		close(inout[1]);
+-		return -1;
++	if (s->is_subsystem) {
++	    	if ((err[0] = open(_PATH_DEVNULL, O_WRONLY)) == -1) {
++			error("%s: open(%s): %s", __func__, _PATH_DEVNULL,
++			    strerror(errno));
++			close(inout[0]);
++			close(inout[1]);
++			return -1;
++		}
++		err[1] = -1;
++	} else {
++		if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) {
++			error("%s: socketpair #2: %.100s", __func__,
++			    strerror(errno));
++			close(inout[0]);
++			close(inout[1]);
++			return -1;
++		}
+ 	}
+ #endif
+ 
+-	if (s == NULL)
+-		fatal("do_exec_no_pty: no session");
+-
+ 	session_proctitle(s);
+ 
+ 	/* Fork the child. */
+@@ -496,13 +526,15 @@ do_exec_no_pty(Session *s, const char *c
+ 		close(pin[1]);
+ 		close(pout[0]);
+ 		close(pout[1]);
+-		close(perr[0]);
++		if (perr[0] != -1)
++			close(perr[0]);
+ 		close(perr[1]);
+ #else
+ 		close(inout[0]);
+ 		close(inout[1]);
+ 		close(err[0]);
+-		close(err[1]);
++		if (err[1] != -1)
++			close(err[1]);
+ #endif
+ 		return -1;
+ 	case 0:
+@@ -536,7 +568,8 @@ do_exec_no_pty(Session *s, const char *c
+ 		close(pout[1]);
+ 
+ 		/* Redirect stderr. */
+-		close(perr[0]);
++		if (perr[0] != -1)
++			close(perr[0]);
+ 		if (dup2(perr[1], 2) < 0)
+ 			perror("dup2 stderr");
+ 		close(perr[1]);
+@@ -547,7 +580,8 @@ do_exec_no_pty(Session *s, const char *c
+ 		 * seem to depend on it.
+ 		 */
+ 		close(inout[1]);
+-		close(err[1]);
++		if (err[1] != -1)
++			close(err[1]);
+ 		if (dup2(inout[0], 0) < 0)	/* stdin */
+ 			perror("dup2 stdin");
+ 		if (dup2(inout[0], 1) < 0)	/* stdout (same as stdin) */
+@@ -595,10 +629,6 @@ do_exec_no_pty(Session *s, const char *c
+ 	close(perr[1]);
+ 
+ 	if (compat20) {
+-		if (s->is_subsystem) {
+-			close(perr[0]);
+-			perr[0] = -1;
+-		}
+ 		session_set_fds(s, pin[1], pout[0], perr[0], 0);
+ 	} else {
+ 		/* Enter the interactive session. */
+@@ -615,10 +645,7 @@ do_exec_no_pty(Session *s, const char *c
+ 	 * handle the case that fdin and fdout are the same.
+ 	 */
+ 	if (compat20) {
+-		session_set_fds(s, inout[1], inout[1],
+-		    s->is_subsystem ? -1 : err[1], 0);
+-		if (s->is_subsystem)
+-			close(err[1]);
++		session_set_fds(s, inout[1], inout[1], err[1], 0);
+ 	} else {
+ 		server_loop(pid, inout[1], inout[1], err[1]);
+ 		/* server_loop has closed inout[1] and err[1]. */
diff --git a/openssh-5.3p1-strictalias.patch b/openssh-5.3p1-strictalias.patch
new file mode 100644
index 0000000..cf94b4f
--- /dev/null
+++ b/openssh-5.3p1-strictalias.patch
@@ -0,0 +1,12 @@
+diff -urN openssh-5.3p1/configure.ac openssh-5.4p1/configure.ac
+--- openssh-5.3p1/configure.ac	2009-09-11 06:56:08.000000000 +0200
++++ openssh-5.4p1/configure.ac	2010-03-05 05:04:35.000000000 +0100
+@@ -108,7 +108,7 @@
+ 		     ;;
+ 		2.*) no_attrib_nonnull=1 ;;
+ 		3.*) CFLAGS="$CFLAGS -Wsign-compare -Wformat-security" ;;
+-		4.*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign -Wformat-security" ;;
++		4.*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign -Wformat-security -fno-strict-aliasing" ;;
+ 		*) ;;
+ 	esac
+ 
diff --git a/openssh-5.3p1-unblock-signals.patch b/openssh-5.3p1-unblock-signals.patch
new file mode 100644
index 0000000..326f1e6
--- /dev/null
+++ b/openssh-5.3p1-unblock-signals.patch
@@ -0,0 +1,76 @@
+diff -ur openssh-5.3p1.orig/gss-serv-gsi.c openssh-5.3p1/gss-serv-gsi.c
+--- openssh-5.3p1.orig/gss-serv-gsi.c	2011-08-17 08:45:26.119890783 +0200
++++ openssh-5.3p1/gss-serv-gsi.c	2011-08-17 08:46:18.905892255 +0200
+@@ -63,6 +63,22 @@
+ 	&ssh_gssapi_gsi_updatecreds
+ };
+ 
++static
++void
++undo_globus_signal_blocking()
++{
++	sigset_t mysigset;
++	sigemptyset(&mysigset);
++	sigaddset(&mysigset, SIGCHLD);
++	sigaddset(&mysigset, SIGTERM);
++	sigaddset(&mysigset, SIGALRM);
++	sigaddset(&mysigset, SIGHUP);
++	sigaddset(&mysigset, SIGTERM);
++	sigaddset(&mysigset, SIGQUIT);
++	sigaddset(&mysigset, SIGINT);
++	sigprocmask(SIG_UNBLOCK, &mysigset, NULL);
++}
++
+ /*
+  * Check if this user is OK to login under GSI. User has been authenticated
+  * as identity in global 'client_name.value' and is trying to log in as passed
+@@ -83,6 +99,7 @@
+     if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
+ 	return 0;
+     }
++    undo_globus_signal_blocking();
+ #endif
+ 
+ /* use new globus_gss_assist_map_and_authorize() interface if available */
+@@ -129,6 +146,7 @@
+     if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
+ 	return 0;
+     }
++    undo_globus_signal_blocking();
+ #endif
+ 
+ /* use new globus_gss_assist_map_and_authorize() interface if available */
+diff -ur openssh-5.3p1.orig/ssh-globus-usage.c openssh-5.3p1/ssh-globus-usage.c
+--- openssh-5.3p1.orig/ssh-globus-usage.c	2011-08-17 08:45:26.144890783 +0200
++++ openssh-5.3p1/ssh-globus-usage.c	2011-08-17 08:49:03.068896835 +0200
+@@ -59,6 +59,22 @@
+ } ssh_usage_ent_t;
+ 
+ 
++static
++void
++undo_globus_signal_blocking()
++{
++        sigset_t mysigset;
++        sigemptyset(&mysigset);
++        sigaddset(&mysigset, SIGCHLD);
++        sigaddset(&mysigset, SIGTERM);
++        sigaddset(&mysigset, SIGALRM);
++        sigaddset(&mysigset, SIGHUP);
++        sigaddset(&mysigset, SIGTERM);
++        sigaddset(&mysigset, SIGQUIT);
++        sigaddset(&mysigset, SIGINT);
++        sigprocmask(SIG_UNBLOCK, &mysigset, NULL);
++}
++
+ globus_result_t
+ ssh_usage_stats_init(int disable_usage_stats, char *usage_stats_targets)
+ {
+@@ -74,6 +90,7 @@
+ 	return GLOBUS_SUCCESS;
+ 
+     result = globus_module_activate(GLOBUS_USAGE_MODULE);
++    undo_globus_signal_blocking();
+     if (result != GLOBUS_SUCCESS)
+     {
+         error("ERROR: couldn't activate USAGE module");
diff --git a/openssh-5.3p1-x11.patch b/openssh-5.3p1-x11.patch
new file mode 100644
index 0000000..cac5d5e
--- /dev/null
+++ b/openssh-5.3p1-x11.patch
@@ -0,0 +1,54 @@
+diff -up openssh-5.3p1/channels.c.bz595935 openssh-5.3p1/channels.c
+--- openssh-5.3p1/channels.c.bz595935	2010-08-12 14:19:28.000000000 +0200
++++ openssh-5.3p1/channels.c	2010-08-12 14:33:51.000000000 +0200
+@@ -3185,7 +3185,7 @@ x11_create_display_inet(int x11_display_
+ }
+ 
+ static int
+-connect_local_xsocket_path(const char *pathname)
++connect_local_xsocket_path(const char *pathname, int len)
+ {
+ 	int sock;
+ 	struct sockaddr_un addr;
+@@ -3195,11 +3195,14 @@ connect_local_xsocket_path(const char *p
+ 		error("socket: %.100s", strerror(errno));
+ 	memset(&addr, 0, sizeof(addr));
+ 	addr.sun_family = AF_UNIX;
+-	strlcpy(addr.sun_path, pathname, sizeof addr.sun_path);
+-	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0)
++	if (len <= 0)
++		return -1;
++	if (len > sizeof addr.sun_path)
++		len = sizeof addr.sun_path;
++	memcpy(addr.sun_path, pathname, len);
++	if (connect(sock, (struct sockaddr *)&addr, sizeof addr - (sizeof addr.sun_path - len) ) == 0)
+ 		return sock;
+ 	close(sock);
+-	error("connect %.100s: %.100s", addr.sun_path, strerror(errno));
+ 	return -1;
+ }
+ 
+@@ -3207,8 +3210,21 @@ static int
+ connect_local_xsocket(u_int dnr)
+ {
+ 	char buf[1024];
+-	snprintf(buf, sizeof buf, _PATH_UNIX_X, dnr);
+-	return connect_local_xsocket_path(buf);
++	int len;
++#ifdef linux
++	int ret;
++#endif
++	len = snprintf(buf + 1, sizeof (buf) - 1, _PATH_UNIX_X, dnr);
++#ifdef linux
++	/* try abstract socket first */
++	buf[0] = '\0';
++	if ((ret = connect_local_xsocket_path(buf, len + 1)) >= 0)
++		return ret;
++#endif
++	if ((ret = connect_local_xsocket_path(buf + 1, len)) >= 0)
++		return ret;
++	error("connect %.100s: %.100s", buf + 1, strerror(errno));
++	return -1;
+ }
+ 
+ int
diff --git a/openssh-nukeacss.sh b/openssh-nukeacss.sh
new file mode 100755
index 0000000..ccc1354
--- /dev/null
+++ b/openssh-nukeacss.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+#  Remove the ACSS implementation from OpenSSH, and disable its use so that the
+#  rest of the package can still be built.
+#
+> acss.c
+patch -sp0 << EOF
+--- cipher.c.orig       2005-07-17 09:02:10.000000000 +0200
++++ cipher.c    2005-09-06 14:52:06.000000000 +0200
+@@ -45,6 +45,8 @@
+
+ /* compatibility with old or broken OpenSSL versions */
+ #include "openbsd-compat/openssl-compat.h"
++#undef USE_CIPHER_ACSS
++#define EVP_acss NULL
+
+ extern const EVP_CIPHER *evp_ssh1_bf(void);
+ extern const EVP_CIPHER *evp_ssh1_3des(void);
+EOF
diff --git a/sources b/sources
index e69de29..7d28e2e 100644
--- a/sources
+++ b/sources
@@ -0,0 +1 @@
+89f85c1da83c24ca0b10c05344f7c93c  openssh-5.3p1-noacss.tar.bz2


More information about the scm-commits mailing list