This is the commit of:

- librewrite, for string rewriting; it may be used in back-ldap
    by configuring with '--enable-rewrite'. It must be used in
    back-meta. There's a text file, 'libraries/librewrite/RATIONALE',
    that explains the usage and the features. More comprehensive
    documentation will follow.
  - enhancements of back-ldap (ITS#989,ITS#998,ITS#1002,ITS#1054 and ITS#1137)
    including dn rewriting, a fix to group acl matching and so
  - back-meta: a new backend that proxies a set of remote servers
    by spawning queries. It uses portions of back-ldap and the rewrite
    capabilities of librewrite. It can be compiled by configuring
    with `--enable-ldap --enable-rewrite --enable-meta'.
    There's a text file, 'servers/slapd/back-meta/Documentation', that
    describes the main features and config statements.

Note: someone (Kurt?) should run 'autoconf' and commit 'configure' as
my autoconf version must be different: my configures contain a number
of differences and I didn't feel comfortable in adding them :)
This commit is contained in:
Pierangelo Masarati 2001-05-12 00:51:28 +00:00
parent cabeec26d4
commit 74fa239a20
66 changed files with 12110 additions and 181 deletions

View file

@ -116,6 +116,7 @@ OL_ARG_ENABLE(referrals,[ --enable-referrals enable V2 Referrals (experimenta
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
@ -177,6 +178,9 @@ OL_ARG_WITH(ldbm_module,[ --with-ldbm-module module type], static,
[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])
@ -222,6 +226,9 @@ if test $ol_enable_slapd = no ; then
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
@ -273,6 +280,9 @@ dnl 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
@ -291,12 +301,16 @@ dnl 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
@ -318,6 +332,7 @@ dnl ol_enable_multimaster=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
@ -326,6 +341,8 @@ dnl ol_enable_multimaster=no
ol_enable_slurpd=no
ol_enable_rewrite=no
elif test $ol_enable_ldbm = no ; then
dnl SLAPD without LDBM
@ -345,6 +362,7 @@ elif test $ol_enable_ldbm = no ; then
$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 \
@ -427,6 +445,7 @@ BUILD_BDB=no
BUILD_DNSSRV=no
BUILD_LDAP=no
BUILD_LDBM=no
BUILD_META=no
BUILD_PASSWD=no
BUILD_PERL=no
BUILD_SHELL=no
@ -437,6 +456,7 @@ BUILD_BDB_DYNAMIC=static
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
@ -650,6 +670,7 @@ else
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
@ -2342,6 +2363,25 @@ if test "$ol_link_ldbm" != no ; then
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
@ -2412,6 +2452,12 @@ if test "$ol_enable_slurpd" != no -a "$ol_link_threads" != no -a \
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
@ -2442,6 +2488,7 @@ AC_SUBST(BUILD_SLAPD)
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)
@ -2451,6 +2498,7 @@ AC_SUBST(BUILD_SLAPD)
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)
@ -2523,12 +2571,14 @@ libraries/libldbm/Makefile:build/top.mk:libraries/libldbm/Makefile.in:build/lib.
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 \

View file

@ -930,6 +930,12 @@
/* 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
@ -960,6 +966,9 @@
/* 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 */

222
include/rewrite.h Normal file
View file

@ -0,0 +1,222 @@
/******************************************************************************
*
* 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 */

View file

@ -6,5 +6,5 @@
SUBDIRS= liblunicode liblutil libldif \
liblber libldap libldap_r \
libavl libldbm
libavl libldbm librewrite

View file

@ -0,0 +1,23 @@
/******************************************************************************
*
* 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.
*
******************************************************************************/

View file

@ -0,0 +1,27 @@
# $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)

View file

@ -0,0 +1,397 @@
/******************************************************************************
*
* 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 ...)
*/

View file

@ -0,0 +1,412 @@
/******************************************************************************
*
* 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 );
}

View file

@ -0,0 +1,415 @@
/******************************************************************************
*
* 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;
}

254
libraries/librewrite/info.c Normal file
View file

@ -0,0 +1,254 @@
/******************************************************************************
*
* 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;
}

View file

@ -0,0 +1,333 @@
/******************************************************************************
*
* 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;
}

807
libraries/librewrite/map.c Normal file
View file

@ -0,0 +1,807 @@
/******************************************************************************
*
* 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;
}

View file

@ -0,0 +1,140 @@
/******************************************************************************
*
* 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;
}

View file

@ -0,0 +1,127 @@
/******************************************************************************
*
* 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;
}

View file

@ -0,0 +1,554 @@
/******************************************************************************
*
* 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 */

View file

@ -0,0 +1,56 @@
/******************************************************************************
*
* 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 */

View file

@ -0,0 +1,147 @@
/******************************************************************************
*
* 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;
}

393
libraries/librewrite/rule.c Normal file
View file

@ -0,0 +1,393 @@
/******************************************************************************
*
* 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;
}

View file

@ -0,0 +1,330 @@
/******************************************************************************
*
* 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;
}

View file

@ -0,0 +1,427 @@
/******************************************************************************
*
* 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;
}

199
libraries/librewrite/var.c Normal file
View file

@ -0,0 +1,199 @@
/******************************************************************************
*
* 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;
}

View file

@ -58,17 +58,36 @@ ldap_back_add(
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)
@ -78,16 +97,52 @@ ldap_back_add(
attrs = (LDAPMod **)ch_malloc(sizeof(LDAPMod *)*i);
for (i=0, a=e->e_attrs; a; a=a->a_next) {
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++;
}
/*
* 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) {
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;
@ -95,6 +150,60 @@ ldap_back_add(
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 */

View file

@ -40,6 +40,11 @@
#include "external.h"
/* String rewrite library */
#ifdef ENABLE_REWRITE
#include "rewrite.h"
#endif /* ENABLE_REWRITE */
LDAP_BEGIN_DECL
struct slap_conn;
@ -66,14 +71,15 @@ struct ldapmapping {
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;
@ -89,15 +95,33 @@ int back_ldap_LTX_init_module(int argc, char *argv[]);
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

View file

@ -47,6 +47,8 @@
#include "slap.h"
#include "back-ldap.h"
#define PRINT_CONNTREE 0
int
ldap_back_bind(
Backend *be,
@ -72,30 +74,56 @@ ldap_back_bind(
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 );
if (ldap_bind_s(lc->ld, mdn, cred->bv_val, method) != LDAP_SUCCESS) {
case REWRITE_REGEXEC_ERR:
return( -1 );
}
#else /* !ENABLE_REWRITE */
mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 );
#endif /* !ENABLE_REWRITE */
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
)
@ -107,13 +135,13 @@ conn_cmp(
}
/*
* 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
)
@ -124,6 +152,7 @@ conn_dup(
return( ( lc1->conn == lc2->conn ) ? -1 : 0 );
}
#if PRINT_CONNTREE > 0
static void ravl_print( Avlnode *root, int depth )
{
int i;
@ -136,7 +165,7 @@ static void ravl_print( Avlnode *root, int depth )
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 );
}
@ -153,6 +182,7 @@ static void myprint( Avlnode *root )
printf( "********\n" );
}
#endif /* PRINT_CONNTREE */
struct ldapconn *
ldap_back_getconn(struct ldapinfo *li, Connection *conn, Operation *op)
@ -164,7 +194,7 @@ 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... */
@ -186,9 +216,49 @@ ldap_back_getconn(struct ldapinfo *li, Connection *conn, Operation *op)
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;
}
@ -197,17 +267,17 @@ ldap_back_getconn(struct ldapinfo *li, Connection *conn, Operation *op)
/* 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 ) {
@ -218,8 +288,8 @@ ldap_back_getconn(struct ldapinfo *li, Connection *conn, Operation *op)
}
} 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 );
@ -305,9 +375,23 @@ ldap_back_op_result(struct ldapconn *lc, Operation *op)
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 );
}

View file

@ -64,10 +64,32 @@ ldap_back_compare(
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)
@ -79,7 +101,13 @@ ldap_back_compare(
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 ) );
}

View file

@ -113,34 +113,59 @@ ldap_back_db_config(
/* 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 );
@ -153,7 +178,14 @@ ldap_back_db_config(
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;
@ -293,7 +325,12 @@ ldap_back_map ( struct ldapmap *map, char *s, int remap )
}
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;
@ -315,7 +352,7 @@ ldap_back_map_filter ( struct ldapinfo *li, char *f, int remap )
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) {
@ -339,9 +376,9 @@ ldap_back_map_filter ( struct ldapinfo *li, char *f, int remap )
} 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;
}
@ -374,7 +411,11 @@ ldap_back_map_filter ( struct ldapinfo *li, char *f, int remap )
}
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;
@ -391,7 +432,7 @@ ldap_back_map_attrs ( struct ldapinfo *li, char **a, int remap )
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) {
@ -405,3 +446,137 @@ ldap_back_map_attrs ( struct ldapinfo *li, char **a, int remap )
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 */

View file

@ -57,7 +57,7 @@ ldap_back_delete(
struct ldapinfo *li = (struct ldapinfo *) be->be_private;
struct ldapconn *lc;
char *mdn;
char *mdn = NULL;
lc = ldap_back_getconn( li, conn, op );
@ -65,14 +65,39 @@ ldap_back_delete(
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 ) );
}

View file

@ -16,9 +16,9 @@
#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(
@ -35,12 +35,13 @@ 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;
@ -55,65 +56,150 @@ ldap_back_group(
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 ) {
if ((attr = attr_find(e->e_attrs, group_at)) == NULL)
return(1);
bv.bv_val = (char *) op_ndn;
bv.bv_len = strlen( op_ndn );
if( value_find( group_at, attr->a_vals, &bv ) == 0 )
return(1);
} 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);
}
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);
/*
* Now we can check for the group objectClass value
*/
if( !is_entry_objectclass( target, group_oc ) ) {
return(1);
}
}
ldap_unbind(ld);
ch_free(filter);
return(rc);
}
return(0);
/*
* 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;
}
/*
* 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;
}
if (ldap_bind_s(ld, li->binddn, li->bindpw, LDAP_AUTH_SIMPLE)
!= 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;
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);
}
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);
}

View file

@ -106,6 +106,18 @@ ldap_back_db_init(
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) );
@ -123,7 +135,7 @@ ldap_back_db_init(
be->be_private = li;
return li == NULL;
return 0;
}
static void
@ -136,7 +148,7 @@ conn_free(
free( lc );
}
static void
void
mapping_free ( struct ldapmapping *mapping )
{
ch_free( mapping->src );
@ -168,13 +180,18 @@ ldap_back_db_destroy(
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 );

View file

@ -61,45 +61,89 @@ ldap_back_modify(
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 ));
}

View file

@ -60,10 +60,10 @@ ldap_back_modrdn(
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 );
}
@ -71,26 +71,78 @@ ldap_back_modrdn(
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) ) {
#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 );
case REWRITE_REGEXEC_ERR:
return( -1 );
}
#else /* !ENABLE_REWRITE */
mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 );
if ( mdn == NULL ) {
return( -1 );
}
#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 ) );
}

View file

@ -70,9 +70,12 @@ ldap_back_search(
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 ) {
@ -90,17 +93,73 @@ ldap_back_search(
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 );
if ( mbase == NULL ) {
return -1;
}
#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;
}
@ -109,16 +168,8 @@ ldap_back_search(
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
@ -139,6 +190,7 @@ fail:
if (ab) {
ldap_abandon(lc->ld, msgid);
rc = 0;
goto finish;
}
if (rc == 0) {
@ -163,20 +215,78 @@ fail:
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
@ -198,7 +308,39 @@ ldap_send_entry(
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;
@ -228,7 +370,7 @@ ldap_send_entry(
} 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]);
@ -244,7 +386,59 @@ ldap_send_entry(
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;
}
@ -265,3 +459,4 @@ ldap_send_entry(
if ( ent.e_ndn )
free( ent.e_ndn );
}

View file

@ -30,6 +30,8 @@
#include "portable.h"
#ifndef ENABLE_REWRITE
#include <stdio.h>
#include <ac/socket.h>
@ -154,4 +156,5 @@ ldap_back_dn_restore(
return dn;
}
#endif /* !ENABLE_REWRITE */

View file

@ -62,14 +62,21 @@ ldap_back_conn_destroy(
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

View file

@ -0,0 +1,68 @@
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!)

View file

@ -0,0 +1,63 @@
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.

View file

@ -0,0 +1,285 @@
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.

View file

@ -0,0 +1,26 @@
# $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 $@

View file

@ -0,0 +1,20 @@
* 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

View file

@ -0,0 +1,189 @@
/*
* 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 );
}

View file

@ -0,0 +1,208 @@
/*
* 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);
}

View file

@ -0,0 +1,284 @@
/*
* 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 */

View file

@ -0,0 +1,356 @@
/*
* 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;
}

View file

@ -0,0 +1,284 @@
/*
* 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;
}

View file

@ -0,0 +1,336 @@
/*
* 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;
}

View file

@ -0,0 +1,519 @@
/*
* 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( &lt->at_map.map, ( caddr_t )mapping,
mapping_cmp, mapping_dup );
avl_insert( &lt->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;
}

View file

@ -0,0 +1,501 @@
/*
* 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;
}

View file

@ -0,0 +1,10 @@
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

View file

@ -0,0 +1,10 @@
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

View file

@ -0,0 +1,11 @@
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

View file

@ -0,0 +1,51 @@
#!/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

View file

@ -0,0 +1,15 @@
#######################################################################
# 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

View file

@ -0,0 +1,44 @@
#
# 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

View file

@ -0,0 +1,30 @@
#
# 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

View file

@ -0,0 +1,43 @@
#
# 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

View file

@ -0,0 +1,82 @@
#
# 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

View file

@ -0,0 +1,128 @@
/*
* 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 );
}

View file

@ -0,0 +1,281 @@
/*
* 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 );
}

View file

@ -0,0 +1,211 @@
/*
* 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 */

View file

@ -0,0 +1,272 @@
/*
* 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;
}

View file

@ -0,0 +1,250 @@
/*
* 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;
}

View file

@ -0,0 +1,195 @@
/*
* 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 );
}

View file

@ -0,0 +1,187 @@
/*
* 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 );
}

View file

@ -0,0 +1,666 @@
/*
* 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;
}

View file

@ -0,0 +1,127 @@
/*
* 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;
}

View file

@ -30,6 +30,9 @@
#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
@ -62,6 +65,9 @@ static BackendInfo binfo[] = {
#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