OL_ARG_ENABLE(kbind,[ --enable-kbind enable V2 Kerberos IV bind (deprecated)], no)dnl
OL_ARG_ENABLE(ipv6,[ --enable-ipv6 enable IPv6 support], auto)dnl
OL_ARG_ENABLE(local,[ --enable-local enable AF_LOCAL (AF_UNIX) socket support], auto)dnl
+OL_ARG_ENABLE(rewrite,[ --enable-rewrite enable rewrite], no)dnl
OL_ARG_ENABLE(x_compile,[ --enable-x-compile enable cross compiling],
no, [yes no])dnl
[static dynamic])
OL_ARG_WITH(ldbm_type,[ --with-ldbm-type use LDBM type], auto,
[auto btree hash])
+OL_ARG_ENABLE(meta,[ --enable-meta enable metadirectory backend], no)dnl
+OL_ARG_WITH(meta_module,[ --with-meta-module module type], static,
+ [static dynamic])
OL_ARG_ENABLE(passwd,[ --enable-passwd enable passwd backend], no)dnl
OL_ARG_WITH(passwd_module,[ --with-passwd-module module type], static,
[static dynamic])
if test $ol_enable_ldbm = yes ; then
AC_MSG_WARN([slapd disabled, ignoring --enable-ldbm argument])
fi
+ if test $ol_enable_meta = yes ; then
+ AC_MSG_WARN([slapd disabled, ignoring --enable-meta argument])
+ fi
if test $ol_enable_passwd = yes ; then
AC_MSG_WARN([slapd disabled, ignoring --enable-passwd argument])
fi
if test $ol_with_ldbm_module != static ; then
AC_MSG_WARN([slapd disabled, ignoring --with-ldbm-module argument])
fi
+ if test $ol_with_meta_module != static ; then
+ AC_MSG_WARN([slapd disabled, ignoring --with-meta-module argument])
+ fi
if test $ol_with_passwd_module != static ; then
AC_MSG_WARN([slapd disabled, ignoring --with-passwd-module argument])
fi
if test $ol_enable_slurpd = yes ; then
AC_MSG_ERROR([slurpd requires slapd])
fi
+ if test $ol_enable_rewrite = yes ; then
+ AC_MSG_WARN([slapd disabled, ignoring --enable-rewrite argument])
+ fi
# force settings to no
ol_enable_bdb=no
ol_enable_dnssrv=no
ol_enable_ldap=no
ol_enable_ldbm=no
+ ol_enable_meta=no
ol_enable_passwd=no
ol_enable_perl=no
ol_enable_shell=no
ol_with_dnssrv_module=static
ol_with_ldap_module=static
ol_with_ldbm_module=static
+ ol_with_meta_module=static
ol_with_passwd_module=static
ol_with_perl_module=static
ol_with_shell_module=static
ol_enable_slurpd=no
+ ol_enable_rewrite=no
+
elif test $ol_enable_ldbm = no ; then
dnl SLAPD without LDBM
$ol_enable_bdb = no -a \
$ol_enable_dnssrv = no -a \
$ol_enable_ldap = no -a \
+ $ol_enable_meta = no -a \
$ol_enable_passwd = no -a \
$ol_enable_perl = no -a \
$ol_enable_shell = no -a \
BUILD_DNSSRV=no
BUILD_LDAP=no
BUILD_LDBM=no
+BUILD_META=no
BUILD_PASSWD=no
BUILD_PERL=no
BUILD_SHELL=no
BUILD_DNSSRV_DYNAMIC=static
BUILD_LDAP_DYNAMIC=static
BUILD_LDBM_DYNAMIC=static
+BUILD_META_DYNAMIC=static
BUILD_PASSWD_DYNAMIC=static
BUILD_PERL_DYNAMIC=static
BUILD_SHELL_DYNAMIC=static
ol_with_dnssrv_module=static
ol_with_ldap_module=static
ol_with_ldbm_module=static
+ ol_with_meta_module=static
ol_with_passwd_module=static
ol_with_perl_module=static
ol_with_shell_module=static
fi
fi
+if test "$ol_enable_meta" != no ; then
+ if test "$ol_enable_ldap" = no ; then
+ AC_MSG_ERROR([need --enable-ldap to use --enable-meta])
+ fi
+ if test "$ol_enable_rewrite" = no ; then
+ AC_MSG_ERROR([need --enable-rewrite to use --enable-meta])
+ fi
+ AC_DEFINE(SLAPD_META,1,[define to support LDAP Metadirectory backend])
+ BUILD_SLAPD=yes
+ BUILD_META=yes
+ if test "$ol_with_meta_module" != static ; then
+ AC_DEFINE(SLAPD_META_DYNAMIC,1,
+ [define to support dynamic LDAP Metadirectory backend])
+ BUILD_META=mod
+ BUILD_META_DYNAMIC=shared
+ SLAPD_MODULES_LIST="$SLAPD_MODULES_LIST -dlopen \$(SLAP_DIR)back-meta/back_meta.la"
+ fi
+fi
+
if test "$ol_enable_passwd" != no ; then
AC_DEFINE(SLAPD_PASSWD,1,[define to support PASSWD backend])
BUILD_SLAPD=yes
BUILD_SLURPD=yes
fi
+if test "$ol_enable_rewrite" != no ; then
+ AC_DEFINE(ENABLE_REWRITE,1,[define to enable rewriting in back-ldap and back-meta])
+ BUILD_REWRITE=yes
+ SLAPD_LIBS="$SLAPD_LIBS -lrewrite"
+fi
+
dnl ----------------------------------------------------------------
if test "$LINK_BINS_DYNAMIC" = yes; then
AC_SUBST(BUILD_DNSSRV)
AC_SUBST(BUILD_LDAP)
AC_SUBST(BUILD_LDBM)
+ AC_SUBST(BUILD_META)
AC_SUBST(BUILD_PASSWD)
AC_SUBST(BUILD_PERL)
AC_SUBST(BUILD_SHELL)
AC_SUBST(BUILD_DNSSRV_DYNAMIC)
AC_SUBST(BUILD_LDAP_DYNAMIC)
AC_SUBST(BUILD_LDBM_DYNAMIC)
+ AC_SUBST(BUILD_META_DYNAMIC)
AC_SUBST(BUILD_PASSWD_DYNAMIC)
AC_SUBST(BUILD_PERL_DYNAMIC)
AC_SUBST(BUILD_SHELL_DYNAMIC)
libraries/libldif/Makefile:build/top.mk:libraries/libldif/Makefile.in:build/lib.mk:build/lib-static.mk \
libraries/liblunicode/Makefile:build/top.mk:libraries/liblunicode/Makefile.in:build/lib.mk:build/lib-static.mk \
libraries/liblutil/Makefile:build/top.mk:libraries/liblutil/Makefile.in:build/lib.mk:build/lib-static.mk \
+libraries/librewrite/Makefile:build/top.mk:libraries/librewrite/Makefile.in:build/lib.mk:build/lib-static.mk \
servers/Makefile:build/top.mk:servers/Makefile.in:build/dir.mk \
servers/slapd/Makefile:build/top.mk:servers/slapd/Makefile.in:build/srv.mk \
servers/slapd/back-bdb/Makefile:build/top.mk:servers/slapd/back-bdb/Makefile.in:build/mod.mk \
servers/slapd/back-dnssrv/Makefile:build/top.mk:servers/slapd/back-dnssrv/Makefile.in:build/mod.mk \
servers/slapd/back-ldap/Makefile:build/top.mk:servers/slapd/back-ldap/Makefile.in:build/mod.mk \
servers/slapd/back-ldbm/Makefile:build/top.mk:servers/slapd/back-ldbm/Makefile.in:build/mod.mk \
+servers/slapd/back-meta/Makefile:build/top.mk:servers/slapd/back-meta/Makefile.in:build/mod.mk \
servers/slapd/back-passwd/Makefile:build/top.mk:servers/slapd/back-passwd/Makefile.in:build/mod.mk \
servers/slapd/back-perl/Makefile:build/top.mk:servers/slapd/back-perl/Makefile.in:build/mod.mk \
servers/slapd/back-shell/Makefile:build/top.mk:servers/slapd/back-shell/Makefile.in:build/mod.mk \
/* define to support dynamic LDBM backend */
#undef SLAPD_LDBM_DYNAMIC
+/* define to support LDAP Metadirectory backend */
+#undef SLAPD_META
+
+/* define to support dynamic LDAP Metadirectory backend */
+#undef SLAPD_META_DYNAMIC
+
/* define to support PASSWD backend */
#undef SLAPD_PASSWD
/* define to support dynamic SQL backend */
#undef SLAPD_SQL_DYNAMIC
+/* define to enable rewriting in back-ldap and back-meta */
+#undef ENABLE_REWRITE
+
/* begin of postamble */
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#ifndef REWRITE_H
+#define REWRITE_H
+
+LDAP_BEGIN_DECL
+
+/*
+ * Default rewrite context
+ */
+#define REWRITE_DEFAULT_CONTEXT "default"
+
+/*
+ * Rewrite engine states
+ */
+#define REWRITE_OFF 0x0000
+#define REWRITE_ON 0x0001
+#define REWRITE_DEFAULT REWRITE_OFF
+
+/*
+ * Rewrite internal status returns
+ */
+#define REWRITE_SUCCESS LDAP_SUCCESS
+#define REWRITE_ERR LDAP_OPERATIONS_ERROR
+#define REWRITE_NO_SUCH_OBJECT LDAP_NO_SUCH_OBJECT
+
+/*
+ * Rewrite modes (input values for rewrite_info_init); determine the
+ * behavior in case a null or non existent context is required:
+ *
+ * REWRITE_MODE_ERR error
+ * REWRITE_MODE_OK no error but no rewrite
+ * REWRITE_MODE_COPY_INPUT a copy of the input is returned
+ * REWRITE_MODE_USE_DEFAULT the default context is used.
+ */
+#define REWRITE_MODE_ERR 0x0010
+#define REWRITE_MODE_OK 0x0011
+#define REWRITE_MODE_COPY_INPUT 0x0012
+#define REWRITE_MODE_USE_DEFAULT 0x0013
+
+/*
+ * Rewrite status returns
+ *
+ * REWRITE_REGEXEC_OK success (result may be empty in case
+ * of no match)
+ * REWRITE_REGEXEC_ERR error (internal error,
+ * misconfiguration, map not working ...)
+ * REWRITE_REGEXEC_STOP internal use; never returned
+ * REWRITE_REGEXEC_UNWILLING the server should issue an 'unwilling
+ * to perform' error
+ */
+#define REWRITE_REGEXEC_OK 0x0000
+#define REWRITE_REGEXEC_ERR 0x0001
+#define REWRITE_REGEXEC_STOP 0x0002
+#define REWRITE_REGEXEC_UNWILLING 0x0004
+
+/*
+ * Rewrite info
+ */
+struct rewrite_info;
+struct berval;
+
+/*
+ * Inits the info
+ */
+extern struct rewrite_info *
+rewrite_info_init(
+ int mode
+);
+
+/*
+ * Cleans up the info structure
+ */
+extern int
+rewrite_info_delete(
+ struct rewrite_info *info
+);
+
+
+/*
+ * Parses a config line and takes actions to fit content in rewrite structure;
+ * lines handled are of the form:
+ *
+ * rewriteEngine {on|off}
+ * rewriteMaxPasses numPasses
+ * rewriteContext contextName [alias aliasedRewriteContex]
+ * rewriteRule pattern substPattern [ruleFlags]
+ * rewriteMap mapType mapName [mapArgs]
+ * rewriteParam paramName paramValue
+ */
+extern int
+rewrite_parse(
+ struct rewrite_info *info,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv
+);
+
+/*
+ * Rewrites a string according to context.
+ * If the engine is off, OK is returned, but the return string will be NULL.
+ * In case of 'unwilling to perform', UNWILLING is returned, and the
+ * return string will also be null. The same in case of error.
+ * Otherwise, OK is returned, and result will hold a newly allocated string
+ * with the rewriting.
+ *
+ * What to do in case of non-existing rewrite context is still an issue.
+ * Four possibilities:
+ * - error,
+ * - ok with NULL result,
+ * - ok with copy of string as result,
+ * - use the default rewrite context.
+ */
+extern int
+rewrite(
+ struct rewrite_info *info,
+ const char *rewriteContext,
+ const char *string,
+ char **result
+);
+
+/*
+ * Same as above; the cookie relates the rewrite to a session
+ */
+extern int
+rewrite_session(
+ struct rewrite_info *info,
+ const char *rewriteContext,
+ const char *string,
+ const void *cookie,
+ char **result
+);
+
+/*
+ * Inits a session
+ */
+extern struct rewrite_session *
+rewrite_session_init(
+ struct rewrite_info *info,
+ const void *cookie
+);
+
+/*
+ * Defines and inits a variable with session scope
+ */
+extern int
+rewrite_session_var_set(
+ struct rewrite_info *info,
+ const void *cookie,
+ const char *name,
+ const char *value
+);
+
+/*
+ * Deletes a session
+ */
+extern int
+rewrite_session_delete(
+ struct rewrite_info *info,
+ const void *cookie
+);
+
+
+/*
+ * Params
+ */
+
+/*
+ * Defines and inits a variable with global scope
+ */
+extern int
+rewrite_param_set(
+ struct rewrite_info *info,
+ const char *name,
+ const char *value
+);
+
+/*
+ * Gets a var with global scope
+ */
+extern int
+rewrite_param_get(
+ struct rewrite_info *info,
+ const char *name,
+ struct berval *value
+);
+
+/*
+ * Destroys the parameter tree
+ */
+extern int
+rewrite_param_destroy(
+ struct rewrite_info *info
+);
+
+LDAP_END_DECL
+
+#endif /* REWRITE_H */
+
SUBDIRS= liblunicode liblutil libldif \
liblber libldap libldap_r \
- libavl libldbm
+ libavl libldbm librewrite
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
--- /dev/null
+# $OpenLDAP$
+## Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
+## COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+##
+## LIBREWRITE
+##
+## Copyright 2000-2001 Pierangelo Masarati <ando@sys-net.it>
+##
+
+SRCS = config.c context.c info.c ldapmap.c map.c params.c rule.c \
+ session.c subst.c var.c \
+ parse.c rewrite.c
+XSRCS = version.c
+OBJS = config.o context.o info.o ldapmap.o map.o params.o rule.o \
+ session.o subst.o var.o
+
+LDAP_INCDIR= ../../include
+LDAP_LIBDIR= ../../libraries
+
+LIBRARY = librewrite.a
+PROGRAMS = rewrite
+XLIBS = -lrewrite -lavl -llutil -lldap_r -llber
+XXLIBS = $(SECURITY_LIBS) $(LDIF_LIBS) $(LUTIL_LIBS)
+XXXLIBS = $(LTHREAD_LIBS)
+
+rewrite: $(LIBRARY) rewrite.o parse.o
+ $(LTLINK) -o $@ rewrite.o parse.o $(LIBS)
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+/*
+ * Description
+ *
+ * A string is rewritten according to a set of rules, called
+ * a `rewrite context'.
+ * The rules are based on Regular Expressions (POSIX regex) with
+ * substring matching; extensions are planned to allow basic variable
+ * substitution and map resolution of substrings.
+ * The behavior of pattern matching/substitution can be altered by a
+ * set of flags.
+ *
+ * The underlying concept is to build a lightweight rewrite module
+ * for the slapd server (initially dedicated to the back-ldap module).
+ *
+ *
+ * Passes
+ *
+ * An incoming string is matched agains a set of rules. Rules are made
+ * of a match pattern, a substitution pattern and a set of actions.
+ * In case of match a string rewriting is performed according to the
+ * substitution pattern that allows to refer to substrings matched
+ * in the incoming string. The actions, if any, are finally performed.
+ * The substitution pattern allows map resolution of substrings.
+ * A map is a generic object that maps a substitution pattern to a
+ * value.
+ *
+ *
+ * Pattern Matching Flags
+ *
+ * 'C' honors case in matching (default is case insensitive)
+ * 'R' use POSIX Basic Regular Expressions (default is Extended)
+ *
+ *
+ * Action Flags
+ *
+ * ':' apply the rule once only (default is recursive)
+ * '@' stop applying rules in case of match.
+ * '#' stop current operation if the rule matches, and issue an
+ * `unwilling to perform' error.
+ * 'G{n}' jump n rules back and forth (watch for loops!). Note that
+ * 'G{1}' is implicit in every rule.
+ * 'I' ignores errors in rule; this means, in case of error, e.g.
+ * issued by a map, the error is treated as a missed match.
+ * The 'unwilling to perform' is not overridden.
+ *
+ * the ordering of the flags is significant. For instance:
+ *
+ * 'IG{2}' means ignore errors and jump two lines ahead both in case
+ * of match and in case of error, while
+ * 'G{2}I' means ignore errors, but jump thwo lines ahead only in case
+ * of match.
+ *
+ * More flags (mainly Action Flags) will be added as needed.
+ *
+ *
+ * Pattern matching:
+ *
+ * see regex(7)
+ *
+ *
+ * String Substitution:
+ *
+ * the string substitution happens according to a substitution pattern.
+ * - susbtring substitution is allowed with the syntax '\d'
+ * where 'd' is a digit ranging 0-9 (0 is the full match).
+ * I see that 0-9 digit expansion is a widely accepted
+ * practise; however there is no technical reason to use
+ * such a strict limit. A syntax of the form '\{ddd}'
+ * should be fine if there is any need to use a higher
+ * number of possible submatches.
+ * - variable substitution will be allowed (at least when I
+ * figure out which kind of variable could be proficiently
+ * substituted)
+ * - map lookup will be allowed (map lookup of substring matches
+ * in gdbm, ldap(!), math(?) and so on maps 'a la sendmail'.
+ * - subroutine invocation will make it possible to rewrite a
+ * submatch in terms of the output of another rewriteContext
+ *
+ * Old syntax:
+ *
+ * '\' {0-9} [ '{' <name> [ '(' <args> ')' ] '}' ]
+ *
+ * where <name> is the name of a built-in map, and
+ * <args> are optional arguments to the map, if
+ * the map <name> requires them.
+ * The following experimental maps have been implemented:
+ *
+ * \n{xpasswd}
+ * maps the n-th substring match as uid to
+ * the gecos field in /etc/passwd;
+ *
+ * \n{xfile(/absolute/path)}
+ * maps the n-th substring match
+ * to a 'key value' style plain text file.
+ *
+ * \n{xldap(ldap://url/with?%0?in?filter)
+ * maps the n-th substring match to an
+ * attribute retrieved by means of an LDAP
+ * url with substitution of %0 in the filter
+ * (NOT IMPL.)
+ *
+ * New scheme:
+ *
+ * - everything starting with '\' requires substitution;
+ * - the only obvious exception is '\\', which is left as is;
+ * - the basic substitution is '\d', where 'd' is a digit;
+ * 0 means the whole string, while 1-9 is a submatch;
+ * - in the outdated schema, the digit may be optionally
+ * followed by a '{', which means pipe the submatch into
+ * the map described by the string up to the following '}';
+ * - the output of the map is used instead of the submatch;
+ * - in the new schema, a '\' followed by a '{' invokes an
+ * advanced substitution scheme. The pattern is:
+ *
+ * '\' '{' [{ <op> }] <name> '(' <substitution schema> ')' '}'
+ *
+ * where <name> must be a legal name for the map, i.e.
+ *
+ * <name> ::= [a-z][a-z0-9]* (case insensitive)
+ * <op> ::= '>' '|' '&' '&&' '*' '**' '$'
+ *
+ * and <substitution schema> must be a legal substitution
+ * schema, with no limits on the nesting level.
+ * The operators are:
+ * > sub context invocation; <name> must be a legal,
+ * already defined rewrite context name
+ * | external command invocation; <name> must refer
+ * to a legal, already defined command name (NOT IMPL.)
+ * & variable assignment; <name> defines a variable
+ * in the running operation structure which can be
+ * dereferenced later (NOT IMPL.)
+ * * variable dereferencing; <name> must refer to a
+ * variable that is defined and assigned for the
+ * running operation (NOT IMPL.)
+ * $ parameter dereferencing; <name> must refer to
+ * an existing parameter; the idea is to make
+ * some run-time parameters set by the system
+ * available to the rewrite engine, as the client
+ * host name, the bind dn if any, constant
+ * parameters initialized at config time, and so
+ * on (NOT IMPL.)
+ *
+ * Note: as the slapd parsing routines escape backslashes ('\'),
+ * a double backslash is required inside substitution patterns.
+ * To overcome the resulting heavy notation, the substitution escaping
+ * has been delegated to the '%' symbol, which should be used
+ * instead of '\' in string substitution patterns. The symbol can
+ * be altered at will by redefining the related macro in "rewrite-int.h".
+ * In the current snapshot, all the '\' on the left side of each rule
+ * (the regex pattern) must be converted in '\\'; all the '\' on the
+ * right side of the rule (the substitution pattern) must be turned
+ * into '%'. In the following examples, the original (more readable)
+ * syntax is used; however, in the servers/slapd/back-ldap/slapd.conf
+ * example file, the working syntax is used.
+ *
+ *
+ *
+ * Rewrite context:
+ *
+ * a rewrite context is a set of rules which are applied in sequence.
+ * The basic idea is to have an application initialize a rewrite
+ * engine (think of Apache's mod_rewrite ...) with a set of rewrite
+ * contexts; when string rewriting is required, one invokes the
+ * appropriate rewrite context with the input string and obtains the
+ * newly rewritten one if no errors occur.
+ *
+ * An interesting application, in back-ldap or in slapd itself,
+ * could associate each basic server operation to a rewrite context
+ * (most of them possibly aliasing the default one). Then, DN rewriting
+ + could take place at any invocation of a backend operation.
+ *
+ * client -> server:
+ * default if defined and no specific context is available
+ * bindDn bind
+ * searchBase search
+ * searchFilter search
+ * compareDn compare
+ * addDn add
+ * modifyDn modify
+ * modrDn modrdn
+ * newSuperiorDn modrdn
+ * deleteDn delete
+ *
+ * server -> client:
+ * searchResult search (only if defined; no default)
+ *
+ *
+ * Configuration syntax:
+ *
+ * Basics:
+ *
+ * rewriteEngine { on | off }
+ *
+ * rewriteContext <context name> [ alias <aliased context name> ]
+ *
+ * rewriteRule <regex pattern> <substitution pattern> [ <flags> ]
+ *
+ *
+ * Additional:
+ *
+ * rewriteMap <map name> <map type> [ <map attrs> ]
+ *
+ * rewriteParam <param name> <param value>
+ *
+ * rewriteMaxPasses <number of passes>
+ *
+ *
+ *
+ * rewriteEngine:
+ *
+ * if 'on', the requested rewriting is performed; if 'off', no
+ * rewriting takes place (an easy way to stop rewriting without
+ * altering too much the configuration file)
+ *
+ * rewriteContext:
+ *
+ * <context name> is the name that identifies the context, i.e.
+ * the name used by the application to refer to the set of rules
+ * it contains. It is used also to reference sub contexts in
+ * string rewriting. A context may aliase another one. In this
+ * case the alias context contains no rule, and any reference to
+ * it will result in accessing the aliased one.
+ *
+ * rewriteRule:
+ *
+ * determines how a tring can be rewritten if a pattern is matched.
+ * Examples are reported below.
+ *
+ * rewriteMap:
+ *
+ * allows to define a map that transforms substring rewriting into
+ * something else. The map is referenced inside the substitution
+ * pattern of a rule.
+ *
+ * rewriteParam:
+ *
+ * sets a value with global scope, that can be dereferenced by the
+ * command '\{$paramName}'.
+ *
+ * rewriteMaxPasses:
+ *
+ * sets the maximum number of total rewriting passes taht can be
+ * performed in a signle rewriting operation (to avoid loops).
+ *
+ *
+ * Configuration examples:
+ *
+ * # set to 'off' to disable rewriting
+ *
+ * rewriteEngine on
+ *
+ *
+ * # everything defined here goes into the 'default' context
+ * # this rule changes the naming context of anything sent to
+ * # 'dc=home,dc=net' to 'dc=OpenLDAP, dc=org'
+ *
+ * rewriteRule "(.*)dc=home,[ ]?dc=net" "\1dc=OpenLDAP, dc=org" ":"
+ *
+ *
+ * # start a new context (ends input of the previous one)
+ * # this rule adds blancs between dn parts if not present.
+ *
+ * rewriteContext addBlancs
+ * rewriteRule "(.*),([^ ].*)" "\1, \2"
+ *
+ *
+ * # this one eats blancs
+ *
+ * rewriteContext eatBlancs
+ * rewriteRule "(.*),[ ](.*)" "\1,\2"
+ *
+ *
+ * # here control goes back to the default rewrite context; rules are
+ * # appended to the existing ones.
+ * # anything that gets here is piped into rule 'addBlancs'
+ *
+ * rewriteContext default
+ * rewriteRule ".*" "\{>addBlancs(\0)}" ":"
+ *
+ *
+ * # anything with 'uid=username' gets looked up in /etc/passwd for
+ * # gecos (I know it's nearly useless, but it is there just to
+ * # test something fancy!). Note the 'I' flag that leaves
+ * # 'uid=username' in place if 'username' does not have a valid
+ * # account. Note also the ':' that forces the rule to be processed
+ * # exactly once.
+ *
+ * rewriteContext uid2Gecos
+ * rewriteRule "(.*)uid=([a-z0-9]+),(.+)" "\1cn=\2{xpasswd},\3" "I:"
+ *
+ *
+ * # finally, in case of bind, if one uses a 'uid=username' dn,
+ * # it is rewritten in 'cn=name surname' if possible.
+ *
+ * rewriteContext bindDn
+ * rewriteRule ".*" "\{>addBlancs(\{>uid2Gecos(\0)})}" ":"
+ *
+ *
+ * # the search base is rewritten according to 'default' rules
+ *
+ * rewriteContext searchBase alias default
+ *
+ *
+ * # search results with OpenLDAP dn are rewritten back with
+ * # 'dc=home,dc=net' naming context, with spaces eaten.
+ *
+ * rewriteContext searchResult
+ * rewriteRule "(.*[^ ]?)[ ]?dc=OpenLDAP,[ ]?dc=org"
+ * "\{>eatBlancs(\1)}dc=home,dc=net" ":"
+ *
+ * # bind with email instead of full dn: we first need an ldap map
+ * # that turns attributes into a dn (the filter is provided by the
+ * # substitution string):
+ *
+ * rewriteMap ldap attr2dn "ldap://host/dc=my,dc=org?dn?sub"
+ *
+ * # then we need to detect emails; note that the rule in case of match
+ * # stops rewriting; in case of error, it is ignored.
+ * # In case we are mapping virtual to real naming contexts, we also
+ * # need to rewrite regular dns, because the definition of a bindDn
+ * # rewrite context overrides the default definition.
+ *
+ * rewriteContext bindDn
+ * rewriteRule "(mail=[^,]+@[^,]+)" "\{attr2dn(\1)}" "@I"
+ *
+ * # This is a rather sophisticate example. It massages a search filter
+ * # in case who performs the search has administrative privileges.
+ * # First we need to keep track of the bind dn of the incoming request:
+ *
+ * rewriteContext bindDn
+ * rewriteRule ".+" "\{**&binddn(\0)}" ":"
+ *
+ * # a search filter containing 'uid=' is rewritten only if an
+ * # appropriate dn is bound.
+ * # to do this, in the first rule the bound dn is dereferenced, while
+ * # the filter is decomposed in a prefix, the argument of the 'uid=',
+ * # and in a suffix. A tag '<>' is appended to the dn. If the dn
+ * # refers to an entry in the 'ou=admin' subtree, the filter is
+ * # rewritten OR-ing the 'uid=<arg>' with 'cn=<arg>'; otherwise
+ * # it is left as is. This could be useful, for instance, to allow
+ * # apache's auth_ldap-1.4 module to authenticate users with both
+ * # 'uid' and 'cn', but only if the request comes from a possible
+ * # 'dn: cn=Web auth, ou=admin, dc=home, dc=net' user.
+ *
+ * rewriteContext searchFilter
+ * rewriteRule "(.*\()uid=([a-z0-9_]+)(\).*)"
+ * "\{**binddn}<>\{&prefix(\1)}\{&arg(\2)}\{&suffix(\3)}" ":I"
+ * rewriteRule "[^,]+,[ ]?ou=admin,[ ]?dc=home,[ ]?dc=net"
+ * "\{*prefix}|(uid=\{*arg})(cn=\{*arg})\{*suffix}" "@I"
+ * rewriteRule ".*<>" "\{*prefix}uid=\{*arg}\{*suffix}"
+ *
+ *
+ * LDAP Proxy resolution (a possible evolution of the back-ldap):
+ *
+ * in case the rewritten dn is an LDAP URL, the operation is initiated
+ * towards the host[:port] indicated in the url, if it does not refer
+ * to the local server.
+ *
+ * e.g.:
+ *
+ * rewriteRule '^cn=root,.*' '\0' 'G{3}'
+ * rewriteRule '^cn=[a-l].*' 'ldap://ldap1.my.org/\0' '@'
+ * rewriteRule '^cn=[m-z].*' 'ldap://ldap2.my.org/\0' '@'
+ * rewriteRule '.*' 'ldap://ldap3.my.org/\0' '@'
+ *
+ * (rule 1 is simply there to illustrate the 'G{n}' action; it could
+ * have been written:
+ *
+ * rewriteRule '^cn=root,.*' 'ldap://ldap3.my.org/\0' '@'
+ *
+ * with the advantage of saving one rewrite pass ...)
+ */
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#include <portable.h>
+
+#include "rewrite-int.h"
+#include "rewrite-map.h"
+
+/*
+ * Global data
+ */
+extern struct rewrite_context *__curr_context;
+
+/*
+ * Parses a plugin map
+ */
+static int
+rewrite_parse_builtin_map(
+ struct rewrite_info *info,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv
+);
+
+/*
+ * Parses a config line and takes actions to fit content in rewrite structure;
+ * lines handled are of the form:
+ *
+ * rewriteEngine {on|off}
+ * rewriteMaxPasses numPasses
+ * rewriteContext contextName [alias aliasedContextName]
+ * rewriteRule pattern substPattern [ruleFlags]
+ * rewriteMap mapType mapName [mapArgs]
+ * rewriteParam paramName paramValue
+ */
+int
+rewrite_parse(
+ struct rewrite_info *info,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv
+)
+{
+ int rc = -1;
+
+ assert( info != NULL );
+ assert( fname != NULL );
+ assert( argv != NULL );
+ assert( argc > 0 );
+
+ /*
+ * Switch on the rewrite engine
+ */
+ if ( strcasecmp( argv[ 0 ], "rewriteEngine" ) == 0 ) {
+ if ( argc < 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] rewriteEngine needs 'state'\n%s",
+ fname, lineno, "" );
+ return -1;
+ } else if ( argc > 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] extra fields in rewriteEngine"
+ " will be discarded\n%s",
+ fname, lineno, "" );
+ }
+
+ if ( strcasecmp( argv[ 1 ], "on" ) == 0 ) {
+ info->li_state = REWRITE_ON;
+ } else if ( strcasecmp( argv[ 1 ], "off" ) == 0 ) {
+ info->li_state = REWRITE_OFF;
+ } else {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] unknown 'state' in rewriteEngine;"
+ " assuming 'on'\n%s",
+ fname, lineno, "" );
+ info->li_state = REWRITE_ON;
+ }
+ rc = REWRITE_SUCCESS;
+
+ /*
+ * Alter max passes
+ */
+ } else if ( strcasecmp( argv[ 0 ], "rewriteMaxPasses" ) == 0 ) {
+ if ( argc < 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] rewriteMaxPasses needs 'value'\n%s",
+ fname, lineno, "" );
+ return -1;
+ }
+ info->li_max_passes = atoi( argv[ 1 ] );
+ rc = REWRITE_SUCCESS;
+
+ /*
+ * Start a new rewrite context and set current context
+ */
+ } else if ( strcasecmp( argv[ 0 ], "rewriteContext" ) == 0 ) {
+ if ( argc < 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] rewriteContext needs 'name'\n%s",
+ fname, lineno, "" );
+ return -1;
+ }
+
+ /*
+ * Checks for existence (lots of contexts should be
+ * available by default ...)
+ */
+ __curr_context = rewrite_context_find( info, argv[ 1 ] );
+ if ( __curr_context == NULL ) {
+ __curr_context = rewrite_context_create( info,
+ argv[ 1 ] );
+ }
+ if ( __curr_context == NULL ) {
+ return -1;
+ }
+
+ if ( argc > 2 ) {
+
+ /*
+ * A context can alias another (e.g., the `builtin'
+ * contexts for backend operations, if not defined,
+ * alias the `default' rewrite context (with the
+ * notable exception of the searchResult context,
+ * which can be undefined)
+ */
+ if ( strcasecmp( argv[ 2 ], "alias" ) == 0 ) {
+ struct rewrite_context *aliased;
+
+ if ( argc == 3 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] rewriteContext"
+ " needs 'name' after"
+ " 'alias'\n%s",
+ fname, lineno, "" );
+ return -1;
+ } else if ( argc > 4 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] extra fields in"
+ " rewriteContext"
+ " after aliased name"
+ " will be"
+ " discarded\n%s",
+ fname, lineno, "" );
+ }
+
+ aliased = rewrite_context_find( info,
+ argv[ 3 ] );
+ if ( aliased == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] aliased"
+ " rewriteContext '%s'"
+ " does not exists\n",
+ fname, lineno,
+ argv[ 3 ] );
+ return -1;
+ }
+
+ __curr_context->lc_alias = aliased;
+ __curr_context = aliased;
+ } else {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] extra fields"
+ " in rewriteContext"
+ " will be discarded\n%s",
+ fname, lineno, "" );
+ }
+ }
+ rc = REWRITE_SUCCESS;
+
+ /*
+ * Compile a rule in current context
+ */
+ } else if ( strcasecmp( argv[ 0 ], "rewriteRule" ) == 0 ) {
+ if ( argc < 3 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] rewriteRule needs 'pattern'"
+ " 'subst' ['flags']\n%s",
+ fname, lineno, "" );
+ return -1;
+ } else if ( argc > 4 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] extra fields in rewriteRule"
+ " will be discarded\n%s",
+ fname, lineno, "" );
+ }
+
+ if ( __curr_context == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] rewriteRule outside a"
+ " context; will add to default\n%s",
+ fname, lineno, "" );
+ __curr_context = rewrite_context_find( info,
+ REWRITE_DEFAULT_CONTEXT );
+
+ /*
+ * Default context MUST exist in a properly initialized
+ * struct rewrite_info
+ */
+ assert( __curr_context != NULL );
+ }
+
+ rc = rewrite_rule_compile( info, __curr_context, argv[ 1 ],
+ argv[ 2 ], ( argc == 4 ? argv[ 3 ] : "" ) );
+
+ /*
+ * Add a plugin map to the map tree
+ */
+ } else if ( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 ) {
+ if ( argc < 3 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] rewriteMap needs at least 'type'"
+ " and 'name' ['args']\n%s",
+ fname, lineno, "" );
+ return -1;
+ }
+
+ rc = rewrite_parse_builtin_map( info, fname, lineno,
+ argc, argv );
+
+ /*
+ * Set the value of a global scope parameter
+ */
+ } else if ( strcasecmp( argv[ 0 ], "rewriteParam" ) == 0 ) {
+ if ( argc < 3 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] rewriteParam needs 'name'"
+ " and 'value'\n%s",
+ fname, lineno, "" );
+ return -1;
+ }
+
+ rc = rewrite_param_set( info, argv[ 1 ], argv[ 2 ] );
+
+ /*
+ * Error
+ */
+ } else {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] unknown command '%s'\n",
+ fname, lineno, "" );
+ return -1;
+ }
+
+ return rc;
+}
+
+/*
+ * Compares two maps
+ */
+static int
+rewrite_builtin_map_cmp(
+ const void *c1,
+ const void *c2
+)
+{
+ const struct rewrite_builtin_map *m1, *m2;
+
+ m1 = ( struct rewrite_builtin_map * )c1;
+ m2 = ( struct rewrite_builtin_map * )c2;
+
+ assert( m1 != NULL );
+ assert( m2 != NULL );
+ assert( m1->lb_name != NULL );
+ assert( m2->lb_name != NULL );
+
+ return strcasecmp( m1->lb_name, m2->lb_name );
+}
+
+/*
+ * Duplicate map ?
+ */
+static int
+rewrite_builtin_map_dup(
+ void *c1,
+ void *c2
+)
+{
+ struct rewrite_builtin_map *m1, *m2;
+
+ m1 = ( struct rewrite_builtin_map * )c1;
+ m2 = ( struct rewrite_builtin_map * )c2;
+
+ assert( m1 != NULL );
+ assert( m2 != NULL );
+ assert( m1->lb_name != NULL );
+ assert( m2->lb_name != NULL );
+
+ return ( strcasecmp( m1->lb_name, m2->lb_name ) == 0 ? -1 : 0 );
+}
+
+/*
+ * Adds a map to the info map tree
+ */
+static int
+rewrite_builtin_map_insert(
+ struct rewrite_info *info,
+ struct rewrite_builtin_map *map
+)
+{
+ /*
+ * May need a mutex?
+ */
+ return avl_insert( &info->li_maps, ( caddr_t )map,
+ rewrite_builtin_map_cmp,
+ rewrite_builtin_map_dup );
+}
+
+/*
+ * Retrieves a map
+ */
+struct rewrite_builtin_map *
+rewrite_builtin_map_find(
+ struct rewrite_info *info,
+ const char *name
+)
+{
+ struct rewrite_builtin_map tmp;
+
+ assert( info != NULL );
+ assert( name != NULL );
+
+ tmp.lb_name = ( char * )name;
+
+ return ( struct rewrite_builtin_map * )avl_find( info->li_maps,
+ ( caddr_t )&tmp, rewrite_builtin_map_cmp );
+}
+
+/*
+ * Parses a plugin map
+ */
+static int
+rewrite_parse_builtin_map(
+ struct rewrite_info *info,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv
+)
+{
+ struct rewrite_builtin_map *map;
+
+#define MAP_TYPE 1
+#define MAP_NAME 2
+
+ assert( info != NULL );
+ assert( fname != NULL );
+ assert( argc > 2 );
+ assert( argv != NULL );
+ assert( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 );
+
+ map = calloc( sizeof( struct rewrite_builtin_map ), 1 );
+ if ( map == NULL ) {
+ return REWRITE_ERR;
+ }
+
+ map->lb_name = strdup( argv[ MAP_NAME ] );
+ if ( map->lb_name == NULL ) {
+ free( map );
+ return REWRITE_ERR;
+ }
+
+ /*
+ * Built-in ldap map
+ */
+ if ( strcasecmp( argv[ MAP_TYPE ], "ldap" ) == 0 ) {
+ map->lb_type = REWRITE_BUILTIN_MAP_LDAP;
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ if ( ldap_pvt_thread_mutex_init( & map->lb_mutex ) ) {
+ free( map->lb_name );
+ free( map );
+ return REWRITE_ERR;
+ }
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ map->lb_private = map_ldap_parse( info, fname, lineno,
+ argc - 3, argv + 3 );
+
+ /*
+ * Error
+ */
+ } else {
+ Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown map type\n%s",
+ fname, lineno, "" );
+ return -1;
+ }
+
+ return rewrite_builtin_map_insert( info, map );
+}
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#include <portable.h>
+
+#include "rewrite-int.h"
+
+/*
+ * Compares two struct rewrite_context based on the name;
+ * used by avl stuff
+ */
+static int
+rewrite_context_cmp(
+ const void *c1,
+ const void *c2
+)
+{
+ struct rewrite_context *lc1, *lc2;
+
+ lc1 = (struct rewrite_context *)c1;
+ lc2 = (struct rewrite_context *)c2;
+
+ assert( c1 != NULL );
+ assert( c2 != NULL );
+ assert( lc1->lc_name != NULL );
+ assert( lc2->lc_name != NULL );
+
+ return strcasecmp( lc1->lc_name, lc2->lc_name );
+}
+
+/*
+ * Returns -1 in case a duplicate struct rewrite_context
+ * has been inserted; used by avl stuff
+ */
+static int
+rewrite_context_dup(
+ void *c1,
+ void *c2
+ )
+{
+ struct rewrite_context *lc1, *lc2;
+
+ lc1 = (struct rewrite_context *)c1;
+ lc2 = (struct rewrite_context *)c2;
+
+ assert( c1 != NULL );
+ assert( c2 != NULL );
+ assert( lc1->lc_name != NULL );
+ assert( lc2->lc_name != NULL );
+
+ return( strcasecmp( lc1->lc_name, lc2->lc_name) == 0 ? -1 : 0 );
+}
+
+/*
+ * Finds the context named rewriteContext in the context tree
+ */
+struct rewrite_context *
+rewrite_context_find(
+ struct rewrite_info *info,
+ const char *rewriteContext
+)
+{
+ struct rewrite_context *context, c;
+
+ assert( info != NULL );
+ assert( rewriteContext != NULL );
+
+ /*
+ * Fetches the required rewrite context
+ */
+ c.lc_name = (char *)rewriteContext;
+ context = (struct rewrite_context *)avl_find( info->li_context,
+ (caddr_t)&c, rewrite_context_cmp );
+ if ( context == NULL ) {
+ return NULL;
+ }
+
+ /*
+ * De-aliases the context if required
+ */
+ if ( context->lc_alias ) {
+ return context->lc_alias;
+ }
+
+ return context;
+}
+
+/*
+ * Creates a new context called rewriteContext and stores in into the tree
+ */
+struct rewrite_context *
+rewrite_context_create(
+ struct rewrite_info *info,
+ const char *rewriteContext
+)
+{
+ struct rewrite_context *context;
+ int rc;
+
+ assert( info != NULL );
+ assert( rewriteContext != NULL );
+
+ context = calloc( sizeof( struct rewrite_context ), 1 );
+ if ( context == NULL ) {
+ return NULL;
+ }
+
+ /*
+ * Context name
+ */
+ context->lc_name = strdup( rewriteContext );
+ if ( context->lc_name == NULL ) {
+ free( context );
+ return NULL;
+ }
+
+ /*
+ * The first, empty rule
+ */
+ context->lc_rule = calloc( sizeof( struct rewrite_rule ), 1 );
+ if ( context->lc_rule == NULL ) {
+ free( context->lc_name );
+ free( context );
+ return NULL;
+ }
+
+ /*
+ * Add context to tree
+ */
+ rc = avl_insert( &info->li_context, (caddr_t)context,
+ rewrite_context_cmp, rewrite_context_dup );
+ if ( rc == -1 ) {
+ free( context->lc_rule );
+ free( context->lc_name );
+ free( context );
+ return NULL;
+ }
+
+ return context;
+}
+
+/*
+ * Finds the next rule according to a goto action statement,
+ * or null in case of error.
+ * Helper for rewrite_context_apply.
+ */
+static struct rewrite_rule *
+rewrite_action_goto(
+ struct rewrite_action *action,
+ struct rewrite_rule *rule
+)
+{
+ int n;
+
+ assert( action != NULL );
+ assert( action->la_args != NULL );
+ assert( rule != NULL );
+
+ n = ((int *)action->la_args)[ 0 ];
+
+ if ( n > 0 ) {
+ for ( ; n > 1 && rule != NULL ; n-- ) {
+ rule = rule->lr_next;
+ }
+ } else if ( n <= 0 ) {
+ for ( ; n < 1 && rule != NULL ; n++ ) {
+ rule = rule->lr_prev;
+ }
+ }
+
+ return rule;
+}
+
+/*
+ * Rewrites string according to context; may return:
+ * OK: fine; if *result != NULL rule matched and rewrite succeeded.
+ * STOP: fine, rule matched; stop processing following rules
+ * UNWILL: rule matched; force 'unwilling to perform'
+ */
+int
+rewrite_context_apply(
+ struct rewrite_info *info,
+ struct rewrite_op *op,
+ struct rewrite_context *context,
+ const char *string,
+ char **result
+)
+{
+ struct rewrite_rule *rule;
+ char *s, *res = NULL;
+ int return_code = REWRITE_REGEXEC_OK;
+
+ assert( info != NULL );
+ assert( op != NULL );
+ assert( context != NULL );
+ assert( context->lc_rule != NULL );
+ assert( string != NULL );
+ assert( result != NULL );
+
+ op->lo_depth++;
+ assert( op->lo_depth > 0 );
+
+ Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
+ " [depth=%d] string='%s'\n%s",
+ op->lo_depth, string, "" );
+
+ s = strdup( string );
+
+ for ( rule = context->lc_rule->lr_next;
+ rule != NULL && op->lo_num_passes < info->li_max_passes;
+ rule = rule->lr_next, op->lo_num_passes++ ) {
+ int rc;
+
+ /*
+ * Apply a single rule
+ */
+ rc = rewrite_rule_apply( info, op, rule, s, &res );
+
+ /*
+ * A rule may return:
+ * OK with result != NULL if matched
+ * ERR if anything was wrong
+ * UNWILLING if the server should drop the request
+ * the latter case in honored immediately;
+ * the other two may require some special actions to take
+ * place.
+ */
+ switch ( rc ) {
+
+ case REWRITE_REGEXEC_ERR:
+ Debug( LDAP_DEBUG_ANY, "==> rewrite_context_apply"
+ " error ...\n%s%s%s", "", "", "");
+
+ /*
+ * Checks for special actions to be taken
+ * in case of error ...
+ */
+ if ( rule->lr_action != NULL ) {
+ struct rewrite_action *action;
+ int do_continue = 0;
+
+ for ( action = rule->lr_action;
+ action != NULL;
+ action = action->la_next ) {
+ switch ( action->la_type ) {
+
+ /*
+ * This action takes precedence
+ * over the others in case of failure
+ */
+ case REWRITE_ACTION_IGNORE_ERR:
+ Debug( LDAP_DEBUG_ANY,
+ "==> rewrite_context_apply"
+ " ignoring error ...\n%s%s%s",
+ "", "", "" );
+ do_continue = 1;
+ break;
+
+ /*
+ * Goto is honored only if it comes
+ * after ignore error
+ */
+ case REWRITE_ACTION_GOTO:
+ if ( do_continue ) {
+ rule = rewrite_action_goto( action, rule );
+ if ( rule == NULL ) {
+ return_code = REWRITE_REGEXEC_ERR;
+ goto rc_end_of_context;
+ }
+ }
+ break;
+
+ /*
+ * Other actions are ignored
+ */
+ default:
+ break;
+ }
+ }
+
+ if ( do_continue ) {
+ if ( rule->lr_next == NULL ) {
+ res = s;
+ }
+ goto rc_continue;
+ }
+ }
+
+ /*
+ * Default behavior is to bail out ...
+ */
+ return_code = REWRITE_REGEXEC_ERR;
+ goto rc_end_of_context;
+
+ /*
+ * OK means there were no errors or special return codes;
+ * if res is defined, it means the rule matched and we
+ * got a sucessful rewriting
+ */
+ case REWRITE_REGEXEC_OK:
+
+ /*
+ * It matched! Check for actions ...
+ */
+ if ( res != NULL ) {
+ struct rewrite_action *action;
+
+ free( s );
+ s = res;
+
+ for ( action = rule->lr_action;
+ action != NULL;
+ action = action->la_next ) {
+
+ switch ( action->la_type ) {
+
+ /*
+ * This ends the rewrite context
+ * successfully
+ */
+ case REWRITE_ACTION_STOP:
+ goto rc_end_of_context;
+
+ /*
+ * This instructs the server to return
+ * an `unwilling to perform' error
+ * message
+ */
+ case REWRITE_ACTION_UNWILLING:
+ return_code = REWRITE_REGEXEC_UNWILLING;
+ goto rc_end_of_context;
+
+ /*
+ * This causes the processing to
+ * jump n rules back and forth
+ */
+ case REWRITE_ACTION_GOTO:
+ rule = rewrite_action_goto( action, rule );
+ if ( rule == NULL ) {
+ return_code = REWRITE_REGEXEC_ERR;
+ goto rc_end_of_context;
+ }
+ break;
+
+ default:
+ /* ... */
+ break;
+ }
+ }
+
+ /*
+ * If result was OK and string didn't match,
+ * in case of last rule we need to set the
+ * result back to the string
+ */
+ } else if ( rule->lr_next == NULL ) {
+ res = s;
+ }
+
+ break;
+
+ /*
+ * A STOP has propagated ...
+ */
+ case REWRITE_REGEXEC_STOP:
+ goto rc_end_of_context;
+
+ /*
+ * This will instruct the server to return
+ * an `unwilling to perform' error message
+ */
+ case REWRITE_REGEXEC_UNWILLING:
+ return_code = REWRITE_REGEXEC_UNWILLING;
+ goto rc_end_of_context;
+
+ }
+
+rc_continue: /* sent here by actions that require to continue */
+
+ }
+
+rc_end_of_context:
+ *result = res;
+
+ Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
+ " [depth=%d] res={%d,'%s'}\n",
+ op->lo_depth, return_code, ( res ? res : "NULL" ) );
+
+ assert( op->lo_depth > 0 );
+ op->lo_depth--;
+
+ return return_code;
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#include <portable.h>
+
+#include "rewrite-int.h"
+
+/*
+ * Global data
+ */
+
+/*
+ * This becomes the running context for subsequent calls to
+ * rewrite_parse; it can be altered only by a
+ * rewriteContext config line or by a change in info.
+ */
+struct rewrite_context *__curr_context = NULL;
+
+/*
+ * Inits the info
+ */
+struct rewrite_info *
+rewrite_info_init(
+ int mode
+)
+{
+ struct rewrite_info *info;
+ struct rewrite_context *context;
+
+ switch ( mode ) {
+ case REWRITE_MODE_ERR:
+ case REWRITE_MODE_OK:
+ case REWRITE_MODE_COPY_INPUT:
+ case REWRITE_MODE_USE_DEFAULT:
+ break;
+ default:
+ mode = REWRITE_MODE_USE_DEFAULT;
+ break;
+ /* return NULL */
+ }
+
+ /*
+ * Resets the running context for parsing ...
+ */
+ __curr_context = NULL;
+
+ info = calloc( sizeof( struct rewrite_info ), 1 );
+ if ( info == NULL ) {
+ return NULL;
+ }
+
+ info->li_state = REWRITE_DEFAULT;
+ info->li_max_passes = REWRITE_MAX_PASSES;
+ info->li_rewrite_mode = mode;
+
+ /*
+ * Add the default (empty) rule
+ */
+ context = rewrite_context_create( info, REWRITE_DEFAULT_CONTEXT );
+ if ( context == NULL ) {
+ free( info );
+ return NULL;
+ }
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ if ( ldap_pvt_thread_rdwr_init( &info->li_cookies_mutex ) ) {
+ free( info );
+ return NULL;
+ }
+ if ( ldap_pvt_thread_rdwr_init( &info->li_params_mutex ) ) {
+ free( info );
+ return NULL;
+ }
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ return info;
+}
+
+/*
+ * Cleans up the info structure
+ */
+int
+rewrite_info_delete(
+ struct rewrite_info *info
+)
+{
+ assert( info != NULL );
+
+ rewrite_session_destroy( info );
+
+ rewrite_param_destroy( info );
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_destroy( &info->li_cookies_mutex );
+ ldap_pvt_thread_rdwr_destroy( &info->li_params_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ return REWRITE_SUCCESS;
+}
+
+/*
+ * Rewrites a string according to context.
+ * If the engine is off, OK is returned, but the return string will be NULL.
+ * In case of 'unwilling to perform', UNWILLING is returned, and the
+ * return string will also be null. The same in case of error.
+ * Otherwise, OK is returned, and result will hold a newly allocated string
+ * with the rewriting.
+ *
+ * What to do in case of non-existing rewrite context is still an issue.
+ * Four possibilities:
+ * - error,
+ * - ok with NULL result,
+ * - ok with copy of string as result,
+ * - use the default rewrite context.
+ */
+int
+rewrite(
+ struct rewrite_info *info,
+ const char *rewriteContext,
+ const char *string,
+ char **result
+)
+{
+ return rewrite_session( info, rewriteContext,
+ string, NULL, result );
+}
+
+int
+rewrite_session(
+ struct rewrite_info *info,
+ const char *rewriteContext,
+ const char *string,
+ const void *cookie,
+ char **result
+)
+{
+ struct rewrite_context *context;
+ struct rewrite_op op = { 0, 0, NULL, NULL, NULL, NULL };
+ int rc;
+
+ assert( info != NULL );
+ assert( rewriteContext != NULL );
+ assert( string != NULL );
+ assert( result != NULL );
+
+ /*
+ * cookie can be null; means: don't care about session stuff
+ */
+
+ *result = NULL;
+ op.lo_cookie = cookie;
+
+ /*
+ * Engine not on means no failure, but explicit no rewriting
+ */
+ if ( info->li_state != REWRITE_ON ) {
+ rc = REWRITE_REGEXEC_OK;
+ goto rc_return;
+ }
+
+ /*
+ * Undefined context means no rewriting also
+ * (conservative, are we sure it's what we want?)
+ */
+ context = rewrite_context_find( info, rewriteContext );
+ if ( context == NULL ) {
+ switch ( info->li_rewrite_mode ) {
+ case REWRITE_MODE_ERR:
+ rc = REWRITE_REGEXEC_ERR;
+ goto rc_return;
+ case REWRITE_MODE_OK:
+ rc = REWRITE_REGEXEC_OK;
+ goto rc_return;
+ case REWRITE_MODE_COPY_INPUT:
+ *result = strdup( string );
+ rc = REWRITE_REGEXEC_OK;
+ goto rc_return;
+ case REWRITE_MODE_USE_DEFAULT:
+ context = rewrite_context_find( info,
+ REWRITE_DEFAULT_CONTEXT );
+ break;
+ }
+ }
+
+ op.lo_string = strdup( string );
+ if ( op.lo_string == NULL ) {
+ rc = REWRITE_REGEXEC_ERR;
+ goto rc_return;
+ }
+
+ /*
+ * Applies rewrite context
+ */
+ rc = rewrite_context_apply(info, &op, context, string, result );
+ assert( op.lo_depth == 0 );
+
+ /* ?!? */
+ free( op.lo_string );
+
+ switch ( rc ) {
+ /*
+ * Success
+ */
+ case REWRITE_REGEXEC_OK:
+ case REWRITE_REGEXEC_STOP:
+ /*
+ * If rewrite succeeded return OK regardless of how
+ * the successful rewriting was obtained!
+ */
+ rc = REWRITE_REGEXEC_OK;
+ break;
+
+
+ /*
+ * Internal or forced error, return = NULL; rc already OK.
+ */
+ case REWRITE_REGEXEC_UNWILLING:
+ case REWRITE_REGEXEC_ERR:
+ default:
+ if ( *result != NULL ) {
+ free( *result );
+ *result = NULL;
+ }
+ }
+
+rc_return:
+ if ( op.lo_vars ) {
+ rewrite_var_delete( op.lo_vars );
+ }
+
+ return rc;
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#include <portable.h>
+
+#include "rewrite-int.h"
+#include "rewrite-map.h"
+
+/*
+ * LDAP map data structure
+ */
+struct ldap_map_data {
+ char *url;
+ LDAPURLDesc *lud;
+ int attrsonly;
+ char *binddn;
+ char *bindpw;
+
+#define MAP_LDAP_EVERYTIME 0x00
+#define MAP_LDAP_NOW 0x01
+#define MAP_LDAP_LATER 0x02
+ int when;
+
+ LDAP *ld;
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_mutex_t mutex;
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+};
+
+static void
+map_ldap_free(
+ struct ldap_map_data *data
+)
+{
+ assert( data != NULL );
+
+ if ( data->url != NULL ) {
+ free( data->url );
+ }
+
+ if ( data->lud != NULL ) {
+ ldap_free_urldesc( data->lud );
+ }
+
+ if ( data->binddn != NULL ) {
+ free( data->binddn );
+ }
+
+ if ( data->bindpw != NULL ) {
+ free( data->bindpw );
+ }
+
+ if ( data->when != MAP_LDAP_EVERYTIME && data->ld != NULL ) {
+ ldap_unbind_s( data->ld );
+ }
+
+ free( data );
+}
+
+void *
+map_ldap_parse(
+ struct rewrite_info *info,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv
+)
+{
+ struct ldap_map_data *data;
+ char *p;
+
+ assert( info != NULL );
+ assert( fname != NULL );
+ assert( argv != NULL );
+
+ data = calloc( sizeof( struct ldap_map_data ), 1 );
+ if ( data == NULL ) {
+ return NULL;
+ }
+
+ if ( argc < 1 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] ldap map needs URI\n%s",
+ fname, lineno, "" );
+ free( data );
+ return NULL;
+ }
+
+ data->url = strdup( argv[ 0 ] );
+ if ( data->url == NULL ) {
+ map_ldap_free( data );
+ return NULL;
+ }
+
+ if ( ldap_url_parse( argv[ 0 ], &data->lud ) != REWRITE_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY,
+ "[%s:%d] illegal URI '%s'\n",
+ fname, lineno, argv[ 0 ] );
+ map_ldap_free( data );
+ return NULL;
+ }
+
+ p = strchr( data->url, '/' );
+ assert( p[ 1 ] == '/' );
+ if ( ( p = strchr( p + 2, '/' ) ) != NULL ) {
+ p[ 0 ] = '\0';
+ }
+
+ if ( strcasecmp( data->lud->lud_attrs[ 0 ], "dn" ) == 0 ) {
+ data->attrsonly = 1;
+ }
+
+ for ( argc--, argv++; argc > 0; argc--, argv++ ) {
+ if ( strncasecmp( argv[ 0 ], "binddn=", 7 ) == 0 ) {
+ char *p = argv[ 0 ] + 7;
+ int l;
+
+ if ( p[ 0 ] == '\"' || p [ 0 ] == '\'' ) {
+ l = strlen( p ) - 2;
+ p++;
+ if ( p[ l ] != p[ 0 ] ) {
+ map_ldap_free( data );
+ return NULL;
+ }
+ } else {
+ l = strlen( p );
+ }
+
+ data->binddn = strdup( p );
+ if ( data->binddn == NULL ) {
+ map_ldap_free( data );
+ return NULL;
+ }
+
+ if ( data->binddn[ l ] == '\"'
+ || data->binddn[ l ] == '\'' ) {
+ data->binddn[ l ] = '\0';
+ }
+ } else if ( strncasecmp( argv[ 0 ], "bindpw=", 7 ) == 0 ) {
+ data->bindpw = strdup( argv[ 2 ] + 7 );
+ if ( data->bindpw == NULL ) {
+ map_ldap_free( data );
+ return NULL;
+ }
+ } else if ( strncasecmp( argv[ 0 ], "bindwhen=", 9 ) == 0 ) {
+ char *p = argv[ 0 ] + 9;
+
+ if ( strcasecmp( p, "now" ) == 0 ) {
+ int rc;
+
+ data->when = MAP_LDAP_NOW;
+
+ /*
+ * Init LDAP handler ...
+ */
+ rc = ldap_initialize( &data->ld, data->url );
+ if ( rc != LDAP_SUCCESS ) {
+ map_ldap_free( data );
+ return NULL;
+ }
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_mutex_init( &data->mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ } else if ( strcasecmp( p, "later" ) == 0 ) {
+ data->when = MAP_LDAP_LATER;
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_mutex_init( &data->mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ } else if ( strcasecmp( p, "everytime" ) == 0 ) {
+ data->when = MAP_LDAP_EVERYTIME;
+ } else {
+ /* ignore ... */
+ }
+ }
+ }
+
+ return ( void * )data;
+}
+
+int
+map_ldap_apply(
+ struct rewrite_builtin_map *map,
+ const char *filter,
+ struct berval *val
+
+)
+{
+ LDAP *ld;
+ LDAPMessage *res = NULL, *entry;
+ char **values;
+ int rc;
+ struct ldap_map_data *data = ( struct ldap_map_data * )map->lb_private;
+ LDAPURLDesc *lud = data->lud;
+
+ int first_try = 1;
+
+ assert( map != NULL );
+ assert( map->lb_type == REWRITE_BUILTIN_MAP_LDAP );
+ assert( map->lb_private != NULL );
+ assert( filter != NULL );
+ assert( val != NULL );
+
+ val->bv_val = NULL;
+ val->bv_len = 0;
+
+ if ( data->when == MAP_LDAP_EVERYTIME ) {
+ rc = ldap_initialize( &ld, data->url );
+ } else {
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_mutex_lock( &data->mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ rc = LDAP_SUCCESS;
+
+ if ( data->when == MAP_LDAP_LATER && data->ld == NULL ) {
+ rc = ldap_initialize( &data->ld, data->url );
+ }
+
+ ld = data->ld;
+ }
+
+ if ( rc != LDAP_SUCCESS ) {
+ rc = REWRITE_ERR;
+ goto rc_return;
+ }
+
+do_bind:
+ if ( data->binddn != NULL ) {
+ rc = ldap_simple_bind_s( ld, data->binddn, data->bindpw );
+ if ( rc == LDAP_SERVER_DOWN && first_try ) {
+ first_try = 0;
+ if ( ldap_initialize( &ld, data->url ) != LDAP_SUCCESS ) {
+ rc = REWRITE_ERR;
+ goto rc_return;
+ }
+ goto do_bind;
+ } else if ( rc != REWRITE_SUCCESS ) {
+ rc = REWRITE_ERR;
+ goto rc_return;
+ }
+ }
+
+ rc = ldap_search_s( ld, lud->lud_dn, lud->lud_scope, ( char * )filter,
+ lud->lud_attrs, data->attrsonly, &res );
+ if ( rc == LDAP_SERVER_DOWN && first_try ) {
+ first_try = 0;
+ if ( ldap_initialize( &ld, data->url ) != LDAP_SUCCESS ) {
+ rc = REWRITE_ERR;
+ goto rc_return;
+ }
+ goto do_bind;
+ } else if ( rc != REWRITE_SUCCESS ) {
+ rc = REWRITE_ERR;
+ goto rc_return;
+ }
+
+ if ( ldap_count_entries( ld, res ) != 1 ) {
+ ldap_msgfree( res );
+ rc = REWRITE_ERR;
+ goto rc_return;
+ }
+
+ entry = ldap_first_entry( ld, res );
+ assert( entry != NULL );
+
+ if ( data->attrsonly == 1 ) {
+ /*
+ * dn is newly allocated, so there's no need to strdup it
+ */
+ val->bv_val = ldap_get_dn( ld, entry );
+ } else {
+ values = ldap_get_values( ld, entry, lud->lud_attrs[ 0 ] );
+ if ( values == NULL || values[ 0 ] == NULL ) {
+ if ( values != NULL ) {
+ ldap_value_free( values );
+ }
+ ldap_msgfree( res );
+ rc = REWRITE_ERR;
+ goto rc_return;
+ }
+ val->bv_val = strdup( values[ 0 ] );
+ ldap_value_free( values );
+ }
+
+ ldap_msgfree( res );
+
+ if ( val->bv_val == NULL ) {
+ rc = REWRITE_ERR;
+ goto rc_return;
+ }
+ val->bv_len = strlen( val->bv_val );
+
+rc_return:
+ if ( data->when == MAP_LDAP_EVERYTIME ) {
+ if ( ld != NULL ) {
+ ldap_unbind_s( ld );
+ }
+ } else {
+ data->ld = ld;
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_mutex_unlock( &data->mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+ }
+
+ return rc;
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#include <portable.h>
+
+#include <pwd.h>
+
+#include "rewrite-int.h"
+#include "rewrite-map.h"
+
+/*
+ * Global data
+ */
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ldap_pvt_thread_mutex_t xpasswd_mutex;
+static int xpasswd_mutex_init = 0;
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+/*
+ * Map parsing
+ * NOTE: these are old-fashion maps; new maps will be parsed on separate
+ * config lines, and referred by name.
+ */
+struct rewrite_map *
+rewrite_xmap_parse(
+ struct rewrite_info *info,
+ const char *s,
+ const char **currpos
+)
+{
+ struct rewrite_map *map;
+
+ assert( info != NULL );
+ assert( s != NULL );
+ assert( currpos != NULL );
+
+ Debug( LDAP_DEBUG_ARGS, "rewrite_xmap_parse: %s\n%s%s",
+ s, "", "" );
+
+ *currpos = NULL;
+
+ map = calloc( sizeof( struct rewrite_map ), 1 );
+ if ( map == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "rewrite_xmap_parse:"
+ " calloc failed\n%s%s%s", "", "", "" );
+ return NULL;
+ }
+
+ /*
+ * Experimental passwd map:
+ * replaces the uid with the matching gecos from /etc/passwd file
+ */
+ if ( strncasecmp(s, "xpasswd", 7 ) == 0 ) {
+ map->lm_type = REWRITE_MAP_XPWDMAP;
+ map->lm_name = strdup( "xpasswd" );
+
+ assert( s[7] == '}' );
+ *currpos = s + 8;
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ if ( !xpasswd_mutex_init ) {
+ xpasswd_mutex_init = 1;
+ if ( ldap_pvt_thread_mutex_init( &xpasswd_mutex ) ) {
+ free( map );
+ return NULL;
+ }
+ }
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ /* Don't really care if fails */
+ return map;
+
+ /*
+ * Experimental file map:
+ * looks up key in a `key value' ascii file
+ */
+ } else if ( strncasecmp(s, "xfile", 5 ) == 0 ) {
+ char *filename;
+ const char *p;
+ int l;
+ int c = 5;
+
+ map->lm_type = REWRITE_MAP_XFILEMAP;
+
+ if ( s[ c ] != '(' ) {
+ free( map );
+ return NULL;
+ }
+
+ /* Must start with '/' for security concerns */
+ c++;
+ if ( s[ c ] != '/' ) {
+ free( map );
+ return NULL;
+ }
+
+ for ( p = s + c; p[ 0 ] != '\0' && p[ 0 ] != ')'; p++ );
+ if ( p[ 0 ] != ')' ) {
+ free( map );
+ return NULL;
+ }
+
+ l = p - s - c;
+ filename = calloc( sizeof( char ), l + 1 );
+ strncpy( filename, s + c, l );
+ filename[ l ] = '\0';
+
+ map->lm_args = ( void * )fopen( filename, "r" );
+ free( filename );
+
+ if ( map->lm_args == NULL ) {
+ free( map );
+ return NULL;
+ }
+
+ *currpos = p + 1;
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) {
+ fclose( ( FILE * )map->lm_args );
+ free( map );
+ return NULL;
+ }
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ return map;
+
+ /*
+ * Experimental ldap map:
+ * looks up key on the fly (not implemented!)
+ */
+ } else if ( strncasecmp(s, "xldap", 5 ) == 0 ) {
+ char *p;
+ char *url;
+ int l, rc;
+ int c = 5;
+ LDAPURLDesc *lud;
+
+ if ( s[ c ] != '(' ) {
+ free( map );
+ return NULL;
+ }
+ c++;
+
+ p = strchr( s, '}' );
+ if ( p == NULL ) {
+ free( map );
+ return NULL;
+ }
+ p--;
+
+ *currpos = p + 2;
+
+ /*
+ * Add two bytes for urlencoding of '%s'
+ */
+ l = p - s - c;
+ url = calloc( sizeof( char ), l + 3 );
+ strncpy( url, s + c, l );
+ url[ l ] = '\0';
+
+ /*
+ * Urlencodes the '%s' for ldap_url_parse
+ */
+ p = strchr( url, '%' );
+ if ( p != NULL ) {
+ memmove( p + 3, p + 1, strlen( p + 1 ) + 1 );
+ p[ 1 ] = '2';
+ p[ 2 ] = '5';
+ }
+
+ rc = ldap_url_parse( url, &lud );
+ free( url );
+
+ if ( rc != LDAP_SUCCESS ) {
+ free( map );
+ return NULL;
+ }
+ assert( lud != NULL );
+
+ map->lm_args = ( void * )lud;
+ map->lm_type = REWRITE_MAP_XLDAPMAP;
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) {
+ ldap_free_urldesc( lud );
+ free( map );
+ return NULL;
+ }
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ return map;
+
+ /* Unhandled map */
+ }
+
+ return NULL;
+}
+
+struct rewrite_map *
+rewrite_map_parse(
+ struct rewrite_info *info,
+ const char *string,
+ const char **currpos
+)
+{
+ struct rewrite_map *map = NULL;
+ struct rewrite_subst *subst = NULL;
+ char *s, *begin = NULL, *end;
+ const char *p;
+ int l, cnt;
+
+ assert( info != NULL );
+ assert( string != NULL );
+ assert( currpos != NULL );
+
+ *currpos = NULL;
+
+ /*
+ * Go to the end of the map invocation (the right closing brace)
+ */
+ for ( p = string, cnt = 1; p[ 0 ] != '\0' && cnt > 0; p++ ) {
+ if ( p[ 0 ] == REWRITE_SUBMATCH_ESCAPE ) {
+ /*
+ * '\' marks the beginning of a new map
+ */
+ if ( p[ 1 ] == '{' ) {
+ cnt++;
+ /*
+ * '\' followed by a digit may mark the beginning
+ * of an old map
+ */
+ } else if ( isdigit( p[ 1 ] ) && p[ 2 ] == '{' ) {
+ cnt++;
+ p++;
+ }
+ p++;
+ } else if ( p[ 0 ] == '}' ) {
+ cnt--;
+ }
+ }
+ if ( cnt != 0 ) {
+ return NULL;
+ }
+ *currpos = p;
+
+ /*
+ * Copy the map invocation
+ */
+ l = p - string - 1;
+ s = calloc( sizeof( char ), l + 1 );
+ strncpy( s, string, l );
+ s[ l ] = 0;
+
+ /*
+ * Isolate the map name (except for variable deref)
+ */
+ switch ( s[ 0 ] ) {
+ case REWRITE_OPERATOR_VARIABLE_GET:
+ case REWRITE_OPERATOR_PARAM_GET:
+ break;
+ default:
+ begin = strchr( s, '(' );
+ if ( begin == NULL ) {
+ free( s );
+ return NULL;
+ }
+ begin[ 0 ] = '\0';
+ begin++;
+ break;
+ }
+
+ /*
+ * Check for special map types
+ */
+ p = s;
+ switch ( p[ 0 ] ) {
+ case REWRITE_OPERATOR_SUBCONTEXT:
+ case REWRITE_OPERATOR_COMMAND:
+ case REWRITE_OPERATOR_VARIABLE_SET:
+ case REWRITE_OPERATOR_VARIABLE_GET:
+ case REWRITE_OPERATOR_PARAM_GET:
+ p++;
+ break;
+ }
+
+ /*
+ * Variable set and get may be repeated to indicate session-wide
+ * instead of operation-wide variables
+ */
+ switch ( p[ 0 ] ) {
+ case REWRITE_OPERATOR_VARIABLE_SET:
+ case REWRITE_OPERATOR_VARIABLE_GET:
+ p++;
+ break;
+ }
+
+ /*
+ * Variable get token can be appended to variable set to mean store
+ * AND rewrite
+ */
+ if ( p[ 0 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
+ p++;
+ }
+
+ /*
+ * Check the syntax of the variable name
+ */
+ if ( !isalpha( p[ 0 ] ) ) {
+ free( s );
+ return NULL;
+ }
+ for ( p++; p[ 0 ] != '\0'; p++ ) {
+ if ( !isalnum( p[ 0 ] ) ) {
+ free( s );
+ return NULL;
+ }
+ }
+
+ /*
+ * Isolate the argument of the map (except for variable deref)
+ */
+ switch ( s[ 0 ] ) {
+ case REWRITE_OPERATOR_VARIABLE_GET:
+ case REWRITE_OPERATOR_PARAM_GET:
+ break;
+ default:
+ end = strrchr( begin, ')' );
+ if ( end == NULL ) {
+ free( s );
+ return NULL;
+ }
+ end[ 0 ] = '\0';
+
+ /*
+ * Compile the substitution pattern of the map argument
+ */
+ subst = rewrite_subst_compile( info, begin );
+ if ( subst == NULL ) {
+ free( s );
+ return NULL;
+ }
+ break;
+ }
+
+ /*
+ * Create the map
+ */
+ map = calloc( sizeof( struct rewrite_map ), 1 );
+ if ( map == NULL ) {
+ if ( subst != NULL ) {
+ free( subst );
+ }
+ free( s );
+ return NULL;
+ }
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) {
+ if ( subst != NULL ) {
+ free( subst );
+ }
+ free( s );
+ free( map );
+ return NULL;
+ }
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ /*
+ * No subst for variable deref
+ */
+ switch ( s[ 0 ] ) {
+ case REWRITE_OPERATOR_VARIABLE_GET:
+ case REWRITE_OPERATOR_PARAM_GET:
+ break;
+ default:
+ map->lm_subst = subst;
+ break;
+ }
+
+ /*
+ * Parses special map types
+ */
+ switch ( s[ 0 ] ) {
+
+ /*
+ * Subcontext
+ */
+ case REWRITE_OPERATOR_SUBCONTEXT: /* '>' */
+
+ /*
+ * Fetch the rewrite context
+ * it MUST have been defined previously
+ */
+ map->lm_type = REWRITE_MAP_SUBCONTEXT;
+ map->lm_name = strdup( s + 1 );
+ map->lm_data = rewrite_context_find( info, s + 1 );
+ if ( map->lm_data == NULL ) {
+ free( s );
+ free( map );
+ return NULL;
+ }
+ break;
+
+ /*
+ * External command
+ */
+ case REWRITE_OPERATOR_COMMAND: /* '|' */
+ free( map );
+ map = NULL;
+ break;
+
+ /*
+ * Variable set
+ */
+ case REWRITE_OPERATOR_VARIABLE_SET: /* '&' */
+ if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_SET ) {
+ if ( s[ 2 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
+ map->lm_type = REWRITE_MAP_SETW_SESN_VAR;
+ map->lm_name = strdup( s + 3 );
+ } else {
+ map->lm_type = REWRITE_MAP_SET_SESN_VAR;
+ map->lm_name = strdup( s + 2 );
+ }
+ } else {
+ if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
+ map->lm_type = REWRITE_MAP_SETW_OP_VAR;
+ map->lm_name = strdup( s + 2 );
+ } else {
+ map->lm_type = REWRITE_MAP_SET_OP_VAR;
+ map->lm_name = strdup( s + 1 );
+ }
+ }
+ break;
+
+ /*
+ * Variable dereference
+ */
+ case REWRITE_OPERATOR_VARIABLE_GET: /* '*' */
+ if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
+ map->lm_type = REWRITE_MAP_GET_SESN_VAR;
+ map->lm_name = strdup( s + 2 );
+ } else {
+ map->lm_type = REWRITE_MAP_GET_OP_VAR;
+ map->lm_name = strdup( s + 1 );
+ }
+ break;
+
+ /*
+ * Parameter
+ */
+ case REWRITE_OPERATOR_PARAM_GET: /* '$' */
+ map->lm_type = REWRITE_MAP_GET_PARAM;
+ map->lm_name = strdup( s + 1 );
+ break;
+
+ /*
+ * Built-in map
+ */
+ default:
+ map->lm_type = REWRITE_MAP_BUILTIN;
+ map->lm_name = strdup( s );
+ map->lm_data = rewrite_builtin_map_find( info, s );
+ if ( map->lm_data == NULL ) {
+ return NULL;
+ }
+ break;
+
+ }
+
+ free( s );
+ return map;
+}
+
+/*
+ * Map key -> value resolution
+ * NOTE: these are old-fashion maps; new maps will be parsed on separate
+ * config lines, and referred by name.
+ */
+int
+rewrite_xmap_apply(
+ struct rewrite_info *info,
+ struct rewrite_op *op,
+ struct rewrite_map *map,
+ struct berval *key,
+ struct berval *val
+)
+{
+ int rc = REWRITE_SUCCESS;
+
+ assert( info != NULL );
+ assert( op != NULL );
+ assert( map != NULL );
+ assert( key != NULL );
+ assert( val != NULL );
+
+ val->bv_val = NULL;
+ val->bv_len = 0;
+
+ switch ( map->lm_type ) {
+ case REWRITE_MAP_XPWDMAP: {
+ struct passwd *pwd;
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_mutex_lock( &xpasswd_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ pwd = getpwnam( key->bv_val );
+ if ( pwd == NULL ) {
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_mutex_unlock( &xpasswd_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ rc = REWRITE_NO_SUCH_OBJECT;
+ break;
+ }
+
+ if ( pwd->pw_gecos != NULL && pwd->pw_gecos[0] != '\0' ) {
+ int l = strlen( pwd->pw_gecos );
+
+ val->bv_val = strdup( pwd->pw_gecos );
+ if ( val->bv_val == NULL ) {
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_mutex_unlock( &xpasswd_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ rc = REWRITE_ERR;
+ break;
+ }
+ val->bv_len = l;
+ } else {
+ val->bv_val = strdup( key->bv_val );
+ val->bv_len = key->bv_len;
+ }
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_mutex_unlock( &xpasswd_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ break;
+ }
+
+ case REWRITE_MAP_XFILEMAP: {
+ char buf[1024];
+
+ if ( map->lm_args == NULL ) {
+ rc = REWRITE_ERR;
+ break;
+ }
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_mutex_lock( &map->lm_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ rewind( ( FILE * )map->lm_args );
+
+ while ( fgets( buf, sizeof( buf ), ( FILE * )map->lm_args ) ) {
+ char *p;
+ int blen;
+
+ blen = strlen( buf );
+ if ( buf[ blen - 1 ] == '\n' ) {
+ buf[ blen - 1 ] = '\0';
+ }
+
+ p = strtok( buf, " " );
+ if ( p == NULL ) {
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+ rc = REWRITE_ERR;
+ goto rc_return;
+ }
+ if ( strcasecmp( p, key->bv_val ) == 0
+ && ( p = strtok( NULL, "" ) ) ) {
+ val->bv_val = strdup( p );
+ if ( val->bv_val == NULL ) {
+ return REWRITE_ERR;
+ }
+
+ val->bv_len = strlen( p );
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ goto rc_return;
+ }
+ }
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ rc = REWRITE_ERR;
+
+ break;
+ }
+
+ case REWRITE_MAP_XLDAPMAP: {
+ LDAP *ld;
+ char filter[ LDAP_FILT_MAXSIZ ];
+ LDAPMessage *res = NULL, *entry;
+ LDAPURLDesc *lud = ( LDAPURLDesc * )map->lm_args;
+ int attrsonly = 0;
+ char **values;
+
+ assert( lud != NULL );
+
+ /*
+ * No mutex because there is no write on the map data
+ */
+
+ ld = ldap_init( lud->lud_host, lud->lud_port );
+ if ( ld == NULL ) {
+ rc = REWRITE_ERR;
+ goto rc_return;
+ }
+
+ snprintf( filter, sizeof( filter ), lud->lud_filter,
+ key->bv_val );
+
+ if ( strcasecmp( lud->lud_attrs[ 0 ], "dn" ) == 0 ) {
+ attrsonly = 1;
+ }
+ rc = ldap_search_s( ld, lud->lud_dn, lud->lud_scope,
+ filter, lud->lud_attrs, attrsonly, &res );
+ if ( rc != LDAP_SUCCESS ) {
+ ldap_unbind( ld );
+ rc = REWRITE_ERR;
+ goto rc_return;
+ }
+
+ if ( ldap_count_entries( ld, res ) != 1 ) {
+ ldap_unbind( ld );
+ rc = REWRITE_ERR;
+ goto rc_return;
+ }
+
+ entry = ldap_first_entry( ld, res );
+ if ( entry == NULL ) {
+ ldap_msgfree( res );
+ ldap_unbind( ld );
+ rc = REWRITE_ERR;
+ goto rc_return;
+ }
+ if ( attrsonly == 1 ) {
+ val->bv_val = ldap_get_dn( ld, entry );
+ if ( val->bv_val == NULL ) {
+ ldap_msgfree( res );
+ ldap_unbind( ld );
+ rc = REWRITE_ERR;
+ goto rc_return;
+ }
+ } else {
+ values = ldap_get_values( ld, entry,
+ lud->lud_attrs[0] );
+ if ( values == NULL ) {
+ ldap_msgfree( res );
+ ldap_unbind( ld );
+ rc = REWRITE_ERR;
+ goto rc_return;
+ }
+ val->bv_val = strdup( values[ 0 ] );
+ ldap_value_free( values );
+ }
+ val->bv_len = strlen( val->bv_val );
+
+ ldap_msgfree( res );
+ ldap_unbind( ld );
+
+ rc = REWRITE_SUCCESS;
+ }
+ }
+
+rc_return:
+ return rc;
+}
+
+/*
+ * Applies the new map type
+ */
+int
+rewrite_map_apply(
+ struct rewrite_info *info,
+ struct rewrite_op *op,
+ struct rewrite_map *map,
+ struct berval *key,
+ struct berval *val
+)
+{
+ int rc = REWRITE_SUCCESS;
+
+ assert( info != NULL );
+ assert( op != NULL );
+ assert( map != NULL );
+ assert( key != NULL );
+ assert( val != NULL );
+
+ val->bv_val = NULL;
+ val->bv_len = 0;
+
+ switch ( map->lm_type ) {
+ case REWRITE_MAP_SUBCONTEXT:
+ rc = rewrite_context_apply( info, op,
+ ( struct rewrite_context * )map->lm_data,
+ key->bv_val, &val->bv_val );
+ if ( val->bv_val != NULL ) {
+ val->bv_len = strlen( val->bv_val );
+ }
+ break;
+
+ case REWRITE_MAP_SET_OP_VAR:
+ case REWRITE_MAP_SETW_OP_VAR:
+ rc = rewrite_var_set( &op->lo_vars, map->lm_name,
+ key->bv_val, 1 )
+ ? REWRITE_SUCCESS : REWRITE_ERR;
+ if ( map->lm_type == REWRITE_MAP_SET_OP_VAR ) {
+ val->bv_val = strdup( "" );
+ } else {
+ val->bv_val = strdup( key->bv_val );
+ val->bv_len = key->bv_len;
+ }
+ break;
+
+ case REWRITE_MAP_GET_OP_VAR: {
+ struct rewrite_var *var;
+
+ var = rewrite_var_find( op->lo_vars, map->lm_name );
+ if ( var == NULL ) {
+ rc = REWRITE_ERR;
+ } else {
+ val->bv_val = strdup( var->lv_value.bv_val );
+ val->bv_len = var->lv_value.bv_len;
+ }
+ break;
+ }
+
+ case REWRITE_MAP_SET_SESN_VAR:
+ case REWRITE_MAP_SETW_SESN_VAR:
+ if ( op->lo_cookie == NULL ) {
+ rc = REWRITE_ERR;
+ break;
+ }
+ rc = rewrite_session_var_set( info, op->lo_cookie,
+ map->lm_name, key->bv_val );
+ if ( map->lm_type == REWRITE_MAP_SET_SESN_VAR ) {
+ val->bv_val = strdup( "" );
+ } else {
+ val->bv_val = strdup( key->bv_val );
+ val->bv_len = key->bv_len;
+ }
+ break;
+
+ case REWRITE_MAP_GET_SESN_VAR:
+ rc = rewrite_session_var_get( info, op->lo_cookie,
+ map->lm_name, val );
+ break;
+
+ case REWRITE_MAP_GET_PARAM:
+ rc = rewrite_param_get( info, map->lm_name, val );
+ break;
+
+ case REWRITE_MAP_BUILTIN: {
+ struct rewrite_builtin_map *bmap = map->lm_data;
+ switch ( bmap->lb_type ) {
+ case REWRITE_BUILTIN_MAP_LDAP:
+ rc = map_ldap_apply( bmap, key->bv_val, val );
+ break;
+ default:
+ rc = REWRITE_ERR;
+ break;
+ }
+ break;
+ }
+
+ default:
+ rc = REWRITE_ERR;
+ break;
+ }
+
+ return rc;
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#include <portable.h>
+
+#include "rewrite-int.h"
+
+/*
+ * Defines and inits a variable with global scope
+ */
+int
+rewrite_param_set(
+ struct rewrite_info *info,
+ const char *name,
+ const char *value
+)
+{
+ struct rewrite_var *var;
+
+ assert( info != NULL );
+ assert( name != NULL );
+ assert( value != NULL );
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_wlock( &info->li_params_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ var = rewrite_var_find( info->li_params, name );
+ if ( var != NULL ) {
+ assert( var->lv_value.bv_val != NULL );
+ free( var->lv_value.bv_val );
+ var->lv_value.bv_val = strdup( value );
+ var->lv_value.bv_len = strlen( value );
+ } else {
+ var = rewrite_var_insert( &info->li_params, name, value );
+ if ( var == NULL ) {
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_wunlock( &info->li_params_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+ return REWRITE_ERR;
+ }
+ }
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_wunlock( &info->li_params_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ return REWRITE_SUCCESS;
+}
+
+/*
+ * Gets a var with global scope
+ */
+int
+rewrite_param_get(
+ struct rewrite_info *info,
+ const char *name,
+ struct berval *value
+)
+{
+ struct rewrite_var *var;
+
+ assert( info != NULL );
+ assert( name != NULL );
+ assert( value != NULL );
+
+ value->bv_val = NULL;
+ value->bv_len = 0;
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_rlock( &info->li_params_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ var = rewrite_var_find( info->li_params, name );
+ if ( var == NULL ) {
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_runlock( &info->li_params_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ return REWRITE_ERR;
+ } else {
+ value->bv_val = strdup( var->lv_value.bv_val );
+ value->bv_len = var->lv_value.bv_len;
+ }
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_runlock( &info->li_params_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ return REWRITE_SUCCESS;
+}
+
+/*
+ * Destroys the parameter tree
+ */
+int
+rewrite_param_destroy(
+ struct rewrite_info *info
+)
+{
+ int count;
+
+ assert( info != NULL );
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_wlock( &info->li_params_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ count = avl_free( info->li_params, NULL );
+ info->li_params = NULL;
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_wunlock( &info->li_params_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ return REWRITE_SUCCESS;
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#include <portable.h>
+
+#include "rewrite-int.h"
+
+static int
+parse_line(
+ char **argv,
+ int *argc,
+ int maxargs,
+ char *buf
+)
+{
+ char *p, *begin;
+ int in_quoted_field = 0, cnt = 0;
+ char quote = '\0';
+
+ for ( p = buf; isspace( p[ 0 ] ); p++ );
+
+ if ( p[ 0 ] == '#' ) {
+ return 0;
+ }
+
+ for ( begin = p; p[ 0 ] != '\0'; p++ ) {
+ if ( p[ 0 ] == '\\' ) {
+ p++;
+ } else if ( p[ 0 ] == '\'' || p[ 0 ] == '\"') {
+ if ( in_quoted_field && p[ 0 ] == quote ) {
+ in_quoted_field = 1 - in_quoted_field;
+ quote = '\0';
+ p[ 0 ] = '\0';
+ argv[ cnt ] = begin;
+ if ( ++cnt == maxargs ) {
+ *argc = cnt;
+ return 1;
+ }
+ for ( p++; isspace( p[ 0 ] ); p++ );
+ begin = p;
+ p--;
+
+ } else if ( !in_quoted_field ) {
+ if ( p != begin ) {
+ return -1;
+ }
+ begin++;
+ in_quoted_field = 1 - in_quoted_field;
+ quote = p[ 0 ];
+ }
+ } else if ( isspace( p[ 0 ] ) && !in_quoted_field ) {
+ p[ 0 ] = '\0';
+ argv[ cnt ] = begin;
+
+ if ( ++cnt == maxargs ) {
+ *argc = cnt;
+ return 1;
+ }
+
+ for ( p++; isspace( p[ 0 ] ); p++ );
+ begin = p;
+ p--;
+ }
+ }
+
+ *argc = cnt;
+
+ return 1;
+}
+
+int
+read_rewrite(
+ FILE *fin,
+ struct rewrite_info *info
+)
+{
+ char buf[ 1024 ];
+ char *argv[11];
+ int argc, lineno;
+
+ /*
+ * Empty rule at the beginning of the context
+ */
+
+ for ( lineno = 0; fgets( buf, sizeof( buf ), fin ); lineno++ ) {
+ switch ( parse_line( argv, &argc, sizeof( argv ) - 1, buf ) ) {
+ case -1:
+ return REWRITE_ERR;
+ case 0:
+ break;
+ case 1:
+ if ( strncasecmp( argv[ 0 ], "rewrite", 7 ) == 0 ) {
+ int rc;
+ rc = rewrite_parse( info, "file", lineno,
+ argc, argv );
+ if ( rc != REWRITE_SUCCESS ) {
+ return rc;
+ }
+ }
+ break;
+ }
+ }
+
+ return REWRITE_SUCCESS;
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#ifndef REWRITE_INT_H
+#define REWRITE_INT_H
+
+/*
+ * These are required by every file of the library, so they're included here
+ */
+#include <ac/stdlib.h>
+#include <ac/syslog.h>
+#include <ac/regex.h>
+#include <ac/socket.h>
+#include <ac/unistd.h>
+#include <ac/ctype.h>
+
+#include <lber.h>
+#include <ldap.h>
+#include "../libldap/ldap-int.h"
+
+#include <avl.h>
+
+#include <rewrite.h>
+
+/* Uncomment to use ldap pvt threads */
+#define USE_REWRITE_LDAP_PVT_THREADS
+#include <ldap_pvt_thread.h>
+
+/*
+ * For details, see RATIONALE.
+ */
+
+#define REWRITE_MAX_MATCH 11 /* 0: overall string; 1-9: submatches */
+#define REWRITE_MAX_PASSES 100
+
+/*
+ * Submatch escape char
+ */
+//#define REWRITE_SUBMATCH_ESCAPE '\\'
+#define REWRITE_SUBMATCH_ESCAPE '%'
+
+/*
+ * REGEX flags
+ */
+
+#define REWRITE_FLAG_HONORCASE 'C'
+#define REWRITE_FLAG_BASICREGEX 'R'
+
+/*
+ * Action flags
+ */
+#define REWRITE_FLAG_EXECONCE ':'
+#define REWRITE_FLAG_STOP '@'
+#define REWRITE_FLAG_UNWILLING '#'
+#define REWRITE_FLAG_GOTO 'G' /* requires an arg */
+#define REWRITE_FLAG_IGNORE_ERR 'I'
+
+/*
+ * Map operators
+ */
+#define REWRITE_OPERATOR_SUBCONTEXT '>'
+#define REWRITE_OPERATOR_COMMAND '|'
+#define REWRITE_OPERATOR_VARIABLE_SET '&'
+#define REWRITE_OPERATOR_VARIABLE_GET '*'
+#define REWRITE_OPERATOR_PARAM_GET '$'
+
+
+/***********
+ * PRIVATE *
+ ***********/
+
+/*
+ * Action
+ */
+struct rewrite_action {
+ struct rewrite_action *la_next;
+
+#define REWRITE_ACTION_STOP 0x0001
+#define REWRITE_ACTION_UNWILLING 0x0002
+#define REWRITE_ACTION_GOTO 0x0003
+#define REWRITE_ACTION_IGNORE_ERR 0x0004
+ int la_type;
+ void *la_args;
+};
+
+/*
+ * Map
+ */
+struct rewrite_map {
+
+ /*
+ * Legacy stuff
+ */
+#define REWRITE_MAP_XFILEMAP 0x0001 /* Rough implementation! */
+#define REWRITE_MAP_XPWDMAP 0x0002 /* uid -> gecos */
+#define REWRITE_MAP_XLDAPMAP 0x0003 /* Not implemented yet! */
+
+ /*
+ * Maps with args
+ */
+#define REWRITE_MAP_SUBCONTEXT 0x0101
+
+#define REWRITE_MAP_SET_OP_VAR 0x0102
+#define REWRITE_MAP_SETW_OP_VAR 0x0103
+#define REWRITE_MAP_GET_OP_VAR 0x0104
+#define REWRITE_MAP_SET_SESN_VAR 0x0105
+#define REWRITE_MAP_SETW_SESN_VAR 0x0106
+#define REWRITE_MAP_GET_SESN_VAR 0x0107
+#define REWRITE_MAP_GET_PARAM 0x0108
+#define REWRITE_MAP_BUILTIN 0x0109
+ int lm_type;
+
+ char *lm_name;
+ void *lm_data;
+
+ /*
+ * Old maps store private data in _lm_args;
+ * new maps store the substitution pattern in _lm_subst
+ */
+ union {
+ void *_lm_args;
+ struct rewrite_subst *_lm_subst;
+ } lm_union;
+#define lm_args lm_union._lm_args
+#define lm_subst lm_union._lm_subst
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_mutex_t lm_mutex;
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+};
+
+/*
+ * Builtin maps
+ */
+struct rewrite_builtin_map {
+#define REWRITE_BUILTIN_MAP_LDAP 0x0201
+ int lb_type;
+ char *lb_name;
+ void *lb_private;
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_mutex_t lb_mutex;
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+};
+
+/*
+ * Submatch substitution
+ */
+struct rewrite_submatch {
+#define REWRITE_SUBMATCH_ASIS 0x0000
+#define REWRITE_SUBMATCH_XMAP 0x0001
+#define REWRITE_SUBMATCH_MAP_W_ARG 0x0002
+ int ls_type;
+ struct rewrite_map *ls_map;
+ int ls_submatch;
+ /*
+ * The first one represents the index of the submatch in case
+ * the map has single submatch as argument;
+ * the latter represents the map argument scheme in case
+ * the map has substitution string argument form
+ */
+};
+
+/*
+ * Pattern substitution
+ */
+struct rewrite_subst {
+ size_t lt_subs_len;
+ struct berval **lt_subs;
+
+ int lt_num_submatch;
+ struct rewrite_submatch **lt_submatch;
+};
+
+/*
+ * Rule
+ */
+struct rewrite_rule {
+ struct rewrite_rule *lr_next;
+ struct rewrite_rule *lr_prev;
+
+ char *lr_pattern;
+ char *lr_subststring;
+ char *lr_flagstring;
+ regex_t lr_regex;
+
+ /*
+ * I was thinking about some kind of per-rule mutex, but there's
+ * probably no need, because rules after compilation are only read;
+ * however, I need to check whether regexec is reentrant ...
+ */
+
+ struct rewrite_subst *lr_subst;
+
+#define REWRITE_REGEX_ICASE REG_ICASE
+#define REWRITE_REGEX_EXTENDED REG_EXTENDED
+ int lr_flags;
+
+#define REWRITE_RECURSE 0x0001
+#define REWRITE_EXEC_ONCE 0x0002
+ int lr_mode;
+
+ struct rewrite_action *lr_action;
+};
+
+/*
+ * Rewrite Context (set of rules)
+ */
+struct rewrite_context {
+ char *lc_name;
+ struct rewrite_context *lc_alias;
+ struct rewrite_rule *lc_rule;
+};
+
+/*
+ * Session
+ */
+struct rewrite_session {
+ void *ls_cookie;
+ Avlnode *ls_vars;
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_t ls_vars_mutex;
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+};
+
+/*
+ * Variable
+ */
+struct rewrite_var {
+ char *lv_name;
+ struct berval lv_value;
+};
+
+/*
+ * Operation
+ */
+struct rewrite_op {
+ int lo_num_passes;
+ int lo_depth;
+ char *lo_string;
+ char *lo_result;
+ Avlnode *lo_vars;
+ const void *lo_cookie;
+};
+
+
+/**********
+ * PUBLIC *
+ **********/
+
+/*
+ * Rewrite info
+ */
+struct rewrite_info {
+ Avlnode *li_context;
+ Avlnode *li_maps;
+ /*
+ * No global mutex because maps are read only at
+ * config time
+ */
+ Avlnode *li_params;
+ Avlnode *li_cookies;
+ int li_num_cookies;
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_t li_params_mutex;
+ ldap_pvt_thread_rdwr_t li_cookies_mutex;
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ /*
+ * Default to `off';
+ * use `rewriteEngine {on|off}' directive to alter
+ */
+ int li_state;
+
+ /*
+ * Defaults to REWRITE_MAXPASSES;
+ * use `rewriteMaxPasses numPasses' directive to alter
+ */
+#define REWRITE_MAXPASSES 100
+ int li_max_passes;
+
+ /*
+ * Behavior in case a NULL or non-existent context is required
+ */
+ int li_rewrite_mode;
+};
+
+/***********
+ * PRIVATE *
+ ***********/
+
+
+/*
+ * Maps
+ */
+
+/*
+ * Parses a map (also in legacy 'x' version)
+ */
+extern struct rewrite_map *
+rewrite_map_parse(
+ struct rewrite_info *info,
+ const char *s,
+ const char **end
+);
+
+extern struct rewrite_map *
+rewrite_xmap_parse(
+ struct rewrite_info *info,
+ const char *s,
+ const char **end
+);
+
+/*
+ * Resolves key in val by means of map (also in legacy 'x' version)
+ */
+extern int
+rewrite_map_apply(
+ struct rewrite_info *info,
+ struct rewrite_op *op,
+ struct rewrite_map *map,
+ struct berval *key,
+ struct berval *val
+);
+
+extern int
+rewrite_xmap_apply(
+ struct rewrite_info *info,
+ struct rewrite_op *op,
+ struct rewrite_map *map,
+ struct berval *key,
+ struct berval *val
+);
+
+
+/*
+ * Submatch substitution
+ */
+
+/*
+ * Compiles a substitution pattern
+ */
+extern struct rewrite_subst *
+rewrite_subst_compile(
+ struct rewrite_info *info,
+ const char *result
+);
+
+/*
+ * Substitutes a portion of rewritten string according to substitution
+ * pattern using submatches
+ */
+extern int
+rewrite_subst_apply(
+ struct rewrite_info *info,
+ struct rewrite_op *op,
+ struct rewrite_subst *subst,
+ const char *string,
+ const regmatch_t *match,
+ struct berval *val
+);
+
+
+/*
+ * Rules
+ */
+
+/*
+ * Compiles the rule and appends it at the running context
+ */
+extern int
+rewrite_rule_compile(
+ struct rewrite_info *info,
+ struct rewrite_context *context,
+ const char *pattern,
+ const char *result,
+ const char *flagstring
+);
+
+/*
+ * Rewrites string according to rule; may return:
+ * REWRITE_REGEXEC_OK: fine; if *result != NULL rule matched
+ * and rewrite succeeded.
+ * REWRITE_REGEXEC_STOP: fine, rule matched; stop processing
+ * following rules
+ * REWRITE_REGEXEC_UNWILL: rule matched; force 'unwilling to perform'
+ * REWRITE_REGEXEC_ERR: an error occurred
+ */
+extern int
+rewrite_rule_apply(
+ struct rewrite_info *info,
+ struct rewrite_op *op,
+ struct rewrite_rule *rule,
+ const char *string,
+ char **result
+);
+
+/*
+ * Sessions
+ */
+
+/*
+ * Fetches a struct rewrite_session
+ */
+extern struct rewrite_session *
+rewrite_session_find(
+ struct rewrite_info *info,
+ const void *cookie
+);
+
+/*
+ * Defines and inits a variable with session scope
+ */
+extern int
+rewrite_session_var_set(
+ struct rewrite_info *info,
+ const void *cookie,
+ const char *name,
+ const char *value
+);
+
+/*
+ * Gets a var with session scope
+ */
+extern int
+rewrite_session_var_get(
+ struct rewrite_info *info,
+ const void *cookie,
+ const char *name,
+ struct berval *val
+);
+
+/*
+ * Deletes a session
+ */
+extern int
+rewrite_session_delete(
+ struct rewrite_info *info,
+ const void *cookie
+);
+
+/*
+ * Destroys the cookie tree
+ */
+extern int
+rewrite_session_destroy(
+ struct rewrite_info *info
+);
+
+
+/*
+ * Vars
+ */
+
+/*
+ * Finds a var
+ */
+extern struct rewrite_var *
+rewrite_var_find(
+ Avlnode *tree,
+ const char *name
+);
+
+/*
+ * Inserts a newly created var
+ */
+extern struct rewrite_var *
+rewrite_var_insert(
+ Avlnode **tree,
+ const char *name,
+ const char *value
+);
+
+/*
+ * Sets/inserts a var
+ */
+extern struct rewrite_var *
+rewrite_var_set(
+ Avlnode **tree,
+ const char *name,
+ const char *value,
+ int insert
+);
+
+/*
+ * Deletes a var tree
+ */
+extern int
+rewrite_var_delete(
+ Avlnode *tree
+);
+
+
+/*
+ * Contexts
+ */
+
+/*
+ * Finds the context named rewriteContext in the context tree
+ */
+extern struct rewrite_context *
+rewrite_context_find(
+ struct rewrite_info *info,
+ const char *rewriteContext
+);
+
+/*
+ * Creates a new context called rewriteContext and stores in into the tree
+ */
+extern struct rewrite_context *
+rewrite_context_create(
+ struct rewrite_info *info,
+ const char *rewriteContext
+);
+
+/*
+ * Rewrites string according to context; may return:
+ * OK: fine; if *result != NULL rule matched and rewrite succeeded.
+ * STOP: fine, rule matched; stop processing following rules
+ * UNWILL: rule matched; force 'unwilling to perform'
+ */
+extern int
+rewrite_context_apply(
+ struct rewrite_info *info,
+ struct rewrite_op *op,
+ struct rewrite_context *context,
+ const char *string,
+ char **result
+);
+
+#endif /* REWRITE_INT_H */
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#ifndef MAP_H
+#define MAP_H
+
+/*
+ * Retrieves a builtin map
+ */
+struct rewrite_builtin_map *
+rewrite_builtin_map_find(
+ struct rewrite_info *info,
+ const char *name
+);
+
+
+/*
+ * LDAP map
+ */
+void *
+map_ldap_parse(
+ struct rewrite_info *info,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv
+);
+
+int
+map_ldap_apply( struct rewrite_builtin_map *map,
+ const char *filter,
+ struct berval *val
+);
+
+#endif /* MAP_H */
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#include <portable.h>
+
+#include <ac/stdlib.h>
+#include <ac/syslog.h>
+#include <ac/regex.h>
+#include <ac/socket.h>
+#include <ac/unistd.h>
+#include <ac/ctype.h>
+
+#include <rewrite.h>
+
+int ldap_debug;
+int ldap_syslog;
+int ldap_syslog_level;
+
+extern int
+read_rewrite(
+ FILE *fin,
+ struct rewrite_info *info
+);
+
+char *
+apply(
+ FILE *fin,
+ const char *rewriteContext,
+ const char *arg
+)
+{
+ struct rewrite_info *info;
+ char *string, *sep, *result = NULL;
+ int rc;
+ void *cookie = &info;
+
+ info = rewrite_info_init(REWRITE_MODE_ERR);
+
+ if ( read_rewrite( fin, info ) != 0 ) {
+ exit( EXIT_FAILURE );
+ }
+
+ rewrite_param_set( info, "prog", "rewrite" );
+
+ rewrite_session_init( info, cookie );
+
+ string = strdup( arg );
+ for ( sep = strchr( rewriteContext, ',' );
+ rewriteContext != NULL;
+ rewriteContext = sep,
+ sep ? sep = strchr( rewriteContext, ',' ) : NULL ) {
+ if ( sep != NULL ) {
+ sep[ 0 ] = '\0';
+ sep++;
+ }
+ // rc = rewrite( info, rewriteContext, string, &result );
+ rc = rewrite_session( info, rewriteContext, string,
+ cookie, &result );
+
+ fprintf( stdout, "%s -> %s\n", string,
+ ( result ? result : "unwilling to perform" ) );
+ if ( result == NULL ) {
+ break;
+ }
+ free( string );
+ string = result;
+ }
+
+ rewrite_session_delete( info, cookie );
+
+ return result;
+}
+
+int
+main( int argc, char *argv[] )
+{
+ FILE *fin = NULL;
+ char *rewriteContext = REWRITE_DEFAULT_CONTEXT;
+
+ while ( 1 ) {
+ int opt = getopt( argc, argv, "f:hr:" );
+
+ if ( opt == EOF ) {
+ break;
+ }
+
+ switch ( opt ) {
+ case 'f':
+ fin = fopen( optarg, "r" );
+ if ( fin == NULL ) {
+ fprintf( stderr, "unable to open file '%s'\n",
+ optarg );
+ exit( EXIT_FAILURE );
+ }
+ break;
+
+ case 'h':
+ fprintf( stderr,
+ "usage: rewrite [options] string\n"
+ "\n"
+ "\t\t-f file\t\tconfiguration file\n"
+ "\t\t-r rule[s]\tlist of comma-separated rules\n"
+ "\n"
+ "\tsyntax:\n"
+ "\t\trewriteEngine\t{on|off}\n"
+ "\t\trewriteContext\tcontextName [alias aliasedContextName]\n"
+ "\t\trewriteRule\tpattern subst [flags]\n"
+ "\n"
+ );
+ exit( EXIT_SUCCESS );
+
+ case 'r':
+ rewriteContext = strdup( optarg );
+ break;
+ }
+ }
+
+ if ( optind >= argc ) {
+ return -1;
+ }
+
+ apply( ( fin ? fin : stdin ), rewriteContext, argv[ optind ] );
+
+ return 0;
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#include <portable.h>
+
+#include "rewrite-int.h"
+
+/*
+ * Appends a rule to the double linked list of rules
+ * Helper for rewrite_rule_compile
+ */
+static int
+append_rule(
+ struct rewrite_context *context,
+ struct rewrite_rule *rule
+)
+{
+ struct rewrite_rule *r;
+
+ assert( context != NULL );
+ assert( context->lc_rule != NULL );
+ assert( rule != NULL );
+
+ for ( r = context->lc_rule; r->lr_next != NULL; r = r->lr_next );
+ r->lr_next = rule;
+ rule->lr_prev = r;
+
+ return REWRITE_SUCCESS;
+}
+
+/*
+ * Appends an action to the linked list of actions
+ * Helper for rewrite_rule_compile
+ */
+static int
+append_action(
+ struct rewrite_action *base,
+ struct rewrite_action *action
+)
+{
+ struct rewrite_action *a;
+
+ assert( base != NULL );
+ assert( action != NULL );
+
+ for ( a = base; a->la_next != NULL; a = a->la_next );
+ a->la_next = action;
+
+ return REWRITE_SUCCESS;
+}
+
+/*
+ * In case of error it returns NULL and does not free all the memory
+ * it allocated; as this is a once only phase, and an error at this stage
+ * would require the server to stop, there is no need to be paranoid
+ * about memory allocation
+ */
+int
+rewrite_rule_compile(
+ struct rewrite_info *info,
+ struct rewrite_context *context,
+ const char *pattern,
+ const char *result,
+ const char *flagstring
+)
+{
+ int flags = REWRITE_REGEX_EXTENDED | REWRITE_REGEX_ICASE;
+ int mode = REWRITE_RECURSE;
+
+ struct rewrite_rule *rule = NULL;
+ struct rewrite_subst *subst = NULL;
+ struct rewrite_action *action = NULL, *first_action = NULL;
+
+ const char *p;
+
+ assert( info != NULL );
+ assert( context != NULL );
+ assert( pattern != NULL );
+ assert( result != NULL );
+
+ /*
+ * A null flagstring should be allowed
+ */
+
+ /*
+ * Take care of substitution string
+ */
+ subst = rewrite_subst_compile( info, result );
+ if ( subst == NULL ) {
+ return REWRITE_ERR;
+ }
+
+ /*
+ * Take care of flags
+ */
+ for ( p = flagstring; p[ 0 ] != '\0'; p++ ) {
+ switch( p[ 0 ] ) {
+
+ /*
+ * REGEX flags
+ */
+ case REWRITE_FLAG_HONORCASE: /* 'C' */
+ /*
+ * Honor case (default is case insensitive)
+ */
+ flags &= ~REWRITE_REGEX_ICASE;
+ break;
+
+ case REWRITE_FLAG_BASICREGEX: /* 'R' */
+ /*
+ * Use POSIX Basic Regular Expression syntax
+ * instead of POSIX Extended Regular Expression
+ * syntax (default)
+ */
+ flags &= ~REWRITE_REGEX_EXTENDED;
+ break;
+
+ /*
+ * Execution mode flags
+ */
+ case REWRITE_FLAG_EXECONCE: /* ':' */
+ /*
+ * Apply rule once only
+ */
+ mode &= ~REWRITE_RECURSE;
+ mode |= REWRITE_EXEC_ONCE;
+ break;
+
+ /*
+ * Special action flags
+ */
+ case REWRITE_FLAG_STOP: /* '@' */
+ /*
+ * Bail out after applying rule
+ */
+ action = calloc( sizeof( struct rewrite_action ), 1 );
+ if ( action == NULL ) {
+ /* cleanup ... */
+ return REWRITE_ERR;
+ }
+
+ mode &= ~REWRITE_RECURSE;
+ mode |= REWRITE_EXEC_ONCE;
+ action->la_type = REWRITE_ACTION_STOP;
+ break;
+
+ case REWRITE_FLAG_UNWILLING: /* '#' */
+ /*
+ * Matching objs will be marked as gone!
+ */
+ action = calloc( sizeof( struct rewrite_action ), 1 );
+ if ( action == NULL ) {
+ /* cleanup ... */
+ return REWRITE_ERR;
+ }
+
+ mode &= ~REWRITE_RECURSE;
+ mode |= REWRITE_EXEC_ONCE;
+ action->la_type = REWRITE_ACTION_UNWILLING;
+ break;
+
+ case REWRITE_FLAG_GOTO: { /* 'G' */
+ /*
+ * After applying rule, jump N rules
+ */
+
+ char buf[16], *q;
+ size_t l;
+ int *d;
+
+ if ( p[ 1 ] != '{' ) {
+ /* XXX Need to free stuff */
+ return REWRITE_ERR;
+ }
+
+ q = strchr( p + 2, '}' );
+ if ( q == NULL ) {
+ /* XXX Need to free stuff */
+ return REWRITE_ERR;
+ }
+
+ l = q - p + 2;
+ if ( l >= sizeof( buf ) ) {
+ /* XXX Need to free stuff */
+ return REWRITE_ERR;
+ }
+ strncpy( buf, p + 2, l );
+ buf[ l ] = '\0';
+
+ d = malloc( sizeof( int ) );
+ if ( d == NULL ) {
+ /* XXX Need to free stuff */
+ return REWRITE_ERR;
+ }
+ d[ 0 ] = atoi( buf );
+
+ action = calloc( sizeof( struct rewrite_action ), 1 );
+ if ( action == NULL ) {
+ /* cleanup ... */
+ return REWRITE_ERR;
+ }
+ action->la_type = REWRITE_ACTION_GOTO;
+ action->la_args = (void *)d;
+
+ p = q; /* p is incremented by the for ... */
+
+ break;
+ }
+
+ case REWRITE_FLAG_IGNORE_ERR: /* 'I' */
+ /*
+ * Ignore errors!
+ */
+ action = calloc( sizeof( struct rewrite_action ), 1 );
+ if ( action == NULL ) {
+ /* cleanup ... */
+ return REWRITE_ERR;
+ }
+
+ action->la_type = REWRITE_ACTION_IGNORE_ERR;
+ break;
+
+ /*
+ * Other flags ...
+ */
+ default:
+ /*
+ * Unimplemented feature (complain only)
+ */
+ break;
+ }
+
+ /*
+ * Stupid way to append to a list ...
+ */
+ if ( action != NULL ) {
+ if ( first_action == NULL ) {
+ first_action = action;
+ } else {
+ append_action( first_action, action );
+ }
+ action = NULL;
+ }
+ }
+
+ /*
+ * Finally, rule allocation
+ */
+ rule = calloc( sizeof( struct rewrite_rule ), 1 );
+ if ( rule == NULL ) {
+ // charray_free( res );
+ /*
+ * XXX need to free the value subst stuff!
+ */
+ return REWRITE_ERR;
+ }
+
+ /*
+ * REGEX compilation (luckily I don't need to take care of this ...)
+ */
+ if ( regcomp( &rule->lr_regex, ( char * )pattern, flags ) != 0 ) {
+ // charray_free( res );
+ /*
+ *XXX need to free the value subst stuff!
+ */
+ free( rule );
+ return REWRITE_ERR;
+ }
+
+ /*
+ * Just to remember them ...
+ */
+ rule->lr_pattern = strdup( pattern );
+ rule->lr_subststring = strdup( result );
+ rule->lr_flagstring = strdup( flagstring );
+
+ /*
+ * Load compiled data into rule
+ */
+ rule->lr_subst = subst;
+
+ /*
+ * Set various parameters
+ */
+ rule->lr_flags = flags; /* don't really need any longer ... */
+ rule->lr_mode = mode;
+ rule->lr_action = first_action;
+
+ /*
+ * Append rule at the end of the rewrite context
+ */
+ append_rule( context, rule );
+
+ return REWRITE_SUCCESS;
+}
+
+/*
+ * Rewrites string according to rule; may return:
+ * OK: fine; if *result != NULL rule matched and rewrite succeeded.
+ * STOP: fine, rule matched; stop processing following rules
+ * UNWILL: rule matched; force 'unwilling to perform'
+ */
+int
+rewrite_rule_apply(
+ struct rewrite_info *info,
+ struct rewrite_op *op,
+ struct rewrite_rule *rule,
+ const char *arg,
+ char **result
+ )
+{
+ size_t nmatch = REWRITE_MAX_MATCH;
+ regmatch_t match[ REWRITE_MAX_MATCH ];
+
+ int rc = REWRITE_SUCCESS;
+
+ char *string;
+ struct berval val;
+
+ assert( info != NULL );
+ assert( op != NULL );
+ assert( rule != NULL );
+ assert( arg != NULL );
+ assert( result != NULL );
+
+ *result = NULL;
+
+ string = strdup( arg );
+ if ( string == NULL ) {
+ return REWRITE_REGEXEC_ERR;
+ }
+
+ /*
+ * In case recursive match is required (default)
+ */
+recurse:;
+
+ Debug( LDAP_DEBUG_TRACE, "==> rewrite_rule_apply"
+ " rule='%s' string='%s'\n%s",
+ rule->lr_pattern, string, "" );
+
+ op->lo_num_passes++;
+ if ( regexec( &rule->lr_regex, string, nmatch, match, 0 ) != 0 ) {
+ if ( *result == NULL ) {
+ free( string );
+ }
+
+ /*
+ * No match is OK; *result = NULL means no match
+ */
+ return REWRITE_REGEXEC_OK;
+ }
+
+ rc = rewrite_subst_apply( info, op, rule->lr_subst, string,
+ match, &val );
+
+ *result = val.bv_val;
+ free( string );
+
+ if ( rc != REWRITE_REGEXEC_OK ) {
+ return rc;
+ }
+
+ if ( ( rule->lr_mode & REWRITE_RECURSE ) == REWRITE_RECURSE
+ && op->lo_num_passes <= info->li_max_passes ) {
+ string = *result;
+ goto recurse;
+ }
+
+ return REWRITE_REGEXEC_OK;
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#include <portable.h>
+
+#include "rewrite-int.h"
+
+/*
+ * Compares two cookies
+ */
+static int
+rewrite_cookie_cmp(
+ const void *c1,
+ const void *c2
+)
+{
+ struct rewrite_session *s1, *s2;
+
+ s1 = ( struct rewrite_session * )c1;
+ s2 = ( struct rewrite_session * )c2;
+
+ assert( s1 != NULL );
+ assert( s2 != NULL );
+ assert( s1->ls_cookie != NULL );
+ assert( s2->ls_cookie != NULL );
+
+ return ( ( s1->ls_cookie < s2->ls_cookie ) ? -1 :
+ ( ( s1->ls_cookie > s2->ls_cookie ) ? 1 : 0 ) );
+}
+
+/*
+ * Duplicate cookies?
+ */
+static int
+rewrite_cookie_dup(
+ void *c1,
+ void *c2
+)
+{
+ struct rewrite_session *s1, *s2;
+
+ s1 = ( struct rewrite_session * )c1;
+ s2 = ( struct rewrite_session * )c2;
+
+ assert( s1 != NULL );
+ assert( s2 != NULL );
+ assert( s1->ls_cookie != NULL );
+ assert( s2->ls_cookie != NULL );
+
+ return ( ( s1->ls_cookie == s2->ls_cookie ) ? -1 : 0 );
+}
+
+/*
+ * Inits a session
+ */
+struct rewrite_session *
+rewrite_session_init(
+ struct rewrite_info *info,
+ const void *cookie
+)
+{
+ struct rewrite_session *session;
+ int rc;
+
+ assert( info != NULL );
+ assert( cookie != NULL );
+
+ session = calloc( sizeof( struct rewrite_session ), 1 );
+ if ( session == NULL ) {
+ return NULL;
+ }
+ session->ls_cookie = ( void * )cookie;
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ if ( ldap_pvt_thread_rdwr_init( &session->ls_vars_mutex ) ) {
+ free( session );
+ return NULL;
+ }
+ ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ rc = avl_insert( &info->li_cookies, ( caddr_t )session,
+ rewrite_cookie_cmp, rewrite_cookie_dup );
+ info->li_num_cookies++;
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ if ( rc != 0 ) {
+ free( session );
+ return NULL;
+ }
+
+ return session;
+}
+
+/*
+ * Fetches a session
+ */
+struct rewrite_session *
+rewrite_session_find(
+ struct rewrite_info *info,
+ const void *cookie
+)
+{
+ struct rewrite_session *session, tmp;
+
+ assert( info != NULL );
+ assert( cookie != NULL );
+
+ tmp.ls_cookie = ( void * )cookie;
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_rlock( &info->li_cookies_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+ session = ( struct rewrite_session * )avl_find( info->li_cookies,
+ ( caddr_t )&tmp, rewrite_cookie_cmp );
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_runlock( &info->li_cookies_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ return session;
+
+}
+
+/*
+ * Defines and inits a var with session scope
+ */
+int
+rewrite_session_var_set(
+ struct rewrite_info *info,
+ const void *cookie,
+ const char *name,
+ const char *value
+)
+{
+ struct rewrite_session *session;
+ struct rewrite_var *var;
+
+ assert( info != NULL );
+ assert( cookie != NULL );
+ assert( name != NULL );
+ assert( value != NULL );
+
+ session = rewrite_session_find( info, cookie );
+ if ( session == NULL ) {
+ session = rewrite_session_init( info, cookie );
+ }
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_wlock( &session->ls_vars_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ var = rewrite_var_find( session->ls_vars, name );
+ if ( var != NULL ) {
+ assert( var->lv_value.bv_val != NULL );
+ free( var->lv_value.bv_val );
+ var->lv_value.bv_val = strdup( value );
+ var->lv_value.bv_len = strlen( value );
+ } else {
+ var = rewrite_var_insert( &session->ls_vars, name, value );
+ if ( var == NULL ) {
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+ return REWRITE_ERR;
+ }
+ }
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ return REWRITE_SUCCESS;
+}
+
+/*
+ * Gets a var with session scope
+ */
+int
+rewrite_session_var_get(
+ struct rewrite_info *info,
+ const void *cookie,
+ const char *name,
+ struct berval *value
+)
+{
+ struct rewrite_session *session;
+ struct rewrite_var *var;
+
+ assert( info != NULL );
+ assert( cookie != NULL );
+ assert( name != NULL );
+ assert( value != NULL );
+
+ value->bv_val = NULL;
+ value->bv_len = 0;
+
+ if ( cookie == NULL ) {
+ return REWRITE_ERR;
+ }
+
+ session = rewrite_session_find( info, cookie );
+ if ( session == NULL ) {
+ return REWRITE_ERR;
+ }
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_rlock( &session->ls_vars_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ var = rewrite_var_find( session->ls_vars, name );
+ if ( var == NULL ) {
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_runlock( &session->ls_vars_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ return REWRITE_ERR;
+ } else {
+ value->bv_val = strdup( var->lv_value.bv_val );
+ value->bv_len = var->lv_value.bv_len;
+ }
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_runlock( &session->ls_vars_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ return REWRITE_SUCCESS;
+}
+
+/*
+ * Deletes a session
+ */
+int
+rewrite_session_delete(
+ struct rewrite_info *info,
+ const void *cookie
+)
+{
+ struct rewrite_session *session, tmp;
+
+ assert( info != NULL );
+ assert( cookie != NULL );
+
+ tmp.ls_cookie = ( void * )cookie;
+
+ session = rewrite_session_find( info, cookie );
+
+ if ( session != NULL ) {
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_wlock( &session->ls_vars_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+ rewrite_var_delete( session->ls_vars );
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+ }
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ assert( info->li_num_cookies > 0 );
+ info->li_num_cookies--;
+
+ /*
+ * There is nothing to delete in the return value
+ */
+ avl_delete( &info->li_cookies, ( caddr_t )&tmp, rewrite_cookie_cmp );
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ return REWRITE_SUCCESS;
+}
+
+/*
+ * Destroys the cookie tree
+ */
+int
+rewrite_session_destroy(
+ struct rewrite_info *info
+)
+{
+ int count;
+
+ assert( info != NULL );
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ /*
+ * Should call per-session destruction routine ...
+ */
+
+ count = avl_free( info->li_cookies, NULL );
+ info->li_cookies = NULL;
+ assert( count == info->li_num_cookies );
+ info->li_num_cookies = 0;
+
+#ifdef USE_REWRITE_LDAP_PVT_THREADS
+ ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex );
+#endif /* USE_REWRITE_LDAP_PVT_THREADS */
+
+ return REWRITE_SUCCESS;
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#include <portable.h>
+
+#include "rewrite-int.h"
+
+/*
+ * Compiles a substitution pattern
+ */
+struct rewrite_subst *
+rewrite_subst_compile(
+ struct rewrite_info *info,
+ const char *result
+)
+{
+ size_t subs_len;
+ struct berval **subs = NULL;
+ struct rewrite_submatch **submatch = NULL;
+
+ struct rewrite_subst *s = NULL;
+
+ const char *begin, *p;
+ int nsub = 0, l;
+
+ assert( info != NULL );
+ assert( result != NULL );
+
+ /*
+ * Take care of substitution string
+ */
+ for ( p = begin = result, subs_len = 0; p[ 0 ] != '\0'; p++ ) {
+
+ /*
+ * Keep only single escapes '\'
+ */
+ if ( p[ 0 ] != REWRITE_SUBMATCH_ESCAPE ) {
+ continue;
+ } else if ( p[ 1 ] == REWRITE_SUBMATCH_ESCAPE ) {
+ continue;
+ }
+
+ nsub++;
+
+ subs = (struct berval **)realloc( subs,
+ sizeof( struct berval * )*( nsub + 1 ) );
+ if ( subs == NULL ) {
+ /* cleanup */
+ return NULL;
+ }
+ subs[ nsub ] = NULL;
+
+ /*
+ * I think an `if l > 0' at runtime is better outside than
+ * inside a function call ...
+ */
+ l = p - begin;
+ if ( l > 0 ) {
+ subs_len += l;
+ subs[ nsub - 1 ] =
+ calloc( sizeof( struct berval ), 1 );
+ if ( subs[ nsub - 1 ] == NULL ) {
+ /* cleanup */
+ return NULL;
+ }
+ subs[ nsub - 1 ]->bv_len = l;
+ subs[ nsub - 1 ]->bv_val = malloc( l + 1 );
+ if ( subs[ nsub - 1 ]->bv_val == NULL ) {
+ return NULL;
+ }
+ strncpy( subs[ nsub - 1 ]->bv_val, begin, l );
+ subs[ nsub - 1 ]->bv_val[ l ] = '\0';
+ } else {
+ subs[ nsub - 1 ] = NULL;
+ }
+
+ /*
+ * Substitution pattern
+ */
+ if ( isdigit( p[ 1 ] ) ) {
+ int d = p[ 1 ] - '0';
+
+ /*
+ * Add a new value substitution scheme
+ */
+ submatch = realloc( submatch,
+ sizeof( struct rewrite_submatch * )*( nsub + 1 ) );
+ if ( submatch == NULL ) {
+ /* cleanup */
+ return NULL;
+ }
+ submatch[ nsub ] = NULL;
+ submatch[ nsub - 1 ] =
+ calloc( sizeof( struct rewrite_submatch ), 1 );
+ if ( submatch[ nsub - 1 ] == NULL ) {
+ /* cleanup */
+ return NULL;
+ }
+ submatch[ nsub - 1 ]->ls_submatch = d;
+
+ /*
+ * If there is no argument, use default
+ * (substitute substring as is)
+ */
+ if ( p[ 2 ] != '{' ) {
+ submatch[ nsub - 1 ]->ls_type =
+ REWRITE_SUBMATCH_ASIS;
+ begin = ++p + 1;
+ } else {
+ struct rewrite_map *map;
+
+ submatch[ nsub - 1 ]->ls_type =
+ REWRITE_SUBMATCH_XMAP;
+
+ map = rewrite_xmap_parse( info,
+ p + 3, &begin );
+ if ( map == NULL ) {
+ /* cleanup */
+ return NULL;
+ }
+ p = begin - 1;
+
+ submatch[ nsub - 1 ]->ls_map = map;
+ }
+
+ /*
+ * Map with args ...
+ */
+ } else if ( p[ 1 ] == '{' ) {
+ struct rewrite_map *map;
+
+ map = rewrite_map_parse( info, p + 2, &begin );
+ if ( map == NULL ) {
+ /* cleanup */
+ return NULL;
+ }
+ p = begin - 1;
+
+ /*
+ * Add a new value substitution scheme
+ */
+ submatch = realloc( submatch,
+ sizeof( struct rewrite_submatch * )*( nsub + 1 ) );
+ if ( submatch == NULL ) {
+ /* cleanup */
+ return NULL;
+ }
+ submatch[ nsub ] = NULL;
+ submatch[ nsub - 1 ] =
+ calloc( sizeof( struct rewrite_submatch ), 1 );
+ if ( submatch[ nsub - 1 ] == NULL ) {
+ /* cleanup */
+ return NULL;
+ }
+
+ submatch[ nsub - 1 ]->ls_type =
+ REWRITE_SUBMATCH_MAP_W_ARG;
+
+ submatch[ nsub - 1 ]->ls_map = map;
+ }
+ }
+
+ /*
+ * Last part of string
+ */
+ subs = realloc( subs, sizeof( struct berval *)*( nsub + 2 ) );
+ if ( subs == NULL ) {
+ /*
+ * XXX need to free the value subst stuff!
+ */
+ free( submatch );
+ return NULL;
+ }
+
+ subs[ nsub + 1 ] = NULL;
+ l = p - begin;
+ if ( l > 0 ) {
+ subs[ nsub ] = calloc( sizeof( struct berval ), 1 );
+ subs_len += l;
+ subs[ nsub ]->bv_len = l;
+ subs[ nsub ]->bv_val = malloc( l + 1 );
+ strncpy( subs[ nsub ]->bv_val, begin, l );
+ subs[ nsub ]->bv_val[ l ] = '\0';
+ } else {
+ subs[ nsub ] = NULL;
+ }
+
+ s = calloc( sizeof( struct rewrite_subst ), 1 );
+ if ( s == NULL ) {
+ /* cleanup */
+ return NULL;
+ }
+
+ s->lt_subs_len = subs_len;
+ s->lt_subs = subs;
+ s->lt_num_submatch = nsub;
+ s->lt_submatch = submatch;
+
+ return s;
+}
+
+/*
+ * Copies the match referred to by submatch and fetched in string by match.
+ * Helper for rewrite_rule_apply.
+ */
+static int
+submatch_copy(
+ struct rewrite_submatch *submatch,
+ const char *string,
+ const regmatch_t *match,
+ struct berval *val
+)
+{
+ int c, l;
+ const char *s;
+
+ assert( submatch != NULL );
+ assert( submatch->ls_type == REWRITE_SUBMATCH_ASIS
+ || submatch->ls_type == REWRITE_SUBMATCH_XMAP );
+ assert( string != NULL );
+ assert( match != NULL );
+ assert( val != NULL );
+
+ c = submatch->ls_submatch;
+ s = string + match[ c ].rm_so;
+ l = match[ c ].rm_eo - match[ c ].rm_so;
+
+ val->bv_val = NULL;
+ val->bv_len = l;
+ val->bv_val = calloc( sizeof( char ), l + 1 );
+ if ( val->bv_val == NULL ) {
+ return REWRITE_ERR;
+ }
+
+ strncpy( val->bv_val, s, l );
+ val->bv_val[ l ] = '\0';
+
+ return REWRITE_SUCCESS;
+}
+
+/*
+ * Substitutes a portion of rewritten string according to substitution
+ * pattern using submatches
+ */
+int
+rewrite_subst_apply(
+ struct rewrite_info *info,
+ struct rewrite_op *op,
+ struct rewrite_subst *subst,
+ const char *string,
+ const regmatch_t *match,
+ struct berval *val
+)
+{
+ struct berval *submatch = NULL;
+ char *res = NULL;
+ int n, l, cl;
+ int rc = REWRITE_REGEXEC_OK;
+
+ assert( info != NULL );
+ assert( op != NULL );
+ assert( subst != NULL );
+ assert( string != NULL );
+ assert( match != NULL );
+ assert( val != NULL );
+
+ val->bv_val = NULL;
+ val->bv_len = 0;
+
+ /*
+ * Prepare room for submatch expansion
+ */
+ submatch = calloc( sizeof( struct berval ),
+ subst->lt_num_submatch );
+ if ( submatch == NULL ) {
+ return REWRITE_REGEXEC_ERR;
+ }
+
+ /*
+ * Resolve submatches (simple subst, map expansion and so).
+ */
+ for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) {
+ struct berval key;
+ int rc;
+
+ /*
+ * Get key
+ */
+ switch( subst->lt_submatch[ n ]->ls_type ) {
+ case REWRITE_SUBMATCH_ASIS:
+ case REWRITE_SUBMATCH_XMAP:
+ rc = submatch_copy( subst->lt_submatch[ n ],
+ string, match, &key );
+ if ( rc != REWRITE_SUCCESS ) {
+ free( submatch );
+ return REWRITE_REGEXEC_ERR;
+ }
+ break;
+
+ case REWRITE_SUBMATCH_MAP_W_ARG:
+ switch ( subst->lt_submatch[ n ]->ls_map->lm_type ) {
+ case REWRITE_MAP_GET_OP_VAR:
+ case REWRITE_MAP_GET_SESN_VAR:
+ case REWRITE_MAP_GET_PARAM:
+ rc = REWRITE_SUCCESS;
+ break;
+ default:
+ rc = rewrite_subst_apply( info, op,
+ subst->lt_submatch[ n ]->ls_map->lm_subst,
+ string, match, &key);
+ }
+
+ if ( rc != REWRITE_SUCCESS ) {
+ free( submatch );
+ return REWRITE_REGEXEC_ERR;
+ }
+ break;
+
+ default:
+ Debug( LDAP_DEBUG_ANY, "Not Implemented\n%s%s%s",
+ "", "", "" );
+ rc = REWRITE_ERR;
+ break;
+ }
+
+ if ( rc != REWRITE_SUCCESS ) {
+ free( submatch );
+ return REWRITE_REGEXEC_ERR;
+ }
+
+ /*
+ * Resolve key
+ */
+ switch ( subst->lt_submatch[ n ]->ls_type ) {
+ case REWRITE_SUBMATCH_ASIS:
+ submatch[ n ] = key;
+ rc = REWRITE_SUCCESS;
+ break;
+
+ case REWRITE_SUBMATCH_XMAP:
+ rc = rewrite_xmap_apply( info, op,
+ subst->lt_submatch[ n ]->ls_map,
+ &key, &submatch[ n ] );
+ break;
+
+ case REWRITE_SUBMATCH_MAP_W_ARG:
+ rc = rewrite_map_apply( info, op,
+ subst->lt_submatch[ n ]->ls_map,
+ &key, &submatch[ n ] );
+ break;
+
+ default:
+ /*
+ * When implemented, this might return the
+ * exit status of a rewrite context,
+ * which may include a stop, or an
+ * unwilling to perform
+ */
+ rc = REWRITE_ERR;
+ break;
+ }
+
+ if ( rc != REWRITE_SUCCESS ) {
+ free( submatch );
+ return REWRITE_REGEXEC_ERR;
+ }
+
+ /*
+ * Increment the length of the resulting string
+ */
+ l += submatch[ n ].bv_len;
+ }
+
+ /*
+ * Alloc result buffer as big as the constant part
+ * of the subst pattern and initialize it
+ */
+ l += subst->lt_subs_len;
+ res = calloc( sizeof( char ), l + 1 );
+ if ( res == NULL ) {
+ free( submatch );
+ return REWRITE_REGEXEC_ERR;
+ }
+
+ /*
+ * Apply submatches (possibly resolved thru maps
+ */
+ for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) {
+ if ( subst->lt_subs[ n ] != NULL ) {
+ strcpy( res + cl, subst->lt_subs[ n ]->bv_val);
+ cl += subst->lt_subs[ n ]->bv_len;
+ }
+ strcpy( res + cl, submatch[ n ].bv_val );
+ cl += submatch[ n ].bv_len;
+ free( submatch[ n ].bv_val );
+ }
+ if ( subst->lt_subs[ n ] != NULL ) {
+ strcpy( res + cl, subst->lt_subs[ n ]->bv_val );
+ }
+
+ val->bv_val = res;
+ val->bv_len = l;
+
+ return rc;
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#include <portable.h>
+
+#include "rewrite-int.h"
+
+/*
+ * Compares two vars
+ */
+static int
+rewrite_var_cmp(
+ const void *c1,
+ const void *c2
+)
+{
+ const struct rewrite_var *v1, *v2;
+
+ v1 = ( struct rewrite_var * )c1;
+ v2 = ( struct rewrite_var * )c2;
+
+ assert( v1 != NULL );
+ assert( v2 != NULL );
+ assert( v1->lv_name != NULL );
+ assert( v2->lv_name != NULL );
+
+ return strcasecmp( v1->lv_name, v2->lv_name );
+}
+
+/*
+ * Duplicate var ?
+ */
+static int
+rewrite_var_dup(
+ void *c1,
+ void *c2
+)
+{
+ struct rewrite_var *v1, *v2;
+
+ v1 = ( struct rewrite_var * )c1;
+ v2 = ( struct rewrite_var * )c2;
+
+ assert( v1 != NULL );
+ assert( v2 != NULL );
+ assert( v1->lv_name != NULL );
+ assert( v2->lv_name != NULL );
+
+ return ( strcasecmp( v1->lv_name, v2->lv_name ) == 0 ? -1 : 0 );
+}
+
+/*
+ * Finds a var
+ */
+struct rewrite_var *
+rewrite_var_find(
+ Avlnode *tree,
+ const char *name
+)
+{
+ struct rewrite_var var;
+
+ assert( name != NULL );
+
+ var.lv_name = ( char * )name;
+ return ( struct rewrite_var * )avl_find( tree,
+ ( caddr_t )&var, rewrite_var_cmp );
+}
+
+/*
+ * Inserts a newly created var
+ */
+struct rewrite_var *
+rewrite_var_insert(
+ Avlnode **tree,
+ const char *name,
+ const char *value
+)
+{
+ struct rewrite_var *var;
+ int rc;
+
+ assert( tree != NULL );
+ assert( name != NULL );
+ assert( value != NULL );
+
+ var = calloc( sizeof( struct rewrite_var ), 1 );
+ if ( var == NULL ) {
+ return NULL;
+ }
+ var->lv_name = ( char * )strdup( name );
+ if ( var->lv_name == NULL ) {
+ free( var );
+ return NULL;
+ }
+ var->lv_value.bv_val = strdup( value );
+ if ( var->lv_value.bv_val == NULL ) {
+ free( var );
+ free( var->lv_name );
+ return NULL;
+ }
+ var->lv_value.bv_len = strlen( value );
+ rc = avl_insert( tree, ( caddr_t )var,
+ rewrite_var_cmp, rewrite_var_dup );
+ if ( rc != 0 ) {
+ free( var );
+ free( var->lv_name );
+ free( var->lv_value.bv_val );
+ return NULL;
+ }
+
+ return var;
+}
+
+/*
+ * Sets/inserts a var
+ */
+struct rewrite_var *
+rewrite_var_set(
+ Avlnode **tree,
+ const char *name,
+ const char *value,
+ int insert
+)
+{
+ struct rewrite_var *var;
+
+ assert( tree != NULL );
+ assert( name != NULL );
+ assert( value != NULL );
+
+ var = rewrite_var_find( *tree, name );
+ if ( var == NULL ) {
+ if ( insert ) {
+ return rewrite_var_insert( tree, name, value );
+ } else {
+ return NULL;
+ }
+ } else {
+ assert( var->lv_value.bv_val != NULL );
+
+ free( var->lv_value.bv_val );
+ var->lv_value.bv_val = ( char * )value;
+ var->lv_value.bv_len = strlen( value );
+ }
+
+ return var;
+}
+
+/*
+ * Frees a var
+ */
+static void
+rewrite_var_free(
+ struct rewrite_var *var
+)
+{
+ assert( var != NULL );
+
+ assert( var->lv_name != NULL );
+ assert( var->lv_value.bv_val != NULL );
+
+ free( var->lv_name );
+ free( var->lv_value.bv_val );
+}
+
+/*
+ * Deletes a var tree
+ */
+int
+rewrite_var_delete(
+ Avlnode *tree
+)
+{
+ avl_free( tree, ( AVL_FREE )rewrite_var_free );
+ return REWRITE_SUCCESS;
+}
+
int i;
Attribute *a;
LDAPMod **attrs;
- char *mdn, *mapped;
+ char *mdn = NULL, *mapped;
lc = ldap_back_getconn(li, conn, op);
if ( !lc || !ldap_back_dobind( lc, op ) ) {
return( -1 );
}
- mdn = ldap_back_dn_massage( li, ch_strdup( e->e_dn ), 0 );
+ /*
+ * Rewrite the add dn, if needed
+ */
+#ifdef ENABLE_REWRITE
+ switch (rewrite_session( li->rwinfo, "addDn", e->e_dn, conn, &mdn )) {
+ case REWRITE_REGEXEC_OK:
if ( mdn == NULL ) {
+ mdn = e->e_dn;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> addDn: \"%s\" -> \"%s\"\n%s",
+ e->e_dn, mdn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform", NULL, NULL );
+
+ case REWRITE_REGEXEC_ERR:
return( -1 );
}
+#else /* !ENABLE_REWRITE */
+ mdn = ldap_back_dn_massage( li, ch_strdup( e->e_dn ), 0 );
+#endif /* !ENABLE_REWRITE */
/* Count number of attributes in entry */
for (i = 1, a = e->e_attrs; a; i++, a = a->a_next)
attrs = (LDAPMod **)ch_malloc(sizeof(LDAPMod *)*i);
for (i=0, a=e->e_attrs; a; a=a->a_next) {
+ /*
+ * lastmod should always be <off>, so that
+ * creation/modification operational attrs
+ * of the target directory are used, if available
+ */
+#if 0
+ if ( !strcasecmp( a->a_desc->ad_cname->bv_val,
+ slap_schema.si_ad_creatorsName->ad_cname->bv_val )
+ || !strcasecmp( a->a_desc->ad_cname->bv_val,
+ slap_schema.si_ad_createTimestamp->ad_cname->bv_val )
+ || !strcasecmp( a->a_desc->ad_cname->bv_val,
+ slap_schema.si_ad_modifiersName->ad_cname->bv_val )
+ || !strcasecmp( a->a_desc->ad_cname->bv_val,
+ slap_schema.si_ad_modifyTimestamp->ad_cname->bv_val )
+ ) {
+ continue;
+ }
+#endif
+
mapped = ldap_back_map(&li->at_map, a->a_desc->ad_cname->bv_val, 0);
- if (mapped != NULL) {
- attrs[i] = (LDAPMod *)ch_malloc(sizeof(LDAPMod));
- if (attrs[i] != NULL) {
- attrs[i]->mod_op = LDAP_MOD_BVALUES;
- attrs[i]->mod_type = mapped;
- attrs[i]->mod_vals.modv_bvals = a->a_vals;
- i++;
- }
+ if (mapped == NULL) {
+ continue;
+ }
+
+ attrs[i] = (LDAPMod *)ch_malloc(sizeof(LDAPMod));
+ if (attrs[i] == NULL) {
+ continue;
+ }
+
+ attrs[i]->mod_op = LDAP_MOD_BVALUES;
+ attrs[i]->mod_type = mapped;
+
+#ifdef ENABLE_REWRITE
+ /*
+ * FIXME: dn-valued attrs should be rewritten
+ * to allow their use in ACLs at the back-ldap
+ * level.
+ */
+ if ( strcmp( a->a_desc->ad_type->sat_syntax->ssyn_oid,
+ SLAPD_DN_SYNTAX ) == 0 ) {
+ ldap_dnattr_rewrite( li->rwinfo, a->a_vals, conn );
}
+#endif /* ENABLE_REWRITE */
+
+ attrs[i]->mod_vals.modv_bvals = a->a_vals;
+ i++;
}
attrs[i] = NULL;
for (--i; i>= 0; --i)
free(attrs[i]);
free(attrs);
+#ifdef ENABLE_REWRITE
+ if ( mdn != e->e_dn ) {
+#endif /* ENABLE_REWRITE */
free( mdn );
- return( ldap_back_op_result( lc, op ));
+#ifdef ENABLE_REWRITE
+ }
+#endif /* ENABLE_REWRITE */
+
+ return( ldap_back_op_result( lc, op ) );
+}
+
+#ifdef ENABLE_REWRITE
+int
+ldap_dnattr_rewrite(
+ struct rewrite_info *rwinfo,
+ struct berval **a_vals,
+ void *cookie
+)
+{
+ int j;
+ char *mattr;
+
+ for ( j = 0; a_vals[ j ] != NULL; j++ ) {
+ switch ( rewrite_session( rwinfo, "bindDn", a_vals[ j ]->bv_val,
+ cookie, &mattr )) {
+ case REWRITE_REGEXEC_OK:
+ if ( mattr == NULL ) {
+ /* no substitution */
+ continue;
+ }
+ Debug( LDAP_DEBUG_ARGS,
+ "rw> bindDn (in add of dn-valued attr):"
+ " \"%s\" -> \"%s\"\n%s",
+ a_vals[ j ]->bv_val, mattr, "" );
+
+ free( a_vals[ j ]->bv_val );
+ a_vals[ j ]->bv_val = mattr;
+ a_vals[ j ]->bv_len = strlen( mattr );
+
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+
+ case REWRITE_REGEXEC_ERR:
+ /*
+ * FIXME: better give up,
+ * skip the attribute
+ * or leave it untouched?
+ */
+ break;
+ }
+ }
+
+ return 0;
}
+#endif /* ENABLE_REWRITE */
+
#include "external.h"
+/* String rewrite library */
+#ifdef ENABLE_REWRITE
+#include "rewrite.h"
+#endif /* ENABLE_REWRITE */
+
LDAP_BEGIN_DECL
struct slap_conn;
struct ldapinfo {
char *url;
-#if 0 /* unused! */
- char *suffix;
-#endif /* 0 */
- char **suffix_massage;
char *binddn;
char *bindpw;
ldap_pvt_thread_mutex_t conn_mutex;
Avlnode *conntree;
+#ifdef ENABLE_REWRITE
+ struct rewrite_info *rwinfo;
+#else /* !ENABLE_REWRITE */
+ char **suffix_massage;
+#endif /* !ENABLE_REWRITE */
struct ldapmap oc_map;
struct ldapmap at_map;
char *ldap_back_dn_massage(struct ldapinfo *li, char *dn, int normalized);
char *ldap_back_dn_restore(struct ldapinfo *li, char *dn, int normalized);
-int conn_cmp(const void *, const void *);
-int conn_dup(void *, void *);
+extern int ldap_back_conn_cmp( const void *c1, const void *c2);
+extern int ldap_back_conn_dup( void *c1, void *c2 );
int mapping_cmp (const void *, const void *);
int mapping_dup (void *, void *);
char *ldap_back_map ( struct ldapmap *map, char *s, int remap );
-char *ldap_back_map_filter ( struct ldapinfo *li, char *f, int remap );
-char **ldap_back_map_attrs ( struct ldapinfo *li, char **a, int remap );
+char *
+ldap_back_map_filter(
+ struct ldapmap *at_map,
+ struct ldapmap *oc_map,
+ char *f,
+ int remap
+);
+char **
+ldap_back_map_attrs(
+ struct ldapmap *at_map,
+ char **a,
+ int remap
+);
+
+extern void mapping_free ( struct ldapmapping *mapping );
+
+#ifdef ENABLE_REWRITE
+extern int suffix_massage_config( struct rewrite_info *info, int argc, char **argv );
+extern int ldap_dnattr_rewrite( struct rewrite_info *rwinfo, struct berval **a_vals, void *cookie );
+#endif /* ENABLE_REWRITE */
LDAP_END_DECL
#include "slap.h"
#include "back-ldap.h"
+#define PRINT_CONNTREE 0
+
int
ldap_back_bind(
Backend *be,
return( -1 );
}
- mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 );
- if ( mdn == NULL ) {
- return -1;
+ /*
+ * Rewrite the bind dn if needed
+ */
+#ifdef ENABLE_REWRITE
+ switch ( rewrite_session( li->rwinfo, "bindDn", dn, conn, &mdn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mdn == NULL ) {
+ mdn = ( char * )dn;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> bindDn: \"%s\" -> \"%s\"\n%s",
+ dn, mdn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform", NULL, NULL );
+
+ case REWRITE_REGEXEC_ERR:
+ return( -1 );
}
+#else /* !ENABLE_REWRITE */
+ mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 );
+#endif /* !ENABLE_REWRITE */
- if (ldap_bind_s(lc->ld, mdn, cred->bv_val, method) != LDAP_SUCCESS) {
+ rc = ldap_bind_s(lc->ld, mdn, cred->bv_val, method);
+ if (rc != LDAP_SUCCESS) {
rc = ldap_back_op_result( lc, op );
} else {
lc->bound = 1;
}
-
+
+#ifdef ENABLE_REWRITE
+ if ( mdn != dn ) {
+#endif /* ENABLE_REWRITE */
free( mdn );
+#ifdef ENABLE_REWRITE
+ }
+#endif /* ENABLE_REWRITE */
return( rc );
}
/*
- * conn_cmp
+ * ldap_back_conn_cmp
*
* compares two struct ldapconn based on the value of the conn pointer;
* used by avl stuff
*/
int
-conn_cmp(
+ldap_back_conn_cmp(
const void *c1,
const void *c2
)
}
/*
- * conn_dup
+ * ldap_back_conn_dup
*
* returns -1 in case a duplicate struct ldapconn has been inserted;
* used by avl stuff
*/
int
-conn_dup(
+ldap_back_conn_dup(
void *c1,
void *c2
)
return( ( lc1->conn == lc2->conn ) ? -1 : 0 );
}
+#if PRINT_CONNTREE > 0
static void ravl_print( Avlnode *root, int depth )
{
int i;
for ( i = 0; i < depth; i++ )
printf( " " );
- printf( "c(%d) %d\n", ((struct ldapconn *) root->avl_data)->conn->c_connid, root->avl_bf );
+ printf( "c(%ld) %d\n", ((struct ldapconn *) root->avl_data)->conn->c_connid, root->avl_bf );
ravl_print( root->avl_left, depth+1 );
}
printf( "********\n" );
}
+#endif /* PRINT_CONNTREE */
struct ldapconn *
ldap_back_getconn(struct ldapinfo *li, Connection *conn, Operation *op)
lc_curr.conn = conn;
ldap_pvt_thread_mutex_lock( &li->conn_mutex );
lc = (struct ldapconn *)avl_find( li->conntree,
- (caddr_t)&lc_curr, conn_cmp );
+ (caddr_t)&lc_curr, ldap_back_conn_cmp );
ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
/* Looks like we didn't get a bind. Open a new session... */
lc = (struct ldapconn *)ch_malloc(sizeof(struct ldapconn));
lc->conn = conn;
lc->ld = ld;
+
+#ifdef ENABLE_REWRITE
+ /*
+ * Sets a cookie for the rewrite session
+ */
+ ( void )rewrite_session_init( li->rwinfo, conn );
+#endif /* ENABLE_REWRITE */
+
if ( lc->conn->c_cdn != NULL && lc->conn->c_cdn[0] != '\0' ) {
+
+ /*
+ * Rewrite the bind dn if needed
+ */
+#ifdef ENABLE_REWRITE
+ lc->bound_dn = NULL;
+ switch ( rewrite_session( li->rwinfo, "bindDn",
+ lc->conn->c_cdn, conn,
+ &lc->bound_dn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( lc->bound_dn == NULL ) {
+ lc->bound_dn =
+ ch_strdup( lc->conn->c_cdn );
+ }
+ Debug( LDAP_DEBUG_ARGS,
+ "rw> bindDn: \"%s\" ->"
+ " \"%s\"\n%s",
+ lc->conn->c_cdn,
+ lc->bound_dn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op,
+ LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform",
+ NULL, NULL );
+
+ case REWRITE_REGEXEC_ERR:
+ return( NULL );
+ }
+#else /* !ENABLE_REWRITE */
lc->bound_dn = ldap_back_dn_massage( li,
- ch_strdup( lc->conn->c_cdn ), 0 );
+ ch_strdup( lc->conn->c_cdn ), 0 );
+#endif /* !ENABLE_REWRITE */
} else {
lc->bound_dn = NULL;
}
/* Inserts the newly created ldapconn in the avl tree */
ldap_pvt_thread_mutex_lock( &li->conn_mutex );
err = avl_insert( &li->conntree, (caddr_t)lc,
- conn_cmp, conn_dup );
+ ldap_back_conn_cmp, ldap_back_conn_dup );
-#if 0
+#if PRINT_CONNTREE > 0
myprint( li->conntree );
-#endif
+#endif /* PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
Debug( LDAP_DEBUG_TRACE,
- "=>ldap_back_getconn: conn %d inserted\n",
- lc->conn->c_connid, 0, 0 );
+ "=>ldap_back_getconn: conn %ld inserted%s%s\n",
+ lc->conn->c_connid, "", "" );
/* Err could be -1 in case a duplicate ldapconn is inserted */
if ( err != 0 ) {
}
} else {
Debug( LDAP_DEBUG_TRACE,
- "=>ldap_back_getconn: conn %d fetched\n",
- lc->conn->c_connid, 0, 0 );
+ "=>ldap_back_getconn: conn %ld fetched%s%s\n",
+ lc->conn->c_connid, "", "" );
}
return( lc );
ldap_get_option(lc->ld, LDAP_OPT_ERROR_STRING, &msg);
ldap_get_option(lc->ld, LDAP_OPT_MATCHED_DN, &match);
err = ldap_back_map_result(err);
+
+#ifdef ENABLE_REWRITE
+
+ /*
+ * need rewrite info; mmmh ...
+ */
+
+#else /* !ENABLE_REWRITE */
+
send_ldap_result( lc->conn, op, err, match, msg, NULL, NULL );
/* better test the pointers before freeing? */
- if ( match ) free( match );
+ if ( match ) {
+ free( match );
+ }
+#endif /* !ENABLE_REWRITE */
+
if ( msg ) free( msg );
return( (err==LDAP_SUCCESS) ? 0 : -1 );
}
+
return( -1 );
}
+ /*
+ * Rewrite the compare dn, if needed
+ */
+#ifdef ENABLE_REWRITE
+ switch ( rewrite_session( li->rwinfo, "compareDn", dn, conn, &mdn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mdn == NULL ) {
+ mdn = ( char * )dn;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> compareDn: \"%s\" -> \"%s\"\n%s",
+ dn, mdn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform", NULL, NULL );
+
+ case REWRITE_REGEXEC_ERR:
+ return( -1 );
+ }
+#else /* !ENABLE_REWRITE */
mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 );
- if ( mdn == NULL ) {
- return -1;
- }
+ if ( mdn == NULL ) {
+ return -1;
+ }
+#endif /* !ENABLE_REWRITE */
mapped_oc = ldap_back_map(&li->oc_map, ava->aa_desc->ad_cname->bv_val, 0);
if (mapped_oc == NULL)
ldap_compare_s( lc->ld, mdn, mapped_oc, mapped_at );
- free( mdn );
+#ifdef ENABLE_REWRITE
+ if ( mdn != dn ) {
+#endif /* ENABLE_REWRITE */
+ free( mdn );
+#ifdef ENABLE_REWRITE
+ }
+#endif /* ENABLE_REWRITE */
return( ldap_back_op_result( lc, op ) );
}
/* dn massaging */
} else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
+#ifndef ENABLE_REWRITE
char *dn, *massaged_dn;
+#endif /* ENABLE_REWRITE */
BackendDB *tmp_be;
+ /*
+ * syntax:
+ *
+ * suffixmassage <suffix> <massaged suffix>
+ *
+ * the <suffix> field must be defined as a valid suffix
+ * (or suffixAlias?) for the current database;
+ * the <massaged suffix> shouldn't have already been
+ * defined as a valid suffix or suffixAlias for the
+ * current server
+ */
if ( argc != 3 ) {
- fprintf( stderr,
- "%s: line %d: syntax is \"suffixMassage <suffix> <massaged suffix>\"\n",
+ fprintf( stderr, "%s: line %d: syntax is"
+ " \"suffixMassage <suffix>"
+ " <massaged suffix>\"\n",
fname, lineno );
return( 1 );
}
tmp_be = select_backend( argv[1], 0 );
if ( tmp_be != NULL && tmp_be != be ) {
- fprintf( stderr,
- "%s: line %d: suffix already in use by another backend in"
- " \"suffixMassage <suffix> <massaged suffix>\"\n",
+ fprintf( stderr, "%s: line %d: suffix already in use"
+ " by another backend in"
+ " \"suffixMassage <suffix>"
+ " <massaged suffix>\"\n",
fname, lineno );
return( 1 );
}
tmp_be = select_backend( argv[2], 0 );
if ( tmp_be != NULL ) {
- fprintf( stderr,
- "%s: line %d: massaged suffix already in use by another backend in"
- " \"suffixMassage <suffix> <massaged suffix>\"\n",
+ fprintf( stderr, "%s: line %d: massaged suffix"
+ " already in use by another backend in"
+ " \"suffixMassage <suffix>"
+ " <massaged suffix>\"\n",
fname, lineno );
return( 1 );
}
-
+
+#ifdef ENABLE_REWRITE
+ /*
+ * The suffix massaging is emulated by means of the
+ * rewrite capabilities
+ * FIXME: no extra rewrite capabilities should be added
+ * to the database
+ */
+ return suffix_massage_config( li->rwinfo, argc, argv );
+#else /* !ENABLE_REWRITE */
dn = ch_strdup( argv[1] );
charray_add( &li->suffix_massage, dn );
(void) dn_normalize( dn );
free( dn );
free( massaged_dn );
+#endif /* !ENABLE_REWRITE */
+#ifdef ENABLE_REWRITE
+ /* rewrite stuff ... */
+ } else if ( strncasecmp( argv[0], "rewrite", 7 ) == 0 ) {
+ return rewrite_parse( li->rwinfo, fname, lineno, argc, argv );
+#endif /* ENABLE_REWRITE */
+
/* objectclass/attribute mapping */
} else if ( strcasecmp( argv[0], "map" ) == 0 ) {
struct ldapmap *map;
}
char *
-ldap_back_map_filter ( struct ldapinfo *li, char *f, int remap )
+ldap_back_map_filter(
+ struct ldapmap *at_map,
+ struct ldapmap *oc_map,
+ char *f,
+ int remap
+)
{
char *nf, *m, *p, *q, *s, c;
int len, extra, plen, in_quote;
s = nf;
q = NULL;
in_quote = 0;
- for (p = f; c = *p; p++) {
+ for (p = f; (c = *p); p++) {
if (c == '"') {
in_quote = !in_quote;
if (q != NULL) {
} else {
if (q != NULL) {
*p = 0;
- m = ldap_back_map(&li->at_map, q, remap);
+ m = ldap_back_map(at_map, q, remap);
if (m == NULL)
- m = ldap_back_map(&li->oc_map, q, remap);
+ m = ldap_back_map(oc_map, q, remap);
if (m == NULL) {
m = q;
}
}
char **
-ldap_back_map_attrs ( struct ldapinfo *li, char **a, int remap )
+ldap_back_map_attrs(
+ struct ldapmap *at_map,
+ char **a,
+ int remap
+)
{
int i, j, count;
char **na, *mapped;
return(NULL);
for (i = 0, j = 0; i < count; i++) {
- mapped = ldap_back_map(&li->at_map, a[i], remap);
+ mapped = ldap_back_map(at_map, a[i], remap);
if (mapped != NULL) {
mapped = ch_strdup(mapped);
if (mapped == NULL) {
return(na);
}
+#ifdef ENABLE_REWRITE
+static char *
+suffix_massage_regexize( const char *s )
+{
+ char *res, *p, *r;
+ int i;
+
+ for ( i = 0, p = ( char * )s;
+ ( r = strchr( p, ',' ) ) != NULL;
+ p = r + 1, i++ )
+ ;
+
+ res = ch_calloc( sizeof( char ), strlen( s ) + 4 + 4*i + 1 );
+
+ strcpy( res, "(.*)" );
+ for ( i = 0, p = ( char * )s;
+ ( r = strchr( p, ',' ) ) != NULL;
+ p = r + 1 , i++ ) {
+ strncat( res, p, r - p + 1 );
+ strcat( res, "[ ]?" );
+
+ if ( r[ 1 ] == ' ' ) {
+ r++;
+ }
+ }
+ strcat( res, p );
+
+ return res;
+}
+
+static char *
+suffix_massage_patternize( const char *s, int normalize )
+{
+ char *res;
+
+ res = ch_calloc( sizeof( char ), strlen( s ) + 3 );
+
+ sprintf( res, "%%1%s", s );
+
+ if ( normalize ) {
+ char *out = dn_normalize( res + 2 );
+ if ( out != res + 2 ) {
+ strcpy( res + 2, out );
+ free( out );
+ }
+ }
+
+ return res;
+}
+
+int
+suffix_massage_config(
+ struct rewrite_info *info,
+ int argc,
+ char **argv
+)
+{
+ char *rargv[ 5 ];
+
+ rargv[ 0 ] = "rewriteEngine";
+ rargv[ 1 ] = "on";
+ rargv[ 2 ] = NULL;
+ rewrite_parse( info, "<suffix massage>", 1, 2, rargv );
+
+ rargv[ 0 ] = "rewriteContext";
+ rargv[ 1 ] = "default";
+ rargv[ 2 ] = NULL;
+ rewrite_parse( info, "<suffix massage>", 2, 2, rargv );
+
+ rargv[ 0 ] = "rewriteRule";
+ rargv[ 1 ] = suffix_massage_regexize( argv[ 1 ] );
+ rargv[ 2 ] = suffix_massage_patternize( argv[ 2 ], 0 );
+ rargv[ 3 ] = ":";
+ rargv[ 4 ] = NULL;
+ rewrite_parse( info, "<suffix massage>", 3, 4, rargv );
+ ch_free( rargv[ 1 ] );
+ ch_free( rargv[ 2 ] );
+
+ rargv[ 0 ] = "rewriteContext";
+ rargv[ 1 ] = "searchResult";
+ rargv[ 2 ] = NULL;
+ rewrite_parse( info, "<suffix massage>", 4, 2, rargv );
+
+ rargv[ 0 ] = "rewriteRule";
+ rargv[ 1 ] = suffix_massage_regexize( argv[ 2 ] );
+ rargv[ 2 ] = suffix_massage_patternize( argv[ 1 ], 0 );
+ rargv[ 3 ] = ":";
+ rargv[ 4 ] = NULL;
+ rewrite_parse( info, "<suffix massage>", 5, 4, rargv );
+ ch_free( rargv[ 1 ] );
+ ch_free( rargv[ 2 ] );
+
+ /*
+ * the filter should be rewritten as
+ *
+ * rewriteRule
+ * "(.*)member=([^)]+),o=Foo Bar,[ ]?c=US(.*)"
+ * "%1member=%2,dc=example,dc=com%3"
+ *
+ * where "o=Foo Bar, c=US" is the virtual naming context,
+ * and "dc=example, dc=com" is the real naming context
+ */
+ rargv[ 0 ] = "rewriteContext";
+ rargv[ 1 ] = "searchFilter";
+ rargv[ 2 ] = NULL;
+ rewrite_parse( info, "<suffix massage>", 6, 2, rargv );
+
+#if 0 /* matched is not normalized */
+ rargv[ 0 ] = "rewriteContext";
+ rargv[ 1 ] = "matchedDn";
+ rargv[ 2 ] = "alias";
+ rargv[ 3 ] = "searchResult";
+ rargv[ 4 ] = NULL;
+ rewrite_parse( info, "<suffix massage>", 7, 4, rargv );
+#else /* normalize matched */
+ rargv[ 0 ] = "rewriteContext";
+ rargv[ 1 ] = "matchedDn";
+ rargv[ 2 ] = NULL;
+ rewrite_parse( info, "<suffix massage>", 7, 2, rargv );
+
+ rargv[ 0 ] = "rewriteRule";
+ rargv[ 1 ] = suffix_massage_regexize( argv[ 2 ] );
+ rargv[ 2 ] = suffix_massage_patternize( argv[ 1 ], 1 );
+ rargv[ 3 ] = ":";
+ rargv[ 4 ] = NULL;
+ rewrite_parse( info, "<suffix massage>", 8, 4, rargv );
+ ch_free( rargv[ 1 ] );
+ ch_free( rargv[ 2 ] );
+#endif /* normalize matched */
+
+ return 0;
+}
+#endif /* ENABLE_REWRITE */
+
struct ldapinfo *li = (struct ldapinfo *) be->be_private;
struct ldapconn *lc;
- char *mdn;
+ char *mdn = NULL;
lc = ldap_back_getconn( li, conn, op );
return( -1 );
}
- mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 );
+ /*
+ * Rewrite the compare dn, if needed
+ */
+#ifdef ENABLE_REWRITE
+ switch ( rewrite_session( li->rwinfo, "deleteDn", dn, conn, &mdn ) ) {
+ case REWRITE_REGEXEC_OK:
if ( mdn == NULL ) {
+ mdn = ( char * )dn;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> deleteDn: \"%s\" -> \"%s\"\n%s",
+ dn, mdn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform", NULL, NULL );
+
+ case REWRITE_REGEXEC_ERR:
return( -1 );
}
+#else /* !ENABLE_REWRITE */
+ mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 );
+#endif /* !ENABLE_REWRITE */
ldap_delete_s( lc->ld, mdn );
- free( mdn );
+#ifdef ENABLE_REWRITE
+ if ( mdn != dn ) {
+#endif /* ENABLE_REWRITE */
+ free( mdn );
+#ifdef ENABLE_REWRITE
+ }
+#endif /* ENABLE_REWRITE */
return( ldap_back_op_result( lc, op ) );
}
#include "back-ldap.h"
-/* return 0 IFF op_dn is a value in member attribute
+/* return 0 IFF op_dn is a value in group_at (member) attribute
* of entry with gr_dn AND that entry has an objectClass
- * value of groupOfNames
+ * value of group_oc (groupOfNames)
*/
int
ldap_back_group(
struct ldapinfo *li = (struct ldapinfo *) be->be_private;
int rc = 1;
Attribute *attr;
- Entry *e;
struct berval bv;
+
LDAPMessage *result;
char *gattr[2];
char *filter;
LDAP *ld;
+ char *mop_ndn, *mgr_ndn;
AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass;
char *group_oc_name = NULL;
if (target != NULL && strcmp(target->e_ndn, gr_ndn) == 0) {
/* we already have a copy of the entry */
/* attribute and objectclass mapping has already been done */
- e = target;
- if( is_entry_objectclass( e, group_oc ) ) {
- return(1);
+ /*
+ * first we need to check if the objectClass attribute
+ * has been retieved; otherwise we need to repeat the search
+ */
+ attr = attr_find( target->e_attrs, ad_objectClass );
+ if ( attr != NULL ) {
+
+ /*
+ * Now we can check for the group objectClass value
+ */
+ if( !is_entry_objectclass( target, group_oc ) ) {
+ return(1);
+ }
+
+ /*
+ * This part has been reworked: the group attr compare
+ * fails only if the attribute is PRESENT but the value
+ * is NOT PRESENT; if the attribute is NOT PRESENT, the
+ * search must be repeated as well.
+ * This may happen if a search for an entry has already
+ * been performed (target is not null) but the group
+ * attribute has not been required
+ */
+ if ((attr = attr_find(target->e_attrs, group_at)) != NULL) {
+ bv.bv_val = (char *) op_ndn;
+ bv.bv_len = strlen( op_ndn );
+ if( value_find( group_at, attr->a_vals, &bv ) != LDAP_SUCCESS )
+ return(1);
+ return(0);
+ } /* else: repeat the search */
+ } /* else: repeat the search */
+ } /* else: do the search */
+
+ /*
+ * Rewrite the op ndn if needed
+ */
+#ifdef ENABLE_REWRITE
+ switch ( rewrite_session( li->rwinfo, "bindDn",
+ op_ndn, conn, &mop_ndn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mop_ndn == NULL ) {
+ mop_ndn = ( char * )op_ndn;
}
+ Debug( LDAP_DEBUG_ARGS,
+ "rw> bindDn (op ndn in group): \"%s\" -> \"%s\"\n%s",
+ op_ndn, mop_ndn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+
+ case REWRITE_REGEXEC_ERR:
+ goto cleanup;
+ }
- if ((attr = attr_find(e->e_attrs, group_at)) == NULL)
- return(1);
+ /*
+ * Rewrite the gr ndn if needed
+ */
+ switch ( rewrite_session( li->rwinfo, "searchBase",
+ gr_ndn, conn, &mgr_ndn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mgr_ndn == NULL ) {
+ mgr_ndn = ( char * )gr_ndn;
+ }
+ Debug( LDAP_DEBUG_ARGS,
+ "rw> searchBase (gr ndn in group):"
+ " \"%s\" -> \"%s\"\n%s",
+ gr_ndn, mgr_ndn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+
+ case REWRITE_REGEXEC_ERR:
+ goto cleanup;
+ }
+#else /* !ENABLE_REWRITE */
+ mop_ndn = ldap_back_dn_massage( li, ch_strdup( op_ndn ), 1 );
+ if ( mop_ndn == NULL ) {
+ goto cleanup;
+ }
+ mgr_ndn = ldap_back_dn_massage( li, ch_strdup( gr_ndn ), 1 );
+ if ( mgr_ndn == NULL ) {
+ goto cleanup;
+ }
+#endif /* !ENABLE_REWRITE */
+
+ group_oc_name = ldap_back_map(&li->oc_map, group_oc_name, 0);
+ if (group_oc_name == NULL)
+ goto cleanup;
+ group_at_name = ldap_back_map(&li->at_map, group_at_name, 0);
+ if (group_at_name == NULL)
+ goto cleanup;
+
+ filter = ch_malloc(sizeof("(&(objectclass=)(=))")
+ + strlen(group_oc_name)
+ + strlen(group_at_name)
+ + strlen(mop_ndn) + 1);
+ if (filter == NULL)
+ goto cleanup;
+
+ if (ldap_initialize(&ld, li->url) != LDAP_SUCCESS) {
+ goto cleanup;
+ }
- bv.bv_val = (char *) op_ndn;
- bv.bv_len = strlen( op_ndn );
- if( value_find( group_at, attr->a_vals, &bv ) == 0 )
- return(1);
+ if (ldap_bind_s(ld, li->binddn, li->bindpw, LDAP_AUTH_SIMPLE)
+ != LDAP_SUCCESS) {
+ goto cleanup;
+ }
- } else {
- group_oc_name = ldap_back_map(&li->oc_map, group_oc_name, 0);
- if (group_oc_name == NULL)
- return(1);
- group_at_name = ldap_back_map(&li->at_map, group_at_name, 0);
- if (group_at_name == NULL)
- return(1);
-
- filter = ch_malloc(sizeof("(&(objectclass=)(=))")
- + strlen(group_oc_name)
- + strlen(group_at_name)
- + strlen(op_ndn) + 1);
- if (filter == NULL)
- return(1);
-
- if (ldap_initialize(&ld, li->url) != LDAP_SUCCESS) {
- ch_free(filter);
- return(1);
- }
+ strcpy(filter, "(&(objectclass=");
+ strcat(filter, group_oc_name);
+ strcat(filter, ")(");
+ strcat(filter, group_at_name);
+ strcat(filter, "=");
+ strcat(filter, mop_ndn);
+ strcat(filter, "))");
+
+ gattr[0] = "objectclass";
+ gattr[1] = NULL;
+ if (ldap_search_ext_s(ld, mgr_ndn, LDAP_SCOPE_BASE, filter,
+ gattr, 0, NULL, NULL, LDAP_NO_LIMIT,
+ LDAP_NO_LIMIT, &result) == LDAP_SUCCESS) {
+ if (ldap_first_entry(ld, result) != NULL)
+ rc = 0;
+ ldap_msgfree(result);
+ }
- if (ldap_bind_s(ld, li->binddn, li->bindpw, LDAP_AUTH_SIMPLE) == LDAP_SUCCESS) {
- strcpy(filter, "(&(objectclass=");
- strcat(filter, group_oc_name);
- strcat(filter, ")(");
- strcat(filter, group_at_name);
- strcat(filter, "=");
- strcat(filter, op_ndn);
- strcat(filter, "))");
-
- gattr[0] = "objectclass";
- gattr[1] = NULL;
- if (ldap_search_ext_s(ld, gr_ndn, LDAP_SCOPE_BASE, filter,
- gattr, 0, NULL, NULL, LDAP_NO_LIMIT,
- LDAP_NO_LIMIT, &result) == LDAP_SUCCESS)
- {
- if (ldap_first_entry(ld, result) != NULL)
- rc = 0;
- ldap_msgfree(result);
- }
- }
+cleanup:
+ if ( ld != NULL ) {
ldap_unbind(ld);
- ch_free(filter);
- return(rc);
- }
-
- return(0);
+ }
+ ch_free(filter);
+#ifdef ENABLE_REWRITE
+ if ( mop_ndn != op_ndn ) {
+#endif /* ENABLE_REWRITE */
+ free( mop_ndn );
+#ifdef ENABLE_REWRITE
+ }
+ if ( mgr_ndn != gr_ndn ) {
+#endif /* ENABLE_REWRITE */
+ free( mgr_ndn );
+#ifdef ENABLE_REWRITE
+ }
+#endif /* ENABLE_REWRITE */
+ return(rc);
}
struct ldapmapping *mapping;
li = (struct ldapinfo *) ch_calloc( 1, sizeof(struct ldapinfo) );
+ if ( li == NULL ) {
+ return -1;
+ }
+
+#ifdef ENABLE_REWRITE
+ li->rwinfo = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
+ if ( li->rwinfo == NULL ) {
+ ch_free( li );
+ return -1;
+ }
+#endif /* ENABLE_REWRITE */
+
ldap_pvt_thread_mutex_init( &li->conn_mutex );
mapping = (struct ldapmapping *)ch_calloc( 2, sizeof(struct ldapmapping) );
be->be_private = li;
- return li == NULL;
+ return 0;
}
static void
free( lc );
}
-static void
+void
mapping_free ( struct ldapmapping *mapping )
{
ch_free( mapping->src );
free(li->bindpw);
li->bindpw = NULL;
}
- if (li->suffix_massage) {
- ldap_value_free( li->suffix_massage );
- li->suffix_massage = NULL;
- }
if (li->conntree) {
avl_free( li->conntree, (AVL_FREE) conn_free );
}
+#ifdef ENABLE_REWRITE
+ if (li->rwinfo) {
+ rewrite_info_delete( li->rwinfo );
+ }
+#else /* !ENABLE_REWRITE */
+ if (li->suffix_massage) {
+ ldap_value_free( li->suffix_massage );
+ }
+#endif /* !ENABLE_REWRITE */
avl_free( li->oc_map.remap, NULL );
avl_free( li->oc_map.map, (AVL_FREE) mapping_free );
LDAPMod *mods;
Modifications *ml;
int i;
- char *mdn, *mapped;
+ char *mdn = NULL, *mapped;
lc = ldap_back_getconn(li, conn, op);
if ( !lc || !ldap_back_dobind( lc, op ) ) {
return( -1 );
}
- mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 );
- if ( mdn == NULL ) {
+ /*
+ * Rewrite the modify dn, if needed
+ */
+#ifdef ENABLE_REWRITE
+ switch ( rewrite_session( li->rwinfo, "modifyDn", dn, conn, &mdn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mdn == NULL ) {
+ mdn = ( char * )dn;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> modifyDN: \"%s\" -> \"%s\"\n%s",
+ dn, mdn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform", NULL, NULL );
+
+ case REWRITE_REGEXEC_ERR:
return( -1 );
}
+#else /* !ENABLE_REWRITE */
+ mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 );
+#endif /* !ENABLE_REWRITE */
for (i=0, ml=modlist; ml; i++,ml=ml->sml_next)
;
mods = (LDAPMod *)ch_malloc(i*sizeof(LDAPMod));
- if (mods == NULL)
- return( -1 );
+ if (mods == NULL) {
+ goto cleanup;
+ }
modv = (LDAPMod **)ch_malloc((i+1)*sizeof(LDAPMod *));
if (modv == NULL) {
- free(mods);
- return( -1 );
+ goto cleanup;
}
for (i=0, ml=modlist; ml; ml=ml->sml_next) {
mapped = ldap_back_map(&li->at_map, ml->sml_desc->ad_cname->bv_val, 0);
- if (mapped != NULL) {
- modv[i] = &mods[i];
- mods[i].mod_op = ml->sml_op | LDAP_MOD_BVALUES;
- mods[i].mod_type = mapped;
- mods[i].mod_bvalues = ml->sml_bvalues;
- i++;
+ if (mapped == NULL) {
+ continue;
}
+
+ modv[i] = &mods[i];
+ mods[i].mod_op = ml->sml_op | LDAP_MOD_BVALUES;
+ mods[i].mod_type = mapped;
+
+#ifdef ENABLE_REWRITE
+ /*
+ * FIXME: dn-valued attrs should be rewritten
+ * to allow their use in ACLs at the back-ldap
+ * level.
+ */
+ if ( strcmp( ml->sml_desc->ad_type->sat_syntax->ssyn_oid,
+ SLAPD_DN_SYNTAX ) == 0 ) {
+ ldap_dnattr_rewrite( li->rwinfo,
+ ml->sml_bvalues, conn );
+ }
+#endif /* ENABLE_REWRITE */
+
+ mods[i].mod_bvalues = ml->sml_bvalues;
+ i++;
}
modv[i] = 0;
ldap_modify_s( lc->ld, mdn, modv );
- free( mdn );
+
+cleanup:
+#ifdef ENABLE_REWRITE
+ if ( mdn != dn ) {
+#endif /* ENABLE_REWRITE */
+ free( mdn );
+#ifdef ENABLE_REWRITE
+ }
+#endif /* ENABLE_REWRITE */
free(mods);
free(modv);
return( ldap_back_op_result( lc, op ));
}
+
struct ldapinfo *li = (struct ldapinfo *) be->be_private;
struct ldapconn *lc;
- char *mdn, *mnewSuperior;
+ char *mdn = NULL, *mnewSuperior = NULL;
lc = ldap_back_getconn( li, conn, op );
- if ( !lc ) {
+ if ( !lc || !ldap_back_dobind(lc, op) ) {
return( -1 );
}
int version = LDAP_VERSION3;
ldap_set_option( lc->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+ /*
+ * Rewrite the new superior, if defined and required
+ */
+#ifdef ENABLE_REWRITE
+ switch ( rewrite_session( li->rwinfo, "newSuperiorDn",
+ newSuperior, conn, &mnewSuperior ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mnewSuperior == NULL ) {
+ mnewSuperior = ( char * )newSuperior;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> newSuperiorDn:"
+ " \"%s\" -> \"%s\"\n%s",
+ newSuperior, mnewSuperior, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform",
+ NULL, NULL );
+
+ case REWRITE_REGEXEC_ERR:
+ return( -1 );
+ }
+#else /* !ENABLE_REWRITE */
mnewSuperior = ldap_back_dn_massage( li,
- ch_strdup( newSuperior ), 0 );
+ ch_strdup( newSuperior ), 0 );
if ( mnewSuperior == NULL ) {
return( -1 );
}
+#endif /* !ENABLE_REWRITE */
}
- if ( !ldap_back_dobind(lc, op) ) {
- return( -1 );
- }
+#ifdef ENABLE_REWRITE
+ /*
+ * Rewrite the modrdn dn, if required
+ */
+ switch ( rewrite_session( li->rwinfo, "modrDn", dn, conn, &mdn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mdn == NULL ) {
+ mdn = ( char * )dn;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> modrDn: \"%s\" -> \"%s\"\n%s",
+ dn, mdn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform", NULL, NULL );
- mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 );
- if ( mdn == NULL ) {
+ case REWRITE_REGEXEC_ERR:
return( -1 );
}
+#else /* !ENABLE_REWRITE */
+ mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 );
+#endif /* !ENABLE_REWRITE */
ldap_rename2_s( lc->ld, mdn, newrdn, mnewSuperior, deleteoldrdn );
+#ifdef ENABLE_REWRITE
+ if ( mdn != dn ) {
+#endif /* ENABLE_REWRITE */
free( mdn );
- if ( mnewSuperior ) free( mnewSuperior );
+#ifdef ENABLE_REWRITE
+ }
+#endif /* ENABLE_REWRITE */
+ if ( mnewSuperior != NULL
+#ifdef ENABLE_REWRITE
+ && mnewSuperior != newSuperior
+#endif /* ENABLE_REWRITE */
+ ) {
+ free( mnewSuperior );
+ }
return( ldap_back_op_result( lc, op ) );
}
struct ldapconn *lc;
struct timeval tv;
LDAPMessage *res, *e;
- int count, rc, msgid, sres = LDAP_SUCCESS;
+ int count, rc = 0, msgid, sres = LDAP_SUCCESS;
char *match = NULL, *err = NULL;
- char *mbase, *mapped_filter, **mapped_attrs;
+ char *mbase = NULL, *mapped_filter = NULL, **mapped_attrs = NULL;
+#ifdef ENABLE_REWRITE
+ char *mfilter = NULL, *mmatch = NULL;
+#endif /* ENABLE_REWRITE */
lc = ldap_back_getconn(li, conn, op);
if ( !lc ) {
return( -1 );
}
- mbase = ldap_back_dn_massage( li, ch_strdup( base ), 0 );
- if ( mbase == NULL ) {
- return -1;
+ /*
+ * Rewrite the search base, if required
+ */
+#ifdef ENABLE_REWRITE
+ switch ( rewrite_session( li->rwinfo, "searchBase",
+ base, conn, &mbase ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mbase == NULL ) {
+ mbase = ( char * )base;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> searchBase: \"%s\" -> \"%s\"\n%s",
+ base, mbase, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform", NULL, NULL );
+
+ case REWRITE_REGEXEC_ERR:
+ rc = -1;
+ goto finish;
}
+
+ /*
+ * Rewrite the search filter, if required
+ */
+ switch ( rewrite_session( li->rwinfo, "searchFilter",
+ filterstr, conn, &mfilter ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mfilter == NULL || mfilter[0] == '\0') {
+ if ( mfilter != NULL ) {
+ free( mfilter );
+ }
+ mfilter = ( char * )filterstr;
+ }
+ Debug( LDAP_DEBUG_ARGS,
+ "rw> searchFilter: \"%s\" -> \"%s\"\n%s",
+ filterstr, mfilter, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform", NULL, NULL );
+ case REWRITE_REGEXEC_ERR:
+ rc = -1;
+ goto finish;
+ }
+#else /* !ENABLE_REWRITE */
+ mbase = ldap_back_dn_massage( li, ch_strdup( base ), 0 );
+#endif /* !ENABLE_REWRITE */
- mapped_filter = ldap_back_map_filter(li, (char *)filterstr, 0);
+ mapped_filter = ldap_back_map_filter(&li->at_map, &li->oc_map,
+#ifdef ENABLE_REWRITE
+ (char *)mfilter,
+#else /* !ENABLE_REWRITE */
+ (char *)filterstr,
+#endif /* !ENABLE_REWRITE */
+ 0);
if ( mapped_filter == NULL ) {
+#ifdef ENABLE_REWRITE
+ mapped_filter = (char *)mfilter;
+#else /* !ENABLE_REWRITE */
mapped_filter = (char *)filterstr;
+#endif /* !ENABLE_REWRITE */
}
- mapped_attrs = ldap_back_map_attrs(li, attrs, 0);
+ mapped_attrs = ldap_back_map_attrs(&li->at_map, attrs, 0);
if ( mapped_attrs == NULL ) {
mapped_attrs = attrs;
}
attrsonly)) == -1)
{
fail:
- if (match)
- free(match);
- if (err)
- free(err);
- if (mapped_attrs != attrs)
- charray_free(mapped_attrs);
- if (mapped_filter != filterstr)
- free(mapped_filter);
- free(mbase);
- return( ldap_back_op_result(lc, op) );
+ rc = ldap_back_op_result(lc, op);
+ goto finish;
}
/* We pull apart the ber result, stuff it into a slapd entry, and
if (ab) {
ldap_abandon(lc->ld, msgid);
+ rc = 0;
goto finish;
}
if (rc == 0) {
if (rc == -1)
goto fail;
+#ifdef ENABLE_REWRITE
+ /*
+ * Rewrite the matched portion of the search base, if required
+ */
+ if ( match != NULL ) {
+ switch ( rewrite_session( li->rwinfo, "matchedDn",
+ match, conn, &mmatch ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mmatch == NULL ) {
+ mmatch = ( char * )match;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> matchedDn:"
+ " \"%s\" -> \"%s\"\n%s",
+ match, mmatch, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform",
+ NULL, NULL );
+
+ case REWRITE_REGEXEC_ERR:
+ rc = -1;
+ goto finish;
+ }
+ }
+
+ send_search_result( conn, op, sres,
+ mmatch, err, NULL, NULL, count );
+
+#else /* !ENABLE_REWRITE */
send_search_result( conn, op, sres,
match, err, NULL, NULL, count );
+#endif /* !ENABLE_REWRITE */
finish:
- if (match)
+ if ( match ) {
+#ifdef ENABLE_REWRITE
+ if ( mmatch != match ) {
+ free( mmatch );
+ }
+#endif /* ENABLE_REWRITE */
free(match);
- if (err)
- free(err);
- if (mapped_attrs != attrs)
- charray_free(mapped_attrs);
- if (mapped_filter != filterstr)
- free(mapped_filter);
- free(mbase);
- return( 0 );
+ }
+ if ( err ) {
+ free( err );
+ }
+ if ( mapped_attrs != attrs ) {
+ charray_free( mapped_attrs );
+ }
+#ifdef ENABLE_REWRITE
+ if ( mapped_filter != mfilter ) {
+ free( mapped_filter );
+ }
+ if ( mfilter != filterstr ) {
+ free( mfilter );
+ }
+#else /* !ENABLE_REWRITE */
+ if ( mapped_filter != filterstr ) {
+ free( mapped_filter );
+ }
+#endif /* !ENABLE_REWRITE */
+
+#ifdef ENABLE_REWRITE
+ if ( mbase != base ) {
+#endif /* ENABLE_REWRITE */
+ free( mbase );
+#ifdef ENABLE_REWRITE
+ }
+#endif /* ENABLE_REWRITE */
+
+ return rc;
}
static void
struct berval *bv;
const char *text;
+#ifdef ENABLE_REWRITE
+ char *dn;
+
+ dn = ldap_get_dn(lc->ld, e);
+ if ( dn == NULL ) {
+ return;
+ }
+
+ /*
+ * Rewrite the dn of the result, if needed
+ */
+ switch ( rewrite_session( li->rwinfo, "searchResult",
+ dn, lc->conn, &ent.e_dn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( ent.e_dn == NULL ) {
+ ent.e_dn = dn;
+ } else {
+ Debug( LDAP_DEBUG_ARGS, "rw> searchResult: \"%s\""
+ " -> \"%s\"\n%s", dn, ent.e_dn, "" );
+ free( dn );
+ dn = NULL;
+ }
+ break;
+
+ case REWRITE_REGEXEC_ERR:
+ case REWRITE_REGEXEC_UNWILLING:
+ free( dn );
+ return;
+ }
+#else /* !ENABLE_REWRITE */
ent.e_dn = ldap_back_dn_restore( li, ldap_get_dn(lc->ld, e), 0 );
+#endif /* !ENABLE_REWRITE */
+
ent.e_ndn = ch_strdup( ent.e_dn );
(void) dn_normalize( ent.e_ndn );
ent.e_id = 0;
} else if ( strcasecmp( mapped, "objectclass" ) == 0 ) {
int i, last;
for ( last = 0; attr->a_vals[last]; last++ ) ;
- for ( i = 0; bv = attr->a_vals[i]; i++ ) {
+ for ( i = 0; ( bv = attr->a_vals[i] ); i++ ) {
mapped = ldap_back_map(&li->oc_map, bv->bv_val, 1);
if (mapped == NULL) {
ber_bvfree(attr->a_vals[i]);
bv->bv_len = strlen( mapped );
}
}
+
+#ifdef ENABLE_REWRITE
+ /*
+ * It is necessary to try to rewrite attributes with
+ * dn syntax because they might be used in ACLs as
+ * members of groups; since ACLs are applied to the
+ * rewritten stuff, no dn-based subecj clause could
+ * be used at the ldap backend side (see
+ * http://www.OpenLDAP.org/faq/data/cache/452.html)
+ * The problem can be overcome by moving the dn-based
+ * ACLs to the target directory server, and letting
+ * everything pass thru the ldap backend.
+ */
+ } else if ( strcmp( attr->a_desc->ad_type->sat_syntax->ssyn_oid,
+ SLAPD_DN_SYNTAX ) == 0 ) {
+ int i;
+ for ( i = 0; ( bv = attr->a_vals[ i ] ); i++ ) {
+ char *newval;
+
+ switch ( rewrite_session( li->rwinfo,
+ "searchResult",
+ bv->bv_val,
+ lc->conn, &newval )) {
+ case REWRITE_REGEXEC_OK:
+ /* left as is */
+ if ( newval == NULL ) {
+ break;
+ }
+ Debug( LDAP_DEBUG_ARGS,
+ "rw> searchResult on attr=%s: \"%s\" -> \"%s\"\n",
+ attr->a_desc->ad_type->sat_cname,
+ bv->bv_val, newval );
+
+ free( bv->bv_val );
+ bv->bv_val = newval;
+ bv->bv_len = strlen( newval );
+
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+
+ case REWRITE_REGEXEC_ERR:
+ /*
+ * FIXME: better give up,
+ * skip the attribute
+ * or leave it untouched?
+ */
+ break;
+ }
+ }
+#endif /* ENABLE_REWRITE */
}
+
*attrp = attr;
attrp = &attr->a_next;
}
if ( ent.e_ndn )
free( ent.e_ndn );
}
+
#include "portable.h"
+#ifndef ENABLE_REWRITE
+
#include <stdio.h>
#include <ac/socket.h>
return dn;
}
+#endif /* !ENABLE_REWRITE */
lc_curr.conn = conn;
ldap_pvt_thread_mutex_lock( &li->conn_mutex );
- lc = avl_delete( &li->conntree, (caddr_t)&lc_curr, conn_cmp );
+ lc = avl_delete( &li->conntree, (caddr_t)&lc_curr, ldap_back_conn_cmp );
ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
if (lc) {
Debug( LDAP_DEBUG_TRACE,
"=>ldap_back_conn_destroy: destroying conn %d\n",
lc->conn->c_connid, 0, 0 );
-
+
+#ifdef ENABLE_REWRITE
+ /*
+ * Cleanup rewrite session
+ */
+ rewrite_session_delete( li->rwinfo, conn );
+#endif /* ENABLE_REWRITE */
+
/*
* Needs a test because the handler may be corrupted,
* and calling ldap_unbind on a corrupted header results
--- /dev/null
+Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+
+* Mon Apr 30 2001 Pierangelo Masarati <ando@sys-net.it>
+- split back-meta from back-ldap
+- inplement init, config, bind, search, unbind
+
+* Tue May 01 2001 Pierangelo Masarati <ando@sys-net.it>
+- refined search propagation based on scope; in case of base shorter
+ than candidate target suffix:
+ "sub" propagates to all candidate targets,
+ "one" propagates to candidate targets only if base is
+ no more than one level shorter than suffix; in such
+ case scope is changed into "base"
+ "base" does not propagate (no such object error)
+
+* Tue May 01 2001 Pierangelo Masarati <ando@sys-net.it>
+- added checks in config.c
+- fixed leaks in search.c
+
+* Fri May 04 2001 Pierangelo Masarati <ando@sys-net.it>
+- added dn cache
+- added test
+
+* Sat May 05 2001 Pierangelo Masarati <ando@sys-net.it>
+- added missing functions
+- fixed flaw in group/attribute funcs (affects also back-ldap)
+ now meta_back_group works fine (group ACLS); nothing to say
+ about meta_back_attribute: unable to trigger it!
+- attributes with dn syntax are rewritten back in search results
+ (otherwise "dnattr"-style ACLs don't work). Now attrs with
+ dn syntax need be rewritten forth in add/modify ...
+
+* Sun May 06 2001 Pierangelo Masarati <ando@sys-net.it>
+- attributes with dn syntax are rewritten during add/modify operations
+ (otherwise "dnattr"-style ACLs don't work).
+- same back/forth rewriting has been applied to back-ldap;
+ actually, the add/modify rewriting function has been implemented
+ in bacl-ldap (ldap_dnattr_rewrite) and recycled in back-meta
+- fixed bug in invocation of meta_back_dobind in delete.c
+- code for deletion of "lastmod" attrs has been commented;
+ explicit "lastmod off" has been recommended in FAQ.
+- fixed a missing return in suffix_massage_config
+
+* Sun May 06 2001 Pierangelo Masarati <ando@sys-net.it>
+- fixed flaw in group.c both in back-ldap and back-meta: the group ndn
+ was not rewritten.
+
+* Tue May 08 2001 Pierangelo Masarati <ando@sys-net.it>
+- removed the limitation on target naming contexts; now they can be the same
+- added support for default target; it may be disabled or set to one of
+ the targets, resulting in that target being selected any time there's
+ a non-unique target selection (the target is missing or multiple targets
+ are selected for a add/modify/delete/compare/... operation).
+ TODO: should be more flexible, e.g. let the administrator decide
+ whether the default target may be used or not.
+- fixed a subtle bind/cache bug.
+- added helpers to clear target connections when they're no longer candidate.
+
+* Wed May 09 2001 Pierangelo Masarati <ando@sys-net.it>
+- reworked connection stuff in a separate file
+- reworked meta_back_getconn to handle singe/multiple target selection
+ correctly and atomicly
+- checked attribute mapping stuff
+
+* Fri May 11 2001 Pierangelo Masarati <ando@sys-net.it>
+- reworked compare to spawn the request on candidate targets (need to check
+ at most one matches!)
+
--- /dev/null
+Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+
+Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+
+This work has been developed to fulfill the requirements
+of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+to the OpenLDAP Foundation in the hope that it may be useful
+to the Open Source community, but WITHOUT ANY WARRANTY.
+
+Permission is granted to anyone to use this software for any purpose
+on any computer system, and to alter it and redistribute it, subject
+to the following restrictions:
+
+1. The author and SysNet s.n.c. are not responsible for the consequences
+ of use of this software, no matter how awful, even if they arise from
+ flaws in it.
+
+2. The origin of this software must not be misrepresented, either by
+ explicit claim or by omission. Since few users ever read sources,
+ credits should appear in the documentation.
+
+3. Altered versions must be plainly marked as such, and must not be
+ misrepresented as being the original software. Since few users
+ ever read sources, credits should appear in the documentation.
+ SysNet s.n.c. cannot be responsible for the consequences of the
+ alterations.
+
+4. This notice may not be removed or altered.
+
+
+This software is based on the backend back-ldap, implemented
+by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+<kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+contributors. The contribution of the original software to the present
+implementation is acknowledged in this copyright statement.
+
+A special acknowledgement goes to Howard for the overall architecture
+(and for borrowing large pieces of code), and to Mark, who implemented
+from scratch the attribute/objectclass mapping.
+
+The original copyright statement follows.
+
+Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+
+Permission is granted to anyone to use this software for any purpose
+on any computer system, and to alter it and redistribute it, subject
+to the following restrictions:
+
+1. The author is not responsible for the consequences of use of this
+ software, no matter how awful, even if they arise from flaws in it.
+
+2. The origin of this software must not be misrepresented, either by
+ explicit claim or by omission. Since few users ever read sources,
+ credits should appear in the documentation.
+
+3. Altered versions must be plainly marked as such, and must not be
+ misrepresented as being the original software. Since few users
+ ever read sources, credits should appear in the documentation.
+
+4. This notice may not be removed or altered.
+
+
--- /dev/null
+Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+
+Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+
+
+
+ Metadirectory backend.
+
+This is a brief introduction to the core functionalities of back-meta.
+
+
+
+ - Introduction.
+
+Back-meta implements a backend for OpenLDAP's slapd. It performs basic
+LDAP proxying with respect to a set of remote LDAP servers, called
+"targets". The information contained in these servers can be presented
+as belonging to a single Directory Information Tree (DIT).
+
+A basic knowledge of the functionality of back-ldap is recommended.
+This backend has been designed as an enhancement of back-ldap.
+The two backends share many features (actually they also share portions
+of code). While back-ldap is intended to proxy operations directed
+to a single server, back-meta is mainly intended for proxying
+of multiple servers and possibly naming context masquerading.
+These features, although useful in many scenarios, may result in
+excessive overhead for some applications, so its use should be
+carefully considered.
+
+In the examples section, some typical scenarios will be discussed.
+
+
+
+ - Common configuration directives
+
+The backend uses most of the common configuration directives. Its
+configuration block starts with the "database" directive:
+
+ database meta
+
+At least a "suffix" directive is required.
+
+Note: as with back-ldap, operational attributes related to entry
+creation/modification should not be used, as they would be passed
+to the target servers, generating an error. Moreover, it makes
+little sense to use such attributes in proxying, as the proxy
+server doesn't actually store data, so it should have no knowledge
+of such attributes. While code to strip the modification attributes
+has been put in place (and #ifdef's), it implies unmotivated overhead.
+So it is strongly recommended to set
+
+ lastmod off
+
+for every back-ldap/back-meta backend.
+
+
+
+ - Special configuration directives
+
+Target configuration starts with the "uri" directive. All the
+configuration directives that are not specific to targets should
+be defined first for clarity, including those that are common to
+all backends. They are:
+
+ default-target none
+
+This directive forces the backend to reject all those operations
+that must resolve to a single target in case none or multiple
+targets are selected. They include: add, delete, modify, modrdn;
+compare is also included, although a different behavior might be
+considered in the future. This directive can also be used when
+processing targets to mark a specific target as default.
+
+ dncache-ttl {forever|disabled|<ttl>}
+
+This directive sets the time-to-live of the dn cache. This caches
+the target that holds a given dn to speed up target selection
+in case multiple targets would result from an uncached search;
+forever means cache never expires; disabled means no dn caching;
+otherwise a valid ( > 0 ) ttl in seconds is required.
+
+
+
+ - Target specification
+
+Target specification starts with a "uri" directive:
+
+ uri <protocol>://[<host>[:<port>]]/<naming context>
+
+The "server" directive that was allowed in back-ldap has been discarded
+in back-meta. The <protocol> part can be anything ldap_initialize(3)
+accepts ({ldap|ldaps|ldapi} and variants); <host> and <port> may be
+omitted, defaulting to whatever is set in /etc/ldap.conf (correct me!?!).
+The <naming context> part is mandatory. It must end with one of the
+naming contexts defined for the backend, e.g.:
+
+ suffix "dc=foo,dc=com"
+ uri "ldap://x.foo.com/dc=x,dc=foo,dc=com"
+
+The <naming context> part doesn't need to be unique across the targets;
+it may also match one of the values of the "suffix" directive.
+
+ default-target [<target>]
+
+the "default-target" directive can also be used during target
+specification. With no arguments it marks the current target as
+the default. The optional number marks target <target> as the
+default one, starting from 1. Target <target> must be defined.
+
+ binddn <administrative dn for ac purposes>
+
+This directive, as in back-ldap, allows to define the dn that is
+used to query the target server for acl checking; it should have
+read access on the target server to attributes used on the proxy
+for acl checking. There is no risk of giving away such values;
+they are only used to check permissions.
+
+ bindpw <plaintext password for ac purposes>
+
+This directive sets the password for acl checking in conjunction
+with the above mentioned "binddn" directive.
+
+ rewrite* ...
+
+ suffixmassage <virtual naming context> <real naming context>
+
+All the directives starting with "rewrite" refer to the rewrite engine
+that has been added to slapd. The "suffixmassage" directive was
+introduced in back-ldap to allow suffix massaging while proxying.
+It has been obsoleted by the rewriting tools. However, both for
+backward compatibility and for ease of configuration when simple
+suffix massage is required, it has been preserved. It wraps the
+basic rewriting instruction that perform suffix massaging.
+
+Note: this also fixes a flaw in suffix massaging, which operated
+on (case insensitive) DNs instead of normalized DNs,
+so "dc=foo, dc=com" would not match "dc=foo,dc=com".
+
+See the "rewrite" section.
+
+ map {objectClass|attribute} {<source>|*} [<dest>|*]
+
+objectClass/attribute mapping stuff. This has been inherited from
+the work made by Mark Valence on the back-ldap backend.
+See the mapping section.
+
+
+
+ - Scenarios
+
+A powerful (and in some sense dangerous) rewrite engine has been added
+to both back-ldap and back-meta. While the former can gain limited
+beneficial effects from rewriting stuff, the latter can become
+an amazingly powerful tool.
+
+Consider a couple of scenarios first.
+
+1) Two directory servers share two levels of naming context;
+say "dc=a,dc=foo,dc=com" and "dc=b,dc=foo,dc=com". Then, an
+unambiguous back-meta can be configured as:
+
+ database meta
+ suffix "dc=foo,dc=com"
+
+ uri "ldap://a.foo.com/dc=a,dc=foo,dc=com"
+
+ uri "ldap://b.foo.com/dc=b,dc=foo,dc=com"
+
+Operations directed to a specific target can be easily resolved
+because there are no ambiguities. The only operation that may
+resolve to multiple targets is a search with base "dc=foo,dc=com"
+and scope at least "one", which results in spawning two searches
+to the targets.
+
+2a) Two directory servers don't share any portion of naming context,
+but they'd present as a single DIT. [Caveat: uniqueness of
+(massaged) entries among the two servers is assumed; integrity
+checks risk to incurr in excessive overhead.]
+Say we have "dc=bar,dc=org" and "o=Foo,c=US", and we'd like them to
+present as branches of "dc=foo,dc=com", say "dc=a,dc=foo,dc=com"
+and "dc=b,dc=foo,dc=com". Then we need to configure our back-meta as:
+
+ database meta
+ suffix "dc=foo,dc=com"
+
+ uri "ldap://a.bar.com/dc=a,dc=foo,dc=com"
+ suffixmassage "dc=a,dc=foo,dc=com" "dc=bar,dc=org"
+
+ uri "ldap://b.foo.com/dc=b,dc=foo,dc=com"
+ suffixmassage "dc=b,dc=foo,dc=com" "o=Foo,c=US"
+
+Again, operations can be resolved without ambiguity, although
+some rewriting is required. Notice that the virtual naming context
+of each target is a branch of the database's naming context; it
+is rewritten back and forth when operations are performed towards
+the target servers. What "back and forth" means will be clarified
+later.
+
+When a search with base "dc=foo,dc=com" is attempted, if the
+scope is "base" it fails with "no such object"; in fact, the
+common root of the two targets (prior to massaging) does not
+exists. If the scope is "one", both targets are contacted with
+the base replaced by each target's base; the scope is decreased
+to "base". In general, the scope "one" search is honored,
+and the scope is decreased, only when the incoming base is
+at most one level lower of a target's naming context (prior
+to massaging).
+Finally, if the scope is "sub" the incoming base is replaced
+by each target's unmassaged naming context, and the scope
+is not altered.
+
+2b) Consider the above reported scenario with the two servers
+sharing the same naming context:
+
+ database meta
+ suffix "dc=foo,dc=com"
+
+ uri "ldap://a.bar.com/dc=foo,dc=com"
+ suffixmassage "dc=foo,dc=com" "dc=bar,dc=org"
+
+ uri "ldap://b.foo.com/dc=foo,dc=com"
+ suffixmassage "dc=foo,dc=com" "o=Foo,c=US"
+
+All the previous considerations hold, except that now there is
+no way to unambiguously resolve a dn. In this case, all the
+operations that require an unambiguous target selection will
+fail unless the dn is already cached or a default target has
+been set.
+
+
+
+ - Rewriting
+
+This part of the document is being prepared. At present you may consult
+the RATIONALE in libraries/librewrite.
+
+
+
+ - Objectclass/attribute mapping
+
+This part of the document is being prepared. At present you may stick with
+
+http://www.openldap.org/lists/openldap-devel/200102/msg00006.html
+
+
+
+ - ACL
+Note on ACLs: at present you may add whatever ACL rule you desire
+to back-meta (as well as to back-ldap). However, the meaning of an ACL
+on a proxy may require some considerations. Two philosophies may be
+considered:
+
+a) the remote server dictates the permissions; the proxy simply passes
+back what it gets from the remore server.
+
+b) the remote server unveils "everything"; the proxy is responsible
+for protecting data from unauthorized access.
+
+Of course the latter sounds unreasonable, but it is not. It is possible
+to imagine scenarios in which a remote host discloses data that can
+be considered "public" in an intranet, and a proxy that connects it to
+the internet may impose additional constraints. To this purpose, the
+proxy should be able to comply with all the ACL matching criteria that
+the server supports. This has been achieved with regard to all the
+criteria supported by slapd except a secial subtle case (please notify
+me if you can find other exceptions).
+The rule
+
+access to dn="<dn>" attr=<attr>
+ by dnattr=<dnattr> read
+ by * none
+
+cannot be matched IFF:
+- the operation dn (the one that bound) is "<dn>", and
+- the entry whose <attr> is being accessed is again <dn>, and
+- the attribute that determines membership, <dnattr>, has not
+ been required (e.g. in a search)
+
+In fact this ACL is resolved by slapd considering the entry it retrieved
+from the remote server without requiring any further intervention of the
+backend, so, if the <dnattr> attribute has not been fetched, the match
+cannot be accomplished because the attribute is not present, not because
+no value matches the requirement.
+
--- /dev/null
+# $OpenLDAP$
+
+SRCS = init.c config.c search.c bind.c unbind.c add.c compare.c \
+ delete.c modify.c modrdn.c group.c attribute.c \
+ conn.c candidates.c dncache.c
+OBJS = init.lo config.lo search.lo bind.lo unbind.lo add.lo compare.lo \
+ delete.lo modify.lo modrdn.lo group.lo attribute.lo \
+ conn.lo candidates.lo dncache.lo
+
+LDAP_INCDIR= ../../../include
+LDAP_LIBDIR= ../../../libraries
+
+BUILD_OPT = "--enable-meta"
+BUILD_MOD = @BUILD_META@
+LINKAGE = @BUILD_META_DYNAMIC@
+
+LIBBASE = back_meta
+
+XINCPATH = -I.. -I$(srcdir)/..
+XDEFS = $(MODULES_CPPFLAGS)
+
+all-local-lib: ../.backend
+
+../.backend: lib$(LIBBASE).a
+ @touch $@
+
--- /dev/null
+* Short term:
+
+- add missing functions (FIXED)
+
+- review per-target error handling
+
+- dn cache and cache exploitation to refine the candidate selection (?) (FIXED)
+
+- review the group and attribute stuff (also in back-ldap!) (FIXED, need to
+ test attribute)
+
+- rework compare and bind to attempt to operate on all candidate entries
+ while checking at most one succeedes
+
+- clear previously bound targets when the bind is repeated
+
+* Long term:
+
+- distributed entries
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-meta.h"
+
+int
+meta_back_add(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ Entry *e
+)
+{
+ struct metainfo *li = ( struct metainfo * )be->be_private;
+ struct metaconn *lc;
+ int i, candidate = -1;
+ Attribute *a;
+ LDAPMod **attrs;
+ char *mdn = NULL, *mapped;
+
+ /*
+ * get the current connection
+ */
+ lc = meta_back_getconn( li, conn, op, META_OP_REQUIRE_SINGLE,
+ e->e_ndn, &candidate );
+ if ( !lc || !meta_back_dobind( lc, op ) ) {
+ return -1;
+ }
+
+ /*
+ * Rewrite the add dn, if needed
+ */
+ switch ( rewrite_session( li->targets[ candidate ]->rwinfo,
+ "addDn", e->e_dn, conn, &mdn )) {
+ case REWRITE_REGEXEC_OK:
+ if ( mdn == NULL ) {
+ mdn = e->e_dn;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> addDn: \"%s\" -> \"%s\"\n%s",
+ e->e_dn, mdn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform", NULL, NULL );
+
+ case REWRITE_REGEXEC_ERR:
+ return -1;
+ }
+
+ /* Count number of attributes in entry */
+ for ( i = 1, a = e->e_attrs; a; i++, a = a->a_next );
+
+ /* Create array of LDAPMods for ldap_add() */
+ attrs = ch_malloc( sizeof( LDAPMod * )*i );
+
+ for ( i = 0, a = e->e_attrs; a; a = a->a_next ) {
+ /*
+ * lastmod should always be <off>, so that
+ * creation/modification operational attrs
+ * of the target directory are used, if available
+ */
+#if 0
+ if ( !strcasecmp( a->a_desc->ad_cname->bv_val,
+ slap_schema.si_ad_creatorsName->ad_cname->bv_val )
+ || !strcasecmp( a->a_desc->ad_cname->bv_val,
+ slap_schema.si_ad_createTimestamp->ad_cname->bv_val )
+ || !strcasecmp( a->a_desc->ad_cname->bv_val,
+ slap_schema.si_ad_modifiersName->ad_cname->bv_val )
+ || !strcasecmp( a->a_desc->ad_cname->bv_val,
+ slap_schema.si_ad_modifyTimestamp->ad_cname->bv_val )
+ ) {
+ continue;
+ }
+#endif
+
+ mapped = ldap_back_map( &li->targets[ candidate ]->at_map,
+ a->a_desc->ad_cname->bv_val, 0);
+ if ( mapped == NULL ) {
+ continue;
+ }
+
+ attrs[ i ] = ch_malloc( sizeof( LDAPMod ) );
+ if ( attrs[ i ] == NULL ) {
+ continue;
+ }
+ attrs[ i ]->mod_op = LDAP_MOD_BVALUES;
+ attrs[ i ]->mod_type = mapped;
+
+ /*
+ * FIXME: dn-valued attrs should be rewritten
+ * to allow their use in ACLs at the back-ldap
+ * level.
+ */
+ if ( strcmp( a->a_desc->ad_type->sat_syntax->ssyn_oid,
+ SLAPD_DN_SYNTAX ) == 0 ) {
+ ldap_dnattr_rewrite( li->targets[ candidate ]->rwinfo,
+ a->a_vals, conn );
+ }
+
+ attrs[ i ]->mod_vals.modv_bvals = a->a_vals;
+ i++;
+ }
+ attrs[ i ] = NULL;
+
+ ldap_add_s( lc->conns[ candidate ]->ld, mdn, attrs );
+ for ( --i; i >= 0; --i ) {
+ free( attrs[ i ] );
+ }
+ free( attrs );
+ if ( mdn != e->e_dn ) {
+ free( mdn );
+ }
+ return meta_back_op_result( lc, op );
+}
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-meta.h"
+
+
+/* return 0 IFF we can retrieve the attributes
+ * of entry with e_ndn
+ */
+
+/*
+ * FIXME: I never testd this function; I know it compiles ... :)
+ */
+int
+meta_back_attribute(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ Entry *target,
+ const char *e_ndn,
+ AttributeDescription *entry_at,
+ struct berval ***vals
+)
+{
+ struct metainfo *li = ( struct metainfo * )be->be_private;
+ int rc = 1, i, j, count, is_oc, candidate;
+ Attribute *attr;
+ struct berval **abv, **v;
+ char **vs, *mapped;
+ LDAPMessage *result, *e;
+ char *gattr[ 2 ];
+ LDAP *ld;
+ char *me_ndn;
+
+ *vals = NULL;
+ if ( target != NULL && strcmp( target->e_ndn, e_ndn ) == 0 ) {
+ /* we already have a copy of the entry */
+ /* attribute and objectclass mapping has already been done */
+ attr = attr_find( target->e_attrs, entry_at );
+ if ( attr == NULL ) {
+ return 1;
+ }
+
+ for ( count = 0; attr->a_vals[ count ] != NULL; count++ )
+ ;
+ v = ch_calloc( ( count + 1 ), sizeof( struct berval * ) );
+ if ( v != NULL ) {
+ for ( j = 0, abv = attr->a_vals; --count >= 0; abv++ ) {
+ if ( ( *abv )->bv_len > 0 ) {
+ v[ j ] = ber_bvdup( *abv );
+ if ( v[ j ] == NULL ) {
+ break;
+ }
+ }
+ }
+ v[ j ] = NULL;
+ *vals = v;
+ rc = 0;
+ }
+
+ return rc;
+ } /* else */
+
+ candidate = meta_back_select_unique_candidate( li, e_ndn );
+ if ( candidate == -1 ) {
+ return 1;
+ }
+
+ mapped = ldap_back_map( &li->targets[ candidate ]->at_map,
+ entry_at->ad_cname->bv_val, 0 );
+ if ( mapped == NULL )
+ return 1;
+
+ rc = ldap_initialize( &ld, li->targets[ candidate ]->uri );
+ if ( rc != LDAP_SUCCESS ) {
+ return 1;
+ }
+
+ rc = ldap_bind_s( ld, li->targets[ candidate ]->binddn,
+ li->targets[ candidate ]->bindpw, LDAP_AUTH_SIMPLE );
+ if ( rc != LDAP_SUCCESS) {
+ return 1;
+ }
+
+ gattr[ 0 ] = mapped;
+ gattr[ 1 ] = NULL;
+ if ( ldap_search_ext_s( ld, e_ndn, LDAP_SCOPE_BASE, "(objectclass=*)",
+ gattr, 0, NULL, NULL, LDAP_NO_LIMIT,
+ LDAP_NO_LIMIT, &result) == LDAP_SUCCESS) {
+ if ( ( e = ldap_first_entry( ld, result ) ) != NULL ) {
+ vs = ldap_get_values( ld, e, mapped );
+ if ( vs != NULL ) {
+ for ( count = 0; vs[ count ] != NULL;
+ count++ ) { }
+ v = ch_calloc( ( count + 1 ),
+ sizeof( struct berval * ) );
+ if ( v == NULL ) {
+ ldap_value_free( vs );
+ } else {
+ is_oc = ( strcasecmp( "objectclass", mapped ) == 0 );
+ for ( i = 0, j = 0; i < count; i++ ) {
+ if ( !is_oc ) {
+ v[ j ] = ber_bvstr( vs[ i ] );
+ if ( v[ j ] == NULL ) {
+ ch_free( vs[ i ] );
+ } else {
+ j++;
+ }
+ } else {
+ mapped = ldap_back_map( &li->targets[ candidate ]->oc_map, vs[ i ], 1 );
+ if ( mapped ) {
+ mapped = ch_strdup( mapped );
+ if ( mapped ) {
+ v[ j ] = ber_bvstr( mapped );
+ if ( v[ j ] ) {
+ j++;
+ }
+ }
+ }
+ ch_free( vs[ i ] );
+ }
+ }
+ v[ j ] = NULL;
+ *vals = v;
+ rc = 0;
+ ch_free( vs );
+ }
+ }
+ }
+ ldap_msgfree( result );
+ }
+ ldap_unbind(ld);
+
+ return(rc);
+}
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#ifndef SLAPD_LDAP_H
+#error "include servers/slapd/back-ldap/back-ldap.h before this file!"
+#endif /* SLAPD_LDAP_H */
+
+#ifndef SLAPD_META_H
+#define SLAPD_META_H
+
+#include "external.h"
+
+/* String rewrite library */
+#include "rewrite.h"
+
+LDAP_BEGIN_DECL
+
+struct slap_conn;
+struct slap_op;
+
+struct metasingleconn {
+ int candidate;
+#define META_NOT_CANDIDATE 0
+#define META_CANDIDATE 1
+
+ LDAP *ld;
+ char *bound_dn;
+ int bound;
+#define META_UNBOUND 0
+#define META_BOUND 1
+#define META_ANONYMOUS 2
+};
+
+struct metaconn {
+ struct slap_conn *conn;
+ struct rewrite_info *rwinfo;
+
+ /*
+ * means that the connection is bound;
+ * of course only one target actually is ...
+ */
+ int bound_target;
+ /* supersedes the connection stuff */
+ struct metasingleconn **conns;
+};
+
+struct metatarget {
+ char *uri;
+ char *suffix;/* normalized suffix */
+ char *binddn;
+ char *bindpw;
+
+ struct rewrite_info *rwinfo;
+
+ struct ldapmap oc_map;
+ struct ldapmap at_map;
+};
+
+struct metadncache {
+ ldap_pvt_thread_mutex_t mutex;
+ Avlnode *tree;
+
+#define META_DNCACHE_DISABLED 0
+#define META_DNCACHE_FOREVER -1
+ long int ttl; /* seconds; 0: no cache, -1: no expiry */
+};
+
+struct metainfo {
+ int ntargets;
+ int defaulttarget;
+#define META_DEFAULT_TARGET_NONE -1
+ struct metatarget **targets;
+
+ struct metadncache cache;
+
+ ldap_pvt_thread_mutex_t conn_mutex;
+ Avlnode *conntree;
+};
+
+extern int
+meta_back_do_single_bind(
+ Operation *op,
+ struct metainfo *li,
+ struct metaconn *lc,
+ const char *dn,
+ const char *ndn,
+ struct berval *cred,
+ int method,
+ int candidate
+);
+
+
+#define META_OP_ALLOW_MULTIPLE 0x00
+#define META_OP_REQUIRE_SINGLE 0x01
+extern struct metaconn *
+meta_back_getconn(
+ struct metainfo *li,
+ struct slap_conn *conn,
+ struct slap_op *op,
+ int op_type,
+ const char *dn,
+ int *candidate
+);
+
+extern int
+meta_back_dobind(
+ struct metaconn *lc,
+ Operation *op
+);
+
+extern int
+meta_back_op_result(
+ struct metaconn *lc,
+ Operation *op
+);
+
+extern int
+back_meta_LTX_init_module(
+ int argc,
+ char *argv[]
+);
+
+extern int
+meta_back_conn_cmp(
+ const void *c1,
+ const void *c2
+);
+
+extern int
+meta_back_conn_dup(
+ void *c1,
+ void *c2
+);
+
+/*
+ * Candidate stuff
+ */
+extern int
+meta_back_is_candidate(
+ const char *nsuffix,
+ const char *ndn,
+ int ndnlen
+);
+
+extern int
+meta_back_count_candidates(
+ struct metainfo *li,
+ const char *ndn
+);
+
+extern int
+meta_back_is_candidate_unique(
+ struct metainfo *li,
+ const char *ndn
+);
+
+extern int
+meta_back_select_unique_candidate(
+ struct metainfo *li,
+ const char *ndn
+);
+
+extern int
+meta_clear_unused_candidates(
+ struct metainfo *li,
+ struct metaconn *lc,
+ int candidate,
+ int reallyclean
+);
+
+extern int
+meta_clear_one_candidate(
+ struct metasingleconn *lc,
+ int reallyclean
+);
+
+/*
+ * Dn cache stuff (experimental)
+ */
+extern int
+meta_dncache_cmp(
+ const void *c1,
+ const void *c2
+);
+
+extern int
+meta_dncache_dup(
+ void *c1,
+ void *c2
+);
+
+extern int
+meta_dncache_get_target(
+ struct metadncache *cache,
+ const char *ndn
+);
+
+extern int
+meta_dncache_update_entry(
+ struct metadncache *cache,
+ const char *ndn,
+ int target
+);
+
+extern int
+meta_dncache_delete_entry(
+ struct metadncache *cache,
+ const char *ndn
+);
+
+extern void
+meta_dncache_free(
+ void *entry
+);
+
+LDAP_END_DECL
+
+#endif /* SLAPD_META_H */
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
+
+#define AVL_INTERNAL
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-meta.h"
+
+int
+meta_back_bind(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn,
+ int method,
+ struct berval *cred,
+ char **edn
+)
+{
+ struct metainfo *li = ( struct metainfo * )be->be_private;
+ struct metaconn *lc;
+
+ int rc = -1, i, gotit = 0, ndnlen, err = LDAP_SUCCESS;
+
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY,
+ "meta_back_bind: dn: %s.\n", dn ));
+#else /* !NEW_LOGGING */
+ Debug( LDAP_DEBUG_ARGS, "meta_back_bind: dn: %s.\n%s%s", dn, "", "" );
+#endif /* !NEW_LOGGING */
+
+ *edn = NULL;
+
+ lc = meta_back_getconn( li, conn, op, META_OP_ALLOW_MULTIPLE,
+ ndn, NULL );
+ if ( !lc ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "backend", LDAP_LEVEL_NOTICE,
+ "meta_back_bind: no target for dn %s.\n", dn ));
+#else /* !NEW_LOGGING */
+ Debug( LDAP_DEBUG_ANY,
+ "meta_back_bind: no target for dn %s.\n%s%s",
+ dn, "", "");
+#endif /* !NEW_LOGGING */
+ return -1;
+ }
+
+ /*
+ * Each target is scanned ...
+ */
+ ndnlen = strlen( ndn );
+ for ( i = 0; i < li->ntargets; i++ ) {
+ int lerr;
+
+ /*
+ * Skip non-candidates
+ */
+ if ( lc->conns[ i ]->candidate != META_CANDIDATE ) {
+ continue;
+ }
+
+ if ( gotit == 0 ) {
+ gotit = 1;
+ } else {
+ /*
+ * A bind operation is expected to have
+ * ONE CANDIDATE ONLY!
+ */
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "backend", LDAP_LEVEL_WARNING,
+"==>meta_back_bind: more that one candidate is attempting to bind ...%s%s%s\n" ));
+#else /* !NEW_LOGGING */
+ Debug( LDAP_DEBUG_ANY,
+"==>meta_back_bind: more that one candidate is attempting to bind ...%s%s%s\n",
+ "", "", "" );
+#endif /* !NEW_LOGGING */
+ }
+
+
+ lerr = meta_back_do_single_bind( op, li, lc, dn, ndn, cred,
+ method, i );
+ if ( lerr != LDAP_SUCCESS ) {
+ err = lerr;
+ ( void )meta_clear_one_candidate( lc->conns[ i ], 1 );
+ } else {
+ rc = LDAP_SUCCESS;
+ }
+ }
+
+ if ( rc != LDAP_SUCCESS && err != LDAP_SUCCESS ) {
+
+ /*
+ * deal with bind failure ...
+ */
+ err = ldap_back_map_result( err );
+ send_ldap_result( conn, op, err, NULL, "", NULL, NULL );
+ }
+
+ return LDAP_SUCCESS;
+}
+
+/*
+ * meta_back_do_single_bind
+ *
+ * attempts to perform a bind with creds
+ */
+int
+meta_back_do_single_bind(
+ Operation *op,
+ struct metainfo *li,
+ struct metaconn *lc,
+ const char *dn,
+ const char *ndn,
+ struct berval *cred,
+ int method,
+ int candidate
+)
+{
+ char *mdn = NULL;
+ int rc;
+
+ /*
+ * Rewrite the bind dn if needed
+ */
+ switch ( rewrite_session( li->targets[ candidate ]->rwinfo,
+ "bindDn", dn, lc->conn, &mdn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mdn == NULL ) {
+ mdn = ( char * )dn;
+ }
+ Debug( LDAP_DEBUG_ARGS,
+ "rw> bindDn: \"%s\" -> \"%s\"\n%s",
+ dn, mdn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( lc->conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform",
+ NULL, NULL );
+ /* continues to next case */
+
+ case REWRITE_REGEXEC_ERR:
+ return -1;
+ }
+
+ rc = ldap_bind_s( lc->conns[ candidate ]->ld, mdn,
+ cred->bv_val, method );
+ if ( rc != LDAP_SUCCESS ) {
+ rc = ldap_back_map_result( rc );
+ } else {
+ lc->conns[ candidate ]->bound_dn = ch_strdup( dn );
+ lc->conns[ candidate ]->bound = META_BOUND;
+ lc->bound_target = candidate;
+
+ if ( li->cache.ttl != META_DNCACHE_DISABLED
+ && ndn[ 0 ] != '\0' ) {
+ ( void )meta_dncache_update_entry( &li->cache,
+ ch_strdup( ndn ), candidate );
+ }
+ }
+
+ if ( mdn != dn ) {
+ free( mdn );
+ }
+
+ return rc;
+}
+
+/*
+ * meta_back_dobind
+ */
+int
+meta_back_dobind( struct metaconn *lc, Operation *op )
+{
+ struct metasingleconn **lsc;
+ int bound = 0, i;
+
+ for ( i = 0, lsc = lc->conns; lsc[ 0 ] != NULL; ++i, ++lsc ) {
+ int rc;
+
+ /*
+ * Not a candidate or something wrong with this target ...
+ */
+ if ( lsc[ 0 ]->ld == NULL ) {
+ continue;
+ }
+
+ /*
+ * If the target is already bound it is skipped
+ */
+ if ( lsc[ 0 ]->bound == META_BOUND && lc->bound_target == i ) {
+ ++bound;
+ continue;
+ }
+
+ /*
+ * Otherwise an anonymous bind is performed
+ * (note: if the target was already bound, the anonymous
+ * bind clears the previous bind).
+ */
+ rc = ldap_bind_s( lsc[ 0 ]->ld, lsc[ 0 ]->bound_dn,
+ NULL, LDAP_AUTH_SIMPLE );
+ if ( rc != LDAP_SUCCESS ) {
+
+ /*
+ * This way, the first bind error would be fatal ...
+ */
+ Debug( LDAP_DEBUG_ANY,
+ "==>meta_back_dobind: (anonymous) bind as \"%s\" failed"
+ " with error \"%s\"\n%s",
+ lsc[ 0 ]->bound_dn,
+ ldap_err2string( rc ), "" );
+
+ /*
+ * null cred bind should always succeed
+ * as anonymous, so a failure means
+ * the target is no longer candidate possibly
+ * due to technical reasons (remote host down?)
+ *
+ * so better clear the handle
+ */
+ ( void )meta_clear_one_candidate( lsc[ 0 ], 1 );
+ continue;
+ } /* else */
+
+ lsc[ 0 ]->bound = META_ANONYMOUS;
+ ++bound;
+ }
+
+ return( bound > 0 );
+}
+
+/*
+ * FIXME: error return must be handled in a cleaner way ...
+ */
+int
+meta_back_op_result( struct metaconn *lc, Operation *op )
+{
+ int i, err = LDAP_SUCCESS;
+ char *msg = NULL;
+ char *match = NULL;
+ struct metasingleconn **lsc;
+
+ for ( i = 0, lsc = lc->conns; lsc[ 0 ] != NULL; ++i, ++lsc ) {
+ ldap_get_option( lsc[ 0 ]->ld, LDAP_OPT_ERROR_NUMBER, &err );
+ if ( err != LDAP_SUCCESS ) {
+ /*
+ * better check the type of error. In some cases
+ * (search ?) it might be better to return a
+ * success if at least one of the targets gave
+ * positive result ...
+ */
+ ldap_get_option( lsc[ 0 ]->ld,
+ LDAP_OPT_ERROR_STRING, &msg );
+ ldap_get_option( lsc[ 0 ]->ld,
+ LDAP_OPT_MATCHED_DN, &match );
+ err = ldap_back_map_result( err );
+
+ /*
+ * FIXME: need to rewrite "match"
+ */
+ send_ldap_result( lc->conn, op, err, match, msg,
+ NULL, NULL );
+
+ Debug(LDAP_DEBUG_ANY,
+"==> meta_back_op_result: target <%d> sending msg \"%s\" (matched \"%s\")\n",
+ i,
+ ( msg ? msg : "" ),
+ ( match ? match : "" ) );
+
+ /* better test the pointers before freeing? */
+ if ( match ) {
+ free( match );
+ }
+ if ( msg ) {
+ free( msg );
+ }
+ return -1;
+ }
+ }
+
+ return ( err == LDAP_SUCCESS ) ? 0 : -1;
+}
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-meta.h"
+
+/*
+ * The meta-directory has one suffix, called <suffix>.
+ * It handles a pool of target servers, each with a branch suffix
+ * of the form <branch X>,<suffix>
+ *
+ * When the meta-directory receives a request with a dn that belongs
+ * to a branch, the corresponding target is invoked. When the dn
+ * does not belong to a specific branch, all the targets that
+ * are compatible with the dn are selected as candidates, and
+ * the request is spawned to all the candidate targets
+ *
+ * A request is characterized by a dn. The following cases are handled:
+ * - the dn is the suffix: <dn> == <suffix>,
+ * all the targets are candidates (search ...)
+ * - the dn is a branch suffix: <dn> == <branch X>,<suffix>, or
+ * - the dn is a subtree of a branch suffix:
+ * <dn> == <rdn>,<branch X>,<suffix>,
+ * the target is the only candidate.
+ *
+ * A possible extension will include the handling of multiple suffixes
+ */
+
+/*
+ * returns 1 if suffix is candidate for dn, otherwise 0
+ *
+ * Note: this function should never be called if dn is the <suffix>.
+ */
+int
+meta_back_is_candidate(
+ const char *nsuffix,
+ const char *ndn,
+ int ndnlen
+)
+{
+ int len = strlen( nsuffix );
+
+ if ( len > ndnlen ) {
+ /*
+ * suffix longer than dn
+ */
+ if ( ! DN_SEPARATOR( nsuffix[ ( len - ndnlen ) - 1 ] ) ) {
+ /*
+ * not a separator begins the possible common part
+ */
+ return META_NOT_CANDIDATE;
+ }
+
+ if ( strcmp( &nsuffix[ len - ndnlen] , ndn ) == 0 ) {
+ /*
+ * Got it!
+ */
+ return META_CANDIDATE;
+ }
+ }
+
+ if ( len < ndnlen && ! DN_SEPARATOR( ndn[ ( ndnlen - len ) - 1 ] ) ) {
+ /*
+ * not a separator begins the possible common part
+ */
+ return META_NOT_CANDIDATE;
+ }
+
+ if ( strcmp( nsuffix, &ndn[ ndnlen - len ] ) == 0 ) {
+ /*
+ * Got it!
+ */
+ return META_CANDIDATE;
+ }
+
+ return META_NOT_CANDIDATE;
+}
+
+/*
+ * meta_back_count_candidates
+ *
+ * returns a count of the possible candidate targets
+ * Note: dn MUST be normalized
+ */
+
+int
+meta_back_count_candidates(
+ struct metainfo *li,
+ const char *ndn
+)
+{
+ int i, cnt = 0, ndnlen = strlen( ndn );
+
+ /*
+ * I know assertions should not check run-time values;
+ * at present I didn't find a place for such checks
+ * after config.c
+ */
+ assert( li->targets != NULL );
+ assert( li->ntargets != 0 );
+
+ for ( i = 0; i < li->ntargets; ++i ) {
+ if ( meta_back_is_candidate( li->targets[ i ]->suffix,
+ ndn, ndnlen ) ) {
+ ++cnt;
+ }
+ }
+
+ return cnt;
+}
+
+/*
+ * meta_back_is_candidate_unique
+ *
+ * checks whether a candidate is unique
+ * Note: dn MUST be normalized
+ */
+int
+meta_back_is_candidate_unique(
+ struct metainfo *li,
+ const char *ndn
+)
+{
+ return ( meta_back_count_candidates( li, ndn ) == 1 );
+}
+
+/*
+ * meta_back_select_unique_candidate
+ *
+ * returns the index of the candidate in case it is unique, otherwise -1
+ * Note: dn MUST be normalized.
+ * Note: if defined, the default candidate is returned in case of no match.
+ */
+int
+meta_back_select_unique_candidate(
+ struct metainfo *li,
+ const char *ndn
+)
+{
+ int i, ndnlen;
+
+ switch ( meta_back_count_candidates( li, ndn ) ) {
+ case 1:
+ break;
+ case 0:
+ default:
+ return ( li->defaulttarget == META_DEFAULT_TARGET_NONE
+ ? -1 : li->defaulttarget );
+ }
+
+ ndnlen = strlen( ndn );
+ for ( i = 0; i < li->ntargets; ++i ) {
+ if ( meta_back_is_candidate( li->targets[ i ]->suffix,
+ ndn, ndnlen ) ) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+/*
+ * meta_clear_unused_candidates
+ *
+ * clears all candidates except candidate
+ */
+int
+meta_clear_unused_candidates(
+ struct metainfo *li,
+ struct metaconn *lc,
+ int candidate,
+ int reallyclean
+)
+{
+ int i;
+
+ for ( i = 0; i < li->ntargets; ++i ) {
+ if ( i == candidate ) {
+ continue;
+ }
+ meta_clear_one_candidate( lc->conns[ i ], reallyclean );
+ }
+
+ return 0;
+}
+
+/*
+ * meta_clear_one_candidate
+ *
+ * clears the selected candidate
+ */
+int
+meta_clear_one_candidate(
+ struct metasingleconn *lsc,
+ int reallyclean
+)
+{
+ lsc->candidate = META_NOT_CANDIDATE;
+
+ if ( !reallyclean ) {
+ return 0;
+ }
+
+ if ( lsc->ld ) {
+ ldap_unbind( lsc->ld );
+ lsc->ld = NULL;
+ }
+
+ if ( lsc->bound_dn != NULL ) {
+ free( lsc->bound_dn );
+ lsc->bound_dn = NULL;
+ }
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-meta.h"
+
+int
+meta_back_compare(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn,
+ AttributeAssertion *ava
+)
+{
+ struct metainfo *li = ( struct metainfo * )be->be_private;
+ struct metaconn *lc;
+ struct metasingleconn **lsc;
+ char *match = NULL, *err = NULL, *mmatch = NULL;
+ int candidates = 0, last = 0, i, count, rc, cres, rres;
+ int *msgid;
+
+ lc = meta_back_getconn( li, conn, op, META_OP_ALLOW_MULTIPLE,
+ ndn, NULL );
+ if ( !lc || !meta_back_dobind( lc, op ) ) {
+ return -1;
+ }
+
+ msgid = ch_calloc( sizeof( int ), li->ntargets );
+ if ( msgid == NULL ) {
+ return -1;
+ }
+
+ /*
+ * start an asynchronous compare for each candidate target
+ */
+ for ( i = 0, lsc = lc->conns; lsc[ 0 ] != NULL; ++i, ++lsc ) {
+ char *mdn = NULL;
+ char *mapped_attr = ava->aa_desc->ad_cname->bv_val;
+ char *mapped_value = ava->aa_value->bv_val;
+
+ if ( lsc[ 0 ]->candidate != META_CANDIDATE ) {
+ continue;
+ }
+
+ /*
+ * Rewrite the compare dn, if needed
+ */
+ switch ( rewrite_session( li->targets[ i ]->rwinfo,
+ "compareDn", dn, conn, &mdn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mdn == NULL ) {
+ mdn = ( char * )dn;
+ }
+ Debug( LDAP_DEBUG_ARGS,
+ "rw> compareDn: \"%s\" -> \"%s\"\n%s",
+ dn, mdn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform",
+ NULL, NULL );
+
+ case REWRITE_REGEXEC_ERR:
+ return -1;
+ }
+
+ /*
+ * if attr is objectClass, try to remap the value
+ */
+ if ( ava->aa_desc->ad_type->sat_oid
+ == slap_schema.si_ad_objectClass->ad_type->sat_oid ) {
+ mapped_value = ldap_back_map( &li->targets[ i ]->oc_map,
+ ava->aa_value->bv_val, 0 );
+
+ if ( mapped_value == NULL ) {
+ lsc[ 0 ]->candidate = META_NOT_CANDIDATE;
+ continue;
+ }
+ /*
+ * else try to remap the attribute
+ */
+ } else {
+ mapped_attr = ldap_back_map( &li->targets[ i ]->at_map,
+ ava->aa_desc->ad_cname->bv_val, 0 );
+ if ( mapped_attr == NULL ) {
+ lsc[ 0 ]->candidate = META_NOT_CANDIDATE;
+ continue;
+ }
+ }
+
+ /*
+ * the compare op is spawned across the targets and the first
+ * that returns determines the result; a constraint on unicity
+ * of the result ought to be enforced
+ */
+ msgid[ i ] = ldap_compare( lc->conns[ i ]->ld, mdn,
+ mapped_attr, mapped_value );
+ if ( msgid[ i ] == -1 ) {
+ lsc[ 0 ]->candidate = META_NOT_CANDIDATE;
+ continue;
+ }
+
+ if ( mdn != dn ) {
+ free( mdn );
+ }
+ if ( mapped_attr != ava->aa_desc->ad_cname->bv_val ) {
+ free( mapped_attr );
+ }
+ if ( mapped_value != ava->aa_value->bv_val ) {
+ free( mapped_value );
+ }
+
+ ++candidates;
+ }
+
+ /*
+ * wait for replies
+ */
+ for ( rc = 0, count = 0; candidates > 0; ) {
+
+ /*
+ * FIXME: should we check for abandon?
+ */
+ for ( i = 0, lsc = lc->conns; lsc[ 0 ] != NULL; lsc++, i++ ) {
+ int lrc;
+ LDAPMessage *res = NULL;
+
+ if ( lsc[ 0 ]->candidate != META_CANDIDATE ) {
+ continue;
+ }
+
+ lrc = ldap_result( lsc[ 0 ]->ld, msgid[ i ],
+ 0, NULL, &res );
+
+ if ( lrc == 0 ) {
+ /*
+ * FIXME: should we yield?
+ */
+ if ( res ) {
+ ldap_msgfree( res );
+ }
+ continue;
+ } else if ( lrc == LDAP_RES_COMPARE ) {
+ if ( count > 0 ) {
+ rres = LDAP_OPERATIONS_ERROR;
+ rc = -1;
+ goto finish;
+ }
+
+ cres = ldap_result2error( lsc[ 0 ]->ld,
+ res, 1 );
+ switch ( cres ) {
+ case LDAP_COMPARE_TRUE:
+ case LDAP_COMPARE_FALSE:
+
+ /*
+ * true or flase, got it;
+ * sending to cache ...
+ */
+ if ( li->cache.ttl != META_DNCACHE_DISABLED ) {
+ ( void )meta_dncache_update_entry( &li->cache, ch_strdup( ndn ), i );
+ }
+
+ count++;
+ rc = 0;
+ break;
+
+ default:
+ rres = ldap_back_map_result( cres );
+
+ if ( err != NULL ) {
+ free( err );
+ }
+ ldap_get_option( lsc[ 0 ]->ld,
+ LDAP_OPT_ERROR_STRING, &err );
+
+ if ( match != NULL ) {
+ free( match );
+ }
+ ldap_get_option( lsc[ 0 ]->ld,
+ LDAP_OPT_MATCHED_DN, &match );
+
+ last = i;
+ break;
+ }
+ lsc[ 0 ]->candidate = META_NOT_CANDIDATE;
+ --candidates;
+ } else {
+ lsc[ 0 ]->candidate = META_NOT_CANDIDATE;
+ --candidates;
+ if ( res ) {
+ ldap_msgfree( res );
+ }
+ break;
+ }
+ }
+ }
+
+finish:
+
+ /*
+ * Rewrite the matched portion of the search base, if required
+ *
+ * FIXME: only the last one gets caught!
+ */
+ if ( count == 1 ) {
+ if ( match != NULL ) {
+ free( match );
+ match = NULL;
+ }
+
+ /*
+ * the result of the compare is assigned to the res code
+ * that will be returned
+ */
+ rres = cres;
+
+ } else if ( match != NULL ) {
+
+ /*
+ * At least one compare failed with matched portion,
+ * and none was successful
+ */
+ switch ( rewrite_session( li->targets[ last ]->rwinfo,
+ "matchedDn", match, conn, &mmatch ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mmatch == NULL ) {
+ mmatch = ( char * )match;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> matchedDn:"
+ " \"%s\" -> \"%s\"\n%s",
+ match, mmatch, "" );
+ break;
+
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform",
+ NULL, NULL );
+ /* continue to the next case */
+
+ case REWRITE_REGEXEC_ERR:
+ rc = -1;
+ break;
+ }
+ }
+ send_ldap_result( conn, op, rres, mmatch, err, NULL, NULL );
+
+ if ( match != NULL ) {
+ if ( mmatch != match ) {
+ free( mmatch );
+ }
+ free( match );
+ }
+
+ if ( msgid ) {
+ free( msgid );
+ }
+
+ return rc;
+}
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-meta.h"
+
+extern int
+suffix_massage_config(
+ struct rewrite_info *info,
+ int argc,
+ char **argv
+);
+
+static struct metatarget *
+new_target( void )
+{
+ struct metatarget *lt;
+ struct ldapmapping *mapping;
+
+ lt = ch_calloc( sizeof( struct metatarget ), 1 );
+ if ( lt == NULL ) {
+ return NULL;
+ }
+
+ lt->rwinfo = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
+ if ( lt->rwinfo == NULL ) {
+ free( lt );
+ return NULL;
+ }
+
+ mapping = ch_calloc( 2, sizeof( struct ldapmapping ) );
+ if ( mapping == NULL ) {
+ free( lt );
+ return NULL;
+ }
+ mapping->src = ch_strdup( "objectClass" );
+ mapping->dst = ch_strdup( "objectClass" );
+ mapping[ 1 ].src = mapping->src;
+ mapping[ 1 ].dst = mapping->dst;
+
+ avl_insert( <->at_map.map, ( caddr_t )mapping,
+ mapping_cmp, mapping_dup );
+ avl_insert( <->at_map.remap, ( caddr_t )&mapping[ 1 ],
+ mapping_cmp, mapping_dup );
+
+ return lt;
+}
+
+int
+meta_back_db_config(
+ BackendDB *be,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv
+)
+{
+ struct metainfo *li = ( struct metainfo * )be->be_private;
+
+ if ( li == NULL ) {
+ fprintf( stderr,
+ "%s: line %d: meta backend info is null!\n",
+ fname, lineno );
+ return 1;
+ }
+
+ /* URI of server to query */
+ if ( strcasecmp( argv[ 0 ], "uri" ) == 0 ) {
+ int j, i = li->ntargets;
+ LDAPURLDesc *ludp;
+ char *last;
+
+ if ( argc != 2 ) {
+ fprintf( stderr,
+ "%s: line %d: missing address"
+ " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
+ fname, lineno );
+ return 1;
+ }
+
+ ++li->ntargets;
+
+ li->targets = ch_realloc( li->targets,
+ sizeof( struct metatarget *)*li->ntargets );
+ if ( li->targets == NULL ) {
+ fprintf( stderr,
+ "%s: line %d: out of memory while storing server name"
+ " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
+ fname, lineno );
+ return 1;
+ }
+
+ if ( ( li->targets[ i ] = new_target() ) == NULL ) {
+ fprintf( stderr,
+ "%s: line %d: unable to init server"
+ " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
+ fname, lineno );
+ return 1;
+ }
+
+ /*
+ * uri MUST be legal!
+ */
+ if ( ldap_url_parse( argv[ 1 ], &ludp ) != LDAP_SUCCESS ) {
+ fprintf( stderr,
+ "%s: line %d: unable to parse URI"
+ " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
+ fname, lineno );
+ return 1;
+ }
+
+ /*
+ * uri MUST have the <dn> part!
+ */
+ if ( ludp->lud_dn == NULL || ludp->lud_dn[ 0 ] == '\0' ) {
+ fprintf( stderr,
+ "%s: line %d: missing <naming context> "
+ " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
+ fname, lineno );
+ return 1;
+ }
+
+ /*
+ * copies and stores uri and suffix
+ */
+ li->targets[ i ]->suffix = ch_strdup( ludp->lud_dn );
+ li->targets[ i ]->uri = ch_strdup( argv[ 1 ] );
+ last = strstr( li->targets[ i ]->uri,
+ li->targets[ i ]->suffix );
+ assert( last != NULL );
+ last[ 0 ] = '\0'; /* wasting memory ... */
+
+ /*
+ * Need to store the suffix in normalized form
+ */
+ (void) dn_normalize( li->targets[ i ]->suffix );
+
+ /*
+ * uri MUST be a branch of suffix!
+ */
+#if 0 /* too strict a constraint */
+ if ( select_backend( li->targets[ i ]->suffix, 0 ) != be ) {
+ fprintf( stderr,
+ "%s: line %d: <naming context> of URI does not refer to current backend"
+ " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
+ fname, lineno );
+ return 1;
+ }
+#else
+ /*
+ * uri MUST be a branch of a suffix!
+ */
+ if ( select_backend( li->targets[ i ]->suffix, 0 ) == NULL ) {
+ fprintf( stderr,
+ "%s: line %d: <naming context> of URI does not resolve to a backend"
+ " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
+ fname, lineno );
+ return 1;
+ }
+#endif
+
+#if 0
+ /*
+ * uri MUST not be used by other URIs!
+ *
+ * FIXME: this limitation may be removed,
+ * or worked out, at least, in some manner
+ */
+ for ( j = 0; j < i-1; j++ ) {
+ if ( strcmp( li->targets[ i ]->suffix,
+ li->targets[ j ]->suffix ) == 0 ) {
+ fprintf( stderr,
+ "%s: line %d: naming context \"%s\" already used"
+ " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
+ fname, lineno, last+1 );
+ return 1;
+ }
+ }
+#endif
+
+ ldap_free_urldesc( ludp );
+
+ Debug( LDAP_DEBUG_CONFIG,
+ "==>meta_back_db_config: URI \"%s\", suffix \"%s\"%s\n",
+ li->targets[ i ]->uri, li->targets[ i ]->suffix, "" );
+
+ /* default target directive */
+ } else if ( strcasecmp( argv[ 0 ], "default-target" ) == 0 ) {
+ int i = li->ntargets-1;
+
+ if ( argc == 1 ) {
+ if ( i < 0 ) {
+ fprintf( stderr,
+ "%s: line %d: \"default-target\" alone need be"
+ " inside a \"uri\" directive\n",
+ fname, lineno );
+ return 1;
+ }
+ li->defaulttarget = i;
+ } else {
+ if ( strcasecmp( argv[ 1 ], "none" ) == 0 ) {
+ if ( i >= 0 ) {
+ fprintf( stderr,
+ "%s: line %d: \"default-target none\""
+ " should go before uri definitions\n",
+ fname, lineno );
+ }
+ li->defaulttarget = META_DEFAULT_TARGET_NONE;
+ } else {
+ int n = atoi( argv[ 1 ] );
+ if ( n < 1 || n >= i ) {
+ fprintf( stderr,
+ "%s: line %d: illegal target number %d\n",
+ fname, lineno, n );
+ return 1;
+ }
+ li->defaulttarget = n-1;
+ }
+ }
+
+ /* ttl of dn cache */
+ } else if ( strcasecmp( argv[ 0 ], "dncache-ttl" ) == 0 ) {
+ if ( argc != 2 ) {
+ fprintf( stderr,
+ "%s: line %d: missing ttl in \"dncache-ttl <ttl>\" line\n",
+ fname, lineno );
+ return 1;
+ }
+
+ if ( strcasecmp( argv[ 1 ], "forever" ) == 0 ) {
+ li->cache.ttl = META_DNCACHE_FOREVER;
+ } else if ( strcasecmp( argv[ 1 ], "disabled" ) == 0 ) {
+ li->cache.ttl = META_DNCACHE_DISABLED;
+ } else {
+ li->cache.ttl = atol( argv[ 1 ] );
+ }
+
+ /* name to use for meta_back_group */
+ } else if ( strcasecmp( argv[ 0 ], "binddn" ) == 0 ) {
+ int i = li->ntargets-1;
+
+ if ( i < 0 ) {
+ fprintf( stderr,
+ "%s: line %d: need \"uri\" directive first\n",
+ fname, lineno );
+ }
+
+ if ( argc != 2 ) {
+ fprintf( stderr,
+ "%s: line %d: missing name in \"binddn <name>\" line\n",
+ fname, lineno );
+ return 1;
+ }
+ li->targets[ i ]->binddn = ch_strdup( argv[ 1 ] );
+
+ /* password to use for meta_back_group */
+ } else if ( strcasecmp( argv[ 0 ], "bindpw" ) == 0 ) {
+ int i = li->ntargets-1;
+
+ if ( i < 0 ) {
+ fprintf( stderr,
+ "%s: line %d: need \"uri\" directive first\n",
+ fname, lineno );
+ }
+
+ if ( argc != 2 ) {
+ fprintf( stderr,
+ "%s: line %d: missing password in \"bindpw <password>\" line\n",
+ fname, lineno );
+ return 1;
+ }
+ li->targets[ i ]->bindpw = ch_strdup( argv[ 1 ] );
+
+ /* dn massaging */
+ } else if ( strcasecmp( argv[ 0 ], "suffixmassage" ) == 0 ) {
+ BackendDB *tmp_be;
+ int i = li->ntargets-1;
+
+ if ( i < 0 ) {
+ fprintf( stderr,
+ "%s: line %d: need \"uri\" directive first\n",
+ fname, lineno );
+ return 1;
+ }
+
+ /*
+ * syntax:
+ *
+ * suffixmassage <suffix> <massaged suffix>
+ *
+ * the <suffix> field must be defined as a valid suffix
+ * (or suffixAlias?) for the current database;
+ * the <massaged suffix> shouldn't have already been
+ * defined as a valid suffix or suffixAlias for the
+ * current server
+ */
+ if ( argc != 3 ) {
+ fprintf( stderr,
+ "%s: line %d: syntax is \"suffixMassage <suffix> <massaged suffix>\"\n",
+ fname, lineno );
+ return 1;
+ }
+
+ tmp_be = select_backend( argv[ 1 ], 0 );
+ if ( tmp_be != NULL && tmp_be != be ) {
+ fprintf( stderr,
+ "%s: line %d: suffix already in use by another backend in"
+ " \"suffixMassage <suffix> <massaged suffix>\"\n",
+ fname, lineno );
+ return 1;
+ }
+
+ tmp_be = select_backend( argv[ 2 ], 0 );
+ if ( tmp_be != NULL ) {
+ fprintf( stderr,
+ "%s: line %d: massaged suffix already in use by another backend in"
+ " \"suffixMassage <suffix> <massaged suffix>\"\n",
+ fname, lineno );
+ return 1;
+ }
+
+ /*
+ * The suffix massaging is emulated by means of the
+ * rewrite capabilities
+ * FIXME: no extra rewrite capabilities should be added
+ * to the database
+ */
+ return suffix_massage_config( li->targets[ i ]->rwinfo,
+ argc, argv );
+
+ /* rewrite stuff ... */
+ } else if ( strncasecmp( argv[ 0 ], "rewrite", 7 ) == 0 ) {
+ int i = li->ntargets-1;
+
+ if ( i < 0 ) {
+ fprintf( stderr,
+ "%s: line %d: need \"uri\" directive first\n",
+ fname, lineno );
+ }
+
+ return rewrite_parse( li->targets[ i ]->rwinfo, fname, lineno,
+ argc, argv );
+
+ /* objectclass/attribute mapping */
+ } else if ( strcasecmp( argv[ 0 ], "map" ) == 0 ) {
+ struct ldapmap *map;
+ struct ldapmapping *mapping;
+ char *src, *dst;
+ int i = li->ntargets-1;
+
+ if ( i < 0 ) {
+ fprintf( stderr,
+ "%s: line %d: need \"uri\" directive first\n",
+ fname, lineno );
+ }
+
+
+ if ( argc < 3 || argc > 4 ) {
+ fprintf( stderr,
+ "%s: line %d: syntax is \"map {objectclass | attribute} {<source> | *} [<dest> | *]\"\n",
+ fname, lineno );
+ return 1;
+ }
+
+ if ( strcasecmp( argv[ 1 ], "objectClass" ) == 0 ) {
+ map = &li->targets[ i ]->oc_map;
+ } else if ( strcasecmp( argv[ 1 ], "attribute" ) == 0 ) {
+ map = &li->targets[ i ]->at_map;
+ } else {
+ fprintf( stderr,
+ "%s: line %d: syntax is \"map {objectclass | attribute} {<source> | *} [<dest> | *]\"\n",
+ fname, lineno );
+ return 1;
+ }
+
+ if ( strcasecmp( argv[ 2 ], "*" ) != 0 ) {
+ src = argv[ 2 ];
+ if ( argc < 4 ) {
+ dst = "";
+ } else if ( strcasecmp( argv[ 3 ], "*" ) == 0 ) {
+ dst = src;
+ } else {
+ dst = argv[ 3 ];
+ }
+ } else {
+ if ( argc < 4 ) {
+ map->drop_missing = 1;
+ return 0;
+ }
+ if ( strcasecmp( argv[ 3 ], "*" ) == 0 ) {
+ map->drop_missing = 0;
+ return 0;
+ }
+
+ src = argv[ 3 ];
+ dst = src;
+ }
+
+ if ( ( map == &li->targets[ i ]->at_map )
+ && ( strcasecmp( src, "objectclass" ) == 0
+ || strcasecmp( dst, "objectclass" ) == 0 ) ) {
+ fprintf( stderr,
+ "%s: line %d: objectclass attribute cannot be mapped\n",
+ fname, lineno );
+ }
+
+ mapping = ch_calloc( 2, sizeof( struct ldapmapping ) );
+ if ( mapping == NULL ) {
+ fprintf( stderr,
+ "%s: line %d: out of memory\n",
+ fname, lineno );
+ return 1;
+ }
+ mapping->src = ch_strdup( src );
+ mapping->dst = ch_strdup( dst );
+ if ( *dst != 0 ) {
+ mapping[ 1 ].src = mapping->dst;
+ mapping[ 1 ].dst = mapping->src;
+ } else {
+ mapping[ 1 ].src = mapping->src;
+ mapping[ 1 ].dst = mapping->dst;
+ }
+
+ if ( avl_find( map->map, ( caddr_t )mapping,
+ mapping_cmp ) != NULL
+ || avl_find( map->remap, ( caddr_t )&mapping[ 1 ],
+ mapping_cmp ) != NULL) {
+ fprintf( stderr,
+ "%s: line %d: duplicate mapping found (ignored)\n",
+ fname, lineno );
+ return 0;
+ }
+
+ avl_insert( &map->map, ( caddr_t )mapping,
+ mapping_cmp, mapping_dup );
+ avl_insert( &map->remap, ( caddr_t )&mapping[ 1 ],
+ mapping_cmp, mapping_dup );
+
+ /* anything else */
+ } else {
+ fprintf( stderr,
+ "%s: line %d: unknown directive \"%s\" in meta database definition"
+ " (ignored)\n",
+ fname, lineno, argv[0] );
+ }
+ return 0;
+}
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
+
+#define AVL_INTERNAL
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-meta.h"
+
+/*
+ * Set PRINT_CONNTREE larger than 0 to dump the connection tree (debug only)
+ */
+#define PRINT_CONNTREE 0
+
+/*
+ * meta_back_conn_cmp
+ *
+ * compares two struct metaconn based on the value of the conn pointer;
+ * used by avl stuff
+ */
+int
+meta_back_conn_cmp(
+ const void *c1,
+ const void *c2
+ )
+{
+ struct metaconn *lc1 = ( struct metaconn * )c1;
+ struct metaconn *lc2 = ( struct metaconn * )c2;
+
+ return ( ( lc1->conn < lc2->conn ) ? -1 :
+ ( ( lc1->conn > lc2-> conn ) ? 1 : 0 ) );
+}
+
+/*
+ * meta_back_conn_dup
+ *
+ * returns -1 in case a duplicate struct metaconn has been inserted;
+ * used by avl stuff
+ */
+int
+meta_back_conn_dup(
+ void *c1,
+ void *c2
+ )
+{
+ struct metaconn *lc1 = ( struct metaconn * )c1;
+ struct metaconn *lc2 = ( struct metaconn * )c2;
+
+ return( ( lc1->conn == lc2->conn ) ? -1 : 0 );
+}
+
+/*
+ * Debug stuff (got it from libavl)
+ */
+#if PRINT_CONNTREE > 0
+static void
+ravl_print( Avlnode *root, int depth )
+{
+ int i;
+
+ if ( root == 0 ) {
+ return;
+ }
+
+ ravl_print( root->avl_right, depth+1 );
+
+ for ( i = 0; i < depth; i++ ) {
+ printf( " " );
+ }
+
+ printf( "c(%d) %d\n", ( ( struct metaconn * )root->avl_data )->conn->c_connid, root->avl_bf );
+
+ ravl_print( root->avl_left, depth+1 );
+}
+
+static void
+myprint( Avlnode *root )
+{
+ printf( "********\n" );
+
+ if ( root == 0 ) {
+ printf( "\tNULL\n" );
+ } else {
+ ravl_print( root, 0 );
+ }
+
+ printf( "********\n" );
+}
+#endif /* PRINT_CONNTREE */
+/*
+ * End of debug stuff
+ */
+
+/*
+ * metaconn_alloc
+ *
+ * Allocates a connection structure, making room for all the referenced targets
+ */
+static struct metaconn *
+metaconn_alloc( int ntargets )
+{
+ struct metaconn *lc;
+ int i;
+
+ assert( ntargets > 0 );
+
+ lc = ch_calloc( sizeof( struct metaconn ), 1 );
+ if ( lc == NULL ) {
+ return NULL;
+ }
+
+ /*
+ * make it a null-terminated array ...
+ */
+ lc->conns = ch_calloc( sizeof( struct metasingleconn * ), ntargets+1 );
+ if ( lc->conns == NULL ) {
+ free( lc );
+ return NULL;
+ }
+
+ for ( i = 0; i < ntargets; i++ ) {
+ lc->conns[ i ] =
+ ch_calloc( sizeof( struct metasingleconn ), 1 );
+ if ( lc->conns[ i ] == NULL ) {
+ charray_free( ( char ** )lc->conns );
+ free( lc->conns );
+ free( lc );
+ return NULL;
+ }
+ }
+
+ lc->bound_target = -1;
+
+ return lc;
+}
+
+/*
+ * metaconn_free
+ *
+ * clears a metaconn
+ */
+static void
+metaconn_free(
+ struct metaconn *lc
+)
+{
+ if ( !lc ) {
+ return;
+ }
+
+ if ( lc->conns ) {
+ int i;
+
+ for ( i = 0; lc->conns[ i ] != NULL; ++i ) {
+ free( lc->conns[ i ] );
+ }
+ charray_free( ( char ** )lc->conns );
+ }
+
+ free( lc );
+}
+
+/*
+ * init_one_conn
+ *
+ * Initializes one connection
+ */
+static int
+init_one_conn(
+ Connection *conn,
+ Operation *op,
+ struct metatarget *lt,
+ int vers,
+ struct metasingleconn *lsc
+ )
+{
+ int err;
+
+ /*
+ * Already init'ed
+ */
+ if ( lsc->ld != NULL ) {
+ return LDAP_SUCCESS;
+ }
+
+ /*
+ * Attempts to initialize the connection to the target ds
+ */
+ err = ldap_initialize( &lsc->ld, lt->uri );
+
+ /*
+ * In case of failure, the error is mapped back from client
+ * to server error code
+ */
+ if ( err != LDAP_SUCCESS ) {
+ return ldap_back_map_result( err );
+ }
+
+ /*
+ * Set LDAP version. This will always succeed: If the client
+ * bound with a particular version, then so can we.
+ */
+ ldap_set_option( lsc->ld, LDAP_OPT_PROTOCOL_VERSION, &vers );
+
+ /*
+ * Sets a cookie for the rewrite session
+ */
+ ( void )rewrite_session_init( lt->rwinfo, conn );
+
+ /*
+ * If the connection dn is not null, an attempt to rewrite it is made
+ */
+ if ( conn->c_cdn != NULL && conn->c_cdn[ 0 ] != '\0' ) {
+ /*
+ * Rewrite the bind dn if needed
+ */
+ lsc->bound_dn = NULL;
+ switch ( rewrite_session( lt->rwinfo, "bindDn",
+ conn->c_cdn, conn,
+ &lsc->bound_dn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( lsc->bound_dn == NULL ) {
+ lsc->bound_dn = ch_strdup( conn->c_cdn );
+ }
+ Debug( LDAP_DEBUG_ARGS,
+ "rw> bindDn: \"%s\" -> \"%s\"\n%s",
+ conn->c_cdn, lsc->bound_dn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op,
+ LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform",
+ NULL, NULL );
+ /* continues to the next case */
+
+ case REWRITE_REGEXEC_ERR:
+ return LDAP_OPERATIONS_ERROR;
+ }
+ } else {
+ lsc->bound_dn = NULL;
+ }
+
+ lsc->bound = META_UNBOUND;
+
+ /*
+ * The candidate is activated
+ */
+ lsc->candidate = META_CANDIDATE;
+ return LDAP_SUCCESS;
+}
+
+/*
+ * meta_back_getconn
+ *
+ * Prepares the connection structure
+ *
+ * FIXME: This function needs to receive some info on the type of operation
+ * it is invoked by, so that only the correct pool of candidate targets
+ * is initialized in case no connection was available yet.
+ *
+ * At present a flag that says whether the candidate target must be unique
+ * is passed; eventually an operation agent will be used.
+ */
+struct metaconn *
+meta_back_getconn(
+ struct metainfo *li,
+ Connection *conn,
+ Operation *op,
+ int op_type,
+ const char *ndn,
+ int *candidate
+ )
+{
+ struct metaconn *lc, lc_curr;
+ int vers, cached = -1, i = -1, err = LDAP_SUCCESS;
+ int new_conn = 0;
+
+ /* Searches for a metaconn in the avl tree */
+ lc_curr.conn = conn;
+ ldap_pvt_thread_mutex_lock( &li->conn_mutex );
+ lc = (struct metaconn *)avl_find( li->conntree,
+ (caddr_t)&lc_curr, meta_back_conn_cmp );
+ ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
+
+ /* Looks like we didn't get a bind. Open a new session... */
+ if ( !lc ) {
+ lc = metaconn_alloc( li->ntargets );
+ lc->conn = conn;
+ new_conn = 1;
+ }
+
+ vers = conn->c_protocol;
+
+ /*
+ * looks in cache, if any
+ */
+ if ( li->cache.ttl != META_DNCACHE_DISABLED ) {
+ cached = i = meta_dncache_get_target( &li->cache, ndn );
+ }
+
+ if ( op_type == META_OP_REQUIRE_SINGLE ) {
+
+ /*
+ * tries to get a unique candidate
+ * (takes care of default target
+ */
+ if ( i < 0 ) {
+ i = meta_back_select_unique_candidate( li, ndn );
+ }
+
+ /*
+ * if any is found, inits the connection
+ */
+ if ( i < 0 ) {
+ if ( new_conn ) {
+ metaconn_free( lc );
+ }
+
+ send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
+ NULL, "", NULL, NULL );
+
+ return NULL;
+ }
+
+
+ Debug( LDAP_DEBUG_CACHE,
+ "==>meta_back_getconn: got target %d for ndn=\"%s\" from cache\n%s",
+ i, ndn, "" );
+
+ /*
+ * Clear all other candidates
+ */
+ ( void )meta_clear_unused_candidates( li, lc, i, 0 );
+
+ /*
+ * The target is activated; if needed, it is
+ * also init'd
+ */
+ err = init_one_conn( conn, op, li->targets[ i ],
+ vers, lc->conns[ i ] );
+ if ( err != LDAP_SUCCESS ) {
+
+ /*
+ * FIXME: in case one target cannot
+ * be init'd, should the other ones
+ * be tried?
+ */
+ ( void )meta_clear_one_candidate( lc->conns[ i ], 1 );
+ if ( new_conn ) {
+ metaconn_free( lc );
+ }
+
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, "internal server error", NULL, NULL );
+
+ return NULL;
+ }
+
+ if ( candidate ) {
+ *candidate = i;
+ }
+
+ /*
+ * if no unique candidate ...
+ */
+ } else {
+ int ndnlen = strlen( ndn );
+ for ( i = 0; i < li->ntargets; i++ ) {
+ if ( i == cached
+ || meta_back_is_candidate( li->targets[ i ]->suffix,
+ ndn, ndnlen ) ) {
+
+ /*
+ * The target is activated; if needed, it is
+ * also init'd
+ */
+ int lerr = init_one_conn( conn, op,
+ li->targets[ i ],
+ vers, lc->conns[ i ] );
+ if ( lerr != LDAP_SUCCESS ) {
+
+ /*
+ * FIXME: in case one target cannot
+ * be init'd, should the other ones
+ * be tried?
+ */
+ ( void )meta_clear_one_candidate( lc->conns[ i ], 1 );
+ err = lerr;
+ continue;
+ }
+ }
+ }
+ }
+
+ if ( new_conn ) {
+
+ /*
+ * Inserts the newly created metaconn in the avl tree
+ */
+ ldap_pvt_thread_mutex_lock( &li->conn_mutex );
+ err = avl_insert( &li->conntree, ( caddr_t )lc,
+ meta_back_conn_cmp, meta_back_conn_dup );
+
+#if PRINT_CONNTREE > 0
+ myprint( li->conntree );
+#endif /* PRINT_CONNTREE */
+
+ ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
+
+ Debug( LDAP_DEBUG_TRACE,
+ "=>meta_back_getconn: conn %ld inserted\n%s%s",
+ lc->conn->c_connid, "", "" );
+
+ /*
+ * Err could be -1 in case a duplicate metaconn is inserted
+ */
+ if ( err != 0 ) {
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+ NULL, "internal server error", NULL, NULL );
+ metaconn_free( lc );
+ return NULL;
+ }
+ } else {
+ Debug( LDAP_DEBUG_TRACE,
+ "=>meta_back_getconn: conn %ld fetched\n%s%s",
+ lc->conn->c_connid, "", "" );
+ }
+
+ return lc;
+}
+
--- /dev/null
+dn: ou=People, dc=foo, dc=example, dc=com
+objectClass: top
+
+dn: cn=Ando, ou=People, dc=foo, dc=example, dc=com
+objectClass: top
+objectClass: person
+cn: Ando
+sn: Ando
+userPassword: ando
+
--- /dev/null
+dn: ou=People, dc=bar, dc=example, dc=com
+objectClass: top
+
+dn: cn=Ando, ou=People, dc=bar, dc=example, dc=com
+objectClass: top
+objectClass: person
+cn: Ando
+sn: Ando
+userPassword: ando
+
--- /dev/null
+dn: ou=Groups, dc=bar, dc=example, dc=com
+objectClass: top
+
+dn: cn=Users, ou=Groups, dc=bar, dc=example, dc=com
+objectClass: top
+objectClass: groupOfNames
+objectClass: simpleSecurityObject
+cn: Users
+member: cn=Users, ou=Groups, dc=bar, dc=example, dc=com
+member: cn=Ando, ou=People, dc=bar, dc=example, dc=com
+userPassword: users
--- /dev/null
+#!/bin/sh
+
+SRCDIR="../../../.."
+METADBDIR="./meta-db"
+SLAPADD="$SRCDIR/servers/slapd/tools/slapadd -v"
+
+ADDCONF="./slapd-meta-plain.conf"
+#ADDCONF="./slapd-meta-rewrite.conf"
+#ADDCONF="./slapd-ldap-rewrite.conf"
+
+LDAPADDCONF="./slapd-ldap-raw.conf"
+CONF="./slapd.conf"
+LDAPCONF="./slapd-ldap.conf"
+PORT=9876
+#DEBUG=-1
+DEBUG=0
+
+rm -rf $METADBDIR
+rm -f schema ucdata
+ln -s "$SRCDIR/servers/slapd/schema" .
+ln -s "$SRCDIR/libraries/liblunicode" ucdata
+for i in 1 2 3 ; do
+ echo "Feeding directory $i"
+ mkdir -p "$METADBDIR/$i"
+ $SLAPADD -f $ADDCONF -n $i -l meta-$i.ldif
+done
+
+sed "s/@PORT@/$PORT/" $ADDCONF > $CONF
+sed "s/@PORT@/$PORT/" $LDAPADDCONF > $LDAPCONF
+
+echo ""
+echo "After slapd started, try"
+echo ""
+echo " ldapsearch -x -H ldap://localhost:$PORT -b '' -s base namingContexts"
+echo ""
+echo "and browse the directory using the last base that appears;"
+echo "you may also try to bind as administrator of each subdirectory"
+echo "or as \"cn=Ando, ...\" with password \"ando\": notice what happens"
+echo "to attrs \"sn\" and \"cn\" of some entries based on the ACLs ..."
+echo ""
+
+echo "Starting slapd on port $PORT"
+$SRCDIR/servers/slapd/slapd -f $CONF -h "ldap://localhost:$PORT/" -d $DEBUG
+echo "Waiting 2 secs for everything to shut down ..."
+sleep 2
+
+#exit
+
+rm -rf $METADBDIR
+rm -f schema ucdata $CONF $LDAPCONF
+
--- /dev/null
+#######################################################################
+# ldap database with suffix massage definitions
+#######################################################################
+
+database ldap
+uri "ldap://localhost:@PORT@/"
+suffix "o=FB, c=US"
+suffixmassage "o=FB, c=US" "ou=Groups, dc=bar, dc=example, dc=com"
+lastmod off
+
+access to dn.regex="[^,]+,o=FB,c=US" attr=cn
+ by group.exact="cn=Users,o=FB,c=US" read
+ by group.exact="cn=Users,ou=Groups,dc=bar,dc=example,dc=com" read
+ by * none
+
--- /dev/null
+#
+# master slapd config -- for testing of ldap metadirectory rewrite
+#
+ucdata-path ./ucdata
+include ./schema/core.schema
+include ./schema/cosine.schema
+include ./schema/inetorgperson.schema
+#
+schemacheck off
+#
+pidfile ./meta-db/slapd.pid
+argsfile ./meta-db/slapd.args
+
+access to attr=userPassword
+ by anonymous auth
+ by self write
+
+access to dn.regex="[^,]+,ou=People,dc=[^,]+,o=Foo Bar,c=US" attr=sn
+ by group.exact="cn=Users,ou=Groups,dc=bar,o=Foo Bar,c=US" read
+ by * none
+
+access to dn.regex="[^,]+,ou=Groups,dc=[^,]+,o=Foo Bar,c=US" attr=cn
+ by group.exact="cn=Users,ou=Groups,dc=bar,o=Foo Bar,c=US" read
+ by * none
+
+#access to dn.regex="[^,]+,ou=Groups,dc=[^,]+,o=Foo Bar,c=US" attr=cn
+# by dnattr=member read
+# by * none
+
+access to *
+ by * read
+
+#######################################################################
+# ldbm database definitions
+#######################################################################
+
+include ./slapd-ldbm.conf
+
+#######################################################################
+# ldap database with suffix massage definitions
+#######################################################################
+
+include ./slapd-ldap.conf
+
--- /dev/null
+#
+# slapd config -- for testing of ldap metadirectory
+#
+
+#######################################################################
+# ldbm database definitions
+#######################################################################
+
+database ldbm
+suffix "ou=People, dc=foo, dc=example, dc=com"
+rootdn "cn=Root, ou=People, dc=foo, dc=example, dc=com"
+rootpw ldap
+directory ./meta-db/1
+lastmod on
+index objectClass pres,eq
+
+database ldbm
+suffix "ou=People, dc=bar, dc=example, dc=com"
+rootdn "cn=Root, ou=People, dc=bar, dc=example, dc=com"
+rootpw ldap
+directory ./meta-db/2
+index objectClass pres,eq
+
+database ldbm
+suffix "ou=Groups, dc=bar, dc=example, dc=com"
+rootdn "cn=Root, ou=Groups, dc=bar, dc=example, dc=com"
+rootpw ldap
+directory ./meta-db/3
+index objectClass pres,eq
+
--- /dev/null
+#
+# master slapd config -- for testing of ldap metadirectory
+#
+ucdata-path ./ucdata
+include ./schema/core.schema
+include ./schema/cosine.schema
+include ./schema/inetorgperson.schema
+#
+schemacheck off
+#
+pidfile ./meta-db/slapd.pid
+argsfile ./meta-db/slapd.args
+
+access to attr=userPassword
+ by anonymous auth
+ by self write
+
+access to *
+ by * read
+
+#######################################################################
+# ldbm database definitions
+#######################################################################
+
+include ./slapd-ldbm.conf
+
+#######################################################################
+# meta database definitions
+#######################################################################
+
+database meta
+suffix "dc=example, dc=com"
+dncache-ttl forever
+uri "ldap://localhost:@PORT@/ou=People, dc=foo, dc=example, dc=com"
+uri "ldap://localhost:@PORT@/ou=People, dc=bar, dc=example, dc=com"
+uri "ldap://localhost:@PORT@/ou=Groups, dc=bar, dc=example, dc=com"
+
+#######################################################################
+# ldap database with suffix massage definitions
+#######################################################################
+
+include ./slapd-ldap.conf
+
--- /dev/null
+#
+# master slapd config -- for testing of ldap metadirectory rewrite
+#
+ucdata-path ./ucdata
+include ./schema/core.schema
+include ./schema/cosine.schema
+include ./schema/inetorgperson.schema
+#
+schemacheck off
+#
+pidfile ./meta-db/slapd.pid
+argsfile ./meta-db/slapd.args
+
+access to attr=userPassword
+ by anonymous auth
+ by self write
+
+access to dn.regex="[^,]+,ou=People,dc=[^,]+,o=Foo Bar,c=US" attr=sn
+ by group.exact="cn=Users,ou=Groups,dc=bar,o=Foo Bar,c=US" read
+ by * none
+
+access to dn.regex="[^,]+,ou=Groups,dc=[^,]+,o=Foo Bar,c=US" attr=cn
+ by group.exact="cn=Users,ou=Groups,dc=bar,o=Foo Bar,c=US" read
+ by * none
+
+#access to dn.regex="[^,]+,ou=Groups,dc=[^,]+,o=Foo Bar,c=US" attr=cn
+# by dnattr=member read
+# by * none
+
+access to *
+ by * read
+
+#######################################################################
+# ldbm database definitions
+#######################################################################
+
+include ./slapd-ldbm.conf
+
+#######################################################################
+# meta database definitions
+#######################################################################
+
+database meta
+suffix "o=Foo Bar, c=US"
+dncache-ttl forever
+lastmod off
+
+uri "ldap://localhost:@PORT@/ou=People, dc=foo, o=Foo Bar, c=US"
+rewriteEngine on
+rewriteContext default
+rewriteRule "(.*)o=Foo Bar,[ ]?c=US" "%1dc=example, dc=com"
+rewriteContext searchResult
+rewriteRule "(.*)dc=example,[ ]?dc=com" "%1o=Foo Bar, c=US"
+rewriteContext searchFilter
+rewriteRule "(.*)member=([^)]+),o=Foo Bar,[ ]?c=US(.*)" "%1member=%2,dc=example,dc=com%3"
+
+uri "ldap://localhost:@PORT@/ou=People, dc=bar, o=Foo Bar, c=US"
+rewriteEngine on
+rewriteContext default
+rewriteRule "(.*)o=Foo Bar,[ ]?c=US" "%1dc=example, dc=com"
+rewriteContext searchResult
+rewriteRule "(.*)dc=example,[ ]?dc=com" "%1o=Foo Bar, c=US"
+rewriteContext searchFilter
+rewriteRule "(.*)member=([^)]+),o=Foo Bar,[ ]?c=US(.*)" "%1member=%2,dc=example,dc=com%3"
+default-target
+map attribute givenName sn
+
+uri "ldap://localhost:@PORT@/ou=Groups, dc=bar, o=Foo Bar, c=US"
+rewriteEngine on
+rewriteContext default
+rewriteRule "(.*)o=Foo Bar,[ ]?c=US" "%1dc=example, dc=com"
+rewriteContext searchResult
+rewriteRule "(.*)dc=example,[ ]?dc=com" "%1o=Foo Bar, c=US"
+rewriteContext searchFilter
+rewriteRule "(.*)member=([^)]+),o=Foo Bar,[ ]?c=US(.*)" "%1member=%2,dc=example,dc=com%3"
+
+#######################################################################
+# ldap database with suffix massage definitions
+#######################################################################
+
+include ./slapd-ldap.conf
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-meta.h"
+
+int
+meta_back_delete(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn
+)
+{
+ struct metainfo *li = ( struct metainfo * )be->be_private;
+ struct metaconn *lc;
+ int candidate = -1;
+
+ char *mdn = NULL;
+
+ lc = meta_back_getconn( li, conn, op, META_OP_REQUIRE_SINGLE,
+ ndn, &candidate );
+ if ( !lc || !meta_back_dobind( lc, op ) ) {
+ return -1;
+ }
+
+ /*
+ * Rewrite the compare dn, if needed
+ */
+ switch ( rewrite_session( li->targets[ candidate ]->rwinfo,
+ "deleteDn", dn, conn, &mdn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mdn == NULL ) {
+ mdn = ( char * )dn;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> deleteDn: \"%s\" -> \"%s\"\n%s",
+ dn, mdn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform", NULL, NULL );
+
+ case REWRITE_REGEXEC_ERR:
+ return( -1 );
+ }
+
+ ldap_delete_s( lc->conns[ candidate ]->ld, mdn );
+
+ if ( mdn != dn ) {
+ free( mdn );
+ }
+
+ return meta_back_op_result( lc, op );
+}
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-meta.h"
+
+/*
+ * The dncache, at present, maps an entry to the target that holds it.
+ */
+
+struct metadncacheentry {
+ char *dn;
+ int target;
+
+ time_t lastupdated;
+};
+
+/*
+ * meta_dncache_cmp
+ *
+ * compares two struct metadncacheentry; used by avl stuff
+ * FIXME: modify avl stuff to delete an entry based on cmp
+ * (e.g. when ttl expired?)
+ */
+int
+meta_dncache_cmp(
+ const void *c1,
+ const void *c2
+)
+{
+ struct metadncacheentry *cc1 = ( struct metadncacheentry * )c1;
+ struct metadncacheentry *cc2 = ( struct metadncacheentry * )c2;
+
+ /*
+ * case sensitive, because the dn MUST be normalized
+ */
+ return strcmp( cc1->dn, cc2->dn );
+}
+
+/*
+ * meta_dncache_dup
+ *
+ * returns -1 in case a duplicate struct metadncacheentry has been inserted;
+ * used by avl stuff
+ */
+int
+meta_dncache_dup(
+ void *c1,
+ void *c2
+)
+{
+ struct metadncacheentry *cc1 = ( struct metadncacheentry * )c1;
+ struct metadncacheentry *cc2 = ( struct metadncacheentry * )c2;
+
+ /*
+ * case sensitive, because the dn MUST be normalized
+ */
+ return ( strcmp( cc1->dn, cc2->dn ) == 0 ) ? -1 : 0;
+}
+
+/*
+ * meta_dncache_get_target
+ *
+ * returns the target a dn belongs to, or -1 in case the dn is not
+ * in the cache
+ */
+int
+meta_dncache_get_target(
+ struct metadncache *cache,
+ const char *ndn
+)
+{
+ struct metadncacheentry tmp_entry, *entry;
+ time_t curr_time;
+ int target = -1;
+
+ tmp_entry.dn = ( char * )ndn;
+ ldap_pvt_thread_mutex_lock( &cache->mutex );
+ entry = ( struct metadncacheentry * )avl_find( cache->tree,
+ ( caddr_t )&tmp_entry, meta_dncache_cmp );
+
+ if ( entry != NULL ) {
+
+ /*
+ * if cache->ttl < 0, cache never expires;
+ * if cache->ttl = 0 no cache is used; shouldn't get here
+ * else, cache is used with ttl
+ */
+ if ( cache->ttl < 0 ) {
+ target = entry->target;
+ } else {
+
+ /*
+ * Need mutex?
+ */
+ curr_time = time( NULL );
+
+ if ( entry->lastupdated+cache->ttl > curr_time ) {
+ target = entry->target;
+ }
+ }
+ }
+ ldap_pvt_thread_mutex_unlock( &cache->mutex );
+
+ return target;
+}
+
+/*
+ * meta_dncache_update_entry
+ *
+ * updates target and lastupdated of a struct metadncacheentry if exists,
+ * otherwise it gets created; returns -1 in case of error
+ */
+int
+meta_dncache_update_entry(
+ struct metadncache *cache,
+ const char *ndn,
+ int target
+)
+{
+ struct metadncacheentry *entry, tmp_entry;
+ time_t curr_time = 0L;
+ int err = 0;
+
+ /*
+ * if cache->ttl < 0, cache never expires;
+ * if cache->ttl = 0 no cache is used; shouldn't get here
+ * else, cache is used with ttl
+ */
+ if ( cache->ttl > 0 ) {
+
+ /*
+ * Need mutex?
+ */
+ curr_time = time( NULL );
+ }
+
+ tmp_entry.dn = ( char * )ndn;
+
+ ldap_pvt_thread_mutex_lock( &cache->mutex );
+ entry = ( struct metadncacheentry * )avl_find( cache->tree,
+ ( caddr_t )&tmp_entry, meta_dncache_cmp );
+
+ if ( entry != NULL ) {
+ entry->target = target;
+ entry->lastupdated = curr_time;
+ } else {
+ entry = ch_calloc( sizeof( struct metadncacheentry ), 1 );
+ if ( entry == NULL ) {
+ ldap_pvt_thread_mutex_unlock( &cache->mutex );
+ return -1;
+ }
+
+ entry->dn = ch_strdup( ndn );
+ if ( entry->dn == NULL ) {
+ ldap_pvt_thread_mutex_unlock( &cache->mutex );
+ return -1;
+ }
+ entry->target = target;
+ entry->lastupdated = curr_time;
+
+ err = avl_insert( &cache->tree, ( caddr_t )entry,
+ meta_dncache_cmp, meta_dncache_dup );
+ }
+ ldap_pvt_thread_mutex_unlock( &cache->mutex );
+
+ return err;
+}
+
+/*
+ * meta_dncache_update_entry
+ *
+ * updates target and lastupdated of a struct metadncacheentry if exists,
+ * otherwise it gets created; returns -1 in case of error
+ */
+int
+meta_dncache_delete_entry(
+ struct metadncache *cache,
+ const char *ndn
+)
+{
+ struct metadncacheentry *entry, tmp_entry;
+
+ tmp_entry.dn = ( char * )ndn;
+
+ ldap_pvt_thread_mutex_lock( &cache->mutex );
+ entry = avl_delete( &cache->tree, ( caddr_t )&tmp_entry,
+ meta_dncache_cmp );
+ ldap_pvt_thread_mutex_lock( &cache->mutex );
+
+ if ( entry != NULL ) {
+ meta_dncache_free( ( void * )entry );
+ }
+
+ return 0;
+}
+
+/*
+ * meta_dncache_free
+ *
+ * frees an entry
+ *
+ */
+void
+meta_dncache_free(
+ void *e
+)
+{
+ struct metadncacheentry *entry = ( struct metadncacheentry * )e;
+
+ free( entry->dn );
+}
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#ifndef META_EXTERNAL_H
+#define META_EXTERNAL_H
+
+LDAP_BEGIN_DECL
+
+extern int
+meta_back_initialize LDAP_P((
+ BackendInfo *bi
+));
+extern int
+meta_back_open LDAP_P((
+ BackendInfo *bi
+));
+extern int
+meta_back_close LDAP_P((
+ BackendInfo *bi
+));
+extern int
+meta_back_destroy LDAP_P((
+ BackendInfo *bi
+));
+extern int
+meta_back_db_init LDAP_P((
+ BackendDB *bd
+));
+extern int
+meta_back_db_destroy LDAP_P((
+ BackendDB *bd
+));
+extern int
+meta_back_db_config LDAP_P((
+ BackendDB *bd,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv
+));
+extern int
+meta_back_bind LDAP_P((
+ BackendDB *bd,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn,
+ int method,
+ struct berval *cred,
+ char** edn
+));
+extern int
+meta_back_conn_destroy LDAP_P((
+ BackendDB *bd,
+ Connection *conn
+));
+extern int
+meta_back_search LDAP_P((
+ BackendDB *bd,
+ Connection *conn,
+ Operation *op,
+ const char *base,
+ const char *nbase,
+ int scope,
+ int deref,
+ int sizelimit,
+ int timelimit,
+ Filter *filter,
+ const char *filterstr,
+ char **attrs,
+ int attrsonly
+));
+extern int
+meta_back_compare LDAP_P((
+ BackendDB *bd,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn,
+ AttributeAssertion *ava
+));
+extern int
+meta_back_modify LDAP_P((
+ BackendDB *bd,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn,
+ Modifications *ml
+));
+extern int
+meta_back_modrdn LDAP_P((
+ BackendDB *bd,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn,
+ const char *newrdn,
+ int deleteoldrdn,
+ const char *newSuperior
+));
+extern int
+meta_back_add LDAP_P((
+ BackendDB *bd,
+ Connection *conn,
+ Operation *op,
+ Entry *e
+));
+extern int
+meta_back_delete LDAP_P((
+ BackendDB *bd,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn
+));
+extern int meta_back_abandon LDAP_P((
+ BackendDB *bd,
+ Connection *conn,
+ Operation *op,
+ int msgid
+));
+extern int meta_back_group LDAP_P((
+ BackendDB *bd,
+ Connection *conn,
+ Operation *op,
+ Entry *target,
+ const char* gr_ndn,
+ const char* op_ndn,
+ ObjectClass* group_oc,
+ AttributeDescription*
+ group_at
+));
+extern int
+meta_back_attribute LDAP_P((
+ BackendDB *bd,
+ Connection *conn,
+ Operation *op,
+ Entry *target,
+ const char* e_ndn,
+ AttributeDescription* entry_at,
+ struct berval ***vals
+));
+
+LDAP_END_DECL
+
+#endif /* META_EXTERNAL_H */
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-meta.h"
+
+
+/* return 0 IFF op_dn is a value in group_at (member) attribute
+ * of entry with gr_dn AND that entry has an objectClass
+ * value of group_oc (groupOfNames)
+ */
+int
+meta_back_group(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ Entry *target,
+ const char *gr_ndn,
+ const char *op_ndn,
+ ObjectClass *group_oc,
+ AttributeDescription *group_at
+)
+{
+ struct metainfo *li = ( struct metainfo * )be->be_private;
+ int rc = 1, candidate;
+ Attribute *attr;
+ struct berval bv;
+
+ AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass;
+ LDAPMessage *result;
+ char *gattr[ 2 ];
+ char *filter;
+ LDAP *ld;
+ char *mop_ndn, *mgr_ndn;
+
+ char *group_oc_name = NULL;
+ char *group_at_name = group_at->ad_cname->bv_val;
+
+ if ( group_oc->soc_names && group_oc->soc_names[ 0 ] ) {
+ group_oc_name = group_oc->soc_names[ 0 ];
+ } else {
+ group_oc_name = group_oc->soc_oid;
+ }
+
+ if ( target != NULL && strcmp( target->e_ndn, gr_ndn ) == 0 ) {
+ /* we already have a copy of the entry */
+ /* attribute and objectclass mapping has already been done */
+
+ /*
+ * first we need to check if the objectClass attribute
+ * has been retrieved; otherwise we need to repeat the search
+ */
+ attr = attr_find( target->e_attrs, ad_objectClass );
+ if ( attr != NULL ) {
+
+ /*
+ * Now we can check for the group objectClass value
+ */
+ if ( !is_entry_objectclass( target, group_oc ) ) {
+ return 1;
+ }
+
+ /*
+ * This part has been reworked: the group attr compare
+ * fails only if the attribute is PRESENT but the value
+ * is NOT PRESENT; if the attribute is NOT PRESENT, the
+ * search must be repeated as well.
+ * This may happen if a search for an entry has already
+ * been performed (target is not null) but the group
+ * attribute has not been required
+ */
+ attr = attr_find( target->e_attrs, group_at );
+ if ( attr != NULL ) {
+ bv.bv_val = ( char * )op_ndn;
+ bv.bv_len = strlen( op_ndn );
+ rc = value_find( group_at, attr->a_vals, &bv );
+ if ( rc != LDAP_SUCCESS ) {
+ return 1;
+ }
+ return 0;
+ } /* else: repeat the search */
+ } /* else: repeat the search */
+ } /* else: do the search */
+
+ candidate = meta_back_select_unique_candidate( li, gr_ndn );
+ if ( candidate == -1 ) {
+ return 1;
+ }
+
+ /*
+ * Rewrite the op ndn if needed
+ */
+ switch ( rewrite_session( li->targets[ candidate ]->rwinfo, "bindDn",
+ op_ndn, conn, &mop_ndn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mop_ndn == NULL ) {
+ mop_ndn = ( char * )op_ndn;
+ }
+ Debug( LDAP_DEBUG_ARGS,
+ "rw> bindDn (op ndn in group):"
+ " \"%s\" -> \"%s\"\n%s",
+ op_ndn, mop_ndn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ /* continues to next case */
+
+ case REWRITE_REGEXEC_ERR:
+ return 1;
+ }
+
+ /*
+ * Rewrite the gr ndn if needed
+ */
+ switch ( rewrite_session( li->targets[ candidate ]->rwinfo,
+ "searchBase",
+ gr_ndn, conn, &mgr_ndn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mgr_ndn == NULL ) {
+ mgr_ndn = ( char * )gr_ndn;
+ }
+ Debug( LDAP_DEBUG_ARGS,
+ "rw> searchBase (gr ndn in group):"
+ " \"%s\" -> \"%s\"\n%s",
+ gr_ndn, mgr_ndn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ /* continues to next case */
+
+ case REWRITE_REGEXEC_ERR:
+ return 1;
+ }
+
+ group_oc_name = ldap_back_map( &li->targets[ candidate ]->oc_map,
+ group_oc_name, 0 );
+ if ( group_oc_name == NULL ) {
+ return 1;
+ }
+ group_at_name = ldap_back_map( &li->targets[ candidate ]->at_map,
+ group_at_name, 0 );
+ if ( group_at_name == NULL ) {
+ return 1;
+ }
+
+ filter = ch_malloc( sizeof( "(&(objectclass=)(=))" )
+ + strlen( group_oc_name )
+ + strlen( group_at_name )
+ + strlen( mop_ndn ) + 1 );
+ if ( filter == NULL ) {
+ goto cleanup;
+ }
+
+ rc = ldap_initialize( &ld, li->targets[ candidate ]->uri );
+ if ( rc != LDAP_SUCCESS ) {
+ goto cleanup;
+ }
+
+ rc = ldap_bind_s( ld, li->targets[ candidate ]->binddn,
+ li->targets[ candidate ]->bindpw, LDAP_AUTH_SIMPLE );
+ if ( rc != LDAP_SUCCESS ) {
+ goto cleanup;
+ }
+
+ strcpy( filter, "(&(objectclass=" );
+ strcat( filter, group_oc_name );
+ strcat( filter, ")(" );
+ strcat( filter, group_at_name );
+ strcat( filter, "=" );
+ strcat( filter, mop_ndn );
+ strcat( filter, "))" );
+
+ gattr[ 0 ] = "objectclass";
+ gattr[ 1 ] = NULL;
+ rc = 1;
+ if ( ldap_search_ext_s( ld, mgr_ndn, LDAP_SCOPE_BASE, filter,
+ gattr, 0, NULL, NULL, LDAP_NO_LIMIT,
+ LDAP_NO_LIMIT, &result ) == LDAP_SUCCESS ) {
+ if ( ldap_first_entry( ld, result ) != NULL ) {
+ rc = 0;
+ }
+ ldap_msgfree( result );
+ }
+
+cleanup:
+ if ( ld != NULL ) {
+ ldap_unbind( ld );
+ }
+ if ( filter != NULL ) {
+ ch_free( filter );
+ }
+ if ( mop_ndn != op_ndn ) {
+ free( mop_ndn );
+ }
+ if ( mgr_ndn != gr_ndn ) {
+ free( mgr_ndn );
+ }
+
+ return rc;
+}
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-meta.h"
+
+#ifdef SLAPD_META_DYNAMIC
+
+int
+back_meta_LTX_init_module( int argc, char *argv[] ) {
+ BackendInfo bi;
+
+ memset( &bi, '\0', sizeof( bi ) );
+ bi.bi_type = "meta";
+ bi.bi_init = meta_back_initialize;
+
+ backend_add( &bi );
+ return 0;
+}
+
+#endif /* SLAPD_META_DYNAMIC */
+
+int
+meta_back_initialize(
+ BackendInfo *bi
+)
+{
+ bi->bi_open = 0;
+ bi->bi_config = 0;
+ bi->bi_close = 0;
+ bi->bi_destroy = 0;
+
+ bi->bi_db_init = meta_back_db_init;
+ bi->bi_db_config = meta_back_db_config;
+ bi->bi_db_open = 0;
+ bi->bi_db_close = 0;
+ bi->bi_db_destroy = meta_back_db_destroy;
+
+ bi->bi_op_bind = meta_back_bind;
+ bi->bi_op_unbind = 0;
+ bi->bi_op_search = meta_back_search;
+ bi->bi_op_compare = meta_back_compare;
+ bi->bi_op_modify = meta_back_modify;
+ bi->bi_op_modrdn = meta_back_modrdn;
+ bi->bi_op_add = meta_back_add;
+ bi->bi_op_delete = meta_back_delete;
+ bi->bi_op_abandon = 0;
+
+ bi->bi_extended = 0;
+
+ bi->bi_acl_group = meta_back_group;
+ bi->bi_acl_attribute = meta_back_attribute;
+ bi->bi_chk_referrals = 0;
+
+ bi->bi_connection_init = 0;
+ bi->bi_connection_destroy = meta_back_conn_destroy;
+
+ return 0;
+}
+
+int
+meta_back_db_init(
+ Backend *be
+)
+{
+ struct metainfo *li;
+
+ li = ch_calloc( 1, sizeof( struct metainfo ) );
+ if ( li == NULL ) {
+ return -1;
+ }
+
+ /*
+ * At present the default is no default target;
+ * this may change
+ */
+ li->defaulttarget = META_DEFAULT_TARGET_NONE;
+
+ ldap_pvt_thread_mutex_init( &li->conn_mutex );
+ ldap_pvt_thread_mutex_init( &li->cache.mutex );
+ be->be_private = li;
+
+ return 0;
+}
+
+static void
+conn_free(
+ struct metaconn *lc
+)
+{
+ struct metasingleconn **lsc;
+
+ for ( lsc = lc->conns; lsc[ 0 ] != NULL; lsc++ ) {
+ if ( lsc[ 0 ]->ld != NULL ) {
+ ldap_unbind( lsc[ 0 ]->ld );
+ }
+ if ( lsc[ 0 ]->bound_dn ) {
+ free( lsc[ 0 ]->bound_dn );
+ }
+ free( lsc[ 0 ] );
+ }
+ free( lc->conns );
+ free( lc );
+}
+
+static void
+target_free(
+ struct metatarget *lt
+)
+{
+ if ( lt->uri ) {
+ free( lt->uri );
+ }
+ if ( lt->binddn ) {
+ free( lt->binddn );
+ }
+ if ( lt->bindpw ) {
+ free( lt->bindpw );
+ }
+ if ( lt->rwinfo ) {
+ rewrite_info_delete( lt->rwinfo );
+ }
+ avl_free( lt->oc_map.remap, NULL );
+ avl_free( lt->oc_map.map, ( AVL_FREE )mapping_free );
+ avl_free( lt->at_map.remap, NULL );
+ avl_free( lt->at_map.map, ( AVL_FREE )mapping_free );
+}
+
+int
+meta_back_db_destroy(
+ Backend *be
+)
+{
+ struct metainfo *li;
+
+ if ( be->be_private ) {
+ int i;
+
+ li = ( struct metainfo * )be->be_private;
+
+ /*
+ * Destroy the connection tree
+ */
+ ldap_pvt_thread_mutex_lock( &li->conn_mutex );
+
+ if ( li->conntree ) {
+ avl_free( li->conntree,
+ ( AVL_FREE )conn_free );
+ }
+
+ ldap_pvt_thread_mutex_unlock( &li->cache.mutex );
+ ldap_pvt_thread_mutex_destroy( &li->cache.mutex );
+
+ /*
+ * Destroy the per-target stuff (assuming there's at
+ * least one ...)
+ */
+ for ( i = 0; i < li->ntargets; i++ ) {
+ target_free( li->targets[ i ] );
+ free( li->targets[ i ] );
+ }
+
+ free( li->targets );
+
+ ldap_pvt_thread_mutex_lock( &li->cache.mutex );
+ if ( li->cache.tree ) {
+ avl_free( li->cache.tree,
+ ( AVL_FREE )meta_dncache_free );
+ }
+
+ ldap_pvt_thread_mutex_unlock( &li->cache.mutex );
+ ldap_pvt_thread_mutex_destroy( &li->cache.mutex );
+
+
+ }
+
+ free( be->be_private );
+ return 0;
+}
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-meta.h"
+
+int
+meta_back_modify(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn,
+ Modifications *modlist
+)
+{
+ struct metainfo *li = ( struct metainfo * )be->be_private;
+ struct metaconn *lc;
+ LDAPMod **modv;
+ LDAPMod *mods;
+ Modifications *ml;
+ int candidate = -1, i;
+ char *mdn, *mapped;
+
+ lc = meta_back_getconn( li, conn, op, META_OP_REQUIRE_SINGLE,
+ ndn, &candidate );
+ if ( !lc || !meta_back_dobind( lc, op ) ) {
+ return -1;
+ }
+
+ /*
+ * Rewrite the modify dn, if needed
+ */
+ switch ( rewrite_session( li->targets[ candidate ]->rwinfo,
+ "modifyDn", dn, conn, &mdn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mdn == NULL ) {
+ mdn = ( char * )dn;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> modifyDN: \"%s\" -> \"%s\"\n%s",
+ dn, mdn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform", NULL, NULL );
+
+ case REWRITE_REGEXEC_ERR:
+ return( -1 );
+ }
+
+ for ( i = 0, ml = modlist; ml; i++ ,ml = ml->sml_next )
+ ;
+
+ mods = ch_malloc( sizeof( LDAPMod )*i );
+ if ( mods == NULL ) {
+ if ( mdn != dn ) {
+ free( mdn );
+ }
+ return -1;
+ }
+ modv = ( LDAPMod ** )ch_malloc( ( i + 1 )*sizeof( LDAPMod * ) );
+ if ( modv == NULL ) {
+ free( mods );
+ if ( mdn != dn ) {
+ free( mdn );
+ }
+ return -1;
+ }
+
+ for ( i = 0, ml = modlist; ml; ml = ml->sml_next ) {
+ /*
+ * lastmod should always be <off>
+ */
+#if 0
+ if ( !strcasecmp( a->a_desc->ad_cname->bv_val,
+ slap_schema.si_ad_creatorsName->ad_cname->bv_val )
+ || !strcasecmp( a->a_desc->ad_cname->bv_val,
+ slap_schema.si_ad_createTimestamp->ad_cname->bv_val )
+ || !strcasecmp( a->a_desc->ad_cname->bv_val,
+ slap_schema.si_ad_modifiersName->ad_cname->bv_val )
+ || !strcasecmp( a->a_desc->ad_cname->bv_val,
+ slap_schema.si_ad_modifyTimestamp->ad_cname->bv_val ) ) {
+ continue;
+ }
+#endif
+
+ mapped = ldap_back_map( &li->targets[ candidate ]->at_map,
+ ml->sml_desc->ad_cname->bv_val, 0 );
+ if ( mapped == NULL ) {
+ continue;
+ }
+
+ modv[ i ] = &mods[ i ];
+ mods[ i ].mod_op = ml->sml_op | LDAP_MOD_BVALUES;
+ mods[ i ].mod_type = mapped;
+
+ /*
+ * FIXME: dn-valued attrs should be rewritten
+ * to allow their use in ACLs at the back-ldap
+ * level.
+ */
+ if ( strcmp( ml->sml_desc->ad_type->sat_syntax->ssyn_oid,
+ SLAPD_DN_SYNTAX ) == 0 ) {
+ ldap_dnattr_rewrite(
+ li->targets[ candidate ]->rwinfo,
+ ml->sml_bvalues, conn );
+ }
+
+ mods[ i ].mod_bvalues = ml->sml_bvalues;
+ i++;
+ }
+ modv[ i ] = 0;
+
+ ldap_modify_s( lc->conns[ candidate ]->ld, mdn, modv );
+
+ if ( mdn != dn ) {
+ free( mdn );
+ }
+ free( mods );
+ free( modv );
+ return meta_back_op_result( lc, op );
+}
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-meta.h"
+
+int
+meta_back_modrdn(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn,
+ const char *newrdn,
+ int deleteoldrdn,
+ const char *newSuperior
+)
+{
+ struct metainfo *li = ( struct metainfo * )be->be_private;
+ struct metaconn *lc;
+ int candidate = -1;
+
+ char *mdn = NULL, *mnewSuperior = NULL;
+
+ lc = meta_back_getconn( li, conn, op, META_OP_REQUIRE_SINGLE,
+ ndn, &candidate );
+ if ( !lc || !meta_back_dobind( lc, op ) ) {
+ return -1;
+ }
+
+ if ( newSuperior ) {
+ int nsCandidate, version = LDAP_VERSION3;
+
+ nsCandidate = meta_back_select_unique_candidate( li,
+ newSuperior );
+
+ if ( nsCandidate != candidate ) {
+ /*
+ * FIXME: one possibility is to delete the entry
+ * from one target and add it to the other;
+ * unfortunately we'd need write access to both,
+ * which is nearly impossible; for administration
+ * needs, the rootdn of the metadirectory could
+ * be mapped to an administrative account on each
+ * target (the binddn?); we'll see.
+ */
+ /*
+ * FIXME: is this the correct return code?
+ */
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform",
+ NULL, NULL );
+ return -1;
+ }
+
+ ldap_set_option( lc->conns[ nsCandidate ]->ld,
+ LDAP_OPT_PROTOCOL_VERSION, &version );
+
+ /*
+ * Rewrite the new superior, if defined and required
+ */
+ switch ( rewrite_session( li->targets[ nsCandidate ]->rwinfo,
+ "newSuperiorDn",
+ newSuperior, conn, &mnewSuperior ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mnewSuperior == NULL ) {
+ mnewSuperior = ( char * )newSuperior;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> newSuperiorDn:"
+ " \"%s\" -> \"%s\"\n%s",
+ newSuperior, mnewSuperior, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform",
+ NULL, NULL );
+
+ case REWRITE_REGEXEC_ERR:
+ return( -1 );
+ }
+ }
+
+ /*
+ * Rewrite the modrdn dn, if required
+ */
+ switch ( rewrite_session( li->targets[ candidate ]->rwinfo,
+ "modrDn", dn, conn, &mdn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mdn == NULL ) {
+ mdn = ( char * )dn;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> modrDn: \"%s\" -> \"%s\"\n%s",
+ dn, mdn, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform", NULL, NULL );
+
+ case REWRITE_REGEXEC_ERR:
+ return( -1 );
+ }
+
+ ldap_rename2_s( lc->conns[ candidate ]->ld, mdn, newrdn,
+ mnewSuperior, deleteoldrdn );
+
+ if ( mdn != dn ) {
+ free( mdn );
+ }
+ if ( mnewSuperior != NULL && mnewSuperior != newSuperior ) {
+ free( mnewSuperior );
+ }
+
+ return meta_back_op_result( lc, op );
+}
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/time.h>
+
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-meta.h"
+#include "ldap_pvt.h"
+
+static void
+meta_send_entry(
+ Backend *be,
+ Operation *op,
+ struct metaconn *lc,
+ int i,
+ LDAPMessage *e,
+ char **attrs,
+ int attrsonly
+);
+
+static int
+is_one_level_rdn(
+ const char *rdn,
+ int len
+);
+
+int
+meta_back_search(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ const char *base,
+ const char *nbase,
+ int scope,
+ int deref,
+ int size,
+ int time,
+ Filter *filter,
+ const char *filterstr,
+ char **attrs,
+ int attrsonly
+)
+{
+ struct metainfo *li = ( struct metainfo * )be->be_private;
+ struct metaconn *lc;
+ struct metasingleconn **lsc;
+ struct timeval tv;
+ LDAPMessage *res, *e;
+ int count, rc = 0, *msgid, sres = LDAP_NO_SUCH_OBJECT;
+ char *match = NULL, *err = NULL;
+ char *mbase = NULL, *mfilter = NULL, *mmatch = NULL,
+ *mapped_filter = NULL, **mapped_attrs = NULL;
+
+ int i, last = 0, candidates = 0, nbaselen, op_type;
+
+ if ( scope == LDAP_SCOPE_BASE ) {
+ op_type = META_OP_REQUIRE_SINGLE;
+ } else {
+ op_type = META_OP_ALLOW_MULTIPLE;
+ }
+
+ lc = meta_back_getconn( li, conn, op, op_type, nbase, NULL );
+ if ( !lc || !meta_back_dobind( lc, op ) ) {
+ return -1;
+ }
+
+ /*
+ * Array of message id of each target
+ */
+ msgid = ch_calloc( sizeof( int ), li->ntargets );
+ if ( msgid == NULL ) {
+ return -1;
+ }
+
+ nbaselen = strlen( nbase );
+
+ /*
+ * Inits searches
+ */
+ for ( i = 0, lsc = lc->conns; lsc[ 0 ] != NULL; ++i, ++lsc ) {
+ char *realbase = ( char * )base;
+ int realscope = scope;
+ int suffixlen;
+
+ if ( lsc[ 0 ]->candidate != META_CANDIDATE ) {
+ continue;
+ }
+
+ if ( deref != -1 ) {
+ ldap_set_option( lsc[ 0 ]->ld, LDAP_OPT_DEREF,
+ ( void * )&deref);
+ }
+ if ( time != -1 ) {
+ ldap_set_option( lsc[ 0 ]->ld, LDAP_OPT_TIMELIMIT,
+ ( void * )&time);
+ }
+ if ( size != -1 ) {
+ ldap_set_option( lsc[ 0 ]->ld, LDAP_OPT_SIZELIMIT,
+ ( void * )&size);
+ }
+
+ /*
+ * modifies the base according to the scope, if required
+ */
+ suffixlen = strlen( li->targets[ i ]->suffix );
+ if ( suffixlen > nbaselen ) {
+ switch ( scope ) {
+ case LDAP_SCOPE_SUBTREE:
+ /*
+ * make the target suffix the new base
+ */
+ realbase = li->targets[ i ]->suffix;
+ break;
+
+ case LDAP_SCOPE_ONELEVEL:
+ if ( is_one_level_rdn( li->targets[ i ]->suffix,
+ suffixlen-nbaselen-1) ) {
+ /*
+ * if there is exactly one level,
+ * make the target suffix the new
+ * base, and make scope "base"
+ */
+ realbase = li->targets[ i ]->suffix;
+ realscope = LDAP_SCOPE_BASE;
+ break;
+ } /* else continue with the next case */
+
+ case LDAP_SCOPE_BASE:
+ /*
+ * this target is no longer candidate
+ */
+ lsc[ 0 ]->candidate = META_NOT_CANDIDATE;
+ continue;
+ // rc = meta_back_op_result(lc, op);
+ // goto finish;
+ }
+
+ }
+
+ /*
+ * Rewrite the search base, if required
+ */
+ switch ( rewrite_session( li->targets[ i ]->rwinfo,
+ "searchBase",
+ realbase, conn, &mbase ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mbase == NULL ) {
+ mbase = realbase;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> searchBase: \"%s\" -> \"%s\"\n%s",
+ base, mbase, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform",
+ NULL, NULL );
+ /* continue to the next case */
+
+ case REWRITE_REGEXEC_ERR:
+ rc = -1;
+ goto finish;
+ }
+
+ /*
+ * Rewrite the search filter, if required
+ */
+ switch ( rewrite_session( li->targets[ i ]->rwinfo,
+ "searchFilter",
+ filterstr, conn, &mfilter ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mfilter == NULL || mfilter[ 0 ] == '\0') {
+ if ( mfilter != NULL ) {
+ free( mfilter );
+ }
+ mfilter = ( char * )filterstr;
+ }
+ Debug( LDAP_DEBUG_ARGS,
+ "rw> searchFilter: \"%s\" -> \"%s\"\n%s",
+ filterstr, mfilter, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform",
+ NULL, NULL );
+ /* continue to the next case */
+
+ case REWRITE_REGEXEC_ERR:
+ rc = -1;
+ goto finish;
+ }
+
+ /*
+ * Maps attributes in filter
+ */
+ mapped_filter = ldap_back_map_filter( &li->targets[ i ]->at_map,
+ &li->targets[ i ]->oc_map,
+ ( char * )mfilter, 0 );
+ if ( mapped_filter == NULL ) {
+ mapped_filter = ( char * )mfilter;
+ }
+
+ /*
+ * Maps required attributes
+ */
+ mapped_attrs = ldap_back_map_attrs( &li->targets[ i ]->at_map,
+ attrs, 0 );
+ if ( mapped_attrs == NULL ) {
+ mapped_attrs = attrs;
+ }
+
+ /*
+ * Starts the search
+ */
+ msgid[ i ] = ldap_search( lsc[ 0 ]->ld, mbase, realscope,
+ mapped_filter, mapped_attrs, attrsonly);
+ if ( msgid[ i ] == -1 ) {
+ lsc[ 0 ]->candidate = META_NOT_CANDIDATE;
+ continue;
+ }
+
+ if ( mapped_attrs != attrs ) {
+ charray_free( mapped_attrs );
+ mapped_attrs = NULL;
+ }
+ if ( mapped_filter != mfilter ) {
+ free( mapped_filter );
+ mapped_filter = NULL;
+ }
+ if ( mfilter != filterstr ) {
+ free( mfilter );
+ mfilter = NULL;
+ }
+ if ( mbase != realbase ) {
+ free( mbase );
+ mbase = NULL;
+ }
+
+ ++candidates;
+ }
+
+ /* We pull apart the ber result, stuff it into a slapd entry, and
+ * let send_search_entry stuff it back into ber format. Slow & ugly,
+ * but this is necessary for version matching, and for ACL processing.
+ */
+
+
+ /*
+ * In case there are no candidates, no cycle takes place...
+ */
+ for ( count = 0, rc = 0; candidates > 0; ) {
+ int ab, gotit = 0;
+
+ /* check for abandon */
+ ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
+ ab = op->o_abandon;
+ ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+
+ for ( i = 0, lsc = lc->conns; lsc[ 0 ] != NULL; lsc++, i++ ) {
+ if ( lsc[ 0 ]->candidate != META_CANDIDATE ) {
+ continue;
+ }
+
+ if ( ab ) {
+ ldap_abandon( lsc[ 0 ]->ld, msgid[ i ] );
+ rc = 0;
+ break;
+ }
+
+ rc = ldap_result( lsc[ 0 ]->ld, LDAP_RES_ANY,
+ 0, &tv, &res );
+
+ if ( rc == 0 ) {
+ continue;
+ } else if ( rc == -1 ) {
+ /* something REALLY bad happened! */
+ ( void )meta_clear_unused_candidates( li,
+ lc, -1, 0 );
+ send_search_result( conn, op,
+ LDAP_OPERATIONS_ERROR,
+ "", "", NULL, NULL, count );
+
+ /* anything else needs be done? */
+ goto finish;
+ } else if ( rc == LDAP_RES_SEARCH_ENTRY ) {
+ e = ldap_first_entry( lsc[ 0 ]->ld,res );
+ meta_send_entry(be, op, lc, i, e, attrs,
+ attrsonly);
+ count++;
+ ldap_msgfree( res );
+ gotit = 1;
+ } else {
+ sres = ldap_result2error( lsc[ 0 ]->ld,
+ res, 1 );
+ sres = ldap_back_map_result( sres );
+ if ( err != NULL ) {
+ free( err );
+ }
+ ldap_get_option( lsc[ 0 ]->ld,
+ LDAP_OPT_ERROR_STRING, &err );
+ if ( match != NULL ) {
+ free( match );
+ }
+ ldap_get_option( lsc[ 0 ]->ld,
+ LDAP_OPT_MATCHED_DN, &match );
+
+ Debug( LDAP_DEBUG_ARGS,
+ "meta_back_search=> [%d] match=\"%s\" err=\"%s\"\n",
+ i, match, err );
+
+ last = i;
+ rc = 0;
+
+ /*
+ * When no candidates are left,
+ * the outer cycle finishes
+ */
+ lsc[ 0 ]->candidate = META_NOT_CANDIDATE;
+ --candidates;
+ }
+ }
+
+ if ( ab ) {
+ goto finish;
+ }
+
+ if ( gotit == 0 ) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+ ldap_pvt_thread_yield();
+ } else {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ }
+ }
+
+ if ( rc == -1 ) {
+ /*
+ * FIXME: need a strategy to handle errors
+ */
+ rc = meta_back_op_result( lc, op );
+ goto finish;
+ }
+
+ /*
+ * Rewrite the matched portion of the search base, if required
+ *
+ * FIXME: only the last one gets caught!
+ */
+ if ( match != NULL ) {
+ switch ( rewrite_session( li->targets[ last ]->rwinfo,
+ "matchedDn", match, conn, &mmatch ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( mmatch == NULL ) {
+ mmatch = ( char * )match;
+ }
+ Debug( LDAP_DEBUG_ARGS, "rw> matchedDn:"
+ " \"%s\" -> \"%s\"\n%s",
+ match, mmatch, "" );
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+ send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Unwilling to perform",
+ NULL, NULL );
+ /* continue to the next case */
+
+ case REWRITE_REGEXEC_ERR:
+ rc = -1;
+ goto finish;
+ }
+ }
+
+ send_search_result( conn, op, sres,
+ mmatch, err, NULL, NULL, count );
+
+finish:
+ if ( match ) {
+ if ( mmatch != match ) {
+ free( mmatch );
+ }
+ free(match);
+ }
+
+ if ( err ) {
+ free( err );
+ }
+
+ if ( msgid ) {
+ free( msgid );
+ }
+
+ return rc;
+}
+
+static void
+meta_send_entry(
+ Backend *be,
+ Operation *op,
+ struct metaconn *lc,
+ int target,
+ LDAPMessage *e,
+ char **attrs,
+ int attrsonly
+)
+{
+ struct metainfo *li = ( struct metainfo * )be->be_private;
+ char *a, *mapped;
+ Entry ent;
+ BerElement *ber = NULL;
+ Attribute *attr, **attrp;
+ struct berval *dummy = NULL;
+ struct berval *bv;
+ const char *text;
+ char *dn;
+
+ struct metasingleconn *lsc = lc->conns[ target ];
+
+ dn = ldap_get_dn( lsc->ld, e );
+ if ( dn == NULL ) {
+ return;
+ }
+
+ /*
+ * Rewrite the dn of the result, if needed
+ */
+ switch ( rewrite_session( li->targets[ target ]->rwinfo,
+ "searchResult", dn, lc->conn, &ent.e_dn ) ) {
+ case REWRITE_REGEXEC_OK:
+ if ( ent.e_dn == NULL ) {
+ ent.e_dn = dn;
+ } else {
+ Debug( LDAP_DEBUG_ARGS, "rw> searchResult[%d]: \"%s\""
+ " -> \"%s\"\n", target, dn, ent.e_dn );
+ free( dn );
+ dn = NULL;
+ }
+ break;
+
+ case REWRITE_REGEXEC_ERR:
+ case REWRITE_REGEXEC_UNWILLING:
+ free( dn );
+ return;
+ }
+
+ ent.e_ndn = ch_strdup( ent.e_dn );
+ ( void )dn_normalize( ent.e_ndn );
+
+ /*
+ * cache dn
+ */
+ if ( li->cache.ttl != META_DNCACHE_DISABLED ) {
+ ( void )meta_dncache_update_entry( &li->cache,
+ ch_strdup( ent.e_ndn ),
+ target );
+ }
+
+ ent.e_id = 0;
+ ent.e_attrs = 0;
+ ent.e_private = 0;
+ attrp = &ent.e_attrs;
+
+ for ( a = ldap_first_attribute( lsc->ld, e, &ber );
+ a != NULL;
+ a = ldap_next_attribute( lsc->ld, e, ber ) )
+ {
+ mapped = ldap_back_map( &li->targets[ target ]->at_map, a, 1 );
+ if ( mapped == NULL ) {
+ continue;
+ }
+ attr = ( Attribute * )ch_malloc( sizeof( Attribute ) );
+ if ( attr == NULL ) {
+ continue;
+ }
+ attr->a_next = 0;
+ attr->a_desc = NULL;
+ if ( slap_str2ad( mapped, &attr->a_desc, &text )
+ != LDAP_SUCCESS) {
+ ch_free( attr );
+ continue;
+ }
+ attr->a_vals = ldap_get_values_len( lsc->ld, e, a );
+ if ( !attr->a_vals ) {
+ attr->a_vals = &dummy;
+ } else if ( strcasecmp( mapped, "objectClass" ) == 0 ) {
+ int i, last;
+ for ( last = 0; attr->a_vals[ last ]; ++last ) ;
+ for ( i = 0; ( bv = attr->a_vals[ i ] ); i++ ) {
+ mapped = ldap_back_map(
+ &li->targets[ target]->oc_map,
+ bv->bv_val, 1 );
+ if ( mapped == NULL ) {
+ ber_bvfree( attr->a_vals[ i ] );
+ attr->a_vals[ i ] = NULL;
+ if ( --last < 0 ) {
+ break;
+ }
+ attr->a_vals[ i ] =
+ attr->a_vals[ last ];
+ attr->a_vals[ last ] = NULL;
+ --i;
+ } else if ( mapped != bv->bv_val ) {
+ ch_free( bv->bv_val );
+ bv->bv_val = ch_strdup( mapped );
+ bv->bv_len = strlen( mapped );
+ }
+ }
+ /*
+ * It is necessary to try to rewrite attributes with
+ * dn syntax because they might be used in ACLs as
+ * members of groups; since ACLs are applied to the
+ * rewritten stuff, no dn-based subecj clause could
+ * be used at the ldap backend side (see
+ * http://www.OpenLDAP.org/faq/data/cache/452.html)
+ * The problem can be overcome by moving the dn-based
+ * ACLs to the target directory server, and letting
+ * everything pass thru the ldap backend.
+ */
+ } else if ( strcmp( attr->a_desc->ad_type->sat_syntax->ssyn_oid,
+ SLAPD_DN_SYNTAX ) == 0 ) {
+ int i;
+ for ( i = 0; ( bv = attr->a_vals[ i ] ); i++ ) {
+ char *newval;
+
+ switch ( rewrite_session( li->targets[ target ]->rwinfo,
+ "searchResult", bv->bv_val,
+ lc->conn, &newval )) {
+ case REWRITE_REGEXEC_OK:
+ /* left as is */
+ if ( newval == NULL ) {
+ break;
+ }
+ Debug( LDAP_DEBUG_ARGS,
+ "rw> searchResult on attr=%s: \"%s\" -> \"%s\"\n",
+ attr->a_desc->ad_type->sat_cname,
+ bv->bv_val, newval );
+
+ free( bv->bv_val );
+ bv->bv_val = newval;
+ bv->bv_len = strlen( newval );
+
+ break;
+
+ case REWRITE_REGEXEC_UNWILLING:
+
+ case REWRITE_REGEXEC_ERR:
+ /*
+ * FIXME: better give up,
+ * skip the attribute
+ * or leave it untouched?
+ */
+ break;
+ }
+ }
+ }
+ *attrp = attr;
+ attrp = &attr->a_next;
+ }
+ send_search_entry( be, lc->conn, op, &ent, attrs, attrsonly, NULL );
+ while ( ent.e_attrs ) {
+ attr = ent.e_attrs;
+ ent.e_attrs = attr->a_next;
+ ad_free( attr->a_desc, 1 );
+ if ( attr->a_vals != &dummy ) {
+ ber_bvecfree(attr->a_vals);
+ }
+ free( attr );
+ }
+ if ( ber ) {
+ ber_free( ber, 0 );
+ }
+
+ if ( ent.e_dn ) {
+ free( ent.e_dn );
+ }
+ if ( ent.e_ndn ) {
+ free( ent.e_ndn );
+ }
+}
+
+static int
+is_one_level_rdn(
+ const char *rdn,
+ int len
+)
+{
+ for ( ; len--; ) {
+ if ( LDAP_DNSEPARATOR( rdn[ len ] ) ) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
--- /dev/null
+/*
+ * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ *
+ * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This work has been developed to fulfill the requirements
+ * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
+ * to the OpenLDAP Foundation in the hope that it may be useful
+ * to the Open Source community, but WITHOUT ANY WARRANTY.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author and SysNet s.n.c. are not responsible for the consequences
+ * of use of this software, no matter how awful, even if they arise from
+ * flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ * SysNet s.n.c. cannot be responsible for the consequences of the
+ * alterations.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ * This software is based on the backend back-ldap, implemented
+ * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
+ * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
+ * contributors. The contribution of the original software to the present
+ * implementation is acknowledged in this copyright statement.
+ *
+ * A special acknowledgement goes to Howard for the overall architecture
+ * (and for borrowing large pieces of code), and to Mark, who implemented
+ * from scratch the attribute/objectclass mapping.
+ *
+ * The original copyright statement follows.
+ *
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the
+ * documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-meta.h"
+
+int
+meta_back_conn_destroy(
+ Backend *be,
+ Connection *conn
+)
+{
+ struct metainfo *li = ( struct metainfo * )be->be_private;
+ struct metaconn *lc, lc_curr;
+
+ Debug( LDAP_DEBUG_TRACE,
+ "=>meta_back_conn_destroy: fetching conn %ld\n%s%s",
+ conn->c_connid, "", "" );
+
+ lc_curr.conn = conn;
+
+ ldap_pvt_thread_mutex_lock( &li->conn_mutex );
+ lc = avl_delete( &li->conntree, ( caddr_t )&lc_curr,
+ meta_back_conn_cmp );
+ ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
+
+ if ( lc ) {
+ int i;
+
+ Debug( LDAP_DEBUG_TRACE,
+ "=>meta_back_conn_destroy: destroying conn %ld\n%s%s",
+ lc->conn->c_connid, "", "" );
+
+ /*
+ * Cleanup rewrite session
+ */
+ for ( i = 0; i < li->ntargets; ++i ) {
+ if ( lc->conns[ i ]->ld == NULL ) {
+ free( lc->conns[ i ] );
+ continue;
+ }
+
+ rewrite_session_delete( li->targets[ i ]->rwinfo, conn );
+ meta_clear_one_candidate( lc->conns[ i ], 1 );
+ free( lc->conns[ i ] );
+ }
+
+ free( lc->conns );
+ free( lc );
+ }
+
+ /* no response to unbind */
+
+ return 0;
+}
+
#ifdef SLAPD_LDBM
#include "back-ldbm/external.h"
#endif
+#ifdef SLAPD_META
+#include "back-meta/external.h"
+#endif
#ifdef SLAPD_PASSWD
#include "back-passwd/external.h"
#endif
#if defined(SLAPD_LDBM) && !defined(SLAPD_LDBM_DYNAMIC)
{"ldbm", ldbm_back_initialize},
#endif
+#if defined(SLAPD_META) && !defined(SLAPD_META_DYNAMIC)
+ {"meta", meta_back_initialize},
+#endif
#if defined(SLAPD_PASSWD) && !defined(SLAPD_PASSWD_DYNAMIC)
{"passwd", passwd_back_initialize},
#endif