Blob Blame History Raw
diff -up openssh-5.5p1/auth2-pubkey.c.pka openssh-5.5p1/auth2-pubkey.c
--- openssh-5.5p1/auth2-pubkey.c.pka	2010-03-21 19:51:21.000000000 +0100
+++ openssh-5.5p1/auth2-pubkey.c	2010-04-29 11:08:25.000000000 +0200
@@ -178,27 +178,15 @@ done:
 
 /* return 1 if user allows given key */
 static int
-user_key_allowed2(struct passwd *pw, Key *key, char *file)
+user_search_key_in_file(FILE *f, char *file, Key* key, struct passwd *pw)
 {
 	char line[SSH_MAX_PUBKEY_BYTES];
 	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);
 
@@ -273,8 +261,6 @@ user_key_allowed2(struct passwd *pw, Key
 			break;
 		}
 	}
-	restore_uid();
-	fclose(f);
 	key_free(found);
 	if (!found_key)
 		debug2("key not found");
@@ -321,13 +307,153 @@ 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_PUBKEY_AGENT
+
+#define WHITESPACE " \t\r\n"
+
+/* return 1 if user allows given key */
+static int
+user_key_via_agent_allowed2(struct passwd *pw, Key *key)
+{
+	FILE *f;
+	int found_key = 0;
+	char *pubkey_agent_string = NULL;
+	char *tmp_pubkey_agent_string = NULL;
+	char *progname;
+	char *cp;
+	struct passwd *runas_pw;
+	struct stat st;
+
+	if (options.pubkey_agent == NULL || options.pubkey_agent[0] != '/')
+		return -1;
+
+	/* get the run as identity from config */
+	runas_pw = (options.pubkey_agent_runas == NULL)? pw
+	    : getpwnam (options.pubkey_agent_runas);
+	if (!runas_pw) {
+		error("%s: getpwnam(\"%s\"): %s", __func__,
+		    options.pubkey_agent_runas, strerror(errno));
+		return 0;
+	}
+
+	/* Temporarily use the specified uid. */
+	if (runas_pw->pw_uid != 0)
+		temporarily_use_uid(runas_pw);
+
+	pubkey_agent_string = percent_expand(options.pubkey_agent,
+	    "h", pw->pw_dir, "u", pw->pw_name, (char *)NULL);
+
+	/* Test whether agent can be modified by non root user */
+	tmp_pubkey_agent_string = xstrdup (pubkey_agent_string);
+	progname = strtok (tmp_pubkey_agent_string, WHITESPACE);
+
+	debug3("%s: checking program '%s'", __func__, progname);
+
+	if (stat (progname, &st) < 0) {
+		error("%s: stat(\"%s\"): %s", __func__,
+		    progname, strerror(errno));
+		goto go_away;
+	}
+
+	if (st.st_uid != 0 || (st.st_mode & 022) != 0) {
+		error("bad ownership or modes for pubkey agent \"%s\"",
+		    progname);
+		goto go_away;
+	}
+
+	if (!S_ISREG(st.st_mode)) {
+		error("pubkey agent \"%s\" is not a regular file",
+		    progname);
+		goto go_away;
+	}
+
+	/*
+	 * Descend the path, checking that each component is a
+	 * root-owned directory with strict permissions.
+	 */
+	do {
+		if ((cp = strrchr(progname, '/')) == NULL)
+			break;
+		else 
+			*cp = '\0';
+	
+		debug3("%s: checking component '%s'", __func__, progname);
+
+		if (stat(progname, &st) != 0) {
+			error("%s: stat(\"%s\"): %s", __func__,
+			    progname, strerror(errno));
+			goto go_away;
+		}
+		if (st.st_uid != 0 || (st.st_mode & 022) != 0) {
+			error("bad ownership or modes for pubkey agent path component \"%s\"",
+			    progname);
+			goto go_away;
+		}
+		if (!S_ISDIR(st.st_mode)) {
+			error("pubkey agent path component \"%s\" is not a directory",
+			    progname);
+			goto go_away;
+		}
+	} while (0);
+
+	/* open the pipe and read the keys */
+	f = popen (pubkey_agent_string, "r");
+	if (!f) {
+		error("%s: popen (\"%s\", \"r\"): %s", __func__,
+		    pubkey_agent_string, strerror (errno));
+		goto go_away;
+	}
+
+	found_key = user_search_key_in_file (f, options.pubkey_agent, key, pw);
+	pclose (f);
+
+go_away:
+	if (tmp_pubkey_agent_string)
+		xfree (tmp_pubkey_agent_string);
+	if (pubkey_agent_string)
+		xfree (pubkey_agent_string);
+
+	if (runas_pw->pw_uid != 0)
+		restore_uid();
+	return found_key;
+}
+#endif
+
+/* check whether given key is in <pkey_agent or .ssh/authorized_keys* */
 int
 user_key_allowed(struct passwd *pw, Key *key)
 {
 	int success;
 	char *file;
 
+#ifdef WITH_PUBKEY_AGENT
+	success = user_key_via_agent_allowed2(pw, key);
+	if (success >= 0)
+		return success;
+#endif
+
 	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.5p1/config.h.in.pka openssh-5.5p1/config.h.in
--- openssh-5.5p1/config.h.in.pka	2010-04-16 02:17:09.000000000 +0200
+++ openssh-5.5p1/config.h.in	2010-04-29 09:40:17.000000000 +0200
@@ -1,5 +1,8 @@
 /* config.h.in.  Generated from configure.ac by autoheader.  */
 
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
 /* Define if you have a getaddrinfo that fails for the all-zeros IPv6 address
    */
 #undef AIX_GETNAMEINFO_HACK
@@ -536,6 +539,54 @@
 /* Define to 1 if you have the <lastlog.h> header file. */
 #undef HAVE_LASTLOG_H
 
+/* Define to 1 if you have the <lber.h> header file. */
+#undef HAVE_LBER_H
+
+/* Define to 1 if you have the `ldapssl_init' function. */
+#undef HAVE_LDAPSSL_INIT
+
+/* Define to 1 if you have the `ldap_controls_free' function. */
+#undef HAVE_LDAP_CONTROLS_FREE
+
+/* Define to 1 if you have the `ldap_get_lderrno' function. */
+#undef HAVE_LDAP_GET_LDERRNO
+
+/* Define to 1 if you have the `ldap_get_option' function. */
+#undef HAVE_LDAP_GET_OPTION
+
+/* Define to 1 if you have the <ldap.h> header file. */
+#undef HAVE_LDAP_H
+
+/* Define to 1 if you have the `ldap_init' function. */
+#undef HAVE_LDAP_INIT
+
+/* Define to 1 if you have the `ldap_initialize' function. */
+#undef HAVE_LDAP_INITIALIZE
+
+/* Define to 1 if you have the `ldap_memfree' function. */
+#undef HAVE_LDAP_MEMFREE
+
+/* Define to 1 if you have the `ldap_parse_result' function. */
+#undef HAVE_LDAP_PARSE_RESULT
+
+/* Define to 1 if you have the `ldap_pvt_tls_set_option' function. */
+#undef HAVE_LDAP_PVT_TLS_SET_OPTION
+
+/* Define to 1 if you have the `ldap_set_lderrno' function. */
+#undef HAVE_LDAP_SET_LDERRNO
+
+/* Define to 1 if you have the `ldap_set_option' function. */
+#undef HAVE_LDAP_SET_OPTION
+
+/* Define to 1 if you have the `ldap_set_rebind_proc' function. */
+#undef HAVE_LDAP_SET_REBIND_PROC
+
+/* Define to 1 if you have the <ldap_ssl.h> header file. */
+#undef HAVE_LDAP_SSL_H
+
+/* Define to 1 if you have the `ldap_start_tls_s' function. */
+#undef HAVE_LDAP_START_TLS_S
+
 /* Define to 1 if you have the `bsm' library (-lbsm). */
 #undef HAVE_LIBBSM
 
@@ -921,13 +972,13 @@
 /* define if you have struct sockaddr_in6 data type */
 #undef HAVE_STRUCT_SOCKADDR_IN6
 
-/* Define to 1 if `sin6_scope_id' is member of `struct sockaddr_in6'. */
+/* Define to 1 if `sin6_scope_id' is a member of `struct sockaddr_in6'. */
 #undef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
 
 /* define if you have struct sockaddr_storage data type */
 #undef HAVE_STRUCT_SOCKADDR_STORAGE
 
-/* Define to 1 if `st_blksize' is member of `struct stat'. */
+/* Define to 1 if `st_blksize' is a member of `struct stat'. */
 #undef HAVE_STRUCT_STAT_ST_BLKSIZE
 
 /* Define to 1 if the system has the type `struct timespec'. */
@@ -1191,6 +1242,9 @@
 /* Define if pututxline updates lastlog too */
 #undef LASTLOG_WRITE_PUTUTXLINE
 
+/* number arguments of ldap_set_rebind_proc */
+#undef LDAP_SET_REBIND_PROC_ARGS
+
 /* Define if you want TCP Wrappers support */
 #undef LIBWRAP
 
@@ -1274,6 +1328,9 @@
 /* Define to the one symbol short name of this package. */
 #undef PACKAGE_TARNAME
 
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 
@@ -1418,12 +1475,26 @@
 /* Define if you want IRIX project management */
 #undef WITH_IRIX_PROJECT
 
+/* Enable LDAP pubkey support */
+#undef WITH_LDAP_PUBKEY
+
+/* Enable pubkey agent support */
+#undef WITH_PUBKEY_AGENT
+
 /* Define if you want SELinux support. */
 #undef WITH_SELINUX
 
-/* Define to 1 if your processor stores words with the most significant byte
-   first (like Motorola and SPARC, unlike Intel and VAX). */
-#undef WORDS_BIGENDIAN
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
 
 /* Define if xauth is found in your path */
 #undef XAUTH_PATH
diff -up openssh-5.5p1/configure.ac.pka openssh-5.5p1/configure.ac
--- openssh-5.5p1/configure.ac.pka	2010-04-10 14:58:01.000000000 +0200
+++ openssh-5.5p1/configure.ac	2010-04-29 11:08:25.000000000 +0200
@@ -1346,6 +1346,118 @@ AC_ARG_WITH(audit,
 	esac ]
 )
 
+# Check whether user wants pubkey agent support
+PKA_MSG="no"
+AC_ARG_WITH(pka,
+	[  --with-pka      Enable pubkey agent support],
+	[
+		if test "x$withval" != "xno" ; then
+			AC_DEFINE([WITH_PUBKEY_AGENT], 1, [Enable pubkey agent support])
+			PKA_MSG="yes"
+		fi
+	]
+)
+
+# 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 \
@@ -4181,6 +4293,8 @@ echo "                   SELinux support
 echo "                 Smartcard support: $SCARD_MSG"
 echo "                     S/KEY support: $SKEY_MSG"
 echo "              TCP Wrappers support: $TCPW_MSG"
+echo "                       PKA support: $PKA_MSG"
+echo "                      LDAP support: $LDAP_MSG"
 echo "              MD5 password support: $MD5_MSG"
 echo "                   libedit support: $LIBEDIT_MSG"
 echo "  Solaris process contract support: $SPC_MSG"
diff -up openssh-5.5p1/ldapbody.c.pka openssh-5.5p1/ldapbody.c
--- openssh-5.5p1/ldapbody.c.pka	2010-04-29 11:08:25.000000000 +0200
+++ openssh-5.5p1/ldapbody.c	2010-04-29 11:08:25.000000000 +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
+				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.5p1/ldapbody.h.pka openssh-5.5p1/ldapbody.h
--- openssh-5.5p1/ldapbody.h.pka	2010-04-29 11:08:25.000000000 +0200
+++ openssh-5.5p1/ldapbody.h	2010-04-29 11:08:25.000000000 +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.5p1/ldapconf.c.pka openssh-5.5p1/ldapconf.c
--- openssh-5.5p1/ldapconf.c.pka	2010-04-29 11:08:25.000000000 +0200
+++ openssh-5.5p1/ldapconf.c	2010-04-29 11:08:25.000000000 +0200
@@ -0,0 +1,665 @@
+/* $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_Certificate, 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[] = {
+	{ "Host", lHost },
+	{ "URI", lURI },
+	{ "Base", lBase },
+	{ "BindDN", lBindDN },
+	{ "BindPW", lBindPW },
+	{ "RootBindDN", lRootBindDN },
+	{ "Scope", lScope },
+	{ "Deref", lDeref },
+	{ "Port", lPort },
+	{ "Timelimit", lTimeLimit },
+	{ "Bind_Timelimit", lBind_TimeLimit },
+	{ "Ldap_Version", lLdap_Version },
+	{ "Bind_Policy", lBind_Policy },
+	{ "SSLPath", lSSLPath },
+	{ "SSL", lSSL },
+	{ "Referrals", lReferrals },
+	{ "Restart", lRestart },
+	{ "TLS_CheckPeer", lTLS_CheckPeer },
+	{ "TLS_Certificate", lTLS_Certificate },
+	{ "TLS_CaCertFile", lTLS_CaCertFile },
+	{ "TLS_CaCertDir", lTLS_CaCertDir },
+	{ "TLS_Ciphers", lTLS_Ciphers },
+	{ "TLS_Cert", lTLS_Cert },
+	{ "TLS_Key", lTLS_Key },
+	{ "TLS_RandFile", lTLS_RandFile },
+	{ "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"))
+			value = LDAP_SCOPE_SUBTREE;
+		else if (!strcasecmp (arg, "one"))
+			value = LDAP_SCOPE_ONELEVEL;
+		else if (!strcasecmp (arg, "base"))
+			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)
+			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)
+			value = LDAP_OPT_X_TLS_NEVER;
+		else if (strcasecmp(arg, "hard") == 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") || strcmp (ludp->lud_scheme, "ldapi"))
+				    options.ssl = 0;
+				else if (strcmp (ludp->lud_scheme, "ldaps"))
+				    options.ssl = 2;
+			}
+			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.5p1/ldapconf.h.pka openssh-5.5p1/ldapconf.h
--- openssh-5.5p1/ldapconf.h.pka	2010-04-29 11:08:25.000000000 +0200
+++ openssh-5.5p1/ldapconf.h	2010-04-29 11:08:25.000000000 +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.5p1/ldap-helper.c.pka openssh-5.5p1/ldap-helper.c
--- openssh-5.5p1/ldap-helper.c.pka	2010-04-29 11:08:25.000000000 +0200
+++ openssh-5.5p1/ldap-helper.c	2010-04-29 11:08:25.000000000 +0200
@@ -0,0 +1,154 @@
+/* $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/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/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 int 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 {
+		fatal ("Not yet implemented");
+/* TODO
+ * open unix socket a run the loop on it
+ */
+	}
+
+	ldap_do_close();
+	return 0;
+}
+
+/* Ugly hack */
+void   *buffer_get_string(Buffer *b, u_int *l) {}
+void    buffer_put_string(Buffer *b, const void *f, u_int l) {}
+
diff -up openssh-5.5p1/ldap-helper.h.pka openssh-5.5p1/ldap-helper.h
--- openssh-5.5p1/ldap-helper.h.pka	2010-04-29 11:08:25.000000000 +0200
+++ openssh-5.5p1/ldap-helper.h	2010-04-29 11:08:25.000000000 +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.5p1/ldapincludes.h.pka openssh-5.5p1/ldapincludes.h
--- openssh-5.5p1/ldapincludes.h.pka	2010-04-29 11:08:26.000000000 +0200
+++ openssh-5.5p1/ldapincludes.h	2010-04-29 11:08:26.000000000 +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.5p1/ldapmisc.c.pka openssh-5.5p1/ldapmisc.c
--- openssh-5.5p1/ldapmisc.c.pka	2010-04-29 11:08:26.000000000 +0200
+++ openssh-5.5p1/ldapmisc.c	2010-04-29 11:08:26.000000000 +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.5p1/ldapmisc.h.pka openssh-5.5p1/ldapmisc.h
--- openssh-5.5p1/ldapmisc.h.pka	2010-04-29 11:08:26.000000000 +0200
+++ openssh-5.5p1/ldapmisc.h	2010-04-29 11:08:26.000000000 +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.5p1/lpk-user-example.txt.pka openssh-5.5p1/lpk-user-example.txt
--- openssh-5.5p1/lpk-user-example.txt.pka	2010-04-29 11:08:26.000000000 +0200
+++ openssh-5.5p1/lpk-user-example.txt	2010-04-29 11:08:26.000000000 +0200
@@ -0,0 +1,117 @@
+
+Post to ML -> User Made Quick Install Doc.
+Contribution from John Lane <john@lane.uk.net>
+
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+OpenSSH LDAP keystore Patch
+===========================
+
+NOTE: these notes are a transcript of a specific installation
+      they work for me, your specifics may be different!
+      from John Lane March 17th 2005         john@lane.uk.net
+
+This is a patch to OpenSSH 4.0p1 to allow it to obtain users' public keys
+from their LDAP record as an alternative to ~/.ssh/authorized_keys.
+
+(Assuming here that necessary build stuff is in $BUILD)
+
+cd $BUILD/openssh-4.0p1
+patch -Np1 -i $BUILD/openssh-lpk-4.0p1-0.3.patch
+mkdir -p /var/empty &&
+./configure --prefix=/usr --sysconfdir=/etc/ssh \
+    --libexecdir=/usr/sbin --with-md5-passwords --with-pam \
+    --with-libs="-lldap" --with-cppflags="-DWITH_LDAP_PUBKEY"
+Now do.
+make &&
+make install
+
+Add the following config to /etc/ssh/ssh_config
+UseLPK yes
+LpkServers ldap://myhost.mydomain.com
+LpkUserDN  ou=People,dc=mydomain,dc=com
+
+We need to tell sshd about the SSL keys during boot, as root's
+environment does not exist at that time. Edit /etc/rc.d/init.d/sshd.
+Change the startup code from this:
+                echo "Starting SSH Server..."
+                loadproc /usr/sbin/sshd
+                ;;
+to this:
+                echo "Starting SSH Server..."
+                LDAPRC="/root/.ldaprc" loadproc /usr/sbin/sshd
+                ;;
+
+Re-start the sshd daemon:
+/etc/rc.d/init.d/sshd restart
+
+Install the additional LDAP schema
+cp $BUILD/openssh-lpk-0.2.schema  /etc/openldap/schema/openssh.schema
+
+Now add the openSSH LDAP schema to /etc/openldap/slapd.conf:
+Add the following to the end of the existing block of schema includes
+include         /etc/openldap/schema/openssh.schema
+
+Re-start the LDAP server:
+/etc/rc.d/init.d/slapd restart
+
+To add one or more public keys to a user, eg "testuser" :
+ldapsearch -x -W -Z -LLL -b "uid=testuser,ou=People,dc=mydomain,dc=com" -D
+"uid=testuser,ou=People,dc=mydomain,dc=com" > /tmp/testuser
+
+append the following to this /tmp/testuser file
+objectclass: ldapPublicKey
+sshPublicKey: ssh-rsa
+AAAAB3NzaC1yc2EAAAABJQAAAIB3dsrwqXqD7E4zYYrxwdDKBUQxKMioXy9pxFVai64kAPxjU9KS
+qIo7QfkjslfsjflksjfldfkjsldfjLX/5zkzRmT28I5piGzunPv17S89z8XwSsuAoR1t86t+5dlI
+7eZE/gVbn2UQkQq7+kdDTS2yXV6VnC52N/kKLG3ciBkBAw== General Purpose RSA Key
+
+Then do a modify:
+ldapmodify -x -D "uid=testuser,ou=People,dc=mydomain,dc=com" -W -f
+/tmp/testuser -Z
+Enter LDAP Password:
+modifying entry "uid=testuser,ou=People,dc=mydomain,dc=com"
+And check the modify is ok:
+ldapsearch -x -W -Z -b "uid=testuser,ou=People,dc=mydomain,dc=com" -D
+"uid=testuser,ou=People,dc=mydomain,dc=com"
+Enter LDAP Password:
+# extended LDIF
+#
+# LDAPv3
+# base <uid=testuser,ou=People,dc=mydomain,dc=com> with scope sub
+# filter: (objectclass=*)
+# requesting: ALL
+#
+
+# testuser, People, mydomain.com
+dn: uid=testuser,ou=People,dc=mydomain,dc=com
+uid: testuser
+cn: testuser
+objectClass: account
+objectClass: posixAccount
+objectClass: top
+objectClass: shadowAccount
+objectClass: ldapPublicKey
+shadowLastChange: 12757
+shadowMax: 99999
+shadowWarning: 7
+loginShell: /bin/bash
+uidNumber: 9999
+gidNumber: 501
+homeDirectory: /home/testuser
+userPassword:: e1NTSEF9UDgwV1hnM1VjUDRJK0k1YnFiL1d4ZUJObXlZZ3Z3UTU=
+sshPublicKey: ssh-rsa
+AAAAB3NzaC1yc2EAAAABJQAAAIB3dsrwqXqD7E4zYYrxwdDKBUQxKMioXy9pxFVai64kAPxjU9KSqIo7QfkjslfsjflksjfldfkjsldfjLX/5zkzRmT28I5piGzunPv17S89z
+8XwSsuAoR1t86t+5dlI7eZE/gVbn2UQkQq7+kdDTS2yXV6VnC52N/kKLG3ciBkBAw== General Purpose RSA Key
+
+# search result
+search: 3
+result: 0 Success
+
+# numResponses: 2
+# numEntries: 1
+
+Now start a ssh session to user "testuser" from usual ssh client (e.g.
+puTTY). Login should succeed.
+
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff -up openssh-5.5p1/Makefile.in.pka openssh-5.5p1/Makefile.in
--- openssh-5.5p1/Makefile.in.pka	2010-03-13 22:41:34.000000000 +0100
+++ openssh-5.5p1/Makefile.in	2010-04-29 11:08:26.000000000 +0200
@@ -26,6 +26,7 @@ ASKPASS_PROGRAM=$(libexecdir)/ssh-askpas
 SFTP_SERVER=$(libexecdir)/sftp-server
 SSH_KEYSIGN=$(libexecdir)/ssh-keysign
 SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
+SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper
 RAND_HELPER=$(libexecdir)/ssh-rand-helper
 PRIVSEP_PATH=@PRIVSEP_PATH@
 SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
@@ -61,8 +62,9 @@ EXEEXT=@EXEEXT@
 
 INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
 INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
+INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@
 
-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT)
+TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT)
 
 LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
 	canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \
@@ -93,8 +95,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw
 	audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \
 	roaming_common.o roaming_serv.o
 
-MANPAGES	= moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out ssh-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-rand-helper.8 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-rand-helper.8.out ssh-keysign.8.out ssh-pkcs11-helper.8.out ssh-ldap-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-rand-helper.8 ssh-keysign.8 ssh-pkcs11-helper.8 ssh-ldap-helper.8 sshd_config.5 ssh_config.5
 MANTYPE		= @MANTYPE@
 
 CONFIGFILES=sshd_config.out ssh_config.out moduli.out
@@ -162,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 $(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)
 
@@ -266,6 +271,9 @@ install-files:
 	fi
 	$(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) ; \
+	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
@@ -285,6 +293,9 @@ 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 ; \
+	fi
 	-rm -f $(DESTDIR)$(bindir)/slogin
 	ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
@@ -384,6 +395,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.5p1/openssh-lpk-openldap.schema.pka openssh-5.5p1/openssh-lpk-openldap.schema
--- openssh-5.5p1/openssh-lpk-openldap.schema.pka	2010-04-29 11:08:26.000000000 +0200
+++ openssh-5.5p1/openssh-lpk-openldap.schema	2010-04-29 11:08:26.000000000 +0200
@@ -0,0 +1,21 @@
+#
+# LDAP Public Key Patch schema for use with openssh-ldappubkey
+#                              useful with PKA-LDAP also
+#
+# Author: Eric AUGE <eau@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.5p1/openssh-lpk-sun.schema.pka openssh-5.5p1/openssh-lpk-sun.schema
--- openssh-5.5p1/openssh-lpk-sun.schema.pka	2010-04-29 11:08:26.000000000 +0200
+++ openssh-5.5p1/openssh-lpk-sun.schema	2010-04-29 11:08:26.000000000 +0200
@@ -0,0 +1,23 @@
+#
+# LDAP Public Key Patch schema for use with openssh-ldappubkey
+#                              useful with PKA-LDAP also
+#
+# Author: Eric AUGE <eau@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.5p1/README.lpk.pka openssh-5.5p1/README.lpk
--- openssh-5.5p1/README.lpk.pka	2010-04-29 11:08:26.000000000 +0200
+++ openssh-5.5p1/README.lpk	2010-04-29 11:08:26.000000000 +0200
@@ -0,0 +1,268 @@
+OpenSSH LDAP PUBLIC KEY PATCH 
+Copyright (c) 2003 Eric AUGE (eau@phear.org)
+All rights reserved.
+
+Rewriten by Jan F. Chadima (jchadima@redhat.com)
+Copyright (c) 2010 Red Hat, Inc.
+The new PKA-LDAP patch is rewritten from the scratch.
+LDAP schema and part of the documentation is based on original
+LPK project (http://code.google.com/p/openssh-lpk),
+copyright (c) 2003 Eric AUGE
+The new openssh configuration is different from the original LPK one.
+
+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.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+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.
+
+purposes of this patch:
+
+This patch would help to have authentication centralization policy
+using ssh public key authentication.
+This patch could be an alternative to other "secure" authentication system
+working in a similar way (Kerberos, SecurID, etc...), except the fact 
+that it's based on OpenSSH and its public key abilities.
+
+>> FYI: <<
+'uid': means unix accounts existing on the current server
+'ServerGroup:' mean server group configured on the current server by the SSH_Filter option in the ldap.conf.
+
+example schema:
+
+
+                                  server1 (uid: eau,rival,toto) (ServerGroup: unix)
+                ___________      /
+               /           \ --- - server3 (uid: eau, titi) (ServerGroup: unix)
+              | LDAP Server |    \
+	      | eau  ,rival |     server2 (uid: rival, eau) (ServerGroup: unix)
+	      | titi ,toto  |
+	      | userx,....  |         server5 (uid: eau)  (ServerGroup: mail)
+               \___________/ \       /
+	                       ----- - server4 (uid: eau, rival)  (no group configured)
+			             \
+				        etc...
+
+- WHAT WE NEED :
+
+  * configured LDAP server somewhere on the network (i.e. OpenLDAP)
+  * patched sshd (with this patch ;)
+  * LDAP user(/group) entry (look at users.ldif (& groups.ldif)):
+        User entry:
+	- attached to the 'ldapPublicKey' objectclass
+	- attached to the 'posixAccount' objectclass
+	- with a filled 'sshPublicKey' attribute 
+	Example:
+		dn: uid=eau,ou=users,dc=cuckoos,dc=net
+		objectclass: top
+		objectclass: person
+		objectclass: organizationalPerson
+		objectclass: posixAccount
+		objectclass: ldapPublicKey
+		description: Eric AUGE Account
+		userPassword: blah
+		cn: Eric AUGE
+		sn: Eric AUGE
+		uid: eau
+		uidNumber: 1034
+		gidNumber: 1
+		homeDirectory: /export/home/eau
+		sshPublicKey: ssh-dss AAAAB3...
+		sshPublicKey: ssh-dss AAAAM5...
+
+	Group entry:
+	- attached to the 'posixGroup' objectclass
+	- with a 'cn' groupname attribute
+	- with multiple 'memberUid' attributes filled with usernames allowed in this group
+	Example:
+		# few members
+		dn: cn=unix,ou=groups,dc=cuckoos,dc=net
+		objectclass: top
+		objectclass: posixGroup
+		description: Unix based servers group
+		cn: unix
+		gidNumber: 1002
+		memberUid: eau
+		memberUid: user1
+		memberUid: user2
+
+
+- HOW IT WORKS :
+
+  * without patch
+  If a user wants to authenticate to log in a server the sshd, will first look for authentication method allowed (RSAauth,kerberos,etc..)
+  and if RSAauth and tickets based auth fails, it will fallback to standard password authentication (if enabled).
+
+  * with the patch
+  If a user want to authenticate to log in a server, the sshd will first look for auth method including LDAP pubkey, if the ldappubkey options is enabled.
+  It will do an ldapsearch to get the public key directly from the LDAP instead of reading it from the server filesystem. 
+  (usually in $HOME/.ssh/authorized_keys)
+
+  2 tokens are added to sshd_config :
+  # here is the new patched ldap related tokens
+  PubkeyAgent /usr/libexec/openssh/ssh-ldap-helper -s %u
+  PubkeyAgentRunAs nobody
+
+  The LDAP configuratin is read from common /etc/ldap.conf configuration file.
+There is also one optional parameter in the LDAP configuration file, SSH_Filter, which is a LDAP filter limiting keys to be searched.
+
+- HOW TO INSERT A USER/KEY INTO AN LDAP ENTRY
+
+  * my way (there is plenty :)
+  - create ldif file (i.e. users.ldif)
+  - cat ~/.ssh/id_dsa.pub OR cat ~/.ssh/id_rsa.pub OR cat ~/.ssh/identity.pub
+  - my way in 4 steps :
+  Example:
+
+  # you add this to the user entry in the LDIF file :
+  [...]
+  objectclass: posixAccount
+  objectclass: ldapPublicKey
+  [...]
+  sshPubliKey: ssh-dss AAAABDh12DDUR2...
+  [...]
+
+  # insert your entry and you're done :)
+  ldapadd -D balblabla -w bleh < file.ldif 
+  
+  all standard options can be present in the 'sshPublicKey' attribute.
+
+- WHY :
+
+  Simply because, i was looking for a way to centralize all sysadmins authentication, easily,  without completely using LDAP 
+  as authentication method (like pam_ldap etc..).  
+  
+  After looking into Kerberos, SecurID, and other centralized secure authentications systems, the use of RSA and LDAP to get 
+  public key for authentication allows us to control who has access to which server (the user needs an account and to be in 'strongAuthenticationUser'
+  objectclass within LDAP and part of the group the SSH server is in). 
+
+  Passwords update are no longer a nightmare for a server farm (key pair passphrase is stored on each user's box and private key is locally encrypted using his passphrase 
+  so each user can change it as much as he wants). 
+
+  Blocking a user account can be done directly from the LDAP (if sshd is using RSAAuth + ldap only).
+
+- RULES :  
+  Entry in the LDAP server must respect 'posixAccount' and 'ldapPublicKey' which are defined in core.schema. 
+  and the additionnal lpk.schema.
+
+  This patch could allow a smooth transition between standard auth (/etc/passwd) and complete LDAP based authentication 
+  (pamldap, nss_ldap, etc..).
+
+  This can be an alternative to other (old?/expensive?) authentication methods (Kerberos/SecurID/..).
+  
+  Referring to schema at the beginning of this file if user 'eau' is only in group 'unix'
+  'eau' would ONLY access 'server1', 'server2', 'server3' AND 'server4' BUT NOT 'server5'.
+  If you then modify the LDAP 'mail' group entry to add 'memberUid: eau' THEN user 'eau' would be able
+  to log in 'server5' (i hope you got the idea, my english is bad :).
+
+  Each server's sshd is patched and configured to ask the public key and the group infos in the LDAP
+  server.
+  When you want to allow a new user to have access to the server parc, you just add him an account on 
+  your servers, you add his public key into his entry on the LDAP server, it's done. 
+
+  Because sshds are looking public keys into the LDAP directly instead of a file ($HOME/.ssh/authorized_keys).
+
+  When the user needs to change his passphrase he can do it directly from his workstation by changing 
+  his own key set lock passphrase, and all servers are automatically aware.
+ 
+  With a CAREFUL LDAP server configuration you could allow a user to add/delete/modify his own entry himself
+  so he can add/modify/delete himself his public key when needed.
+
+­ FLAWS :
+  LDAP must be well configured, getting the public key of some user is not a problem, but if anonymous LDAP 
+  allow write to users dn, somebody could replace someuser's public key by its own and impersonate some 
+  of your users in all your server farm be VERY CAREFUL.
+  
+  MITM attack when sshd is requesting the public key, could lead to a compromise of your servers allowing login 
+  as the impersonnated user.
+
+  If LDAP server is down then, no fallback on passwd auth.
+  
+  the ldap code part has not been well audited yet.
+
+- LDAP USER ENTRY EXAMPLES (LDIF Format, look in users.ldif)
+    --- CUT HERE ---
+    dn: uid=jdoe,ou=users,dc=foobar,dc=net
+    objectclass: top
+    objectclass: person
+    objectclass: organizationalPerson
+    objectclass: posixAccount
+    objectclass: ldapPublicKey
+    description: My account
+    cn: John Doe
+    sn: John Doe
+    uid: jdoe
+    uidNumber: 100
+    gidNumber: 100
+    homeDirectory: /home/jdoe
+    sshPublicKey: ssh-dss AAAAB3NzaC1kc3MAAAEBAOvL8pREUg9wSy/8+hQJ54YF3AXkB0OZrXB....
+    [...]
+    --- CUT HERE ---
+
+- LDAP GROUP ENTRY EXAMPLES (LDIF Format, look in groups.ldif)
+    --- CUT HERE ---
+    dn: cn=unix,ou=groups,dc=cuckoos,dc=net
+    objectclass: top
+    objectclass: posixGroup
+    description: Unix based servers group
+    cn: unix
+    gidNumber: 1002
+    memberUid: jdoe
+    memberUid: user1
+    memberUid: user2
+    [...]
+    --- CUT HERE ---
+
+>> FYI: << 
+Multiple 'sshPublicKey' in a user entry are allowed, as well as multiple 'memberUid' attributes in a group entry
+
+- COMPILING:
+  1. Apply the patch
+  2. ./configure --with-your-options --with-ldap=/prefix/to/ldap_libs_and_includes
+  3. make
+  4. it's done.
+
+- BLA :
+  I hope this could help, and i hope to be clear enough,, or give ideas.  questions/comments/improvements are welcome.
+  
+- TODO :
+  Redesign differently.
+
+- 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 )
+
+- CONTRIBUTORS/IDEAS/GREETS :
+  - Eric AUGE <eau@phear.org>
+  - Andrea Barisani <andrea@inversepath.com>
+  - Falk Siemonsmeier.
+  - Jacob Rief.
+  - Michael Durchgraf.
+  - frederic peters.
+  - Finlay dobbie.
+  - Stefan Fisher.
+  - Robin H. Johnson.
+  - Adrian Bridgett.
+
+- CONTACT :
+    Jan F. Chadima <jchadima@redhat.com>
+
diff -up openssh-5.5p1/servconf.c.pka openssh-5.5p1/servconf.c
--- openssh-5.5p1/servconf.c.pka	2010-03-26 00:40:04.000000000 +0100
+++ openssh-5.5p1/servconf.c	2010-04-29 11:08:25.000000000 +0200
@@ -128,6 +128,8 @@ initialize_server_options(ServerOptions 
 	options->num_permitted_opens = -1;
 	options->adm_forced_command = NULL;
 	options->chroot_directory = NULL;
+	options->pubkey_agent = NULL;
+	options->pubkey_agent_runas = NULL;
 	options->zero_knowledge_password_authentication = -1;
 	options->revoked_keys_file = NULL;
 	options->trusted_user_ca_keys = NULL;
@@ -311,6 +313,7 @@ typedef enum {
 	sUsePrivilegeSeparation, sAllowAgentForwarding,
 	sZeroKnowledgePasswordAuthentication, sHostCertificate,
 	sRevokedKeys, sTrustedUserCAKeys,
+	sPubkeyAgent, sPubkeyAgentRunAs,
 	sDeprecated, sUnsupported
 } ServerOpCodes;
 
@@ -432,6 +435,13 @@ static struct {
 	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
 	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
 	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
+#ifdef WITH_PUBKEY_AGENT
+	{ "pubkeyagent", sPubkeyAgent, SSHCFG_ALL },
+	{ "pubkeyagentrunas", sPubkeyAgentRunAs, SSHCFG_ALL },
+#else
+	{ "pubkeyagent", sUnsupported, SSHCFG_ALL },
+	{ "pubkeyagentrunas", sUnsupported, SSHCFG_ALL },
+#endif
 	{ NULL, sBadOption, 0 }
 };
 
@@ -1345,6 +1355,20 @@ process_server_config_line(ServerOptions
 		charptr = &options->revoked_keys_file;
 		goto parse_filename;
 
+	case sPubkeyAgent:
+		len = strspn(cp, WHITESPACE);
+		if (*activep && options->pubkey_agent == NULL)
+			options->pubkey_agent = xstrdup(cp + len);
+		return 0;
+
+	case sPubkeyAgentRunAs:
+		charptr = &options->pubkey_agent_runas;
+
+		arg = strdelim(&cp);
+		if (*activep && *charptr == NULL)
+			*charptr = xstrdup(arg);
+		break;
+
 	case sDeprecated:
 		logit("%s line %d: Deprecated option %s",
 		    filename, linenum, arg);
@@ -1438,6 +1462,8 @@ copy_set_server_options(ServerOptions *d
 	M_CP_INTOPT(gss_authentication);
 	M_CP_INTOPT(rsa_authentication);
 	M_CP_INTOPT(pubkey_authentication);
+	M_CP_STROPT(pubkey_agent);
+	M_CP_STROPT(pubkey_agent_runas);
 	M_CP_INTOPT(kerberos_authentication);
 	M_CP_INTOPT(hostbased_authentication);
 	M_CP_INTOPT(kbd_interactive_authentication);
@@ -1682,6 +1708,8 @@ dump_config(ServerOptions *o)
 	dump_cfg_string(sChrootDirectory, o->chroot_directory);
 	dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
 	dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
+	dump_cfg_string(sPubkeyAgent, o->pubkey_agent);
+	dump_cfg_string(sPubkeyAgentRunAs, o->pubkey_agent_runas);
 
 	/* string arguments requiring a lookup */
 	dump_cfg_string(sLogLevel, log_level_name(o->log_level));
diff -up openssh-5.5p1/servconf.h.pka openssh-5.5p1/servconf.h
--- openssh-5.5p1/servconf.h.pka	2010-03-04 11:53:35.000000000 +0100
+++ openssh-5.5p1/servconf.h	2010-04-29 11:08:25.000000000 +0200
@@ -156,6 +156,8 @@ typedef struct {
 	char   *chroot_directory;
 	char   *revoked_keys_file;
 	char   *trusted_user_ca_keys;
+	char   *pubkey_agent;
+	char   *pubkey_agent_runas;
 }       ServerOptions;
 
 void	 initialize_server_options(ServerOptions *);
diff -up openssh-5.5p1/sshd_config.0.pka openssh-5.5p1/sshd_config.0
--- openssh-5.5p1/sshd_config.0.pka	2010-04-16 02:17:12.000000000 +0200
+++ openssh-5.5p1/sshd_config.0	2010-04-29 11:08:25.000000000 +0200
@@ -352,7 +352,8 @@ DESCRIPTION
              KbdInteractiveAuthentication, KerberosAuthentication,
              MaxAuthTries, MaxSessions, PasswordAuthentication,
              PermitEmptyPasswords, PermitOpen, PermitRootLogin,
-             PubkeyAuthentication, RhostsRSAAuthentication, RSAAuthentication,
+             PubkeyAuthentication, PubkeyAgent, PubkeyAgentRunAs,
+             RhostsRSAAuthentication, RSAAuthentication,
              X11DisplayOffset, X11Forwarding and X11UseLocalHost.
 
      MaxAuthTries
@@ -467,6 +468,17 @@ DESCRIPTION
              this file is not readable, then public key authentication will be
              refused for all users.
 
+     PubkeyAgent
+             Specifies which agent is used for lookup of the user's public
+             keys. Empty string means to use the authorized_keys file.  By
+             default there is no PubkeyAgent set.  Note that this option has
+             an effect only with PubkeyAuthentication switched on.
+
+     PubkeyAgentRunAs
+             Specifies the user under whose account the PubkeyAgent is run.
+             Empty string (the default value) means the user being authorized
+             is used.
+
      RhostsRSAAuthentication
              Specifies whether rhosts or /etc/hosts.equiv authentication to-
              gether with successful RSA host authentication is allowed.  The
diff -up openssh-5.5p1/sshd_config.5.pka openssh-5.5p1/sshd_config.5
--- openssh-5.5p1/sshd_config.5.pka	2010-03-05 00:41:45.000000000 +0100
+++ openssh-5.5p1/sshd_config.5	2010-04-29 11:08:25.000000000 +0200
@@ -618,6 +618,9 @@ Available keywords are
 .Cm KerberosAuthentication ,
 .Cm MaxAuthTries ,
 .Cm MaxSessions ,
+.Cm PubkeyAuthentication ,
+.Cm PubkeyAgent ,
+.Cm PubkeyAgentRunAs ,
 .Cm PasswordAuthentication ,
 .Cm PermitEmptyPasswords ,
 .Cm PermitOpen ,
@@ -819,6 +822,16 @@ 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 PubkeyAgent
++Specifies which agent is used for lookup of the user's public
++keys. Empty string means to use the authorized_keys file.
++By default there is no PubkeyAgent set.
++Note that this option has an effect only with PubkeyAuthentication
++switched on.
++.It Cm PubkeyAgentRunAs
++Specifies the user under whose account the PubkeyAgent is run. Empty
++string (the default value) means the user being authorized is used.
++.Dq 
 .It Cm RhostsRSAAuthentication
 Specifies whether rhosts or /etc/hosts.equiv authentication together
 with successful RSA host authentication is allowed.
diff -up openssh-5.5p1/sshd_config.pka openssh-5.5p1/sshd_config
--- openssh-5.5p1/sshd_config.pka	2009-10-11 12:51:09.000000000 +0200
+++ openssh-5.5p1/sshd_config	2010-04-29 11:08:25.000000000 +0200
@@ -44,6 +44,8 @@
 #RSAAuthentication yes
 #PubkeyAuthentication yes
 #AuthorizedKeysFile	.ssh/authorized_keys
+#PubkeyAgent none
+#PubkeyAgentRunAs nobody
 
 # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
 #RhostsRSAAuthentication no
diff -up openssh-5.5p1/ssh-ldap-helper.8.pka openssh-5.5p1/ssh-ldap-helper.8
--- openssh-5.5p1/ssh-ldap-helper.8.pka	2010-04-29 11:08:26.000000000 +0200
+++ openssh-5.5p1/ssh-ldap-helper.8	2010-04-29 11:08:26.000000000 +0200
@@ -0,0 +1,78 @@
+.\" $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 a LDAP.
+.Nm
+is disabled by default and can only be enabled in the
+sshd configuration file
+.Pa /etc/ssh/sshd_config
+by setting
+.Cm PubkeyAgent
+to
+.Dq /usr/libexec/ssh-ldap-helper -s %u .
+.Pp
+.Nm
+is not intended to be invoked by the user, but from
+.Xr sshd 8 .
+.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
+halt when an unknown item is found in the ldap.conf file.
+.It Fl f
+Default /etc/ldap.conf.
+.Nm
+uses this file as a ldap configuration file.
+.It Fl s
+.Nm
+print out the keys of the user on stdout and exits.
+.It Fl v
+Implies \-d
+increases verbosity.
+.It Fl w
+.Nm
+writes warnings about unknown items in the ldap.conf file.
+
+.Sh SEE ALSO
+.Xr sshd 8 ,
+.Xr sshd_config 5 ,
+.Sh HISTORY
+.Nm
+first appeared in
+OpenSSH 5.5 + PKA-LDAP .
+.Sh AUTHORS
+.An Jan F. Chadima Aq jchadima@redhat.com