[gsi-openssh] Based on openssh-5.9p1-11.fc17

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


commit 99254d50d67cedb74fec699bd419ee205a43f07b
Author: Mattias Ellert <mattias.ellert at fysast.uu.se>
Date:   Thu Nov 17 20:03:29 2011 +0100

    Based on openssh-5.9p1-11.fc17

 .gitignore                                      |    1 +
 README.sshd-and-gsisshd                         |   12 +
 gsi-openssh.spec                                |  542 +++++
 gsisshd-keygen                                  |   90 +
 gsisshd-keygen.service                          |   12 +
 gsisshd.pam                                     |   15 +
 gsisshd.service                                 |   10 +
 gsisshd.sysconfig                               |   16 +
 openssh-4.3p2-askpass-grab-info.patch           |   18 +
 openssh-5.1p1-askpass-progress.patch            |   79 +
 openssh-5.1p1-scp-manpage.patch                 |   18 +
 openssh-5.2p1-allow-ip-opts.patch               |   37 +
 openssh-5.5p1-x11.patch                         |   54 +
 openssh-5.6p1-exit-deadlock.patch               |   14 +
 openssh-5.8p1-audit0.patch                      |   17 +
 openssh-5.8p1-fingerprint.patch                 |  421 ++++
 openssh-5.8p1-getaddrinfo.patch                 |   11 +
 openssh-5.8p1-glob.patch                        |   10 +
 openssh-5.8p1-gssapi-canohost.patch             |   24 +
 openssh-5.8p1-keyperm.patch                     |   25 +
 openssh-5.8p1-localdomain.patch                 |   14 +
 openssh-5.8p1-packet.patch                      |   12 +
 openssh-5.8p2-askpass-ld.patch                  |   18 +
 openssh-5.8p2-force_krb.patch                   |  288 +++
 openssh-5.8p2-remove-stale-control-socket.patch |   13 +
 openssh-5.8p2-sigpipe.patch                     |   12 +
 openssh-5.8p2-unblock-signals.patch             |   76 +
 openssh-5.9p1-2auth.patch                       |  354 +++
 openssh-5.9p1-akc.patch                         |  452 ++++
 openssh-5.9p1-audit1.patch                      |  641 +++++
 openssh-5.9p1-audit2.patch                      |  353 +++
 openssh-5.9p1-audit3.patch                      |  528 ++++
 openssh-5.9p1-audit4.patch                      |  667 +++++
 openssh-5.9p1-audit5.patch                      |  486 ++++
 openssh-5.9p1-coverity.patch                    |  844 +++++++
 openssh-5.9p1-edns.patch                        |   72 +
 openssh-5.9p1-entropy.patch                     |  251 ++
 openssh-5.9p1-fips.patch                        |  521 ++++
 openssh-5.9p1-gsissh.patch                      | 2945 +++++++++++++++++++++++
 openssh-5.9p1-gsskex.patch                      | 2932 ++++++++++++++++++++++
 openssh-5.9p1-ipv6man.patch                     |   24 +
 openssh-5.9p1-keycat.patch                      |  371 +++
 openssh-5.9p1-keygen.patch                      |   80 +
 openssh-5.9p1-kuserok.patch                     |  167 ++
 openssh-5.9p1-ldap.patch                        | 2596 ++++++++++++++++++++
 openssh-5.9p1-mls.patch                         |  400 +++
 openssh-5.9p1-randclean.patch                   |   13 +
 openssh-5.9p1-redhat.patch                      |  108 +
 openssh-5.9p1-role.patch                        |  613 +++++
 openssh-5.9p1-sesandbox.patch                   |  321 +++
 openssh-5.9p1-sftp-chroot.patch                 |   63 +
 openssh-5.9p1-vendor.patch                      |  157 ++
 openssh-nukeacss.sh                             |   21 +
 sources                                         |    1 +
 54 files changed, 17840 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..d9130c0
--- /dev/null
+++ b/gsi-openssh.spec
@@ -0,0 +1,542 @@
+# gsi-openssh is openssh with support for GSI authentication
+# This gsi-openssh specfile is based on the openssh specfile
+
+# Do we want SELinux & Audit
+%if 0%{?!noselinux:1}
+%global WITH_SELINUX 1
+%else
+%global WITH_SELINUX 0
+%endif
+
+# 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 libedit support
+%global libedit 1
+
+# Do we want LDAP support
+%global ldap 1
+
+# Whether or not /sbin/nologin exists.
+%global nologin 1
+
+%global openssh_ver 5.9p1
+%global openssh_rel 2
+
+Summary: An implementation of the SSH protocol with GSI authentication
+Name: gsi-openssh
+Version: %{openssh_ver}
+Release: %{openssh_rel}%{?dist}
+Provides: gsissh = %{version}-%{release}
+Obsoletes: gsissh < 5.8p2-2
+URL: http://www.openssh.com/portable.html
+#Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz
+#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.pam
+Source7: gsisshd.sysconfig
+Source8: gsisshd-keygen.service
+Source11: gsisshd.service
+Source13: gsisshd-keygen
+Source99: README.sshd-and-gsisshd
+
+#?
+Patch100: openssh-5.9p1-coverity.patch
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1872
+Patch101: openssh-5.8p1-fingerprint.patch
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1894
+Patch102: openssh-5.8p1-getaddrinfo.patch
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1889
+Patch103: openssh-5.8p1-packet.patch
+#https://bugzilla.mindrot.org/show_bug.cgi?id=983
+Patch104: openssh-5.9p1-2auth.patch
+
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1402
+Patch200: openssh-5.8p1-audit0.patch
+# -"-
+Patch201: openssh-5.9p1-audit1.patch
+# -"-
+Patch202: openssh-5.9p1-audit2.patch
+# -"-
+Patch203: openssh-5.9p1-audit3.patch
+# -"-
+Patch204: openssh-5.9p1-audit4.patch
+# -"-
+Patch205: openssh-5.9p1-audit5.patch
+
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1641 (WONTFIX)
+Patch400: openssh-5.9p1-role.patch
+#?
+Patch401: openssh-5.9p1-mls.patch
+#?
+Patch402: openssh-5.9p1-sftp-chroot.patch
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1940
+Patch403: openssh-5.9p1-sesandbox.patch
+
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1663
+Patch500: openssh-5.9p1-akc.patch
+#?-- unwanted child :(
+Patch501: openssh-5.9p1-ldap.patch
+#?
+Patch502: openssh-5.9p1-keycat.patch
+
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1668
+Patch600: openssh-5.9p1-keygen.patch
+#http6://bugzilla.mindrot.org/show_bug.cgi?id=1644
+Patch601: openssh-5.2p1-allow-ip-opts.patch
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1701
+Patch602: openssh-5.9p1-randclean.patch
+#http://cvsweb.netbsd.org/cgi-bin/cvsweb.cgi/src/crypto/dist/ssh/Attic/sftp-glob.c.diff?r1=1.13&r2=1.13.12.1&f=h
+Patch603: openssh-5.8p1-glob.patch
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1893
+Patch604: openssh-5.8p1-keyperm.patch
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1329 (WONTFIX)
+Patch605: openssh-5.8p2-remove-stale-control-socket.patch
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1925
+Patch606: openssh-5.9p1-ipv6man.patch
+#?
+Patch607: openssh-5.8p2-sigpipe.patch
+#?
+Patch608: openssh-5.8p2-askpass-ld.patch
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1789
+Patch609: openssh-5.5p1-x11.patch
+
+#?
+Patch700: openssh-5.9p1-fips.patch
+#?
+Patch701: openssh-5.6p1-exit-deadlock.patch
+#?
+Patch702: openssh-5.1p1-askpass-progress.patch
+#?
+Patch703: openssh-4.3p2-askpass-grab-info.patch
+#?
+Patch704: openssh-5.9p1-edns.patch
+#?
+Patch705: openssh-5.1p1-scp-manpage.patch
+#?
+Patch706: openssh-5.8p1-localdomain.patch
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1635 (WONTFIX)
+Patch707: openssh-5.9p1-redhat.patch
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1890 (WONTFIX) need integration to prng helper which is discontinued :)
+Patch708: openssh-5.9p1-entropy.patch
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1640 (WONTFIX)
+Patch709: openssh-5.9p1-vendor.patch
+
+#http://www.sxw.org.uk/computing/patches/openssh.html
+Patch800: openssh-5.9p1-gsskex.patch
+#http://www.mail-archive.com/kerberos@mit.edu/msg17591.html
+Patch801: openssh-5.8p2-force_krb.patch
+
+#?
+Patch900: openssh-5.8p1-gssapi-canohost.patch
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1780
+Patch901: openssh-5.9p1-kuserok.patch
+#---
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1604
+# sctp
+#https://bugzilla.mindrot.org/show_bug.cgi?id=1873 => https://bugzilla.redhat.com/show_bug.cgi?id=668993
+
+# This is the patch that adds GSI support
+# Based on http://grid.ncsa.illinois.edu/ssh/dl/patch/openssh-5.9p1.patch
+Patch98: openssh-5.9p1-gsissh.patch
+
+# The gsissh server has problems with blocked signals in threaded globus libs
+# This patch from OSG resolves these problems
+Patch99: openssh-5.8p2-unblock-signals.patch
+
+License: BSD
+Group: Applications/Internet
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+%if %{nologin}
+Requires: /sbin/nologin
+%endif
+
+%if %{ldap}
+BuildRequires: openldap-devel
+%endif
+BuildRequires: autoconf, automake, perl, zlib-devel
+BuildRequires: audit-libs-devel >= 2.0.5
+BuildRequires: util-linux, groff
+BuildRequires: pam-devel
+BuildRequires: tcp_wrappers-devel
+BuildRequires: fipscheck-devel >= 1.3.0
+BuildRequires: openssl-devel >= 0.9.8j
+
+%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 %{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
+Provides: gsissh-clients = %{version}-%{release}
+Obsoletes: gsissh-clients < 5.8p2-2
+Group: Applications/Internet
+Requires: %{name} = %{version}-%{release}
+Requires: fipscheck-lib%{_isa} >= 1.3.0
+
+%package server
+Summary: SSH server daemon with GSI authentication
+Provides: gsissh-server = %{version}-%{release}
+Obsoletes: gsissh-server < 5.8p2-2
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+Requires(pre): /usr/sbin/useradd
+Requires: pam >= 1.0.1-3
+Requires: fipscheck-lib%{_isa} >= 1.3.0
+Requires(post): systemd-units
+Requires(preun): systemd-units
+Requires(postun): systemd-units
+# This is actually needed for the %triggerun script but Requires(triggerun)
+# is not valid.  We can use %post because this particular %triggerun script
+# should fire just after this package is installed.
+Requires(post): systemd-sysv
+Requires(post): chkconfig
+
+%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}
+
+%patch100 -p1 -b .coverity
+%patch101 -p1 -b .fingerprint
+%patch102 -p1 -b .getaddrinfo
+%patch103 -p1 -b .packet
+%patch104 -p1 -b .2auth
+
+%patch200 -p1 -b .audit0
+%patch201 -p1 -b .audit1
+%patch202 -p1 -b .audit2
+%patch203 -p1 -b .audit3
+%patch204 -p1 -b .audit4
+%patch205 -p1 -b .audit5
+
+%if %{WITH_SELINUX}
+%patch400 -p1 -b .role
+%patch401 -p1 -b .mls
+%patch402 -p1 -b .sftp-chroot
+%patch403 -p1 -b .sesandbox
+%endif
+
+%patch500 -p1 -b .akc
+%if %{ldap}
+%patch501 -p1 -b .ldap
+%endif
+%patch502 -p1 -b .keycat
+
+%patch600 -p1 -b .keygen
+%patch601 -p1 -b .ip-opts
+%patch602 -p1 -b .randclean
+%patch603 -p1 -b .glob
+%patch604 -p1 -b .keyperm
+%patch605 -p1 -b .remove_stale
+%patch606 -p1 -b .ipv6man
+%patch607 -p1 -b .sigpipe
+%patch608 -p1 -b .askpass-ld
+%patch609 -p1 -b .x11
+
+%patch700 -p1 -b .fips
+%patch701 -p1 -b .exit-deadlock
+%patch702 -p1 -b .progress
+%patch703 -p1 -b .grab-info
+%patch704 -p1 -b .edns
+%patch705 -p1 -b .manpage
+%patch706 -p1 -b .localdomain
+%patch707 -p1 -b .redhat
+%patch708 -p1 -b .entropy
+%patch709 -p1 -b .vendor
+
+%patch800 -p1 -b .gsskex
+%patch801 -p1 -b .force_krb
+
+%patch900 -p1 -b .canohost
+%patch901 -p1 -b .kuserok
+
+%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
+LDFLAGS="$LDFLAGS -pie -z relro -z now"
+
+export CFLAGS
+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 \
+	--with-ipaddr-display \
+%if %{ldap}
+	--with-ldap \
+%endif
+	--with-pam \
+%if %{WITH_SELINUX}
+	--with-selinux --with-audit=linux \
+%if 1
+	--with-sandbox=selinux \
+%else
+	--with-sandbox=no \
+%endif
+%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 -d $RPM_BUILD_ROOT%{_libdir}/fipscheck $RPM_BUILD_ROOT%{_bindir}/gsissh $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
+rm -f $RPM_BUILD_ROOT%{_sysconfdir}/gsissh/ldap.conf
+
+install -d $RPM_BUILD_ROOT/etc/pam.d/
+install -d $RPM_BUILD_ROOT/etc/sysconfig/
+install -d $RPM_BUILD_ROOT%{_libexecdir}/gsissh
+install -d $RPM_BUILD_ROOT%{_libdir}/fipscheck
+install -m644 %{SOURCE2} $RPM_BUILD_ROOT/etc/pam.d/gsisshd
+install -m644 %{SOURCE7} $RPM_BUILD_ROOT/etc/sysconfig/gsisshd
+install -m755 %{SOURCE13} $RPM_BUILD_ROOT/%{_sbindir}/sshd-keygen
+install -d -m755 $RPM_BUILD_ROOT/%{_unitdir}
+install -m644 %{SOURCE8} $RPM_BUILD_ROOT/%{_unitdir}/gsisshd-keygen.service
+install -m644 %{SOURCE11} $RPM_BUILD_ROOT/%{_unitdir}/gsisshd.service
+
+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-ldap-helper
+rm $RPM_BUILD_ROOT%{_libexecdir}/gsissh/ssh-ldap-wrapper
+rm $RPM_BUILD_ROOT%{_libexecdir}/gsissh/ssh-keycat
+rm $RPM_BUILD_ROOT%{_libexecdir}/gsissh/ssh-pkcs11-helper
+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%{_mandir}/man8/ssh-pkcs11-helper.8*
+
+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*/*
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%pre
+getent group ssh_keys >/dev/null || groupadd -r ssh_keys || :
+
+%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
+
+%postun server
+/bin/systemctl daemon-reload >/dev/null 2>&1 || :
+if [ $1 -ge 1 ] ; then
+    # Package upgrade, not uninstall
+    /bin/systemctl try-restart gsisshd.service >/dev/null 2>&1 || :
+    /bin/systemctl try-restart gsisshd-keygen.service >/dev/null 2>&1 || :
+fi
+
+%preun server
+if [ $1 -eq 0 ] ; then
+    # Package removal, not upgrade
+    /bin/systemctl --no-reload disable gsisshd.service > /dev/null 2>&1 || :
+    /bin/systemctl --no-reload disable gsisshd-keygen.service > /dev/null 2>&1 || :
+    /bin/systemctl stop gsisshd.service > /dev/null 2>&1 || :
+    /bin/systemctl stop gsisshd-keygen.service > /dev/null 2>&1 || :
+fi
+
+%triggerun server -- gsi-openssh-server < 5.8p2-1
+/usr/bin/systemd-sysv-convert --save gsisshd >/dev/null 2>&1 || :
+/sbin/chkconfig --del gsisshd >/dev/null 2>&1 || :
+/bin/systemctl try-restart gsisshd.service >/dev/null 2>&1 || :
+# This one was never a service, so we don't simply restart it
+/bin/systemctl is-active -q gsisshd.service && /bin/systemctl start gsisshd-keygen.service >/dev/null 2>&1 || :
+
+%files
+%defattr(-,root,root)
+%doc CREDITS ChangeLog INSTALL LICENCE LICENSE.globus_usage OVERVIEW PROTOCOL* README README.platform README.privsep README.tun README.dns README.sshd-and-gsisshd TODO
+%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(2755,root,ssh_keys) %{_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) %{_libdir}/fipscheck/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(0755,root,root) %{_sbindir}/gsisshd-keygen
+%attr(0644,root,root) %{_libdir}/fipscheck/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(0640,root,root) %config(noreplace) /etc/sysconfig/gsisshd
+%attr(0644,root,root) %{_unitdir}/gsisshd-keygen.service
+%attr(0644,root,root) %{_unitdir}/gsisshd.service
+
+%changelog
+* Thu Nov 17 2011 Mattias Ellert <mattias.ellert at fysast.uu.se> - 5.9p1-2
+- Based on openssh-5.9p1-11.fc17
+
+* Thu Oct 06 2011 Mattias Ellert <mattias.ellert at fysast.uu.se> - 5.9p1-1
+- Initial packaging
+- Based on openssh-5.9p1-7.fc17
diff --git a/gsisshd-keygen b/gsisshd-keygen
new file mode 100644
index 0000000..36976f0
--- /dev/null
+++ b/gsisshd-keygen
@@ -0,0 +1,90 @@
+#!/bin/bash
+
+# Create the host keys for the gsissh server.
+#
+# The creation is controlled by the $AUTOCREATE_SERVER_KEYS environment
+# variable.
+
+# source function library
+. /etc/rc.d/init.d/functions
+
+# pull in sysconfig settings
+[ -f /etc/sysconfig/gsisshd ] && . /etc/sysconfig/gsisshd
+
+# Some functions to make the below more readable
+KEYGEN=/usr/bin/gsissh-keygen
+RSA1_KEY=/etc/gsissh/ssh_host_key
+RSA_KEY=/etc/gsissh/ssh_host_rsa_key
+DSA_KEY=/etc/gsissh/ssh_host_dsa_key
+
+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
+			chgrp ssh_keys $RSA1_KEY
+			chmod 640 $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
+			chgrp ssh_keys $RSA_KEY
+			chmod 640 $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
+			chgrp ssh_keys $DSA_KEY
+			chmod 640 $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
+}
+
+# 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
diff --git a/gsisshd-keygen.service b/gsisshd-keygen.service
new file mode 100644
index 0000000..6f86c84
--- /dev/null
+++ b/gsisshd-keygen.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=gsissh server keys generation.
+After=syslog.target
+Before=gsisshd.service
+
+[Service]
+Type=oneshot
+ExecStart=/usr/sbin/gsisshd-keygen
+RemainAfterExit=yes
+
+[Install]
+WantedBy=multi-user.target
diff --git a/gsisshd.pam b/gsisshd.pam
new file mode 100644
index 0000000..af19ec0
--- /dev/null
+++ b/gsisshd.pam
@@ -0,0 +1,15 @@
+#%PAM-1.0
+auth       required     pam_sepermit.so
+auth       substack     password-auth
+auth       include      postlogin
+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
+session    include      postlogin
diff --git a/gsisshd.service b/gsisshd.service
new file mode 100644
index 0000000..73a2edd
--- /dev/null
+++ b/gsisshd.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=gsissh server daemon.
+After=syslog.target network.target auditd.service
+
+[Service]
+ExecStart=/usr/sbin/gsisshd -D
+ExecReload=/bin/kill -HUP $MAINPID
+
+[Install]
+WantedBy=multi-user.target
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-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-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-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.5p1-x11.patch b/openssh-5.5p1-x11.patch
new file mode 100644
index 0000000..cac5d5e
--- /dev/null
+++ b/openssh-5.5p1-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-5.6p1-exit-deadlock.patch b/openssh-5.6p1-exit-deadlock.patch
new file mode 100644
index 0000000..278dfa1
--- /dev/null
+++ b/openssh-5.6p1-exit-deadlock.patch
@@ -0,0 +1,14 @@
+diff -up openssh-5.6p1/channels.c.exit-deadlock openssh-5.6p1/channels.c
+--- openssh-5.6p1/channels.c.exit-deadlock	2010-08-05 15:09:48.000000000 +0200
++++ openssh-5.6p1/channels.c	2010-08-23 12:41:43.000000000 +0200
+@@ -1647,6 +1647,10 @@ channel_handle_wfd(Channel *c, fd_set *r
+ 	u_int dlen, olen = 0;
+ 	int len;
+ 
++	if(c->wfd != -1 && buffer_len(&c->output) > 0 && c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
++		debug("channel %d: forcing write", c->self);
++		FD_SET(c->wfd, writeset);
++	}
+ 	/* Send buffered output data to the socket. */
+ 	if (c->wfd != -1 &&
+ 	    FD_ISSET(c->wfd, writeset) &&
diff --git a/openssh-5.8p1-audit0.patch b/openssh-5.8p1-audit0.patch
new file mode 100644
index 0000000..9a0f37c
--- /dev/null
+++ b/openssh-5.8p1-audit0.patch
@@ -0,0 +1,17 @@
+Don't audit SSH_INVALID_USER twice.
+
+PRIVSEP(getpwnamallow()) a few lines above already did this.
+
+diff -ur openssh/auth2.c openssh-5.8p1/auth2.c
+--- openssh/auth2.c	2011-03-02 02:32:52.383773622 +0100
++++ openssh-5.8p1/auth2.c	2011-03-02 03:32:34.585110911 +0100
+@@ -250,9 +250,6 @@
+ 		} else {
+ 			logit("input_userauth_request: invalid user %s", user);
+ 			authctxt->pw = fakepw();
+-#ifdef SSH_AUDIT_EVENTS
+-			PRIVSEP(audit_event(SSH_INVALID_USER));
+-#endif
+ 		}
+ #ifdef USE_PAM
+ 		if (options.use_pam)
diff --git a/openssh-5.8p1-fingerprint.patch b/openssh-5.8p1-fingerprint.patch
new file mode 100644
index 0000000..a0438ff
--- /dev/null
+++ b/openssh-5.8p1-fingerprint.patch
@@ -0,0 +1,421 @@
+diff -up openssh-5.8p1/auth2-hostbased.c.fingerprint openssh-5.8p1/auth2-hostbased.c
+--- openssh-5.8p1/auth2-hostbased.c.fingerprint	2010-08-05 05:04:50.000000000 +0200
++++ openssh-5.8p1/auth2-hostbased.c	2011-02-25 09:17:18.000000000 +0100
+@@ -196,16 +196,18 @@ hostbased_key_allowed(struct passwd *pw,
+ 
+ 	if (host_status == HOST_OK) {
+ 		if (key_is_cert(key)) {
+-			fp = key_fingerprint(key->cert->signature_key,
+-			    SSH_FP_MD5, SSH_FP_HEX);
++			fp = key_selected_fingerprint(key->cert->signature_key,
++			    SSH_FP_HEX);
+ 			verbose("Accepted certificate ID \"%s\" signed by "
+-			    "%s CA %s from %s@%s", key->cert->key_id,
+-			    key_type(key->cert->signature_key), fp,
++			    "%s CA %s%s from %s@%s", key->cert->key_id,
++			    key_type(key->cert->signature_key),
++			    key_fingerprint_prefix(), fp,
+ 			    cuser, lookup);
+ 		} else {
+-			fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+-			verbose("Accepted %s public key %s from %s@%s",
+-			    key_type(key), fp, cuser, lookup);
++			fp = key_selected_fingerprint(key, SSH_FP_HEX);
++			verbose("Accepted %s public key %s%s from %s@%s",
++			    key_type(key), key_fingerprint_prefix(),
++			    fp, cuser, lookup);
+ 		}
+ 		xfree(fp);
+ 	}
+diff -up openssh-5.8p1/auth2-pubkey.c.fingerprint openssh-5.8p1/auth2-pubkey.c
+--- openssh-5.8p1/auth2-pubkey.c.fingerprint	2010-12-01 01:50:14.000000000 +0100
++++ openssh-5.8p1/auth2-pubkey.c	2011-02-25 09:17:18.000000000 +0100
+@@ -319,10 +319,10 @@ user_key_allowed2(struct passwd *pw, Key
+ 				continue;
+ 			if (!key_is_cert_authority)
+ 				continue;
+-			fp = key_fingerprint(found, SSH_FP_MD5,
+-			    SSH_FP_HEX);
+-			debug("matching CA found: file %s, line %lu, %s %s",
+-			    file, linenum, key_type(found), fp);
++			fp = key_selected_fingerprint(found, SSH_FP_HEX);
++			debug("matching CA found: file %s, line %lu, %s %s%s",
++			    file, linenum, key_type(found),
++			    key_fingerprint_prefix(), fp);
+ 			/*
+ 			 * If the user has specified a list of principals as
+ 			 * a key option, then prefer that list to matching
+@@ -362,9 +362,9 @@ 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);
+-			verbose("Found matching %s key: %s",
+-			    key_type(found), fp);
++			fp = key_selected_fingerprint(found, SSH_FP_HEX);
++			verbose("Found matching %s key: %s%s",
++			    key_type(found), key_fingerprint_prefix(), fp);
+ 			xfree(fp);
+ 			break;
+ 		}
+@@ -388,13 +388,13 @@ user_cert_trusted_ca(struct passwd *pw, 
+ 	if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL)
+ 		return 0;
+ 
+-	ca_fp = key_fingerprint(key->cert->signature_key,
+-	    SSH_FP_MD5, SSH_FP_HEX);
++	ca_fp = key_selected_fingerprint(key->cert->signature_key, SSH_FP_HEX);
+ 
+ 	if (key_in_file(key->cert->signature_key,
+ 	    options.trusted_user_ca_keys, 1) != 1) {
+-		debug2("%s: CA %s %s is not listed in %s", __func__,
+-		    key_type(key->cert->signature_key), ca_fp,
++		debug2("%s: CA %s%s %s is not listed in %s", __func__,
++		    key_type(key->cert->signature_key),
++		    key_fingerprint_prefix(), ca_fp,
+ 		    options.trusted_user_ca_keys);
+ 		goto out;
+ 	}
+diff -up openssh-5.8p1/auth.c.fingerprint openssh-5.8p1/auth.c
+--- openssh-5.8p1/auth.c.fingerprint	2010-12-01 02:21:51.000000000 +0100
++++ openssh-5.8p1/auth.c	2011-02-25 09:17:18.000000000 +0100
+@@ -639,9 +639,10 @@ auth_key_is_revoked(Key *key)
+ 		return 1;
+ 	case 1:
+ 		/* Key revoked */
+-		key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
++		key_fp = key_selected_fingerprint(key, SSH_FP_HEX);
+ 		error("WARNING: authentication attempt with a revoked "
+-		    "%s key %s ", key_type(key), key_fp);
++		    "%s key %s%s ", key_type(key),
++		    key_fingerprint_prefix(), key_fp);
+ 		xfree(key_fp);
+ 		return 1;
+ 	}
+diff -up openssh-5.8p1/auth-rsa.c.fingerprint openssh-5.8p1/auth-rsa.c
+--- openssh-5.8p1/auth-rsa.c.fingerprint	2010-12-04 23:01:47.000000000 +0100
++++ openssh-5.8p1/auth-rsa.c	2011-02-25 09:17:18.000000000 +0100
+@@ -318,9 +318,9 @@ auth_rsa(Authctxt *authctxt, BIGNUM *cli
+ 	 * options; this will be reset if the options cause the
+ 	 * authentication to be rejected.
+ 	 */
+-	fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+-	verbose("Found matching %s key: %s",
+-	    key_type(key), fp);
++	fp = key_selected_fingerprint(key, SSH_FP_HEX);
++	verbose("Found matching %s key: %s%s",
++	    key_type(key), key_fingerprint_prefix(), fp);
+ 	xfree(fp);
+ 	key_free(key);
+ 
+diff -up openssh-5.8p1/key.c.fingerprint openssh-5.8p1/key.c
+--- openssh-5.8p1/key.c.fingerprint	2011-02-04 01:48:34.000000000 +0100
++++ openssh-5.8p1/key.c	2011-02-25 09:18:16.000000000 +0100
+@@ -594,6 +594,34 @@ key_fingerprint(Key *k, enum fp_type dgs
+ 	return retval;
+ }
+ 
++enum fp_type
++key_fingerprint_selection(void)
++{
++	static enum fp_type rv;
++	static char rv_defined = 0;
++	char *env;
++
++	if (!rv_defined) {
++		env = getenv("SSH_FINGERPRINT_TYPE");
++		rv = (env && !strcmp (env, "sha")) ?
++			SSH_FP_SHA1 : SSH_FP_MD5;
++		rv_defined = 1;
++	}
++	return rv;
++}
++
++char *
++key_selected_fingerprint(Key *k, enum fp_rep dgst_rep)
++{
++	return key_fingerprint(k, key_fingerprint_selection(), dgst_rep);
++}
++
++char *
++key_fingerprint_prefix(void)
++{
++	return key_fingerprint_selection() == SSH_FP_SHA1 ? "sha1:" : "";
++}
++
+ /*
+  * Reads a multiple-precision integer in decimal from the buffer, and advances
+  * the pointer.  The integer must already be initialized.  This function is
+diff -up openssh-5.8p1/key.h.fingerprint openssh-5.8p1/key.h
+--- openssh-5.8p1/key.h.fingerprint	2010-11-05 00:19:49.000000000 +0100
++++ openssh-5.8p1/key.h	2011-02-25 09:17:18.000000000 +0100
+@@ -96,6 +96,9 @@ int		 key_equal_public(const Key *, cons
+ int		 key_equal(const Key *, const Key *);
+ char		*key_fingerprint(Key *, enum fp_type, enum fp_rep);
+ u_char		*key_fingerprint_raw(Key *, enum fp_type, u_int *);
++enum fp_type	 key_fingerprint_selection(void);
++char		*key_selected_fingerprint(Key *, enum fp_rep);
++char		*key_fingerprint_prefix(void);
+ const char	*key_type(const Key *);
+ const char	*key_cert_type(const Key *);
+ int		 key_write(const Key *, FILE *);
+diff -up openssh-5.8p1/ssh-add.c.fingerprint openssh-5.8p1/ssh-add.c
+--- openssh-5.8p1/ssh-add.c.fingerprint	2010-11-11 04:17:02.000000000 +0100
++++ openssh-5.8p1/ssh-add.c	2011-02-25 09:17:18.000000000 +0100
+@@ -280,10 +280,10 @@ list_identities(AuthenticationConnection
+ 		    key = ssh_get_next_identity(ac, &comment, version)) {
+ 			had_identities = 1;
+ 			if (do_fp) {
+-				fp = key_fingerprint(key, SSH_FP_MD5,
+-				    SSH_FP_HEX);
+-				printf("%d %s %s (%s)\n",
+-				    key_size(key), fp, comment, key_type(key));
++				fp = key_selected_fingerprint(key, SSH_FP_HEX);
++				printf("%d %s%s %s (%s)\n",
++				    key_size(key), key_fingerprint_prefix(),
++				    fp, comment, key_type(key));
+ 				xfree(fp);
+ 			} else {
+ 				if (!key_write(key, stdout))
+diff -up openssh-5.8p1/ssh-agent.c.fingerprint openssh-5.8p1/ssh-agent.c
+--- openssh-5.8p1/ssh-agent.c.fingerprint	2010-12-01 01:50:35.000000000 +0100
++++ openssh-5.8p1/ssh-agent.c	2011-02-25 09:17:18.000000000 +0100
+@@ -199,9 +199,9 @@ confirm_key(Identity *id)
+ 	char *p;
+ 	int ret = -1;
+ 
+-	p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
+-	if (ask_permission("Allow use of key %s?\nKey fingerprint %s.",
+-	    id->comment, p))
++	p = key_selected_fingerprint(id->key, SSH_FP_HEX);
++	if (ask_permission("Allow use of key %s?\nKey fingerprint %s%s.",
++	    id->comment, key_fingerprint_prefix(), p))
+ 		ret = 0;
+ 	xfree(p);
+ 
+diff -up openssh-5.8p1/sshconnect2.c.fingerprint openssh-5.8p1/sshconnect2.c
+--- openssh-5.8p1/sshconnect2.c.fingerprint	2010-12-01 02:21:51.000000000 +0100
++++ openssh-5.8p1/sshconnect2.c	2011-02-25 09:17:18.000000000 +0100
+@@ -590,8 +590,9 @@ 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_selected_fingerprint(key, SSH_FP_HEX);
++	debug2("input_userauth_pk_ok: fp %s%s",
++	    key_fingerprint_prefix(), fp);
+ 	xfree(fp);
+ 
+ 	/*
+@@ -1203,8 +1204,9 @@ sign_and_send_pubkey(Authctxt *authctxt,
+ 	int have_sig = 1;
+ 	char *fp;
+ 
+-	fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
+-	debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp);
++	fp = key_selected_fingerprint(id->key, SSH_FP_HEX);
++	debug3("sign_and_send_pubkey: %s %s%s", key_type(id->key),
++	    key_fingerprint_prefix(), fp);
+ 	xfree(fp);
+ 
+ 	if (key_to_blob(id->key, &blob, &bloblen) == 0) {
+diff -up openssh-5.8p1/sshconnect.c.fingerprint openssh-5.8p1/sshconnect.c
+--- openssh-5.8p1/sshconnect.c.fingerprint	2011-01-16 13:17:59.000000000 +0100
++++ openssh-5.8p1/sshconnect.c	2011-02-25 09:17:18.000000000 +0100
+@@ -798,10 +798,10 @@ check_host_key(char *hostname, struct so
+ 				    "key for IP address '%.128s' to the list "
+ 				    "of known hosts.", type, ip);
+ 		} else if (options.visual_host_key) {
+-			fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+-			ra = key_fingerprint(host_key, SSH_FP_MD5,
+-			    SSH_FP_RANDOMART);
+-			logit("Host key fingerprint is %s\n%s\n", fp, ra);
++			fp = key_selected_fingerprint(host_key, SSH_FP_HEX);
++			ra = key_selected_fingerprint(host_key, SSH_FP_RANDOMART);
++			logit("Host key fingerprint is %s%s\n%s\n",
++			    key_fingerprint_prefix(), fp, ra);
+ 			xfree(ra);
+ 			xfree(fp);
+ 		}
+@@ -838,9 +838,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,
+-			    SSH_FP_RANDOMART);
++			fp = key_selected_fingerprint(host_key, SSH_FP_HEX);
++			ra = key_selected_fingerprint(host_key, SSH_FP_RANDOMART);
+ 			msg2[0] = '\0';
+ 			if (options.verify_host_key_dns) {
+ 				if (matching_host_key_dns)
+@@ -855,10 +854,11 @@ 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 fingerprint is %s%s.%s%s\n%s"
+ 			    "Are you sure you want to continue connecting "
+ 			    "(yes/no)? ",
+-			    host, ip, msg1, type, fp,
++			    host, ip, msg1, type,
++			    key_fingerprint_prefix(), fp,
+ 			    options.visual_host_key ? "\n" : "",
+ 			    options.visual_host_key ? ra : "",
+ 			    msg2);
+@@ -1104,8 +1104,9 @@ verify_host_key(char *host, struct socka
+ 	int flags = 0;
+ 	char *fp;
+ 
+-	fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+-	debug("Server host key: %s %s", key_type(host_key), fp);
++	fp = key_selected_fingerprint(host_key, SSH_FP_HEX);
++	debug("Server host key: %s %s%s", key_type(host_key),
++	    key_fingerprint_prefix(), fp);
+ 	xfree(fp);
+ 
+ 	/* XXX certs are not yet supported for DNS */
+@@ -1214,14 +1215,15 @@ show_other_keys(struct hostkeys *hostkey
+ 			continue;
+ 		if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found))
+ 			continue;
+-		fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX);
+-		ra = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_RANDOMART);
++		fp = key_selected_fingerprint(found->key, SSH_FP_HEX);
++		ra = key_selected_fingerprint(found->key, SSH_FP_RANDOMART);
+ 		logit("WARNING: %s key found for host %s\n"
+ 		    "in %s:%lu\n"
+-		    "%s key fingerprint %s.",
++		    "%s key fingerprint %s%s.",
+ 		    key_type(found->key),
+ 		    found->host, found->file, found->line,
+-		    key_type(found->key), fp);
++		    key_type(found->key),
++		    key_fingerprint_prefix(), fp);
+ 		if (options.visual_host_key)
+ 			logit("%s", ra);
+ 		xfree(ra);
+@@ -1236,7 +1238,7 @@ warn_changed_key(Key *host_key)
+ {
+ 	char *fp;
+ 
+-	fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
++	fp = key_selected_fingerprint(host_key, SSH_FP_HEX);
+ 
+ 	error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+ 	error("@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @");
+@@ -1244,8 +1246,8 @@ warn_changed_key(Key *host_key)
+ 	error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
+ 	error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
+ 	error("It is also possible that a host key has just been changed.");
+-	error("The fingerprint for the %s key sent by the remote host is\n%s.",
+-	    key_type(host_key), fp);
++	error("The fingerprint for the %s key sent by the remote host is\n%s%s.",
++	    key_type(host_key),key_fingerprint_prefix(),  fp);
+ 	error("Please contact your system administrator.");
+ 
+ 	xfree(fp);
+diff -up openssh-5.8p1/ssh-keygen.c.fingerprint openssh-5.8p1/ssh-keygen.c
+--- openssh-5.8p1/ssh-keygen.c.fingerprint	2011-01-11 07:20:31.000000000 +0100
++++ openssh-5.8p1/ssh-keygen.c	2011-02-25 09:17:18.000000000 +0100
+@@ -714,13 +714,14 @@ do_fingerprint(struct passwd *pw)
+ {
+ 	FILE *f;
+ 	Key *public;
+-	char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra;
++	char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra, *pfx;
+ 	int i, skip = 0, num = 0, invalid = 1;
+ 	enum fp_rep rep;
+ 	enum fp_type fptype;
+ 	struct stat st;
+ 
+-	fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
++	fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_selection();
++	pfx =	 print_bubblebabble ? "" : key_fingerprint_prefix();
+ 	rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
+ 
+ 	if (!have_identity)
+@@ -732,8 +733,8 @@ do_fingerprint(struct passwd *pw)
+ 	public = key_load_public(identity_file, &comment);
+ 	if (public != NULL) {
+ 		fp = key_fingerprint(public, fptype, rep);
+-		ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
+-		printf("%u %s %s (%s)\n", key_size(public), fp, comment,
++		ra = key_selected_fingerprint(public, SSH_FP_RANDOMART);
++		printf("%u %s%s %s (%s)\n", key_size(public), pfx, fp, comment,
+ 		    key_type(public));
+ 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
+ 			printf("%s\n", ra);
+@@ -798,8 +799,8 @@ do_fingerprint(struct passwd *pw)
+ 		}
+ 		comment = *cp ? cp : comment;
+ 		fp = key_fingerprint(public, fptype, rep);
+-		ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
+-		printf("%u %s %s (%s)\n", key_size(public), fp,
++		ra = key_selected_fingerprint(public, SSH_FP_RANDOMART);
++		printf("%u %s%s %s (%s)\n", key_size(public), pfx, fp,
+ 		    comment ? comment : "no comment", key_type(public));
+ 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
+ 			printf("%s\n", ra);
+@@ -823,13 +824,15 @@ printhost(FILE *f, const char *name, Key
+ 	if (print_fingerprint) {
+ 		enum fp_rep rep;
+ 		enum fp_type fptype;
+-		char *fp, *ra;
++		char *fp, *ra, *pfx;
+ 
+-		fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
++		fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_selection();
++		pfx =	 print_bubblebabble ? "" : key_fingerprint_prefix();
+ 		rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
++
+ 		fp = key_fingerprint(public, fptype, rep);
+-		ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
+-		printf("%u %s %s (%s)\n", key_size(public), fp, name,
++		ra = key_selected_fingerprint(public, SSH_FP_RANDOMART);
++		printf("%u %s%s %s (%s)\n", key_size(public), pfx, fp, name,
+ 		    key_type(public));
+ 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
+ 			printf("%s\n", ra);
+@@ -1695,16 +1698,17 @@ do_show_cert(struct passwd *pw)
+ 		fatal("%s is not a certificate", identity_file);
+ 	v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00;
+ 
+-	key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+-	ca_fp = key_fingerprint(key->cert->signature_key,
+-	    SSH_FP_MD5, SSH_FP_HEX);
++	key_fp = key_selected_fingerprint(key, SSH_FP_HEX);
++	ca_fp = key_selected_fingerprint(key->cert->signature_key, SSH_FP_HEX);
+ 
+ 	printf("%s:\n", identity_file);
+ 	printf("        Type: %s %s certificate\n", key_ssh_name(key),
+ 	    key_cert_type(key));
+-	printf("        Public key: %s %s\n", key_type(key), key_fp);
+-	printf("        Signing CA: %s %s\n",
+-	    key_type(key->cert->signature_key), ca_fp);
++	printf("        Public key: %s %s%s\n", key_type(key),
++	    key_fingerprint_prefix(), key_fp);
++	printf("        Signing CA: %s %s%s\n",
++	    key_type(key->cert->signature_key),
++	    key_fingerprint_prefix(), ca_fp);
+ 	printf("        Key ID: \"%s\"\n", key->cert->key_id);
+ 	if (!v00) {
+ 		printf("        Serial: %llu\n",
+@@ -2249,13 +2253,12 @@ passphrase_again:
+ 	fclose(f);
+ 
+ 	if (!quiet) {
+-		char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
+-		char *ra = key_fingerprint(public, SSH_FP_MD5,
+-		    SSH_FP_RANDOMART);
++		char *fp = key_selected_fingerprint(public, SSH_FP_HEX);
++		char *ra = key_selected_fingerprint(public, SSH_FP_RANDOMART);
+ 		printf("Your public key has been saved in %s.\n",
+ 		    identity_file);
+ 		printf("The key fingerprint is:\n");
+-		printf("%s %s\n", fp, comment);
++		printf("%s%s %s\n", key_fingerprint_prefix(), fp, comment);
+ 		printf("The key's randomart image is:\n");
+ 		printf("%s\n", ra);
+ 		xfree(ra);
diff --git a/openssh-5.8p1-getaddrinfo.patch b/openssh-5.8p1-getaddrinfo.patch
new file mode 100644
index 0000000..6f64067
--- /dev/null
+++ b/openssh-5.8p1-getaddrinfo.patch
@@ -0,0 +1,11 @@
+diff -up openssh-5.8p1/sshconnect.c.getaddrinfo openssh-5.8p1/sshconnect.c
+--- openssh-5.8p1/sshconnect.c.getaddrinfo	2011-04-27 09:51:44.521384633 +0200
++++ openssh-5.8p1/sshconnect.c	2011-04-27 09:53:21.224443308 +0200
+@@ -355,6 +355,7 @@ ssh_connect(const char *host, struct soc
+ 	memset(&hints, 0, sizeof(hints));
+ 	hints.ai_family = family;
+ 	hints.ai_socktype = SOCK_STREAM;
++	hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
+ 	snprintf(strport, sizeof strport, "%u", port);
+ 	if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
+ 		fatal("%s: Could not resolve hostname %.100s: %s", __progname,
diff --git a/openssh-5.8p1-glob.patch b/openssh-5.8p1-glob.patch
new file mode 100644
index 0000000..cb45cd1
--- /dev/null
+++ b/openssh-5.8p1-glob.patch
@@ -0,0 +1,10 @@
+diff -up openssh-5.8p1/sftp-glob.c.glob openssh-5.8p1/sftp-glob.c
+--- openssh-5.8p1/sftp-glob.c.glob	2011-03-07 20:17:34.000000000 +0100
++++ openssh-5.8p1/sftp-glob.c	2011-03-07 20:18:47.000000000 +0100
+@@ -145,5 +145,5 @@ remote_glob(struct sftp_conn *conn, cons
+ 	memset(&cur, 0, sizeof(cur));
+ 	cur.conn = conn;
+ 
+-	return(glob(pattern, flags | GLOB_ALTDIRFUNC, errfunc, pglob));
++	return(glob(pattern, flags | GLOB_LIMIT | GLOB_ALTDIRFUNC, errfunc, pglob));
+ }
diff --git a/openssh-5.8p1-gssapi-canohost.patch b/openssh-5.8p1-gssapi-canohost.patch
new file mode 100644
index 0000000..a8e02fb
--- /dev/null
+++ b/openssh-5.8p1-gssapi-canohost.patch
@@ -0,0 +1,24 @@
+diff -up openssh-5.8p1/sshconnect2.c.canohost openssh-5.8p1/sshconnect2.c
+--- openssh-5.8p1/sshconnect2.c.canohost	2011-02-14 15:15:15.000000000 +0100
++++ openssh-5.8p1/sshconnect2.c	2011-02-14 15:21:45.000000000 +0100
+@@ -697,14 +697,17 @@ userauth_gssapi(Authctxt *authctxt)
+ 	static u_int mech = 0;
+ 	OM_uint32 min;
+ 	int ok = 0;
+-	const char *gss_host;
++	const char *gss_host = NULL;
+ 
+ 	if (options.gss_server_identity)
+ 		gss_host = options.gss_server_identity;
+ 	else if (options.gss_trust_dns)
+ 		gss_host = get_canonical_hostname(1);
+-	else
+-		gss_host = authctxt->host;
++	else {
++		gss_host = get_canonical_hostname(1);
++		if ( strcmp( gss_host, "UNKNOWN" )  == 0 )
++			gss_host = authctxt->host;
++	}
+ 
+ 	/* Try one GSSAPI method at a time, rather than sending them all at
+ 	 * once. */
diff --git a/openssh-5.8p1-keyperm.patch b/openssh-5.8p1-keyperm.patch
new file mode 100644
index 0000000..6167c14
--- /dev/null
+++ b/openssh-5.8p1-keyperm.patch
@@ -0,0 +1,25 @@
+diff -up openssh-5.8p1/authfile.c.keyperm openssh-5.8p1/authfile.c
+--- openssh-5.8p1/authfile.c.keyperm	2010-12-01 02:03:39.000000000 +0100
++++ openssh-5.8p1/authfile.c	2011-04-21 16:43:36.859648916 +0200
+@@ -57,6 +57,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
++#include <grp.h>
+ 
+ #include "xmalloc.h"
+ #include "cipher.h"
+@@ -600,6 +612,13 @@ key_perm_ok(int fd, const char *filename
+ #ifdef HAVE_CYGWIN
+ 	if (check_ntsec(filename))
+ #endif
++	if (st.st_mode & 040) {
++		struct group *gr;
++
++		if ((gr = getgrnam("ssh_keys")) && (st.st_gid == gr->gr_gid))
++			st.st_mode &= ~040;
++	}
++
+ 	if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
+ 		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+ 		error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
diff --git a/openssh-5.8p1-localdomain.patch b/openssh-5.8p1-localdomain.patch
new file mode 100644
index 0000000..2f21658
--- /dev/null
+++ b/openssh-5.8p1-localdomain.patch
@@ -0,0 +1,14 @@
+diff -up openssh-5.8p1/sshd_config.localdomain openssh-5.8p1/sshd_config
+--- openssh-5.8p1/sshd_config.localdomain	2011-04-22 11:37:49.273648812 +0200
++++ openssh-5.8p1/sshd_config	2011-04-22 11:39:31.758648401 +0200
+@@ -130,6 +130,10 @@ X11Forwarding yes
+ # override default of no subsystems
+ Subsystem	sftp	/usr/libexec/sftp-server
+ 
++# Uncomment this if you want to use .local domain
++#Host *.local
++#	CheckHostIP no
++
+ # Example of overriding settings on a per-user basis
+ #Match User anoncvs
+ #	X11Forwarding no
diff --git a/openssh-5.8p1-packet.patch b/openssh-5.8p1-packet.patch
new file mode 100644
index 0000000..4951af6
--- /dev/null
+++ b/openssh-5.8p1-packet.patch
@@ -0,0 +1,12 @@
+diff -up openssh-5.8p1/packet.c.packet openssh-5.8p1/packet.c
+--- openssh-5.8p1/packet.c.packet	2011-04-05 13:29:06.998648899 +0200
++++ openssh-5.8p1/packet.c	2011-04-05 13:30:32.967648596 +0200
+@@ -294,6 +294,8 @@ packet_connection_is_on_socket(void)
+ 	struct sockaddr_storage from, to;
+ 	socklen_t fromlen, tolen;
+ 
++	if (!active_state)
++		return 0;
+ 	/* filedescriptors in and out are the same, so it's a socket */
+ 	if (active_state->connection_in == active_state->connection_out)
+ 		return 1;
diff --git a/openssh-5.8p2-askpass-ld.patch b/openssh-5.8p2-askpass-ld.patch
new file mode 100644
index 0000000..5b85c80
--- /dev/null
+++ b/openssh-5.8p2-askpass-ld.patch
@@ -0,0 +1,18 @@
+diff -up openssh-5.8p2/contrib/Makefile.askpass-ld openssh-5.8p2/contrib/Makefile
+--- openssh-5.8p2/contrib/Makefile.askpass-ld	2011-08-08 22:54:06.050546199 +0200
++++ openssh-5.8p2/contrib/Makefile	2011-08-08 22:54:43.364420118 +0200
+@@ -2,12 +2,12 @@ all:
+ 	@echo "Valid targets: gnome-ssh-askpass1 gnome-ssh-askpass2"
+ 
+ gnome-ssh-askpass1: gnome-ssh-askpass1.c
+-	$(CC) `gnome-config --cflags gnome gnomeui` \
++	$(CC) ${CFLAGS} `gnome-config --cflags gnome gnomeui` \
+ 		gnome-ssh-askpass1.c -o gnome-ssh-askpass1 \
+ 		`gnome-config --libs gnome gnomeui`
+ 
+ gnome-ssh-askpass2: gnome-ssh-askpass2.c
+-	$(CC) `pkg-config --cflags gtk+-2.0` \
++	$(CC) ${CFLAGS} `pkg-config --cflags gtk+-2.0` \
+ 		gnome-ssh-askpass2.c -o gnome-ssh-askpass2 \
+ 		`pkg-config --libs gtk+-2.0 x11`
+ 
diff --git a/openssh-5.8p2-force_krb.patch b/openssh-5.8p2-force_krb.patch
new file mode 100644
index 0000000..1842ce4
--- /dev/null
+++ b/openssh-5.8p2-force_krb.patch
@@ -0,0 +1,288 @@
+diff -up openssh-5.8p2/gss-serv-krb5.c.force_krb openssh-5.8p2/gss-serv-krb5.c
+--- openssh-5.8p2/gss-serv-krb5.c.force_krb	2006-09-01 07:38:36.000000000 +0200
++++ openssh-5.8p2/gss-serv-krb5.c	2011-05-19 03:41:45.801109545 +0200
+@@ -32,7 +32,9 @@
+ #include <sys/types.h>
+ 
+ #include <stdarg.h>
++#include <stdio.h>
+ #include <string.h>
++#include <unistd.h>
+ 
+ #include "xmalloc.h"
+ #include "key.h"
+@@ -40,12 +42,11 @@
+ #include "auth.h"
+ #include "log.h"
+ #include "servconf.h"
++#include "misc.h"
+ 
+ #include "buffer.h"
+ #include "ssh-gss.h"
+ 
+-extern ServerOptions options;
+-
+ #ifdef HEIMDAL
+ # include <krb5.h>
+ #else
+@@ -56,6 +57,16 @@ extern ServerOptions options;
+ # endif
+ #endif
+ 
++extern Authctxt *the_authctxt;
++extern ServerOptions options;
++
++/* all commands are allowed by default */
++char **k5users_allowed_cmds = NULL;
++
++static int ssh_gssapi_k5login_exists();
++static int ssh_gssapi_krb5_cmdok(krb5_principal, const char *, const char *,
++    int);
++
+ static krb5_context krb_context = NULL;
+ 
+ /* Initialise the krb5 library, for the stuff that GSSAPI won't do */
+@@ -83,10 +94,11 @@ ssh_gssapi_krb5_init(void)
+  */
+ 
+ static int
+-ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
++ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *luser)
+ {
+ 	krb5_principal princ;
+ 	int retval;
++	int k5login_exists;
+ 
+ 	if (ssh_gssapi_krb5_init() == 0)
+ 		return 0;
+@@ -97,10 +109,22 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client
+ 		    krb5_get_err_text(krb_context, retval));
+ 		return 0;
+ 	}
+-	if (krb5_kuserok(krb_context, princ, name)) {
++	/* krb5_kuserok() returns 1 if .k5login DNE and this is self-login.
++	 * We have to make sure to check .k5users in that case. */
++	k5login_exists = ssh_gssapi_k5login_exists();
++	/* NOTE: .k5login and .k5users must opened as root, not the user,
++	 * because if they are on a krb5-protected filesystem, user credentials
++	 * to access these files aren't available yet. */
++	if (krb5_kuserok(krb_context, princ, luser) && k5login_exists) {
+ 		retval = 1;
+ 		logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
+-		    name, (char *)client->displayname.value);
++		    luser, (char *)client->displayname.value);
++	} else if (ssh_gssapi_krb5_cmdok(princ, client->exportedname.value,
++		luser, k5login_exists)) {
++		retval = 1;
++		logit("Authorized to %s, krb5 principal %s "
++		    "(ssh_gssapi_krb5_cmdok)",
++		    luser, (char *)client->displayname.value);
+ 	} else
+ 		retval = 0;
+ 
+@@ -108,6 +132,134 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client
+ 	return retval;
+ }
+ 
++/* Test for existence of .k5login.
++ * We need this as part of our .k5users check, because krb5_kuserok()
++ * returns success if .k5login DNE and user is logging in as himself.
++ * With .k5login absent and .k5users present, we don't want absence
++ * of .k5login to authorize self-login.  (absence of both is required)
++ * Returns 1 if .k5login is available, 0 otherwise.
++ */
++static int
++ssh_gssapi_k5login_exists()
++{
++	char file[MAXPATHLEN];
++	struct passwd *pw = the_authctxt->pw;
++
++	snprintf(file, sizeof(file), "%s/.k5login", pw->pw_dir);
++	return access(file, F_OK) == 0;
++}
++
++/* check .k5users for login or command authorization
++ * Returns 1 if principal is authorized, 0 otherwise.
++ * If principal is authorized, (global) k5users_allowed_cmds may be populated.
++ */
++static int
++ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name,
++    const char *luser, int k5login_exists)
++{
++	FILE *fp;
++	char file[MAXPATHLEN];
++	char line[BUFSIZ];
++	char kuser[65]; /* match krb5_kuserok() */
++	struct stat st;
++	struct passwd *pw = the_authctxt->pw;
++	int found_principal = 0;
++	int ncommands = 0, allcommands = 0;
++	u_long linenum;
++
++	snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir);
++	/* If both .k5login and .k5users DNE, self-login is ok. */
++	if (!k5login_exists && (access(file, F_OK) == -1)) {
++		return (krb5_aname_to_localname(krb_context, principal,
++		    sizeof(kuser), kuser) == 0) &&
++		    (strcmp(kuser, luser) == 0);
++	}
++	if ((fp = fopen(file, "r")) == NULL) {
++		int saved_errno = errno;
++		/* 2nd access check to ease debugging if file perms are wrong.
++		 * But we don't want to report this if .k5users simply DNE. */
++		if (access(file, F_OK) == 0) {
++			logit("User %s fopen %s failed: %s",
++			    pw->pw_name, file, strerror(saved_errno));
++		}
++		return 0;
++	}
++	/* .k5users must be owned either by the user or by root */
++	if (fstat(fileno(fp), &st) == -1) {
++		/* can happen, but very wierd error so report it */
++		logit("User %s fstat %s failed: %s",
++		    pw->pw_name, file, strerror(errno));
++		fclose(fp);
++		return 0;
++	}
++	if (!(st.st_uid == pw->pw_uid || st.st_uid == 0)) {
++		logit("User %s %s is not owned by root or user",
++		    pw->pw_name, file);
++		fclose(fp);
++		return 0;
++	}
++	/* .k5users must be a regular file.  krb5_kuserok() doesn't do this
++	  * check, but we don't want to be deficient if they add a check. */
++	if (!S_ISREG(st.st_mode)) {
++		logit("User %s %s is not a regular file", pw->pw_name, file);
++		fclose(fp);
++		return 0;
++	}
++	/* file exists; initialize k5users_allowed_cmds (to none!) */
++	k5users_allowed_cmds = xcalloc(++ncommands,
++	    sizeof(*k5users_allowed_cmds));
++
++	/* Check each line.  ksu allows unlimited length lines.  We don't. */
++	while (!allcommands && read_keyfile_line(fp, file, line, sizeof(line),
++	    &linenum) != -1) {
++		char *token;
++
++		/* we parse just like ksu, even though we could do better */
++		token = strtok(line, " \t\n");
++		if (strcmp(name, token) == 0) {
++			/* we matched on client principal */
++			found_principal = 1;
++			if ((token = strtok(NULL, " \t\n")) == NULL) {
++				/* only shell is allowed */
++				k5users_allowed_cmds[ncommands-1] =
++				    xstrdup(pw->pw_shell);
++				k5users_allowed_cmds =
++				    xrealloc(k5users_allowed_cmds, ++ncommands,
++					sizeof(*k5users_allowed_cmds));
++				break;
++			}
++			/* process the allowed commands */
++			while (token) {
++				if (strcmp(token, "*") == 0) {
++					allcommands = 1;
++					break;
++				}
++				k5users_allowed_cmds[ncommands-1] =
++				    xstrdup(token);
++				k5users_allowed_cmds =
++				    xrealloc(k5users_allowed_cmds, ++ncommands,
++					sizeof(*k5users_allowed_cmds));
++				token = strtok(NULL, " \t\n");
++			}
++		}
++       }
++	if (k5users_allowed_cmds) {
++		/* terminate vector */
++		k5users_allowed_cmds[ncommands-1] = NULL;
++		/* if all commands are allowed, free vector */
++		if (allcommands) {
++			int i;
++			for (i = 0; i < ncommands; i++) {
++				free(k5users_allowed_cmds[i]);
++			}
++			free(k5users_allowed_cmds);
++			k5users_allowed_cmds = NULL;
++		}
++	}
++	fclose(fp);
++	return found_principal;
++}
++ 
+ 
+ /* This writes out any forwarded credentials from the structure populated
+  * during userauth. Called after we have setuid to the user */
+diff -up openssh-5.8p2/session.c.force_krb openssh-5.8p2/session.c
+--- openssh-5.8p2/session.c.force_krb	2011-05-19 03:41:41.000000000 +0200
++++ openssh-5.8p2/session.c	2011-05-19 03:43:32.437173662 +0200
+@@ -816,6 +816,29 @@ do_exec(Session *s, const char *command)
+ 		debug("Forced command (key option) '%.900s'", command);
+ 	}
+ 
++#ifdef GSSAPI
++#ifdef KRB5 /* k5users_allowed_cmds only available w/ GSSAPI+KRB5 */
++	else if (k5users_allowed_cmds) {
++		const char *match = command;
++		int allowed = 0, i = 0;
++ 
++		if (!match)
++			match = s->pw->pw_shell;
++		while (k5users_allowed_cmds[i]) {
++			if (strcmp(match, k5users_allowed_cmds[i++]) == 0) {
++				debug("Allowed command '%.900s'", match);
++				allowed = 1;
++				break;
++			}
++		}
++		if (!allowed) {
++			debug("command '%.900s' not allowed", match);
++			return 1;
++		}
++	}
++#endif
++#endif
++
+ #ifdef SSH_AUDIT_EVENTS
+ 	if (s->command != NULL || s->command_handle != -1)
+ 		fatal("do_exec: command already set");
+diff -up openssh-5.8p2/sshd.8.force_krb openssh-5.8p2/sshd.8
+--- openssh-5.8p2/sshd.8.force_krb	2011-05-19 03:41:30.582114401 +0200
++++ openssh-5.8p2/sshd.8	2011-05-19 03:41:46.159106308 +0200
+@@ -320,6 +320,7 @@ Finally, the server and the client enter
+ The client tries to authenticate itself using
+ host-based authentication,
+ public key authentication,
++GSSAPI authentication,
+ challenge-response authentication,
+ or password authentication.
+ .Pp
+@@ -788,6 +789,12 @@ This file is used in exactly the same wa
+ but allows host-based authentication without permitting login with
+ rlogin/rsh.
+ .Pp
++.It Pa ~/.k5login
++.It Pa ~/.k5users
++These files enforce GSSAPI/Kerberos authentication access control.
++Further details are described in
++.Xr ksu 1 .
++.Pp
+ .It Pa ~/.ssh/
+ This directory is the default location for all user-specific configuration
+ and authentication information.
+diff -up openssh-5.8p2/ssh-gss.h.force_krb openssh-5.8p2/ssh-gss.h
+--- openssh-5.8p2/ssh-gss.h.force_krb	2007-06-12 15:40:39.000000000 +0200
++++ openssh-5.8p2/ssh-gss.h	2011-05-19 03:41:46.302234118 +0200
+@@ -48,6 +48,10 @@
+ #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+ #endif /* GSS_C_NT_... */
+ #endif /* !HEIMDAL */
++
++/* .k5users support */
++extern char **k5users_allowed_cmds;
++
+ #endif /* KRB5 */
+ 
+ /* draft-ietf-secsh-gsskeyex-06 */
diff --git a/openssh-5.8p2-remove-stale-control-socket.patch b/openssh-5.8p2-remove-stale-control-socket.patch
new file mode 100644
index 0000000..4a25d9e
--- /dev/null
+++ b/openssh-5.8p2-remove-stale-control-socket.patch
@@ -0,0 +1,13 @@
+diff -up openssh-5.8p2/mux.c.remove_stale openssh-5.8p2/mux.c
+--- openssh-5.8p2/mux.c.remove_stale	2011-01-14 02:01:32.000000000 +0100
++++ openssh-5.8p2/mux.c	2011-06-09 15:27:42.556360291 +0200
+@@ -1867,6 +1867,9 @@ muxclient(const char *path)
+ 			unlink(path);
+ 		} else if (errno == ENOENT) {
+ 			debug("Control socket \"%.100s\" does not exist", path);
++		} else if (errno == ECONNREFUSED) {
++			debug("Removing stale control socket \"%.100s\"", path);
++			unlink(path);
+ 		} else {
+ 			error("Control socket connect(%.100s): %s", path,
+ 			    strerror(errno));
diff --git a/openssh-5.8p2-sigpipe.patch b/openssh-5.8p2-sigpipe.patch
new file mode 100644
index 0000000..56af045
--- /dev/null
+++ b/openssh-5.8p2-sigpipe.patch
@@ -0,0 +1,12 @@
+diff -up openssh-5.8p2/ssh-keyscan.c.sigpipe openssh-5.8p2/ssh-keyscan.c
+--- openssh-5.8p2/ssh-keyscan.c.sigpipe	2011-08-23 18:30:33.873025916 +0200
++++ openssh-5.8p2/ssh-keyscan.c	2011-08-23 18:32:24.574025362 +0200
+@@ -715,6 +715,8 @@ main(int argc, char **argv)
+ 		fdlim_set(maxfd);
+ 	fdcon = xcalloc(maxfd, sizeof(con));
+ 
++	signal(SIGPIPE, SIG_IGN);
++
+ 	read_wait_nfdset = howmany(maxfd, NFDBITS);
+ 	read_wait = xcalloc(read_wait_nfdset, sizeof(fd_mask));
+ 
diff --git a/openssh-5.8p2-unblock-signals.patch b/openssh-5.8p2-unblock-signals.patch
new file mode 100644
index 0000000..2529855
--- /dev/null
+++ b/openssh-5.8p2-unblock-signals.patch
@@ -0,0 +1,76 @@
+diff -ur openssh-5.8p2.orig/gss-serv-gsi.c openssh-5.8p2/gss-serv-gsi.c
+--- openssh-5.8p2.orig/gss-serv-gsi.c	2011-08-17 08:59:16.374913940 +0200
++++ openssh-5.8p2/gss-serv-gsi.c	2011-08-17 09:00:01.577915218 +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.8p2.orig/ssh-globus-usage.c openssh-5.8p2/ssh-globus-usage.c
+--- openssh-5.8p2.orig/ssh-globus-usage.c	2011-08-17 08:59:16.402913941 +0200
++++ openssh-5.8p2/ssh-globus-usage.c	2011-08-17 09:00:01.578915209 +0200
+@@ -62,6 +62,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)
+ {
+@@ -77,6 +93,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 STATS module");
diff --git a/openssh-5.9p1-2auth.patch b/openssh-5.9p1-2auth.patch
new file mode 100644
index 0000000..b19d2ac
--- /dev/null
+++ b/openssh-5.9p1-2auth.patch
@@ -0,0 +1,354 @@
+diff -up openssh-5.9p1/auth.h.2auth openssh-5.9p1/auth.h
+--- openssh-5.9p1/auth.h.2auth	2011-05-29 13:39:38.000000000 +0200
++++ openssh-5.9p1/auth.h	2011-09-17 11:36:54.314522599 +0200
+@@ -149,6 +149,8 @@ int	auth_root_allowed(char *);
+ 
+ char	*auth2_read_banner(void);
+ 
++void	userauth_restart(const char *);
++
+ void	privsep_challenge_enable(void);
+ 
+ int	auth2_challenge(Authctxt *, char *);
+diff -up openssh-5.9p1/auth2.c.2auth openssh-5.9p1/auth2.c
+--- openssh-5.9p1/auth2.c.2auth	2011-05-05 06:04:11.000000000 +0200
++++ openssh-5.9p1/auth2.c	2011-09-17 11:36:54.402521709 +0200
+@@ -290,6 +290,24 @@ input_userauth_request(int type, u_int32
+ }
+ 
+ void
++userauth_restart(const char *method)
++{
++	options.two_factor_authentication = 0;
++
++	debug2("userauth restart, method = %s", method);
++	options.pubkey_authentication = options.second_pubkey_authentication && strcmp(method, method_pubkey.name);
++#ifdef GSSAPI
++	options.gss_authentication = options.second_gss_authentication && strcmp(method, method_gssapi.name);
++#endif
++#ifdef JPAKE
++	options.zero_knowledge_password_authentication = options.second_zero_knowledge_password_authentication && strcmp(method, method_jpake.name);
++#endif
++	options.password_authentication = options.second_password_authentication && strcmp(method, method_passwd.name);
++	options.kbd_interactive_authentication = options.second_kbd_interactive_authentication && strcmp(method, method_kbdint.name);
++	options.hostbased_authentication = options.second_hostbased_authentication && strcmp(method, method_hostbased.name);
++}
++
++void
+ userauth_finish(Authctxt *authctxt, int authenticated, char *method)
+ {
+ 	char *methods;
+@@ -337,6 +355,12 @@ userauth_finish(Authctxt *authctxt, int
+ 
+ 	/* XXX todo: check if multiple auth methods are needed */
+ 	if (authenticated == 1) {
++		if (options.two_factor_authentication) {
++			userauth_restart(method);
++			debug("1st factor authentication done go to 2nd factor");
++			goto ask_methods;
++		}
++
+ 		/* turn off userauth */
+ 		dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
+ 		packet_start(SSH2_MSG_USERAUTH_SUCCESS);
+@@ -356,7 +380,9 @@ userauth_finish(Authctxt *authctxt, int
+ #endif
+ 			packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
+ 		}
++ask_methods:
+ 		methods = authmethods_get();
++		debug2("next auth methods = %s", methods);
+ 		packet_start(SSH2_MSG_USERAUTH_FAILURE);
+ 		packet_put_cstring(methods);
+ 		packet_put_char(0);	/* XXX partial success, unused */
+diff -up openssh-5.9p1/monitor.c.2auth openssh-5.9p1/monitor.c
+--- openssh-5.9p1/monitor.c.2auth	2011-08-05 22:15:18.000000000 +0200
++++ openssh-5.9p1/monitor.c	2011-09-17 11:36:54.513491937 +0200
+@@ -417,6 +417,10 @@ monitor_child_preauth(Authctxt *_authctx
+ 			}
+ 		}
+ #endif
++		if (authenticated && options.two_factor_authentication) {
++			userauth_restart(auth_method);
++			authenticated = 0;
++		}
+ 	}
+ 
+ 	/* Drain any buffered messages from the child */
+diff -up openssh-5.9p1/servconf.c.2auth openssh-5.9p1/servconf.c
+--- openssh-5.9p1/servconf.c.2auth	2011-06-23 00:30:03.000000000 +0200
++++ openssh-5.9p1/servconf.c	2011-09-17 11:36:54.632461730 +0200
+@@ -92,6 +92,13 @@ initialize_server_options(ServerOptions
+ 	options->hostbased_uses_name_from_packet_only = -1;
+ 	options->rsa_authentication = -1;
+ 	options->pubkey_authentication = -1;
++	options->two_factor_authentication = -1;
++	options->second_pubkey_authentication = -1;
++	options->second_gss_authentication = -1;
++	options->second_password_authentication = -1;
++	options->second_kbd_interactive_authentication = -1;
++	options->second_zero_knowledge_password_authentication = -1;
++	options->second_hostbased_authentication = -1;
+ 	options->kerberos_authentication = -1;
+ 	options->kerberos_or_local_passwd = -1;
+ 	options->kerberos_ticket_cleanup = -1;
+@@ -237,6 +244,20 @@ fill_default_server_options(ServerOption
+ 		options->permit_empty_passwd = 0;
+ 	if (options->permit_user_env == -1)
+ 		options->permit_user_env = 0;
++	if (options->two_factor_authentication == -1)
++		options->two_factor_authentication = 0;
++	if (options->second_pubkey_authentication == -1)
++		options->second_pubkey_authentication = 1;
++	if (options->second_gss_authentication == -1)
++		options->second_gss_authentication = 0;
++	if (options->second_password_authentication == -1)
++		options->second_password_authentication = 1;
++	if (options->second_kbd_interactive_authentication == -1)
++		options->second_kbd_interactive_authentication = 0;
++	if (options->second_zero_knowledge_password_authentication == -1)
++		options->second_zero_knowledge_password_authentication = 0;
++	if (options->second_hostbased_authentication == -1)
++		options->second_hostbased_authentication = 0;
+ 	if (options->use_login == -1)
+ 		options->use_login = 0;
+ 	if (options->compression == -1)
+@@ -316,8 +337,11 @@ typedef enum {
+ 	sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
+ 	sMaxStartups, sMaxAuthTries, sMaxSessions,
+ 	sBanner, sUseDNS, sHostbasedAuthentication,
+-	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
+-	sClientAliveCountMax, sAuthorizedKeysFile,
++	sHostbasedUsesNameFromPacketOnly, sTwoFactorAuthentication,
++	sSecondPubkeyAuthentication, sSecondGssAuthentication,
++	sSecondPasswordAuthentication, sSecondKbdInteractiveAuthentication,
++	sSecondZeroKnowledgePasswordAuthentication, sSecondHostbasedAuthentication,
++	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
+ 	sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
+ 	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
+ 	sUsePrivilegeSeparation, sAllowAgentForwarding,
+@@ -395,6 +419,21 @@ static struct {
+ #else
+ 	{ "zeroknowledgepasswordauthentication", sUnsupported, SSHCFG_ALL },
+ #endif
++	{ "twofactorauthentication", sTwoFactorAuthentication, SSHCFG_ALL },
++	{ "secondpubkeyauthentication", sSecondPubkeyAuthentication, SSHCFG_ALL },
++#ifdef GSSAPI
++	{ "secondgssapiauthentication", sSecondGssAuthentication, SSHCFG_ALL },
++#else
++	{ "secondgssapiauthentication", sUnsupported, SSHCFG_ALL },
++#endif
++	{ "secondpasswordauthentication", sSecondPasswordAuthentication, SSHCFG_ALL },
++	{ "secondkbdinteractiveauthentication", sSecondKbdInteractiveAuthentication, SSHCFG_ALL },
++#ifdef JPAKE
++	{ "secondzeroknowledgepasswordauthentication", sSecondZeroKnowledgePasswordAuthentication, SSHCFG_ALL },
++#else
++	{ "secondzeroknowledgepasswordauthentication", sUnsupported, SSHCFG_ALL },
++#endif
++	{ "secondhostbasedauthentication", sSecondHostbasedAuthentication, SSHCFG_ALL },
+ 	{ "checkmail", sDeprecated, SSHCFG_GLOBAL },
+ 	{ "listenaddress", sListenAddress, SSHCFG_GLOBAL },
+ 	{ "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
+@@ -982,6 +1021,34 @@ process_server_config_line(ServerOptions
+ 		intptr = &options->challenge_response_authentication;
+ 		goto parse_flag;
+ 
++	case sTwoFactorAuthentication:
++		intptr = &options->two_factor_authentication;
++		goto parse_flag;
++
++	case sSecondPubkeyAuthentication:
++		intptr = &options->second_pubkey_authentication;
++		goto parse_flag;
++
++	case sSecondGssAuthentication:
++		intptr = &options->second_gss_authentication;
++		goto parse_flag;
++
++	case sSecondPasswordAuthentication:
++		intptr = &options->second_password_authentication;
++		goto parse_flag;
++
++	case sSecondKbdInteractiveAuthentication:
++		intptr = &options->second_kbd_interactive_authentication;
++		goto parse_flag;
++
++	case sSecondZeroKnowledgePasswordAuthentication:
++		intptr = &options->second_zero_knowledge_password_authentication;
++		goto parse_flag;
++
++	case sSecondHostbasedAuthentication:
++		intptr = &options->second_hostbased_authentication;
++		goto parse_flag;
++
+ 	case sPrintMotd:
+ 		intptr = &options->print_motd;
+ 		goto parse_flag;
+@@ -1491,14 +1558,21 @@ void
+ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
+ {
+ 	M_CP_INTOPT(password_authentication);
++	M_CP_INTOPT(second_password_authentication);
+ 	M_CP_INTOPT(gss_authentication);
++	M_CP_INTOPT(second_gss_authentication);
+ 	M_CP_INTOPT(rsa_authentication);
+ 	M_CP_INTOPT(pubkey_authentication);
++	M_CP_INTOPT(second_pubkey_authentication);
+ 	M_CP_INTOPT(kerberos_authentication);
+ 	M_CP_INTOPT(hostbased_authentication);
++	M_CP_INTOPT(second_hostbased_authentication);
+ 	M_CP_INTOPT(hostbased_uses_name_from_packet_only);
+ 	M_CP_INTOPT(kbd_interactive_authentication);
++	M_CP_INTOPT(second_kbd_interactive_authentication);
+ 	M_CP_INTOPT(zero_knowledge_password_authentication);
++	M_CP_INTOPT(second_zero_knowledge_password_authentication);
++	M_CP_INTOPT(two_factor_authentication);
+ 	M_CP_INTOPT(permit_root_login);
+ 	M_CP_INTOPT(permit_empty_passwd);
+ 
+@@ -1720,17 +1794,24 @@ dump_config(ServerOptions *o)
+ #endif
+ #ifdef GSSAPI
+ 	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
++	dump_cfg_fmtint(sSecondGssAuthentication, o->second_gss_authentication);
+ 	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
+ #endif
+ #ifdef JPAKE
+ 	dump_cfg_fmtint(sZeroKnowledgePasswordAuthentication,
+ 	    o->zero_knowledge_password_authentication);
++	dump_cfg_fmtint(sSecondZeroKnowledgePasswordAuthentication,
++	    o->second_zero_knowledge_password_authentication);
+ #endif
+ 	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
++	dump_cfg_fmtint(sSecondPasswordAuthentication, o->second_password_authentication);
+ 	dump_cfg_fmtint(sKbdInteractiveAuthentication,
+ 	    o->kbd_interactive_authentication);
++	dump_cfg_fmtint(sSecondKbdInteractiveAuthentication,
++	    o->second_kbd_interactive_authentication);
+ 	dump_cfg_fmtint(sChallengeResponseAuthentication,
+ 	    o->challenge_response_authentication);
++	dump_cfg_fmtint(sTwoFactorAuthentication, o->two_factor_authentication);
+ 	dump_cfg_fmtint(sPrintMotd, o->print_motd);
+ 	dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
+ 	dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
+diff -up openssh-5.9p1/servconf.h.2auth openssh-5.9p1/servconf.h
+--- openssh-5.9p1/servconf.h.2auth	2011-06-23 00:30:03.000000000 +0200
++++ openssh-5.9p1/servconf.h	2011-09-17 11:36:54.749584245 +0200
+@@ -112,6 +112,14 @@ typedef struct {
+ 					/* If true, permit jpake auth */
+ 	int     permit_empty_passwd;	/* If false, do not permit empty
+ 					 * passwords. */
++	int	two_factor_authentication;	/* If true, the first sucessful authentication
++					 * will be followed by the second one from anorher set */
++	int	second_pubkey_authentication;	/* second set of authentications */
++	int	second_gss_authentication;
++	int	second_password_authentication;
++	int	second_kbd_interactive_authentication;
++	int	second_zero_knowledge_password_authentication;
++	int	second_hostbased_authentication;
+ 	int     permit_user_env;	/* If true, read ~/.ssh/environment */
+ 	int     use_login;	/* If true, login(1) is used */
+ 	int     compression;	/* If true, compression is allowed */
+diff -up openssh-5.9p1/sshd_config.2auth openssh-5.9p1/sshd_config
+--- openssh-5.9p1/sshd_config.2auth	2011-05-29 13:39:39.000000000 +0200
++++ openssh-5.9p1/sshd_config	2011-09-17 11:36:54.859588726 +0200
+@@ -87,6 +87,13 @@ AuthorizedKeysFile	.ssh/authorized_keys
+ # and ChallengeResponseAuthentication to 'no'.
+ #UsePAM no
+ 
++#TwoFactorAuthentication no
++#SecondPubkeyAuthentication yes
++#SecondHostbasedAuthentication no
++#SecondPasswordAuthentication yes
++#SecondKBDInteractiveAuthentication yes
++#SecondGSSAPIAuthentication no
++
+ #AllowAgentForwarding yes
+ #AllowTcpForwarding yes
+ #GatewayPorts no
+diff -up openssh-5.9p1/sshd_config.5.2auth openssh-5.9p1/sshd_config.5
+--- openssh-5.9p1/sshd_config.5.2auth	2011-08-05 22:17:33.000000000 +0200
++++ openssh-5.9p1/sshd_config.5	2011-09-17 13:45:49.022521436 +0200
+@@ -726,6 +726,12 @@ Available keywords are
+ .Cm PubkeyAuthentication ,
+ .Cm RhostsRSAAuthentication ,
+ .Cm RSAAuthentication ,
++.Cm SecondGSSAPIAuthentication ,
++.Cm SecondHostbasedAuthentication ,
++.Cm SecondKbdInteractiveAuthentication ,
++.Cm SecondPasswordAuthentication ,
++.Cm SecondPubkeyAuthentication ,
++.Cm TwoFactorAuthentication ,
+ .Cm X11DisplayOffset ,
+ .Cm X11Forwarding
+ and
+@@ -931,6 +937,45 @@ Specifies whether pure RSA authenticatio
+ The default is
+ .Dq yes .
+ This option applies to protocol version 1 only.
++.It Cm SecondGSSAPIAuthentication
++Specifies whether the
++.Cm GSSAPIAuthentication
++may be used on the second authentication while
++.Cm TwoFactorAuthentication
++is set.
++The default is
++.Dq no .
++.It Cm SecondHostbasedAuthentication
++Specifies whether the
++.Cm HostbasedAuthentication
++may be used on the second authentication while
++.Cm TwoFactorAuthentication
++is set.
++The default is
++.Dq no .
++.It Cm SecondKbdInteractiveAuthentication
++Specifies whether the
++.Cm KbdInteractiveAuthentication
++may be used on the second authentication while
++.Cm TwoFactorAuthentication
++is set.
++The default is
++.Dq yes .
++.It Cm SecondPasswordAuthentication
++Specifies whether the
++.Cm PasswordAuthentication
++may be used on the second authentication while
++.Cm TwoFactorAuthentication
++is set.
++The default is
++.Dq yes .
++Specifies whether the
++.Cm PubkeyAuthentication
++may be used on the second authentication while
++.Cm TwoFactorAuthentication
++is set.
++The default is
++.Dq yes .
+ .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.
+@@ -1011,6 +1056,23 @@ For more details on certificates, see th
+ .Sx CERTIFICATES
+ section in
+ .Xr ssh-keygen 1 .
++.It Cm TwoFactorAuthentication
++Specifies whether for a successful login is necessary to meet two independent authentications.
++If select the first method is selected from the set of allowed methods from
++.Cm GSSAPIAuthentication ,
++.Cm HostbasedAuthentication ,
++.Cm KbdInteractiveAuthentication ,
++.Cm PasswordAuthentication ,
++.Cm PubkeyAuthentication .
++And the second method is selected from the set of allowed methods from
++.Cm SecondGSSAPIAuthentication ,
++.Cm SecondHostbasedAuthentication ,
++.Cm SecondKbdInteractiveAuthentication ,
++.Cm SecondPasswordAuthentication ,
++.Cm SecondPubkeyAuthentication 
++without the method used for the first authentication.
++The default is
++.Dq no .
+ .It Cm UseDNS
+ Specifies whether
+ .Xr sshd 8
diff --git a/openssh-5.9p1-akc.patch b/openssh-5.9p1-akc.patch
new file mode 100644
index 0000000..62a478b
--- /dev/null
+++ b/openssh-5.9p1-akc.patch
@@ -0,0 +1,452 @@
+diff -up openssh-5.9p1/auth2-pubkey.c.akc openssh-5.9p1/auth2-pubkey.c
+--- openssh-5.9p1/auth2-pubkey.c.akc	2011-09-14 07:24:40.876512251 +0200
++++ openssh-5.9p1/auth2-pubkey.c	2011-09-14 07:24:43.318458515 +0200
+@@ -27,6 +27,7 @@
+ 
+ #include <sys/types.h>
+ #include <sys/stat.h>
++#include <sys/wait.h>
+ 
+ #include <fcntl.h>
+ #include <pwd.h>
+@@ -276,27 +277,15 @@ match_principals_file(char *file, struct
+ 
+ /* 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];
+ 	const char *reason;
+ 	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_is_cert(key) ? KEY_UNSPEC : key->type);
+ 
+@@ -389,8 +378,6 @@ user_key_allowed2(struct passwd *pw, Key
+ 			break;
+ 		}
+ 	}
+-	restore_uid();
+-	fclose(f);
+ 	key_free(found);
+ 	if (!found_key)
+ 		debug2("key not found");
+@@ -452,13 +439,191 @@ user_cert_trusted_ca(struct passwd *pw,
+ 	return ret;
+ }
+ 
+-/* 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 0;
++
++	/* 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)
+ {
+ 	u_int success, i;
+ 	char *file;
+ 
++#ifdef WITH_AUTHORIZED_KEYS_COMMAND
++	success = user_key_via_command_allowed2(pw, key);
++	if (success > 0)
++		return success;
++#endif
++
+ 	if (auth_key_is_revoked(key))
+ 		return 0;
+ 	if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
+diff -up openssh-5.9p1/configure.ac.akc openssh-5.9p1/configure.ac
+--- openssh-5.9p1/configure.ac.akc	2011-09-14 07:24:42.863494886 +0200
++++ openssh-5.9p1/configure.ac	2011-09-14 07:24:43.441583848 +0200
+@@ -1421,6 +1421,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 \
+@@ -4239,6 +4251,7 @@ echo "                   SELinux 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.9p1/servconf.c.akc openssh-5.9p1/servconf.c
+--- openssh-5.9p1/servconf.c.akc	2011-09-14 07:24:29.402475399 +0200
++++ openssh-5.9p1/servconf.c	2011-09-14 07:56:27.158585590 +0200
+@@ -139,6 +139,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;
+ 	options->revoked_keys_file = NULL;
+ 	options->trusted_user_ca_keys = NULL;
+@@ -348,6 +350,7 @@ typedef enum {
+ 	sZeroKnowledgePasswordAuthentication, sHostCertificate,
+ 	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
+ 	sKexAlgorithms, sIPQoS,
++	sAuthorizedKeysCommand, sAuthorizedKeysCommandRunAs,
+ 	sDeprecated, sUnsupported
+ } ServerOpCodes;
+ 
+@@ -487,6 +490,13 @@ static struct {
+ 	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
+ 	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
+ 	{ "ipqos", sIPQoS, 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 }
+ };
+ 
+@@ -1462,6 +1472,24 @@ process_server_config_line(ServerOptions
+ 		}
+ 		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 (!arg || *arg == '\0')
++			fatal("%s line %d: missing account.",
++			    filename, linenum);
++
++		if (*activep && *charptr == NULL)
++			*charptr = xstrdup(arg);
++		break;
++
+ 	case sDeprecated:
+ 		logit("%s line %d: Deprecated option %s",
+ 		    filename, linenum, arg);
+@@ -1573,6 +1601,8 @@ copy_set_server_options(ServerOptions *d
+ 	M_CP_INTOPT(zero_knowledge_password_authentication);
+ 	M_CP_INTOPT(second_zero_knowledge_password_authentication);
+ 	M_CP_INTOPT(two_factor_authentication);
++	M_CP_STROPT(authorized_keys_command);
++	M_CP_STROPT(authorized_keys_command_runas);
+ 	M_CP_INTOPT(permit_root_login);
+ 	M_CP_INTOPT(permit_empty_passwd);
+ 
+@@ -1839,6 +1869,8 @@ dump_config(ServerOptions *o)
+ 	dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
+ 	dump_cfg_string(sAuthorizedPrincipalsFile,
+ 	    o->authorized_principals_file);
++	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.9p1/servconf.h.akc openssh-5.9p1/servconf.h
+--- openssh-5.9p1/servconf.h.akc	2011-09-14 07:24:29.511480441 +0200
++++ openssh-5.9p1/servconf.h	2011-09-14 07:24:43.678459183 +0200
+@@ -174,6 +174,8 @@ typedef struct {
+ 	char   *revoked_keys_file;
+ 	char   *trusted_user_ca_keys;
+ 	char   *authorized_principals_file;
++	char   *authorized_keys_command;
++	char   *authorized_keys_command_runas;
+ }       ServerOptions;
+ 
+ /*
+diff -up openssh-5.9p1/sshd_config.0.akc openssh-5.9p1/sshd_config.0
+--- openssh-5.9p1/sshd_config.0.akc	2011-09-07 01:16:30.000000000 +0200
++++ openssh-5.9p1/sshd_config.0	2011-09-14 07:24:43.791460201 +0200
+@@ -71,6 +71,23 @@ DESCRIPTION
+ 
+              See PATTERNS in ssh_config(5) for more information on patterns.
+ 
++     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.
++
+      AuthorizedKeysFile
+              Specifies the file that contains the public keys that can be used
+              for user authentication.  The format is described in the
+@@ -401,7 +418,8 @@ DESCRIPTION
+ 
+              Only a subset of keywords may be used on the lines following a
+              Match keyword.  Available keywords are AllowAgentForwarding,
+-             AllowTcpForwarding, AuthorizedKeysFile, AuthorizedPrincipalsFile,
++             AllowTcpForwarding, AuthorizedKeysFile, AuthorizedKeysCommand,
++             AuthorizedKeysCommandRunAs, AuthorizedPrincipalsFile,
+              Banner, ChrootDirectory, ForceCommand, GatewayPorts,
+              GSSAPIAuthentication, HostbasedAuthentication,
+              HostbasedUsesNameFromPacketOnly, KbdInteractiveAuthentication,
+diff -up openssh-5.9p1/sshd_config.5.akc openssh-5.9p1/sshd_config.5
+--- openssh-5.9p1/sshd_config.5.akc	2011-09-14 07:24:29.793520372 +0200
++++ openssh-5.9p1/sshd_config.5	2011-09-14 07:24:43.912583678 +0200
+@@ -706,6 +706,8 @@ Available keywords are
+ .Cm AllowAgentForwarding ,
+ .Cm AllowTcpForwarding ,
+ .Cm AuthorizedKeysFile ,
++.Cm AuthorizedKeysCommand ,
++.Cm AuthorizedKeysCommandRunAs ,
+ .Cm AuthorizedPrincipalsFile ,
+ .Cm Banner ,
+ .Cm ChrootDirectory ,
+@@ -718,6 +720,7 @@ Available keywords are
+ .Cm KerberosAuthentication ,
+ .Cm MaxAuthTries ,
+ .Cm MaxSessions ,
++.Cm PubkeyAuthentication ,
+ .Cm PasswordAuthentication ,
+ .Cm PermitEmptyPasswords ,
+ .Cm PermitOpen ,
+@@ -926,6 +929,20 @@ Specifies a list of revoked public keys.
+ Keys listed in this file will be refused for public key authentication.
+ Note that if this file is not readable, then public key authentication will
+ be refused for all users.
++.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.9p1/sshd_config.akc openssh-5.9p1/sshd_config
+--- openssh-5.9p1/sshd_config.akc	2011-09-14 07:24:29.620461608 +0200
++++ openssh-5.9p1/sshd_config	2011-09-14 07:24:44.034462546 +0200
+@@ -49,6 +49,9 @@
+ # but this is overridden so installations will only check .ssh/authorized_keys
+ 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
+ # similar for protocol version 2
diff --git a/openssh-5.9p1-audit1.patch b/openssh-5.9p1-audit1.patch
new file mode 100644
index 0000000..7a71332
--- /dev/null
+++ b/openssh-5.9p1-audit1.patch
@@ -0,0 +1,641 @@
+diff -up openssh-5.9p0/audit-bsm.c.audit1 openssh-5.9p0/audit-bsm.c
+--- openssh-5.9p0/audit-bsm.c.audit1	2011-01-17 11:15:29.000000000 +0100
++++ openssh-5.9p0/audit-bsm.c	2011-08-30 10:46:57.704148875 +0200
+@@ -298,10 +298,23 @@ audit_connection_from(const char *host,
+ #endif
+ }
+ 
+-void
++int
+ audit_run_command(const char *command)
+ {
+ 	/* not implemented */
++	return 0;
++}
++
++void
++audit_end_command(int handle, const char *command)
++{
++	/* not implemented */
++}
++
++void
++audit_count_session_open(void)
++{
++	/* not necessary */
+ }
+ 
+ void
+diff -up openssh-5.9p0/audit-linux.c.audit1 openssh-5.9p0/audit-linux.c
+--- openssh-5.9p0/audit-linux.c.audit1	2011-01-17 11:15:30.000000000 +0100
++++ openssh-5.9p0/audit-linux.c	2011-08-30 10:46:58.059024733 +0200
+@@ -35,13 +35,20 @@
+ 
+ #include "log.h"
+ #include "audit.h"
++#include "key.h"
++#include "hostfile.h"
++#include "auth.h"
++#include "servconf.h"
+ #include "canohost.h"
+ 
++extern ServerOptions options;
++extern Authctxt *the_authctxt;
++extern u_int utmp_len;
+ const char* audit_username(void);
+ 
+-int
+-linux_audit_record_event(int uid, const char *username,
+-    const char *hostname, const char *ip, const char *ttyn, int success)
++static void
++linux_audit_user_logxxx(int uid, const char *username,
++    const char *hostname, const char *ip, const char *ttyn, int success, int event)
+ {
+ 	int audit_fd, rc, saved_errno;
+ 
+@@ -49,11 +56,11 @@ linux_audit_record_event(int uid, const
+ 	if (audit_fd < 0) {
+ 		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
+ 		    errno == EAFNOSUPPORT)
+-			return 1; /* No audit support in kernel */
++			return; /* No audit support in kernel */
+ 		else
+-			return 0; /* Must prevent login */
++			goto fatal_report; /* Must prevent login */
+ 	}
+-	rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN,
++	rc = audit_log_acct_message(audit_fd, event,
+ 	    NULL, "login", username ? username : "(unknown)",
+ 	    username == NULL ? uid : -1, hostname, ip, ttyn, success);
+ 	saved_errno = errno;
+@@ -65,35 +72,119 @@ linux_audit_record_event(int uid, const
+ 	if ((rc == -EPERM) && (geteuid() != 0))
+ 		rc = 0;
+ 	errno = saved_errno;
+-	return (rc >= 0);
++	if (rc < 0) {
++fatal_report:
++		fatal("linux_audit_write_entry failed: %s", strerror(errno));
++	}
++}
++
++static void
++linux_audit_user_auth(int uid, const char *username,
++    const char *hostname, const char *ip, const char *ttyn, int success, int event)
++{
++	int audit_fd, rc, saved_errno;
++	static const char *event_name[] = {
++		"maxtries exceeded",
++		"root denied",
++		"success",
++		"none",
++		"password",
++		"challenge-response",
++		"pubkey",
++		"hostbased",
++		"gssapi",
++		"invalid user",
++		"nologin",
++		"connection closed",
++		"connection abandoned",
++		"unknown"
++	};
++
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
++		    errno == EAFNOSUPPORT)
++			return; /* No audit support in kernel */
++		else
++			goto fatal_report; /* Must prevent login */
++	}
++	
++	if ((event < 0) || (event > SSH_AUDIT_UNKNOWN))
++		event = SSH_AUDIT_UNKNOWN;
++
++	rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH,
++	    NULL, event_name[event], username ? username : "(unknown)",
++	    username == NULL ? uid : -1, hostname, ip, ttyn, success);
++	saved_errno = errno;
++	close(audit_fd);
++	/*
++	 * Do not report error if the error is EPERM and sshd is run as non
++	 * root user.
++	 */
++	if ((rc == -EPERM) && (geteuid() != 0))
++		rc = 0;
++	errno = saved_errno;
++	if (rc < 0) {
++fatal_report:
++		fatal("linux_audit_write_entry failed: %s", strerror(errno));
++	}
+ }
+ 
++static int user_login_count = 0;
++
+ /* Below is the sshd audit API code */
+ 
+ void
+ audit_connection_from(const char *host, int port)
+ {
+-}
+ 	/* not implemented */
++}
+ 
+-void
++int
+ audit_run_command(const char *command)
+ {
+-	/* not implemented */
++	if (!user_login_count++) 
++		linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++		    NULL, "ssh", 1, AUDIT_USER_LOGIN);
++	linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++	    NULL, "ssh", 1, AUDIT_USER_START);
++	return 0;
++}
++
++void
++audit_end_command(int handle, const char *command)
++{
++	linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++	    NULL, "ssh", 1, AUDIT_USER_END);
++	if (user_login_count && !--user_login_count) 
++		linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++		    NULL, "ssh", 1, AUDIT_USER_LOGOUT);
++}
++
++void
++audit_count_session_open(void)
++{
++	user_login_count++;
+ }
+ 
+ void
+ audit_session_open(struct logininfo *li)
+ {
+-	if (linux_audit_record_event(li->uid, NULL, li->hostname,
+-	    NULL, li->line, 1) == 0)
+-		fatal("linux_audit_write_entry failed: %s", strerror(errno));
++	if (!user_login_count++) 
++		linux_audit_user_logxxx(li->uid, NULL, li->hostname,
++		    NULL, li->line, 1, AUDIT_USER_LOGIN);
++	linux_audit_user_logxxx(li->uid, NULL, li->hostname,
++	    NULL, li->line, 1, AUDIT_USER_START);
+ }
+ 
+ void
+ audit_session_close(struct logininfo *li)
+ {
+-	/* not implemented */
++	linux_audit_user_logxxx(li->uid, NULL, li->hostname,
++	    NULL, li->line, 1, AUDIT_USER_END);
++	if (user_login_count && !--user_login_count) 
++		linux_audit_user_logxxx(li->uid, NULL, li->hostname,
++		    NULL, li->line, 1, AUDIT_USER_LOGOUT);
+ }
+ 
+ void
+@@ -101,21 +192,43 @@ audit_event(ssh_audit_event_t event)
+ {
+ 	switch(event) {
+ 	case SSH_AUTH_SUCCESS:
+-	case SSH_CONNECTION_CLOSE:
++		linux_audit_user_auth(-1, audit_username(), NULL,
++			get_remote_ipaddr(), "ssh", 1, event);
++		break;
++
+ 	case SSH_NOLOGIN:
+-	case SSH_LOGIN_EXCEED_MAXTRIES:
+ 	case SSH_LOGIN_ROOT_DENIED:
++		linux_audit_user_auth(-1, audit_username(), NULL,
++			get_remote_ipaddr(), "ssh", 0, event);
++		linux_audit_user_logxxx(-1, audit_username(), NULL,
++			get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN);
+ 		break;
+ 
++	case SSH_LOGIN_EXCEED_MAXTRIES:
+ 	case SSH_AUTH_FAIL_NONE:
+ 	case SSH_AUTH_FAIL_PASSWD:
+ 	case SSH_AUTH_FAIL_KBDINT:
+ 	case SSH_AUTH_FAIL_PUBKEY:
+ 	case SSH_AUTH_FAIL_HOSTBASED:
+ 	case SSH_AUTH_FAIL_GSSAPI:
++		linux_audit_user_auth(-1, audit_username(), NULL,
++			get_remote_ipaddr(), "ssh", 0, event);
++		break;
++
++	case SSH_CONNECTION_CLOSE:
++		if (user_login_count) {
++			while (user_login_count--)
++				linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++				    NULL, "ssh", 1, AUDIT_USER_END);
++			linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns),
++			    NULL, "ssh", 1, AUDIT_USER_LOGOUT);
++		}
++		break;
++
++	case SSH_CONNECTION_ABANDON:
+ 	case SSH_INVALID_USER:
+-		linux_audit_record_event(-1, audit_username(), NULL,
+-			get_remote_ipaddr(), "sshd", 0);
++		linux_audit_user_logxxx(-1, audit_username(), NULL,
++			get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN);
+ 		break;
+ 
+ 	default:
+diff -up openssh-5.9p0/audit.c.audit1 openssh-5.9p0/audit.c
+--- openssh-5.9p0/audit.c.audit1	2011-01-17 11:15:30.000000000 +0100
++++ openssh-5.9p0/audit.c	2011-08-30 10:46:57.822025769 +0200
+@@ -140,6 +140,17 @@ audit_event(ssh_audit_event_t event)
+ }
+ 
+ /*
++ * Called when a child process has called, or will soon call,
++ * audit_session_open.
++ */
++void
++audit_count_session_open(void)
++{
++	debug("audit count session open euid %d user %s", geteuid(),
++	      audit_username());
++}
++
++/*
+  * Called when a user session is started.  Argument is the tty allocated to
+  * the session, or NULL if no tty was allocated.
+  *
+@@ -174,13 +185,29 @@ audit_session_close(struct logininfo *li
+ /*
+  * This will be called when a user runs a non-interactive command.  Note that
+  * it may be called multiple times for a single connection since SSH2 allows
+- * multiple sessions within a single connection.
++ * multiple sessions within a single connection.  Returns a "handle" for
++ * audit_end_command.
+  */
+-void
++int
+ audit_run_command(const char *command)
+ {
+ 	debug("audit run command euid %d user %s command '%.200s'", geteuid(),
+ 	    audit_username(), command);
++	return 0;
++}
++
++/*
++ * This will be called when the non-interactive command finishes.  Note that
++ * it may be called multiple times for a single connection since SSH2 allows
++ * multiple sessions within a single connection.  "handle" should come from
++ * the corresponding audit_run_command.
++ */
++void
++audit_end_command(int handle, const char *command)
++{
++	debug("audit end nopty exec  euid %d user %s command '%.200s'", geteuid(),
++	    audit_username(), command);
+ }
++
+ # endif  /* !defined CUSTOM_SSH_AUDIT_EVENTS */
+ #endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-5.9p0/audit.h.audit1 openssh-5.9p0/audit.h
+--- openssh-5.9p0/audit.h.audit1	2011-01-17 11:15:30.000000000 +0100
++++ openssh-5.9p0/audit.h	2011-08-30 10:46:57.952035525 +0200
+@@ -49,9 +49,11 @@ typedef enum ssh_audit_event_type ssh_au
+ 
+ void	audit_connection_from(const char *, int);
+ void	audit_event(ssh_audit_event_t);
++void	audit_count_session_open(void);
+ void	audit_session_open(struct logininfo *);
+ void	audit_session_close(struct logininfo *);
+-void	audit_run_command(const char *);
++int	audit_run_command(const char *);
++void 	audit_end_command(int, const char *);
+ ssh_audit_event_t audit_classify_auth(const char *);
+ 
+ #endif /* _SSH_AUDIT_H */
+diff -up openssh-5.9p0/monitor.c.audit1 openssh-5.9p0/monitor.c
+--- openssh-5.9p0/monitor.c.audit1	2011-08-05 22:15:18.000000000 +0200
++++ openssh-5.9p0/monitor.c	2011-08-30 10:50:47.074038891 +0200
+@@ -185,6 +185,7 @@ int mm_answer_gss_checkmic(int, Buffer *
+ #ifdef SSH_AUDIT_EVENTS
+ int mm_answer_audit_event(int, Buffer *);
+ int mm_answer_audit_command(int, Buffer *);
++int mm_answer_audit_end_command(int, Buffer *);
+ #endif
+ 
+ static int monitor_read_log(struct monitor *);
+@@ -271,6 +272,7 @@ 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},
+ #endif
+     {0, 0, NULL}
+ };
+@@ -313,6 +315,7 @@ 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},
+ #endif
+     {0, 0, NULL}
+ };
+@@ -1398,6 +1401,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);
+ }
+ 
+@@ -1720,11 +1729,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);
+ }
+diff -up openssh-5.9p0/monitor.h.audit1 openssh-5.9p0/monitor.h
+--- openssh-5.9p0/monitor.h.audit1	2011-06-20 06:42:23.000000000 +0200
++++ openssh-5.9p0/monitor.h	2011-08-30 10:46:58.392112520 +0200
+@@ -60,6 +60,7 @@ 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,
+diff -up openssh-5.9p0/monitor_wrap.c.audit1 openssh-5.9p0/monitor_wrap.c
+--- openssh-5.9p0/monitor_wrap.c.audit1	2011-06-20 06:42:23.000000000 +0200
++++ openssh-5.9p0/monitor_wrap.c	2011-08-30 10:46:58.505031574 +0200
+@@ -1188,10 +1188,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);
+ 
+@@ -1199,6 +1200,26 @@ mm_audit_run_command(const char *command
+ 	buffer_put_cstring(&m, command);
+ 
+ 	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, &m);
++
++	handle = buffer_get_int(&m);
++	buffer_free(&m);
++
++	return (handle);
++}
++
++void
++mm_audit_end_command(int handle, const char *command)
++{
++	Buffer m;
++
++	debug3("%s entering command %s", __func__, command);
++
++	buffer_init(&m);
++	buffer_put_int(&m, handle);
++	buffer_put_cstring(&m, command);
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, &m);
+ 	buffer_free(&m);
+ }
+ #endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-5.9p0/monitor_wrap.h.audit1 openssh-5.9p0/monitor_wrap.h
+--- openssh-5.9p0/monitor_wrap.h.audit1	2011-06-20 06:42:23.000000000 +0200
++++ openssh-5.9p0/monitor_wrap.h	2011-08-30 10:46:58.616212835 +0200
+@@ -74,7 +74,8 @@ 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 *);
+ #endif
+ 
+ struct Session;
+diff -up openssh-5.9p0/session.c.audit1 openssh-5.9p0/session.c
+--- openssh-5.9p0/session.c.audit1	2011-05-20 03:23:10.000000000 +0200
++++ openssh-5.9p0/session.c	2011-08-30 10:46:58.756024849 +0200
+@@ -742,6 +742,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, 
+@@ -813,15 +821,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);
+@@ -1848,6 +1860,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;
+ }
+@@ -1930,6 +1943,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;
+@@ -2455,6 +2481,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)
+ {
+@@ -2463,6 +2513,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)
+@@ -2682,6 +2736,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)
+ {
+@@ -2730,5 +2793,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.9p0/session.h.audit1 openssh-5.9p0/session.h
+--- openssh-5.9p0/session.h.audit1	2008-05-19 07:34:50.000000000 +0200
++++ openssh-5.9p0/session.h	2011-08-30 10:46:58.884024597 +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.9p0/sshd.c.audit1 openssh-5.9p0/sshd.c
+--- openssh-5.9p0/sshd.c.audit1	2011-06-23 11:45:51.000000000 +0200
++++ openssh-5.9p0/sshd.c	2011-08-30 10:46:59.009025421 +0200
+@@ -2364,7 +2364,8 @@ cleanup_exit(int i)
+ 		do_cleanup(the_authctxt);
+ #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.9p1-audit2.patch b/openssh-5.9p1-audit2.patch
new file mode 100644
index 0000000..023563d
--- /dev/null
+++ b/openssh-5.9p1-audit2.patch
@@ -0,0 +1,353 @@
+diff -up openssh-5.9p0/audit-bsm.c.audit2 openssh-5.9p0/audit-bsm.c
+--- openssh-5.9p0/audit-bsm.c.audit2	2011-08-30 10:55:35.281025258 +0200
++++ openssh-5.9p0/audit-bsm.c	2011-08-30 10:55:37.500052231 +0200
+@@ -329,6 +329,12 @@ audit_session_close(struct logininfo *li
+ 	/* not implemented */
+ }
+ 
++int
++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv)
++{
++	/* not implemented */
++}
++
+ void
+ audit_event(ssh_audit_event_t event)
+ {
+diff -up openssh-5.9p0/audit-linux.c.audit2 openssh-5.9p0/audit-linux.c
+--- openssh-5.9p0/audit-linux.c.audit2	2011-08-30 10:55:35.385102905 +0200
++++ openssh-5.9p0/audit-linux.c	2011-08-30 10:55:38.009088040 +0200
+@@ -41,6 +41,8 @@
+ #include "servconf.h"
+ #include "canohost.h"
+ 
++#define AUDIT_LOG_SIZE 128
++
+ extern ServerOptions options;
+ extern Authctxt *the_authctxt;
+ extern u_int utmp_len;
+@@ -130,6 +132,37 @@ fatal_report:
+ 	}
+ }
+ 
++int
++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv)
++{
++	char buf[AUDIT_LOG_SIZE];
++	int audit_fd, rc, saved_errno;
++
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
++					 errno == EAFNOSUPPORT)
++			return 1; /* No audit support in kernel */
++		else                                                                                                                                       
++			return 0; /* Must prevent login */
++	}
++	snprintf(buf, sizeof(buf), "%s_auth rport=%d", host_user ? "pubkey" : "hostbased", get_remote_port());
++	rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
++		buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv);
++	if ((rc < 0) && ((rc != -1) || (getuid() == 0)))
++		goto out;
++	snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s%s rport=%d",
++			type, bits, key_fingerprint_prefix(), fp, get_remote_port());
++	rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
++		buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv);
++out:
++	saved_errno = errno;
++	audit_close(audit_fd);
++	errno = saved_errno;
++	/* do not report error if the error is EPERM and sshd is run as non root user */
++	return (rc >= 0) || ((rc == -EPERM) && (getuid() != 0));
++}
++
+ static int user_login_count = 0;
+ 
+ /* Below is the sshd audit API code */
+diff -up openssh-5.9p0/audit.c.audit2 openssh-5.9p0/audit.c
+--- openssh-5.9p0/audit.c.audit2	2011-08-30 10:55:35.523141273 +0200
++++ openssh-5.9p0/audit.c	2011-08-30 10:55:37.658024710 +0200
+@@ -36,6 +36,7 @@
+ #include "key.h"
+ #include "hostfile.h"
+ #include "auth.h"
++#include "xmalloc.h"
+ 
+ /*
+  * Care must be taken when using this since it WILL NOT be initialized when
+@@ -111,6 +112,22 @@ audit_event_lookup(ssh_audit_event_t ev)
+ 	return(event_lookup[i].name);
+ }
+ 
++void
++audit_key(int host_user, int *rv, const Key *key)
++{
++	char *fp;
++	const char *crypto_name;
++
++	fp = key_selected_fingerprint(key, SSH_FP_HEX);
++	if (key->type == KEY_RSA1)
++		crypto_name = "ssh-rsa1";
++	else
++		crypto_name = key_ssh_name(key);
++	if (audit_keyusage(host_user, crypto_name, key_size(key), fp, *rv) == 0)
++		*rv = 0;
++	xfree(fp);
++}
++
+ # ifndef CUSTOM_SSH_AUDIT_EVENTS
+ /*
+  * Null implementations of audit functions.
+@@ -209,5 +226,17 @@ audit_end_command(int handle, const char
+ 	    audit_username(), command);
+ }
+ 
++/*
++ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key.
++ *
++ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key.
++ */
++int
++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv)
++{
++	debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s%s, result %d", 
++		host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), type, bits,
++		key_fingerprint_prefix(), fp, rv);
++}
+ # endif  /* !defined CUSTOM_SSH_AUDIT_EVENTS */
+ #endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-5.9p0/audit.h.audit2 openssh-5.9p0/audit.h
+--- openssh-5.9p0/audit.h.audit2	2011-08-30 10:55:35.723122290 +0200
++++ openssh-5.9p0/audit.h	2011-08-30 10:55:37.905212176 +0200
+@@ -28,6 +28,7 @@
+ # define _SSH_AUDIT_H
+ 
+ #include "loginrec.h"
++#include "key.h"
+ 
+ enum ssh_audit_event_type {
+ 	SSH_LOGIN_EXCEED_MAXTRIES,
+@@ -55,5 +56,7 @@ void	audit_session_close(struct logininf
+ int	audit_run_command(const char *);
+ void 	audit_end_command(int, const char *);
+ ssh_audit_event_t audit_classify_auth(const char *);
++int	audit_keyusage(int, const char *, unsigned, char *, int);
++void	audit_key(int, int *, const Key *);
+ 
+ #endif /* _SSH_AUDIT_H */
+diff -up openssh-5.9p0/auth-rsa.c.audit2 openssh-5.9p0/auth-rsa.c
+--- openssh-5.9p0/auth-rsa.c.audit2	2011-08-30 10:55:33.120097071 +0200
++++ openssh-5.9p0/auth-rsa.c	2011-08-30 10:55:38.729025376 +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 (timingsafe_bcmp(response, mdbuf, 16) != 0) {
+-		/* Wrong answer. */
+-		return (0);
++	rv = timingsafe_bcmp(response, mdbuf, 16) == 0;
++
++#ifdef SSH_AUDIT_EVENTS
++	fp = key_selected_fingerprint(key, SSH_FP_HEX);
++	if (audit_keyusage(1, "ssh-rsa1", RSA_size(key->rsa) * 8, fp, rv) == 0) {
++		debug("unsuccessful audit");
++		rv = 0;
+ 	}
+-	/* Correct answer. */
+-	return (1);
++	xfree(fp);
++#endif
++
++	return rv;
+ }
+ 
+ /*
+diff -up openssh-5.9p0/auth.h.audit2 openssh-5.9p0/auth.h
+--- openssh-5.9p0/auth.h.audit2	2011-05-29 13:39:38.000000000 +0200
++++ openssh-5.9p0/auth.h	2011-08-30 10:57:43.238087347 +0200
+@@ -170,6 +170,7 @@ void	abandon_challenge_response(Authctxt
+ 
+ char	*expand_authorized_keys(const char *, struct passwd *pw);
+ char	*authorized_principals_file(struct passwd *);
++int	 user_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
+ 
+ FILE	*auth_openkeyfile(const char *, struct passwd *, int);
+ FILE	*auth_openprincipals(const char *, struct passwd *, int);
+@@ -185,6 +186,7 @@ Key	*get_hostkey_public_by_type(int);
+ Key	*get_hostkey_private_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.9p0/auth2-hostbased.c.audit2 openssh-5.9p0/auth2-hostbased.c
+--- openssh-5.9p0/auth2-hostbased.c.audit2	2011-08-30 10:55:32.696212587 +0200
++++ openssh-5.9p0/auth2-hostbased.c	2011-08-30 10:55:38.120068864 +0200
+@@ -119,7 +119,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;
+ 
+@@ -136,6 +136,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.9p0/auth2-pubkey.c.audit2 openssh-5.9p0/auth2-pubkey.c
+--- openssh-5.9p0/auth2-pubkey.c.audit2	2011-08-30 10:55:32.803126151 +0200
++++ openssh-5.9p0/auth2-pubkey.c	2011-08-30 10:55:38.426108672 +0200
+@@ -140,7 +140,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);
+@@ -177,6 +177,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;
++}
++
+ static int
+ match_principals_option(const char *principal_list, struct KeyCert *cert)
+ {
+diff -up openssh-5.9p0/monitor.c.audit2 openssh-5.9p0/monitor.c
+--- openssh-5.9p0/monitor.c.audit2	2011-08-30 10:55:35.849023496 +0200
++++ openssh-5.9p0/monitor.c	2011-08-30 10:55:38.848024600 +0200
+@@ -1318,9 +1318,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);
+@@ -1328,6 +1330,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)
+@@ -1348,7 +1352,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");
+ 
+diff -up openssh-5.9p0/monitor_wrap.c.audit2 openssh-5.9p0/monitor_wrap.c
+--- openssh-5.9p0/monitor_wrap.c.audit2	2011-08-30 10:55:36.431043533 +0200
++++ openssh-5.9p0/monitor_wrap.c	2011-08-30 10:55:39.074038187 +0200
+@@ -431,7 +431,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;
+@@ -445,6 +445,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);
+@@ -462,6 +463,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)
+diff -up openssh-5.9p0/monitor_wrap.h.audit2 openssh-5.9p0/monitor_wrap.h
+--- openssh-5.9p0/monitor_wrap.h.audit2	2011-08-30 10:55:36.550088263 +0200
++++ openssh-5.9p0/monitor_wrap.h	2011-08-30 10:55:39.282151179 +0200
+@@ -49,7 +49,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 *);
diff --git a/openssh-5.9p1-audit3.patch b/openssh-5.9p1-audit3.patch
new file mode 100644
index 0000000..da59660
--- /dev/null
+++ b/openssh-5.9p1-audit3.patch
@@ -0,0 +1,528 @@
+diff -up openssh-5.9p1/Makefile.in.audit3 openssh-5.9p1/Makefile.in
+--- openssh-5.9p1/Makefile.in.audit3	2011-08-05 22:15:18.000000000 +0200
++++ openssh-5.9p1/Makefile.in	2011-09-14 07:05:58.337520327 +0200
+@@ -71,7 +71,7 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o b
+ 	monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
+ 	kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \
+ 	msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o jpake.o \
+-	schnorr.o ssh-pkcs11.o
++	schnorr.o ssh-pkcs11.o auditstub.o
+ 
+ SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
+ 	sshconnect.o sshconnect1.o sshconnect2.o mux.o \
+diff -up openssh-5.9p1/audit-bsm.c.audit3 openssh-5.9p1/audit-bsm.c
+--- openssh-5.9p1/audit-bsm.c.audit3	2011-09-14 07:05:56.719459048 +0200
++++ openssh-5.9p1/audit-bsm.c	2011-09-14 07:05:58.430520147 +0200
+@@ -396,4 +396,16 @@ audit_event(ssh_audit_event_t event)
+ 		debug("%s: unhandled event %d", __func__, event);
+ 	}
+ }
++
++void
++audit_unsupported_body(int what)
++{
++	/* not implemented */
++}
++
++void
++audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, uid_t uid)
++{
++	/* not implemented */
++}
+ #endif /* BSM */
+diff -up openssh-5.9p1/audit-linux.c.audit3 openssh-5.9p1/audit-linux.c
+--- openssh-5.9p1/audit-linux.c.audit3	2011-09-14 07:05:56.820460613 +0200
++++ openssh-5.9p1/audit-linux.c	2011-09-14 07:07:29.651459660 +0200
+@@ -40,6 +40,8 @@
+ #include "auth.h"
+ #include "servconf.h"
+ #include "canohost.h"
++#include "packet.h"
++#include "cipher.h"
+ 
+ #define AUDIT_LOG_SIZE 128
+ 
+@@ -269,4 +271,60 @@ audit_event(ssh_audit_event_t event)
+ 	}
+ }
+ 
++void
++audit_unsupported_body(int what)
++{
++#ifdef AUDIT_CRYPTO_SESSION
++	char buf[AUDIT_LOG_SIZE];
++	const static char *name[] = { "cipher", "mac", "comp" };
++	char *s;
++	int audit_fd;
++
++	snprintf(buf, sizeof(buf), "op=unsupported-%s direction=? cipher=? ksize=? rport=%d laddr=%s lport=%d ",
++		name[what], get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())),
++		get_local_port());
++	xfree(s);
++	audit_fd = audit_open();
++	if (audit_fd < 0)
++		/* no problem, the next instruction will be fatal() */
++		return;
++	audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION,
++			buf, NULL, get_remote_ipaddr(), NULL, 0);
++	audit_close(audit_fd);
++#endif
++}
++
++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;
++	const static char *direction[] = { "from-server", "from-client", "both" };
++	Cipher *cipher = cipher_by_name(enc);
++	char *s;
++
++	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(), (s = get_local_ipaddr(packet_get_connection_in())), get_local_port());
++	xfree(s);
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
++					 errno == EAFNOSUPPORT)
++			return; /* No audit support in kernel */
++		else                                                                                                                                       
++			fatal("cannot open audit"); /* Must prevent login */
++	}
++	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION,
++			buf, NULL, get_remote_ipaddr(), NULL, 1);
++	audit_close(audit_fd);
++	/* do not abort if the error is EPERM and sshd is run as non root user */
++	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
++		fatal("cannot write into audit"); /* Must prevent login */
++#endif
++}
++
+ #endif /* USE_LINUX_AUDIT */
+diff -up openssh-5.9p1/audit.c.audit3 openssh-5.9p1/audit.c
+--- openssh-5.9p1/audit.c.audit3	2011-09-14 07:05:56.937585272 +0200
++++ openssh-5.9p1/audit.c	2011-09-14 07:05:58.646521393 +0200
+@@ -28,6 +28,7 @@
+ 
+ #include <stdarg.h>
+ #include <string.h>
++#include <unistd.h>
+ 
+ #ifdef SSH_AUDIT_EVENTS
+ 
+@@ -36,6 +37,8 @@
+ #include "key.h"
+ #include "hostfile.h"
+ #include "auth.h"
++#include "ssh-gss.h"
++#include "monitor_wrap.h"
+ #include "xmalloc.h"
+ 
+ /*
+@@ -128,6 +131,18 @@ audit_key(int host_user, int *rv, const
+ 	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()));
++}
++
+ # ifndef CUSTOM_SSH_AUDIT_EVENTS
+ /*
+  * Null implementations of audit functions.
+@@ -238,5 +253,26 @@ audit_keyusage(int host_user, const char
+ 		host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), type, bits,
+ 		key_fingerprint_prefix(), fp, rv);
+ }
++
++/*
++ * This will be called when the protocol negotiation fails.
++ */
++void
++audit_unsupported_body(int what)
++{
++	debug("audit unsupported protocol euid %d type %d", geteuid(), what);
++}
++
++/*
++ * This will be called on succesfull protocol negotiation.
++ */
++void
++audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid,
++	       uid_t uid)
++{
++	debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s from pid %ld uid %u",
++		(unsigned)geteuid(), ctos, enc, mac, compress, (long)pid,
++	        (unsigned)uid);
++}
+ # endif  /* !defined CUSTOM_SSH_AUDIT_EVENTS */
+ #endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-5.9p1/audit.h.audit3 openssh-5.9p1/audit.h
+--- openssh-5.9p1/audit.h.audit3	2011-09-14 07:05:57.391522394 +0200
++++ openssh-5.9p1/audit.h	2011-09-14 07:05:58.766586362 +0200
+@@ -58,5 +58,9 @@ void 	audit_end_command(int, const char
+ ssh_audit_event_t audit_classify_auth(const char *);
+ int	audit_keyusage(int, const char *, unsigned, char *, int);
+ void	audit_key(int, int *, const Key *);
++void	audit_unsupported(int);
++void	audit_kex(int, char *, char *, char *);
++void	audit_unsupported_body(int);
++void	audit_kex_body(int, char *, char *, char *, pid_t, uid_t);
+ 
+ #endif /* _SSH_AUDIT_H */
+diff -up openssh-5.9p1/auditstub.c.audit3 openssh-5.9p1/auditstub.c
+--- openssh-5.9p1/auditstub.c.audit3	2011-09-14 07:05:58.866461077 +0200
++++ openssh-5.9p1/auditstub.c	2011-09-14 07:05:58.870569033 +0200
+@@ -0,0 +1,39 @@
++/* $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>
++ */
++
++void
++audit_unsupported(int n)
++{
++}
++
++void
++audit_kex(int ctos, char *enc, char *mac, char *comp)
++{
++}
++
+diff -up openssh-5.9p1/cipher.c.audit3 openssh-5.9p1/cipher.c
+--- openssh-5.9p1/cipher.c.audit3	2011-09-07 15:05:09.000000000 +0200
++++ openssh-5.9p1/cipher.c	2011-09-14 07:05:58.955582581 +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.9p1/cipher.h.audit3 openssh-5.9p1/cipher.h
+--- openssh-5.9p1/cipher.h.audit3	2009-01-28 06:38:41.000000000 +0100
++++ openssh-5.9p1/cipher.h	2011-09-14 07:05:59.063459363 +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.9p1/kex.c.audit3 openssh-5.9p1/kex.c
+--- openssh-5.9p1/kex.c.audit3	2010-09-24 14:11:14.000000000 +0200
++++ openssh-5.9p1/kex.c	2011-09-14 07:05:59.171457800 +0200
+@@ -49,6 +49,7 @@
+ #include "dispatch.h"
+ #include "monitor.h"
+ #include "roaming.h"
++#include "audit.h"
+ 
+ #if OPENSSL_VERSION_NUMBER >= 0x00907000L
+ # if defined(HAVE_EVP_SHA256)
+@@ -286,9 +287,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;
+@@ -303,9 +308,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 */
+@@ -320,8 +329,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) {
+@@ -446,6 +459,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],
+diff -up openssh-5.9p1/monitor.c.audit3 openssh-5.9p1/monitor.c
+--- openssh-5.9p1/monitor.c.audit3	2011-09-14 07:05:57.952459820 +0200
++++ openssh-5.9p1/monitor.c	2011-09-14 07:05:59.272520466 +0200
+@@ -97,6 +97,7 @@
+ #include "ssh2.h"
+ #include "jpake.h"
+ #include "roaming.h"
++#include "audit.h"
+ 
+ #ifdef GSSAPI
+ static Gssctxt *gsscontext = NULL;
+@@ -187,6 +188,8 @@ int mm_answer_gss_checkmic(int, Buffer *
+ 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 *);
+ #endif
+ 
+ static int monitor_read_log(struct monitor *);
+@@ -237,6 +240,8 @@ 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},
+ #endif
+ #ifdef BSD_AUTH
+     {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
+@@ -275,6 +280,8 @@ struct mon_table mon_dispatch_postauth20
+     {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},
+ #endif
+     {0, 0, NULL}
+ };
+@@ -306,6 +313,8 @@ 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},
+ #endif
+     {0, 0, NULL}
+ };
+@@ -318,6 +327,8 @@ struct mon_table mon_dispatch_postauth15
+     {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},
+ #endif
+     {0, 0, NULL}
+ };
+@@ -2383,3 +2394,47 @@ 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);
++
++	xfree(cipher);
++	xfree(mac);
++	xfree(compress);
++	buffer_clear(m);
++
++	mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m);
++	return 0;
++}
++
++#endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-5.9p1/monitor.h.audit3 openssh-5.9p1/monitor.h
+--- openssh-5.9p1/monitor.h.audit3	2011-09-14 07:05:55.510580908 +0200
++++ openssh-5.9p1/monitor.h	2011-09-14 07:05:59.378647273 +0200
+@@ -61,6 +61,8 @@ enum monitor_reqtype {
+ 	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_AUDIT_UNSUPPORTED, MONITOR_ANS_AUDIT_UNSUPPORTED,
++	MONITOR_REQ_AUDIT_KEX, MONITOR_ANS_AUDIT_KEX,
+ 	MONITOR_REQ_TERM,
+ 	MONITOR_REQ_JPAKE_STEP1, MONITOR_ANS_JPAKE_STEP1,
+ 	MONITOR_REQ_JPAKE_GET_PWDATA, MONITOR_ANS_JPAKE_GET_PWDATA,
+diff -up openssh-5.9p1/monitor_wrap.c.audit3 openssh-5.9p1/monitor_wrap.c
+--- openssh-5.9p1/monitor_wrap.c.audit3	2011-09-14 07:05:58.059501118 +0200
++++ openssh-5.9p1/monitor_wrap.c	2011-09-14 07:05:59.511503364 +0200
+@@ -1505,3 +1505,41 @@ mm_jpake_check_confirm(const BIGNUM *k,
+ 	return success;
+ }
+ #endif /* JPAKE */
++
++#ifdef SSH_AUDIT_EVENTS
++void
++mm_audit_unsupported_body(int what)
++{
++	Buffer m;
++
++	buffer_init(&m);
++	buffer_put_int(&m, what);
++
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED,
++				  &m);
++
++	buffer_free(&m);
++}
++
++void
++mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, pid_t pid,
++		  uid_t uid)
++{
++	Buffer m;
++
++	buffer_init(&m);
++	buffer_put_int(&m, ctos);
++	buffer_put_cstring(&m, cipher);
++	buffer_put_cstring(&m, mac);
++	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 */
+diff -up openssh-5.9p1/monitor_wrap.h.audit3 openssh-5.9p1/monitor_wrap.h
+--- openssh-5.9p1/monitor_wrap.h.audit3	2011-09-14 07:05:58.171521245 +0200
++++ openssh-5.9p1/monitor_wrap.h	2011-09-14 07:05:59.624646515 +0200
+@@ -78,6 +78,8 @@ void mm_sshpam_free_ctx(void *);
+ void mm_audit_event(ssh_audit_event_t);
+ int mm_audit_run_command(const char *);
+ void mm_audit_end_command(int, const char *);
++void mm_audit_unsupported_body(int);
++void mm_audit_kex_body(int, char *, char *, char *, pid_t, uid_t);
+ #endif
+ 
+ struct Session;
+diff -up openssh-5.9p1/sshd.c.audit3 openssh-5.9p1/sshd.c
+--- openssh-5.9p1/sshd.c.audit3	2011-09-14 07:05:56.554583874 +0200
++++ openssh-5.9p1/sshd.c	2011-09-14 07:05:59.828466112 +0200
+@@ -118,6 +118,7 @@
+ #endif
+ #include "monitor_wrap.h"
+ #include "roaming.h"
++#include "audit.h"
+ #include "ssh-sandbox.h"
+ #include "version.h"
+ 
+@@ -2209,6 +2210,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. */
diff --git a/openssh-5.9p1-audit4.patch b/openssh-5.9p1-audit4.patch
new file mode 100644
index 0000000..0594a63
--- /dev/null
+++ b/openssh-5.9p1-audit4.patch
@@ -0,0 +1,667 @@
+diff -up openssh-5.9p1/audit-bsm.c.audit4 openssh-5.9p1/audit-bsm.c
+--- openssh-5.9p1/audit-bsm.c.audit4	2011-09-18 05:13:24.922458521 +0200
++++ openssh-5.9p1/audit-bsm.c	2011-09-18 05:13:26.808459314 +0200
+@@ -408,4 +408,10 @@ audit_kex_body(int ctos, char *enc, char
+ {
+ 	/* not implemented */
+ }
++
++void
++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
++{
++	/* not implemented */
++}
+ #endif /* BSM */
+diff -up openssh-5.9p1/audit-linux.c.audit4 openssh-5.9p1/audit-linux.c
+--- openssh-5.9p1/audit-linux.c.audit4	2011-09-18 05:13:25.041460630 +0200
++++ openssh-5.9p1/audit-linux.c	2011-09-18 05:13:26.897563551 +0200
+@@ -294,6 +294,8 @@ audit_unsupported_body(int what)
+ #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)
+@@ -301,7 +303,6 @@ audit_kex_body(int ctos, char *enc, char
+ #ifdef AUDIT_CRYPTO_SESSION
+ 	char buf[AUDIT_LOG_SIZE];
+ 	int audit_fd, audit_ok;
+-	const static char *direction[] = { "from-server", "from-client", "both" };
+ 	Cipher *cipher = cipher_by_name(enc);
+ 	char *s;
+ 
+@@ -327,4 +328,32 @@ audit_kex_body(int ctos, char *enc, char
+ #endif
+ }
+ 
++void
++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
++{
++	char buf[AUDIT_LOG_SIZE];
++	int audit_fd, audit_ok;
++	char *s;
++
++	snprintf(buf, sizeof(buf), "op=destroy kind=session fp=? direction=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ",
++		 direction[ctos], (intmax_t)pid, (intmax_t)uid,
++		 get_remote_port(),
++		 (s = get_local_ipaddr(packet_get_connection_in())),
++		 get_local_port());
++	xfree(s);
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		if (errno != EINVAL && errno != EPROTONOSUPPORT &&
++					 errno != EAFNOSUPPORT)
++			error("cannot open audit");
++		return;
++	}
++	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER,
++			buf, NULL, get_remote_ipaddr(), NULL, 1);
++	audit_close(audit_fd);
++	/* do not abort if the error is EPERM and sshd is run as non root user */
++	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
++		error("cannot write into audit");
++}
++
+ #endif /* USE_LINUX_AUDIT */
+diff -up openssh-5.9p1/audit.c.audit4 openssh-5.9p1/audit.c
+--- openssh-5.9p1/audit.c.audit4	2011-09-18 05:13:25.151459504 +0200
++++ openssh-5.9p1/audit.c	2011-09-18 05:13:26.995548664 +0200
+@@ -143,6 +143,12 @@ audit_kex(int ctos, char *enc, char *mac
+ 	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.
+@@ -274,5 +280,15 @@ audit_kex_body(int ctos, char *enc, char
+ 		(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);
++}
+ # endif  /* !defined CUSTOM_SSH_AUDIT_EVENTS */
+ #endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-5.9p1/audit.h.audit4 openssh-5.9p1/audit.h
+--- openssh-5.9p1/audit.h.audit4	2011-09-18 05:13:25.247587021 +0200
++++ openssh-5.9p1/audit.h	2011-09-18 05:13:27.107531553 +0200
+@@ -62,5 +62,7 @@ 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);
+ 
+ #endif /* _SSH_AUDIT_H */
+diff -up openssh-5.9p1/auditstub.c.audit4 openssh-5.9p1/auditstub.c
+--- openssh-5.9p1/auditstub.c.audit4	2011-09-18 05:13:25.350459598 +0200
++++ openssh-5.9p1/auditstub.c	2011-09-18 05:13:27.209523920 +0200
+@@ -27,6 +27,8 @@
+  * Red Hat author: Jan F. Chadima <jchadima at redhat.com>
+  */
+ 
++#include <sys/types.h>
++
+ void
+ audit_unsupported(int n)
+ {
+@@ -37,3 +39,12 @@ audit_kex(int ctos, char *enc, char *mac
+ {
+ }
+ 
++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.9p1/kex.c.audit4 openssh-5.9p1/kex.c
+--- openssh-5.9p1/kex.c.audit4	2011-09-18 05:13:25.656459960 +0200
++++ openssh-5.9p1/kex.c	2011-09-18 05:13:27.309500951 +0200
+@@ -624,3 +624,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.9p1/kex.h.audit4 openssh-5.9p1/kex.h
+--- openssh-5.9p1/kex.h.audit4	2010-09-24 14:11:14.000000000 +0200
++++ openssh-5.9p1/kex.h	2011-09-18 05:13:27.419492884 +0200
+@@ -156,6 +156,8 @@ void	 kexgex_server(Kex *);
+ void	 kexecdh_client(Kex *);
+ void	 kexecdh_server(Kex *);
+ 
++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.9p1/mac.c.audit4 openssh-5.9p1/mac.c
+--- openssh-5.9p1/mac.c.audit4	2011-08-17 02:29:03.000000000 +0200
++++ openssh-5.9p1/mac.c	2011-09-18 05:13:27.545464964 +0200
+@@ -168,6 +168,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.9p1/mac.h.audit4 openssh-5.9p1/mac.h
+--- openssh-5.9p1/mac.h.audit4	2007-06-11 06:01:42.000000000 +0200
++++ openssh-5.9p1/mac.h	2011-09-18 05:13:27.675473027 +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.9p1/monitor.c.audit4 openssh-5.9p1/monitor.c
+--- openssh-5.9p1/monitor.c.audit4	2011-09-18 05:13:25.778584691 +0200
++++ openssh-5.9p1/monitor.c	2011-09-18 05:15:22.786522699 +0200
+@@ -189,6 +189,7 @@ 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 *);
+ #endif
+ 
+ static int monitor_read_log(struct monitor *);
+@@ -241,6 +242,7 @@ struct mon_table mon_dispatch_proto20[]
+     {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},
+ #endif
+ #ifdef BSD_AUTH
+     {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
+@@ -280,6 +282,7 @@ struct mon_table mon_dispatch_postauth20
+     {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},
+ #endif
+     {0, 0, NULL}
+ };
+@@ -313,6 +316,7 @@ struct mon_table mon_dispatch_proto15[]
+     {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},
+ #endif
+     {0, 0, NULL}
+ };
+@@ -327,6 +331,7 @@ struct mon_table mon_dispatch_postauth15
+     {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},
+ #endif
+     {0, 0, NULL}
+ };
+@@ -437,10 +442,6 @@ monitor_child_preauth(Authctxt *_authctx
+ 		}
+ 	}
+ 
+-	/* Drain any buffered messages from the child */
+-	while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0)
+-		;
+-
+ 	if (!authctxt->valid)
+ 		fatal("%s: authenticated invalid user", __func__);
+ 	if (strcmp(auth_method, "unknown") == 0)
+@@ -1927,11 +1928,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 */
+@@ -1977,6 +1980,21 @@ mm_get_keystate(struct monitor *pmonitor
+ 	}
+ 
+ 	buffer_free(&m);
++
++#ifdef SSH_AUDIT_EVENTS
++	if (compat20) {
++		buffer_init(&m);
++		mm_request_receive_expect(pmonitor->m_sendfd,
++					  MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m);
++		mm_answer_audit_session_key_free_body(pmonitor->m_sendfd, &m);
++		buffer_free(&m);
++	}
++#endif
++
++	/* Drain any buffered messages from the child */
++	while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0)
++		;
++
+ }
+ 
+ 
+@@ -2421,4 +2439,22 @@ mm_answer_audit_kex_body(int sock, Buffe
+ 	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;
++}
+ #endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-5.9p1/monitor.h.audit4 openssh-5.9p1/monitor.h
+--- openssh-5.9p1/monitor.h.audit4	2011-09-18 05:13:25.887586033 +0200
++++ openssh-5.9p1/monitor.h	2011-09-18 05:13:27.934522919 +0200
+@@ -63,6 +63,7 @@ enum monitor_reqtype {
+ 	MONITOR_ANS_AUDIT_COMMAND, MONITOR_REQ_AUDIT_END_COMMAND,
+ 	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_TERM,
+ 	MONITOR_REQ_JPAKE_STEP1, MONITOR_ANS_JPAKE_STEP1,
+ 	MONITOR_REQ_JPAKE_GET_PWDATA, MONITOR_ANS_JPAKE_GET_PWDATA,
+diff -up openssh-5.9p1/monitor_wrap.c.audit4 openssh-5.9p1/monitor_wrap.c
+--- openssh-5.9p1/monitor_wrap.c.audit4	2011-09-18 05:13:26.013583317 +0200
++++ openssh-5.9p1/monitor_wrap.c	2011-09-18 05:13:28.049519981 +0200
+@@ -653,12 +653,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);
+@@ -1522,4 +1524,19 @@ mm_audit_kex_body(int ctos, char *cipher
+ 
+ 	buffer_free(&m);
+ }
++
++void
++mm_audit_session_key_free_body(int ctos, pid_t pid, uid_t uid)
++{
++	Buffer m;
++
++	buffer_init(&m);
++	buffer_put_int(&m, ctos);
++	buffer_put_int64(&m, pid);
++	buffer_put_int64(&m, uid);
++	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m);
++	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE,
++				  &m);
++	buffer_free(&m);
++}
+ #endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-5.9p1/monitor_wrap.h.audit4 openssh-5.9p1/monitor_wrap.h
+--- openssh-5.9p1/monitor_wrap.h.audit4	2011-09-18 05:13:26.119474152 +0200
++++ openssh-5.9p1/monitor_wrap.h	2011-09-18 05:13:28.151521539 +0200
+@@ -79,6 +79,7 @@ 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);
+ #endif
+ 
+ struct Session;
+diff -up openssh-5.9p1/packet.c.audit4 openssh-5.9p1/packet.c
+--- openssh-5.9p1/packet.c.audit4	2011-09-18 05:13:20.417548627 +0200
++++ openssh-5.9p1/packet.c	2011-09-18 05:13:28.278520968 +0200
+@@ -60,6 +60,7 @@
+ #include <signal.h>
+ 
+ #include "xmalloc.h"
++#include "audit.h"
+ #include "buffer.h"
+ #include "packet.h"
+ #include "crc32.h"
+@@ -472,6 +473,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 +488,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 +496,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. */
+@@ -731,6 +742,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)
+ {
+@@ -756,18 +784,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)
+@@ -1927,6 +1946,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.
+@@ -1934,18 +1994,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();
+ }
+ 
+ /*
+@@ -1962,9 +2016,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);
+@@ -1972,4 +2024,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.9p1/packet.h.audit4 openssh-5.9p1/packet.h
+--- openssh-5.9p1/packet.h.audit4	2011-05-15 00:43:13.000000000 +0200
++++ openssh-5.9p1/packet.h	2011-09-18 05:13:28.385521238 +0200
+@@ -124,4 +124,5 @@ void	 packet_restore_state(void);
+ void	*packet_get_input(void);
+ void	*packet_get_output(void);
+ 
++void	 packet_destroy_all(int, int);
+ #endif				/* PACKET_H */
+diff -up openssh-5.9p1/session.c.audit4 openssh-5.9p1/session.c
+--- openssh-5.9p1/session.c.audit4	2011-09-18 05:13:22.842504192 +0200
++++ openssh-5.9p1/session.c	2011-09-18 05:13:28.511522576 +0200
+@@ -1634,6 +1634,9 @@ do_child(Session *s, const char *command
+ 
+ 	/* remove hostkey from the child's memory */
+ 	destroy_sensitive_data();
++	/* 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) {
+diff -up openssh-5.9p1/sshd.c.audit4 openssh-5.9p1/sshd.c
+--- openssh-5.9p1/sshd.c.audit4	2011-09-18 05:13:26.617460032 +0200
++++ openssh-5.9p1/sshd.c	2011-09-18 05:13:28.621521065 +0200
+@@ -686,6 +686,8 @@ privsep_preauth(Authctxt *authctxt)
+ 	}
+ }
+ 
++extern Newkeys *current_keys[];
++
+ static void
+ privsep_postauth(Authctxt *authctxt)
+ {
+@@ -710,6 +712,10 @@ privsep_postauth(Authctxt *authctxt)
+ 	else if (pmonitor->m_pid != 0) {
+ 		verbose("User child is on pid %ld", (long)pmonitor->m_pid);
+ 		buffer_clear(&loginmsg);
++ 		newkeys_destroy(current_keys[MODE_OUT]);
++		newkeys_destroy(current_keys[MODE_IN]);
++		audit_session_key_free_body(2, getpid(), getuid());
++		packet_destroy_all(0, 0);
+ 		monitor_child_postauth(pmonitor);
+ 
+ 		/* NEVERREACHED */
+@@ -2001,6 +2007,7 @@ main(int ac, char **av)
+ 	 */
+ 	if (use_privsep) {
+ 		mm_send_keystate(pmonitor);
++		packet_destroy_all(1, 1);
+ 		exit(0);
+ 	}
+ 
+@@ -2053,6 +2060,8 @@ main(int ac, char **av)
+ 	do_authenticated(authctxt);
+ 
+ 	/* The connection has been terminated. */
++	packet_destroy_all(1, 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",
+@@ -2370,8 +2379,20 @@ do_ssh2_kex(void)
+ void
+ cleanup_exit(int i)
+ {
++	static int in_cleanup = 0;
++	int is_privsep_child;
++
++	/* cleanup_exit can be called at the very least from the privsep
++	   wrappers used for auditing.  Make sure we don't recurse
++	   indefinitely. */
++	if (in_cleanup)
++		_exit(i);
++	in_cleanup = 1;
++
+ 	if (the_authctxt)
+ 		do_cleanup(the_authctxt);
++	is_privsep_child = use_privsep && pmonitor != NULL && !mm_is_monitor();
++	packet_destroy_all(1, is_privsep_child);
+ #ifdef SSH_AUDIT_EVENTS
+ 	/* done after do_cleanup so it can cancel the PAM auth 'thread' */
+ 	if ((the_authctxt == NULL || !the_authctxt->authenticated) &&
diff --git a/openssh-5.9p1-audit5.patch b/openssh-5.9p1-audit5.patch
new file mode 100644
index 0000000..144b4fe
--- /dev/null
+++ b/openssh-5.9p1-audit5.patch
@@ -0,0 +1,486 @@
+diff -up openssh-5.9p1/audit-bsm.c.audit5 openssh-5.9p1/audit-bsm.c
+--- openssh-5.9p1/audit-bsm.c.audit5	2011-09-13 22:07:31.262575526 +0200
++++ openssh-5.9p1/audit-bsm.c	2011-09-13 22:07:33.268491813 +0200
+@@ -414,4 +414,22 @@ audit_session_key_free_body(int ctos, pi
+ {
+ 	/* 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.9p1/audit-linux.c.audit5 openssh-5.9p1/audit-linux.c
+--- openssh-5.9p1/audit-linux.c.audit5	2011-09-13 22:07:31.400584308 +0200
++++ openssh-5.9p1/audit-linux.c	2011-09-13 22:07:33.357460348 +0200
+@@ -350,4 +350,50 @@ audit_session_key_free_body(int ctos, pi
+ 		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.9p1/audit.c.audit5 openssh-5.9p1/audit.c
+--- openssh-5.9p1/audit.c.audit5	2011-09-13 22:07:31.495458797 +0200
++++ openssh-5.9p1/audit.c	2011-09-13 22:07:33.478458341 +0200
+@@ -290,5 +290,24 @@ audit_session_key_free_body(int ctos, pi
+ 	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.9p1/audit.h.audit5 openssh-5.9p1/audit.h
+--- openssh-5.9p1/audit.h.audit5	2011-09-13 22:07:31.616459125 +0200
++++ openssh-5.9p1/audit.h	2011-09-13 22:07:33.612458074 +0200
+@@ -48,6 +48,8 @@ enum ssh_audit_event_type {
+ };
+ typedef enum ssh_audit_event_type ssh_audit_event_t;
+ 
++int	listening_for_clients(void);
++
+ void	audit_connection_from(const char *, int);
+ void	audit_event(ssh_audit_event_t);
+ void	audit_count_session_open(void);
+@@ -64,5 +66,7 @@ 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.9p1/key.c.audit5 openssh-5.9p1/key.c
+--- openssh-5.9p1/key.c.audit5	2011-09-13 22:07:23.054490740 +0200
++++ openssh-5.9p1/key.c	2011-09-13 22:07:33.721583661 +0200
+@@ -1799,6 +1799,30 @@ key_demote(const Key *k)
+ }
+ 
+ int
++key_is_private(const Key *k)
++{
++	switch (k->type) {
++	case KEY_RSA_CERT_V00:
++	case KEY_RSA_CERT:
++	case KEY_RSA1:
++	case KEY_RSA:
++		return k->rsa->d != NULL;
++	case KEY_DSA_CERT_V00:
++	case KEY_DSA_CERT:
++	case KEY_DSA:
++		return k->dsa->priv_key != NULL;
++#ifdef OPENSSL_HAS_ECC
++	case KEY_ECDSA_CERT:
++	case KEY_ECDSA:
++		return EC_KEY_get0_private_key(k->ecdsa) != NULL;
++#endif
++	default:
++		fatal("key_is_private: bad key type %d", k->type);
++		return 1;
++	}
++}
++
++int
+ key_is_cert(const Key *k)
+ {
+ 	if (k == NULL)
+diff -up openssh-5.9p1/key.h.audit5 openssh-5.9p1/key.h
+--- openssh-5.9p1/key.h.audit5	2011-09-13 22:07:23.160459285 +0200
++++ openssh-5.9p1/key.h	2011-09-13 22:07:33.847459341 +0200
+@@ -109,6 +109,7 @@ Key	*key_generate(int, u_int);
+ Key	*key_from_private(const Key *);
+ int	 key_type_from_name(char *);
+ int	 key_is_cert(const Key *);
++int	 key_is_private(const Key *k);
+ int	 key_type_plain(int);
+ int	 key_to_certified(Key *, int);
+ int	 key_drop_cert(Key *);
+diff -up openssh-5.9p1/monitor.c.audit5 openssh-5.9p1/monitor.c
+--- openssh-5.9p1/monitor.c.audit5	2011-09-13 22:07:32.285495537 +0200
++++ openssh-5.9p1/monitor.c	2011-09-13 22:10:04.148554239 +0200
+@@ -114,6 +114,8 @@ extern Buffer auth_debug;
+ extern int auth_debug_init;
+ extern Buffer loginmsg;
+ 
++extern void destroy_sensitive_data(int);
++
+ /* State exported from the child */
+ 
+ struct {
+@@ -191,6 +193,7 @@ int mm_answer_audit_end_command(int, Buf
+ int mm_answer_audit_unsupported_body(int, Buffer *);
+ int mm_answer_audit_kex_body(int, Buffer *);
+ int mm_answer_audit_session_key_free_body(int, Buffer *);
++int mm_answer_audit_server_key_free(int, Buffer *);
+ #endif
+ 
+ static int monitor_read_log(struct monitor *);
+@@ -244,6 +247,7 @@ struct mon_table mon_dispatch_proto20[]
+     {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},
+@@ -285,6 +289,7 @@ struct mon_table mon_dispatch_postauth20
+     {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}
+ };
+@@ -319,6 +324,7 @@ struct mon_table mon_dispatch_proto15[]
+     {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}
+ };
+@@ -334,6 +340,7 @@ struct mon_table mon_dispatch_postauth15
+     {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}
+ };
+@@ -1716,6 +1723,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);
+@@ -2470,4 +2479,25 @@ mm_answer_audit_session_key_free_body(in
+ 	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);
++
++	xfree(fp);
++	buffer_clear(m);
++
++	mm_request_send(sock, MONITOR_ANS_AUDIT_SERVER_KEY_FREE, m);
++	return 0;
++}
+ #endif /* SSH_AUDIT_EVENTS */
+diff -up openssh-5.9p1/monitor.h.audit5 openssh-5.9p1/monitor.h
+--- openssh-5.9p1/monitor.h.audit5	2011-09-13 22:07:32.385522626 +0200
++++ openssh-5.9p1/monitor.h	2011-09-13 22:07:34.098459356 +0200
+@@ -64,6 +64,7 @@ enum monitor_reqtype {
+ 	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,
+ 	MONITOR_REQ_TERM,
+ 	MONITOR_REQ_JPAKE_STEP1, MONITOR_ANS_JPAKE_STEP1,
+ 	MONITOR_REQ_JPAKE_GET_PWDATA, MONITOR_ANS_JPAKE_GET_PWDATA,
+diff -up openssh-5.9p1/monitor_wrap.c.audit5 openssh-5.9p1/monitor_wrap.c
+--- openssh-5.9p1/monitor_wrap.c.audit5	2011-09-13 22:07:32.510521163 +0200
++++ openssh-5.9p1/monitor_wrap.c	2011-09-13 22:07:34.610458275 +0200
+@@ -1559,4 +1559,20 @@ mm_audit_session_key_free_body(int ctos,
+ 				  &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.9p1/monitor_wrap.h.audit5 openssh-5.9p1/monitor_wrap.h
+--- openssh-5.9p1/monitor_wrap.h.audit5	2011-09-13 22:07:32.607520810 +0200
++++ openssh-5.9p1/monitor_wrap.h	2011-09-13 22:07:34.716458214 +0200
+@@ -81,6 +81,7 @@ void mm_audit_end_command(int, const cha
+ 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.9p1/session.c.audit5 openssh-5.9p1/session.c
+--- openssh-5.9p1/session.c.audit5	2011-09-13 22:07:32.973544819 +0200
++++ openssh-5.9p1/session.c	2011-09-13 22:07:34.849585578 +0200
+@@ -136,7 +136,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. */
+@@ -1633,7 +1633,7 @@ 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);
+diff -up openssh-5.9p1/sshd.c.audit5 openssh-5.9p1/sshd.c
+--- openssh-5.9p1/sshd.c.audit5	2011-09-13 22:07:33.106516378 +0200
++++ openssh-5.9p1/sshd.c	2011-09-13 22:07:34.989470331 +0200
+@@ -254,7 +254,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);
+@@ -273,6 +273,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)
+ {
+@@ -533,22 +542,47 @@ sshd_exchange_identification(int sock_in
+ 	}
+ }
+ 
+-/* Destroy the host and server keys.  They will no longer be needed. */
++/*
++ * Destroy the host and server keys.  They will no longer be needed.  Careful,
++ * this can be called from cleanup_exit() - i.e. from just about anywhere.
++ */
+ void
+-destroy_sensitive_data(void)
++destroy_sensitive_data(int privsep)
+ {
+ 	int i;
++	pid_t pid;
++	uid_t uid;
+ 
+ 	if (sensitive_data.server_key) {
+ 		key_free(sensitive_data.server_key);
+ 		sensitive_data.server_key = NULL;
+ 	}
++	pid = getpid();
++	uid = getuid();
+ 	for (i = 0; i < options.num_host_key_files; i++) {
+ 		if (sensitive_data.host_keys[i]) {
++			char *fp;
++
++			if (key_is_private(sensitive_data.host_keys[i]))
++				fp = 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);
++			}
+ 		}
+-		if (sensitive_data.host_certificates[i]) {
++		if (sensitive_data.host_certificates
++		    && sensitive_data.host_certificates[i]) {
+ 			key_free(sensitive_data.host_certificates[i]);
+ 			sensitive_data.host_certificates[i] = NULL;
+ 		}
+@@ -562,6 +596,8 @@ void
+ demote_sensitive_data(void)
+ {
+ 	Key *tmp;
++	pid_t pid;
++	uid_t uid;
+ 	int i;
+ 
+ 	if (sensitive_data.server_key) {
+@@ -570,13 +606,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);
++			}
+ 		}
+ 		/* Certs do not need demotion */
+ 	}
+@@ -1145,6 +1195,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(received_sigterm == SIGTERM ? 0 : 255);
+@@ -2050,7 +2101,7 @@ main(int ac, char **av)
+ 		privsep_postauth(authctxt);
+ 		/* the monitor process [priv] will not return */
+ 		if (!compat20)
+-			destroy_sensitive_data();
++			destroy_sensitive_data(0);
+ 	}
+ 
+ 	packet_set_timeout(options.client_alive_interval,
+@@ -2061,6 +2112,7 @@ main(int ac, char **av)
+ 
+ 	/* 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);
+@@ -2289,7 +2341,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);
+@@ -2392,6 +2444,8 @@ cleanup_exit(int i)
+ 	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' */
diff --git a/openssh-5.9p1-coverity.patch b/openssh-5.9p1-coverity.patch
new file mode 100644
index 0000000..f3524e3
--- /dev/null
+++ b/openssh-5.9p1-coverity.patch
@@ -0,0 +1,844 @@
+diff -up openssh-5.9p1/auth-pam.c.coverity openssh-5.9p1/auth-pam.c
+--- openssh-5.9p1/auth-pam.c.coverity	2009-07-12 14:07:21.000000000 +0200
++++ openssh-5.9p1/auth-pam.c	2011-09-14 08:09:47.074520582 +0200
+@@ -216,7 +216,12 @@ pthread_join(sp_pthread_t thread, void *
+ 	if (sshpam_thread_status != -1)
+ 		return (sshpam_thread_status);
+ 	signal(SIGCHLD, sshpam_oldsig);
+-	waitpid(thread, &status, 0);
++	while (waitpid(thread, &status, 0) < 0) {                     
++		if (errno == EINTR)                                
++			continue;
++		fatal("%s: waitpid: %s", __func__,         
++				strerror(errno));                      
++	}
+ 	return (status);
+ }
+ #endif
+diff -up openssh-5.9p1/channels.c.coverity openssh-5.9p1/channels.c
+--- openssh-5.9p1/channels.c.coverity	2011-06-23 00:31:57.000000000 +0200
++++ openssh-5.9p1/channels.c	2011-09-14 08:09:47.556582810 +0200
+@@ -229,11 +229,11 @@ channel_register_fds(Channel *c, int rfd
+ 	channel_max_fd = MAX(channel_max_fd, wfd);
+ 	channel_max_fd = MAX(channel_max_fd, efd);
+ 
+-	if (rfd != -1)
++	if (rfd >= 0)
+ 		fcntl(rfd, F_SETFD, FD_CLOEXEC);
+-	if (wfd != -1 && wfd != rfd)
++	if (wfd >= 0 && wfd != rfd)
+ 		fcntl(wfd, F_SETFD, FD_CLOEXEC);
+-	if (efd != -1 && efd != rfd && efd != wfd)
++	if (efd >= 0 && efd != rfd && efd != wfd)
+ 		fcntl(efd, F_SETFD, FD_CLOEXEC);
+ 
+ 	c->rfd = rfd;
+@@ -248,11 +248,11 @@ channel_register_fds(Channel *c, int rfd
+ 
+ 	/* enable nonblocking mode */
+ 	if (nonblock) {
+-		if (rfd != -1)
++		if (rfd >= 0)
+ 			set_nonblock(rfd);
+-		if (wfd != -1)
++		if (wfd >= 0)
+ 			set_nonblock(wfd);
+-		if (efd != -1)
++		if (efd >= 0)
+ 			set_nonblock(efd);
+ 	}
+ }
+diff -up openssh-5.9p1/clientloop.c.coverity openssh-5.9p1/clientloop.c
+--- openssh-5.9p1/clientloop.c.coverity	2011-06-23 00:31:58.000000000 +0200
++++ openssh-5.9p1/clientloop.c	2011-09-14 08:17:41.556521887 +0200
+@@ -1970,14 +1970,15 @@ client_input_global_request(int type, u_
+ 	char *rtype;
+ 	int want_reply;
+ 	int success = 0;
++/* success is still 0 the packet is allways SSH2_MSG_REQUEST_FAILURE, isn't it? */
+ 
+ 	rtype = packet_get_string(NULL);
+ 	want_reply = packet_get_char();
+ 	debug("client_input_global_request: rtype %s want_reply %d",
+ 	    rtype, want_reply);
+ 	if (want_reply) {
+-		packet_start(success ?
+-		    SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
++		packet_start(/*success ?
++		    SSH2_MSG_REQUEST_SUCCESS :*/ SSH2_MSG_REQUEST_FAILURE);
+ 		packet_send();
+ 		packet_write_wait();
+ 	}
+diff -up openssh-5.9p1/key.c.coverity openssh-5.9p1/key.c
+--- openssh-5.9p1/key.c.coverity	2011-05-20 11:03:08.000000000 +0200
++++ openssh-5.9p1/key.c	2011-09-14 08:09:47.803458435 +0200
+@@ -803,8 +803,10 @@ key_read(Key *ret, char **cpp)
+ 		success = 1;
+ /*XXXX*/
+ 		key_free(k);
++/*XXXX
+ 		if (success != 1)
+ 			break;
++XXXX*/
+ 		/* advance cp: skip whitespace and data */
+ 		while (*cp == ' ' || *cp == '\t')
+ 			cp++;
+diff -up openssh-5.9p1/misc.c.coverity openssh-5.9p1/misc.c
+diff -up openssh-5.9p1/monitor.c.coverity openssh-5.9p1/monitor.c
+--- openssh-5.9p1/monitor.c.coverity	2011-08-05 22:15:18.000000000 +0200
++++ openssh-5.9p1/monitor.c	2011-09-14 08:09:47.914584009 +0200
+@@ -420,7 +420,7 @@ monitor_child_preauth(Authctxt *_authctx
+ 	}
+ 
+ 	/* Drain any buffered messages from the child */
+-	while (pmonitor->m_log_recvfd != -1 && monitor_read_log(pmonitor) == 0)
++	while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0)
+ 		;
+ 
+ 	if (!authctxt->valid)
+@@ -1161,6 +1161,10 @@ mm_answer_keyallowed(int sock, Buffer *m
+ 			break;
+ 		}
+ 	}
++
++	debug3("%s: key %p is %s",
++	    __func__, key, allowed ? "allowed" : "not allowed");
++
+ 	if (key != NULL)
+ 		key_free(key);
+ 
+@@ -1182,9 +1186,6 @@ mm_answer_keyallowed(int sock, Buffer *m
+ 		xfree(chost);
+ 	}
+ 
+-	debug3("%s: key %p is %s",
+-	    __func__, key, allowed ? "allowed" : "not allowed");
+-
+ 	buffer_clear(m);
+ 	buffer_put_int(m, allowed);
+ 	buffer_put_int(m, forced_command != NULL);
+diff -up openssh-5.9p1/monitor_wrap.c.coverity openssh-5.9p1/monitor_wrap.c
+--- openssh-5.9p1/monitor_wrap.c.coverity	2011-09-14 08:11:36.480500123 +0200
++++ openssh-5.9p1/monitor_wrap.c	2011-09-14 08:14:11.279520598 +0200
+@@ -707,10 +707,10 @@ mm_pty_allocate(int *ptyfd, int *ttyfd,
+ 	if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 ||
+ 	    (tmp2 = dup(pmonitor->m_recvfd)) == -1) {
+ 		error("%s: cannot allocate fds for pty", __func__);
+-		if (tmp1 > 0)
++		if (tmp1 >= 0)
+ 			close(tmp1);
+-		if (tmp2 > 0)
+-			close(tmp2);
++		/*DEAD CODE if (tmp2 >= 0)
++			close(tmp2);*/
+ 		return 0;
+ 	}
+ 	close(tmp1);
+diff -up openssh-5.9p1/openbsd-compat/bindresvport.c.coverity openssh-5.9p1/openbsd-compat/bindresvport.c
+--- openssh-5.9p1/openbsd-compat/bindresvport.c.coverity	2010-12-03 00:50:26.000000000 +0100
++++ openssh-5.9p1/openbsd-compat/bindresvport.c	2011-09-14 08:09:48.084459344 +0200
+@@ -58,7 +58,7 @@ bindresvport_sa(int sd, struct sockaddr
+ 	struct sockaddr_in6 *in6;
+ 	u_int16_t *portp;
+ 	u_int16_t port;
+-	socklen_t salen;
++	socklen_t salen = sizeof(struct sockaddr_storage);
+ 	int i;
+ 
+ 	if (sa == NULL) {
+diff -up openssh-5.9p1/packet.c.coverity openssh-5.9p1/packet.c
+--- openssh-5.9p1/packet.c.coverity	2011-05-15 00:58:15.000000000 +0200
++++ openssh-5.9p1/packet.c	2011-09-14 08:09:48.184587842 +0200
+@@ -1177,6 +1177,7 @@ packet_read_poll1(void)
+ 		case DEATTACK_DETECTED:
+ 			packet_disconnect("crc32 compensation attack: "
+ 			    "network attack detected");
++			break;
+ 		case DEATTACK_DOS_DETECTED:
+ 			packet_disconnect("deattack denial of "
+ 			    "service detected");
+@@ -1684,7 +1685,7 @@ void
+ packet_write_wait(void)
+ {
+ 	fd_set *setp;
+-	int ret, ms_remain;
++	int ret, ms_remain = 0;
+ 	struct timeval start, timeout, *timeoutp = NULL;
+ 
+ 	setp = (fd_set *)xcalloc(howmany(active_state->connection_out + 1,
+diff -up openssh-5.9p1/progressmeter.c.coverity openssh-5.9p1/progressmeter.c
+--- openssh-5.9p1/progressmeter.c.coverity	2006-08-05 04:39:40.000000000 +0200
++++ openssh-5.9p1/progressmeter.c	2011-09-14 08:09:48.300586004 +0200
+@@ -65,7 +65,7 @@ static void update_progress_meter(int);
+ 
+ static time_t start;		/* start progress */
+ static time_t last_update;	/* last progress update */
+-static char *file;		/* name of the file being transferred */
++static const char *file;	/* name of the file being transferred */
+ static off_t end_pos;		/* ending position of transfer */
+ static off_t cur_pos;		/* transfer position as of last refresh */
+ static volatile off_t *counter;	/* progress counter */
+@@ -247,7 +247,7 @@ update_progress_meter(int ignore)
+ }
+ 
+ void
+-start_progress_meter(char *f, off_t filesize, off_t *ctr)
++start_progress_meter(const char *f, off_t filesize, off_t *ctr)
+ {
+ 	start = last_update = time(NULL);
+ 	file = f;
+diff -up openssh-5.9p1/progressmeter.h.coverity openssh-5.9p1/progressmeter.h
+--- openssh-5.9p1/progressmeter.h.coverity	2006-03-26 05:30:02.000000000 +0200
++++ openssh-5.9p1/progressmeter.h	2011-09-14 08:09:48.420645724 +0200
+@@ -23,5 +23,5 @@
+  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+-void	start_progress_meter(char *, off_t, off_t *);
++void	start_progress_meter(const char *, off_t, off_t *);
+ void	stop_progress_meter(void);
+diff -up openssh-5.9p1/scp.c.coverity openssh-5.9p1/scp.c
+--- openssh-5.9p1/scp.c.coverity	2011-01-06 12:41:21.000000000 +0100
++++ openssh-5.9p1/scp.c	2011-09-14 08:09:48.531505457 +0200
+@@ -155,7 +155,7 @@ killchild(int signo)
+ {
+ 	if (do_cmd_pid > 1) {
+ 		kill(do_cmd_pid, signo ? signo : SIGTERM);
+-		waitpid(do_cmd_pid, NULL, 0);
++		(void) waitpid(do_cmd_pid, NULL, 0);
+ 	}
+ 
+ 	if (signo)
+diff -up openssh-5.9p1/servconf.c.coverity openssh-5.9p1/servconf.c
+--- openssh-5.9p1/servconf.c.coverity	2011-06-23 00:30:03.000000000 +0200
++++ openssh-5.9p1/servconf.c	2011-09-14 08:30:17.557468182 +0200
+@@ -609,7 +609,7 @@ match_cfg_line(char **condition, int lin
+ 		debug3("checking syntax for 'Match %s'", cp);
+ 	else
+ 		debug3("checking match for '%s' user %s host %s addr %s", cp,
+-		    user ? user : "(null)", host ? host : "(null)",
++		    user /* User is not NULL ? user : "(null)" */, host ? host : "(null)",
+ 		    address ? address : "(null)");
+ 
+ 	while ((attrib = strdelim(&cp)) && *attrib != '\0') {
+@@ -1171,7 +1171,7 @@ process_server_config_line(ServerOptions
+ 			fatal("%s line %d: Missing subsystem name.",
+ 			    filename, linenum);
+ 		if (!*activep) {
+-			arg = strdelim(&cp);
++			/*arg =*/ (void) strdelim(&cp);
+ 			break;
+ 		}
+ 		for (i = 0; i < options->num_subsystems; i++)
+@@ -1262,8 +1262,9 @@ process_server_config_line(ServerOptions
+ 		if (*activep && *charptr == NULL) {
+ 			*charptr = tilde_expand_filename(arg, getuid());
+ 			/* increase optional counter */
+-			if (intptr != NULL)
+-				*intptr = *intptr + 1;
++			/* DEAD CODE intptr is still NULL ;)
++  			 if (intptr != NULL)
++				*intptr = *intptr + 1; */
+ 		}
+ 		break;
+ 
+diff -up openssh-5.9p1/serverloop.c.coverity openssh-5.9p1/serverloop.c
+--- openssh-5.9p1/serverloop.c.coverity	2011-05-20 11:02:50.000000000 +0200
++++ openssh-5.9p1/serverloop.c	2011-09-14 08:09:48.793586380 +0200
+@@ -147,13 +147,13 @@ notify_setup(void)
+ static void
+ notify_parent(void)
+ {
+-	if (notify_pipe[1] != -1)
++	if (notify_pipe[1] >= 0)
+ 		write(notify_pipe[1], "", 1);
+ }
+ static void
+ notify_prepare(fd_set *readset)
+ {
+-	if (notify_pipe[0] != -1)
++	if (notify_pipe[0] >= 0)
+ 		FD_SET(notify_pipe[0], readset);
+ }
+ static void
+@@ -161,8 +161,8 @@ notify_done(fd_set *readset)
+ {
+ 	char c;
+ 
+-	if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset))
+-		while (read(notify_pipe[0], &c, 1) != -1)
++	if (notify_pipe[0] >= 0 && FD_ISSET(notify_pipe[0], readset))
++		while (read(notify_pipe[0], &c, 1) >= 0)
+ 			debug2("notify_done: reading");
+ }
+ 
+@@ -330,7 +330,7 @@ wait_until_can_do_something(fd_set **rea
+ 		 * If we have buffered data, try to write some of that data
+ 		 * to the program.
+ 		 */
+-		if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
++		if (fdin >= 0 && buffer_len(&stdin_buffer) > 0)
+ 			FD_SET(fdin, *writesetp);
+ 	}
+ 	notify_prepare(*readsetp);
+@@ -470,7 +470,7 @@ process_output(fd_set *writeset)
+ 	int len;
+ 
+ 	/* Write buffered data to program stdin. */
+-	if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) {
++	if (!compat20 && fdin >= 0 && FD_ISSET(fdin, writeset)) {
+ 		data = buffer_ptr(&stdin_buffer);
+ 		dlen = buffer_len(&stdin_buffer);
+ 		len = write(fdin, data, dlen);
+@@ -583,7 +583,7 @@ server_loop(pid_t pid, int fdin_arg, int
+ 	set_nonblock(fdin);
+ 	set_nonblock(fdout);
+ 	/* we don't have stderr for interactive terminal sessions, see below */
+-	if (fderr != -1)
++	if (fderr >= 0)
+ 		set_nonblock(fderr);
+ 
+ 	if (!(datafellows & SSH_BUG_IGNOREMSG) && isatty(fdin))
+@@ -607,7 +607,7 @@ server_loop(pid_t pid, int fdin_arg, int
+ 	max_fd = MAX(connection_in, connection_out);
+ 	max_fd = MAX(max_fd, fdin);
+ 	max_fd = MAX(max_fd, fdout);
+-	if (fderr != -1)
++	if (fderr >= 0)
+ 		max_fd = MAX(max_fd, fderr);
+ #endif
+ 
+@@ -637,7 +637,7 @@ server_loop(pid_t pid, int fdin_arg, int
+ 		 * If we have received eof, and there is no more pending
+ 		 * input data, cause a real eof by closing fdin.
+ 		 */
+-		if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) {
++		if (stdin_eof && fdin >= 0 && buffer_len(&stdin_buffer) == 0) {
+ 			if (fdin != fdout)
+ 				close(fdin);
+ 			else
+@@ -735,15 +735,15 @@ server_loop(pid_t pid, int fdin_arg, int
+ 	buffer_free(&stderr_buffer);
+ 
+ 	/* Close the file descriptors. */
+-	if (fdout != -1)
++	if (fdout >= 0)
+ 		close(fdout);
+ 	fdout = -1;
+ 	fdout_eof = 1;
+-	if (fderr != -1)
++	if (fderr >= 0)
+ 		close(fderr);
+ 	fderr = -1;
+ 	fderr_eof = 1;
+-	if (fdin != -1)
++	if (fdin >= 0)
+ 		close(fdin);
+ 	fdin = -1;
+ 
+@@ -937,7 +937,7 @@ server_input_window_size(int type, u_int
+ 
+ 	debug("Window change received.");
+ 	packet_check_eom();
+-	if (fdin != -1)
++	if (fdin >= 0)
+ 		pty_change_window_size(fdin, row, col, xpixel, ypixel);
+ }
+ 
+@@ -990,7 +990,7 @@ server_request_tun(void)
+ 	}
+ 
+ 	tun = packet_get_int();
+-	if (forced_tun_device != -1) {
++	if (forced_tun_device >= 0) {
+ 		if (tun != SSH_TUNID_ANY && forced_tun_device != tun)
+ 			goto done;
+ 		tun = forced_tun_device;
+diff -up openssh-5.9p1/sftp-client.c.coverity openssh-5.9p1/sftp-client.c
+--- openssh-5.9p1/sftp-client.c.coverity	2010-12-04 23:02:48.000000000 +0100
++++ openssh-5.9p1/sftp-client.c	2011-09-14 08:09:48.910470343 +0200
+@@ -149,7 +149,7 @@ get_msg(struct sftp_conn *conn, Buffer *
+ }
+ 
+ static void
+-send_string_request(struct sftp_conn *conn, u_int id, u_int code, char *s,
++send_string_request(struct sftp_conn *conn, u_int id, u_int code, const char *s,
+     u_int len)
+ {
+ 	Buffer msg;
+@@ -165,7 +165,7 @@ send_string_request(struct sftp_conn *co
+ 
+ static void
+ send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code,
+-    char *s, u_int len, Attrib *a)
++    const char *s, u_int len, Attrib *a)
+ {
+ 	Buffer msg;
+ 
+@@ -422,7 +422,7 @@ sftp_proto_version(struct sftp_conn *con
+ }
+ 
+ int
+-do_close(struct sftp_conn *conn, char *handle, u_int handle_len)
++do_close(struct sftp_conn *conn, const char *handle, u_int handle_len)
+ {
+ 	u_int id, status;
+ 	Buffer msg;
+@@ -447,7 +447,7 @@ do_close(struct sftp_conn *conn, char *h
+ 
+ 
+ static int
+-do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
++do_lsreaddir(struct sftp_conn *conn, const char *path, int printflag,
+     SFTP_DIRENT ***dir)
+ {
+ 	Buffer msg;
+@@ -571,7 +571,7 @@ do_lsreaddir(struct sftp_conn *conn, cha
+ }
+ 
+ int
+-do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir)
++do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir)
+ {
+ 	return(do_lsreaddir(conn, path, 0, dir));
+ }
+@@ -589,7 +589,7 @@ void free_sftp_dirents(SFTP_DIRENT **s)
+ }
+ 
+ int
+-do_rm(struct sftp_conn *conn, char *path)
++do_rm(struct sftp_conn *conn, const char *path)
+ {
+ 	u_int status, id;
+ 
+@@ -604,7 +604,7 @@ do_rm(struct sftp_conn *conn, char *path
+ }
+ 
+ int
+-do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag)
++do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int printflag)
+ {
+ 	u_int status, id;
+ 
+@@ -620,7 +620,7 @@ do_mkdir(struct sftp_conn *conn, char *p
+ }
+ 
+ int
+-do_rmdir(struct sftp_conn *conn, char *path)
++do_rmdir(struct sftp_conn *conn, const char *path)
+ {
+ 	u_int status, id;
+ 
+@@ -636,7 +636,7 @@ do_rmdir(struct sftp_conn *conn, char *p
+ }
+ 
+ Attrib *
+-do_stat(struct sftp_conn *conn, char *path, int quiet)
++do_stat(struct sftp_conn *conn, const char *path, int quiet)
+ {
+ 	u_int id;
+ 
+@@ -650,7 +650,7 @@ do_stat(struct sftp_conn *conn, char *pa
+ }
+ 
+ Attrib *
+-do_lstat(struct sftp_conn *conn, char *path, int quiet)
++do_lstat(struct sftp_conn *conn, const char *path, int quiet)
+ {
+ 	u_int id;
+ 
+@@ -684,7 +684,7 @@ do_fstat(struct sftp_conn *conn, char *h
+ #endif
+ 
+ int
+-do_setstat(struct sftp_conn *conn, char *path, Attrib *a)
++do_setstat(struct sftp_conn *conn, const char *path, Attrib *a)
+ {
+ 	u_int status, id;
+ 
+@@ -701,7 +701,7 @@ do_setstat(struct sftp_conn *conn, char
+ }
+ 
+ int
+-do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len,
++do_fsetstat(struct sftp_conn *conn, const char *handle, u_int handle_len,
+     Attrib *a)
+ {
+ 	u_int status, id;
+@@ -718,12 +718,12 @@ do_fsetstat(struct sftp_conn *conn, char
+ }
+ 
+ char *
+-do_realpath(struct sftp_conn *conn, char *path)
++do_realpath(struct sftp_conn *conn, const char *path)
+ {
+ 	Buffer msg;
+ 	u_int type, expected_id, count, id;
+ 	char *filename, *longname;
+-	Attrib *a;
++/*UNUSED Attrib *a; */
+ 
+ 	expected_id = id = conn->msg_id++;
+ 	send_string_request(conn, id, SSH2_FXP_REALPATH, path,
+@@ -754,7 +754,7 @@ do_realpath(struct sftp_conn *conn, char
+ 
+ 	filename = buffer_get_string(&msg, NULL);
+ 	longname = buffer_get_string(&msg, NULL);
+-	a = decode_attrib(&msg);
++	/*a =*/ (void) decode_attrib(&msg);
+ 
+ 	debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
+ 
+@@ -766,7 +766,7 @@ do_realpath(struct sftp_conn *conn, char
+ }
+ 
+ int
+-do_rename(struct sftp_conn *conn, char *oldpath, char *newpath)
++do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath)
+ {
+ 	Buffer msg;
+ 	u_int status, id;
+@@ -800,7 +800,7 @@ do_rename(struct sftp_conn *conn, char *
+ }
+ 
+ int
+-do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath)
++do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
+ {
+ 	Buffer msg;
+ 	u_int status, id;
+@@ -833,7 +833,7 @@ do_hardlink(struct sftp_conn *conn, char
+ }
+ 
+ int
+-do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
++do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
+ {
+ 	Buffer msg;
+ 	u_int status, id;
+@@ -984,7 +984,7 @@ send_read_request(struct sftp_conn *conn
+ }
+ 
+ int
+-do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
++do_download(struct sftp_conn *conn, const char *remote_path, const char *local_path,
+     Attrib *a, int pflag)
+ {
+ 	Attrib junk;
+@@ -1223,7 +1223,7 @@ do_download(struct sftp_conn *conn, char
+ }
+ 
+ static int
+-download_dir_internal(struct sftp_conn *conn, char *src, char *dst,
++download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
+     Attrib *dirattrib, int pflag, int printflag, int depth)
+ {
+ 	int i, ret = 0;
+@@ -1313,7 +1313,7 @@ download_dir_internal(struct sftp_conn *
+ }
+ 
+ int
+-download_dir(struct sftp_conn *conn, char *src, char *dst,
++download_dir(struct sftp_conn *conn, const char *src, const char *dst,
+     Attrib *dirattrib, int pflag, int printflag)
+ {
+ 	char *src_canon;
+@@ -1331,7 +1331,7 @@ download_dir(struct sftp_conn *conn, cha
+ }
+ 
+ int
+-do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
++do_upload(struct sftp_conn *conn, const char *local_path, const char *remote_path,
+     int pflag)
+ {
+ 	int local_fd;
+@@ -1514,7 +1514,7 @@ do_upload(struct sftp_conn *conn, char *
+ }
+ 
+ static int
+-upload_dir_internal(struct sftp_conn *conn, char *src, char *dst,
++upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
+     int pflag, int printflag, int depth)
+ {
+ 	int ret = 0, status;
+@@ -1605,7 +1605,7 @@ upload_dir_internal(struct sftp_conn *co
+ }
+ 
+ int
+-upload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag,
++upload_dir(struct sftp_conn *conn, const char *src, const char *dst, int printflag,
+     int pflag)
+ {
+ 	char *dst_canon;
+@@ -1622,7 +1622,7 @@ upload_dir(struct sftp_conn *conn, char
+ }
+ 
+ char *
+-path_append(char *p1, char *p2)
++path_append(const char *p1, const char *p2)
+ {
+ 	char *ret;
+ 	size_t len = strlen(p1) + strlen(p2) + 2;
+diff -up openssh-5.9p1/sftp-client.h.coverity openssh-5.9p1/sftp-client.h
+--- openssh-5.9p1/sftp-client.h.coverity	2010-12-04 23:02:48.000000000 +0100
++++ openssh-5.9p1/sftp-client.h	2011-09-14 08:09:49.021583940 +0200
+@@ -56,49 +56,49 @@ struct sftp_conn *do_init(int, int, u_in
+ u_int sftp_proto_version(struct sftp_conn *);
+ 
+ /* Close file referred to by 'handle' */
+-int do_close(struct sftp_conn *, char *, u_int);
++int do_close(struct sftp_conn *, const char *, u_int);
+ 
+ /* Read contents of 'path' to NULL-terminated array 'dir' */
+-int do_readdir(struct sftp_conn *, char *, SFTP_DIRENT ***);
++int do_readdir(struct sftp_conn *, const char *, SFTP_DIRENT ***);
+ 
+ /* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from do_readdir) */
+ void free_sftp_dirents(SFTP_DIRENT **);
+ 
+ /* Delete file 'path' */
+-int do_rm(struct sftp_conn *, char *);
++int do_rm(struct sftp_conn *, const char *);
+ 
+ /* Create directory 'path' */
+-int do_mkdir(struct sftp_conn *, char *, Attrib *, int);
++int do_mkdir(struct sftp_conn *, const char *, Attrib *, int);
+ 
+ /* Remove directory 'path' */
+-int do_rmdir(struct sftp_conn *, char *);
++int do_rmdir(struct sftp_conn *, const char *);
+ 
+ /* Get file attributes of 'path' (follows symlinks) */
+-Attrib *do_stat(struct sftp_conn *, char *, int);
++Attrib *do_stat(struct sftp_conn *, const char *, int);
+ 
+ /* Get file attributes of 'path' (does not follow symlinks) */
+-Attrib *do_lstat(struct sftp_conn *, char *, int);
++Attrib *do_lstat(struct sftp_conn *, const char *, int);
+ 
+ /* Set file attributes of 'path' */
+-int do_setstat(struct sftp_conn *, char *, Attrib *);
++int do_setstat(struct sftp_conn *, const char *, Attrib *);
+ 
+ /* Set file attributes of open file 'handle' */
+-int do_fsetstat(struct sftp_conn *, char *, u_int, Attrib *);
++int do_fsetstat(struct sftp_conn *, const char *, u_int, Attrib *);
+ 
+ /* Canonicalise 'path' - caller must free result */
+-char *do_realpath(struct sftp_conn *, char *);
++char *do_realpath(struct sftp_conn *, const char *);
+ 
+ /* Get statistics for filesystem hosting file at "path" */
+ int do_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int);
+ 
+ /* Rename 'oldpath' to 'newpath' */
+-int do_rename(struct sftp_conn *, char *, char *);
++int do_rename(struct sftp_conn *, const char *, const char *);
+ 
+ /* Link 'oldpath' to 'newpath' */
+-int do_hardlink(struct sftp_conn *, char *, char *);
++int do_hardlink(struct sftp_conn *, const char *, const char *);
+ 
+-/* Rename 'oldpath' to 'newpath' */
+-int do_symlink(struct sftp_conn *, char *, char *);
++/* Symlink 'oldpath' to 'newpath' */
++int do_symlink(struct sftp_conn *, const char *, const char *);
+ 
+ /* XXX: add callbacks to do_download/do_upload so we can do progress meter */
+ 
+@@ -106,27 +106,27 @@ int do_symlink(struct sftp_conn *, char
+  * Download 'remote_path' to 'local_path'. Preserve permissions and times
+  * if 'pflag' is set
+  */
+-int do_download(struct sftp_conn *, char *, char *, Attrib *, int);
++int do_download(struct sftp_conn *, const char *, const char *, Attrib *, int);
+ 
+ /*
+  * Recursively download 'remote_directory' to 'local_directory'. Preserve 
+  * times if 'pflag' is set
+  */
+-int download_dir(struct sftp_conn *, char *, char *, Attrib *, int, int);
++int download_dir(struct sftp_conn *, const char *, const char *, Attrib *, int, int);
+ 
+ /*
+  * Upload 'local_path' to 'remote_path'. Preserve permissions and times
+  * if 'pflag' is set
+  */
+-int do_upload(struct sftp_conn *, char *, char *, int);
++int do_upload(struct sftp_conn *, const char *, const char *, int);
+ 
+ /*
+  * Recursively upload 'local_directory' to 'remote_directory'. Preserve 
+  * times if 'pflag' is set
+  */
+-int upload_dir(struct sftp_conn *, char *, char *, int, int);
++int upload_dir(struct sftp_conn *, const char *, const char *, int, int);
+ 
+ /* Concatenate paths, taking care of slashes. Caller must free result. */
+-char *path_append(char *, char *);
++char *path_append(const char *, const char *);
+ 
+ #endif
+diff -up openssh-5.9p1/sftp.c.coverity openssh-5.9p1/sftp.c
+--- openssh-5.9p1/sftp.c.coverity	2010-12-04 23:02:48.000000000 +0100
++++ openssh-5.9p1/sftp.c	2011-09-14 08:09:49.468493585 +0200
+@@ -206,7 +206,7 @@ killchild(int signo)
+ {
+ 	if (sshpid > 1) {
+ 		kill(sshpid, SIGTERM);
+-		waitpid(sshpid, NULL, 0);
++		(void) waitpid(sshpid, NULL, 0);
+ 	}
+ 
+ 	_exit(1);
+@@ -316,7 +316,7 @@ local_do_ls(const char *args)
+ 
+ /* Strip one path (usually the pwd) from the start of another */
+ static char *
+-path_strip(char *path, char *strip)
++path_strip(const char *path, const char *strip)
+ {
+ 	size_t len;
+ 
+@@ -334,7 +334,7 @@ path_strip(char *path, char *strip)
+ }
+ 
+ static char *
+-make_absolute(char *p, char *pwd)
++make_absolute(char *p, const char *pwd)
+ {
+ 	char *abs_str;
+ 
+@@ -482,7 +482,7 @@ parse_df_flags(const char *cmd, char **a
+ }
+ 
+ static int
+-is_dir(char *path)
++is_dir(const char *path)
+ {
+ 	struct stat sb;
+ 
+@@ -494,7 +494,7 @@ is_dir(char *path)
+ }
+ 
+ static int
+-remote_is_dir(struct sftp_conn *conn, char *path)
++remote_is_dir(struct sftp_conn *conn, const char *path)
+ {
+ 	Attrib *a;
+ 
+@@ -508,7 +508,7 @@ remote_is_dir(struct sftp_conn *conn, ch
+ 
+ /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
+ static int
+-pathname_is_dir(char *pathname)
++pathname_is_dir(const char *pathname)
+ {
+ 	size_t l = strlen(pathname);
+ 
+@@ -516,7 +516,7 @@ pathname_is_dir(char *pathname)
+ }
+ 
+ static int
+-process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd,
++process_get(struct sftp_conn *conn, const char *src, const char *dst, const char *pwd,
+     int pflag, int rflag)
+ {
+ 	char *abs_src = NULL;
+@@ -590,7 +590,7 @@ out:
+ }
+ 
+ static int
+-process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd,
++process_put(struct sftp_conn *conn, const char *src, const char *dst, const char *pwd,
+     int pflag, int rflag)
+ {
+ 	char *tmp_dst = NULL;
+@@ -695,7 +695,7 @@ sdirent_comp(const void *aa, const void
+ 
+ /* sftp ls.1 replacement for directories */
+ static int
+-do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)
++do_ls_dir(struct sftp_conn *conn, const char *path, const char *strip_path, int lflag)
+ {
+ 	int n;
+ 	u_int c = 1, colspace = 0, columns = 1;
+@@ -780,10 +780,10 @@ do_ls_dir(struct sftp_conn *conn, char *
+ 
+ /* sftp ls.1 replacement which handles path globs */
+ static int
+-do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
++do_globbed_ls(struct sftp_conn *conn, const char *path, const char *strip_path,
+     int lflag)
+ {
+-	Attrib *a = NULL;
++/*UNUSED Attrib *a = NULL;*/
+ 	char *fname, *lname;
+ 	glob_t g;
+ 	int err;
+@@ -828,7 +828,7 @@ do_globbed_ls(struct sftp_conn *conn, ch
+ 		colspace = width / columns;
+ 	}
+ 
+-	for (i = 0; g.gl_pathv[i] && !interrupted; i++, a = NULL) {
++	for (i = 0; g.gl_pathv[i] && !interrupted; i++/*, a = NULL*/) {
+ 		fname = path_strip(g.gl_pathv[i], strip_path);
+ 		if (lflag & LS_LONG_VIEW) {
+ 			if (g.gl_statv[i] == NULL) {
+@@ -861,7 +861,7 @@ do_globbed_ls(struct sftp_conn *conn, ch
+ }
+ 
+ static int
+-do_df(struct sftp_conn *conn, char *path, int hflag, int iflag)
++do_df(struct sftp_conn *conn, const char *path, int hflag, int iflag)
+ {
+ 	struct sftp_statvfs st;
+ 	char s_used[FMT_SCALED_STRSIZE];
+diff -up openssh-5.9p1/ssh-agent.c.coverity openssh-5.9p1/ssh-agent.c
+--- openssh-5.9p1/ssh-agent.c.coverity	2011-06-03 06:14:16.000000000 +0200
++++ openssh-5.9p1/ssh-agent.c	2011-09-14 08:09:49.572460295 +0200
+@@ -1147,8 +1147,8 @@ main(int ac, char **av)
+ 	sanitise_stdfd();
+ 
+ 	/* drop */
+-	setegid(getgid());
+-	setgid(getgid());
++	(void) setegid(getgid());
++	(void) setgid(getgid());
+ 
+ #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
+ 	/* Disable ptrace on Linux without sgid bit */
+diff -up openssh-5.9p1/sshd.c.coverity openssh-5.9p1/sshd.c
+--- openssh-5.9p1/sshd.c.coverity	2011-06-23 11:45:51.000000000 +0200
++++ openssh-5.9p1/sshd.c	2011-09-14 08:09:49.687509968 +0200
+@@ -676,8 +676,10 @@ privsep_preauth(Authctxt *authctxt)
+ 		if (getuid() == 0 || geteuid() == 0)
+ 			privsep_preauth_child();
+ 		setproctitle("%s", "[net]");
+-		if (box != NULL)
++		if (box != NULL) {
+ 			ssh_sandbox_child(box);
++			xfree(box);
++		}
+ 
+ 		return 0;
+ 	}
+@@ -1302,6 +1304,9 @@ server_accept_loop(int *sock_in, int *so
+ 		if (num_listen_socks < 0)
+ 			break;
+ 	}
++
++	if (fdset != NULL)
++		xfree(fdset);
+ }
+ 
+ 
+@@ -1774,7 +1779,7 @@ main(int ac, char **av)
+ 
+ 	/* Chdir to the root directory so that the current disk can be
+ 	   unmounted if desired. */
+-	chdir("/");
++	(void) chdir("/");
+ 
+ 	/* ignore SIGPIPE */
+ 	signal(SIGPIPE, SIG_IGN);
diff --git a/openssh-5.9p1-edns.patch b/openssh-5.9p1-edns.patch
new file mode 100644
index 0000000..34f3851
--- /dev/null
+++ b/openssh-5.9p1-edns.patch
@@ -0,0 +1,72 @@
+diff -up openssh-5.9p1/dns.c.edns openssh-5.9p1/dns.c
+--- openssh-5.9p1/dns.c.edns	2010-08-31 14:41:14.000000000 +0200
++++ openssh-5.9p1/dns.c	2011-09-09 08:05:27.782440497 +0200
+@@ -177,6 +177,7 @@ verify_host_key_dns(const char *hostname
+ {
+ 	u_int counter;
+ 	int result;
++	unsigned int rrset_flags = 0;
+ 	struct rrsetinfo *fingerprints = NULL;
+ 
+ 	u_int8_t hostkey_algorithm;
+@@ -200,8 +201,19 @@ verify_host_key_dns(const char *hostname
+ 		return -1;
+ 	}
+ 
++	/*
++	 * Original getrrsetbyname function, found on OpenBSD for example,
++	 * doesn't accept any flag and prerequisite for obtaining AD bit in
++	 * DNS response is set by "options edns0" in resolv.conf.
++	 *
++	 * Our version is more clever and use RRSET_FORCE_EDNS0 flag.
++	 */
++#ifndef HAVE_GETRRSETBYNAME
++	rrset_flags |= RRSET_FORCE_EDNS0;
++#endif
+ 	result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
+-	    DNS_RDATATYPE_SSHFP, 0, &fingerprints);
++	    DNS_RDATATYPE_SSHFP, rrset_flags, &fingerprints);
++
+ 	if (result) {
+ 		verbose("DNS lookup error: %s", dns_result_totext(result));
+ 		return -1;
+diff -up openssh-5.9p1/openbsd-compat/getrrsetbyname.c.edns openssh-5.9p1/openbsd-compat/getrrsetbyname.c
+--- openssh-5.9p1/openbsd-compat/getrrsetbyname.c.edns	2009-07-13 03:38:23.000000000 +0200
++++ openssh-5.9p1/openbsd-compat/getrrsetbyname.c	2011-09-09 15:03:39.930500801 +0200
+@@ -209,8 +209,8 @@ getrrsetbyname(const char *hostname, uns
+ 		goto fail;
+ 	}
+ 
+-	/* don't allow flags yet, unimplemented */
+-	if (flags) {
++	/* Allow RRSET_FORCE_EDNS0 flag only. */
++	if ((flags & ~RRSET_FORCE_EDNS0) != 0) {
+ 		result = ERRSET_INVAL;
+ 		goto fail;
+ 	}
+@@ -226,9 +226,9 @@ getrrsetbyname(const char *hostname, uns
+ #endif /* DEBUG */
+ 
+ #ifdef RES_USE_DNSSEC
+-	/* turn on DNSSEC if EDNS0 is configured */
+-	if (_resp->options & RES_USE_EDNS0)
+-		_resp->options |= RES_USE_DNSSEC;
++	/* turn on DNSSEC if required  */
++	if (flags & RRSET_FORCE_EDNS0)
++		_resp->options |= (RES_USE_EDNS0|RES_USE_DNSSEC);
+ #endif /* RES_USE_DNSEC */
+ 
+ 	/* make query */
+diff -up openssh-5.9p1/openbsd-compat/getrrsetbyname.h.edns openssh-5.9p1/openbsd-compat/getrrsetbyname.h
+--- openssh-5.9p1/openbsd-compat/getrrsetbyname.h.edns	2007-10-26 08:26:50.000000000 +0200
++++ openssh-5.9p1/openbsd-compat/getrrsetbyname.h	2011-09-09 08:05:27.965438689 +0200
+@@ -72,6 +72,9 @@
+ #ifndef RRSET_VALIDATED
+ # define RRSET_VALIDATED	1
+ #endif
++#ifndef RRSET_FORCE_EDNS0
++# define RRSET_FORCE_EDNS0	0x0001
++#endif
+ 
+ /*
+  * Return codes for getrrsetbyname()
diff --git a/openssh-5.9p1-entropy.patch b/openssh-5.9p1-entropy.patch
new file mode 100644
index 0000000..b3dec46
--- /dev/null
+++ b/openssh-5.9p1-entropy.patch
@@ -0,0 +1,251 @@
+diff -up openssh-5.9p0/entropy.c.entropy openssh-5.9p0/entropy.c
+--- openssh-5.9p0/entropy.c.entropy	2011-08-31 13:20:59.660150441 +0200
++++ openssh-5.9p0/entropy.c	2011-08-31 13:21:05.072024970 +0200
+@@ -232,6 +232,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.9p0/openbsd-compat/Makefile.in.entropy openssh-5.9p0/openbsd-compat/Makefile.in
+--- openssh-5.9p0/openbsd-compat/Makefile.in.entropy	2011-08-31 13:20:54.000000000 +0200
++++ openssh-5.9p0/openbsd-compat/Makefile.in	2011-08-31 13:44:25.138151565 +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-linux_part_2.o port-solaris.o port-tun.o port-uw.o
++PORTS=port-aix.o port-irix.o port-linux.o port-linux_part_2.o port-linux-prng.o port-solaris.o port-tun.o port-uw.o
+ 
+ .c.o:
+ 	$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
+diff -up openssh-5.9p0/openbsd-compat/port-linux-prng.c.entropy openssh-5.9p0/openbsd-compat/port-linux-prng.c
+--- openssh-5.9p0/openbsd-compat/port-linux-prng.c.entropy	2011-08-31 13:21:05.382024083 +0200
++++ openssh-5.9p0/openbsd-compat/port-linux-prng.c	2011-08-31 13:21:05.386024776 +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.9p0/ssh-add.1.entropy openssh-5.9p0/ssh-add.1
+--- openssh-5.9p0/ssh-add.1.entropy	2010-11-05 00:20:14.000000000 +0100
++++ openssh-5.9p0/ssh-add.1	2011-08-31 13:21:05.597122030 +0200
+@@ -158,6 +158,20 @@ Identifies the path of a
+ .Ux Ns -domain
+ socket used to communicate with the agent.
+ .El
++.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
+ .It Pa ~/.ssh/identity
+diff -up openssh-5.9p0/ssh-agent.1.entropy openssh-5.9p0/ssh-agent.1
+--- openssh-5.9p0/ssh-agent.1.entropy	2010-12-01 01:50:35.000000000 +0100
++++ openssh-5.9p0/ssh-agent.1	2011-08-31 13:21:05.735150196 +0200
+@@ -198,6 +198,24 @@ sockets used to contain the connection t
+ 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.
++.El
+ .Sh SEE ALSO
+ .Xr ssh 1 ,
+ .Xr ssh-add 1 ,
+diff -up openssh-5.9p0/ssh-keygen.1.entropy openssh-5.9p0/ssh-keygen.1
+--- openssh-5.9p0/ssh-keygen.1.entropy	2011-08-31 13:20:59.200212619 +0200
++++ openssh-5.9p0/ssh-keygen.1	2011-08-31 13:21:06.077150115 +0200
+@@ -669,6 +669,24 @@ 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.
++.El
+ .Sh SEE ALSO
+ .Xr ssh 1 ,
+ .Xr ssh-add 1 ,
+diff -up openssh-5.9p0/ssh-keysign.8.entropy openssh-5.9p0/ssh-keysign.8
+--- openssh-5.9p0/ssh-keysign.8.entropy	2010-08-31 14:41:14.000000000 +0200
++++ openssh-5.9p0/ssh-keysign.8	2011-08-31 13:21:06.207024356 +0200
+@@ -78,6 +78,24 @@ must be set-uid root if host-based authe
+ If these files exist they are assumed to contain public certificate
+ information corresponding with the private keys above.
+ .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.
++.El
+ .Sh SEE ALSO
+ .Xr ssh 1 ,
+ .Xr ssh-keygen 1 ,
+diff -up openssh-5.9p0/ssh.1.entropy openssh-5.9p0/ssh.1
+--- openssh-5.9p0/ssh.1.entropy	2011-08-31 13:21:00.835103535 +0200
++++ openssh-5.9p0/ssh.1	2011-08-31 13:21:05.482032754 +0200
+@@ -1255,6 +1255,23 @@ For more information, see the
+ .Cm PermitUserEnvironment
+ option in
+ .Xr sshd_config 5 .
++.Sh ENVIRONMENT
++.Bl -tag -width Ds -compact
++.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 -compact
+ .It Pa ~/.rhosts
+diff -up openssh-5.9p0/sshd.8.entropy openssh-5.9p0/sshd.8
+--- openssh-5.9p0/sshd.8.entropy	2011-08-31 13:21:00.000000000 +0200
++++ openssh-5.9p0/sshd.8	2011-08-31 13:46:27.341025537 +0200
+@@ -940,6 +940,24 @@ 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.
++.El
+ .Sh IPV6
+ IPv6 address can be used everywhere where IPv4 address. In all entries must be the IPv6 address enclosed in square brackets. Note: The square brackets are metacharacters for the shell and must be escaped in shell.
+ .Sh SEE ALSO
diff --git a/openssh-5.9p1-fips.patch b/openssh-5.9p1-fips.patch
new file mode 100644
index 0000000..c783f6a
--- /dev/null
+++ b/openssh-5.9p1-fips.patch
@@ -0,0 +1,521 @@
+diff -up openssh-5.9p1/Makefile.in.fips openssh-5.9p1/Makefile.in
+--- openssh-5.9p1/Makefile.in.fips	2011-09-08 14:51:55.788515769 +0200
++++ openssh-5.9p1/Makefile.in	2011-09-08 14:51:58.390439672 +0200
+@@ -142,25 +142,25 @@ libssh.a: $(LIBSSH_OBJS)
+ 	$(RANLIB) $@
+ 
+ ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS)
+-	$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS)
++	$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHLIBS) $(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 ssh-pkcs11-client.o
+-	$(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
++	$(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
+ 
+ ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o
+-	$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
++	$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
+ 
+ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o readconf.o
+-	$(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
++	$(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
+ 
+ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o
+ 	$(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
+@@ -172,7 +172,7 @@ ssh-keycat$(EXEEXT): $(LIBCOMPAT) libssh
+ 	$(LD) -o $@ ssh-keycat.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(SSHDLIBS)
+ 
+ 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.9p1/authfile.c.fips openssh-5.9p1/authfile.c
+--- openssh-5.9p1/authfile.c.fips	2011-09-08 14:51:57.076455523 +0200
++++ openssh-5.9p1/authfile.c	2011-09-08 14:51:58.485565698 +0200
+@@ -148,8 +148,14 @@ key_private_rsa1_to_blob(Key *key, Buffe
+ 	/* 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);
+@@ -472,8 +478,13 @@ key_parse_private_rsa1(Buffer *blob, con
+ 	cp = buffer_append_space(&decrypted, buffer_len(&copy));
+ 
+ 	/* 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);
++	    goto fail;
++	}
++
+ 	cipher_crypt(&ciphercontext, cp,
+ 	    buffer_ptr(&copy), buffer_len(&copy));
+ 	cipher_cleanup(&ciphercontext);
+diff -up openssh-5.9p1/cipher-ctr.c.fips openssh-5.9p1/cipher-ctr.c
+--- openssh-5.9p1/cipher-ctr.c.fips	2010-10-07 13:06:42.000000000 +0200
++++ openssh-5.9p1/cipher-ctr.c	2011-09-08 14:51:58.593563819 +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.9p1/cipher.c.fips openssh-5.9p1/cipher.c
+--- openssh-5.9p1/cipher.c.fips	2011-09-08 14:51:44.592501867 +0200
++++ openssh-5.9p1/cipher.c	2011-09-08 14:51:58.700440064 +0200
+@@ -40,6 +40,7 @@
+ #include <sys/types.h>
+ 
+ #include <openssl/md5.h>
++#include <openssl/fips.h>
+ 
+ #include <string.h>
+ #include <stdarg.h>
+@@ -86,6 +87,22 @@ struct Cipher ciphers[] = {
+ 	{ 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
+@@ -128,7 +145,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;
+@@ -138,7 +155,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;
+@@ -182,7 +199,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;
+@@ -289,14 +306,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);
+ 
+@@ -304,6 +322,7 @@ cipher_set_key_string(CipherContext *cc,
+ 
+ 	memset(digest, 0, sizeof(digest));
+ 	memset(&md, 0, sizeof(md));
++	return 0;
+ }
+ 
+ /*
+diff -up openssh-5.9p1/cipher.h.fips openssh-5.9p1/cipher.h
+--- openssh-5.9p1/cipher.h.fips	2011-09-08 14:51:44.697501719 +0200
++++ openssh-5.9p1/cipher.h	2011-09-08 14:51:58.800502283 +0200
+@@ -87,7 +87,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.9p1/key.c.fips openssh-5.9p1/key.c
+--- openssh-5.9p1/key.c.fips	2011-09-08 14:51:49.002451595 +0200
++++ openssh-5.9p1/key.c	2011-09-08 14:51:58.908501542 +0200
+@@ -40,6 +40,7 @@
+ #include <sys/types.h>
+ 
+ #include <openssl/evp.h>
++#include <openssl/fips.h>
+ #include <openbsd-compat/openssl-compat.h>
+ 
+ #include <stdarg.h>
+@@ -602,9 +603,13 @@ key_fingerprint_selection(void)
+ 	char *env;
+ 
+ 	if (!rv_defined) {
+-		env = getenv("SSH_FINGERPRINT_TYPE");
+-		rv = (env && !strcmp (env, "sha")) ?
+-			SSH_FP_SHA1 : SSH_FP_MD5;
++		if (FIPS_mode())
++			rv = SSH_FP_SHA1;
++		else {
++			env = getenv("SSH_FINGERPRINT_TYPE");
++			rv = (env && !strcmp (env, "sha")) ?
++				SSH_FP_SHA1 : SSH_FP_MD5;
++		}
+ 		rv_defined = 1;
+ 	}
+ 	return rv;
+diff -up openssh-5.9p1/mac.c.fips openssh-5.9p1/mac.c
+--- openssh-5.9p1/mac.c.fips	2011-09-08 14:51:46.755466816 +0200
++++ openssh-5.9p1/mac.c	2011-09-08 14:51:59.029600712 +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 },
+ #ifdef HAVE_EVP_SHA256
+@@ -71,9 +72,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) {
+@@ -94,6 +101,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.9p1/myproposal.h.fips openssh-5.9p1/myproposal.h
+--- openssh-5.9p1/myproposal.h.fips	2011-08-17 02:29:03.000000000 +0200
++++ openssh-5.9p1/myproposal.h	2011-09-08 14:51:59.150503573 +0200
+@@ -97,6 +97,12 @@
+ #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.9p1/openbsd-compat/bsd-arc4random.c.fips openssh-5.9p1/openbsd-compat/bsd-arc4random.c
+--- openssh-5.9p1/openbsd-compat/bsd-arc4random.c.fips	2010-03-25 22:52:02.000000000 +0100
++++ openssh-5.9p1/openbsd-compat/bsd-arc4random.c	2011-09-08 14:51:59.262439903 +0200
+@@ -37,25 +37,18 @@
+ #define REKEY_BYTES	(1 << 24)
+ 
+ static int rc4_ready = 0;
+-static RC4_KEY rc4;
+ 
+ unsigned int
+ arc4random(void)
+ {
+ 	unsigned int r = 0;
+-	static int first_time = 1;
++	void *rp = &r;
+ 
+-	if (rc4_ready <= 0) {
+-		if (first_time)
+-			seed_rng();
+-		first_time = 0;
++	if (!rc4_ready) {
+ 		arc4random_stir();
+ 	}
++	RAND_bytes(rp, sizeof(r));
+ 
+-	RC4(&rc4, sizeof(r), (unsigned char *)&r, (unsigned char *)&r);
+-
+-	rc4_ready -= sizeof(r);
+-	
+ 	return(r);
+ }
+ 
+@@ -63,24 +56,11 @@ void
+ arc4random_stir(void)
+ {
+ 	unsigned char rand_buf[SEED_SIZE];
+-	int i;
+ 
+-	memset(&rc4, 0, sizeof(rc4));
+ 	if (RAND_bytes(rand_buf, sizeof(rand_buf)) <= 0)
+ 		fatal("Couldn't obtain random bytes (error %ld)",
+ 		    ERR_get_error());
+-	RC4_set_key(&rc4, sizeof(rand_buf), rand_buf);
+-
+-	/*
+-	 * Discard early keystream, as per recommendations in:
+-	 * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
+-	 */
+-	for(i = 0; i <= 256; i += sizeof(rand_buf))
+-		RC4(&rc4, sizeof(rand_buf), rand_buf, rand_buf);
+-
+-	memset(rand_buf, 0, sizeof(rand_buf));
+-
+-	rc4_ready = REKEY_BYTES;
++	rc4_ready = 1;
+ }
+ #endif /* !HAVE_ARC4RANDOM */
+ 
+diff -up openssh-5.9p1/ssh.c.fips openssh-5.9p1/ssh.c
+--- openssh-5.9p1/ssh.c.fips	2011-08-05 22:18:16.000000000 +0200
++++ openssh-5.9p1/ssh.c	2011-09-08 14:51:59.369485419 +0200
+@@ -73,6 +73,8 @@
+ 
+ #include <openssl/evp.h>
+ #include <openssl/err.h>
++#include <openssl/fips.h>
++#include <fipscheck.h>
+ #include "openbsd-compat/openssl-compat.h"
+ #include "openbsd-compat/sys-queue.h"
+ 
+@@ -253,6 +255,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.");
++        }
+ 
+ #ifndef HAVE_SETPROCTITLE
+ 	/* Prepare for later setproctitle emulation */
+@@ -329,6 +335,9 @@ main(int ac, char **av)
+ 	    "ACD:F:I:KL:MNO:PR:S:TVw:W:XYy")) != -1) {
+ 		switch (opt) {
+ 		case '1':
++			if (FIPS_mode()) {
++				fatal("Protocol 1 not allowed in the FIPS mode.");
++			}
+ 			options.protocol = SSH_PROTO_1;
+ 			break;
+ 		case '2':
+@@ -630,7 +639,6 @@ main(int ac, char **av)
+ 	if (!host)
+ 		usage();
+ 
+-	OpenSSL_add_all_algorithms();
+ 	ERR_load_crypto_strings();
+ 
+ 	/* Initialize the command to execute on remote host. */
+@@ -721,6 +729,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);
+ 
+@@ -789,6 +801,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.9p1/sshconnect2.c.fips openssh-5.9p1/sshconnect2.c
+--- openssh-5.9p1/sshconnect2.c.fips	2011-09-08 14:51:38.333470704 +0200
++++ openssh-5.9p1/sshconnect2.c	2011-09-08 14:51:59.474500288 +0200
+@@ -44,6 +44,8 @@
+ #include <vis.h>
+ #endif
+ 
++#include <openssl/fips.h>
++
+ #include "openbsd-compat/sys-queue.h"
+ 
+ #include "xmalloc.h"
+@@ -170,6 +172,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]);
+@@ -185,7 +191,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;
+diff -up openssh-5.9p1/sshd.c.fips openssh-5.9p1/sshd.c
+--- openssh-5.9p1/sshd.c.fips	2011-09-08 14:51:52.866451334 +0200
++++ openssh-5.9p1/sshd.c	2011-09-08 14:57:01.982447369 +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
+@@ -1391,6 +1393,11 @@ main(int ac, char **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.");
++        }
++
+ 	/* Save argv. Duplicate so setproctitle emulation doesn't clobber it */
+ 	saved_argc = ac;
+ 	rexec_argc = ac;
+@@ -1550,8 +1557,6 @@ main(int ac, char **av)
+ 	else
+ 		closefrom(REEXEC_DEVCRYPTO_RESERVED_FD);
+ 
+-	OpenSSL_add_all_algorithms();
+-
+ 	/*
+ 	 * Force logging to stderr until we have loaded the private host
+ 	 * key (unless started from inetd)
+@@ -1669,6 +1674,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;
+@@ -1833,6 +1842,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. */
+ 	(void) chdir("/");
+@@ -2375,6 +2388,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]);
+@@ -2384,6 +2400,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 --git a/openssh-5.9p1-gsissh.patch b/openssh-5.9p1-gsissh.patch
new file mode 100644
index 0000000..57cc6d8
--- /dev/null
+++ b/openssh-5.9p1-gsissh.patch
@@ -0,0 +1,2945 @@
+diff -Nur openssh-5.9p1.orig/auth2.c openssh-5.9p1/auth2.c
+--- openssh-5.9p1.orig/auth2.c	2011-11-17 16:58:30.462800089 +0100
++++ openssh-5.9p1/auth2.c	2011-11-17 16:59:47.475791524 +0100
+@@ -229,7 +229,27 @@
+ 	user = packet_get_cstring(NULL);
+ 	service = packet_get_cstring(NULL);
+ 	method = packet_get_cstring(NULL);
+-	debug("userauth-request for user %s service %s method %s", user, service, method);
++
++#ifdef GSSAPI
++	if (user[0] == '\0') {
++		debug("received empty username for %s", method);
++		if (strcmp(method, "gssapi-keyex") == 0) {
++			char *lname = NULL;
++			PRIVSEP(ssh_gssapi_localname(&lname));
++			if (lname && lname[0] != '\0') {
++				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.9p1.orig/auth2-gss.c openssh-5.9p1/auth2-gss.c
+--- openssh-5.9p1.orig/auth2-gss.c	2011-11-17 16:58:30.461800102 +0100
++++ openssh-5.9p1/auth2-gss.c	2011-11-17 16:59:47.475791524 +0100
+@@ -47,6 +47,7 @@
+ 
+ extern ServerOptions options;
+ 
++static void ssh_gssapi_userauth_error(Gssctxt *ctxt);
+ static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
+ static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
+ static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
+@@ -59,8 +60,8 @@
+ userauth_gsskeyex(Authctxt *authctxt)
+ {
+ 	int authenticated = 0;
+-	Buffer b;
+-	gss_buffer_desc mic, gssbuf;
++	Buffer b, b2;
++	gss_buffer_desc mic, gssbuf, gssbuf2;
+ 	u_int len;
+ 
+ 	mic.value = packet_get_string(&len);
+@@ -74,13 +75,27 @@
+ 	gssbuf.value = buffer_ptr(&b);
+ 	gssbuf.length = buffer_len(&b);
+ 
++	/* client may have used empty username to determine target
++	   name from GSSAPI context */
++	ssh_gssapi_buildmic(&b2, "", authctxt->service, "gssapi-keyex");
++
++	gssbuf2.value = buffer_ptr(&b2);
++	gssbuf2.length = buffer_len(&b2);
++
+ 	/* gss_kex_context is NULL with privsep, so we can't check it here */
+ 	if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, 
+-	    &gssbuf, &mic))))
+-		authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
+-		    authctxt->pw));
++						   &gssbuf, &mic))) ||
++	    !GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, 
++						   &gssbuf2, &mic)))) {
++		if (authctxt->valid && authctxt->user && authctxt->user[0]) {
++			authenticated =
++			    PRIVSEP(ssh_gssapi_userok(authctxt->user,
++				    authctxt->pw, 1 /* gssapi-keyex */));
++		}
++	}
+ 	
+ 	buffer_free(&b);
++	buffer_free(&b2);
+ 	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.9p1.orig/auth.c openssh-5.9p1/auth.c
+--- openssh-5.9p1.orig/auth.c	2011-11-17 16:58:30.244802942 +0100
++++ openssh-5.9p1/auth.c	2011-11-17 16:59:47.482791433 +0100
+@@ -72,6 +72,9 @@
+ #include "authfile.h"
+ #include "monitor_wrap.h"
+ 
++#include "version.h"
++#include "ssh-globus-usage.h"
++
+ /* import */
+ extern ServerOptions options;
+ extern int use_privsep;
+@@ -275,7 +278,8 @@
+ 	    authmsg,
+ 	    method,
+ 	    authctxt->valid ? "" : "invalid user ",
+-	    authctxt->user,
++	    (authctxt->user && authctxt->user[0]) ?
++		authctxt->user : "unknown",
+ 	    get_remote_ipaddr(),
+ 	    get_remote_port(),
+ 	    info);
+@@ -297,6 +301,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);
++	}
+ }
+ 
+ /*
+@@ -553,6 +572,10 @@
+ #endif
+ 
+ 	pw = getpwnam(user);
++#ifdef USE_PAM
++	if (options.use_pam && options.permit_pam_user_change && pw == NULL)
++		pw = sshpam_getpw(user);
++#endif
+ 
+ #if defined(_AIX) && defined(HAVE_SETAUTHDB)
+ 	aix_restoreauthdb();
+@@ -572,7 +595,8 @@
+ #endif
+ 	if (pw == NULL) {
+ 		logit("Invalid user %.100s from %.100s",
+-		    user, get_remote_ipaddr());
++		      (user && user[0]) ? user : "unknown",
++		      get_remote_ipaddr());
+ #ifdef CUSTOM_FAILED_LOGIN
+ 		record_failed_login(user,
+ 		    get_canonical_hostname(options.use_dns), "ssh");
+diff -Nur openssh-5.9p1.orig/auth.h openssh-5.9p1/auth.h
+--- openssh-5.9p1.orig/auth.h	2011-11-17 16:58:30.328801841 +0100
++++ openssh-5.9p1/auth.h	2011-11-17 16:59:47.483791420 +0100
+@@ -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.9p1.orig/auth-pam.c openssh-5.9p1/auth-pam.c
+--- openssh-5.9p1.orig/auth-pam.c	2011-11-17 16:58:30.327801854 +0100
++++ openssh-5.9p1/auth-pam.c	2011-11-17 16:59:47.484791406 +0100
+@@ -122,6 +122,10 @@
+  */
+ typedef pthread_t sp_pthread_t;
+ #else
++#define pthread_create openssh_pthread_create
++#define pthread_exit openssh_pthread_exit
++#define pthread_cancel openssh_pthread_cancel
++#define pthread_join openssh_pthread_join
+ typedef pid_t sp_pthread_t;
+ #endif
+ 
+@@ -277,6 +281,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)
+ {
+@@ -299,7 +346,7 @@
+ static void
+ import_environments(Buffer *b)
+ {
+-	char *env;
++	char *env, *user;
+ 	u_int i, num_env;
+ 	int err;
+ 
+@@ -309,6 +356,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);
+@@ -474,6 +530,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;
+@@ -494,6 +553,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++)
+@@ -912,6 +974,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);
+@@ -1211,6 +1279,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.9p1.orig/auth-pam.h openssh-5.9p1/auth-pam.h
+--- openssh-5.9p1.orig/auth-pam.h	2011-11-17 16:58:30.328801841 +0100
++++ openssh-5.9p1/auth-pam.h	2011-11-17 16:59:47.484791406 +0100
+@@ -46,5 +46,6 @@
+ void sshpam_cleanup(void);
+ int sshpam_auth_passwd(Authctxt *, const char *);
+ int is_pam_session_open(void);
++struct passwd *sshpam_getpw(const char *);
+ 
+ #endif /* USE_PAM */
+diff -Nur openssh-5.9p1.orig/canohost.c openssh-5.9p1/canohost.c
+--- openssh-5.9p1.orig/canohost.c	2011-11-17 16:58:30.401800888 +0100
++++ openssh-5.9p1/canohost.c	2011-11-17 16:59:47.485791392 +0100
+@@ -16,6 +16,7 @@
+ 
+ #include <sys/types.h>
+ #include <sys/socket.h>
++#include <sys/param.h>          /* for MAXHOSTNAMELEN */
+ 
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+@@ -453,3 +454,33 @@
+ {
+ 	return get_port(1);
+ }
++
++void
++resolve_localhost(char **host)
++{
++	struct hostent *hostinfo;
++
++	hostinfo = gethostbyname(*host);
++	if (hostinfo == NULL || hostinfo->h_name == NULL) {
++		debug("gethostbyname(%s) failed", *host);
++		return;
++	}
++	if (hostinfo->h_addrtype == AF_INET) {
++		struct in_addr addr;
++		addr = *(struct in_addr *)(hostinfo->h_addr);
++		if (ntohl(addr.s_addr) == INADDR_LOOPBACK) {
++			char buf[MAXHOSTNAMELEN];
++			if (gethostname(buf, sizeof(buf)) < 0) {
++				debug("gethostname() failed");
++				return;
++			}
++			hostinfo = gethostbyname(buf);
++			xfree(*host);
++			if (hostinfo == NULL || hostinfo->h_name == NULL) {
++				*host = xstrdup(buf);
++			} else {
++				*host = xstrdup(hostinfo->h_name);
++			}
++		}
++	}
++}
+diff -Nur openssh-5.9p1.orig/canohost.h openssh-5.9p1/canohost.h
+--- openssh-5.9p1.orig/canohost.h	2009-06-21 11:50:08.000000000 +0200
++++ openssh-5.9p1/canohost.h	2011-11-17 16:59:47.485791392 +0100
+@@ -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.9p1.orig/configure.ac openssh-5.9p1/configure.ac
+--- openssh-5.9p1.orig/configure.ac	2011-11-17 16:58:30.465800050 +0100
++++ openssh-5.9p1/configure.ac	2011-11-17 16:59:47.495791261 +0100
+@@ -3600,6 +3600,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"
+@@ -3619,6 +3627,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
++
+ # Looking for programs, paths and files
+ 
+ PRIVSEP_PATH=/var/empty
+diff -Nur openssh-5.9p1.orig/gss-genr.c openssh-5.9p1/gss-genr.c
+--- openssh-5.9p1.orig/gss-genr.c	2011-11-17 16:58:30.466800036 +0100
++++ openssh-5.9p1/gss-genr.c	2011-11-17 16:59:47.497791234 +0100
+@@ -38,6 +38,7 @@
+ #include "xmalloc.h"
+ #include "buffer.h"
+ #include "log.h"
++#include "canohost.h"
+ #include "ssh2.h"
+ #include "cipher.h"
+ #include "key.h"
+@@ -367,9 +368,18 @@
+ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
+ {
+ 	gss_buffer_desc gssbuf;
++	char *xhost;
+ 	char *val;
+ 
+-	xasprintf(&val, "host@%s", host);
++	/* Make a copy of the host name, in case it was returned by a
++	 * previous call to gethostbyname(). */	
++	xhost = xstrdup(host);
++
++	/* Make sure we have the FQDN. Some GSSAPI implementations don't do
++	 * this for us themselves */
++	resolve_localhost(&xhost);
++	
++	xasprintf(&val, "host@%s", xhost);
+ 	gssbuf.value = val;
+ 	gssbuf.length = strlen(gssbuf.value);
+ 
+@@ -377,6 +387,7 @@
+ 	    &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name)))
+ 		ssh_gssapi_error(ctx);
+ 
++	xfree(xhost);
+ 	xfree(gssbuf.value);
+ 	return (ctx->major);
+ }
+diff -Nur openssh-5.9p1.orig/gss-serv.c openssh-5.9p1/gss-serv.c
+--- openssh-5.9p1.orig/gss-serv.c	2011-11-17 16:58:30.467800022 +0100
++++ openssh-5.9p1/gss-serv.c	2011-11-17 16:59:47.497791235 +0100
+@@ -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
+@@ -298,8 +324,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);
+@@ -342,9 +371,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);
+ 	}
+@@ -371,6 +403,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);
+ }
+ 
+@@ -391,6 +427,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");
+@@ -414,8 +455,9 @@
+ }
+ 
+ /* Privileged */
++/* gssapi_keyex arg added for Globus usage */
+ int
+-ssh_gssapi_userok(char *user, struct passwd *pw)
++ssh_gssapi_userok(char *user, struct passwd *pw, int gssapi_keyex)
+ {
+ 	OM_uint32 lmin;
+ 
+@@ -424,6 +466,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;
+@@ -442,6 +490,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.
+  *
+@@ -468,6 +534,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 && 
+@@ -497,6 +564,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);
+ 
+@@ -528,4 +607,13 @@
+ 	return ok;
+ }
+ 
++/* added for Globus usage */
++void
++ssh_gssapi_get_client_info(char **userdn, char **mech) {
++	*userdn = gssapi_client.displayname.value;
++
++	if (gssapi_client.mech)
++		*mech = gssapi_client.mech->name;
++}
++
+ #endif
+diff -Nur openssh-5.9p1.orig/gss-serv-gsi.c openssh-5.9p1/gss-serv-gsi.c
+--- openssh-5.9p1.orig/gss-serv-gsi.c	1970-01-01 01:00:00.000000000 +0100
++++ openssh-5.9p1/gss-serv-gsi.c	2011-11-17 16:59:47.497791235 +0100
+@@ -0,0 +1,238 @@
++/*
++ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "includes.h"
++
++#ifdef GSSAPI
++#ifdef GSI
++
++#include <sys/types.h>
++
++#include <stdarg.h>
++#include <string.h>
++
++#include "xmalloc.h"
++#include "key.h"
++#include "hostfile.h"
++#include "auth.h"
++#include "log.h"
++#include "servconf.h"
++
++#include "buffer.h"
++#include "ssh-gss.h"
++
++extern ServerOptions options;
++
++#include <globus_gss_assist.h>
++
++static int ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name);
++static int ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user);
++static void ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client);
++static int ssh_gssapi_gsi_updatecreds(ssh_gssapi_ccache *store,
++				       ssh_gssapi_client *client);
++
++ssh_gssapi_mech gssapi_gsi_mech = {
++	"dZuIebMjgUqaxvbF7hDbAw==",
++	"GSI",
++	{9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"},
++	NULL,
++	&ssh_gssapi_gsi_userok,
++	&ssh_gssapi_gsi_localname,
++	&ssh_gssapi_gsi_storecreds,
++	&ssh_gssapi_gsi_updatecreds
++};
++
++/*
++ * Check if this user is OK to login under GSI. User has been authenticated
++ * as identity in global 'client_name.value' and is trying to log in as passed
++ * username in 'name'.
++ *
++ * Returns non-zero if user is authorized, 0 otherwise.
++ */
++static int
++ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name)
++{
++    int authorized = 0;
++    globus_result_t res;
++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
++    char lname[256] = "";
++#endif
++    
++#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
++    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
++	return 0;
++    }
++#endif
++
++/* use new globus_gss_assist_map_and_authorize() interface if available */
++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
++    debug("calling globus_gss_assist_map_and_authorize()");
++    if (GLOBUS_SUCCESS !=
++        (res = globus_gss_assist_map_and_authorize(client->context, "ssh",
++                                                   name, lname, 256))) {
++        debug("%s", globus_error_print_chain(globus_error_get(res)));
++    } else if (lname[0] && strcmp(name, lname) != 0) {
++        debug("GSI user maps to %s, not %s", lname, name);
++    } else {
++        authorized = 1;
++    }
++#else
++    debug("calling globus_gss_assist_userok()");
++    if (GLOBUS_SUCCESS !=
++        (res = (globus_gss_assist_userok(client->displayname.value,
++                                         name)))) {
++        debug("%s", globus_error_print_chain(globus_error_get(res)));
++    } else {
++        authorized = 1;
++    }
++#endif
++    
++    logit("GSI user %s is%s authorized as target user %s",
++	(char *) client->displayname.value, (authorized ? "" : " not"), name);
++    
++    return authorized;
++}
++
++/*
++ * Return the local username associated with the GSI credentials.
++ */
++int
++ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user)
++{
++    globus_result_t res;
++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
++    char lname[256] = "";
++#endif
++
++#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
++    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
++	return 0;
++    }
++#endif
++
++/* use new globus_gss_assist_map_and_authorize() interface if available */
++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE
++    debug("calling globus_gss_assist_map_and_authorize()");
++    if (GLOBUS_SUCCESS !=
++        (res = globus_gss_assist_map_and_authorize(client->context, "ssh",
++                                                   NULL, lname, 256))) {
++        debug("%s", globus_error_print_chain(globus_error_get(res)));
++        logit("failed to map GSI user %s", (char *)client->displayname.value);
++        return 0;
++    }
++    *user = strdup(lname);
++#else
++    debug("calling globus_gss_assist_gridmap()");
++    if (GLOBUS_SUCCESS !=
++        (res = globus_gss_assist_gridmap(client->displayname.value, user))) {
++        debug("%s", globus_error_print_chain(globus_error_get(res)));
++        logit("failed to map GSI user %s", (char *)client->displayname.value);
++        return 0;
++    }
++#endif
++
++    logit("GSI user %s mapped to target user %s",
++          (char *) client->displayname.value, *user);
++
++    return 1;
++}
++
++/*
++ * Export GSI credentials to disk.
++ */
++static void
++ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client)
++{
++	OM_uint32	major_status;
++	OM_uint32	minor_status;
++	gss_buffer_desc	export_cred = GSS_C_EMPTY_BUFFER;
++	char *		p;
++	
++	if (!client || !client->creds) {
++	    return;
++	}
++
++	major_status = gss_export_cred(&minor_status,
++				       client->creds,
++				       GSS_C_NO_OID,
++				       1,
++				       &export_cred);
++	if (GSS_ERROR(major_status) && major_status != GSS_S_UNAVAILABLE) {
++	    Gssctxt *ctx;
++	    ssh_gssapi_build_ctx(&ctx);
++	    ctx->major = major_status;
++	    ctx->minor = minor_status;
++	    ssh_gssapi_set_oid(ctx, &gssapi_gsi_mech.oid);
++	    ssh_gssapi_error(ctx);
++	    ssh_gssapi_delete_ctx(&ctx);
++	    return;
++	}
++	
++	p = strchr((char *) export_cred.value, '=');
++	if (p == NULL) {
++	    logit("Failed to parse exported credentials string '%.100s'",
++		(char *)export_cred.value);
++	    gss_release_buffer(&minor_status, &export_cred);
++	    return;
++	}
++	*p++ = '\0';
++	if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0) {
++	    client->store.envvar = strdup("X509_USER_PROXY");
++	} else {
++	    client->store.envvar = strdup((char *)export_cred.value);
++	}
++	if (access(p, R_OK) == 0) {
++        if (client->store.filename) {
++            if (rename(p, client->store.filename) < 0) {
++                logit("Failed to rename %s to %s: %s", p,
++                      client->store.filename, strerror(errno));
++                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.9p1.orig/gss-serv-krb5.c openssh-5.9p1/gss-serv-krb5.c
+--- openssh-5.9p1.orig/gss-serv-krb5.c	2011-11-17 16:58:30.497799630 +0100
++++ openssh-5.9p1/gss-serv-krb5.c	2011-11-17 16:59:47.498791222 +0100
+@@ -261,6 +261,34 @@
+ 	return found_principal;
+ }
+  
++/* Retrieve the local username associated with a set of Kerberos 
++ * credentials. Hopefully we can use this for the 'empty' username
++ * logins discussed in the draft  */
++static int
++ssh_gssapi_krb5_localname(ssh_gssapi_client *client, char **user) {
++	krb5_principal princ;
++	int retval;
++
++	if (ssh_gssapi_krb5_init() == 0)
++		return 0;
++
++	if ((retval=krb5_parse_name(krb_context, client->displayname.value, 
++				    &princ))) {
++		logit("krb5_parse_name(): %.100s", 
++			krb5_get_err_text(krb_context,retval));
++		return 0;
++	}
++
++	/* We've got to return a malloc'd string */
++	*user = (char *)xmalloc(256);
++	if (krb5_aname_to_localname(krb_context, princ, 256, *user)) {
++		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 */
+@@ -343,7 +371,7 @@
+ 	return;
+ }
+ 
+-int
++static int
+ ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, 
+     ssh_gssapi_client *client)
+ {
+@@ -414,7 +442,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.9p1.orig/kexgsss.c openssh-5.9p1/kexgsss.c
+--- openssh-5.9p1.orig/kexgsss.c	2011-11-17 16:58:30.470799983 +0100
++++ openssh-5.9p1/kexgsss.c	2011-11-17 16:59:47.498791222 +0100
+@@ -44,6 +44,7 @@
+ #include "monitor_wrap.h"
+ #include "servconf.h"
+ 
++static void kex_gss_send_error(Gssctxt *ctxt);
+ extern ServerOptions options;
+ 
+ void
+@@ -89,8 +90,10 @@
+ 
+ 	debug2("%s: Acquiring credentials", __func__);
+ 
+-	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
++	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) {
++		kex_gss_send_error(ctxt);
+ 		fatal("Unable to acquire credentials for the server");
++	}
+ 
+ 	switch (kex->kex_type) {
+ 	case KEX_GSS_GRP1_SHA1:
+@@ -176,12 +179,13 @@
+ 	} while (maj_status & GSS_S_CONTINUE_NEEDED);
+ 
+ 	if (GSS_ERROR(maj_status)) {
++		kex_gss_send_error(ctxt);
+ 		if (send_tok.length > 0) {
+ 			packet_start(SSH2_MSG_KEXGSS_CONTINUE);
+ 			packet_put_string(send_tok.value, send_tok.length);
+ 			packet_send();
+ 		}
+-		fatal("accept_ctx died");
++		packet_disconnect("GSSAPI Key Exchange handshake failed");
+ 	}
+ 
+ 	if (!(ret_flags & GSS_C_MUTUAL_FLAG))
+@@ -285,4 +289,23 @@
+ 	if (options.gss_store_rekey)
+ 		ssh_gssapi_rekey_creds();
+ }
++
++static void 
++kex_gss_send_error(Gssctxt *ctxt) {
++	char *errstr;
++	OM_uint32 maj,min;
++		
++	errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
++	if (errstr) {
++		packet_start(SSH2_MSG_KEXGSS_ERROR);
++		packet_put_int(maj);
++		packet_put_int(min);
++		packet_put_cstring(errstr);
++		packet_put_cstring("");
++		packet_send();
++		packet_write_wait();
++		/* XXX - We should probably log the error locally here */
++		xfree(errstr);
++	}
++}
+ #endif /* GSSAPI */
+diff -Nur openssh-5.9p1.orig/LICENSE.globus_usage openssh-5.9p1/LICENSE.globus_usage
+--- openssh-5.9p1.orig/LICENSE.globus_usage	1970-01-01 01:00:00.000000000 +0100
++++ openssh-5.9p1/LICENSE.globus_usage	2011-11-17 16:59:47.500791195 +0100
+@@ -0,0 +1,18 @@
++/*
++ * Portions of the Usage Metrics suport code are derived from the
++ * Globus project's GridFTP subject to the following license.
++ *
++ * Copyright 2010 University of Chicago
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
+diff -Nur openssh-5.9p1.orig/Makefile.in openssh-5.9p1/Makefile.in
+--- openssh-5.9p1.orig/Makefile.in	2011-11-17 16:58:30.460800115 +0100
++++ openssh-5.9p1/Makefile.in	2011-11-17 16:59:47.501791182 +0100
+@@ -92,8 +92,10 @@
+ 	monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \
+ 	auth-krb5.o \
+ 	auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\
++	gss-serv-gsi.o \
+ 	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
+ 	sftp-server.o sftp-common.o \
++	ssh-globus-usage.o \
+ 	roaming_common.o roaming_serv.o \
+ 	sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o sandbox-selinux.o
+ 
+diff -Nur openssh-5.9p1.orig/misc.c openssh-5.9p1/misc.c
+--- openssh-5.9p1.orig/misc.c	2011-11-17 16:58:30.345801619 +0100
++++ openssh-5.9p1/misc.c	2011-11-17 16:59:47.501791182 +0100
+@@ -158,11 +158,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)
+@@ -170,6 +173,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);
+@@ -223,6 +241,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.9p1.orig/misc.h openssh-5.9p1/misc.h
+--- openssh-5.9p1.orig/misc.h	2011-05-05 06:14:34.000000000 +0200
++++ openssh-5.9p1/misc.h	2011-11-17 16:59:47.502791169 +0100
+@@ -38,6 +38,7 @@
+ void	 sock_set_v6only(int);
+ 
+ struct passwd *pwcopy(struct passwd *);
++void pwfree(struct passwd *);
+ const char *ssh_gai_strerror(int);
+ 
+ typedef struct arglist arglist;
+diff -Nur openssh-5.9p1.orig/monitor.c openssh-5.9p1/monitor.c
+--- openssh-5.9p1.orig/monitor.c	2011-11-17 16:58:30.473799944 +0100
++++ openssh-5.9p1/monitor.c	2011-11-17 16:59:47.503791156 +0100
+@@ -187,6 +187,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
+ 
+@@ -234,7 +237,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},
+@@ -242,7 +245,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},
+@@ -272,6 +275,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},
+@@ -288,6 +294,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},
+@@ -325,7 +333,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},
+@@ -415,6 +423,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;
+@@ -516,6 +526,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;
+@@ -783,14 +795,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);
+ 
+@@ -2253,12 +2268,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);
+@@ -2266,12 +2284,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.9p1.orig/monitor.h openssh-5.9p1/monitor.h
+--- openssh-5.9p1.orig/monitor.h	2011-11-17 16:58:30.474799931 +0100
++++ openssh-5.9p1/monitor.h	2011-11-17 16:59:47.504791143 +0100
+@@ -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.9p1.orig/monitor_wrap.c openssh-5.9p1/monitor_wrap.c
+--- openssh-5.9p1.orig/monitor_wrap.c	2011-11-17 16:58:30.475799918 +0100
++++ openssh-5.9p1/monitor_wrap.c	2011-11-17 16:59:47.504791144 +0100
+@@ -1326,12 +1326,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,
+@@ -1344,6 +1345,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.9p1.orig/monitor_wrap.h openssh-5.9p1/monitor_wrap.h
+--- openssh-5.9p1.orig/monitor_wrap.h	2011-11-17 16:58:30.475799918 +0100
++++ openssh-5.9p1/monitor_wrap.h	2011-11-17 16:59:47.506791117 +0100
+@@ -62,9 +62,13 @@
+ OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
+ OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
+    gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
+-int mm_ssh_gssapi_userok(char *user, struct passwd *);
++int mm_ssh_gssapi_userok(char *user, struct passwd *, int gssapi_keyex);
+ OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
+ OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
++int mm_ssh_gssapi_localname(char **user);
++OM_uint32 mm_gss_indicate_mechs(OM_uint32 *minor_status,
++				gss_OID_set *mech_set);
++char *mm_ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min);
+ int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
+ #endif
+ 
+diff -Nur openssh-5.9p1.orig/readconf.c openssh-5.9p1/readconf.c
+--- openssh-5.9p1.orig/readconf.c	2011-11-17 16:58:30.476799905 +0100
++++ openssh-5.9p1/readconf.c	2011-11-17 16:59:47.507791104 +0100
+@@ -1273,13 +1273,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.9p1.orig/readconf.h openssh-5.9p1/readconf.h
+--- openssh-5.9p1.orig/readconf.h	2011-11-17 16:58:30.478799878 +0100
++++ openssh-5.9p1/readconf.h	2011-11-17 16:59:47.508791091 +0100
+@@ -87,6 +87,8 @@
+ 	char   *host_key_alias;	/* hostname alias for .ssh/known_hosts */
+ 	char   *proxy_command;	/* Proxy command for connecting the host. */
+ 	char   *user;		/* User to log in as. */
++	int     implicit;	/* Login user was not specified.
++				   Server may choose based on authctxt. */
+ 	int     escape_char;	/* Escape character; -2 = none */
+ 
+ 	u_int	num_system_hostfiles;	/* Paths for /etc/ssh/ssh_known_hosts */
+diff -Nur openssh-5.9p1.orig/servconf.c openssh-5.9p1/servconf.c
+--- openssh-5.9p1.orig/servconf.c	2011-11-17 16:58:30.498799616 +0100
++++ openssh-5.9p1/servconf.c	2011-11-17 16:59:47.509791078 +0100
+@@ -62,6 +62,7 @@
+ 
+ 	/* Portable-specific options */
+ 	options->use_pam = -1;
++	options->permit_pam_user_change = -1;
+ 
+ 	/* Standard Options */
+ 	options->num_ports = 0;
+@@ -104,9 +105,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;
+@@ -146,6 +149,8 @@
+ 	options->authorized_keys_command = NULL;
+ 	options->authorized_keys_command_runas = NULL;
+ 	options->zero_knowledge_password_authentication = -1;
++	options->disable_usage_stats = 0;
++	options->usage_stats_targets = NULL;
+ 	options->revoked_keys_file = NULL;
+ 	options->trusted_user_ca_keys = NULL;
+ 	options->authorized_principals_file = NULL;
+@@ -160,6 +165,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)
+@@ -238,13 +245,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)
+@@ -335,7 +346,7 @@
+ typedef enum {
+ 	sBadOption,		/* == unknown option */
+ 	/* Portable-specific options */
+-	sUsePAM,
++	sUsePAM, sPermitPAMUserChange,
+ 	/* Standard Options */
+ 	sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
+ 	sPermitRootLogin, sLogFacility, sLogLevel,
+@@ -359,11 +370,15 @@
+ 	sSecondPasswordAuthentication, sSecondKbdInteractiveAuthentication,
+ 	sSecondZeroKnowledgePasswordAuthentication, sSecondHostbasedAuthentication,
+ 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
++	sGssDelegateCreds,
++	sGssCredsPath,
++	sGsiAllowLimitedProxy,
+ 	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
+ 	sGssKeyEx, sGssStoreRekey,
+ 	sAcceptEnv, sPermitTunnel,
+ 	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
+ 	sUsePrivilegeSeparation, sAllowAgentForwarding,
++	sDisUsageStats, sUsageStatsTarg,
+ 	sZeroKnowledgePasswordAuthentication, sHostCertificate,
+ 	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
+ 	sKexAlgorithms, sIPQoS,
+@@ -384,8 +399,10 @@
+ 	/* Portable-specific options */
+ #ifdef USE_PAM
+ 	{ "usepam", sUsePAM, SSHCFG_GLOBAL },
++	{ "permitpamuserchange", sPermitPAMUserChange, SSHCFG_GLOBAL },
+ #else
+ 	{ "usepam", sUnsupported, SSHCFG_GLOBAL },
++	{ "permitpamuserchange", sUnsupported, SSHCFG_GLOBAL },
+ #endif
+ 	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
+ 	/* Standard Options */
+@@ -427,15 +444,25 @@
+ 	{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
+ #ifdef GSSAPI
+ 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
++	{ "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_ALL },
+ 	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
+ 	{ "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
++	{ "gssapicredentialspath", sGssCredsPath, SSHCFG_GLOBAL },
++#ifdef GSI
++	{ "gsiallowlimitedproxy", sGsiAllowLimitedProxy, SSHCFG_GLOBAL },
++#else
++	{ "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL },
++#endif
+ 	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
+ 	{ "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
+ 	{ "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
+ #else
+ 	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
++	{ "gssapidelegatecredentials", sUnsupported, SSHCFG_ALL },
+ 	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
+ 	{ "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
++	{ "gssapicredentialspath", sUnsupported, SSHCFG_GLOBAL },
++	{ "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL },
+ 	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
+ 	{ "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
+ 	{ "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
+@@ -514,6 +541,8 @@
+ 	{ "permitopen", sPermitOpen, SSHCFG_ALL },
+ 	{ "forcecommand", sForceCommand, SSHCFG_ALL },
+ 	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
++	{ "disableusagestats", sDisUsageStats, SSHCFG_GLOBAL},
++	{ "usagestatstargets", sUsageStatsTarg, SSHCFG_GLOBAL},
+ 	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
+ 	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
+ 	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
+@@ -837,6 +866,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;
+@@ -1041,6 +1074,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;
+@@ -1049,6 +1086,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;
+@@ -1057,6 +1098,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;
+@@ -1498,6 +1545,18 @@
+ 			*charptr = xstrdup(arg);
+ 		break;
+ 
++	case sDisUsageStats:
++		intptr = &options->disable_usage_stats;
++		goto parse_flag;
++
++	case sUsageStatsTarg:
++		arg = strdelim(&cp);
++		if (!arg || *arg == '\0')
++			fatal("%s line %d: missing value.",
++			    filename, linenum);
++		options->usage_stats_targets = xstrdup(arg);
++		break;
++
+ 	case sTrustedUserCAKeys:
+ 		charptr = &options->trusted_user_ca_keys;
+ 		goto parse_filename;
+@@ -1640,6 +1699,7 @@
+ 	M_CP_INTOPT(second_password_authentication);
+ 	M_CP_INTOPT(gss_authentication);
+ 	M_CP_INTOPT(second_gss_authentication);
++	M_CP_INTOPT(gss_deleg_creds);
+ 	M_CP_INTOPT(rsa_authentication);
+ 	M_CP_INTOPT(pubkey_authentication);
+ 	M_CP_INTOPT(second_pubkey_authentication);
+diff -Nur openssh-5.9p1.orig/servconf.h openssh-5.9p1/servconf.h
+--- openssh-5.9p1.orig/servconf.h	2011-11-17 16:58:30.498799616 +0100
++++ openssh-5.9p1/servconf.h	2011-11-17 16:59:47.510791065 +0100
+@@ -102,9 +102,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
+@@ -169,6 +172,7 @@
+ 	char   *adm_forced_command;
+ 
+ 	int	use_pam;		/* Enable auth via PAM */
++	int	permit_pam_user_change;	/* Allow PAM to change user name */
+ 
+ 	int	permit_tun;
+ 
+@@ -176,6 +180,10 @@
+ 
+ 	int	use_kuserok;
+ 	char   *chroot_directory;
++
++	int	disable_usage_stats;
++	char   *usage_stats_targets;
++
+ 	char   *revoked_keys_file;
+ 	char   *trusted_user_ca_keys;
+ 	char   *authorized_principals_file;
+diff -Nur openssh-5.9p1.orig/ssh.1 openssh-5.9p1/ssh.1
+--- openssh-5.9p1.orig/ssh.1	2011-11-17 16:58:30.447800284 +0100
++++ openssh-5.9p1/ssh.1	2011-11-17 16:59:47.510791066 +0100
+@@ -1241,6 +1241,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.9p1.orig/ssh.c openssh-5.9p1/ssh.c
+--- openssh-5.9p1.orig/ssh.c	2011-11-17 16:58:30.422800613 +0100
++++ openssh-5.9p1/ssh.c	2011-11-17 16:59:47.512791039 +0100
+@@ -709,6 +709,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))
+@@ -733,8 +759,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.9p1.orig/ssh_config openssh-5.9p1/ssh_config
+--- openssh-5.9p1.orig/ssh_config	2011-11-17 16:58:30.482799826 +0100
++++ openssh-5.9p1/ssh_config	2011-11-17 16:59:47.512791039 +0100
+@@ -24,10 +24,10 @@
+ #   RSAAuthentication yes
+ #   PasswordAuthentication yes
+ #   HostbasedAuthentication no
+-#   GSSAPIAuthentication no
+-#   GSSAPIDelegateCredentials no
+-#   GSSAPIKeyExchange no
+-#   GSSAPITrustDNS no
++#   GSSAPIAuthentication yes
++#   GSSAPIDelegateCredentials yes
++#   GSSAPIKeyExchange yes
++#   GSSAPITrustDNS yes
+ #   BatchMode no
+ #   CheckHostIP yes
+ #   AddressFamily any
+diff -Nur openssh-5.9p1.orig/ssh_config.5 openssh-5.9p1/ssh_config.5
+--- openssh-5.9p1.orig/ssh_config.5	2011-11-17 16:58:30.480799853 +0100
++++ openssh-5.9p1/ssh_config.5	2011-11-17 16:59:47.513791026 +0100
+@@ -55,6 +55,12 @@
+ user's configuration file
+ .Pq Pa ~/.ssh/config
+ .It
++GSSAPI configuration file
++.Pq Pa $HOME/.ssh/config.gssapi
++.It
++Kerberos configuration file
++.Pq Pa $HOME/.ssh/config.krb
++.It
+ system-wide configuration file
+ .Pq Pa /etc/ssh/ssh_config
+ .El
+diff -Nur openssh-5.9p1.orig/sshconnect2.c openssh-5.9p1/sshconnect2.c
+--- openssh-5.9p1.orig/sshconnect2.c	2011-11-17 16:58:30.495799657 +0100
++++ openssh-5.9p1/sshconnect2.c	2011-11-17 16:59:47.514791013 +0100
+@@ -701,6 +701,11 @@
+ 	int ok = 0;
+ 	const char *gss_host = NULL;
+ 
++	if (!options.gss_authentication) {
++		verbose("GSSAPI authentication disabled.");
++		return 0;
++	}
++
+ 	if (options.gss_server_identity)
+ 		gss_host = options.gss_server_identity;
+ 	else if (options.gss_trust_dns)
+@@ -935,6 +940,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)
+ {
+@@ -952,8 +966,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);
+@@ -964,7 +986,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.9p1.orig/sshd.8 openssh-5.9p1/sshd.8
+--- openssh-5.9p1.orig/sshd.8	2011-11-17 16:58:30.492799696 +0100
++++ openssh-5.9p1/sshd.8	2011-11-17 16:59:47.515791000 +0100
+@@ -757,6 +757,43 @@
+ # A CA key, accepted for any host in *.mydomain.com or *.mydomain.org
+ @cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W...
+ .Ed
++.Sh ENVIRONMENT
++.Nm
++will normally set the following environment variables:
++.Bl -tag -width "SSH_ORIGINAL_COMMAND"
++.It Ev GLOBUS_USAGE_OPTOUT
++Setting this environment variable to "1" will disable the reporting
++of usage metrics. Usage metrics can also be disabled using the
++.Cm DisableUsageStats
++setting in
++.Xr sshd_config 5 .
++.It Ev GLOBUS_USAGE_TARGETS
++If
++.Cm UsageStatsTargets
++is not specified in
++.Xr sshd_config 5 ,
++a comma-separated list of targets (without any tags specified) if
++specified in the environment variable
++.Ev GLOBUS_USAGE_TARGETS
++will be used.
++.It Ev GRIDMAP
++Applies to GSI authentication/authorization. Specifies the location of the
++gridmapfile. If not specified, the gridmap file is assumed to be available at
++/etc/grid-security/grid-mapfile for services running as root and at
++HOME/.gridmap for services running as non-root where HOME is the home directory
++of the effective user from the password file entry.
++.It Ev X509_CERT_DIR
++Used for GSI authentication. Specifies a non-standard location for the
++CA certificates directory.
++.It Ev X509_USER_CERT
++Used for GSI authentication. Specifies a non-standard location for the
++certificate to be used for authentication to the client.
++.It Ev X509_USER_KEY
++Used for GSI authentication. Specifies a non-standard location for the
++private key to be used for authentication to the client.
++.It Ev X509_USER_PROXY
++Used for GSI authentication. Specifies a non-standard location for the
++proxy credential to be used for authentication to the client.
+ .Sh FILES
+ .Bl -tag -width Ds -compact
+ .It Pa ~/.hushlogin
+diff -Nur openssh-5.9p1.orig/sshd.c openssh-5.9p1/sshd.c
+--- openssh-5.9p1.orig/sshd.c	2011-11-17 16:58:30.483799814 +0100
++++ openssh-5.9p1/sshd.c	2011-11-17 16:59:47.516790987 +0100
+@@ -123,6 +123,7 @@
+ #include "audit.h"
+ #include "ssh-sandbox.h"
+ #include "version.h"
++#include "ssh-globus-usage.h"
+ 
+ #ifdef USE_SECURITY_SESSION_API
+ #include <Security/AuthSession.h>
+@@ -1625,6 +1626,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;
+@@ -2157,7 +2165,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.9p1.orig/sshd_config openssh-5.9p1/sshd_config
+--- openssh-5.9p1.orig/sshd_config	2011-11-17 16:58:30.500799590 +0100
++++ openssh-5.9p1/sshd_config	2011-11-17 16:59:47.517790974 +0100
+@@ -80,12 +80,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 
+@@ -106,6 +105,10 @@
+ #SecondKBDInteractiveAuthentication yes
+ #SecondGSSAPIAuthentication no
+ 
++# 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
+@@ -150,3 +153,7 @@
+ #	X11Forwarding no
+ #	AllowTcpForwarding no
+ #	ForceCommand cvs server
++
++# Usage Metrics
++#UsageStatsTargets usage-stats.cilogon.org:4810
++#DisableUsageStats no
+diff -Nur openssh-5.9p1.orig/sshd_config.5 openssh-5.9p1/sshd_config.5
+--- openssh-5.9p1.orig/sshd_config.5	2011-11-17 16:58:30.499799603 +0100
++++ openssh-5.9p1/sshd_config.5	2011-11-17 16:59:47.519790948 +0100
+@@ -380,6 +380,15 @@
+ in
+ .Xr ssh_config 5
+ for more information on patterns.
++.It Cm DisableUsageStats
++This keyword can be followed by "yes" to disable reporting of usage metrics.
++Or it can be set to "no" to enable reporting of usage metrics, which is the
++default. Setting the
++.Cm GLOBUS_USAGE_OPTOUT
++environment variable to "1" will also disable the reporting of usage metrics.
++Disabling reporting of usage metrics will cause the
++.Cm UsageStatsTargets
++setting to be ignored.
+ .It Cm ForceCommand
+ Forces the execution of the command specified by
+ .Cm ForceCommand ,
+@@ -424,6 +433,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.
+@@ -436,6 +449,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
+@@ -1098,6 +1127,121 @@
+ .Pp
+ To disable TCP keepalive messages, the value should be set to
+ .Dq no .
++.It Cm UsageStatsTargets
++This option can be used to specify the target collector hosts to which usage
++metrics should be reported. This setting will be ignored if
++.Cm DisableUsageStats
++is enabled. Multiple targets can be specified separated by comma(s), but no
++space(s). Each target specification is of the format
++.Pa host:port[!tags].
++Tags control what data elements are reported. The following list specifies
++the tags for the corresponding data elements.
++.Pp
++.Bl -item -offset indent -compact
++.It
++.Cm V
++.Sm off
++- OpenSSH version, reported by default.
++.Sm on
++.It
++.Cm v
++.Sm off
++- SSL version, reported by default.
++.Sm on
++.It
++.Cm M
++.Sm off
++- User authentication method used such as "gssapi-keyex", "gssapi-with-mic", etc. Reported by default.
++.Sm on
++.It
++.Cm m
++.Sm off
++- User authentication mechanism used such as "GSI", "Kerberos", etc. Reported by default.
++.Sm on
++.It
++.Cm I
++.Sm off
++- Client IP address. Not reported by default.
++.Sm on
++.It
++.Cm u
++.Sm off
++- User name. Not reported by default.
++.Sm on
++.It
++.Cm U
++.Sm off
++- User DN. Not reported by default.
++.Sm on
++.Pp
++In addition to the above selected information, the following data are
++reported to ALL the specified/default target collectors. There's no way to
++exclude these from being reported other than by disabling the reporting of
++usage metrics altogether:
++.Pp
++.It
++.Cm Component code
++.Sm off
++- 12 for GSI OpenSSH
++.Sm on
++.It
++.Cm Component Data Format version
++.Sm off
++- 0 currently
++.Sm on
++.It
++.Cm IP Address
++.Sm off
++- IP address of reporting server
++.Sm on
++.It
++.Cm Timestamp
++.It
++.Cm Hostname
++.Sm off
++- Host name of reporting server
++.Sm on
++.Pp
++If no tags are specified in a host spec, or the special string
++.Dq default
++is specified, the tags
++.Dq VvMm
++are assumed. A site could choose to allow a
++different set of data to be reported by specifying a different tag set. The
++last 3 tags
++.Dq I ,
++.Dq u
++and
++.Dq U
++above are more meant for a local collector that a
++site might like to deploy since they could be construed as private information.
++The special string
++.Dq all
++denotes all tags.
++.El
++.Pp
++By default, Usage Metrics reporting is sent to
++.Dq usage-stats.cilogon.org:4810 .
++This can be made explicit by specifying
++.Dq default
++(all by itself) for the
++target specification as in:
++.Pp
++.Bl -item -offset indent -compact
++.It
++.Cm UsageStatsTargets
++.Sm off
++default
++.Sm on
++.El
++.Pp
++If
++.Cm UsageStatsTargets
++is not specified, a comma-separated list of targets
++(without any tags specified) if specified in the environment variable
++.Cm GLOBUS_USAGE_TARGETS
++will be used.
++.Pp
+ .It Cm TrustedUserCAKeys
+ Specifies a file containing public keys of certificate authorities that are
+ trusted to sign user certificates for authentication.
+@@ -1182,6 +1326,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.9p1.orig/ssh-globus-usage.c openssh-5.9p1/ssh-globus-usage.c
+--- openssh-5.9p1.orig/ssh-globus-usage.c	1970-01-01 01:00:00.000000000 +0100
++++ openssh-5.9p1/ssh-globus-usage.c	2011-11-17 16:59:47.519790948 +0100
+@@ -0,0 +1,396 @@
++/*
++ * Copyright 2009 The Board of Trustees of the University
++ * of Illinois.  See the LICENSE file for detailed license information.
++ *
++ * Portions, specifically log_usage_stats(), ssh_usage_stats_init(),
++ * ssh_usage_stats_close(), ssh_usage_ent_s, ssh_usage_tag_e and
++ * TAG #defines were based on those from Usage Metrics portions of:
++ * gridftp/server/source/globus_i_gfs_log.c
++ *
++ * Copyright 1999-2006 University of Chicago
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include "includes.h"
++
++#ifdef HAVE_GLOBUS_USAGE
++
++#include <stdarg.h>
++#include <unistd.h> 
++
++#include "log.h"
++#include "ssh-globus-usage.h"
++
++static globus_list_t *usage_handle_list = NULL;
++
++#define SSH_GLOBUS_USAGE_ID 12
++#define SSH_GLOBUS_USAGE_VER 0
++
++#define SSH_GLOBUS_DEFAULT_TAGLIST "VvMm"
++#define SSH_GLOBUS_ALL_TAGLIST     "VvMmIuU"
++#define SSH_GLOBUS_TAGCOUNT 25
++
++typedef enum ssh_usage_tag_e
++{
++    SSH_GLOBUS_USAGE_SSH_VER        = 'V',
++    SSH_GLOBUS_USAGE_SSL_VER        = 'v',
++    SSH_GLOBUS_USAGE_METHOD         = 'M',
++    SSH_GLOBUS_USAGE_MECHANISM      = 'm',
++    SSH_GLOBUS_USAGE_CLIENTIP       = 'I',
++    SSH_GLOBUS_USAGE_USERNAME       = 'u',
++    SSH_GLOBUS_USAGE_USERDN         = 'U'
++    /* !! ADD to ALL_TAGLIST above and to globus_usage_stats_send()
++          invocation below when adding here */
++} ssh_usage_tag_t;
++
++typedef struct ssh_usage_ent_s
++{
++    globus_usage_stats_handle_t         handle;
++    char *                              target;
++    char *                              taglist;
++} ssh_usage_ent_t;
++
++
++globus_result_t
++ssh_usage_stats_init(int disable_usage_stats, char *usage_stats_targets)
++{
++    globus_result_t                     result;
++    char *                              target_str = NULL;
++    char *                              ptr = ptr;
++    char *                              target = NULL;
++    char *                              entry = NULL;
++    globus_list_t *                     list = NULL;
++    ssh_usage_ent_t *               usage_ent = NULL;
++
++    if (disable_usage_stats)
++	return GLOBUS_SUCCESS;
++
++    result = globus_module_activate(GLOBUS_USAGE_MODULE);
++    if (result != GLOBUS_SUCCESS)
++    {
++        error("ERROR: couldn't activate USAGE STATS module");
++        return result;
++    }
++
++    if (!usage_stats_targets ||
++        !strcasecmp(usage_stats_targets, "default"))
++        target_str = strdup(CILOGON_COLLECTOR);
++    else
++        target_str = strdup(usage_stats_targets);
++
++    if (target_str == NULL)
++    {
++        error("ERROR: strdup failure for target_str");
++        goto error;
++    }
++    debug("Processing usage_stats_target (%s)\n", target_str);
++
++    if(target_str && (strchr(target_str, ',') || strchr(target_str, '!')))
++    {
++        target = target_str;
++
++        do {
++            usage_ent = (ssh_usage_ent_t *) malloc(sizeof(ssh_usage_ent_t));
++            if (usage_ent == NULL)
++            {
++                error("ERROR: couldn't allocate for ssh_usage_ent_t");
++                goto error;
++            }
++
++            if ((ptr = strchr(target, ',')) != NULL)
++                *ptr = '\0';
++
++            entry = strdup(target);
++            if (entry == NULL)
++            {
++                error("ERROR: strdup failure for target");
++                goto error;
++            }
++
++            if (ptr)
++                target = ptr + 1;
++            else
++                target = NULL;
++
++            if((ptr = strchr(entry, '!')) != NULL)
++            {
++                *ptr = '\0';
++                usage_ent->taglist = strdup(ptr + 1);
++                if (usage_ent->taglist == NULL)
++                {
++                    error("ERROR: strdup failure for taglist");
++                    goto error;
++                }
++                if(strlen(usage_ent->taglist) > SSH_GLOBUS_TAGCOUNT)
++                {
++                    usage_ent->taglist[SSH_GLOBUS_TAGCOUNT + 1] = '\0';
++                }
++            }
++            else
++            {
++                usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST);
++                if (usage_ent->taglist == NULL)
++                {
++                    error("ERROR: couldn't allocate for taglist");
++                    goto error;
++                }
++            }
++            
++            if(strcasecmp(usage_ent->taglist, "default") == 0)
++            {
++                free(usage_ent->taglist);
++                usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST);
++                if (usage_ent->taglist == NULL)
++                {
++                    error("ERROR: couldn't allocate for taglist");
++                    goto error;
++                }
++            }                
++            else if(strcasecmp(usage_ent->taglist, "all") == 0)
++            {
++                free(usage_ent->taglist);
++                usage_ent->taglist = strdup(SSH_GLOBUS_ALL_TAGLIST);
++                if (usage_ent->taglist == NULL)
++                {
++                    error("ERROR: couldn't allocate for taglist");
++                    goto error;
++                }
++            }
++            
++            usage_ent->target = entry;
++
++            globus_list_insert(&usage_handle_list, usage_ent);
++        }
++        while(target != NULL);
++
++        free(target_str);
++    }
++    else
++    {
++        usage_ent = (ssh_usage_ent_t *) malloc(sizeof(ssh_usage_ent_t));
++        if (usage_ent == NULL)
++        {
++             error("ERROR: couldn't allocate for usage_ent");
++             goto error;
++        }
++
++        usage_ent->target = target_str;
++        usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST);
++        if (usage_ent->taglist == NULL)
++        {
++             error("ERROR: couldn't allocate for taglist");
++             goto error;
++        }
++
++        globus_list_insert(&usage_handle_list, usage_ent);
++    }
++
++    result = GLOBUS_SUCCESS;
++    for(list = usage_handle_list;
++        !globus_list_empty(list);
++        list = globus_list_rest(list))
++    {
++        usage_ent = (ssh_usage_ent_t *) globus_list_first(list);
++
++        usage_ent->handle = NULL;
++        if (globus_usage_stats_handle_init(
++            &usage_ent->handle,
++            SSH_GLOBUS_USAGE_ID,
++            SSH_GLOBUS_USAGE_VER,
++            usage_ent->target) != GLOBUS_SUCCESS)
++        {
++            error("USAGE-STATS: Error initializing (%s) (%s)",
++                     usage_ent->target?:"NULL",
++                     usage_ent->taglist?:"NULL");
++            result = GLOBUS_FAILURE;
++        } else
++            debug("USAGE-STATS: Initialized (%s) (%s)", usage_ent->target?:"NULL",
++                     usage_ent->taglist?:"NULL");
++
++    }
++
++    return result;
++
++error:
++    if (target_str)
++    {
++        free(target_str); 
++        target_str = NULL;
++    }
++    if (entry)
++    {
++        free(target_str); 
++        target_str = NULL;
++    }
++    return GLOBUS_FAILURE;
++}
++
++void
++ssh_usage_stats_close(int disable_usage_stats)
++{
++    globus_list_t *list;
++
++    if (disable_usage_stats)
++	return;
++
++    list = usage_handle_list;
++    
++    while(!globus_list_empty(list))
++    {
++        ssh_usage_ent_t *usage_ent;
++        
++        usage_ent = (ssh_usage_ent_t *) 
++            globus_list_remove(&list, list);
++    
++        if(usage_ent)
++        {
++            if(usage_ent->handle)
++            {
++                globus_usage_stats_handle_destroy(usage_ent->handle);
++            }
++            if(usage_ent->target)
++            {
++                free(usage_ent->target);
++            }
++            if(usage_ent->taglist)
++            {
++                free(usage_ent->taglist);
++            }
++            free(usage_ent);
++        }
++    }
++    usage_handle_list = NULL;
++}
++
++static void
++log_usage_stats(char *ssh_release, const char *ssl_release,
++                char *method, char *mechanism, const char *clientip,
++                char *username, char *userdn)
++{
++    globus_result_t                     result;
++    globus_list_t *                     list;
++    ssh_usage_ent_t *                   usage_ent;
++    char *                              keys[SSH_GLOBUS_TAGCOUNT];
++    char *                              values[SSH_GLOBUS_TAGCOUNT];
++    char *                              ptr;
++    char *                              key;
++    char *                              value;
++    int                                 i = 0;
++    char *                              save_taglist = NULL;
++
++    for(list = usage_handle_list;
++        !globus_list_empty(list);
++        list = globus_list_rest(list))
++    {
++        usage_ent = (ssh_usage_ent_t *) globus_list_first(list);
++
++        if(!usage_ent || usage_ent->handle == NULL)
++            continue;
++        
++        if(save_taglist == NULL || 
++            strcmp(save_taglist, usage_ent->taglist) != 0)
++        {
++            save_taglist = usage_ent->taglist;
++            
++            ptr = usage_ent->taglist;
++            i = 0;
++            while(ptr && *ptr)
++            {
++                switch(*ptr)
++                {
++                  case SSH_GLOBUS_USAGE_SSH_VER:
++                    key = "SSH_VER";
++                    value = ssh_release;
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_SSL_VER:
++                    key = "SSL_VER";
++                    value = (char *) ssl_release;
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_METHOD:
++                    key = "METHOD";
++                    value = method;
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_MECHANISM:
++                    key = "MECH";
++                    value = mechanism?:"";
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_CLIENTIP:
++                    key = "CLIENTIP";
++                    value = (char *) clientip?:"";
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_USERNAME:
++                    key = "USER";
++                    value = username?:"";
++                    break;
++    
++                  case SSH_GLOBUS_USAGE_USERDN:
++                    key = "USERDN";
++                    value = userdn?:"";
++                    break;
++    
++                  default:
++                    key = NULL;
++                    value = NULL;
++                    break;
++                }
++                
++                if(key != NULL && value != NULL)
++                {
++                    keys[i] = key;
++                    values[i] = value;
++                    i++;
++                }
++                
++                ptr++;
++            }
++        }
++
++#ifdef HAVE_GLOBUS_USAGE_SEND_ARRAY
++        result = globus_usage_stats_send_array(
++            usage_ent->handle, i, keys, values);
++#else
++        if (i)
++            result = globus_usage_stats_send(
++                usage_ent->handle, i,
++                i>0?keys[0]:NULL, i>0?values[0]:NULL,
++                i>1?keys[1]:NULL, i>1?values[1]:NULL,
++                i>2?keys[2]:NULL, i>2?values[2]:NULL,
++                i>3?keys[3]:NULL, i>3?values[3]:NULL,
++                i>4?keys[4]:NULL, i>4?values[4]:NULL,
++                i>5?keys[5]:NULL, i>5?values[5]:NULL,
++                i>6?keys[6]:NULL, i>6?values[6]:NULL);
++#endif /* HAVE_GLOBUS_USAGE_SEND_ARRAY */
++    }
++    
++    return;
++}
++#endif /* HAVE_GLOBUS_USAGE */
++
++void
++ssh_globus_send_usage_metrics(char *ssh_release, const char *ssl_release,
++                              char *method, char *mechanism, const char *client_ip,
++                              char *username, char *userdn)
++{
++#ifdef HAVE_GLOBUS_USAGE
++
++    log_usage_stats(ssh_release, ssl_release, method, mechanism,
++                    client_ip, username, userdn);
++
++#endif /* HAVE_GLOBUS_USAGE */
++}
+diff -Nur openssh-5.9p1.orig/ssh-globus-usage.h openssh-5.9p1/ssh-globus-usage.h
+--- openssh-5.9p1.orig/ssh-globus-usage.h	1970-01-01 01:00:00.000000000 +0100
++++ openssh-5.9p1/ssh-globus-usage.h	2011-11-17 16:59:47.519790948 +0100
+@@ -0,0 +1,46 @@
++/*
++ * Copyright 2009 The Board of Trustees of the University
++ * of Illinois.  See the LICENSE file for detailed license information.
++ *
++ * Portions, specifically ssh_usage_stats_init(), ssh_usage_stats_close()
++ * were based on those from: gridftp/server/source/globus_i_gfs_log.h
++ * Copyright 1999-2006 University of Chicago
++ * 
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ * 
++ * http://www.apache.org/licenses/LICENSE-2.0
++ * 
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef __SSH_GLOBUS_USAGE_H
++#define __SSH_GLOBUS_USAGE_H
++
++#include "includes.h"
++
++#ifdef HAVE_GLOBUS_USAGE
++
++#include "globus_usage.h"
++
++#define CILOGON_COLLECTOR "usage-stats.cilogon.org:4810"
++
++globus_result_t
++ssh_usage_stats_init(int disable_usage_stats, char *usage_stats_targets);
++
++void
++ssh_usage_stats_close(int disable_usage_stats);
++
++#endif /* HAVE_GLOBUS_USAGE */
++
++void
++ssh_globus_send_usage_metrics(char *ssh_release, const char *ssl_release,
++                           char *method, char *mechanism, const char *client_ip,
++                           char *username, char *userdn);
++
++#endif /* __SSH_GLOBUS_USAGE_H */
+diff -Nur openssh-5.9p1.orig/ssh-gss.h openssh-5.9p1/ssh-gss.h
+--- openssh-5.9p1.orig/ssh-gss.h	2011-11-17 16:58:30.493799683 +0100
++++ openssh-5.9p1/ssh-gss.h	2011-11-17 16:59:47.520790935 +0100
+@@ -90,6 +90,7 @@
+ 	gss_name_t name;
+ 	struct ssh_gssapi_mech_struct *mech;
+ 	ssh_gssapi_ccache store;
++	gss_ctx_id_t context; /* needed for globus_gss_assist_map_and_authorize() */
+ 	int used;
+ 	int updated;
+ } ssh_gssapi_client;
+@@ -110,7 +111,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 */
+@@ -141,6 +142,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 *);
+@@ -151,7 +155,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);
+@@ -161,6 +165,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.9p1.orig/version.h openssh-5.9p1/version.h
+--- openssh-5.9p1.orig/version.h	2011-09-07 01:11:20.000000000 +0200
++++ openssh-5.9p1/version.h	2011-11-17 16:59:47.520790935 +0100
+@@ -1,5 +1,19 @@
+ /* $OpenBSD: version.h,v 1.62 2011/08/02 23:13:01 djm Exp $ */
+ 
++#ifdef GSI
++#define GSI_VERSION	" GSI"
++#else
++#define GSI_VERSION	""
++#endif
++
++#ifdef KRB5
++#define KRB5_VERSION	" KRB5"
++#else
++#define KRB5_VERSION	""
++#endif
++
++#define NCSA_VERSION	" GSI_GSSAPI_20110906"
++
+ #define SSH_VERSION	"OpenSSH_5.9"
+ 
+ #define SSH_PORTABLE	"p1"
diff --git a/openssh-5.9p1-gsskex.patch b/openssh-5.9p1-gsskex.patch
new file mode 100644
index 0000000..c7ac7e2
--- /dev/null
+++ b/openssh-5.9p1-gsskex.patch
@@ -0,0 +1,2932 @@
+diff -up openssh-5.9p0/ChangeLog.gssapi.gsskex openssh-5.9p0/ChangeLog.gssapi
+--- openssh-5.9p0/ChangeLog.gssapi.gsskex	2011-09-03 20:30:47.817440618 +0200
++++ openssh-5.9p0/ChangeLog.gssapi	2011-09-03 20:30:47.843489156 +0200
+@@ -0,0 +1,113 @@
++20110101
++  - Finally update for OpenSSH 5.6p1
++  - Add GSSAPIServerIdentity option from Jim Basney
++ 
++20100308
++  - [ Makefile.in, key.c, key.h ]
++    Updates for OpenSSH 5.4p1
++  - [ servconf.c ]
++    Include GSSAPI options in the sshd -T configuration dump, and flag
++    some older configuration options as being unsupported. Thanks to Colin 
++    Watson.
++  -
++
++20100124
++  - [ sshconnect2.c ]
++    Adapt to deal with additional element in Authmethod structure. Thanks to
++    Colin Watson
++
++20090615
++  - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c
++      sshd.c ]
++    Fix issues identified by Greg Hudson following a code review
++	Check return value of gss_indicate_mechs
++	Protect GSSAPI calls in monitor, so they can only be used if enabled
++	Check return values of bignum functions in key exchange
++	Use BN_clear_free to clear other side's DH value
++	Make ssh_gssapi_id_kex more robust
++	Only configure kex table pointers if GSSAPI is enabled
++	Don't leak mechanism list, or gss mechanism list
++	Cast data.length before printing
++	If serverkey isn't provided, use an empty string, rather than NULL
++
++20090201
++  - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h
++      ssh_config.5 sshconnet2.c ]
++    Add support for the GSSAPIClientIdentity option, which allows the user
++    to specify which GSSAPI identity to use to contact a given server
++
++20080404
++  - [ gss-serv.c ]
++    Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow
++    been omitted from a previous version of this patch. Reported by Borislav
++    Stoichkov
++
++20070317
++  - [ gss-serv-krb5.c ]
++    Remove C99ism, where new_ccname was being declared in the middle of a 
++    function
++
++20061220
++  - [ servconf.c ]
++    Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and 
++    documented, behaviour. Reported by Dan Watson.
++
++20060910
++  - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c
++      ssh-gss.h ]
++    add support for gss-group14-sha1 key exchange mechanisms
++  - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ]
++    Add GSSAPIStrictAcceptorCheck option to allow the disabling of
++    acceptor principal checking on multi-homed machines.
++    <Bugzilla #928>
++  - [ sshd_config ssh_config ]
++    Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample
++    configuration files
++  - [ kexgss.c kegsss.c sshconnect2.c sshd.c ]
++    Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf()
++    Limit length of error messages displayed by client
++
++20060909
++  - [ gss-genr.c gss-serv.c ]
++    move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server
++    only, where they belong 
++    <Bugzilla #1225>
++
++20060829
++  - [ gss-serv-krb5.c ]
++    Fix CCAPI credentials cache name when creating KRB5CCNAME environment 
++    variable
++
++20060828
++  - [ gss-genr.c ]
++    Avoid Heimdal context freeing problem
++    <Fixed upstream 20060829>
++
++20060818
++  - [ gss-genr.c ssh-gss.h sshconnect2.c ]
++    Make sure that SPENGO is disabled 
++    <Bugzilla #1218 - Fixed upstream 20060818>
++
++20060421
++  - [ gssgenr.c, sshconnect2.c ]
++    a few type changes (signed versus unsigned, int versus size_t) to
++    fix compiler errors/warnings 
++    (from jbasney AT ncsa.uiuc.edu)
++  - [ kexgssc.c, sshconnect2.c ]
++    fix uninitialized variable warnings
++    (from jbasney AT ncsa.uiuc.edu)
++  - [ gssgenr.c ]
++    pass oid to gss_display_status (helpful when using GSSAPI mechglue)
++    (from jbasney AT ncsa.uiuc.edu)
++    <Bugzilla #1220 >
++  - [ gss-serv-krb5.c ]
++    #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H
++    (from jbasney AT ncsa.uiuc.edu)
++    <Fixed upstream 20060304>
++  - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c 
++    add client-side GssapiKeyExchange option
++    (from jbasney AT ncsa.uiuc.edu)
++  - [ sshconnect2.c ]
++    add support for GssapiTrustDns option for gssapi-with-mic
++    (from jbasney AT ncsa.uiuc.edu)
++    <gssapi-with-mic support is Bugzilla #1008>
+diff -up openssh-5.9p0/Makefile.in.gsskex openssh-5.9p0/Makefile.in
+--- openssh-5.9p0/Makefile.in.gsskex	2011-09-03 20:30:41.636439385 +0200
++++ openssh-5.9p0/Makefile.in	2011-09-03 20:30:47.923501149 +0200
+@@ -74,6 +74,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-ecdsa.o ssh-rsa.o dh.o \
+ 	kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \
++	kexgssc.o \
+ 	msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o jpake.o \
+ 	schnorr.o ssh-pkcs11.o auditstub.o
+ 
+@@ -90,7 +91,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 kexecdhs.o \
+ 	auth-krb5.o \
+-	auth2-gss.o gss-serv.o gss-serv-krb5.o \
++	auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\
+ 	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
+ 	sftp-server.o sftp-common.o \
+ 	roaming_common.o roaming_serv.o \
+diff -up openssh-5.9p0/auth-krb5.c.gsskex openssh-5.9p0/auth-krb5.c
+--- openssh-5.9p0/auth-krb5.c.gsskex	2009-12-21 00:49:22.000000000 +0100
++++ openssh-5.9p0/auth-krb5.c	2011-09-03 20:30:48.038503119 +0200
+@@ -170,8 +170,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)
+@@ -226,15 +231,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);
+@@ -249,6 +261,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_c
+ 		return errno;
+ 	}
+ 	close(tmpfd);
++#endif
+ 
+ 	return (krb5_cc_resolve(ctx, ccname, ccache));
+ }
+diff -up openssh-5.9p0/auth2-gss.c.gsskex openssh-5.9p0/auth2-gss.c
+--- openssh-5.9p0/auth2-gss.c.gsskex	2011-09-03 20:30:32.938448441 +0200
++++ openssh-5.9p0/auth2-gss.c	2011-09-03 20:30:48.173461037 +0200
+@@ -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)
+@@ -244,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);
+@@ -286,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");
+ 
+@@ -303,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.9p0/auth2.c.gsskex openssh-5.9p0/auth2.c
+--- openssh-5.9p0/auth2.c.gsskex	2011-09-03 20:30:33.358627098 +0200
++++ openssh-5.9p0/auth2.c	2011-09-03 20:30:48.386436741 +0200
+@@ -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
+diff -up openssh-5.9p0/clientloop.c.gsskex openssh-5.9p0/clientloop.c
+--- openssh-5.9p0/clientloop.c.gsskex	2011-06-23 00:31:58.000000000 +0200
++++ openssh-5.9p0/clientloop.c	2011-09-03 20:30:48.595502066 +0200
+@@ -111,6 +111,10 @@
+ #include "msg.h"
+ #include "roaming.h"
+ 
++#ifdef GSSAPI
++#include "ssh-gss.h"
++#endif
++
+ /* import options */
+ extern Options options;
+ 
+@@ -1508,6 +1512,15 @@ client_loop(int have_pty, int escape_cha
+ 		/* Do channel operations unless rekeying in progress. */
+ 		if (!rekeying) {
+ 			channel_after_select(readset, writeset);
++
++#ifdef GSSAPI
++			if (options.gss_renewal_rekey &&
++			    ssh_gssapi_credentials_updated(GSS_C_NO_CONTEXT)) {
++				debug("credentials updated - forcing rekey");
++				need_rekeying = 1;
++			}
++#endif
++
+ 			if (need_rekeying || packet_need_rekeying()) {
+ 				debug("need rekeying");
+ 				xxx_kex->done = 0;
+diff -up openssh-5.9p0/configure.ac.gsskex openssh-5.9p0/configure.ac
+--- openssh-5.9p0/configure.ac.gsskex	2011-09-03 20:30:46.489501732 +0200
++++ openssh-5.9p0/configure.ac	2011-09-03 20:30:48.783501901 +0200
+@@ -515,6 +515,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.9p0/gss-genr.c.gsskex openssh-5.9p0/gss-genr.c
+--- openssh-5.9p0/gss-genr.c.gsskex	2009-06-22 08:11:07.000000000 +0200
++++ openssh-5.9p0/gss-genr.c	2011-09-03 20:30:48.951554007 +0200
+@@ -1,7 +1,7 @@
+ /* $OpenBSD: gss-genr.c,v 1.20 2009/06/22 05:39:28 dtucker Exp $ */
+ 
+ /*
+- * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
++ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+@@ -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.9p0/gss-serv-krb5.c.gsskex openssh-5.9p0/gss-serv-krb5.c
+--- openssh-5.9p0/gss-serv-krb5.c.gsskex	2006-09-01 07:38:36.000000000 +0200
++++ openssh-5.9p0/gss-serv-krb5.c	2011-09-03 20:30:49.134564925 +0200
+@@ -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.9p0/gss-serv.c.gsskex openssh-5.9p0/gss-serv.c
+--- openssh-5.9p0/gss-serv.c.gsskex	2011-08-05 22:16:46.000000000 +0200
++++ openssh-5.9p0/gss-serv.c	2011-09-03 20:30:49.261439762 +0200
+@@ -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,
+@@ -249,8 +286,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);
++
++		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_buffer_desc ename;
++		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;
+ 
+@@ -265,6 +342,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);
+@@ -282,6 +366,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;
+@@ -329,7 +415,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;
+ 
+@@ -339,9 +425,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);
+@@ -354,14 +442,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.9p0/kex.c.gsskex openssh-5.9p0/kex.c
+--- openssh-5.9p0/kex.c.gsskex	2011-09-03 20:30:28.322627701 +0200
++++ openssh-5.9p0/kex.c	2011-09-03 20:30:49.522466612 +0200
+@@ -51,6 +51,10 @@
+ #include "roaming.h"
+ #include "audit.h"
+ 
++#ifdef GSSAPI
++#include "ssh-gss.h"
++#endif
++
+ #if OPENSSL_VERSION_NUMBER >= 0x00907000L
+ # if defined(HAVE_EVP_SHA256)
+ # define evp_ssh_sha256 EVP_sha256
+@@ -371,6 +375,20 @@ choose_kex(Kex *k, char *client, char *s
+  		k->kex_type = KEX_ECDH_SHA2;
+ 		k->evp_md = kex_ecdh_name_to_evpmd(k->name);
+ #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 openssh-5.9p0/kex.h.gsskex openssh-5.9p0/kex.h
+--- openssh-5.9p0/kex.h.gsskex	2011-09-03 20:30:28.429502160 +0200
++++ openssh-5.9p0/kex.h	2011-09-03 20:30:49.719501645 +0200
+@@ -73,6 +73,9 @@ enum kex_exchange {
+ 	KEX_DH_GEX_SHA1,
+ 	KEX_DH_GEX_SHA256,
+ 	KEX_ECDH_SHA2,
++	KEX_GSS_GRP1_SHA1,
++	KEX_GSS_GRP14_SHA1,
++	KEX_GSS_GEX_SHA1,
+ 	KEX_MAX
+ };
+ 
+@@ -129,6 +132,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 *);
+@@ -156,6 +165,11 @@ void	 kexgex_server(Kex *);
+ void	 kexecdh_client(Kex *);
+ void	 kexecdh_server(Kex *);
+ 
++#ifdef GSSAPI
++void	kexgss_client(Kex *);
++void	kexgss_server(Kex *);
++#endif
++
+ void	newkeys_destroy(Newkeys *newkeys);
+ 
+ void
+diff -up openssh-5.9p0/kexgssc.c.gsskex openssh-5.9p0/kexgssc.c
+--- openssh-5.9p0/kexgssc.c.gsskex	2011-09-03 20:30:49.951501851 +0200
++++ openssh-5.9p0/kexgssc.c	2011-09-03 20:30:49.956501669 +0200
+@@ -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 ((int)kout < 0)
++		fatal("DH_compute_key: failed");
++
++	shared_secret = BN_new();
++	if (shared_secret == NULL)
++		fatal("kexgss_client: BN_new failed");
++
++	if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
++		fatal("kexdh_client: BN_bin2bn failed");
++
++	memset(kbuf, 0, klen);
++	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 openssh-5.9p0/kexgsss.c.gsskex openssh-5.9p0/kexgsss.c
+--- openssh-5.9p0/kexgsss.c.gsskex	2011-09-03 20:30:50.062501851 +0200
++++ openssh-5.9p0/kexgsss.c	2011-09-03 20:30:50.067500552 +0200
+@@ -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 ((int)kout < 0)
++		fatal("DH_compute_key: failed");
++
++	shared_secret = BN_new();
++	if (shared_secret == NULL)
++		fatal("kexgss_server: BN_new failed");
++
++	if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
++		fatal("kexgss_server: BN_bin2bn failed");
++
++	memset(kbuf, 0, klen);
++	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.9p0/key.c.gsskex openssh-5.9p0/key.c
+--- openssh-5.9p0/key.c.gsskex	2011-09-03 20:30:42.237461404 +0200
++++ openssh-5.9p0/key.c	2011-09-03 20:30:50.257564328 +0200
+@@ -1004,6 +1004,8 @@ key_ssh_name_from_type_nid(int type, int
+ 		}
+ 		break;
+ #endif /* OPENSSL_HAS_ECC */
++	case KEY_NULL:
++		return "null";
+ 	}
+ 	return "ssh-unknown";
+ }
+@@ -1309,6 +1311,8 @@ key_type_from_name(char *name)
+ 	    strcmp(name, "ecdsa-sha2-nistp521-cert-v01 at openssh.com") == 0) {
+ 		return KEY_ECDSA_CERT;
+ #endif
++	} else if (strcmp(name, "null") == 0) {
++		return KEY_NULL;
+ 	}
+ 
+ 	debug2("key_type_from_name: unknown key type '%s'", name);
+diff -up openssh-5.9p0/key.h.gsskex openssh-5.9p0/key.h
+--- openssh-5.9p0/key.h.gsskex	2011-09-03 20:30:30.877627339 +0200
++++ openssh-5.9p0/key.h	2011-09-03 20:30:50.364564076 +0200
+@@ -44,6 +44,7 @@ enum types {
+ 	KEY_ECDSA_CERT,
+ 	KEY_RSA_CERT_V00,
+ 	KEY_DSA_CERT_V00,
++	KEY_NULL,
+ 	KEY_UNSPEC
+ };
+ enum fp_type {
+diff -up openssh-5.9p0/monitor.c.gsskex openssh-5.9p0/monitor.c
+--- openssh-5.9p0/monitor.c.gsskex	2011-09-03 20:30:33.495451533 +0200
++++ openssh-5.9p0/monitor.c	2011-09-03 20:30:50.494501810 +0200
+@@ -187,6 +187,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
+@@ -270,6 +272,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},
+@@ -283,6 +286,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},
+@@ -405,6 +414,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;
+ 
+@@ -505,6 +518,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);
+@@ -1920,6 +1937,13 @@ mm_get_kex(Buffer *m)
+ 	kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
+ 	kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
+ 	kex->kex[KEX_ECDH_SHA2] = kexecdh_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);
+@@ -2151,6 +2175,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;
+ 
+@@ -2178,6 +2205,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);
+@@ -2195,6 +2225,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);
+ }
+@@ -2206,6 +2237,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);
+@@ -2232,7 +2266,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);
+@@ -2245,6 +2283,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.9p0/monitor.h.gsskex openssh-5.9p0/monitor.h
+--- openssh-5.9p0/monitor.h.gsskex	2011-09-03 20:30:33.604501395 +0200
++++ openssh-5.9p0/monitor.h	2011-09-03 20:30:50.619494143 +0200
+@@ -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.9p0/monitor_wrap.c.gsskex openssh-5.9p0/monitor_wrap.c
+--- openssh-5.9p0/monitor_wrap.c.gsskex	2011-09-03 20:30:33.751439358 +0200
++++ openssh-5.9p0/monitor_wrap.c	2011-09-03 20:30:50.775502083 +0200
+@@ -1346,7 +1346,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;
+@@ -1363,6 +1363,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.9p0/monitor_wrap.h.gsskex openssh-5.9p0/monitor_wrap.h
+--- openssh-5.9p0/monitor_wrap.h.gsskex	2011-09-03 20:30:33.849563456 +0200
++++ openssh-5.9p0/monitor_wrap.h	2011-09-03 20:30:50.888502327 +0200
+@@ -63,8 +63,10 @@ void mm_userauth_restart(const char *);
+ 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.9p0/readconf.c.gsskex openssh-5.9p0/readconf.c
+--- openssh-5.9p0/readconf.c.gsskex	2011-05-29 13:42:31.000000000 +0200
++++ openssh-5.9p0/readconf.c	2011-09-03 20:30:51.018475602 +0200
+@@ -129,6 +129,8 @@ typedef enum {
+ 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
+ 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
+ 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
++	oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey,
++	oGssServerIdentity, 
+ 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
+ 	oSendEnv, oControlPath, oControlMaster, oControlPersist,
+ 	oHashKnownHosts,
+@@ -169,10 +171,19 @@ static struct {
+ 	{ "afstokenpassing", oUnsupported },
+ #if defined(GSSAPI)
+ 	{ "gssapiauthentication", oGssAuthentication },
++	{ "gssapikeyexchange", oGssKeyEx },
+ 	{ "gssapidelegatecredentials", oGssDelegateCreds },
++	{ "gssapitrustdns", oGssTrustDns },
++	{ "gssapiclientidentity", oGssClientIdentity },
++	{ "gssapiserveridentity", oGssServerIdentity },
++	{ "gssapirenewalforcesrekey", oGssRenewalRekey },
+ #else
+ 	{ "gssapiauthentication", oUnsupported },
++	{ "gssapikeyexchange", oUnsupported },
+ 	{ "gssapidelegatecredentials", oUnsupported },
++	{ "gssapitrustdns", oUnsupported },
++	{ "gssapiclientidentity", oUnsupported },
++	{ "gssapirenewalforcesrekey", oUnsupported },
+ #endif
+ 	{ "fallbacktorsh", oDeprecated },
+ 	{ "usersh", oDeprecated },
+@@ -482,10 +493,30 @@ 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 oGssServerIdentity:
++		charptr = &options->gss_server_identity;
++		goto parse_string;
++
++	case oGssRenewalRekey:
++		intptr = &options->gss_renewal_rekey;
++		goto parse_flag;
++
+ 	case oBatchMode:
+ 		intptr = &options->batch_mode;
+ 		goto parse_flag;
+@@ -1138,7 +1169,12 @@ initialize_options(Options * options)
+ 	options->pubkey_authentication = -1;
+ 	options->challenge_response_authentication = -1;
+ 	options->gss_authentication = -1;
++	options->gss_keyex = -1;
+ 	options->gss_deleg_creds = -1;
++	options->gss_trust_dns = -1;
++	options->gss_renewal_rekey = -1;
++	options->gss_client_identity = NULL;
++	options->gss_server_identity = NULL;
+ 	options->password_authentication = -1;
+ 	options->kbd_interactive_authentication = -1;
+ 	options->kbd_interactive_devices = NULL;
+@@ -1238,8 +1274,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.9p0/readconf.h.gsskex openssh-5.9p0/readconf.h
+--- openssh-5.9p0/readconf.h.gsskex	2011-05-29 13:42:33.000000000 +0200
++++ openssh-5.9p0/readconf.h	2011-09-03 20:30:51.121501216 +0200
+@@ -47,7 +47,12 @@ typedef struct {
+ 	int     challenge_response_authentication;
+ 					/* Try S/Key or TIS, authentication. */
+ 	int     gss_authentication;	/* Try GSS authentication */
++	int     gss_keyex;		/* Try GSS key exchange */
+ 	int     gss_deleg_creds;	/* Delegate GSS credentials */
++	int	gss_trust_dns;		/* Trust DNS for GSS canonicalization */
++	int	gss_renewal_rekey;	/* Credential renewal forces rekey */
++	char    *gss_client_identity;   /* Principal to initiate GSSAPI with */
++	char    *gss_server_identity;   /* GSSAPI target principal */
+ 	int     password_authentication;	/* Try password
+ 						 * authentication. */
+ 	int     kbd_interactive_authentication; /* Try keyboard-interactive auth. */
+diff -up openssh-5.9p0/servconf.c.gsskex openssh-5.9p0/servconf.c
+--- openssh-5.9p0/servconf.c.gsskex	2011-09-03 20:30:46.652622175 +0200
++++ openssh-5.9p0/servconf.c	2011-09-03 20:33:28.089540342 +0200
+@@ -104,7 +104,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;
+@@ -235,8 +238,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)
+@@ -347,7 +356,9 @@ typedef enum {
+ 	sSecondPasswordAuthentication, sSecondKbdInteractiveAuthentication,
+ 	sSecondZeroKnowledgePasswordAuthentication, sSecondHostbasedAuthentication,
+ 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
+-	sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
++	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
++	sGssKeyEx, sGssStoreRekey,
++	sAcceptEnv, sPermitTunnel,
+ 	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
+ 	sUsePrivilegeSeparation, sAllowAgentForwarding,
+ 	sZeroKnowledgePasswordAuthentication, sHostCertificate,
+@@ -412,10 +423,20 @@ static struct {
+ #ifdef GSSAPI
+ 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
+ 	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
++	{ "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
++	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
++	{ "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
++	{ "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
+ #else
+ 	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
+ 	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
++	{ "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
++	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
++	{ "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
++	{ "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
+ #endif
++	{ "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
++	{ "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
+ 	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
+ 	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
+ 	{ "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
+@@ -1015,10 +1036,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;
+@@ -1830,6 +1863,9 @@ dump_config(ServerOptions *o)
+ 	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
+ 	dump_cfg_fmtint(sSecondGssAuthentication, o->second_gss_authentication);
+ 	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
++	dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
++	dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
++	dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey);
+ #endif
+ #ifdef JPAKE
+ 	dump_cfg_fmtint(sZeroKnowledgePasswordAuthentication,
+diff -up openssh-5.9p0/servconf.h.gsskex openssh-5.9p0/servconf.h
+--- openssh-5.9p0/servconf.h.gsskex	2011-09-03 20:30:46.822603704 +0200
++++ openssh-5.9p0/servconf.h	2011-09-03 20:30:51.430501923 +0200
+@@ -103,7 +103,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.9p0/ssh-gss.h.gsskex openssh-5.9p0/ssh-gss.h
+--- openssh-5.9p0/ssh-gss.h.gsskex	2007-06-12 15:40:39.000000000 +0200
++++ openssh-5.9p0/ssh-gss.h	2011-09-03 20:30:51.703513904 +0200
+@@ -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 -up openssh-5.9p0/ssh_config.5.gsskex openssh-5.9p0/ssh_config.5
+--- openssh-5.9p0/ssh_config.5.gsskex	2011-08-05 22:17:32.000000000 +0200
++++ openssh-5.9p0/ssh_config.5	2011-09-03 20:30:51.838501958 +0200
+@@ -527,11 +527,43 @@ 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 GSSAPIServerIdentity
++If set, specifies the GSSAPI server identity that ssh should expect when 
++connecting to the server. The default is unset, which means that the
++expected GSSAPI server identity will be determined from the target
++hostname.
+ .It Cm GSSAPIDelegateCredentials
+ Forward (delegate) credentials to the server.
+ The default is
+ .Dq no .
+-Note that this option applies to protocol version 2 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.9p0/ssh_config.gsskex openssh-5.9p0/ssh_config
+--- openssh-5.9p0/ssh_config.gsskex	2011-09-03 20:30:44.855596300 +0200
++++ openssh-5.9p0/ssh_config	2011-09-03 20:30:51.978439644 +0200
+@@ -26,6 +26,8 @@
+ #   HostbasedAuthentication no
+ #   GSSAPIAuthentication no
+ #   GSSAPIDelegateCredentials no
++#   GSSAPIKeyExchange no
++#   GSSAPITrustDNS no
+ #   BatchMode no
+ #   CheckHostIP yes
+ #   AddressFamily any
+diff -up openssh-5.9p0/sshconnect2.c.gsskex openssh-5.9p0/sshconnect2.c
+--- openssh-5.9p0/sshconnect2.c.gsskex	2011-09-03 20:30:42.893440087 +0200
++++ openssh-5.9p0/sshconnect2.c	2011-09-03 20:30:52.147454994 +0200
+@@ -162,9 +162,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;
+@@ -207,6 +232,17 @@ ssh_kex2(char *host, struct sockaddr *ho
+ 	if (options.kex_algorithms != NULL)
+ 		myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
+ 
++#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);
+ 
+@@ -217,10 +253,30 @@ ssh_kex2(char *host, struct sockaddr *ho
+ 	kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
+ 	kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
+ 	kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
++#ifdef GSSAPI
++	if (options.gss_keyex) {
++		kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
++		kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
++		kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
++	}
++#endif
+ 	kex->client_version_string=client_version_string;
+ 	kex->server_version_string=server_version_string;
+ 	kex->verify_host_key=&verify_host_key_callback;
+ 
++#ifdef GSSAPI
++	if (options.gss_keyex) {
++		kex->gss_deleg_creds = options.gss_deleg_creds;
++		kex->gss_trust_dns = options.gss_trust_dns;
++		kex->gss_client = options.gss_client_identity;
++		if (options.gss_server_identity) {
++			kex->gss_host = options.gss_server_identity;
++		} else {
++			kex->gss_host = gss_host;
++        }
++	}
++#endif
++
+ 	xxx_kex = kex;
+ 
+ 	dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
+@@ -315,6 +371,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 *);
+@@ -330,6 +387,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,
+@@ -637,19 +699,31 @@ userauth_gssapi(Authctxt *authctxt)
+ 	static u_int mech = 0;
+ 	OM_uint32 min;
+ 	int ok = 0;
++	const char *gss_host;
++
++	if (options.gss_server_identity)
++		gss_host = options.gss_server_identity;
++	else if (options.gss_trust_dns)
++		gss_host = get_canonical_hostname(1);
++	else
++		gss_host = authctxt->host;
+ 
+ 	/* Try one GSSAPI method at a time, rather than sending them all at
+ 	 * once. */
+ 
+ 	if (gss_supported == NULL)
+-		gss_indicate_mechs(&min, &gss_supported);
++		if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
++			gss_supported = NULL;
++			return 0;
++		}
+ 
+ 	/* Check to see if the mechanism is usable before we offer it */
+ 	while (mech < gss_supported->count && !ok) {
+ 		/* My DER encoding requires length<128 */
+ 		if (gss_supported->elements[mech].length < 128 &&
+ 		    ssh_gssapi_check_mechanism(&gssctxt, 
+-		    &gss_supported->elements[mech], authctxt->host)) {
++		    &gss_supported->elements[mech], gss_host, 
++                    options.gss_client_identity)) {
+ 			ok = 1; /* Mechanism works */
+ 		} else {
+ 			mech++;
+@@ -746,8 +820,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");
+@@ -857,6 +931,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.9p0/sshd.c.gsskex openssh-5.9p0/sshd.c
+--- openssh-5.9p0/sshd.c.gsskex	2011-09-03 20:30:46.968587856 +0200
++++ openssh-5.9p0/sshd.c	2011-09-03 20:30:52.340449797 +0200
+@@ -124,6 +124,10 @@
+ #include "ssh-sandbox.h"
+ #include "version.h"
+ 
++#ifdef USE_SECURITY_SESSION_API
++#include <Security/AuthSession.h>
++#endif
++
+ #ifdef LIBWRAP
+ #include <tcpd.h>
+ #include <syslog.h>
+@@ -1680,10 +1684,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);
+@@ -2016,6 +2023,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
+@@ -2414,6 +2475,48 @@ 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;
+@@ -2421,6 +2524,13 @@ do_ssh2_kex(void)
+ 	kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
+ 	kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
+ 	kex->kex[KEX_ECDH_SHA2] = kexecdh_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.9p0/sshd_config.5.gsskex openssh-5.9p0/sshd_config.5
+--- openssh-5.9p0/sshd_config.5.gsskex	2011-09-03 20:30:47.419537225 +0200
++++ openssh-5.9p0/sshd_config.5	2011-09-03 20:30:52.608440675 +0200
+@@ -424,12 +424,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.9p0/sshd_config.gsskex openssh-5.9p0/sshd_config
+--- openssh-5.9p0/sshd_config.gsskex	2011-09-03 20:30:47.604456790 +0200
++++ openssh-5.9p0/sshd_config	2011-09-03 20:30:52.720566647 +0200
+@@ -85,6 +85,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 --git a/openssh-5.9p1-ipv6man.patch b/openssh-5.9p1-ipv6man.patch
new file mode 100644
index 0000000..ece1a73
--- /dev/null
+++ b/openssh-5.9p1-ipv6man.patch
@@ -0,0 +1,24 @@
+diff -up openssh-5.9p0/ssh.1.ipv6man openssh-5.9p0/ssh.1
+--- openssh-5.9p0/ssh.1.ipv6man	2011-08-05 22:17:32.000000000 +0200
++++ openssh-5.9p0/ssh.1	2011-08-31 13:08:34.880024485 +0200
+@@ -1400,6 +1400,8 @@ manual page for more information.
+ .Nm
+ exits with the exit status of the remote command or with 255
+ if an error occurred.
++.Sh IPV6
++IPv6 address can be used everywhere where IPv4 address. In all entries must be the IPv6 address enclosed in square brackets. Note: The square brackets are metacharacters for the shell and must be escaped in shell.
+ .Sh SEE ALSO
+ .Xr scp 1 ,
+ .Xr sftp 1 ,
+diff -up openssh-5.9p0/sshd.8.ipv6man openssh-5.9p0/sshd.8
+--- openssh-5.9p0/sshd.8.ipv6man	2011-08-05 22:17:32.000000000 +0200
++++ openssh-5.9p0/sshd.8	2011-08-31 13:10:34.129039094 +0200
+@@ -940,6 +940,8 @@ concurrently for different ports, this c
+ started last).
+ The content of this file is not sensitive; it can be world-readable.
+ .El
++.Sh IPV6
++IPv6 address can be used everywhere where IPv4 address. In all entries must be the IPv6 address enclosed in square brackets. Note: The square brackets are metacharacters for the shell and must be escaped in shell.
+ .Sh SEE ALSO
+ .Xr scp 1 ,
+ .Xr sftp 1 ,
diff --git a/openssh-5.9p1-keycat.patch b/openssh-5.9p1-keycat.patch
new file mode 100644
index 0000000..74c3ecf
--- /dev/null
+++ b/openssh-5.9p1-keycat.patch
@@ -0,0 +1,371 @@
+diff -up openssh-5.9p0/HOWTO.ssh-keycat.keycat openssh-5.9p0/HOWTO.ssh-keycat
+--- openssh-5.9p0/HOWTO.ssh-keycat.keycat	2011-08-31 11:51:49.886087176 +0200
++++ openssh-5.9p0/HOWTO.ssh-keycat	2011-08-31 11:51:49.890087179 +0200
+@@ -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.9p0/Makefile.in.keycat openssh-5.9p0/Makefile.in
+--- openssh-5.9p0/Makefile.in.keycat	2011-08-31 11:51:48.367122382 +0200
++++ openssh-5.9p0/Makefile.in	2011-08-31 12:03:46.433088864 +0200
+@@ -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
+ SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
+ PRIVSEP_PATH=@PRIVSEP_PATH@
+ SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
+@@ -62,7 +63,7 @@ EXEEXT=@EXEEXT@
+ MANFMT=@MANFMT@
+ INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@
+ 
+-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT)
++TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT)
+ 
+ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
+ 	canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \
+@@ -167,6 +168,9 @@ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT)
+ ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o
+ 	$(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
+ 
++ssh-keycat$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keycat.o
++	$(LD) -o $@ ssh-keycat.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(SSHDLIBS)
++
+ 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)
+ 
+@@ -266,6 +270,7 @@ install-files:
+ 		$(INSTALL) -m 0700 $(STRIP_OPT) ssh-ldap-helper $(DESTDIR)$(SSH_LDAP_HELPER) ; \
+ 		$(INSTALL) -m 0700 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \
+ 	fi
++	$(INSTALL) -m 0755 $(STRIP_OPT) ssh-keycat$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-keycat$(EXEEXT)
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT)
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
+ 	$(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
+diff -up openssh-5.9p0/auth2-pubkey.c.keycat openssh-5.9p0/auth2-pubkey.c
+--- openssh-5.9p0/auth2-pubkey.c.keycat	2011-08-31 11:51:47.066149816 +0200
++++ openssh-5.9p0/auth2-pubkey.c	2011-08-31 11:51:50.143087097 +0200
+@@ -579,6 +579,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.9p0/openbsd-compat/port-linux.c.keycat openssh-5.9p0/openbsd-compat/port-linux.c
+--- openssh-5.9p0/openbsd-compat/port-linux.c.keycat	2011-08-31 11:51:46.275119773 +0200
++++ openssh-5.9p0/openbsd-compat/port-linux.c	2011-08-31 11:51:50.240087963 +0200
+@@ -313,7 +313,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;
+@@ -324,16 +324,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);
+@@ -341,6 +341,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.9p0/ssh-keycat.c.keycat openssh-5.9p0/ssh-keycat.c
+--- openssh-5.9p0/ssh-keycat.c.keycat	2011-08-31 11:51:50.354136025 +0200
++++ openssh-5.9p0/ssh-keycat.c	2011-08-31 11:51:50.359087309 +0200
+@@ -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.9p1-keygen.patch b/openssh-5.9p1-keygen.patch
new file mode 100644
index 0000000..69d4a6f
--- /dev/null
+++ b/openssh-5.9p1-keygen.patch
@@ -0,0 +1,80 @@
+diff -up openssh-5.9p0/ssh-keygen.0.keygen openssh-5.9p0/ssh-keygen.0
+--- openssh-5.9p0/ssh-keygen.0.keygen	2011-08-29 16:30:02.000000000 +0200
++++ openssh-5.9p0/ssh-keygen.0	2011-08-30 13:47:56.208087184 +0200
+@@ -4,7 +4,7 @@ NAME
+      ssh-keygen - authentication key generation, management and conversion
+ 
+ SYNOPSIS
+-     ssh-keygen [-q] [-b bits] -t type [-N new_passphrase] [-C comment]
++     ssh-keygen [-q] [-o] [-b bits] -t type [-N new_passphrase] [-C comment]
+                 [-f output_keyfile]
+      ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]
+      ssh-keygen -i [-m key_format] [-f input_keyfile]
+@@ -181,6 +181,8 @@ DESCRIPTION
+              principals may be specified, separated by commas.  Please see the
+              CERTIFICATES section for details.
+ 
++     -o      Overwrite the key without prompting user.
++
+      -O option
+              Specify a certificate option when signing a key.  This option may
+              be specified multiple times.  Please see the CERTIFICATES section
+diff -up openssh-5.9p0/ssh-keygen.1.keygen openssh-5.9p0/ssh-keygen.1
+--- openssh-5.9p0/ssh-keygen.1.keygen	2011-08-30 13:32:30.787149917 +0200
++++ openssh-5.9p0/ssh-keygen.1	2011-08-30 13:46:42.638087171 +0200
+@@ -45,6 +45,7 @@
+ .Bk -words
+ .Nm ssh-keygen
+ .Op Fl q
++.Op Fl o
+ .Op Fl b Ar bits
+ .Fl t Ar type
+ .Op Fl N Ar new_passphrase
+@@ -339,6 +340,8 @@ Multiple principals may be specified, se
+ Please see the
+ .Sx CERTIFICATES
+ section for details.
++.It Fl o
++Overwrite the key without prompting user.
+ .It Fl O Ar option
+ Specify a certificate option when signing a key.
+ This option may be specified multiple times.
+diff -up openssh-5.9p0/ssh-keygen.c.keygen openssh-5.9p0/ssh-keygen.c
+--- openssh-5.9p0/ssh-keygen.c.keygen	2011-08-30 13:32:20.268149992 +0200
++++ openssh-5.9p0/ssh-keygen.c	2011-08-30 13:39:34.550214102 +0200
+@@ -73,6 +73,7 @@ int change_passphrase = 0;
+ int change_comment = 0;
+ 
+ int quiet = 0;
++int overwrite = 0;
+ 
+ int log_level = SYSLOG_LEVEL_INFO;
+ 
+@@ -1959,7 +1960,7 @@ main(int argc, char **argv)
+ 		exit(1);
+ 	}
+ 
+-	while ((opt = getopt(argc, argv, "AegiqpclBHLhvxXyF:b:f:t:D:I:P:m:N:n:"
++	while ((opt = getopt(argc, argv, "AegiqopclBHLhvxXyF:b:f:t:D:I:P:m:N:n:"
+ 	    "O:C:r:g:R:T:G:M:S:s:a:V:W:z:")) != -1) {
+ 		switch (opt) {
+ 		case 'A':
+@@ -2042,6 +2043,9 @@ main(int argc, char **argv)
+ 		case 'q':
+ 			quiet = 1;
+ 			break;
++		case 'o':
++			overwrite = 1;
++			break;
+ 		case 'e':
+ 		case 'x':
+ 			/* export key */
+@@ -2278,7 +2282,7 @@ main(int argc, char **argv)
+ 		}
+ 	}
+ 	/* If the file already exists, ask the user to confirm. */
+-	if (stat(identity_file, &st) >= 0) {
++	if (!overwrite && stat(identity_file, &st) >= 0) {
+ 		char yesno[3];
+ 		printf("%s already exists.\n", identity_file);
+ 		printf("Overwrite (y/n)? ");
diff --git a/openssh-5.9p1-kuserok.patch b/openssh-5.9p1-kuserok.patch
new file mode 100644
index 0000000..11f38a5
--- /dev/null
+++ b/openssh-5.9p1-kuserok.patch
@@ -0,0 +1,167 @@
+diff -up openssh-5.9p0/auth-krb5.c.kuserok openssh-5.9p0/auth-krb5.c
+--- openssh-5.9p0/auth-krb5.c.kuserok	2011-08-30 16:37:32.651150128 +0200
++++ openssh-5.9p0/auth-krb5.c	2011-08-30 16:37:37.549087368 +0200
+@@ -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)
+ {
+@@ -146,7 +160,7 @@ auth_krb5_password(Authctxt *authctxt, c
+ 	if (problem)
+ 		goto out;
+ 
+-	if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, client)) {
++	if (!ssh_krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, client)) {
+ 		problem = -1;
+ 		goto out;
+ 	}
+diff -up openssh-5.9p0/gss-serv-krb5.c.kuserok openssh-5.9p0/gss-serv-krb5.c
+--- openssh-5.9p0/gss-serv-krb5.c.kuserok	2011-08-30 16:37:36.988024804 +0200
++++ openssh-5.9p0/gss-serv-krb5.c	2011-08-30 16:37:37.659088030 +0200
+@@ -68,6 +68,7 @@ static int ssh_gssapi_krb5_cmdok(krb5_pr
+     int);
+ 
+ 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 */
+ 
+@@ -115,7 +116,7 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client
+ 	/* NOTE: .k5login and .k5users must opened as root, not the user,
+ 	 * because if they are on a krb5-protected filesystem, user credentials
+ 	 * to access these files aren't available yet. */
+-	if (krb5_kuserok(krb_context, princ, luser) && k5login_exists) {
++	if (ssh_krb5_kuserok(krb_context, princ, luser) && k5login_exists) {
+ 		retval = 1;
+ 		logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
+ 		    luser, (char *)client->displayname.value);
+diff -up openssh-5.9p0/servconf.c.kuserok openssh-5.9p0/servconf.c
+--- openssh-5.9p0/servconf.c.kuserok	2011-08-30 16:37:35.093073603 +0200
++++ openssh-5.9p0/servconf.c	2011-08-30 16:41:13.568087145 +0200
+@@ -144,6 +144,7 @@ initialize_server_options(ServerOptions
+ 	options->authorized_principals_file = NULL;
+ 	options->ip_qos_interactive = -1;
+ 	options->ip_qos_bulk = -1;
++	options->use_kuserok = -1;
+ }
+ 
+ void
+@@ -291,6 +292,8 @@ fill_default_server_options(ServerOption
+ 		options->ip_qos_bulk = IPTOS_THROUGHPUT;
+ 	if (options->show_patchlevel == -1)
+  		options->show_patchlevel = 0;
++	if (options->use_kuserok == -1)
++		options->use_kuserok = 1;
+ 
+ 	/* Turn privilege separation on by default */
+ 	if (use_privsep == -1)
+@@ -317,7 +320,7 @@ typedef enum {
+ 	sPermitRootLogin, sLogFacility, sLogLevel,
+ 	sRhostsRSAAuthentication, sRSAAuthentication,
+ 	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
+-	sKerberosGetAFSToken,
++	sKerberosGetAFSToken, sKerberosUseKuserok,
+ 	sKerberosTgtPassing, sChallengeResponseAuthentication,
+ 	sPasswordAuthentication, sKbdInteractiveAuthentication,
+ 	sListenAddress, sAddressFamily,
+@@ -388,11 +391,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 },
+@@ -1371,6 +1376,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')
+@@ -1580,6 +1589,7 @@ copy_set_server_options(ServerOptions *d
+ 	M_CP_INTOPT(max_authtries);
+ 	M_CP_INTOPT(ip_qos_interactive);
+ 	M_CP_INTOPT(ip_qos_bulk);
++	M_CP_INTOPT(use_kuserok);
+ 
+ 	/* See comment in servconf.h */
+ 	COPY_MATCH_STRING_OPTS();
+@@ -1816,6 +1826,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.9p0/servconf.h.kuserok openssh-5.9p0/servconf.h
+--- openssh-5.9p0/servconf.h.kuserok	2011-08-30 16:37:35.201051957 +0200
++++ openssh-5.9p0/servconf.h	2011-08-30 16:37:37.926087431 +0200
+@@ -166,6 +166,7 @@ typedef struct {
+ 
+ 	int	num_permitted_opens;
+ 
++	int	use_kuserok;
+ 	char   *chroot_directory;
+ 	char   *revoked_keys_file;
+ 	char   *trusted_user_ca_keys;
+diff -up openssh-5.9p0/sshd_config.5.kuserok openssh-5.9p0/sshd_config.5
+--- openssh-5.9p0/sshd_config.5.kuserok	2011-08-30 16:37:35.979024607 +0200
++++ openssh-5.9p0/sshd_config.5	2011-08-30 16:37:38.040087843 +0200
+@@ -603,6 +603,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 KexAlgorithms
+ Specifies the available KEX (Key Exchange) algorithms.
+ Multiple algorithms must be comma-separated.
+@@ -746,6 +750,7 @@ Available keywords are
+ .Cm HostbasedUsesNameFromPacketOnly ,
+ .Cm KbdInteractiveAuthentication ,
+ .Cm KerberosAuthentication ,
++.Cm KerberosUseKuserok ,
+ .Cm MaxAuthTries ,
+ .Cm MaxSessions ,
+ .Cm PubkeyAuthentication ,
+diff -up openssh-5.9p0/sshd_config.kuserok openssh-5.9p0/sshd_config
+--- openssh-5.9p0/sshd_config.kuserok	2011-08-30 16:37:36.808026328 +0200
++++ openssh-5.9p0/sshd_config	2011-08-30 16:37:38.148071520 +0200
+@@ -77,6 +77,7 @@ ChallengeResponseAuthentication no
+ #KerberosOrLocalPasswd yes
+ #KerberosTicketCleanup yes
+ #KerberosGetAFSToken no
++#KerberosUseKuserok yes
+ 
+ # GSSAPI options
+ #GSSAPIAuthentication no
diff --git a/openssh-5.9p1-ldap.patch b/openssh-5.9p1-ldap.patch
new file mode 100644
index 0000000..bc6eb98
--- /dev/null
+++ b/openssh-5.9p1-ldap.patch
@@ -0,0 +1,2596 @@
+diff -up openssh-5.9p1/HOWTO.ldap-keys.ldap openssh-5.9p1/HOWTO.ldap-keys
+--- openssh-5.9p1/HOWTO.ldap-keys.ldap	2011-09-13 11:17:05.178644691 +0200
++++ openssh-5.9p1/HOWTO.ldap-keys	2011-09-13 11:17:05.181522429 +0200
+@@ -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.9p1/Makefile.in.ldap openssh-5.9p1/Makefile.in
+--- openssh-5.9p1/Makefile.in.ldap	2011-09-13 11:17:04.064644353 +0200
++++ openssh-5.9p1/Makefile.in	2011-09-13 11:20:16.996522219 +0200
+@@ -25,6 +25,8 @@ SSH_PROGRAM=@bindir@/ssh
+ ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass
+ SFTP_SERVER=$(libexecdir)/sftp-server
+ SSH_KEYSIGN=$(libexecdir)/ssh-keysign
++SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper
++SSH_LDAP_WRAPPER=$(libexecdir)/ssh-ldap-wrapper
+ SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
+ PRIVSEP_PATH=@PRIVSEP_PATH@
+ SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
+@@ -58,8 +60,9 @@ XAUTH_PATH=@XAUTH_PATH@
+ LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@
+ EXEEXT=@EXEEXT@
+ MANFMT=@MANFMT@
++INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@
+ 
+-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT)
++TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT)
+ 
+ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
+ 	canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \
+@@ -92,8 +95,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw
+ 	roaming_common.o roaming_serv.o \
+ 	sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o sandbox-selinux.o
+ 
+-MANPAGES	= moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out
+-MANPAGES_IN	= moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5
++MANPAGES	= moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out 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-keysign.8 ssh-pkcs11-helper.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
+@@ -161,6 +164,9 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libss
+ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o
+ 	$(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
+ 
++ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o
++	$(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS)
++
+ ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o
+ 	$(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
+ 
+@@ -256,6 +262,10 @@ install-files:
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) sshd$(EXEEXT) $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
+ 	$(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
++	if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \
++		$(INSTALL) -m 0700 $(STRIP_OPT) ssh-ldap-helper $(DESTDIR)$(SSH_LDAP_HELPER) ; \
++		$(INSTALL) -m 0700 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \
++	fi
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT)
+ 	$(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
+ 	$(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
+@@ -272,6 +282,10 @@ install-files:
+ 	$(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
+ 	$(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
+ 	$(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
++	if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \
++		$(INSTALL) -m 644 ssh-ldap-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-ldap-helper.8 ; \
++		$(INSTALL) -m 644 ssh-ldap.conf.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/ssh-ldap.conf.5 ; \
++	fi
+ 	-rm -f $(DESTDIR)$(bindir)/slogin
+ 	ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
+@@ -301,6 +315,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 \
+@@ -358,6 +379,8 @@ uninstall:
+ 	-rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
+ 	-rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
+ 	-rm -f $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
++	-rm -f $(DESTDIR)$(SSH_LDAP_HELPER)$(EXEEXT)
++	-rm -f $(DESTDIR)$(SSH_LDAP_WRAPPER)$(EXEEXT)
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
+@@ -369,6 +392,7 @@ uninstall:
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
++	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-ldap-helper.8
+ 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
+ 
+ tests interop-tests:	$(TARGETS)
+diff -up openssh-5.9p1/configure.ac.ldap openssh-5.9p1/configure.ac
+--- openssh-5.9p1/configure.ac.ldap	2011-09-13 11:17:04.488583772 +0200
++++ openssh-5.9p1/configure.ac	2011-09-13 11:17:05.418529375 +0200
+@@ -1433,6 +1433,106 @@ 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
++
++			INSTALL_SSH_LDAP_HELPER="yes"
++			CPPFLAGS="$CPPFLAGS -DLDAP_DEPRECATED"
++
++			if test "x$withval" != "xyes" ; then
++				CPPFLAGS="$CPPFLAGS -I${withval}/include"
++				LDFLAGS="$LDFLAGS -L${withval}/lib"
++			fi
++
++			AC_DEFINE([WITH_LDAP_PUBKEY], 1, [Enable LDAP pubkey support])
++			LDAP_MSG="yes"
++
++			AC_CHECK_HEADERS(lber.h)
++			AC_CHECK_HEADERS(ldap.h, , AC_MSG_ERROR(could not locate <ldap.h>))
++			AC_CHECK_HEADERS(ldap_ssl.h)
++
++			AC_ARG_WITH(ldap-lib,
++				[  --with-ldap-lib=type    select ldap library [auto|netscape5|netscape4|netscape3|umich|openldap]])
++
++			if test -z "$with_ldap_lib"; then
++				with_ldap_lib=auto
++			fi
++
++			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = umich -o $with_ldap_lib = openldap \); then
++				AC_CHECK_LIB(lber, main, LIBS="-llber $LIBS" found_ldap_lib=yes)
++				AC_CHECK_LIB(ldap, main, LIBS="-lldap $LIBS" found_ldap_lib=yes)
++			fi
++
++			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape5 \); then
++				AC_CHECK_LIB(ldap50, main, LIBS="-lldap50 -lssldap50 -lssl3 -lnss3 -lnspr4 -lprldap50 -lplc4 -lplds4 $LIBS" found_ldap_lib=yes)
++			fi
++
++			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape4 \); then
++				AC_CHECK_LIB(ldapssl41, main, LIBS="-lldapssl41 -lplc3 -lplds3 -lnspr3 $LIBS" found_ldap_lib=yes)
++				if test -z "$found_ldap_lib"; then
++					AC_CHECK_LIB(ldapssl40, main, LIBS="-lldapssl40 $LIBS" found_ldap_lib=yes)
++				fi
++				if test -z "$found_ldap_lib"; then
++					AC_CHECK_LIB(ldap41, main, LIBS="-lldap41 $LIBS" found_ldap_lib=yes)
++				fi
++				if test -z "$found_ldap_lib"; then
++					AC_CHECK_LIB(ldap40, main, LIBS="-lldap40 $LIBS" found_ldap_lib=yes)
++				fi
++			fi
++
++			if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape3 \); then
++				AC_CHECK_LIB(ldapssl30, main, LIBS="-lldapssl30 $LIBS" found_ldap_lib=yes)
++			fi
++
++			if test -z "$found_ldap_lib"; then
++				AC_MSG_ERROR(could not locate a valid LDAP library)
++			fi
++
++			AC_MSG_CHECKING([for working LDAP support])
++			AC_TRY_COMPILE(
++				[#include <sys/types.h>
++				 #include <ldap.h>],
++				[(void)ldap_init(0, 0);],
++				[AC_MSG_RESULT(yes)],
++				[
++				    AC_MSG_RESULT(no) 
++					AC_MSG_ERROR([** Incomplete or missing ldap libraries **])
++				])
++			AC_CHECK_FUNCS( \
++				ldap_init \
++				ldap_get_lderrno \
++				ldap_set_lderrno \
++				ldap_parse_result \
++				ldap_memfree \
++				ldap_controls_free \
++				ldap_set_option \
++				ldap_get_option \
++				ldapssl_init \
++				ldap_start_tls_s \
++				ldap_pvt_tls_set_option \
++				ldap_initialize \
++			)
++			AC_CHECK_FUNCS(ldap_set_rebind_proc,
++				AC_MSG_CHECKING([number arguments of ldap_set_rebind_proc])
++				AC_TRY_COMPILE(
++					[#include <lber.h>
++					#include <ldap.h>],
++					[ldap_set_rebind_proc(0, 0, 0);],
++					[ac_cv_ldap_set_rebind_proc=3],
++					[ac_cv_ldap_set_rebind_proc=2])
++				AC_MSG_RESULT($ac_cv_ldap_set_rebind_proc)
++				AC_DEFINE(LDAP_SET_REBIND_PROC_ARGS, $ac_cv_ldap_set_rebind_proc, [number arguments of ldap_set_rebind_proc])
++			)
++		fi
++	]
++)
++AC_SUBST(INSTALL_SSH_LDAP_HELPER)
++
+ dnl    Checks for library functions. Please keep in alphabetical order
+ AC_CHECK_FUNCS([ \
+ 	arc4random \
+diff -up openssh-5.9p1/ldap-helper.c.ldap openssh-5.9p1/ldap-helper.c
+--- openssh-5.9p1/ldap-helper.c.ldap	2011-09-13 11:17:05.527520185 +0200
++++ openssh-5.9p1/ldap-helper.c	2011-09-13 11:17:05.531521117 +0200
+@@ -0,0 +1,155 @@
++/* $OpenBSD: ssh-pka-ldap.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */
++/*
++ * Copyright (c) 2009 Jan F. Chadima.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "ldapincludes.h"
++#include "log.h"
++#include "misc.h"
++#include "xmalloc.h"
++#include "ldapconf.h"
++#include "ldapbody.h"
++#include <string.h>
++#include <unistd.h>
++
++static int config_debug = 0;
++int config_exclusive_config_file = 0;
++static char *config_file_name = "/etc/ssh/ldap.conf";
++static char *config_single_user = NULL;
++static int config_verbose = SYSLOG_LEVEL_VERBOSE;
++int config_warning_config_file = 0;
++extern char *__progname;
++
++static void
++usage(void)
++{
++	fprintf(stderr, "usage: %s [options]\n",
++	    __progname);
++	fprintf(stderr, "Options:\n");
++	fprintf(stderr, "  -d          Output the log messages to stderr.\n");
++	fprintf(stderr, "  -e          Check the config file for unknown commands.\n");
++	fprintf(stderr, "  -f file     Use alternate config file (default is /etc/ssh/ldap.conf).\n");
++	fprintf(stderr, "  -s user     Do not demonize, send the user's key to stdout.\n");
++	fprintf(stderr, "  -v          Increase verbosity of the debug output (implies -d).\n");
++	fprintf(stderr, "  -w          Warn on unknown commands in the config file.\n");
++	exit(1);
++}
++
++/*
++ * Main program for the ssh pka ldap agent.
++ */
++
++int
++main(int ac, char **av)
++{
++	int opt;
++	FILE *outfile = NULL;
++
++	__progname = ssh_get_progname(av[0]);
++
++	log_init(__progname, SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0);
++
++	/*
++	 * Initialize option structure to indicate that no values have been
++	 * set.
++	 */
++	initialize_options();
++
++	/* Parse command-line arguments. */
++	while ((opt = getopt(ac, av, "def:s:vw")) != -1) {
++		switch (opt) {
++		case 'd':
++			config_debug = 1;
++			break;
++
++		case 'e':
++			config_exclusive_config_file = 1;
++			config_warning_config_file = 1;
++			break;
++
++		case 'f':
++			config_file_name = optarg;
++			break;
++
++		case 's':
++			config_single_user = optarg;
++			outfile = fdopen (dup (fileno (stdout)), "w");
++			break;
++
++		case 'v':
++			config_debug = 1;
++			if (config_verbose < SYSLOG_LEVEL_DEBUG3)
++			    config_verbose++;
++			break;
++
++		case 'w':
++			config_warning_config_file = 1;
++			break;
++
++		case '?':
++		default:
++			usage();
++			break;
++		}
++	}
++
++	/* Initialize loging */
++	log_init(__progname, config_verbose, SYSLOG_FACILITY_AUTH, config_debug);
++
++	if (ac != optind)
++	    fatal ("illegal extra parameter %s", av[1]);
++
++	/* Ensure that fds 0 and 2 are open or directed to /dev/null */
++	if (config_debug == 0)
++	    sanitise_stdfd();
++
++	/* Read config file */
++	read_config_file(config_file_name);
++	fill_default_options();
++	if (config_verbose == SYSLOG_LEVEL_DEBUG3) {
++		debug3 ("=== Configuration ===");
++		dump_config();
++		debug3 ("=== *** ===");
++	}
++
++	ldap_checkconfig();
++	ldap_do_connect();
++
++	if (config_single_user) {
++		process_user (config_single_user, outfile);
++	} else {
++		usage();
++		fatal ("Not yet implemented");
++/* TODO
++ * open unix socket a run the loop on it
++ */
++	}
++
++	ldap_do_close();
++	return 0;
++}
++
++/* Ugly hack */
++void   *buffer_get_string(Buffer *b, u_int *l) { return NULL; }
++void    buffer_put_string(Buffer *b, const void *f, u_int l) {}
++
+diff -up openssh-5.9p1/ldap-helper.h.ldap openssh-5.9p1/ldap-helper.h
+--- openssh-5.9p1/ldap-helper.h.ldap	2011-09-13 11:17:05.619520027 +0200
++++ openssh-5.9p1/ldap-helper.h	2011-09-13 11:17:05.621522622 +0200
+@@ -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.9p1/ldap.conf.ldap openssh-5.9p1/ldap.conf
+--- openssh-5.9p1/ldap.conf.ldap	2011-09-13 11:17:05.697522387 +0200
++++ openssh-5.9p1/ldap.conf	2011-09-13 11:17:05.699522577 +0200
+@@ -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.9p1/ldapbody.c.ldap openssh-5.9p1/ldapbody.c
+--- openssh-5.9p1/ldapbody.c.ldap	2011-09-13 11:17:05.782571211 +0200
++++ openssh-5.9p1/ldapbody.c	2011-09-13 11:17:05.785584958 +0200
+@@ -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
++				(void) ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &options.debug);
++#endif /* LDAP_OPT_DEBUG_LEVEL */
++				debug3 ("Set LDAP debug to %d", options.debug);
++			}
++		}
++#endif /* HAVE_LDAP_SET_OPTION */
++
++		ld = NULL;
++#ifdef HAVE_LDAPSSL_INIT
++		if (options.host != NULL) {
++			if (options.ssl_on == SSL_LDAPS) {
++				if ((rc = ldapssl_client_init (options.sslpath, NULL)) != LDAP_SUCCESS)
++				    fatal ("ldapssl_client_init %s", ldap_err2string (rc));
++				debug3 ("LDAPssl client init");
++			}
++
++			if (options.ssl_on != SSL_OFF) {
++				if ((ld = ldapssl_init (options.host, options.port, TRUE)) == NULL)
++				    fatal ("ldapssl_init failed");
++				debug3 ("LDAPssl init");
++			}
++		}
++#endif /* HAVE_LDAPSSL_INIT */
++
++		/* continue with opening */
++		if (ld == NULL) {
++#if defined (HAVE_LDAP_START_TLS_S) || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS))
++			/* Some global TLS-specific options need to be set before we create our
++			 * session context, so we set them here. */
++
++#ifdef LDAP_OPT_X_TLS_RANDOM_FILE
++			/* rand file */
++			if (options.tls_randfile != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
++				    options.tls_randfile)) != LDAP_SUCCESS)
++					fatal ("ldap_set_option(LDAP_OPT_X_TLS_RANDOM_FILE): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS random file %s", options.tls_randfile);
++			}
++#endif /* LDAP_OPT_X_TLS_RANDOM_FILE */
++
++			/* ca cert file */
++			if (options.tls_cacertfile != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE,
++				    options.tls_cacertfile)) != LDAP_SUCCESS)
++					error ("ldap_set_option(LDAP_OPT_X_TLS_CACERTFILE): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS CA cert file %s ", options.tls_cacertfile);
++			}
++
++			/* ca cert directory */
++			if (options.tls_cacertdir != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR,
++				    options.tls_cacertdir)) != LDAP_SUCCESS)
++					fatal ("ldap_set_option(LDAP_OPT_X_TLS_CACERTDIR): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS CA cert dir %s ", options.tls_cacertdir);
++			}
++
++			/* require cert? */
++			if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
++			    &options.tls_checkpeer)) != LDAP_SUCCESS)
++				fatal ("ldap_set_option(LDAP_OPT_X_TLS_REQUIRE_CERT): %s",
++				    ldap_err2string (rc));
++			debug3 ("Set TLS check peer to %d ", options.tls_checkpeer);
++
++			/* set cipher suite, certificate and private key: */
++			if (options.tls_ciphers != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
++				    options.tls_ciphers)) != LDAP_SUCCESS)
++					fatal ("ldap_set_option(LDAP_OPT_X_TLS_CIPHER_SUITE): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS ciphers to %s ", options.tls_ciphers);
++			}
++
++			/* cert file */
++			if (options.tls_cert != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE,
++				    options.tls_cert)) != LDAP_SUCCESS)
++					fatal ("ldap_set_option(LDAP_OPT_X_TLS_CERTFILE): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS cert file %s ", options.tls_cert);
++			}
++
++			/* key file */
++			if (options.tls_key != NULL) {
++				if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE,
++				    options.tls_key)) != LDAP_SUCCESS)
++					fatal ("ldap_set_option(LDAP_OPT_X_TLS_KEYFILE): %s",
++					    ldap_err2string (rc));
++				debug3 ("Set TLS key file %s ", options.tls_key);
++			}
++#endif
++#ifdef HAVE_LDAP_INITIALIZE
++			if (options.uri != NULL) {
++				if ((rc = ldap_initialize (&ld, options.uri)) != LDAP_SUCCESS)
++					fatal ("ldap_initialize %s", ldap_err2string (rc));
++				debug3 ("LDAP initialize %s", options.uri);
++			}
++	}
++#endif /* HAVE_LDAP_INTITIALIZE */
++
++		/* continue with opening */
++		if ((ld == NULL) && (options.host != NULL)) {
++#ifdef HAVE_LDAP_INIT
++			if ((ld = ldap_init (options.host, options.port)) == NULL)
++			    fatal ("ldap_init failed");
++			debug3 ("LDAP init %s:%d", options.host, options.port);
++#else
++			if ((ld = ldap_open (options.host, options.port)) == NULL)
++			    fatal ("ldap_open failed");
++			debug3 ("LDAP open %s:%d", options.host, options.port);
++#endif /* HAVE_LDAP_INIT */
++		}
++
++		if (ld == NULL)
++			fatal ("no way to open ldap");
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
++		if (options.ssl == SSL_LDAPS) {
++			if ((rc = ldap_set_option (ld, LDAP_OPT_X_TLS, &options.tls_checkpeer)) != LDAP_SUCCESS)
++				fatal ("ldap_set_option(LDAP_OPT_X_TLS) %s", ldap_err2string (rc));
++			debug3 ("LDAP set LDAP_OPT_X_TLS_%d", options.tls_checkpeer);
++		}
++#endif /* LDAP_OPT_X_TLS */
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_PROTOCOL_VERSION)
++		(void) ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION,
++		    &options.ldap_version);
++#else
++		ld->ld_version = options.ldap_version;
++#endif
++		debug3 ("LDAP set version to %d", options.ldap_version);
++
++#if LDAP_SET_REBIND_PROC_ARGS == 3
++		ldap_set_rebind_proc (ld, _rebind_proc, NULL);
++#elif LDAP_SET_REBIND_PROC_ARGS == 2
++		ldap_set_rebind_proc (ld, _rebind_proc);
++#else
++#warning unknown LDAP_SET_REBIND_PROC_ARGS
++#endif
++		debug3 ("LDAP set rebind proc");
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_DEREF)
++		(void) ldap_set_option (ld, LDAP_OPT_DEREF, &options.deref);
++#else
++		ld->ld_deref = options.deref;
++#endif
++		debug3 ("LDAP set deref to %d", options.deref);
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_TIMELIMIT)
++		(void) ldap_set_option (ld, LDAP_OPT_TIMELIMIT,
++		    &options.timelimit);
++#else
++		ld->ld_timelimit = options.timelimit;
++#endif
++		debug3 ("LDAP set timelimit to %d", options.timelimit);
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_X_OPT_CONNECT_TIMEOUT)
++		/*
++		 * This is a new option in the Netscape SDK which sets 
++		 * the TCP connect timeout. For want of a better value,
++		 * we use the bind_timelimit to control this.
++		 */
++		timeout = options.bind_timelimit * 1000;
++		(void) ldap_set_option (ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout);
++		debug3 ("LDAP set opt connect timeout to %d", timeout);
++#endif
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_NETWORK_TIMEOUT)
++		tv.tv_sec = options.bind_timelimit;
++		tv.tv_usec = 0;
++		(void) ldap_set_option (ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
++		debug3 ("LDAP set opt network timeout to %ld.0", tv.tv_sec);
++#endif
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_REFERRALS)
++		(void) ldap_set_option (ld, LDAP_OPT_REFERRALS,
++		    options.referrals ? LDAP_OPT_ON : LDAP_OPT_OFF);
++		debug3 ("LDAP set referrals to %d", options.referrals);
++#endif
++
++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_RESTART)
++		(void) ldap_set_option (ld, LDAP_OPT_RESTART,
++		    options.restart ? LDAP_OPT_ON : LDAP_OPT_OFF);
++		debug3 ("LDAP set restart to %d", options.restart);
++#endif
++
++#ifdef HAVE_LDAP_START_TLS_S
++		if (options.ssl == SSL_START_TLS) {
++			int version;
++
++			if (ldap_get_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version)
++			    == LDAP_SUCCESS) {
++				if (version < LDAP_VERSION3) {
++					version = LDAP_VERSION3;
++					(void) ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION,
++					    &version);
++					debug3 ("LDAP set version to %d", version);
++				}
++			}
++
++			if ((rc = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS)
++			    fatal ("ldap_starttls_s: %s", ldap_err2string (rc));
++			debug3 ("LDAP start TLS");
++		}
++#endif /* HAVE_LDAP_START_TLS_S */
++	}
++
++	if ((msgid = ldap_simple_bind (ld, options.binddn,
++	    options.bindpw)) == -1) {
++		ld_errno = ldap_get_lderrno (ld, 0, 0);
++
++		error ("ldap_simple_bind %s", ldap_err2string (ld_errno));
++		reconnect++;
++		goto retry;
++	}
++	debug3 ("LDAP simple bind (%s)", options.binddn);
++
++	timeout.tv_sec = options.bind_timelimit;
++	timeout.tv_usec = 0;
++	if ((rc = ldap_result (ld, msgid, FALSE, &timeout, &result)) < 1) {
++		ld_errno = ldap_get_lderrno (ld, 0, 0);
++
++		error ("ldap_result %s", ldap_err2string (ld_errno));
++		reconnect++;
++		goto retry;
++	}
++	debug3 ("LDAP result in time");
++
++#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE)
++	controls = NULL;
++	if ((parserc = ldap_parse_result (ld, result, &rc, 0, 0, 0, &controls, TRUE)) != LDAP_SUCCESS)
++	    fatal ("ldap_parse_result %s", ldap_err2string (parserc));
++	debug3 ("LDAP parse result OK");
++
++	if (controls != NULL) {
++		ldap_controls_free (controls);
++	}
++#else
++	rc = ldap_result2error (session->ld, result, TRUE);
++#endif
++	if (rc != LDAP_SUCCESS)
++	    fatal ("error trying to bind as user \"%s\" (%s)",
++		options.binddn, ldap_err2string (rc));
++
++	debug2 ("LDAP do connect OK");
++}
++
++void
++process_user (const char *user, FILE *output)
++{
++	LDAPMessage *res, *e;
++	char *buffer;
++	int bufflen, rc, i;
++	struct timeval timeout;
++
++	debug ("LDAP process user");
++
++	/* quick check for attempts to be evil */
++	if ((strchr(user, '(') != NULL) || (strchr(user, ')') != NULL) ||
++	    (strchr(user, '*') != NULL) || (strchr(user, '\\') != NULL)) {
++		logit ("illegal user name %s not processed", user);
++		return;
++	}
++
++	/* build  filter for LDAP request */
++	bufflen = strlen (LDAPSEARCH_FORMAT) + strlen (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.9p1/ldapbody.h.ldap openssh-5.9p1/ldapbody.h
+--- openssh-5.9p1/ldapbody.h.ldap	2011-09-13 11:17:05.861522789 +0200
++++ openssh-5.9p1/ldapbody.h	2011-09-13 11:17:05.863522010 +0200
+@@ -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.9p1/ldapconf.c.ldap openssh-5.9p1/ldapconf.c
+--- openssh-5.9p1/ldapconf.c.ldap	2011-09-13 11:17:05.937548294 +0200
++++ openssh-5.9p1/ldapconf.c	2011-09-13 11:17:05.941547073 +0200
+@@ -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.9p1/ldapconf.h.ldap openssh-5.9p1/ldapconf.h
+--- openssh-5.9p1/ldapconf.h.ldap	2011-09-13 11:17:06.016522201 +0200
++++ openssh-5.9p1/ldapconf.h	2011-09-13 11:17:06.018522083 +0200
+@@ -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.9p1/ldapincludes.h.ldap openssh-5.9p1/ldapincludes.h
+--- openssh-5.9p1/ldapincludes.h.ldap	2011-09-13 11:17:06.123519312 +0200
++++ openssh-5.9p1/ldapincludes.h	2011-09-13 11:17:06.126518977 +0200
+@@ -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.9p1/ldapmisc.c.ldap openssh-5.9p1/ldapmisc.c
+--- openssh-5.9p1/ldapmisc.c.ldap	2011-09-13 11:17:06.195508388 +0200
++++ openssh-5.9p1/ldapmisc.c	2011-09-13 11:17:06.197507964 +0200
+@@ -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.9p1/ldapmisc.h.ldap openssh-5.9p1/ldapmisc.h
+--- openssh-5.9p1/ldapmisc.h.ldap	2011-09-13 11:17:06.273496889 +0200
++++ openssh-5.9p1/ldapmisc.h	2011-09-13 11:17:06.276496151 +0200
+@@ -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.9p1/openssh-lpk-openldap.schema.ldap openssh-5.9p1/openssh-lpk-openldap.schema
+--- openssh-5.9p1/openssh-lpk-openldap.schema.ldap	2011-09-13 11:17:06.349485171 +0200
++++ openssh-5.9p1/openssh-lpk-openldap.schema	2011-09-13 11:17:06.351484488 +0200
+@@ -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.9p1/openssh-lpk-sun.schema.ldap openssh-5.9p1/openssh-lpk-sun.schema
+--- openssh-5.9p1/openssh-lpk-sun.schema.ldap	2011-09-13 11:17:06.420474045 +0200
++++ openssh-5.9p1/openssh-lpk-sun.schema	2011-09-13 11:17:06.422473843 +0200
+@@ -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.9p1/ssh-ldap-helper.8.ldap openssh-5.9p1/ssh-ldap-helper.8
+--- openssh-5.9p1/ssh-ldap-helper.8.ldap	2011-09-13 11:17:06.504461435 +0200
++++ openssh-5.9p1/ssh-ldap-helper.8	2011-09-13 11:17:06.506460976 +0200
+@@ -0,0 +1,79 @@
++.\" $OpenBSD: ssh-ldap-helper.8,v 1.1 2010/02/10 23:20:38 markus Exp $
++.\"
++.\" Copyright (c) 2010 Jan F. Chadima.  All rights reserved.
++.\"
++.\" Permission to use, copy, modify, and distribute this software for any
++.\" purpose with or without fee is hereby granted, provided that the above
++.\" copyright notice and this permission notice appear in all copies.
++.\"
++.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++.\"
++.Dd $Mdocdate: April 29 2010 $
++.Dt SSH-LDAP-HELPER 8
++.Os
++.Sh NAME
++.Nm ssh-ldap-helper
++.Nd sshd helper program for ldap support
++.Sh SYNOPSIS
++.Nm ssh-ldap-helper
++.Op Fl devw
++.Op Fl f Ar file
++.Op Fl s Ar user
++.Sh DESCRIPTION
++.Nm
++is used by
++.Xr sshd 1
++to access keys provided by an LDAP.
++.Nm
++is disabled by default and can only be enabled in the
++sshd configuration file
++.Pa /etc/ssh/sshd_config
++by setting
++.Cm AuthorizedKeysCommand
++to
++.Dq /usr/libexec/ssh-ldap-wrapper .
++.Pp
++.Nm
++is not intended to be invoked by the user, but from
++.Xr sshd 8 via
++.Xr ssh-ldap-wrapper .
++.Pp
++The options are as follows:
++.Bl -tag -width Ds
++.It Fl d
++Set the debug mode; 
++.Nm
++prints all logs to stderr instead of syslog.
++.It Fl e
++Implies \-w;
++.Nm
++halts if it encounters an unknown item in the ldap.conf file.
++.It Fl f
++.Nm
++uses this file as the ldap configuration file instead of /etc/ssh/ldap.conf (default).
++.It Fl s
++.Nm
++prints out the user's keys to stdout and exits.
++.It Fl v
++Implies \-d;
++increases verbosity.
++.It Fl w
++.Nm
++writes warnings about unknown items in the ldap.conf configuration file.
++.El
++.Sh SEE ALSO
++.Xr sshd 8 ,
++.Xr sshd_config 5 ,
++.Xr ssh-ldap.conf 5 ,
++.Sh HISTORY
++.Nm
++first appeared in
++OpenSSH 5.5 + PKA-LDAP .
++.Sh AUTHORS
++.An Jan F. Chadima Aq jchadima at redhat.com
+diff -up openssh-5.9p1/ssh-ldap-wrapper.ldap openssh-5.9p1/ssh-ldap-wrapper
+--- openssh-5.9p1/ssh-ldap-wrapper.ldap	2011-09-13 11:17:06.574455869 +0200
++++ openssh-5.9p1/ssh-ldap-wrapper	2011-09-13 11:17:06.576475704 +0200
+@@ -0,0 +1,4 @@
++#!/bin/sh
++
++exec /usr/libexec/openssh/ssh-ldap-helper -s "$1"
++
+diff -up openssh-5.9p1/ssh-ldap.conf.5.ldap openssh-5.9p1/ssh-ldap.conf.5
+--- openssh-5.9p1/ssh-ldap.conf.5.ldap	2011-09-13 11:17:06.650522542 +0200
++++ openssh-5.9p1/ssh-ldap.conf.5	2011-09-13 11:17:06.653474746 +0200
+@@ -0,0 +1,376 @@
++.\" $OpenBSD: ssh-ldap.conf.5,v 1.1 2010/02/10 23:20:38 markus Exp $
++.\"
++.\" Copyright (c) 2010 Jan F. Chadima.  All rights reserved.
++.\"
++.\" Permission to use, copy, modify, and distribute this software for any
++.\" purpose with or without fee is hereby granted, provided that the above
++.\" copyright notice and this permission notice appear in all copies.
++.\"
++.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++.\"
++.Dd $Mdocdate: may 12 2010 $
++.Dt SSH-LDAP.CONF 5
++.Os
++.Sh NAME
++.Nm ssh-ldap.conf
++.Nd configuration file for ssh-ldap-helper
++.Sh SYNOPSIS
++.Nm /etc/ssh/ldap.conf
++.Sh DESCRIPTION
++.Xr ssh-ldap-helper 8
++reads configuration data from
++.Pa /etc/ssh/ldap.conf
++(or the file specified with
++.Fl f
++on the command line).
++The file contains keyword-argument pairs, one per line.
++Lines starting with
++.Ql #
++and empty lines are interpreted as comments.
++.Pp
++The value starts with the first non-blank character after 
++the keyword's name, and terminates at the end of the line, 
++or at the last sequence of blanks before the end of the line.
++Quoting values that contain blanks 
++may be incorrect, as the quotes would become part of the value.
++The possible keywords and their meanings are as follows (note that
++keywords are case-insensitive, and arguments, on a case by case basis, may be case-sensitive).
++.Bl -tag -width Ds
++.It Cm URI
++The argument(s) are in the form
++.Pa ldap[si]://[name[:port]]
++and specify the URI(s) of an LDAP server(s) to which the
++.Xr ssh-ldap-helper 8 
++should connect. The URI scheme may be any of
++.Dq ldap ,
++.Dq ldaps 
++or
++.Dq ldapi ,
++which refer to LDAP over TCP, LDAP over SSL (TLS) and LDAP
++over IPC (UNIX domain sockets), respectively.
++Each server's name can be specified as a
++domain-style name or an IP address literal.  Optionally, the
++server's name can followed by a ':' and the port number the LDAP
++server is listening on.  If no port number is provided, the default
++port for the scheme is used (389 for ldap://, 636 for ldaps://).
++For LDAP over IPC, name is the name of the socket, and no port
++is required, nor allowed; note that directory separators must be 
++URL-encoded, like any other characters that are special to URLs; 
++A space separated list of URIs may be provided.
++There is no default.
++.It Cm Base
++Specifies the default base Distinguished Name (DN) to use when performing ldap operations.
++The base must be specified as a DN in LDAP format.
++There is no default.
++.It Cm BindDN
++Specifies the default BIND DN to use when connecting to the ldap server.
++The bind DN must be specified as a Distinguished Name in LDAP format.
++There is no default.
++.It Cm BindPW
++Specifies the default password to use when connecting to the ldap server via
++.Cm BindDN .
++There is no default.
++.It Cm RootBindDN
++Intentionaly does nothing. Recognized for compatibility reasons.
++.It Cm Host
++The argument(s) specifies the name(s) of an LDAP server(s) to which the
++.Xr ssh-ldap-helper 8
++should connect.  Each server's name can be specified as a
++domain-style name or an IP address and optionally followed by a ':' and
++the port number the ldap server is listening on.  A space-separated
++list of hosts may be provided.
++There is no default.
++.Cm Host
++is deprecated in favor of
++.Cm URI .
++.It Cm Port
++Specifies the default port used when connecting to LDAP servers(s).
++The port may be specified as a number.
++The default port is 389 for ldap:// or 636 for ldaps:// respectively.
++.Cm Port
++is deprecated in favor of
++.Cm URI .
++.It Cm Scope
++Specifies the starting point of an LDAP search and the depth from the base DN to which the search should descend.
++There are three options (values) that can be assigned to the
++.Cm Scope parameter:
++.Dq base ,
++.Dq one
++and
++.Dq subtree .
++Alias for the subtree is
++.Dq sub .
++The value
++.Dq base
++is used to indicate searching only the entry at the base DN, resulting in only that entry being returned (keeping in mind that it also has to meet the search filter criteria!).
++The value
++.Dq one
++is used to indicate searching all entries one level under the base DN, but not including the base DN and not including any entries under that one level under the base DN.
++The value
++.Dq subtree
++is used to indicate searching of all entries at all levels under and including the specified base DN.
++The default is
++.Dq subtree .
++.It Cm Deref
++Specifies how alias dereferencing is done when performing a search. There are four
++possible values that can be assigned to the
++.Cm Deref
++parameter:
++.Dq never ,
++.Dq searching ,
++.Dq finding ,
++and
++.Dq always .
++The value
++.Dq never
++means that the aliases are never dereferenced.
++The value
++.Dq searching
++means that the aliases are dereferenced in subordinates of the base object, but
++not in locating the base object of the search.
++The value
++.Dq finding
++means that the aliases are only dereferenced when locating the base object of the search.
++The value
++.Dq always
++means that the aliases are dereferenced both in searching and in locating the base object
++of the search.
++The default is
++.Dq never .
++.It Cm TimeLimit
++Specifies a time limit (in seconds) to use when performing searches.
++The number should be a non-negative integer. A
++.Cm TimeLimit
++of zero (0) specifies that the search time is unlimited. Please note that the server
++may still apply any server-side limit on the duration of a search operation.
++The default value is 10.
++.It Cm TimeOut
++Is an aliast to
++.Cm TimeLimit .
++.It Cm Bind_TimeLimit
++Specifies the timeout (in seconds) after which the poll(2)/select(2)
++following a connect(2) returns in case of no activity.
++The default value is 10.
++.It Cm Network_TimeOut
++Is an alias to
++.Cm Bind_TimeLimit .
++.It Cm Ldap_Version
++Specifies what version of the LDAP protocol should be used.
++The allowed values are 2 or 3. The default is 3.
++.It Cm Version
++Is an alias to
++.Cm Ldap_Version .
++.It Cm Bind_Policy
++Specifies the policy to use for reconnecting to an unavailable LDAP server. There are 2 available values:
++.Dq hard
++and
++.Dq soft.
++.Dq hard has 2 aliases
++.Dq hard_open
++and
++.Dq hard_init .
++The value
++.Dq hard
++means that reconects that the
++.Xr ssh-ldap-helper 8
++tries to reconnect to the LDAP server 5 times before failure. There is exponential backoff before retrying.
++The value
++.Dq soft
++means that
++.Xr ssh-ldap-helper 8
++fails immediately when it cannot connect to the LDAP seerver.
++The deault is
++.Dq hard .
++.It Cm SSLPath
++Specifies the path to the X.509 certificate database.
++There is no default.
++.It Cm SSL
++Specifies whether to use SSL/TLS or not.
++There are three allowed values:
++.Dq yes ,
++.Dq no
++and
++.Dq start_tls
++Both
++.Dq true
++and
++.Dq on
++are the aliases for
++.Dq yes .
++.Dq false
++and
++.Dq off
++are the aliases for
++.Dq no .
++If
++.Dq start_tls
++is specified then StartTLS is used rather than raw LDAP over SSL.
++The default for ldap:// is
++.Dq start_tls ,
++for ldaps://
++.Dq yes
++and
++.Dq no
++for the ldapi:// .
++In case of host based configuration the default is
++.Dq start_tls .
++.It Cm Referrals
++Specifies if the client should automatically follow referrals returned
++by LDAP servers.
++The value can be or
++.Dq yes
++or
++.Dq no .
++.Dq true
++and
++.Dq on
++are the aliases for
++.Dq yes .
++.Dq false
++and
++.Dq off
++are the aliases for
++.Dq no .
++The default is yes.
++.It Cm Restart
++Specifies whether the LDAP client library should restart the select(2) system call when interrupted.
++The value can be or
++.Dq yes
++or
++.Dq no .
++.Dq true
++and
++.Dq on
++are the aliases for
++.Dq yes .
++.Dq false
++and
++.Dq off
++are the aliases for
++.Dq no .
++The default is yes.
++.It Cm TLS_CheckPeer
++Specifies what checks to perform on server certificates in a TLS session,
++if any. The value
++can be specified as one of the following keywords:
++.Dq never ,
++.Dq hard ,
++.Dq demand ,
++.Dq allow
++and
++.Dq try .
++.Dq true ,
++.Dq on
++and
++.Dq yes
++are aliases for
++.Dq hard .
++.Dq false ,
++.Dq off
++and
++.Dq no
++are the aliases for
++.Dq never .
++The value
++.Dq never
++means that the client will not request or check any server certificate.
++The value
++.Dq allow
++means that the server certificate is requested. If no certificate is provided,
++the session proceeds normally. If a bad certificate is provided, it will
++be ignored and the session proceeds normally.
++The value
++.Dq try
++means that the server certificate is requested. If no certificate is provided,
++the session proceeds normally. If a bad certificate is provided,
++the session is immediately terminated.
++The value
++.Dq demand
++means that the server certificate is requested. If no
++certificate is provided, or a bad certificate is provided, the session
++is immediately terminated.
++The value
++.Dq hard
++is the same as
++.Dq demand .
++It requires an SSL connection. In the case of the plain conection the
++session is immediately terminated.
++The default is
++.Dq hard .
++.It Cm TLS_ReqCert
++Is an alias for 
++.Cm TLS_CheckPeer .
++.It Cm TLS_CACertFile
++Specifies the file that contains certificates for all of the Certificate
++Authorities the client will recognize.
++There is no default.
++.It Cm TLS_CACert
++Is an alias for
++.Cm TLS_CACertFile .
++.It Cm TLS_CACertDIR
++Specifies the path of a directory that contains Certificate Authority
++certificates in separate individual files. The
++.Cm TLS_CACert
++is always used before
++.Cm TLS_CACertDir .
++The specified directory must be managed with the OpenSSL c_rehash utility.
++There is no default.
++.It Cm TLS_Ciphers
++Specifies acceptable cipher suite and preference order.
++The value should be a cipher specification for OpenSSL,
++e.g.,
++.Dq HIGH:MEDIUM:+SSLv2 .
++The default is
++.Dq ALL .
++.It Cm TLS_Cipher_Suite
++Is an alias for
++.Cm TLS_Ciphers .
++.It Cm TLS_Cert
++Specifies the file that contains the client certificate.
++There is no default.
++.It Cm TLS_Certificate
++Is an alias for
++.Cm TLS_Cert .
++.It Cm TLS_Key
++Specifies the file that contains the private key that matches the certificate
++stored in the
++.Cm TLS_Cert
++file. Currently, the private key must not be protected with a password, so
++it is of critical importance that the key file is protected carefully.
++There is no default.
++.It Cm TLS_RandFile
++Specifies the file to obtain random bits from when /dev/[u]random is
++not available. Generally set to the name of the EGD/PRNGD socket.
++The environment variable RANDFILE can also be used to specify the filename.
++There is no default.
++.It Cm LogDir
++Specifies the directory used for logging by the LDAP client library.
++There is no default.
++.It Cm Debug
++Specifies the debug level used for logging by the LDAP client library.
++There is no default.
++.It Cm SSH_Filter
++Specifies the user filter applied on the LDAP serch.
++The default is no filter.
++.El
++.Sh FILES
++.Bl -tag -width Ds
++.It Pa  /etc/ssh/ldap.conf
++Ldap configuration file for
++.Xr ssh-ldap-helper 8 .
++.El
++.Sh "SEE ALSO"
++.Xr ldap.conf 5 ,
++.Xr ssh-ldap-helper 8
++.Sh HISTORY
++.Nm
++first appeared in
++OpenSSH 5.5 + PKA-LDAP .
++.Sh AUTHORS
++.An Jan F. Chadima Aq jchadima at redhat.com
diff --git a/openssh-5.9p1-mls.patch b/openssh-5.9p1-mls.patch
new file mode 100644
index 0000000..1163949
--- /dev/null
+++ b/openssh-5.9p1-mls.patch
@@ -0,0 +1,400 @@
+diff -up openssh-5.9p0/misc.c.mls openssh-5.9p0/misc.c
+--- openssh-5.9p0/misc.c.mls	2011-05-05 06:14:34.000000000 +0200
++++ openssh-5.9p0/misc.c	2011-08-30 12:29:29.157087474 +0200
+@@ -427,6 +427,7 @@ char *
+ colon(char *cp)
+ {
+ 	int flag = 0;
++	int start = 1;
+ 
+ 	if (*cp == ':')		/* Leading colon is part of file name. */
+ 		return NULL;
+@@ -442,6 +443,13 @@ colon(char *cp)
+ 			return (cp);
+ 		if (*cp == '/')
+ 			return NULL;
++		if (start) {
++		/* Slash on beginning or after dots only denotes file name. */
++			if (*cp == '/')
++				return (0);
++			if (*cp != '.')
++				start = 0;
++		}
+ 	}
+ 	return NULL;
+ }
+diff -up openssh-5.9p0/openbsd-compat/port-linux.c.mls openssh-5.9p0/openbsd-compat/port-linux.c
+--- openssh-5.9p0/openbsd-compat/port-linux.c.mls	2011-08-30 12:29:28.873086987 +0200
++++ openssh-5.9p0/openbsd-compat/port-linux.c	2011-08-30 13:28:12.584149668 +0200
+@@ -40,7 +40,15 @@
+ #ifdef WITH_SELINUX
+ #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
+ 
+ #ifndef SSH_SELINUX_UNCONFINED_TYPE
+ # define SSH_SELINUX_UNCONFINED_TYPE ":unconfined_t:"
+@@ -51,6 +59,149 @@ extern Authctxt *the_authctxt;
+ extern int inetd_flag;
+ extern int rexeced_flag;
+ 
++/* 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;
++}
++
+ static void
+ ssh_selinux_get_role_level(char **role, const char **level)
+ {
+@@ -69,14 +220,15 @@ ssh_selinux_get_role_level(char **role,
+ }
+ 
+ /* 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;
+ 	char *role;
+ 	const char *reqlvl;
+ 	int r = 0;
++	context_t con = NULL;
+  
+ 	ssh_selinux_get_role_level(&role, &reqlvl);
+ 
+@@ -87,37 +239,62 @@ 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
+@@ -126,8 +303,12 @@ ssh_selinux_getctxbyname(char *pwname)
+ 	if (lvl != NULL)
+ 		xfree(lvl);
+ #endif
+-
+-	return (sc);
++	if (role != NULL)
++		xfree(role);
++	if (con)
++		context_free(con);
++ 
++	return (r);
+ }
+ 
+ /* Setup environment variables for pam_selinux */
+@@ -165,6 +346,8 @@ void
+ ssh_selinux_setup_exec_context(char *pwname)
+ {
+ 	security_context_t user_ctx = NULL;
++	int r = 0;
++	security_context_t default_ctx = NULL;
+ 
+ 	if (!ssh_selinux_enabled())
+ 		return;
+@@ -189,22 +372,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__);
+ }
+@@ -222,7 +428,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.9p0/sshd.c.mls openssh-5.9p0/sshd.c
+--- openssh-5.9p0/sshd.c.mls	2011-08-30 12:29:22.663149706 +0200
++++ openssh-5.9p0/sshd.c	2011-08-30 12:29:29.524024777 +0200
+@@ -2082,6 +2082,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.9p1-randclean.patch b/openssh-5.9p1-randclean.patch
new file mode 100644
index 0000000..a2c5d33
--- /dev/null
+++ b/openssh-5.9p1-randclean.patch
@@ -0,0 +1,13 @@
+diff -up openssh-5.9p0/entropy.c.randclean openssh-5.9p0/entropy.c
+--- openssh-5.9p0/entropy.c.randclean	2011-08-30 13:52:45.000000000 +0200
++++ openssh-5.9p0/entropy.c	2011-08-30 13:57:44.630111338 +0200
+@@ -217,6 +217,9 @@ seed_rng(void)
+ 		fatal("OpenSSL version mismatch. Built against %lx, you "
+ 		    "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay());
+ 
++	/* clean the PRNG status when exiting the program */
++	atexit(RAND_cleanup);
++
+ #ifndef OPENSSL_PRNG_ONLY
+ 	if (RAND_status() == 1) {
+ 		debug3("RNG is ready, skipping seeding");
diff --git a/openssh-5.9p1-redhat.patch b/openssh-5.9p1-redhat.patch
new file mode 100644
index 0000000..cdb49c6
--- /dev/null
+++ b/openssh-5.9p1-redhat.patch
@@ -0,0 +1,108 @@
+diff -up openssh-5.9p0/ssh_config.redhat openssh-5.9p0/ssh_config
+--- openssh-5.9p0/ssh_config.redhat	2010-01-12 09:40:27.000000000 +0100
++++ openssh-5.9p0/ssh_config	2011-09-05 14:48:16.386439023 +0200
+@@ -45,3 +45,14 @@
+ #   PermitLocalCommand no
+ #   VisualHostKey no
+ #   ProxyCommand ssh -q -W %h:%p gateway.example.com
++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.9p0/sshd_config.0.redhat openssh-5.9p0/sshd_config.0
+--- openssh-5.9p0/sshd_config.0.redhat	2011-09-05 14:48:08.522441255 +0200
++++ openssh-5.9p0/sshd_config.0	2011-09-05 14:48:16.477443868 +0200
+@@ -581,9 +581,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
+-             default 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.9p0/sshd_config.5.redhat openssh-5.9p0/sshd_config.5
+--- openssh-5.9p0/sshd_config.5.redhat	2011-09-05 14:48:08.657564688 +0200
++++ openssh-5.9p0/sshd_config.5	2011-09-05 14:48:16.589501736 +0200
+@@ -1029,7 +1029,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.9p0/sshd_config.redhat openssh-5.9p0/sshd_config
+--- openssh-5.9p0/sshd_config.redhat	2011-09-05 14:48:16.250626793 +0200
++++ openssh-5.9p0/sshd_config	2011-09-05 15:06:01.513443553 +0200
+@@ -32,6 +32,7 @@
+ # Logging
+ # obsoletes QuietMode and FascistLogging
+ #SyslogFacility AUTH
++SyslogFacility AUTHPRIV
+ #LogLevel INFO
+ 
+ # Authentication:
+@@ -65,9 +66,11 @@ AuthorizedKeysFile	.ssh/authorized_keys
+ # 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
+@@ -77,7 +80,9 @@ AuthorizedKeysFile	.ssh/authorized_keys
+ 
+ # 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 
+@@ -89,6 +94,7 @@ AuthorizedKeysFile	.ssh/authorized_keys
+ # PAM authentication, then enable this but set PasswordAuthentication
+ # and ChallengeResponseAuthentication to 'no'.
+ #UsePAM no
++UsePAM yes
+ 
+ #TwoFactorAuthentication no
+ #SecondPubkeyAuthentication yes
+@@ -101,6 +107,7 @@ AuthorizedKeysFile	.ssh/authorized_keys
+ #AllowTcpForwarding yes
+ #GatewayPorts no
+ #X11Forwarding no
++X11Forwarding yes
+ #X11DisplayOffset 10
+ #X11UseLocalhost yes
+ #PrintMotd yes
+@@ -121,6 +128,12 @@ AuthorizedKeysFile	.ssh/authorized_keys
+ # no default banner path
+ #Banner none
+ 
++# 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
++
+ # override default of no subsystems
+ Subsystem	sftp	/usr/libexec/sftp-server
+ 
diff --git a/openssh-5.9p1-role.patch b/openssh-5.9p1-role.patch
new file mode 100644
index 0000000..8a26bdf
--- /dev/null
+++ b/openssh-5.9p1-role.patch
@@ -0,0 +1,613 @@
+diff -up openssh-5.9p0/auth-pam.c.role openssh-5.9p0/auth-pam.c
+--- openssh-5.9p0/auth-pam.c.role	2009-07-12 14:07:21.000000000 +0200
++++ openssh-5.9p0/auth-pam.c	2011-08-31 11:42:54.870087433 +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.9p0/auth-pam.h.role openssh-5.9p0/auth-pam.h
+--- openssh-5.9p0/auth-pam.h.role	2004-09-11 14:17:26.000000000 +0200
++++ openssh-5.9p0/auth-pam.h	2011-08-31 11:42:54.979086333 +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.9p0/auth.h.role openssh-5.9p0/auth.h
+--- openssh-5.9p0/auth.h.role	2011-08-31 11:42:47.760024631 +0200
++++ openssh-5.9p0/auth.h	2011-08-31 11:42:55.090151027 +0200
+@@ -59,6 +59,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.9p0/auth1.c.role openssh-5.9p0/auth1.c
+--- openssh-5.9p0/auth1.c.role	2010-08-31 14:36:39.000000000 +0200
++++ openssh-5.9p0/auth1.c	2011-08-31 11:42:55.215033075 +0200
+@@ -384,6 +384,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);
+@@ -392,11 +395,24 @@ do_authentication(Authctxt *authctxt)
+ 	user = packet_get_cstring(&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.9p0/auth2-gss.c.role openssh-5.9p0/auth2-gss.c
+--- openssh-5.9p0/auth2-gss.c.role	2011-05-05 06:04:11.000000000 +0200
++++ openssh-5.9p0/auth2-gss.c	2011-08-31 11:42:55.313025576 +0200
+@@ -260,6 +260,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;
+@@ -272,7 +273,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);
+@@ -284,6 +291,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.9p0/auth2-hostbased.c.role openssh-5.9p0/auth2-hostbased.c
+--- openssh-5.9p0/auth2-hostbased.c.role	2011-08-31 11:42:47.863023264 +0200
++++ openssh-5.9p0/auth2-hostbased.c	2011-08-31 11:42:55.421024814 +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.9p0/auth2-pubkey.c.role openssh-5.9p0/auth2-pubkey.c
+--- openssh-5.9p0/auth2-pubkey.c.role	2011-08-31 11:42:47.978087418 +0200
++++ openssh-5.9p0/auth2-pubkey.c	2011-08-31 11:42:55.551025263 +0200
+@@ -121,7 +121,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.9p0/auth2.c.role openssh-5.9p0/auth2.c
+--- openssh-5.9p0/auth2.c.role	2011-08-31 11:42:45.409026065 +0200
++++ openssh-5.9p0/auth2.c	2011-08-31 11:42:55.676024869 +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;
+ 
+@@ -249,8 +257,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.9p0/monitor.c.role openssh-5.9p0/monitor.c
+--- openssh-5.9p0/monitor.c.role	2011-08-31 11:42:53.301024819 +0200
++++ openssh-5.9p0/monitor.c	2011-08-31 11:42:55.796025812 +0200
+@@ -148,6 +148,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 *);
+@@ -231,6 +234,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
+@@ -819,6 +825,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);
+ 	}
+ #ifdef USE_PAM
+@@ -862,6 +871,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)
+ {
+@@ -1227,7 +1255,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;
+ 
+@@ -1253,6 +1281,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);
+@@ -1284,7 +1314,7 @@ monitor_valid_hostbasedblob(u_char *data
+     char *chost)
+ {
+ 	Buffer b;
+-	char *p;
++	char *p, *r;
+ 	u_int len;
+ 	int fail = 0;
+ 
+@@ -1301,6 +1331,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.9p0/monitor.h.role openssh-5.9p0/monitor.h
+--- openssh-5.9p0/monitor.h.role	2011-08-31 11:42:53.409025333 +0200
++++ openssh-5.9p0/monitor.h	2011-08-31 11:42:55.889024801 +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.9p0/monitor_wrap.c.role openssh-5.9p0/monitor_wrap.c
+--- openssh-5.9p0/monitor_wrap.c.role	2011-08-31 11:42:53.548024503 +0200
++++ openssh-5.9p0/monitor_wrap.c	2011-08-31 11:42:56.029024553 +0200
+@@ -336,6 +336,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.9p0/monitor_wrap.h.role openssh-5.9p0/monitor_wrap.h
+--- openssh-5.9p0/monitor_wrap.h.role	2011-08-31 11:42:53.660025271 +0200
++++ openssh-5.9p0/monitor_wrap.h	2011-08-31 11:42:56.131025748 +0200
+@@ -42,6 +42,9 @@ int mm_is_monitor(void);
+ DH *mm_choose_dh(int, int, int);
+ int mm_key_sign(Key *, u_char **, u_int *, u_char *, u_int);
+ 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.9p0/openbsd-compat/Makefile.in.role openssh-5.9p0/openbsd-compat/Makefile.in
+--- openssh-5.9p0/openbsd-compat/Makefile.in.role	2010-10-07 13:19:24.000000000 +0200
++++ openssh-5.9p0/openbsd-compat/Makefile.in	2011-08-31 11:48:02.404091479 +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_part_2.o port-solaris.o port-tun.o port-uw.o
+ 
+ .c.o:
+ 	$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
+diff -up openssh-5.9p0/openbsd-compat/port-linux.c.role openssh-5.9p0/openbsd-compat/port-linux.c
+--- openssh-5.9p0/openbsd-compat/port-linux.c.role	2011-08-29 08:09:57.000000000 +0200
++++ openssh-5.9p0/openbsd-compat/port-linux.c	2011-08-31 11:42:56.492087969 +0200
+@@ -31,7 +31,11 @@
+ 
+ #include "log.h"
+ #include "xmalloc.h"
++#include "servconf.h"
+ #include "port-linux.h"
++#include "key.h"
++#include "hostfile.h"
++#include "auth.h"
+ 
+ #ifdef WITH_SELINUX
+ #include <selinux/selinux.h>
+@@ -42,41 +46,63 @@
+ # define SSH_SELINUX_UNCONFINED_TYPE ":unconfined_t:"
+ #endif
+ 
+-/* Wrapper around is_selinux_enabled() to log its return value once only */
+-int
+-ssh_selinux_enabled(void)
+-{
+-	static int enabled = -1;
++extern ServerOptions options;
++extern Authctxt *the_authctxt;
++extern int inetd_flag;
++extern int rexeced_flag;
+ 
+-	if (enabled == -1) {
+-		enabled = (is_selinux_enabled() == 1);
+-		debug("SELinux support %s", enabled ? "enabled" : "disabled");
++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 (enabled);
+ }
+ 
+ /* Return the default security context for the given username */
+ 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;
++	const char *reqlvl;
++	int r = 0;
++ 
++	ssh_selinux_get_role_level(&role, &reqlvl);
+ 
+ #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()) {
+@@ -104,6 +130,36 @@ ssh_selinux_getctxbyname(char *pwname)
+ 	return (sc);
+ }
+ 
++/* 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)
+@@ -113,6 +169,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__);
+ 
+ 	user_ctx = ssh_selinux_getctxbyname(pwname);
+@@ -220,21 +294,6 @@ ssh_selinux_change_context(const char *n
+ 	xfree(newctx);
+ }
+ 
+-void
+-ssh_selinux_setfscreatecon(const char *path)
+-{
+-	security_context_t context;
+-
+-	if (!ssh_selinux_enabled())
+-		return;
+-	if (path == NULL) {
+-		setfscreatecon(NULL);
+-		return;
+-	}
+-	if (matchpathcon(path, 0700, &context) == 0)
+-		setfscreatecon(context);
+-}
+-
+ #endif /* WITH_SELINUX */
+ 
+ #ifdef LINUX_OOM_ADJUST
+diff -up openssh-5.9p0/openbsd-compat/port-linux_part_2.c.role openssh-5.9p0/openbsd-compat/port-linux_part_2.c
+--- openssh-5.9p0/openbsd-compat/port-linux_part_2.c.role	2011-08-31 11:42:56.583047619 +0200
++++ openssh-5.9p0/openbsd-compat/port-linux_part_2.c	2011-08-31 11:42:56.586178005 +0200
+@@ -0,0 +1,75 @@
++/* $Id: port-linux.c,v 1.11.4.2 2011/02/04 00:43:08 djm Exp $ */
++
++/*
++ * Copyright (c) 2005 Daniel Walsh <dwalsh at redhat.com>
++ * Copyright (c) 2006 Damien Miller <djm at openbsd.org>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Linux-specific portability code - just SELinux support at present
++ */
++
++#include "includes.h"
++
++#if defined(WITH_SELINUX) || defined(LINUX_OOM_ADJUST)
++#include <errno.h>
++#include <stdarg.h>
++#include <string.h>
++#include <stdio.h>
++
++#include "log.h"
++#include "xmalloc.h"
++#include "port-linux.h"
++#include "key.h"
++#include "hostfile.h"
++#include "auth.h"
++
++#ifdef WITH_SELINUX
++#include <selinux/selinux.h>
++#include <selinux/flask.h>
++#include <selinux/get_context_list.h>
++
++/* Wrapper around is_selinux_enabled() to log its return value once only */
++int
++ssh_selinux_enabled(void)
++{
++	static int enabled = -1;
++
++	if (enabled == -1) {
++		enabled = (is_selinux_enabled() == 1);
++		debug("SELinux support %s", enabled ? "enabled" : "disabled");
++	}
++
++	return (enabled);
++}
++
++void
++ssh_selinux_setfscreatecon(const char *path)
++{
++	security_context_t context;
++
++	if (!ssh_selinux_enabled())
++		return;
++	if (path == NULL) {
++		setfscreatecon(NULL);
++		return;
++	}
++	if (matchpathcon(path, 0700, &context) == 0)
++		setfscreatecon(context);
++}
++
++#endif /* WITH_SELINUX */
++
++#endif /* WITH_SELINUX || LINUX_OOM_ADJUST */
diff --git a/openssh-5.9p1-sesandbox.patch b/openssh-5.9p1-sesandbox.patch
new file mode 100644
index 0000000..ec84cef
--- /dev/null
+++ b/openssh-5.9p1-sesandbox.patch
@@ -0,0 +1,321 @@
+diff -up openssh-5.9p1/Makefile.in.sesandbox openssh-5.9p1/Makefile.in
+--- openssh-5.9p1/Makefile.in.sesandbox	2011-09-19 04:10:05.706521484 +0200
++++ openssh-5.9p1/Makefile.in	2011-09-19 04:10:15.092646473 +0200
+@@ -90,7 +90,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw
+ 	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
+ 	sftp-server.o sftp-common.o \
+ 	roaming_common.o roaming_serv.o \
+-	sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o
++	sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o sandbox-selinux.o
+ 
+ MANPAGES	= moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out
+ MANPAGES_IN	= moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5
+diff -up openssh-5.9p1/configure.ac.sesandbox openssh-5.9p1/configure.ac
+--- openssh-5.9p1/configure.ac.sesandbox	2011-08-18 06:48:24.000000000 +0200
++++ openssh-5.9p1/configure.ac	2011-09-19 04:10:15.193521356 +0200
+@@ -2476,7 +2476,7 @@ AC_SUBST([SSH_PRIVSEP_USER])
+ # Decide which sandbox style to use
+ sandbox_arg=""
+ AC_ARG_WITH([sandbox],
+-	[  --with-sandbox=style    Specify privilege separation sandbox (no, darwin, rlimit, systrace)],
++	[  --with-sandbox=style    Specify privilege separation sandbox (no, darwin, rlimit, systrace, selinux)],
+ 	[
+ 		if test "x$withval" = "xyes" ; then
+ 			sandbox_arg=""
+@@ -2499,6 +2499,10 @@ elif test "x$sandbox_arg" = "xdarwin" ||
+ 		AC_MSG_ERROR([Darwin seatbelt sandbox requires sandbox.h and sandbox_init function])
+ 	SANDBOX_STYLE="darwin"
+ 	AC_DEFINE([SANDBOX_DARWIN], [1], [Sandbox using Darwin sandbox_init(3)])
++elif test "x$sandbox_arg" = "xselinux"  || \
++    test "x$WITH_SELINUX" = "x1"; then
++	SANDBOX_STYLE="selinux"
++	AC_DEFINE([SANDBOX_SELINUX], [1], [Sandbox using selinux(8)])
+ elif test "x$sandbox_arg" = "xrlimit" || \
+      ( test -z "$sandbox_arg" && test "x$ac_cv_func_setrlimit" = "xyes" ) ; then
+ 	test "x$ac_cv_func_setrlimit" != "xyes" && \
+diff -up openssh-5.9p1/openbsd-compat/port-linux.c.sesandbox openssh-5.9p1/openbsd-compat/port-linux.c
+--- openssh-5.9p1/openbsd-compat/port-linux.c.sesandbox	2011-09-19 04:10:14.731521450 +0200
++++ openssh-5.9p1/openbsd-compat/port-linux.c	2011-09-19 04:10:15.292521265 +0200
+@@ -459,24 +459,24 @@ ssh_selinux_setup_pty(char *pwname, cons
+ 	debug3("%s: done", __func__);
+ }
+ 
+-void
++int
+ ssh_selinux_change_context(const char *newname)
+ {
+-	int len, newlen;
++	int len, newlen, rv = -1;
+ 	char *oldctx, *newctx, *cx;
+ 	void (*switchlog) (const char *fmt,...) = logit;
+ 
+ 	if (!ssh_selinux_enabled())
+-		return;
++		return -2;
+ 
+ 	if (getcon((security_context_t *)&oldctx) < 0) {
+ 		logit("%s: getcon failed with %s", __func__, strerror(errno));
+-		return;
++		return -1;
+ 	}
+ 	if ((cx = index(oldctx, ':')) == NULL || (cx = index(cx + 1, ':')) ==
+ 	    NULL) {
+ 		logit ("%s: unparseable context %s", __func__, oldctx);
+-		return;
++		return -1;
+ 	}
+ 
+ 	/*
+@@ -484,8 +484,10 @@ ssh_selinux_change_context(const char *n
+ 	 * security context.
+ 	 */
+ 	if (strncmp(cx, SSH_SELINUX_UNCONFINED_TYPE,
+-	    sizeof(SSH_SELINUX_UNCONFINED_TYPE) - 1) == 0)
++	    sizeof(SSH_SELINUX_UNCONFINED_TYPE) - 1) == 0) {
+ 		switchlog = debug3;
++		rv = -2;
++	}
+ 
+ 	newlen = strlen(oldctx) + strlen(newname) + 1;
+ 	newctx = xmalloc(newlen);
+@@ -499,8 +501,11 @@ ssh_selinux_change_context(const char *n
+ 	if (setcon(newctx) < 0)
+ 		switchlog("%s: setcon %s from %s failed with %s", __func__,
+ 		    newctx, oldctx, strerror(errno));
++	else
++		rv = 0;
+ 	xfree(oldctx);
+ 	xfree(newctx);
++	return rv;
+ }
+ 
+ void
+diff -up openssh-5.9p1/openbsd-compat/port-linux.h.sesandbox openssh-5.9p1/openbsd-compat/port-linux.h
+--- openssh-5.9p1/openbsd-compat/port-linux.h.sesandbox	2011-09-19 04:10:14.817647868 +0200
++++ openssh-5.9p1/openbsd-compat/port-linux.h	2011-09-19 04:10:15.401648009 +0200
+@@ -23,7 +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 *);
++int ssh_selinux_change_context(const char *);
+ void ssh_selinux_chopy_context(void);
+ void ssh_selinux_setfscreatecon(const char *);
+ #endif
+diff -up openssh-5.9p1/sandbox-darwin.c.sesandbox openssh-5.9p1/sandbox-darwin.c
+--- openssh-5.9p1/sandbox-darwin.c.sesandbox	2011-06-26 23:18:21.000000000 +0200
++++ openssh-5.9p1/sandbox-darwin.c	2011-09-19 04:10:15.490523231 +0200
+@@ -83,6 +83,12 @@ ssh_sandbox_child(struct ssh_sandbox *bo
+ }
+ 
+ void
++ssh_sandbox_privileged_child(struct ssh_sandbox *box)
++{
++	/* empty */
++}
++
++void
+ ssh_sandbox_parent_finish(struct ssh_sandbox *box)
+ {
+ 	free(box);
+diff -up openssh-5.9p1/sandbox-null.c.sesandbox openssh-5.9p1/sandbox-null.c
+--- openssh-5.9p1/sandbox-null.c.sesandbox	2011-06-23 11:45:51.000000000 +0200
++++ openssh-5.9p1/sandbox-null.c	2011-09-19 04:10:15.599458687 +0200
+@@ -58,6 +58,12 @@ ssh_sandbox_child(struct ssh_sandbox *bo
+ }
+ 
+ void
++ssh_sandbox_privileged_child(struct ssh_sandbox *box)
++{
++	/* empty */
++}
++
++void
+ ssh_sandbox_parent_finish(struct ssh_sandbox *box)
+ {
+ 	free(box);
+diff -up openssh-5.9p1/sandbox-rlimit.c.sesandbox openssh-5.9p1/sandbox-rlimit.c
+--- openssh-5.9p1/sandbox-rlimit.c.sesandbox	2011-06-23 11:45:51.000000000 +0200
++++ openssh-5.9p1/sandbox-rlimit.c	2011-09-19 04:10:16.077647289 +0200
+@@ -78,6 +78,12 @@ ssh_sandbox_child(struct ssh_sandbox *bo
+ }
+ 
+ void
++ssh_sandbox_privileged_child(struct ssh_sandbox *box)
++{
++	/* empty */
++}
++
++void
+ ssh_sandbox_parent_finish(struct ssh_sandbox *box)
+ {
+ 	free(box);
+diff -up openssh-5.9p1/sandbox-selinux.c.sesandbox openssh-5.9p1/sandbox-selinux.c
+--- openssh-5.9p1/sandbox-selinux.c.sesandbox	2011-09-19 04:10:16.179526059 +0200
++++ openssh-5.9p1/sandbox-selinux.c	2011-09-19 04:39:00.058646230 +0200
+@@ -0,0 +1,122 @@
++/* $Id: sandbox-selinux.c,v 1.0 2011/01/17 10:15:30 jfch Exp $ */
++ 
++/*
++ * Copyright 2011 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"
++
++#ifdef SANDBOX_SELINUX
++
++#include <sys/types.h>
++
++#include <errno.h>
++#include <stdarg.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <sys/resource.h>
++
++#include "log.h"
++#include "ssh-sandbox.h"
++#include "xmalloc.h"
++#include "openbsd-compat/port-linux.h"
++
++/* selinux based sandbox */
++
++struct ssh_sandbox {
++	pid_t child_pid;
++};
++
++struct ssh_sandbox *
++ssh_sandbox_init(void)
++{
++	struct ssh_sandbox *box;
++
++	/*
++	 * Strictly, we don't need to maintain any state here but we need
++	 * to return non-NULL to satisfy the API.
++	 */
++	debug3("selinux sandbox init");
++	box = xcalloc(1, sizeof(*box));
++	box->child_pid = 0;
++	return box;
++}
++
++void
++ssh_sandbox_child(struct ssh_sandbox *box)
++{
++	struct rlimit rl_zero;
++
++	rl_zero.rlim_cur = rl_zero.rlim_max = 0;
++
++	if (setrlimit(RLIMIT_FSIZE, &rl_zero) == -1)
++		fatal("%s: setrlimit(RLIMIT_FSIZE, { 0, 0 }): %s",
++			__func__, strerror(errno));
++	if (setrlimit(RLIMIT_NOFILE, &rl_zero) == -1)
++		fatal("%s: setrlimit(RLIMIT_NOFILE, { 0, 0 }): %s",
++			__func__, strerror(errno));
++#ifdef HAVE_RLIMIT_NPROC
++	if (setrlimit(RLIMIT_NPROC, &rl_zero) == -1)
++		fatal("%s: setrlimit(RLIMIT_NPROC, { 0, 0 }): %s",
++			__func__, strerror(errno));
++#endif
++}
++
++void
++ssh_sandbox_privileged_child(struct ssh_sandbox *box)
++{
++	switch (ssh_selinux_change_context("sshd_sandbox_t")) {
++	case 0:
++		debug3("selinux sandbox child sucessfully enabled");
++		break;
++	case -2:
++		logit("selinux sandbox not useful");
++		break;
++	case -1:
++		fatal("cannot set up selinux sandbox");
++	default:
++		fatal("inmternal error in selinux sandbox");
++	}
++}
++
++void
++ssh_sandbox_parent_finish(struct ssh_sandbox *box)
++{
++	free(box);
++	debug3("%s: finished", __func__);
++}
++
++void
++ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid)
++{
++	debug3("selinux sandbox parent sucessfully enabled");
++	box->child_pid = child_pid;
++}
++
++#endif /* SANDBOX_NULL */
+diff -up openssh-5.9p1/sandbox-systrace.c.sesandbox openssh-5.9p1/sandbox-systrace.c
+--- openssh-5.9p1/sandbox-systrace.c.sesandbox	2011-08-05 22:16:23.000000000 +0200
++++ openssh-5.9p1/sandbox-systrace.c	2011-09-19 04:10:16.268646532 +0200
+@@ -109,6 +109,12 @@ ssh_sandbox_child(struct ssh_sandbox *bo
+ 	close(box->child_sock);
+ }
+ 
++void
++ssh_sandbox_privileged_child(struct ssh_sandbox *box)
++{
++	/* empty */
++}
++
+ static void
+ ssh_sandbox_parent(struct ssh_sandbox *box, pid_t child_pid,
+     const struct sandbox_policy *allowed_syscalls)
+diff -up openssh-5.9p1/ssh-sandbox.h.sesandbox openssh-5.9p1/ssh-sandbox.h
+--- openssh-5.9p1/ssh-sandbox.h.sesandbox	2011-06-23 11:45:51.000000000 +0200
++++ openssh-5.9p1/ssh-sandbox.h	2011-09-19 04:10:16.392523931 +0200
+@@ -19,5 +19,6 @@ struct ssh_sandbox;
+ 
+ struct ssh_sandbox *ssh_sandbox_init(void);
+ void ssh_sandbox_child(struct ssh_sandbox *);
++void ssh_sandbox_privileged_child(struct ssh_sandbox *);
+ void ssh_sandbox_parent_finish(struct ssh_sandbox *);
+ void ssh_sandbox_parent_preauth(struct ssh_sandbox *, pid_t);
+diff -up openssh-5.9p1/sshd.c.sesandbox openssh-5.9p1/sshd.c
+--- openssh-5.9p1/sshd.c.sesandbox	2011-09-19 04:10:14.564467584 +0200
++++ openssh-5.9p1/sshd.c	2011-09-19 04:36:43.324520132 +0200
+@@ -728,10 +730,12 @@ privsep_preauth(Authctxt *authctxt)
+ 		set_log_handler(mm_log_handler, pmonitor);
+ 
+ 		/* Demote the child */
+-		if (getuid() == 0 || geteuid() == 0)
++		if (getuid() == 0 || geteuid() == 0) {
++			ssh_sandbox_privileged_child(box);
+ 			privsep_preauth_child();
++		}
+ 		setproctitle("%s", "[net]");
+ 		if (box != NULL) {
+ 			ssh_sandbox_child(box);
+ 			xfree(box);
+ 		}
diff --git a/openssh-5.9p1-sftp-chroot.patch b/openssh-5.9p1-sftp-chroot.patch
new file mode 100644
index 0000000..cfe4366
--- /dev/null
+++ b/openssh-5.9p1-sftp-chroot.patch
@@ -0,0 +1,63 @@
+diff -up openssh-5.9p0/openbsd-compat/port-linux.c.sftp-chroot openssh-5.9p0/openbsd-compat/port-linux.c
+--- openssh-5.9p0/openbsd-compat/port-linux.c.sftp-chroot	2011-09-01 04:12:22.743024608 +0200
++++ openssh-5.9p0/openbsd-compat/port-linux.c	2011-09-01 04:12:23.069088065 +0200
+@@ -503,6 +503,23 @@ ssh_selinux_change_context(const char *n
+ 	xfree(newctx);
+ }
+ 
++void
++ssh_selinux_copy_context(void)
++{
++	char *ctx;
++
++	if (!ssh_selinux_enabled())
++		return;
++
++	if (getexeccon((security_context_t *)&ctx) < 0) {
++		logit("%s: getcon failed with %s", __func__, strerror (errno));
++		return;
++	}
++	if (setcon(ctx) < 0)
++		logit("%s: setcon failed with %s", __func__, strerror (errno));
++	xfree(ctx);
++}
++
+ #endif /* WITH_SELINUX */
+ 
+ #ifdef LINUX_OOM_ADJUST
+diff -up openssh-5.9p0/openbsd-compat/port-linux.h.sftp-chroot openssh-5.9p0/openbsd-compat/port-linux.h
+--- openssh-5.9p0/openbsd-compat/port-linux.h.sftp-chroot	2011-01-25 02:16:18.000000000 +0100
++++ openssh-5.9p0/openbsd-compat/port-linux.h	2011-09-01 04:12:23.163088777 +0200
+@@ -24,6 +24,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 *);
++void ssh_selinux_chopy_context(void);
+ void ssh_selinux_setfscreatecon(const char *);
+ #endif
+ 
+diff -up openssh-5.9p0/session.c.sftp-chroot openssh-5.9p0/session.c
+--- openssh-5.9p0/session.c.sftp-chroot	2011-09-01 04:12:19.698049195 +0200
++++ openssh-5.9p0/session.c	2011-09-01 04:40:03.598148719 +0200
+@@ -1519,6 +1519,9 @@ do_setusercontext(struct passwd *pw)
+ 			    pw->pw_uid);
+ 			chroot_path = percent_expand(tmp, "h", pw->pw_dir,
+ 			    "u", pw->pw_name, (char *)NULL);
++#ifdef WITH_SELINUX
++			ssh_selinux_change_context("chroot_user_t");
++#endif
+ 			safely_chroot(chroot_path, pw->pw_uid);
+ 			free(tmp);
+ 			free(chroot_path);
+@@ -1788,7 +1791,10 @@ do_child(Session *s, const char *command
+ 		optind = optreset = 1;
+ 		__progname = argv[0];
+ #ifdef WITH_SELINUX
+-		ssh_selinux_change_context("sftpd_t");
++		if (options.chroot_directory == NULL ||
++		    strcasecmp(options.chroot_directory, "none") == 0) {
++			ssh_selinux_copy_context();
++		}
+ #endif
+ 		exit(sftp_server_main(i, argv, s->pw));
+ 	}
diff --git a/openssh-5.9p1-vendor.patch b/openssh-5.9p1-vendor.patch
new file mode 100644
index 0000000..3e63d3b
--- /dev/null
+++ b/openssh-5.9p1-vendor.patch
@@ -0,0 +1,157 @@
+diff -up openssh-5.9p0/configure.ac.vendor openssh-5.9p0/configure.ac
+--- openssh-5.9p0/configure.ac.vendor	2011-09-03 20:24:29.899501572 +0200
++++ openssh-5.9p0/configure.ac	2011-09-03 20:24:39.153501595 +0200
+@@ -4131,6 +4131,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
+@@ -4357,6 +4363,7 @@ echo "           Translate v4 in v6 hack
+ echo "                  BSD Auth support: $BSD_AUTH_MSG"
+ echo "              Random number source: $RAND_MSG"
+ echo "             Privsep sandbox style: $SANDBOX_STYLE"
++echo "                Vendor patch level: $SSH_VENDOR_PATCHLEVEL"
+ 
+ echo ""
+ 
+diff -up openssh-5.9p0/servconf.c.vendor openssh-5.9p0/servconf.c
+--- openssh-5.9p0/servconf.c.vendor	2011-09-03 20:24:29.080500853 +0200
++++ openssh-5.9p0/servconf.c	2011-09-03 20:27:15.727564566 +0200
+@@ -130,6 +130,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;
+@@ -300,6 +301,8 @@ fill_default_server_options(ServerOption
+ 		options->ip_qos_interactive = IPTOS_LOWDELAY;
+ 	if (options->ip_qos_bulk == -1)
+ 		options->ip_qos_bulk = IPTOS_THROUGHPUT;
++	if (options->show_patchlevel == -1)
++ 		options->show_patchlevel = 0;
+ 
+ 	/* Turn privilege separation on by default */
+ 	if (use_privsep == -1)
+@@ -338,7 +341,7 @@ typedef enum {
+ 	sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
+ 	sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
+ 	sMaxStartups, sMaxAuthTries, sMaxSessions,
+-	sBanner, sUseDNS, sHostbasedAuthentication,
++	sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication,
+ 	sHostbasedUsesNameFromPacketOnly, sTwoFactorAuthentication,
+ 	sSecondPubkeyAuthentication, sSecondGssAuthentication,
+ 	sSecondPasswordAuthentication, sSecondKbdInteractiveAuthentication,
+@@ -470,6 +473,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 },
+@@ -1152,6 +1156,10 @@ process_server_config_line(ServerOptions
+ 		multistate_ptr = multistate_privsep;
+ 		goto parse_multistate;
+ 
++	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)
+@@ -1849,6 +1857,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.9p0/servconf.h.vendor openssh-5.9p0/servconf.h
+--- openssh-5.9p0/servconf.h.vendor	2011-09-03 20:24:29.179632045 +0200
++++ openssh-5.9p0/servconf.h	2011-09-03 20:24:39.426502323 +0200
+@@ -148,6 +148,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.9p0/sshd.c.vendor openssh-5.9p0/sshd.c
+--- openssh-5.9p0/sshd.c.vendor	2011-09-03 20:24:35.987501565 +0200
++++ openssh-5.9p0/sshd.c	2011-09-03 20:24:39.542501643 +0200
+@@ -431,7 +431,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. */
+@@ -1627,7 +1627,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 -up openssh-5.9p0/sshd_config.0.vendor openssh-5.9p0/sshd_config.0
+--- openssh-5.9p0/sshd_config.0.vendor	2011-09-03 20:24:37.524438185 +0200
++++ openssh-5.9p0/sshd_config.0	2011-09-03 20:24:39.677508255 +0200
+@@ -556,6 +556,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.9p0/sshd_config.5.vendor openssh-5.9p0/sshd_config.5
+--- openssh-5.9p0/sshd_config.5.vendor	2011-09-03 20:24:37.640442022 +0200
++++ openssh-5.9p0/sshd_config.5	2011-09-03 20:24:40.176544206 +0200
+@@ -952,6 +952,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.9p0/sshd_config.vendor openssh-5.9p0/sshd_config
+--- openssh-5.9p0/sshd_config.vendor	2011-09-03 20:24:37.770439735 +0200
++++ openssh-5.9p0/sshd_config	2011-09-03 20:24:40.278628002 +0200
+@@ -120,6 +120,7 @@ X11Forwarding yes
+ #Compression delayed
+ #ClientAliveInterval 0
+ #ClientAliveCountMax 3
++#ShowPatchLevel no
+ #UseDNS yes
+ #PidFile /var/run/sshd.pid
+ #MaxStartups 10
diff --git a/openssh-nukeacss.sh b/openssh-nukeacss.sh
new file mode 100755
index 0000000..ecb90f3
--- /dev/null
+++ b/openssh-nukeacss.sh
@@ -0,0 +1,21 @@
+#!/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,9 @@
+
+ /* compatibility with old or broken OpenSSL versions */
+ #include "openbsd-compat/openssl-compat.h"
++#undef USE_CIPHER_ACSS
++#undef EVP_acss
++#define EVP_acss NULL
+
+ extern const EVP_CIPHER *evp_ssh1_bf(void);
+ extern const EVP_CIPHER *evp_ssh1_3des(void);
+EOF
+echo "Well done."
diff --git a/sources b/sources
index e69de29..851576e 100644
--- a/sources
+++ b/sources
@@ -0,0 +1 @@
+085cfbb262f1b8b875aadea6fba60b1b  openssh-5.9p1-noacss.tar.bz2


More information about the scm-commits mailing list