cb484f5f5e
- still broken on -CURRENT PR: ports/135407 Submitted by: Denis Barov <dindin@dindin.ru> (maintainer)
1682 lines
54 KiB
Diff
1682 lines
54 KiB
Diff
This is a forward-port of the OpenSSH LPK support patch.
|
||
|
||
It adds support for storing OpenSSH public keys in LDAP. It also supports
|
||
grouping of machines in the LDAP data to limit users to specific machines.
|
||
|
||
The latest homepage for the LPK project is:
|
||
http://code.google.com/p/openssh-lpk/
|
||
|
||
The 0.3.10 version of the patch includes a fix for 64-bit platforms, as
|
||
discovered by Gentoo, where the bind timeout and search timeout values were not
|
||
being parsed correctly: http://bugs.gentoo.org/210110
|
||
|
||
Forward-ported-from: openssh-lpk-5.1p1-0.3.9.patch
|
||
Signed-off-by: Robin H. Johnson <robbat2@gentoo.org>
|
||
|
||
diff -Nuar --exclude '*.orig' --exclude '*.rej' auth2-pubkey.c auth2-pubkey.c
|
||
--- auth2-pubkey.c 2008-07-03 19:54:25.000000000 -0700
|
||
+++ auth2-pubkey.c 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -55,6 +55,10 @@
|
||
#include "monitor_wrap.h"
|
||
#include "misc.h"
|
||
|
||
+#ifdef WITH_LDAP_PUBKEY
|
||
+#include "ldapauth.h"
|
||
+#endif
|
||
+
|
||
/* import */
|
||
extern ServerOptions options;
|
||
extern u_char *session_id2;
|
||
@@ -187,10 +191,79 @@
|
||
u_long linenum = 0;
|
||
Key *found;
|
||
char *fp;
|
||
+#ifdef WITH_LDAP_PUBKEY
|
||
+ ldap_key_t * k;
|
||
+ unsigned int i = 0;
|
||
+#endif
|
||
|
||
/* Temporarily use the user's uid. */
|
||
temporarily_use_uid(pw);
|
||
|
||
+#ifdef WITH_LDAP_PUBKEY
|
||
+ found_key = 0;
|
||
+ /* allocate a new key type */
|
||
+ found = key_new(key->type);
|
||
+
|
||
+ /* first check if the options is enabled, then try.. */
|
||
+ if (options.lpk.on) {
|
||
+ debug("[LDAP] trying LDAP first uid=%s",pw->pw_name);
|
||
+ if (ldap_ismember(&options.lpk, pw->pw_name) > 0) {
|
||
+ if ((k = ldap_getuserkey(&options.lpk, pw->pw_name)) != NULL) {
|
||
+ /* Skip leading whitespace, empty and comment lines. */
|
||
+ for (i = 0 ; i < k->num ; i++) {
|
||
+ /* dont forget if multiple keys to reset options */
|
||
+ char *cp, *options = NULL;
|
||
+
|
||
+ for (cp = (char *)k->keys[i]->bv_val; *cp == ' ' || *cp == '\t'; cp++)
|
||
+ ;
|
||
+ if (!*cp || *cp == '\n' || *cp == '#')
|
||
+ continue;
|
||
+
|
||
+ if (key_read(found, &cp) != 1) {
|
||
+ /* no key? check if there are options for this key */
|
||
+ int quoted = 0;
|
||
+ debug2("[LDAP] user_key_allowed: check options: '%s'", cp);
|
||
+ options = cp;
|
||
+ for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
|
||
+ if (*cp == '\\' && cp[1] == '"')
|
||
+ cp++; /* Skip both */
|
||
+ else if (*cp == '"')
|
||
+ quoted = !quoted;
|
||
+ }
|
||
+ /* Skip remaining whitespace. */
|
||
+ for (; *cp == ' ' || *cp == '\t'; cp++)
|
||
+ ;
|
||
+ if (key_read(found, &cp) != 1) {
|
||
+ debug2("[LDAP] user_key_allowed: advance: '%s'", cp);
|
||
+ /* still no key? advance to next line*/
|
||
+ continue;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (key_equal(found, key) &&
|
||
+ auth_parse_options(pw, options, file, linenum) == 1) {
|
||
+ found_key = 1;
|
||
+ debug("[LDAP] matching key found");
|
||
+ fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
|
||
+ verbose("[LDAP] Found matching %s key: %s", key_type(found), fp);
|
||
+
|
||
+ /* restoring memory */
|
||
+ ldap_keys_free(k);
|
||
+ xfree(fp);
|
||
+ restore_uid();
|
||
+ key_free(found);
|
||
+ return found_key;
|
||
+ break;
|
||
+ }
|
||
+ }/* end of LDAP for() */
|
||
+ } else {
|
||
+ logit("[LDAP] no keys found for '%s'!", pw->pw_name);
|
||
+ }
|
||
+ } else {
|
||
+ logit("[LDAP] '%s' is not in '%s'", pw->pw_name, options.lpk.sgroup);
|
||
+ }
|
||
+ }
|
||
+#endif
|
||
debug("trying public key file %s", file);
|
||
f = auth_openkeyfile(file, pw, options.strict_modes);
|
||
|
||
diff -Nuar --exclude '*.orig' --exclude '*.rej' auth-rsa.c auth-rsa.c
|
||
--- auth-rsa.c 2008-07-02 05:37:30.000000000 -0700
|
||
+++ auth-rsa.c 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -174,10 +174,96 @@
|
||
FILE *f;
|
||
u_long linenum = 0;
|
||
Key *key;
|
||
+#ifdef WITH_LDAP_PUBKEY
|
||
+ ldap_key_t * k;
|
||
+ unsigned int i = 0;
|
||
+#endif
|
||
|
||
/* Temporarily use the user's uid. */
|
||
temporarily_use_uid(pw);
|
||
|
||
+#ifdef WITH_LDAP_PUBKEY
|
||
+ /* here is the job */
|
||
+ key = key_new(KEY_RSA1);
|
||
+
|
||
+ if (options.lpk.on) {
|
||
+ debug("[LDAP] trying LDAP first uid=%s", pw->pw_name);
|
||
+ if ( ldap_ismember(&options.lpk, pw->pw_name) > 0) {
|
||
+ if ( (k = ldap_getuserkey(&options.lpk, pw->pw_name)) != NULL) {
|
||
+ for (i = 0 ; i < k->num ; i++) {
|
||
+ char *cp, *options = NULL;
|
||
+
|
||
+ for (cp = k->keys[i]->bv_val; *cp == ' ' || *cp == '\t'; cp++)
|
||
+ ;
|
||
+ if (!*cp || *cp == '\n' || *cp == '#')
|
||
+ continue;
|
||
+
|
||
+ /*
|
||
+ * Check if there are options for this key, and if so,
|
||
+ * save their starting address and skip the option part
|
||
+ * for now. If there are no options, set the starting
|
||
+ * address to NULL.
|
||
+ */
|
||
+ if (*cp < '0' || *cp > '9') {
|
||
+ int quoted = 0;
|
||
+ options = cp;
|
||
+ for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
|
||
+ if (*cp == '\\' && cp[1] == '"')
|
||
+ cp++; /* Skip both */
|
||
+ else if (*cp == '"')
|
||
+ quoted = !quoted;
|
||
+ }
|
||
+ } else
|
||
+ options = NULL;
|
||
+
|
||
+ /* Parse the key from the line. */
|
||
+ if (hostfile_read_key(&cp, &bits, key) == 0) {
|
||
+ debug("[LDAP] line %d: non ssh1 key syntax", i);
|
||
+ continue;
|
||
+ }
|
||
+ /* cp now points to the comment part. */
|
||
+
|
||
+ /* Check if the we have found the desired key (identified by its modulus). */
|
||
+ if (BN_cmp(key->rsa->n, client_n) != 0)
|
||
+ continue;
|
||
+
|
||
+ /* check the real bits */
|
||
+ if (bits != (unsigned int)BN_num_bits(key->rsa->n))
|
||
+ logit("[LDAP] Warning: ldap, line %lu: keysize mismatch: "
|
||
+ "actual %d vs. announced %d.", (unsigned long)i, BN_num_bits(key->rsa->n), bits);
|
||
+
|
||
+ /* We have found the desired key. */
|
||
+ /*
|
||
+ * If our options do not allow this key to be used,
|
||
+ * do not send challenge.
|
||
+ */
|
||
+ if (!auth_parse_options(pw, options, "[LDAP]", (unsigned long) i))
|
||
+ continue;
|
||
+
|
||
+ /* break out, this key is allowed */
|
||
+ allowed = 1;
|
||
+
|
||
+ /* add the return stuff etc... */
|
||
+ /* Restore the privileged uid. */
|
||
+ restore_uid();
|
||
+
|
||
+ /* return key if allowed */
|
||
+ if (allowed && rkey != NULL)
|
||
+ *rkey = key;
|
||
+ else
|
||
+ key_free(key);
|
||
+
|
||
+ ldap_keys_free(k);
|
||
+ return (allowed);
|
||
+ }
|
||
+ } else {
|
||
+ logit("[LDAP] no keys found for '%s'!", pw->pw_name);
|
||
+ }
|
||
+ } else {
|
||
+ logit("[LDAP] '%s' is not in '%s'", pw->pw_name, options.lpk.sgroup);
|
||
+ }
|
||
+ }
|
||
+#endif
|
||
/* The authorized keys. */
|
||
file = authorized_keys_file(pw);
|
||
debug("trying public RSA key file %s", file);
|
||
diff -Nuar --exclude '*.orig' --exclude '*.rej' config.h.in config.h.in
|
||
--- config.h.in 2008-07-21 01:30:49.000000000 -0700
|
||
+++ config.h.in 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -560,6 +560,9 @@
|
||
/* Define to 1 if you have the <linux/if_tun.h> header file. */
|
||
#undef HAVE_LINUX_IF_TUN_H
|
||
|
||
+/* Define if you want LDAP support */
|
||
+#undef WITH_LDAP_PUBKEY
|
||
+
|
||
/* Define if your libraries define login() */
|
||
#undef HAVE_LOGIN
|
||
|
||
diff -Nuar --exclude '*.orig' --exclude '*.rej' configure configure
|
||
--- configure 2008-07-21 01:30:50.000000000 -0700
|
||
+++ configure 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -1340,6 +1340,7 @@
|
||
--with-tcp-wrappers[=PATH] Enable tcpwrappers support (optionally in PATH)
|
||
--with-libedit[=PATH] Enable libedit support for sftp
|
||
--with-audit=module Enable EXPERIMENTAL audit support (modules=debug,bsm)
|
||
+ --with-ldap[=PATH] Enable LDAP pubkey support (optionally in PATH)
|
||
--with-ssl-dir=PATH Specify path to OpenSSL installation
|
||
--without-openssl-header-check Disable OpenSSL version consistency check
|
||
--with-ssl-engine Enable OpenSSL (hardware) ENGINE support
|
||
@@ -12568,6 +12569,85 @@
|
||
fi
|
||
|
||
|
||
+# Check whether user wants LDAP support
|
||
+LDAP_MSG="no"
|
||
+
|
||
+# Check whether --with-ldap was given.
|
||
+if test "${with_ldap+set}" = set; then
|
||
+ withval=$with_ldap;
|
||
+ if test "x$withval" != "xno" ; then
|
||
+
|
||
+ if test "x$withval" != "xyes" ; then
|
||
+ CPPFLAGS="$CPPFLAGS -I${withval}/include"
|
||
+ LDFLAGS="$LDFLAGS -L${withval}/lib"
|
||
+ fi
|
||
+
|
||
+
|
||
+cat >>confdefs.h <<\_ACEOF
|
||
+#define WITH_LDAP_PUBKEY 1
|
||
+_ACEOF
|
||
+
|
||
+ LIBS="-lldap $LIBS"
|
||
+ LDAP_MSG="yes"
|
||
+
|
||
+ { echo "$as_me:$LINENO: checking for LDAP support" >&5
|
||
+echo $ECHO_N "checking for LDAP support... $ECHO_C" >&6; }
|
||
+ cat >conftest.$ac_ext <<_ACEOF
|
||
+/* confdefs.h. */
|
||
+_ACEOF
|
||
+cat confdefs.h >>conftest.$ac_ext
|
||
+cat >>conftest.$ac_ext <<_ACEOF
|
||
+/* end confdefs.h. */
|
||
+#include <sys/types.h>
|
||
+ #include <ldap.h>
|
||
+int
|
||
+main ()
|
||
+{
|
||
+(void)ldap_init(0, 0);
|
||
+ ;
|
||
+ return 0;
|
||
+}
|
||
+_ACEOF
|
||
+rm -f conftest.$ac_objext
|
||
+if { (ac_try="$ac_compile"
|
||
+case "(($ac_try" in
|
||
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||
+ *) ac_try_echo=$ac_try;;
|
||
+esac
|
||
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||
+ (eval "$ac_compile") 2>conftest.er1
|
||
+ ac_status=$?
|
||
+ grep -v '^ *+' conftest.er1 >conftest.err
|
||
+ rm -f conftest.er1
|
||
+ cat conftest.err >&5
|
||
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||
+ (exit $ac_status); } && {
|
||
+ test -z "$ac_c_werror_flag" ||
|
||
+ test ! -s conftest.err
|
||
+ } && test -s conftest.$ac_objext; then
|
||
+ { echo "$as_me:$LINENO: result: yes" >&5
|
||
+echo "${ECHO_T}yes" >&6; }
|
||
+else
|
||
+ echo "$as_me: failed program was:" >&5
|
||
+sed 's/^/| /' conftest.$ac_ext >&5
|
||
+
|
||
+
|
||
+ { echo "$as_me:$LINENO: result: no" >&5
|
||
+echo "${ECHO_T}no" >&6; }
|
||
+ { { echo "$as_me:$LINENO: error: ** Incomplete or missing ldap libraries **" >&5
|
||
+echo "$as_me: error: ** Incomplete or missing ldap libraries **" >&2;}
|
||
+ { (exit 1); exit 1; }; }
|
||
+
|
||
+
|
||
+fi
|
||
+
|
||
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||
+ fi
|
||
+
|
||
+
|
||
+fi
|
||
+
|
||
+
|
||
|
||
|
||
|
||
@@ -30135,6 +30215,7 @@
|
||
echo " Smartcard support: $SCARD_MSG"
|
||
echo " S/KEY support: $SKEY_MSG"
|
||
echo " TCP Wrappers support: $TCPW_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 -Nuar --exclude '*.orig' --exclude '*.rej' configure.ac configure.ac
|
||
--- configure.ac 2008-07-09 04:07:19.000000000 -0700
|
||
+++ configure.ac 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -1299,6 +1299,37 @@
|
||
esac ]
|
||
)
|
||
|
||
+# Check whether user wants LDAP support
|
||
+LDAP_MSG="no"
|
||
+AC_ARG_WITH(ldap,
|
||
+ [ --with-ldap[[=PATH]] Enable LDAP pubkey support (optionally in PATH)],
|
||
+ [
|
||
+ if test "x$withval" != "xno" ; then
|
||
+
|
||
+ 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])
|
||
+ LIBS="-lldap $LIBS"
|
||
+ LDAP_MSG="yes"
|
||
+
|
||
+ AC_MSG_CHECKING([for 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 **])
|
||
+ ]
|
||
+ )
|
||
+ fi
|
||
+ ]
|
||
+)
|
||
+
|
||
dnl Checks for library functions. Please keep in alphabetical order
|
||
AC_CHECK_FUNCS( \
|
||
arc4random \
|
||
@@ -4137,6 +4168,7 @@
|
||
echo " Smartcard support: $SCARD_MSG"
|
||
echo " S/KEY support: $SKEY_MSG"
|
||
echo " TCP Wrappers support: $TCPW_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 -Nuar --exclude '*.orig' --exclude '*.rej' ldapauth.c ldapauth.c
|
||
--- ldapauth.c 1969-12-31 16:00:00.000000000 -0800
|
||
+++ ldapauth.c 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -0,0 +1,575 @@
|
||
+/*
|
||
+ * $Id: openssh-lpk-4.3p1-0.3.7.patch,v 1.3 2006/04/18 15:29:09 eau Exp $
|
||
+ */
|
||
+
|
||
+/*
|
||
+ *
|
||
+ * Copyright (c) 2005, Eric AUGE <eau@phear.org>
|
||
+ * All rights reserved.
|
||
+ *
|
||
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||
+ *
|
||
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||
+ * 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.
|
||
+ * Neither the name of the phear.org nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||
+ *
|
||
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
+ *
|
||
+ *
|
||
+ */
|
||
+
|
||
+#include "includes.h"
|
||
+
|
||
+#ifdef WITH_LDAP_PUBKEY
|
||
+
|
||
+#include <stdio.h>
|
||
+#include <stdlib.h>
|
||
+#include <unistd.h>
|
||
+#include <string.h>
|
||
+
|
||
+#include "ldapauth.h"
|
||
+#include "log.h"
|
||
+
|
||
+static char *attrs[] = {
|
||
+ PUBKEYATTR,
|
||
+ NULL
|
||
+};
|
||
+
|
||
+/* filter building infos */
|
||
+#define FILTER_GROUP_PREFIX "(&(objectclass=posixGroup)"
|
||
+#define FILTER_OR_PREFIX "(|"
|
||
+#define FILTER_OR_SUFFIX ")"
|
||
+#define FILTER_CN_PREFIX "(cn="
|
||
+#define FILTER_CN_SUFFIX ")"
|
||
+#define FILTER_UID_FORMAT "(memberUid=%s)"
|
||
+#define FILTER_GROUP_SUFFIX ")"
|
||
+#define FILTER_GROUP_SIZE(group) (size_t) (strlen(group)+(ldap_count_group(group)*5)+52)
|
||
+
|
||
+/* just filter building stuff */
|
||
+#define REQUEST_GROUP_SIZE(filter, uid) (size_t) (strlen(filter)+strlen(uid)+1)
|
||
+#define REQUEST_GROUP(buffer, prefilter, pwname) \
|
||
+ buffer = (char *) calloc(REQUEST_GROUP_SIZE(prefilter, pwname), sizeof(char)); \
|
||
+ if (!buffer) { \
|
||
+ perror("calloc()"); \
|
||
+ return FAILURE; \
|
||
+ } \
|
||
+ snprintf(buffer, REQUEST_GROUP_SIZE(prefilter,pwname), prefilter, pwname)
|
||
+/*
|
||
+XXX OLD group building macros
|
||
+#define REQUEST_GROUP_SIZE(grp, uid) (size_t) (strlen(grp)+strlen(uid)+46)
|
||
+#define REQUEST_GROUP(buffer,pwname,grp) \
|
||
+ buffer = (char *) calloc(REQUEST_GROUP_SIZE(grp, pwname), sizeof(char)); \
|
||
+ if (!buffer) { \
|
||
+ perror("calloc()"); \
|
||
+ return FAILURE; \
|
||
+ } \
|
||
+ snprintf(buffer,REQUEST_GROUP_SIZE(grp,pwname),"(&(objectclass=posixGroup)(cn=%s)(memberUid=%s))",grp,pwname)
|
||
+ */
|
||
+
|
||
+/*
|
||
+XXX stock upstream version without extra filter support
|
||
+#define REQUEST_USER_SIZE(uid) (size_t) (strlen(uid)+64)
|
||
+#define REQUEST_USER(buffer, pwname) \
|
||
+ buffer = (char *) calloc(REQUEST_USER_SIZE(pwname), sizeof(char)); \
|
||
+ if (!buffer) { \
|
||
+ perror("calloc()"); \
|
||
+ return NULL; \
|
||
+ } \
|
||
+ snprintf(buffer,REQUEST_USER_SIZE(pwname),"(&(objectclass=posixAccount)(objectclass=ldapPublicKey)(uid=%s))",pwname)
|
||
+ */
|
||
+
|
||
+#define REQUEST_USER_SIZE(uid, filter) (size_t) (strlen(uid)+64+(filter != NULL ? strlen(filter) : 0))
|
||
+#define REQUEST_USER(buffer, pwname, customfilter) \
|
||
+ buffer = (char *) calloc(REQUEST_USER_SIZE(pwname, customfilter), sizeof(char)); \
|
||
+ if (!buffer) { \
|
||
+ perror("calloc()"); \
|
||
+ return NULL; \
|
||
+ } \
|
||
+ snprintf(buffer, REQUEST_USER_SIZE(pwname, customfilter), \
|
||
+ "(&(objectclass=posixAccount)(objectclass=ldapPublicKey)(uid=%s)%s)", \
|
||
+ pwname, (customfilter != NULL ? customfilter : ""))
|
||
+
|
||
+/* some portable and working tokenizer, lame though */
|
||
+static int tokenize(char ** o, size_t size, char * input) {
|
||
+ unsigned int i = 0, num;
|
||
+ const char * charset = " \t";
|
||
+ char * ptr = input;
|
||
+
|
||
+ /* leading white spaces are ignored */
|
||
+ num = strspn(ptr, charset);
|
||
+ ptr += num;
|
||
+
|
||
+ while ((num = strcspn(ptr, charset))) {
|
||
+ if (i < size-1) {
|
||
+ o[i++] = ptr;
|
||
+ ptr += num;
|
||
+ if (*ptr)
|
||
+ *ptr++ = '\0';
|
||
+ }
|
||
+ }
|
||
+ o[i] = NULL;
|
||
+ return SUCCESS;
|
||
+}
|
||
+
|
||
+void ldap_close(ldap_opt_t * ldap) {
|
||
+
|
||
+ if (!ldap)
|
||
+ return;
|
||
+
|
||
+ if ( ldap_unbind_ext(ldap->ld, NULL, NULL) < 0)
|
||
+ ldap_perror(ldap->ld, "ldap_unbind()");
|
||
+
|
||
+ ldap->ld = NULL;
|
||
+ FLAG_SET_DISCONNECTED(ldap->flags);
|
||
+
|
||
+ return;
|
||
+}
|
||
+
|
||
+/* init && bind */
|
||
+int ldap_connect(ldap_opt_t * ldap) {
|
||
+ int version = LDAP_VERSION3;
|
||
+
|
||
+ if (!ldap->servers)
|
||
+ return FAILURE;
|
||
+
|
||
+ /* Connection Init and setup */
|
||
+ ldap->ld = ldap_init(ldap->servers, LDAP_PORT);
|
||
+ if (!ldap->ld) {
|
||
+ ldap_perror(ldap->ld, "ldap_init()");
|
||
+ return FAILURE;
|
||
+ }
|
||
+
|
||
+ if ( ldap_set_option(ldap->ld, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_OPT_SUCCESS) {
|
||
+ ldap_perror(ldap->ld, "ldap_set_option(LDAP_OPT_PROTOCOL_VERSION)");
|
||
+ return FAILURE;
|
||
+ }
|
||
+
|
||
+ /* Timeouts setup */
|
||
+ if (ldap_set_option(ldap->ld, LDAP_OPT_NETWORK_TIMEOUT, &ldap->b_timeout) != LDAP_SUCCESS) {
|
||
+ ldap_perror(ldap->ld, "ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT)");
|
||
+ }
|
||
+ if (ldap_set_option(ldap->ld, LDAP_OPT_TIMEOUT, &ldap->s_timeout) != LDAP_SUCCESS) {
|
||
+ ldap_perror(ldap->ld, "ldap_set_option(LDAP_OPT_TIMEOUT)");
|
||
+ }
|
||
+
|
||
+ /* TLS support */
|
||
+ if ( (ldap->tls == -1) || (ldap->tls == 1) ) {
|
||
+ if (ldap_start_tls_s(ldap->ld, NULL, NULL ) != LDAP_SUCCESS) {
|
||
+ /* failed then reinit the initial connect */
|
||
+ ldap_perror(ldap->ld, "ldap_connect: (TLS) ldap_start_tls()");
|
||
+ if (ldap->tls == 1)
|
||
+ return FAILURE;
|
||
+
|
||
+ ldap->ld = ldap_init(ldap->servers, LDAP_PORT);
|
||
+ if (!ldap->ld) {
|
||
+ ldap_perror(ldap->ld, "ldap_init()");
|
||
+ return FAILURE;
|
||
+ }
|
||
+
|
||
+ if ( ldap_set_option(ldap->ld, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_OPT_SUCCESS) {
|
||
+ ldap_perror(ldap->ld, "ldap_set_option()");
|
||
+ return FAILURE;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+
|
||
+ if ( ldap_simple_bind_s(ldap->ld, ldap->binddn, ldap->bindpw) != LDAP_SUCCESS) {
|
||
+ ldap_perror(ldap->ld, "ldap_simple_bind_s()");
|
||
+ return FAILURE;
|
||
+ }
|
||
+
|
||
+ /* says it is connected */
|
||
+ FLAG_SET_CONNECTED(ldap->flags);
|
||
+
|
||
+ return SUCCESS;
|
||
+}
|
||
+
|
||
+/* must free allocated ressource */
|
||
+static char * ldap_build_host(char *host, int port) {
|
||
+ unsigned int size = strlen(host)+11;
|
||
+ char * h = (char *) calloc (size, sizeof(char));
|
||
+ int rc;
|
||
+ if (!h)
|
||
+ return NULL;
|
||
+
|
||
+ rc = snprintf(h, size, "%s:%d ", host, port);
|
||
+ if (rc == -1)
|
||
+ return NULL;
|
||
+ return h;
|
||
+}
|
||
+
|
||
+static int ldap_count_group(const char * input) {
|
||
+ const char * charset = " \t";
|
||
+ const char * ptr = input;
|
||
+ unsigned int count = 0;
|
||
+ unsigned int num;
|
||
+
|
||
+ num = strspn(ptr, charset);
|
||
+ ptr += num;
|
||
+
|
||
+ while ((num = strcspn(ptr, charset))) {
|
||
+ count++;
|
||
+ ptr += num;
|
||
+ ptr++;
|
||
+ }
|
||
+
|
||
+ return count;
|
||
+}
|
||
+
|
||
+/* format filter */
|
||
+char * ldap_parse_groups(const char * groups) {
|
||
+ unsigned int buffer_size = FILTER_GROUP_SIZE(groups);
|
||
+ char * buffer = (char *) calloc(buffer_size, sizeof(char));
|
||
+ char * g = NULL;
|
||
+ char * garray[32];
|
||
+ unsigned int i = 0;
|
||
+
|
||
+ if ((!groups)||(!buffer))
|
||
+ return NULL;
|
||
+
|
||
+ g = strdup(groups);
|
||
+ if (!g) {
|
||
+ free(buffer);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ /* first separate into n tokens */
|
||
+ if ( tokenize(garray, sizeof(garray)/sizeof(*garray), g) < 0) {
|
||
+ free(g);
|
||
+ free(buffer);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ /* build the final filter format */
|
||
+ strlcat(buffer, FILTER_GROUP_PREFIX, buffer_size);
|
||
+ strlcat(buffer, FILTER_OR_PREFIX, buffer_size);
|
||
+ i = 0;
|
||
+ while (garray[i]) {
|
||
+ strlcat(buffer, FILTER_CN_PREFIX, buffer_size);
|
||
+ strlcat(buffer, garray[i], buffer_size);
|
||
+ strlcat(buffer, FILTER_CN_SUFFIX, buffer_size);
|
||
+ i++;
|
||
+ }
|
||
+ strlcat(buffer, FILTER_OR_SUFFIX, buffer_size);
|
||
+ strlcat(buffer, FILTER_UID_FORMAT, buffer_size);
|
||
+ strlcat(buffer, FILTER_GROUP_SUFFIX, buffer_size);
|
||
+
|
||
+ free(g);
|
||
+ return buffer;
|
||
+}
|
||
+
|
||
+/* a bit dirty but leak free */
|
||
+char * ldap_parse_servers(const char * servers) {
|
||
+ char * s = NULL;
|
||
+ char * tmp = NULL, *urls[32];
|
||
+ unsigned int num = 0 , i = 0 , asize = 0;
|
||
+ LDAPURLDesc *urld[32];
|
||
+
|
||
+ if (!servers)
|
||
+ return NULL;
|
||
+
|
||
+ /* local copy of the arg */
|
||
+ s = strdup(servers);
|
||
+ if (!s)
|
||
+ return NULL;
|
||
+
|
||
+ /* first separate into URL tokens */
|
||
+ if ( tokenize(urls, sizeof(urls)/sizeof(*urls), s) < 0)
|
||
+ return NULL;
|
||
+
|
||
+ i = 0;
|
||
+ while (urls[i]) {
|
||
+ if (! ldap_is_ldap_url(urls[i]) ||
|
||
+ (ldap_url_parse(urls[i], &urld[i]) != 0)) {
|
||
+ return NULL;
|
||
+ }
|
||
+ i++;
|
||
+ }
|
||
+
|
||
+ /* now free(s) */
|
||
+ free (s);
|
||
+
|
||
+ /* how much memory do we need */
|
||
+ num = i;
|
||
+ for (i = 0 ; i < num ; i++)
|
||
+ asize += strlen(urld[i]->lud_host)+11;
|
||
+
|
||
+ /* alloc */
|
||
+ s = (char *) calloc( asize+1 , sizeof(char));
|
||
+ if (!s) {
|
||
+ for (i = 0 ; i < num ; i++)
|
||
+ ldap_free_urldesc(urld[i]);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ /* then build the final host string */
|
||
+ for (i = 0 ; i < num ; i++) {
|
||
+ /* built host part */
|
||
+ tmp = ldap_build_host(urld[i]->lud_host, urld[i]->lud_port);
|
||
+ strncat(s, tmp, strlen(tmp));
|
||
+ ldap_free_urldesc(urld[i]);
|
||
+ free(tmp);
|
||
+ }
|
||
+
|
||
+ return s;
|
||
+}
|
||
+
|
||
+void ldap_options_print(ldap_opt_t * ldap) {
|
||
+ debug("ldap options:");
|
||
+ debug("servers: %s", ldap->servers);
|
||
+ if (ldap->u_basedn)
|
||
+ debug("user basedn: %s", ldap->u_basedn);
|
||
+ if (ldap->g_basedn)
|
||
+ debug("group basedn: %s", ldap->g_basedn);
|
||
+ if (ldap->binddn)
|
||
+ debug("binddn: %s", ldap->binddn);
|
||
+ if (ldap->bindpw)
|
||
+ debug("bindpw: %s", ldap->bindpw);
|
||
+ if (ldap->sgroup)
|
||
+ debug("group: %s", ldap->sgroup);
|
||
+ if (ldap->filter)
|
||
+ debug("filter: %s", ldap->filter);
|
||
+}
|
||
+
|
||
+void ldap_options_free(ldap_opt_t * l) {
|
||
+ if (!l)
|
||
+ return;
|
||
+ if (l->servers)
|
||
+ free(l->servers);
|
||
+ if (l->u_basedn)
|
||
+ free(l->u_basedn);
|
||
+ if (l->g_basedn)
|
||
+ free(l->g_basedn);
|
||
+ if (l->binddn)
|
||
+ free(l->binddn);
|
||
+ if (l->bindpw)
|
||
+ free(l->bindpw);
|
||
+ if (l->sgroup)
|
||
+ free(l->sgroup);
|
||
+ if (l->fgroup)
|
||
+ free(l->fgroup);
|
||
+ if (l->filter)
|
||
+ free(l->filter);
|
||
+ if (l->l_conf)
|
||
+ free(l->l_conf);
|
||
+ free(l);
|
||
+}
|
||
+
|
||
+/* free keys */
|
||
+void ldap_keys_free(ldap_key_t * k) {
|
||
+ ldap_value_free_len(k->keys);
|
||
+ free(k);
|
||
+ return;
|
||
+}
|
||
+
|
||
+ldap_key_t * ldap_getuserkey(ldap_opt_t *l, const char * user) {
|
||
+ ldap_key_t * k = (ldap_key_t *) calloc (1, sizeof(ldap_key_t));
|
||
+ LDAPMessage *res, *e;
|
||
+ char * filter;
|
||
+ int i;
|
||
+
|
||
+ if ((!k) || (!l))
|
||
+ return NULL;
|
||
+
|
||
+ /* Am i still connected ? RETRY n times */
|
||
+ /* XXX TODO: setup some conf value for retrying */
|
||
+ if (!(l->flags & FLAG_CONNECTED))
|
||
+ for (i = 0 ; i < 2 ; i++)
|
||
+ if (ldap_connect(l) == 0)
|
||
+ break;
|
||
+
|
||
+ /* quick check for attempts to be evil */
|
||
+ if ((strchr(user, '(') != NULL) || (strchr(user, ')') != NULL) ||
|
||
+ (strchr(user, '*') != NULL) || (strchr(user, '\\') != NULL))
|
||
+ return NULL;
|
||
+
|
||
+ /* build filter for LDAP request */
|
||
+ REQUEST_USER(filter, user, l->filter);
|
||
+
|
||
+ if ( ldap_search_st( l->ld,
|
||
+ l->u_basedn,
|
||
+ LDAP_SCOPE_SUBTREE,
|
||
+ filter,
|
||
+ attrs, 0, &l->s_timeout, &res ) != LDAP_SUCCESS) {
|
||
+
|
||
+ ldap_perror(l->ld, "ldap_search_st()");
|
||
+
|
||
+ free(filter);
|
||
+ free(k);
|
||
+
|
||
+ /* XXX error on search, timeout etc.. close ask for reconnect */
|
||
+ ldap_close(l);
|
||
+
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ /* free */
|
||
+ free(filter);
|
||
+
|
||
+ /* check if any results */
|
||
+ i = ldap_count_entries(l->ld,res);
|
||
+ if (i <= 0) {
|
||
+ ldap_msgfree(res);
|
||
+ free(k);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ if (i > 1)
|
||
+ debug("[LDAP] duplicate entries, using the FIRST entry returned");
|
||
+
|
||
+ e = ldap_first_entry(l->ld, res);
|
||
+ k->keys = ldap_get_values_len(l->ld, e, PUBKEYATTR);
|
||
+ k->num = ldap_count_values_len(k->keys);
|
||
+
|
||
+ ldap_msgfree(res);
|
||
+ return k;
|
||
+}
|
||
+
|
||
+
|
||
+/* -1 if trouble
|
||
+ 0 if user is NOT member of current server group
|
||
+ 1 if user IS MEMBER of current server group
|
||
+ */
|
||
+int ldap_ismember(ldap_opt_t * l, const char * user) {
|
||
+ LDAPMessage *res;
|
||
+ char * filter;
|
||
+ int i;
|
||
+
|
||
+ if ((!l->sgroup) || !(l->g_basedn))
|
||
+ return 1;
|
||
+
|
||
+ /* Am i still connected ? RETRY n times */
|
||
+ /* XXX TODO: setup some conf value for retrying */
|
||
+ if (!(l->flags & FLAG_CONNECTED))
|
||
+ for (i = 0 ; i < 2 ; i++)
|
||
+ if (ldap_connect(l) == 0)
|
||
+ break;
|
||
+
|
||
+ /* quick check for attempts to be evil */
|
||
+ if ((strchr(user, '(') != NULL) || (strchr(user, ')') != NULL) ||
|
||
+ (strchr(user, '*') != NULL) || (strchr(user, '\\') != NULL))
|
||
+ return FAILURE;
|
||
+
|
||
+ /* build filter for LDAP request */
|
||
+ REQUEST_GROUP(filter, l->fgroup, user);
|
||
+
|
||
+ if (ldap_search_st( l->ld,
|
||
+ l->g_basedn,
|
||
+ LDAP_SCOPE_SUBTREE,
|
||
+ filter,
|
||
+ NULL, 0, &l->s_timeout, &res) != LDAP_SUCCESS) {
|
||
+
|
||
+ ldap_perror(l->ld, "ldap_search_st()");
|
||
+
|
||
+ free(filter);
|
||
+
|
||
+ /* XXX error on search, timeout etc.. close ask for reconnect */
|
||
+ ldap_close(l);
|
||
+
|
||
+ return FAILURE;
|
||
+ }
|
||
+
|
||
+ free(filter);
|
||
+
|
||
+ /* check if any results */
|
||
+ if (ldap_count_entries(l->ld, res) > 0) {
|
||
+ ldap_msgfree(res);
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ ldap_msgfree(res);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * ldap.conf simple parser
|
||
+ * XXX TODO: sanity checks
|
||
+ * must either
|
||
+ * - free the previous ldap_opt_before replacing entries
|
||
+ * - free each necessary previously parsed elements
|
||
+ * ret:
|
||
+ * -1 on FAILURE, 0 on SUCCESS
|
||
+ */
|
||
+int ldap_parse_lconf(ldap_opt_t * l) {
|
||
+ FILE * lcd; /* ldap.conf descriptor */
|
||
+ char buf[BUFSIZ];
|
||
+ char * s = NULL, * k = NULL, * v = NULL;
|
||
+ int li, len;
|
||
+
|
||
+ lcd = fopen (l->l_conf, "r");
|
||
+ if (lcd == NULL) {
|
||
+ /* debug("Cannot open %s", l->l_conf); */
|
||
+ perror("ldap_parse_lconf()");
|
||
+ return FAILURE;
|
||
+ }
|
||
+
|
||
+ while (fgets (buf, sizeof (buf), lcd) != NULL) {
|
||
+
|
||
+ if (*buf == '\n' || *buf == '#')
|
||
+ continue;
|
||
+
|
||
+ k = buf;
|
||
+ v = k;
|
||
+ while (*v != '\0' && *v != ' ' && *v != '\t')
|
||
+ v++;
|
||
+
|
||
+ if (*v == '\0')
|
||
+ continue;
|
||
+
|
||
+ *(v++) = '\0';
|
||
+
|
||
+ while (*v == ' ' || *v == '\t')
|
||
+ v++;
|
||
+
|
||
+ li = strlen (v) - 1;
|
||
+ while (v[li] == ' ' || v[li] == '\t' || v[li] == '\n')
|
||
+ --li;
|
||
+ v[li + 1] = '\0';
|
||
+
|
||
+ if (!strcasecmp (k, "uri")) {
|
||
+ if ((l->servers = ldap_parse_servers(v)) == NULL) {
|
||
+ fatal("error in ldap servers");
|
||
+ return FAILURE;
|
||
+ }
|
||
+
|
||
+ }
|
||
+ else if (!strcasecmp (k, "base")) {
|
||
+ s = strchr (v, '?');
|
||
+ if (s != NULL) {
|
||
+ len = s - v;
|
||
+ l->u_basedn = malloc (len + 1);
|
||
+ strncpy (l->u_basedn, v, len);
|
||
+ l->u_basedn[len] = '\0';
|
||
+ } else {
|
||
+ l->u_basedn = strdup (v);
|
||
+ }
|
||
+ }
|
||
+ else if (!strcasecmp (k, "binddn")) {
|
||
+ l->binddn = strdup (v);
|
||
+ }
|
||
+ else if (!strcasecmp (k, "bindpw")) {
|
||
+ l->bindpw = strdup (v);
|
||
+ }
|
||
+ else if (!strcasecmp (k, "timelimit")) {
|
||
+ l->s_timeout.tv_sec = atoi (v);
|
||
+ }
|
||
+ else if (!strcasecmp (k, "bind_timelimit")) {
|
||
+ l->b_timeout.tv_sec = atoi (v);
|
||
+ }
|
||
+ else if (!strcasecmp (k, "ssl")) {
|
||
+ if (!strcasecmp (v, "start_tls"))
|
||
+ l->tls = 1;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ fclose (lcd);
|
||
+ return SUCCESS;
|
||
+}
|
||
+
|
||
+#endif /* WITH_LDAP_PUBKEY */
|
||
diff -Nuar --exclude '*.orig' --exclude '*.rej' ldapauth.h ldapauth.h
|
||
--- ldapauth.h 1969-12-31 16:00:00.000000000 -0800
|
||
+++ ldapauth.h 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -0,0 +1,124 @@
|
||
+/*
|
||
+ * $Id: openssh-lpk-4.3p1-0.3.7.patch,v 1.3 2006/04/18 15:29:09 eau Exp $
|
||
+ */
|
||
+
|
||
+/*
|
||
+ *
|
||
+ * Copyright (c) 2005, Eric AUGE <eau@phear.org>
|
||
+ * All rights reserved.
|
||
+ *
|
||
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||
+ *
|
||
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||
+ * 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.
|
||
+ * Neither the name of the phear.org nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||
+ *
|
||
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
+ *
|
||
+ *
|
||
+ */
|
||
+
|
||
+#ifndef LDAPAUTH_H
|
||
+#define LDAPAUTH_H
|
||
+
|
||
+#define LDAP_DEPRECATED 1
|
||
+
|
||
+#include <string.h>
|
||
+#include <time.h>
|
||
+#include <ldap.h>
|
||
+#include <lber.h>
|
||
+
|
||
+/* tokens in use for config */
|
||
+#define _DEFAULT_LPK_TOKEN "UseLPK"
|
||
+#define _DEFAULT_SRV_TOKEN "LpkServers"
|
||
+#define _DEFAULT_USR_TOKEN "LpkUserDN"
|
||
+#define _DEFAULT_GRP_TOKEN "LpkGroupDN"
|
||
+#define _DEFAULT_BDN_TOKEN "LpkBindDN"
|
||
+#define _DEFAULT_BPW_TOKEN "LpkBindPw"
|
||
+#define _DEFAULT_MYG_TOKEN "LpkServerGroup"
|
||
+#define _DEFAULT_FIL_TOKEN "LpkFilter"
|
||
+#define _DEFAULT_TLS_TOKEN "LpkForceTLS"
|
||
+#define _DEFAULT_BTI_TOKEN "LpkBindTimelimit"
|
||
+#define _DEFAULT_STI_TOKEN "LpkSearchTimelimit"
|
||
+#define _DEFAULT_LDP_TOKEN "LpkLdapConf"
|
||
+
|
||
+/* default options */
|
||
+#define _DEFAULT_LPK_ON 0
|
||
+#define _DEFAULT_LPK_SERVERS NULL
|
||
+#define _DEFAULT_LPK_UDN NULL
|
||
+#define _DEFAULT_LPK_GDN NULL
|
||
+#define _DEFAULT_LPK_BINDDN NULL
|
||
+#define _DEFAULT_LPK_BINDPW NULL
|
||
+#define _DEFAULT_LPK_SGROUP NULL
|
||
+#define _DEFAULT_LPK_FILTER NULL
|
||
+#define _DEFAULT_LPK_TLS -1
|
||
+#define _DEFAULT_LPK_BTIMEOUT 10
|
||
+#define _DEFAULT_LPK_STIMEOUT 10
|
||
+#define _DEFAULT_LPK_LDP NULL
|
||
+
|
||
+/* flags */
|
||
+#define FLAG_EMPTY 0x00000000
|
||
+#define FLAG_CONNECTED 0x00000001
|
||
+
|
||
+/* flag macros */
|
||
+#define FLAG_SET_EMPTY(x) x&=(FLAG_EMPTY)
|
||
+#define FLAG_SET_CONNECTED(x) x|=(FLAG_CONNECTED)
|
||
+#define FLAG_SET_DISCONNECTED(x) x&=~(FLAG_CONNECTED)
|
||
+
|
||
+/* defines */
|
||
+#define FAILURE -1
|
||
+#define SUCCESS 0
|
||
+#define PUBKEYATTR "sshPublicKey"
|
||
+
|
||
+/*
|
||
+ *
|
||
+ * defined files path
|
||
+ * (should be relocated to pathnames.h,
|
||
+ * if one day it's included within the tree)
|
||
+ *
|
||
+ */
|
||
+#define _PATH_LDAP_CONFIG_FILE "/etc/ldap.conf"
|
||
+
|
||
+/* structures */
|
||
+typedef struct ldap_options {
|
||
+ int on; /* Use it or NOT */
|
||
+ LDAP * ld; /* LDAP file desc */
|
||
+ char * servers; /* parsed servers for ldaplib failover handling */
|
||
+ char * u_basedn; /* user basedn */
|
||
+ char * g_basedn; /* group basedn */
|
||
+ char * binddn; /* binddn */
|
||
+ char * bindpw; /* bind password */
|
||
+ char * sgroup; /* server group */
|
||
+ char * fgroup; /* group filter */
|
||
+ char * filter; /* additional filter */
|
||
+ char * l_conf; /* use ldap.conf */
|
||
+ int tls; /* TLS only */
|
||
+ struct timeval b_timeout; /* bind timeout */
|
||
+ struct timeval s_timeout; /* search timeout */
|
||
+ unsigned int flags; /* misc flags (reconnection, future use?) */
|
||
+} ldap_opt_t;
|
||
+
|
||
+typedef struct ldap_keys {
|
||
+ struct berval ** keys; /* the public keys retrieved */
|
||
+ unsigned int num; /* number of keys */
|
||
+} ldap_key_t;
|
||
+
|
||
+
|
||
+/* function headers */
|
||
+void ldap_close(ldap_opt_t *);
|
||
+int ldap_connect(ldap_opt_t *);
|
||
+char * ldap_parse_groups(const char *);
|
||
+char * ldap_parse_servers(const char *);
|
||
+void ldap_options_print(ldap_opt_t *);
|
||
+void ldap_options_free(ldap_opt_t *);
|
||
+void ldap_keys_free(ldap_key_t *);
|
||
+int ldap_parse_lconf(ldap_opt_t *);
|
||
+ldap_key_t * ldap_getuserkey(ldap_opt_t *, const char *);
|
||
+int ldap_ismember(ldap_opt_t *, const char *);
|
||
+
|
||
+#endif
|
||
diff -Nuar --exclude '*.orig' --exclude '*.rej' lpk-user-example.txt lpk-user-example.txt
|
||
--- lpk-user-example.txt 1969-12-31 16:00:00.000000000 -0800
|
||
+++ lpk-user-example.txt 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -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 -Nuar --exclude '*.orig' --exclude '*.rej' Makefile.in Makefile.in
|
||
--- Makefile.in 2008-07-08 07:21:12.000000000 -0700
|
||
+++ Makefile.in 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -86,7 +86,7 @@
|
||
auth-krb5.o \
|
||
auth2-gss.o gss-serv.o gss-serv-krb5.o \
|
||
loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
|
||
- audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o
|
||
+ audit.o audit-bsm.o platform.o ldapauth.o sftp-server.o sftp-common.o
|
||
|
||
MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out sshd_config.5.out ssh_config.5.out
|
||
MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 sshd_config.5 ssh_config.5
|
||
diff -Nuar --exclude '*.orig' --exclude '*.rej' openssh-lpk_openldap.schema openssh-lpk_openldap.schema
|
||
--- openssh-lpk_openldap.schema 1969-12-31 16:00:00.000000000 -0800
|
||
+++ openssh-lpk_openldap.schema 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -0,0 +1,19 @@
|
||
+#
|
||
+# LDAP Public Key Patch schema for use with openssh-ldappubkey
|
||
+# 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 -Nuar --exclude '*.orig' --exclude '*.rej' openssh-lpk_sun.schema openssh-lpk_sun.schema
|
||
--- openssh-lpk_sun.schema 1969-12-31 16:00:00.000000000 -0800
|
||
+++ openssh-lpk_sun.schema 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -0,0 +1,21 @@
|
||
+#
|
||
+# LDAP Public Key Patch schema for use with openssh-ldappubkey
|
||
+# 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 -Nuar --exclude '*.orig' --exclude '*.rej' README.lpk README.lpk
|
||
--- README.lpk 1969-12-31 16:00:00.000000000 -0800
|
||
+++ README.lpk 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -0,0 +1,267 @@
|
||
+OpenSSH LDAP PUBLIC KEY PATCH
|
||
+Copyright (c) 2003 Eric AUGE (eau@phear.org)
|
||
+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.
|
||
+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
|
||
+'lpkServerGroup:' mean server group configured on the current server ('lpkServerGroup' in sshd_config)
|
||
+
|
||
+example schema:
|
||
+
|
||
+
|
||
+ server1 (uid: eau,rival,toto) (lpkServerGroup: unix)
|
||
+ ___________ /
|
||
+ / \ --- - server3 (uid: eau, titi) (lpkServerGroup: unix)
|
||
+ | LDAP Server | \
|
||
+ | eau ,rival | server2 (uid: rival, eau) (lpkServerGroup: unix)
|
||
+ | titi ,toto |
|
||
+ | userx,.... | server5 (uid: eau) (lpkServerGroup: 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)
|
||
+
|
||
+ If groups are enabled, it will also check if the user that wants to login is in the group of the server he is trying to log into.
|
||
+ If it fails, it falls back on RSA auth files ($HOME/.ssh/authorized_keys), etc.. and finally to standard password authentication (if enabled).
|
||
+
|
||
+ 7 tokens are added to sshd_config :
|
||
+ # here is the new patched ldap related tokens
|
||
+ # entries in your LDAP must be posixAccount & strongAuthenticationUser & posixGroup
|
||
+ UseLPK yes # look the pub key into LDAP
|
||
+ LpkServers ldap://10.31.32.5/ ldap://10.31.32.4 ldap://10.31.32.3 # which LDAP server for users ? (URL format)
|
||
+ LpkUserDN ou=users,dc=foobar,dc=net # which base DN for users ?
|
||
+ LpkGroupDN ou=groups,dc=foobar,dc=net # which base DN for groups ?
|
||
+ LpkBindDN cn=manager,dc=foobar,dc=net # which bind DN ?
|
||
+ LpkBindPw asecret # bind DN credidentials
|
||
+ LpkServerGroup agroupname # the group the server is part of
|
||
+
|
||
+ Right now i'm using anonymous binding to get public keys, because getting public keys of someone doesn't impersonate him<69> but there is some
|
||
+ flaws you have to take care of.
|
||
+
|
||
+- 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.
|
||
+
|
||
+<2B> 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, 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 :
|
||
+ - Falk Siemonsmeier.
|
||
+ - Jacob Rief.
|
||
+ - Michael Durchgraf.
|
||
+ - frederic peters.
|
||
+ - Finlay dobbie.
|
||
+ - Stefan Fisher.
|
||
+ - Robin H. Johnson.
|
||
+ - Adrian Bridgett.
|
||
+
|
||
+- CONTACT :
|
||
+ - Eric AUGE <eau@phear.org>
|
||
+ - Andrea Barisani <andrea@inversepath.com>
|
||
|
||
diff -Nuar --exclude '*.orig' --exclude '*.rej' servconf.h servconf.h
|
||
--- servconf.h 2008-06-10 06:01:51.000000000 -0700
|
||
+++ servconf.h 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -16,6 +16,10 @@
|
||
#ifndef SERVCONF_H
|
||
#define SERVCONF_H
|
||
|
||
+#ifdef WITH_LDAP_PUBKEY
|
||
+#include "ldapauth.h"
|
||
+#endif
|
||
+
|
||
#define MAX_PORTS 256 /* Max # ports. */
|
||
|
||
#define MAX_ALLOW_USERS 256 /* Max # users on allow list. */
|
||
@@ -145,6 +149,9 @@
|
||
int use_pam; /* Enable auth via PAM */
|
||
|
||
int permit_tun;
|
||
+#ifdef WITH_LDAP_PUBKEY
|
||
+ ldap_opt_t lpk;
|
||
+#endif
|
||
|
||
int num_permitted_opens;
|
||
|
||
diff -Nuar --exclude '*.orig' --exclude '*.rej' sshd.c sshd.c
|
||
--- sshd.c 2008-07-11 00:36:49.000000000 -0700
|
||
+++ sshd.c 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -127,6 +127,10 @@
|
||
int deny_severity;
|
||
#endif /* LIBWRAP */
|
||
|
||
+#ifdef WITH_LDAP_PUBKEY
|
||
+#include "ldapauth.h"
|
||
+#endif
|
||
+
|
||
#ifndef O_NOCTTY
|
||
#define O_NOCTTY 0
|
||
#endif
|
||
@@ -1484,6 +1488,16 @@
|
||
exit(1);
|
||
}
|
||
|
||
+#ifdef WITH_LDAP_PUBKEY
|
||
+ /* ldap_options_print(&options.lpk); */
|
||
+ /* XXX initialize/check ldap connection and set *LD */
|
||
+ if (options.lpk.on) {
|
||
+ if (options.lpk.l_conf && (ldap_parse_lconf(&options.lpk) < 0) )
|
||
+ error("[LDAP] could not parse %s", options.lpk.l_conf);
|
||
+ if (ldap_connect(&options.lpk) < 0)
|
||
+ error("[LDAP] could not initialize ldap connection");
|
||
+ }
|
||
+#endif
|
||
debug("sshd version %.100s", SSH_RELEASE);
|
||
|
||
/* Store privilege separation user for later use if required. */
|
||
diff -Nuar --exclude '*.orig' --exclude '*.rej' sshd_config sshd_config
|
||
--- sshd_config 2008-07-02 05:35:43.000000000 -0700
|
||
+++ sshd_config 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -109,6 +109,21 @@
|
||
# no default banner path
|
||
#Banner none
|
||
|
||
+# here are the new patched ldap related tokens
|
||
+# entries in your LDAP must have posixAccount & ldapPublicKey objectclass
|
||
+#UseLPK yes
|
||
+#LpkLdapConf /etc/ldap.conf
|
||
+#LpkServers ldap://10.1.7.1/ ldap://10.1.7.2/
|
||
+#LpkUserDN ou=users,dc=phear,dc=org
|
||
+#LpkGroupDN ou=groups,dc=phear,dc=org
|
||
+#LpkBindDN cn=Manager,dc=phear,dc=org
|
||
+#LpkBindPw secret
|
||
+#LpkServerGroup mail
|
||
+#LpkFilter (hostAccess=master.phear.org)
|
||
+#LpkForceTLS no
|
||
+#LpkSearchTimelimit 3
|
||
+#LpkBindTimelimit 3
|
||
+
|
||
# override default of no subsystems
|
||
Subsystem sftp /usr/libexec/sftp-server
|
||
|
||
diff -Nuar --exclude '*.orig' --exclude '*.rej' sshd_config.5 sshd_config.5
|
||
--- sshd_config.5 2008-07-02 05:35:43.000000000 -0700
|
||
+++ sshd_config.5 2008-08-23 15:02:47.000000000 -0700
|
||
@@ -1003,6 +1003,62 @@
|
||
program.
|
||
The default is
|
||
.Pa /usr/X11R6/bin/xauth .
|
||
+.It Cm UseLPK
|
||
+Specifies whether LDAP public key retrieval must be used or not. It allow
|
||
+an easy centralisation of public keys within an LDAP directory. The argument must be
|
||
+.Dq yes
|
||
+or
|
||
+.Dq no .
|
||
+.It Cm LpkLdapConf
|
||
+Specifies whether LDAP Public keys should parse the specified ldap.conf file
|
||
+instead of sshd_config Tokens. The argument must be a valid path to an ldap.conf
|
||
+file like
|
||
+.Pa /etc/ldap.conf
|
||
+.It Cm LpkServers
|
||
+Specifies LDAP one or more [:space:] separated server's url the following form may be used:
|
||
+.Pp
|
||
+LpkServers ldaps://127.0.0.1 ldap://127.0.0.2 ldap://127.0.0.3
|
||
+.It Cm LpkUserDN
|
||
+Specifies the LDAP user DN.
|
||
+.Pp
|
||
+LpkUserDN ou=users,dc=phear,dc=org
|
||
+.It Cm LpkGroupDN
|
||
+Specifies the LDAP groups DN.
|
||
+.Pp
|
||
+LpkGroupDN ou=groups,dc=phear,dc=org
|
||
+.It Cm LpkBindDN
|
||
+Specifies the LDAP bind DN to use if necessary.
|
||
+.Pp
|
||
+LpkBindDN cn=Manager,dc=phear,dc=org
|
||
+.It Cm LpkBindPw
|
||
+Specifies the LDAP bind credential.
|
||
+.Pp
|
||
+LpkBindPw secret
|
||
+.It Cm LpkServerGroup
|
||
+Specifies one or more [:space:] separated group the server is part of.
|
||
+.Pp
|
||
+LpkServerGroup unix mail prod
|
||
+.It Cm LpkFilter
|
||
+Specifies an additional LDAP filter to use for finding SSH keys
|
||
+.Pp
|
||
+LpkFilter (hostAccess=master.phear.org)
|
||
+.It Cm LpkForceTLS
|
||
+Specifies if the LDAP server connection must be tried, forced or not used. The argument must be
|
||
+.Dq yes
|
||
+or
|
||
+.Dq no
|
||
+or
|
||
+.Dq try .
|
||
+.It Cm LpkSearchTimelimit
|
||
+Sepcifies the search time limit before the search is considered over. value is
|
||
+in seconds.
|
||
+.Pp
|
||
+LpkSearchTimelimit 3
|
||
+.It Cm LpkBindTimelimit
|
||
+Sepcifies the bind time limit before the connection is considered dead. value is
|
||
+in seconds.
|
||
+.Pp
|
||
+LpkBindTimelimit 3
|
||
.El
|
||
.Sh TIME FORMATS
|
||
.Xr sshd 8
|