mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-02-03 20:40:05 -05:00
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:
parent
cabeec26d4
commit
74fa239a20
66 changed files with 12110 additions and 181 deletions
50
configure.in
50
configure.in
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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
222
include/rewrite.h
Normal 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 */
|
||||
|
||||
|
|
@ -6,5 +6,5 @@
|
|||
|
||||
SUBDIRS= liblunicode liblutil libldif \
|
||||
liblber libldap libldap_r \
|
||||
libavl libldbm
|
||||
libavl libldbm librewrite
|
||||
|
||||
|
|
|
|||
23
libraries/librewrite/Copyright
Normal file
23
libraries/librewrite/Copyright
Normal 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.
|
||||
*
|
||||
******************************************************************************/
|
||||
27
libraries/librewrite/Makefile.in
Normal file
27
libraries/librewrite/Makefile.in
Normal 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)
|
||||
397
libraries/librewrite/RATIONALE
Normal file
397
libraries/librewrite/RATIONALE
Normal 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 ...)
|
||||
*/
|
||||
|
||||
412
libraries/librewrite/config.c
Normal file
412
libraries/librewrite/config.c
Normal 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 );
|
||||
}
|
||||
415
libraries/librewrite/context.c
Normal file
415
libraries/librewrite/context.c
Normal 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
254
libraries/librewrite/info.c
Normal 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;
|
||||
}
|
||||
|
||||
333
libraries/librewrite/ldapmap.c
Normal file
333
libraries/librewrite/ldapmap.c
Normal 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
807
libraries/librewrite/map.c
Normal 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;
|
||||
}
|
||||
|
||||
140
libraries/librewrite/params.c
Normal file
140
libraries/librewrite/params.c
Normal 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;
|
||||
}
|
||||
|
||||
127
libraries/librewrite/parse.c
Normal file
127
libraries/librewrite/parse.c
Normal 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;
|
||||
}
|
||||
|
||||
554
libraries/librewrite/rewrite-int.h
Normal file
554
libraries/librewrite/rewrite-int.h
Normal 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 */
|
||||
|
||||
56
libraries/librewrite/rewrite-map.h
Normal file
56
libraries/librewrite/rewrite-map.h
Normal 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 */
|
||||
147
libraries/librewrite/rewrite.c
Normal file
147
libraries/librewrite/rewrite.c
Normal 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
393
libraries/librewrite/rule.c
Normal 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;
|
||||
}
|
||||
|
||||
330
libraries/librewrite/session.c
Normal file
330
libraries/librewrite/session.c
Normal 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;
|
||||
}
|
||||
|
||||
427
libraries/librewrite/subst.c
Normal file
427
libraries/librewrite/subst.c
Normal 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
199
libraries/librewrite/var.c
Normal 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;
|
||||
}
|
||||
|
||||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ) );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ) );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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 ));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ) );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
68
servers/slapd/back-meta/Changes
Normal file
68
servers/slapd/back-meta/Changes
Normal 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!)
|
||||
|
||||
63
servers/slapd/back-meta/Copyright
Normal file
63
servers/slapd/back-meta/Copyright
Normal 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.
|
||||
|
||||
|
||||
285
servers/slapd/back-meta/Documentation
Normal file
285
servers/slapd/back-meta/Documentation
Normal 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.
|
||||
|
||||
26
servers/slapd/back-meta/Makefile.in
Normal file
26
servers/slapd/back-meta/Makefile.in
Normal 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 $@
|
||||
|
||||
20
servers/slapd/back-meta/TODO
Normal file
20
servers/slapd/back-meta/TODO
Normal 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
|
||||
|
||||
189
servers/slapd/back-meta/add.c
Normal file
189
servers/slapd/back-meta/add.c
Normal 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 );
|
||||
}
|
||||
|
||||
208
servers/slapd/back-meta/attribute.c
Normal file
208
servers/slapd/back-meta/attribute.c
Normal 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);
|
||||
}
|
||||
|
||||
284
servers/slapd/back-meta/back-meta.h
Normal file
284
servers/slapd/back-meta/back-meta.h
Normal 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 */
|
||||
|
||||
356
servers/slapd/back-meta/bind.c
Normal file
356
servers/slapd/back-meta/bind.c
Normal 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;
|
||||
}
|
||||
|
||||
284
servers/slapd/back-meta/candidates.c
Normal file
284
servers/slapd/back-meta/candidates.c
Normal 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;
|
||||
}
|
||||
|
||||
336
servers/slapd/back-meta/compare.c
Normal file
336
servers/slapd/back-meta/compare.c
Normal 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;
|
||||
}
|
||||
|
||||
519
servers/slapd/back-meta/config.c
Normal file
519
servers/slapd/back-meta/config.c
Normal 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( <->at_map.map, ( caddr_t )mapping,
|
||||
mapping_cmp, mapping_dup );
|
||||
avl_insert( <->at_map.remap, ( caddr_t )&mapping[ 1 ],
|
||||
mapping_cmp, mapping_dup );
|
||||
|
||||
return lt;
|
||||
}
|
||||
|
||||
int
|
||||
meta_back_db_config(
|
||||
BackendDB *be,
|
||||
const char *fname,
|
||||
int lineno,
|
||||
int argc,
|
||||
char **argv
|
||||
)
|
||||
{
|
||||
struct metainfo *li = ( struct metainfo * )be->be_private;
|
||||
|
||||
if ( li == NULL ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: meta backend info is null!\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* URI of server to query */
|
||||
if ( strcasecmp( argv[ 0 ], "uri" ) == 0 ) {
|
||||
int j, i = li->ntargets;
|
||||
LDAPURLDesc *ludp;
|
||||
char *last;
|
||||
|
||||
if ( argc != 2 ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: missing address"
|
||||
" in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
|
||||
++li->ntargets;
|
||||
|
||||
li->targets = ch_realloc( li->targets,
|
||||
sizeof( struct metatarget *)*li->ntargets );
|
||||
if ( li->targets == NULL ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: out of memory while storing server name"
|
||||
" in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( ( li->targets[ i ] = new_target() ) == NULL ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: unable to init server"
|
||||
" in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* uri MUST be legal!
|
||||
*/
|
||||
if ( ldap_url_parse( argv[ 1 ], &ludp ) != LDAP_SUCCESS ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: unable to parse URI"
|
||||
" in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* uri MUST have the <dn> part!
|
||||
*/
|
||||
if ( ludp->lud_dn == NULL || ludp->lud_dn[ 0 ] == '\0' ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: missing <naming context> "
|
||||
" in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* copies and stores uri and suffix
|
||||
*/
|
||||
li->targets[ i ]->suffix = ch_strdup( ludp->lud_dn );
|
||||
li->targets[ i ]->uri = ch_strdup( argv[ 1 ] );
|
||||
last = strstr( li->targets[ i ]->uri,
|
||||
li->targets[ i ]->suffix );
|
||||
assert( last != NULL );
|
||||
last[ 0 ] = '\0'; /* wasting memory ... */
|
||||
|
||||
/*
|
||||
* Need to store the suffix in normalized form
|
||||
*/
|
||||
(void) dn_normalize( li->targets[ i ]->suffix );
|
||||
|
||||
/*
|
||||
* uri MUST be a branch of suffix!
|
||||
*/
|
||||
#if 0 /* too strict a constraint */
|
||||
if ( select_backend( li->targets[ i ]->suffix, 0 ) != be ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: <naming context> of URI does not refer to current backend"
|
||||
" in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* uri MUST be a branch of a suffix!
|
||||
*/
|
||||
if ( select_backend( li->targets[ i ]->suffix, 0 ) == NULL ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: <naming context> of URI does not resolve to a backend"
|
||||
" in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* uri MUST not be used by other URIs!
|
||||
*
|
||||
* FIXME: this limitation may be removed,
|
||||
* or worked out, at least, in some manner
|
||||
*/
|
||||
for ( j = 0; j < i-1; j++ ) {
|
||||
if ( strcmp( li->targets[ i ]->suffix,
|
||||
li->targets[ j ]->suffix ) == 0 ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: naming context \"%s\" already used"
|
||||
" in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
|
||||
fname, lineno, last+1 );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ldap_free_urldesc( ludp );
|
||||
|
||||
Debug( LDAP_DEBUG_CONFIG,
|
||||
"==>meta_back_db_config: URI \"%s\", suffix \"%s\"%s\n",
|
||||
li->targets[ i ]->uri, li->targets[ i ]->suffix, "" );
|
||||
|
||||
/* default target directive */
|
||||
} else if ( strcasecmp( argv[ 0 ], "default-target" ) == 0 ) {
|
||||
int i = li->ntargets-1;
|
||||
|
||||
if ( argc == 1 ) {
|
||||
if ( i < 0 ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: \"default-target\" alone need be"
|
||||
" inside a \"uri\" directive\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
li->defaulttarget = i;
|
||||
} else {
|
||||
if ( strcasecmp( argv[ 1 ], "none" ) == 0 ) {
|
||||
if ( i >= 0 ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: \"default-target none\""
|
||||
" should go before uri definitions\n",
|
||||
fname, lineno );
|
||||
}
|
||||
li->defaulttarget = META_DEFAULT_TARGET_NONE;
|
||||
} else {
|
||||
int n = atoi( argv[ 1 ] );
|
||||
if ( n < 1 || n >= i ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: illegal target number %d\n",
|
||||
fname, lineno, n );
|
||||
return 1;
|
||||
}
|
||||
li->defaulttarget = n-1;
|
||||
}
|
||||
}
|
||||
|
||||
/* ttl of dn cache */
|
||||
} else if ( strcasecmp( argv[ 0 ], "dncache-ttl" ) == 0 ) {
|
||||
if ( argc != 2 ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: missing ttl in \"dncache-ttl <ttl>\" line\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( strcasecmp( argv[ 1 ], "forever" ) == 0 ) {
|
||||
li->cache.ttl = META_DNCACHE_FOREVER;
|
||||
} else if ( strcasecmp( argv[ 1 ], "disabled" ) == 0 ) {
|
||||
li->cache.ttl = META_DNCACHE_DISABLED;
|
||||
} else {
|
||||
li->cache.ttl = atol( argv[ 1 ] );
|
||||
}
|
||||
|
||||
/* name to use for meta_back_group */
|
||||
} else if ( strcasecmp( argv[ 0 ], "binddn" ) == 0 ) {
|
||||
int i = li->ntargets-1;
|
||||
|
||||
if ( i < 0 ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: need \"uri\" directive first\n",
|
||||
fname, lineno );
|
||||
}
|
||||
|
||||
if ( argc != 2 ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: missing name in \"binddn <name>\" line\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
li->targets[ i ]->binddn = ch_strdup( argv[ 1 ] );
|
||||
|
||||
/* password to use for meta_back_group */
|
||||
} else if ( strcasecmp( argv[ 0 ], "bindpw" ) == 0 ) {
|
||||
int i = li->ntargets-1;
|
||||
|
||||
if ( i < 0 ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: need \"uri\" directive first\n",
|
||||
fname, lineno );
|
||||
}
|
||||
|
||||
if ( argc != 2 ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: missing password in \"bindpw <password>\" line\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
li->targets[ i ]->bindpw = ch_strdup( argv[ 1 ] );
|
||||
|
||||
/* dn massaging */
|
||||
} else if ( strcasecmp( argv[ 0 ], "suffixmassage" ) == 0 ) {
|
||||
BackendDB *tmp_be;
|
||||
int i = li->ntargets-1;
|
||||
|
||||
if ( i < 0 ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: need \"uri\" directive first\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* syntax:
|
||||
*
|
||||
* suffixmassage <suffix> <massaged suffix>
|
||||
*
|
||||
* the <suffix> field must be defined as a valid suffix
|
||||
* (or suffixAlias?) for the current database;
|
||||
* the <massaged suffix> shouldn't have already been
|
||||
* defined as a valid suffix or suffixAlias for the
|
||||
* current server
|
||||
*/
|
||||
if ( argc != 3 ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: syntax is \"suffixMassage <suffix> <massaged suffix>\"\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
|
||||
tmp_be = select_backend( argv[ 1 ], 0 );
|
||||
if ( tmp_be != NULL && tmp_be != be ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: suffix already in use by another backend in"
|
||||
" \"suffixMassage <suffix> <massaged suffix>\"\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
|
||||
tmp_be = select_backend( argv[ 2 ], 0 );
|
||||
if ( tmp_be != NULL ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: massaged suffix already in use by another backend in"
|
||||
" \"suffixMassage <suffix> <massaged suffix>\"\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The suffix massaging is emulated by means of the
|
||||
* rewrite capabilities
|
||||
* FIXME: no extra rewrite capabilities should be added
|
||||
* to the database
|
||||
*/
|
||||
return suffix_massage_config( li->targets[ i ]->rwinfo,
|
||||
argc, argv );
|
||||
|
||||
/* rewrite stuff ... */
|
||||
} else if ( strncasecmp( argv[ 0 ], "rewrite", 7 ) == 0 ) {
|
||||
int i = li->ntargets-1;
|
||||
|
||||
if ( i < 0 ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: need \"uri\" directive first\n",
|
||||
fname, lineno );
|
||||
}
|
||||
|
||||
return rewrite_parse( li->targets[ i ]->rwinfo, fname, lineno,
|
||||
argc, argv );
|
||||
|
||||
/* objectclass/attribute mapping */
|
||||
} else if ( strcasecmp( argv[ 0 ], "map" ) == 0 ) {
|
||||
struct ldapmap *map;
|
||||
struct ldapmapping *mapping;
|
||||
char *src, *dst;
|
||||
int i = li->ntargets-1;
|
||||
|
||||
if ( i < 0 ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: need \"uri\" directive first\n",
|
||||
fname, lineno );
|
||||
}
|
||||
|
||||
|
||||
if ( argc < 3 || argc > 4 ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: syntax is \"map {objectclass | attribute} {<source> | *} [<dest> | *]\"\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( strcasecmp( argv[ 1 ], "objectClass" ) == 0 ) {
|
||||
map = &li->targets[ i ]->oc_map;
|
||||
} else if ( strcasecmp( argv[ 1 ], "attribute" ) == 0 ) {
|
||||
map = &li->targets[ i ]->at_map;
|
||||
} else {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: syntax is \"map {objectclass | attribute} {<source> | *} [<dest> | *]\"\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( strcasecmp( argv[ 2 ], "*" ) != 0 ) {
|
||||
src = argv[ 2 ];
|
||||
if ( argc < 4 ) {
|
||||
dst = "";
|
||||
} else if ( strcasecmp( argv[ 3 ], "*" ) == 0 ) {
|
||||
dst = src;
|
||||
} else {
|
||||
dst = argv[ 3 ];
|
||||
}
|
||||
} else {
|
||||
if ( argc < 4 ) {
|
||||
map->drop_missing = 1;
|
||||
return 0;
|
||||
}
|
||||
if ( strcasecmp( argv[ 3 ], "*" ) == 0 ) {
|
||||
map->drop_missing = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
src = argv[ 3 ];
|
||||
dst = src;
|
||||
}
|
||||
|
||||
if ( ( map == &li->targets[ i ]->at_map )
|
||||
&& ( strcasecmp( src, "objectclass" ) == 0
|
||||
|| strcasecmp( dst, "objectclass" ) == 0 ) ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: objectclass attribute cannot be mapped\n",
|
||||
fname, lineno );
|
||||
}
|
||||
|
||||
mapping = ch_calloc( 2, sizeof( struct ldapmapping ) );
|
||||
if ( mapping == NULL ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: out of memory\n",
|
||||
fname, lineno );
|
||||
return 1;
|
||||
}
|
||||
mapping->src = ch_strdup( src );
|
||||
mapping->dst = ch_strdup( dst );
|
||||
if ( *dst != 0 ) {
|
||||
mapping[ 1 ].src = mapping->dst;
|
||||
mapping[ 1 ].dst = mapping->src;
|
||||
} else {
|
||||
mapping[ 1 ].src = mapping->src;
|
||||
mapping[ 1 ].dst = mapping->dst;
|
||||
}
|
||||
|
||||
if ( avl_find( map->map, ( caddr_t )mapping,
|
||||
mapping_cmp ) != NULL
|
||||
|| avl_find( map->remap, ( caddr_t )&mapping[ 1 ],
|
||||
mapping_cmp ) != NULL) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: duplicate mapping found (ignored)\n",
|
||||
fname, lineno );
|
||||
return 0;
|
||||
}
|
||||
|
||||
avl_insert( &map->map, ( caddr_t )mapping,
|
||||
mapping_cmp, mapping_dup );
|
||||
avl_insert( &map->remap, ( caddr_t )&mapping[ 1 ],
|
||||
mapping_cmp, mapping_dup );
|
||||
|
||||
/* anything else */
|
||||
} else {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: unknown directive \"%s\" in meta database definition"
|
||||
" (ignored)\n",
|
||||
fname, lineno, argv[0] );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
501
servers/slapd/back-meta/conn.c
Normal file
501
servers/slapd/back-meta/conn.c
Normal 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;
|
||||
}
|
||||
|
||||
10
servers/slapd/back-meta/data/meta-1.ldif
Normal file
10
servers/slapd/back-meta/data/meta-1.ldif
Normal 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
|
||||
|
||||
10
servers/slapd/back-meta/data/meta-2.ldif
Normal file
10
servers/slapd/back-meta/data/meta-2.ldif
Normal 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
|
||||
|
||||
11
servers/slapd/back-meta/data/meta-3.ldif
Normal file
11
servers/slapd/back-meta/data/meta-3.ldif
Normal 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
|
||||
51
servers/slapd/back-meta/data/setup.sh
Normal file
51
servers/slapd/back-meta/data/setup.sh
Normal 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
|
||||
|
||||
15
servers/slapd/back-meta/data/slapd-ldap-raw.conf
Normal file
15
servers/slapd/back-meta/data/slapd-ldap-raw.conf
Normal 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
|
||||
|
||||
44
servers/slapd/back-meta/data/slapd-ldap-rewrite.conf
Normal file
44
servers/slapd/back-meta/data/slapd-ldap-rewrite.conf
Normal 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
|
||||
|
||||
30
servers/slapd/back-meta/data/slapd-ldbm.conf
Normal file
30
servers/slapd/back-meta/data/slapd-ldbm.conf
Normal 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
|
||||
|
||||
43
servers/slapd/back-meta/data/slapd-meta-plain.conf
Normal file
43
servers/slapd/back-meta/data/slapd-meta-plain.conf
Normal 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
|
||||
|
||||
82
servers/slapd/back-meta/data/slapd-meta-rewrite.conf
Normal file
82
servers/slapd/back-meta/data/slapd-meta-rewrite.conf
Normal 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
|
||||
|
||||
128
servers/slapd/back-meta/delete.c
Normal file
128
servers/slapd/back-meta/delete.c
Normal 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 );
|
||||
}
|
||||
|
||||
281
servers/slapd/back-meta/dncache.c
Normal file
281
servers/slapd/back-meta/dncache.c
Normal 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 );
|
||||
}
|
||||
|
||||
211
servers/slapd/back-meta/external.h
Normal file
211
servers/slapd/back-meta/external.h
Normal 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 */
|
||||
|
||||
272
servers/slapd/back-meta/group.c
Normal file
272
servers/slapd/back-meta/group.c
Normal 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;
|
||||
}
|
||||
|
||||
250
servers/slapd/back-meta/init.c
Normal file
250
servers/slapd/back-meta/init.c
Normal 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;
|
||||
}
|
||||
|
||||
195
servers/slapd/back-meta/modify.c
Normal file
195
servers/slapd/back-meta/modify.c
Normal 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 );
|
||||
}
|
||||
|
||||
187
servers/slapd/back-meta/modrdn.c
Normal file
187
servers/slapd/back-meta/modrdn.c
Normal 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 );
|
||||
}
|
||||
666
servers/slapd/back-meta/search.c
Normal file
666
servers/slapd/back-meta/search.c
Normal 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;
|
||||
}
|
||||
|
||||
127
servers/slapd/back-meta/unbind.c
Normal file
127
servers/slapd/back-meta/unbind.c
Normal 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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue