am_aux_dir=`cd $ac_aux_dir && pwd`
])
-
-# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2005
-# Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# serial 4
-
-# This was merged into AC_PROG_CC in Autoconf.
-
-AU_DEFUN([AM_PROG_CC_STDC],
-[AC_PROG_CC
-AC_DIAGNOSE([obsolete], [$0:
- your code should no longer depend upon `am_cv_prog_cc_stdc', but upon
- `ac_cv_prog_cc_stdc'. Remove this warning and the assignment when
- you adjust the code. You can also remove the above call to
- AC_PROG_CC if you already called it elsewhere.])
-am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc
-])
-AU_DEFUN([fp_PROG_CC_STDC])
-
# AM_CONDITIONAL -*- Autoconf -*-
# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005
-$(MKDIR) $(DESTDIR)$(MANDIR)
PAGES=`cd $(srcdir); echo *.$(MANSECT)`; \
for page in $$PAGES; do \
- echo "installing $(MANDIR)/$$page"; \
+ echo "installing $$page in $(DESTDIR)$(MANDIR)"; \
$(RM) $(DESTDIR)$(MANDIR)/$$page; \
$(INSTALL) $(INSTALLFLAGS) -m 644 $$page.$(TMP_SUFFIX) $(DESTDIR)$(MANDIR)/$$page; \
if test -f "$(srcdir)/$$page.links" ; then \
for link in `$(CAT) $(srcdir)/$$page.links`; do \
- echo "installing $(MANDIR)/$$link as link to $$page"; \
+ echo "installing $$link in $(DESTDIR)$(MANDIR) as link to $$page"; \
$(RM) $(DESTDIR)$(MANDIR)/$$link ; \
- $(LN_S) $$page $(DESTDIR)$(MANDIR)/$$link; \
+ $(LN_S) $(DESTDIR)$(MANDIR)/$$page $(DESTDIR)$(MANDIR)/$$link; \
done; \
fi; \
done
# include <unistd.h>
#endif"
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar OPENLDAP_LIBRELEASE OPENLDAP_LIBVERSION OPENLDAP_RELEASE_DATE top_builddir ldap_subdir CC AR CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE EGREP LN_S ECHO ac_ct_AR RANLIB ac_ct_RANLIB DLLTOOL ac_ct_DLLTOOL AS ac_ct_AS OBJDUMP ac_ct_OBJDUMP CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL PERLBIN OL_MKDEP OL_MKDEP_FLAGS LTSTATIC LIBOBJS LIBSRCS PLAT WITH_SASL WITH_TLS WITH_MODULES_ENABLED BUILD_LIBS_DYNAMIC BUILD_SLAPD BUILD_SLAPI SLAPD_SLAPI_DEPEND BUILD_BDB BUILD_DNSSRV BUILD_HDB BUILD_LDAP BUILD_LDBM BUILD_META BUILD_MONITOR BUILD_NULL BUILD_PASSWD BUILD_RELAY BUILD_PERL BUILD_SHELL BUILD_SQL BUILD_ACCESSLOG BUILD_DENYOP BUILD_DYNGROUP BUILD_DYNLIST BUILD_GLUE BUILD_LASTMOD BUILD_PPOLICY BUILD_PROXYCACHE BUILD_REFINT BUILD_RETCODE BUILD_RWM BUILD_SYNCPROV BUILD_TRANSLUCENT BUILD_UNIQUE BUILD_SLURPD LDAP_LIBS SLAPD_LIBS SLURPD_LIBS LDBM_LIBS LTHREAD_LIBS LUTIL_LIBS WRAP_LIBS SLAPD_MODULES_CPPFLAGS SLAPD_MODULES_LDFLAGS SLAPD_NO_STATIC SLAPD_STATIC_BACKENDS SLAPD_DYNAMIC_BACKENDS SLAPD_STATIC_OVERLAYS SLAPD_DYNAMIC_OVERLAYS PERL_CPPFLAGS SLAPD_PERL_LDFLAGS MOD_PERL_LDFLAGS KRB4_LIBS KRB5_LIBS SASL_LIBS TLS_LIBS MODULES_LIBS SLAPI_LIBS LIBSLAPI LIBSLAPITOOLS AUTH_LIBS SLAPD_SLP_LIBS SLAPD_GMP_LIBS SLAPD_SQL_LDFLAGS SLAPD_SQL_LIBS SLAPD_SQL_INCLUDES LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar OPENLDAP_LIBRELEASE OPENLDAP_LIBVERSION OPENLDAP_RELEASE_DATE top_builddir ldap_subdir CC AR CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE EGREP LN_S ECHO ac_ct_AR RANLIB ac_ct_RANLIB DLLTOOL ac_ct_DLLTOOL AS ac_ct_AS OBJDUMP ac_ct_OBJDUMP CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL PERLBIN OL_MKDEP OL_MKDEP_FLAGS LTSTATIC LIBOBJS LIBSRCS PLAT WITH_SASL WITH_TLS WITH_MODULES_ENABLED BUILD_LIBS_DYNAMIC BUILD_SLAPD BUILD_SLAPI SLAPD_SLAPI_DEPEND BUILD_BDB BUILD_DNSSRV BUILD_HDB BUILD_LDAP BUILD_LDBM BUILD_META BUILD_MONITOR BUILD_NULL BUILD_PASSWD BUILD_RELAY BUILD_PERL BUILD_SHELL BUILD_SQL BUILD_ACCESSLOG BUILD_DENYOP BUILD_DYNGROUP BUILD_DYNLIST BUILD_GLUE BUILD_LASTMOD BUILD_PPOLICY BUILD_PROXYCACHE BUILD_REFINT BUILD_RETCODE BUILD_RWM BUILD_SYNCPROV BUILD_TRANSLUCENT BUILD_UNIQUE BUILD_VALSORT BUILD_SLURPD LDAP_LIBS SLAPD_LIBS SLURPD_LIBS LDBM_LIBS LTHREAD_LIBS LUTIL_LIBS WRAP_LIBS SLAPD_MODULES_CPPFLAGS SLAPD_MODULES_LDFLAGS SLAPD_NO_STATIC SLAPD_STATIC_BACKENDS SLAPD_DYNAMIC_BACKENDS SLAPD_STATIC_OVERLAYS SLAPD_DYNAMIC_OVERLAYS PERL_CPPFLAGS SLAPD_PERL_LDFLAGS MOD_PERL_LDFLAGS KRB4_LIBS KRB5_LIBS SASL_LIBS TLS_LIBS MODULES_LIBS SLAPI_LIBS LIBSLAPI LIBSLAPITOOLS AUTH_LIBS SLAPD_SLP_LIBS SLAPD_GMP_LIBS SLAPD_SQL_LDFLAGS SLAPD_SQL_LIBS SLAPD_SQL_INCLUDES LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
--enable-syncprov Syncrepl Provider overlay no|yes|mod [yes]
--enable-translucent Translucent Proxy overlay no|yes|mod [no]
--enable-unique Attribute Uniqueness overlay no|yes|mod [no]
+ --enable-valsort Value Sorting overlay no|yes|mod [no]
SLURPD (Replication Daemon) Options:
--enable-slurpd enable building slurpd [auto]
fi;
# end --enable-sql
-Overlays="accesslog denyop dyngroup dynlist glue lastmod ppolicy proxycache \
- refint retcode rwm syncprov translucent unique"
+Overlays="accesslog \
+ denyop \
+ dyngroup \
+ dynlist \
+ glue \
+ lastmod \
+ ppolicy \
+ proxycache \
+ refint \
+ retcode \
+ rwm \
+ syncprov \
+ translucent \
+ unique \
+ valsort"
# Check whether --enable-xxslapoverlays or --disable-xxslapoverlays was given.
if test "${enable_xxslapoverlays+set}" = set; then
fi;
# end --enable-unique
+# OpenLDAP --enable-unique
+
+ # Check whether --enable-unique or --disable-unique was given.
+if test "${enable_unique+set}" = set; then
+ enableval="$enable_unique"
+
+ ol_arg=invalid
+ for ol_val in no yes mod ; do
+ if test "$enableval" = "$ol_val" ; then
+ ol_arg="$ol_val"
+ fi
+ done
+ if test "$ol_arg" = "invalid" ; then
+ { { echo "$as_me:$LINENO: error: bad value $enableval for --enable-unique" >&5
+echo "$as_me: error: bad value $enableval for --enable-unique" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ ol_enable_unique="$ol_arg"
+
+else
+ ol_enable_unique=${ol_enable_overlays:-no}
+fi;
+# end --enable-unique
+
# Check whether --enable-xxslurpdoptions or --disable-xxslurpdoptions was given.
if test "${enable_xxslurpdoptions+set}" = set; then
BUILD_SYNCPROV=no
BUILD_TRANSLUCENT=no
BUILD_UNIQUE=no
+BUILD_VALSORT=no
SLAPD_STATIC_OVERLAYS=
SLAPD_DYNAMIC_OVERLAYS=
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 5675 "configure"' > conftest.$ac_ext
+ echo '#line 5714 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
# Provide some information about the compiler.
-echo "$as_me:7496:" \
+echo "$as_me:7535:" \
"checking for Fortran 77 compiler version" >&5
ac_compiler=`set X $ac_compile; echo $2`
{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:8594: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:8633: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:8598: \$? = $ac_status" >&5
+ echo "$as_me:8637: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:8856: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:8895: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:8860: \$? = $ac_status" >&5
+ echo "$as_me:8899: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:8918: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:8957: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:8922: \$? = $ac_status" >&5
+ echo "$as_me:8961: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 11158 "configure"
+#line 11197 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 11256 "configure"
+#line 11295 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:13504: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:13543: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:13508: \$? = $ac_status" >&5
+ echo "$as_me:13547: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:13566: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:13605: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:13570: \$? = $ac_status" >&5
+ echo "$as_me:13609: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 14935 "configure"
+#line 14974 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 15033 "configure"
+#line 15072 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:15918: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:15957: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:15922: \$? = $ac_status" >&5
+ echo "$as_me:15961: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:15980: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:16019: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:15984: \$? = $ac_status" >&5
+ echo "$as_me:16023: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:18102: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:18141: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:18106: \$? = $ac_status" >&5
+ echo "$as_me:18145: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:18364: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:18403: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:18368: \$? = $ac_status" >&5
+ echo "$as_me:18407: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:18426: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:18465: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:18430: \$? = $ac_status" >&5
+ echo "$as_me:18469: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 20666 "configure"
+#line 20705 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 20764 "configure"
+#line 20803 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
fi
if test "$ol_enable_shell" != no ; then
- if test "$ol_link_thread" != no ; then
+ if test "$ol_link_threads" != no ; then
{ echo "$as_me:$LINENO: WARNING: Use of --without-threads is recommended with back-shell" >&5
echo "$as_me: WARNING: Use of --without-threads is recommended with back-shell" >&2;}
fi
fi
+if test "$ol_enable_valsort" != no ; then
+ BUILD_VALSORT=$ol_enable_valsort
+ if test "$ol_enable_valsort" = mod ; then
+ MFLAG=SLAPD_MOD_DYNAMIC
+ SLAPD_DYNAMIC_OVERLAYS="$SLAPD_DYNAMIC_OVERLAYS valsort.la"
+ else
+ MFLAG=SLAPD_MOD_STATIC
+ SLAPD_STATIC_OVERLAYS="$SLAPD_STATIC_OVERLAYS valsort.o"
+ fi
+
+cat >>confdefs.h <<_ACEOF
+#define SLAPD_OVER_VALSORT $MFLAG
+_ACEOF
+
+fi
+
if test "$ol_enable_slurpd" != no -a "$ol_link_threads" != no -a \
$BUILD_SLAPD = yes ; then
BUILD_SLURPD=yes
+
# Check whether --with-xxinstall or --without-xxinstall was given.
s,@BUILD_SYNCPROV@,$BUILD_SYNCPROV,;t t
s,@BUILD_TRANSLUCENT@,$BUILD_TRANSLUCENT,;t t
s,@BUILD_UNIQUE@,$BUILD_UNIQUE,;t t
+s,@BUILD_VALSORT@,$BUILD_VALSORT,;t t
s,@BUILD_SLURPD@,$BUILD_SLURPD,;t t
s,@LDAP_LIBS@,$LDAP_LIBS,;t t
s,@SLAPD_LIBS@,$SLAPD_LIBS,;t t
dnl ----------------------------------------------------------------
dnl SLAPD Overlay Options
-Overlays="accesslog denyop dyngroup dynlist glue lastmod ppolicy proxycache \
- refint retcode rwm syncprov translucent unique"
+Overlays="accesslog \
+ denyop \
+ dyngroup \
+ dynlist \
+ glue \
+ lastmod \
+ ppolicy \
+ proxycache \
+ refint \
+ retcode \
+ rwm \
+ syncprov \
+ translucent \
+ unique \
+ valsort"
AC_ARG_ENABLE(xxslapoverlays,[
SLAPD Overlay Options:])
no, [no yes mod], ol_enable_overlays)
OL_ARG_ENABLE(unique,[ --enable-unique Attribute Uniqueness overlay],
no, [no yes mod], ol_enable_overlays)
+OL_ARG_ENABLE(unique,[ --enable-valsort Value Sorting overlay],
+ no, [no yes mod], ol_enable_overlays)
dnl ----------------------------------------------------------------
dnl SLURPD OPTIONS
BUILD_SYNCPROV=no
BUILD_TRANSLUCENT=no
BUILD_UNIQUE=no
+BUILD_VALSORT=no
SLAPD_STATIC_OVERLAYS=
SLAPD_DYNAMIC_OVERLAYS=
fi
if test "$ol_enable_shell" != no ; then
- if test "$ol_link_thread" != no ; then
+ if test "$ol_link_threads" != no ; then
AC_MSG_WARN([Use of --without-threads is recommended with back-shell])
fi
BUILD_SLAPD=yes
AC_DEFINE_UNQUOTED(SLAPD_OVER_UNIQUE,$MFLAG,[define for Attribute Uniqueness overlay])
fi
+if test "$ol_enable_valsort" != no ; then
+ BUILD_VALSORT=$ol_enable_valsort
+ if test "$ol_enable_valsort" = mod ; then
+ MFLAG=SLAPD_MOD_DYNAMIC
+ SLAPD_DYNAMIC_OVERLAYS="$SLAPD_DYNAMIC_OVERLAYS valsort.la"
+ else
+ MFLAG=SLAPD_MOD_STATIC
+ SLAPD_STATIC_OVERLAYS="$SLAPD_STATIC_OVERLAYS valsort.o"
+ fi
+ AC_DEFINE_UNQUOTED(SLAPD_OVER_VALSORT,$MFLAG,[define for Value Sorting overlay])
+fi
+
if test "$ol_enable_slurpd" != no -a "$ol_link_threads" != no -a \
$BUILD_SLAPD = yes ; then
BUILD_SLURPD=yes
AC_SUBST(BUILD_SYNCPROV)
AC_SUBST(BUILD_TRANSLUCENT)
AC_SUBST(BUILD_UNIQUE)
+ AC_SUBST(BUILD_VALSORT)
AC_SUBST(BUILD_SLURPD)
AC_SUBST(LDAP_LIBS)
--- /dev/null
+Copyright 2005 The OpenLDAP Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
+This directory contains native slapd plugins that implement access rules.
+
+posixgroup.c contains a simple example that implements access control
+based on posixGroup membership, loosely inspired by ITS#3849. It should
+be made clear that this access control policy does not reflect any
+standard track model of handling access control, and should be
+essentially viewed as an illustration of the use of the dynamic
+extension of access control within slapd.
+
+To use the acl-posixgroup plugin, add:
+
+moduleload acl-posixgroup.so
+
+to your slapd configuration file; it requires "nis.schema" to be loaded.
+It is configured using
+
+access to <what>
+ by dynacl/posixGroup[.{exact,expand}]=<dnpat> {<level>|<priv(s)}
+
+The default is "exact"; in case of "expand", "<dnpat>" results from
+the expansion of submatches in the "<what>" portion. "<level>|<priv(s)>"
+describe the level of privilege this rule can assume.
+
+No Makefile is provided. Use a command line similar to:
+
+gcc -shared -I../../../include -I../../../servers/slapd -Wall -g \
+ -o acl-posixgroup.so posixgroup.c
+
+to compile the posixGroup ACL plugin.
+
--- /dev/null
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2005 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#include <portable.h>
+
+#include <ac/string.h>
+#include <slap.h>
+#include <lutil.h>
+
+/* Need dynacl... */
+
+#ifdef SLAP_DYNACL
+
+typedef struct pg_t {
+ slap_style_t pg_style;
+ struct berval pg_pat;
+} pg_t;
+
+static ObjectClass *pg_posixGroup;
+static AttributeDescription *pg_memberUid;
+static ObjectClass *pg_posixAccount;
+static AttributeDescription *pg_uidNumber;
+
+static int pg_dynacl_destroy( void *priv );
+
+static int
+pg_dynacl_parse(
+ const char *fname,
+ int lineno,
+ const char *opts,
+ slap_style_t style,
+ const char *pattern,
+ void **privp )
+{
+ pg_t *pg;
+ int rc;
+ const char *text = NULL;
+ struct berval pat;
+
+ ber_str2bv( pattern, 0, 0, &pat );
+
+ pg = ch_calloc( 1, sizeof( pg_t ) );
+
+ pg->pg_style = style;
+
+ switch ( pg->pg_style ) {
+ case ACL_STYLE_BASE:
+ rc = dnNormalize( 0, NULL, NULL, &pat, &pg->pg_pat, NULL );
+ if ( rc != LDAP_SUCCESS ) {
+ fprintf( stderr, "%s line %d: posixGroup ACL: "
+ "unable to normalize DN \"%s\".\n",
+ fname, lineno, pattern );
+ goto cleanup;
+ }
+ break;
+
+ case ACL_STYLE_EXPAND:
+ ber_dupbv( &pg->pg_pat, &pat );
+ break;
+
+ default:
+ fprintf( stderr, "%s line %d: posixGroup ACL: "
+ "unsupported style \"%s\".\n",
+ fname, lineno, style_strings[ pg->pg_style ] );
+ goto cleanup;
+ }
+
+ /* TODO: use opts to allow the use of different
+ * group objects and member attributes */
+ if ( pg_posixGroup == NULL ) {
+ pg_posixGroup = oc_find( "posixGroup" );
+ if ( pg_posixGroup == NULL ) {
+ fprintf( stderr, "%s line %d: posixGroup ACL: "
+ "unable to lookup \"posixGroup\" "
+ "objectClass.\n",
+ fname, lineno );
+ goto cleanup;
+ }
+
+ pg_posixAccount = oc_find( "posixAccount" );
+ if ( pg_posixGroup == NULL ) {
+ fprintf( stderr, "%s line %d: posixGroup ACL: "
+ "unable to lookup \"posixAccount\" "
+ "objectClass.\n",
+ fname, lineno );
+ goto cleanup;
+ }
+
+ rc = slap_str2ad( "memberUid", &pg_memberUid, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ fprintf( stderr, "%s line %d: posixGroup ACL: "
+ "unable to lookup \"memberUid\" "
+ "attributeDescription (%d: %s).\n",
+ fname, lineno, rc, text );
+ goto cleanup;
+ }
+
+ rc = slap_str2ad( "uidNumber", &pg_uidNumber, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ fprintf( stderr, "%s line %d: posixGroup ACL: "
+ "unable to lookup \"uidNumber\" "
+ "attributeDescription (%d: %s).\n",
+ fname, lineno, rc, text );
+ goto cleanup;
+ }
+ }
+
+ *privp = (void *)pg;
+ return 0;
+
+cleanup:
+ (void)pg_dynacl_destroy( (void *)pg );
+
+ return 1;
+}
+
+static int
+pg_dynacl_unparse(
+ void *priv,
+ struct berval *bv )
+{
+ pg_t *pg = (pg_t *)priv;
+ char *ptr;
+
+ bv->bv_len = STRLENOF( " dynacl/posixGroup.expand=" ) + pg->pg_pat.bv_len;
+ bv->bv_val = ch_malloc( bv->bv_len + 1 );
+
+ ptr = lutil_strcopy( bv->bv_val, " dynacl/posixGroup" );
+
+ switch ( pg->pg_style ) {
+ case ACL_STYLE_BASE:
+ ptr = lutil_strcopy( ptr, ".exact=" );
+ break;
+
+ case ACL_STYLE_EXPAND:
+ ptr = lutil_strcopy( ptr, ".expand=" );
+ break;
+
+ default:
+ assert( 0 );
+ }
+
+ ptr = lutil_strncopy( ptr, pg->pg_pat.bv_val, pg->pg_pat.bv_len );
+ ptr[ 0 ] = '\0';
+
+ bv->bv_len = ptr - bv->bv_val;
+
+ return 0;
+}
+
+static int
+pg_dynacl_mask(
+ void *priv,
+ struct slap_op *op,
+ Entry *target,
+ AttributeDescription *desc,
+ struct berval *val,
+ int nmatch,
+ regmatch_t *matches,
+ slap_access_t *grant,
+ slap_access_t *deny )
+{
+ pg_t *pg = (pg_t *)priv;
+ Entry *group = NULL,
+ *user = NULL;
+ int rc;
+ Backend *be = op->o_bd,
+ *group_be = NULL,
+ *user_be = NULL;
+ struct berval group_ndn;
+
+ ACL_INVALIDATE( *deny );
+
+ /* get user */
+ if ( target && dn_match( &target->e_nname, &op->o_ndn ) ) {
+ user = target;
+ rc = LDAP_SUCCESS;
+
+ } else {
+ user_be = op->o_bd = select_backend( &op->o_ndn, 0, 0 );
+ if ( op->o_bd == NULL ) {
+ op->o_bd = be;
+ return 0;
+ }
+ rc = be_entry_get_rw( op, &op->o_ndn, pg_posixAccount, pg_uidNumber, 0, &user );
+ }
+
+ if ( rc != LDAP_SUCCESS || user == NULL ) {
+ op->o_bd = be;
+ return 0;
+ }
+
+ /* get target */
+ if ( pg->pg_style == ACL_STYLE_EXPAND ) {
+ char buf[ 1024 ];
+ struct berval bv;
+
+ bv.bv_len = sizeof( buf ) - 1;
+ bv.bv_val = buf;
+
+ if ( acl_string_expand( &bv, &pg->pg_pat,
+ target->e_nname.bv_val,
+ nmatch, matches ) )
+ {
+ goto cleanup;
+ }
+
+ if ( dnNormalize( 0, NULL, NULL, &bv, &group_ndn,
+ op->o_tmpmemctx ) != LDAP_SUCCESS )
+ {
+ /* did not expand to a valid dn */
+ goto cleanup;
+ }
+
+ } else {
+ group_ndn = pg->pg_pat;
+ }
+
+ if ( target && dn_match( &target->e_nname, &group_ndn ) ) {
+ group = target;
+ rc = LDAP_SUCCESS;
+
+ } else {
+ group_be = op->o_bd = select_backend( &group_ndn, 0, 0 );
+ if ( op->o_bd == NULL ) {
+ goto cleanup;
+ }
+ rc = be_entry_get_rw( op, &group_ndn, pg_posixGroup, pg_memberUid, 0, &group );
+ }
+
+ if ( group_ndn.bv_val != pg->pg_pat.bv_val ) {
+ op->o_tmpfree( group_ndn.bv_val, op->o_tmpmemctx );
+ }
+
+ if ( rc == LDAP_SUCCESS && group != NULL ) {
+ Attribute *a_uid,
+ *a_member;
+
+ a_uid = attr_find( user->e_attrs, pg_uidNumber);
+ if ( !a_uid || !BER_BVISNULL( &a_uid->a_nvals[ 1 ] ) ) {
+ rc = LDAP_NO_SUCH_ATTRIBUTE;
+
+ } else {
+ a_member = attr_find( group->e_attrs, pg_memberUid );
+ if ( !a_member ) {
+ rc = LDAP_NO_SUCH_ATTRIBUTE;
+
+ } else {
+ rc = value_find_ex( pg_memberUid,
+ SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
+ SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
+ a_member->a_nvals, &a_uid->a_nvals[ 0 ],
+ op->o_tmpmemctx );
+ }
+ }
+
+ } else {
+ rc = LDAP_NO_SUCH_OBJECT;
+ }
+
+
+ if ( rc == LDAP_SUCCESS ) {
+ ACL_LVL_ASSIGN_WRITE( *grant );
+ }
+
+cleanup:;
+ if ( group != NULL && group != target ) {
+ op->o_bd = group_be;
+ be_entry_release_r( op, group );
+ op->o_bd = be;
+ }
+
+ if ( user != NULL && user != target ) {
+ op->o_bd = user_be;
+ be_entry_release_r( op, group );
+ op->o_bd = be;
+ }
+
+ return 0;
+}
+
+static int
+pg_dynacl_destroy(
+ void *priv )
+{
+ pg_t *pg = (pg_t *)priv;
+
+ if ( pg != NULL ) {
+ if ( !BER_BVISNULL( &pg->pg_pat ) ) {
+ ber_memfree( pg->pg_pat.bv_val );
+ }
+ ch_free( pg );
+ }
+
+ return 0;
+}
+
+static struct slap_dynacl_t pg_dynacl = {
+ "posixGroup",
+ pg_dynacl_parse,
+ pg_dynacl_unparse,
+ pg_dynacl_mask,
+ pg_dynacl_destroy
+};
+
+int
+init_module( int argc, char *argv[] )
+{
+ return slap_dynacl_register( &pg_dynacl );
+}
+
+#endif /* SLAP_DYNACL */
--- /dev/null
+Copyright 2004-2005 The OpenLDAP Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
+This directory contains a slapd overlay, allop.
+The intended usage is as a global overlay for use with those clients
+that do not make use of the RFC3673 allOp ("+") in the requested
+attribute list, but expect all operational attributes to be returned.
+Usage: add to slapd.conf(5)
+
+moduleload path/to/allop.so
+
+overlay allop
+allop-URI <ldapURI>
+
+if the allop-URI is not given, the rootDSE, i.e. "ldap:///??base",
+is assumed.
+
+No Makefile is provided. Use a command line similar to:
+
+gcc -shared -I../../../include -I../../../servers/slapd -Wall -g \
+ -o allop.so allop.c
+
+to compile this overlay.
+
--- /dev/null
+/* allop.c - returns all operational attributes when appropriate */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2005 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion in
+ * OpenLDAP Software.
+ */
+
+/*
+ * The intended usage is as a global overlay for use with those clients
+ * that do not make use of the RFC3673 allOp ("+") in the requested
+ * attribute list, but expect all operational attributes to be returned.
+ * Usage: add
+ *
+
+overlay allop
+allop-URI <ldapURI>
+
+ *
+ * if the allop-URI is not given, the rootDSE, i.e. "ldap:///??base",
+ * is assumed.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "slap.h"
+
+#define SLAP_OVER_VERSION_REQUIRE(major,minor,patch) \
+ ( \
+ ( LDAP_VENDOR_VERSION_MAJOR == X || LDAP_VENDOR_VERSION_MAJOR >= (major) ) \
+ && ( LDAP_VENDOR_VERSION_MINOR == X || LDAP_VENDOR_VERSION_MINOR >= (minor) ) \
+ && ( LDAP_VENDOR_VERSION_PATCH == X || LDAP_VENDOR_VERSION_PATCH >= (patch) ) \
+ )
+
+#if !SLAP_OVER_VERSION_REQUIRE(2,3,0)
+#error "version mismatch"
+#endif
+
+typedef struct allop_t {
+ struct berval ao_ndn;
+ int ao_scope;
+} allop_t;
+
+static int
+allop_db_config(
+ BackendDB *be,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv )
+{
+ slap_overinst *on = (slap_overinst *)be->bd_info;
+ allop_t *ao = (allop_t *)on->on_bi.bi_private;
+
+ if ( strcasecmp( argv[ 0 ], "allop-uri" ) == 0 ) {
+ LDAPURLDesc *lud;
+ struct berval dn,
+ ndn;
+ int scope,
+ rc = LDAP_SUCCESS;
+
+ if ( argc != 2 ) {
+ fprintf( stderr, "%s line %d: "
+ "need exactly 1 arg "
+ "in \"allop-uri <ldapURI>\" "
+ "directive.\n",
+ fname, lineno );
+ return 1;
+ }
+
+ if ( ldap_url_parse( argv[ 1 ], &lud ) != LDAP_URL_SUCCESS ) {
+ return -1;
+ }
+
+ scope = lud->lud_scope;
+ if ( scope == LDAP_SCOPE_DEFAULT ) {
+ scope = LDAP_SCOPE_BASE;
+ }
+
+ if ( lud->lud_dn == NULL || lud->lud_dn[ 0 ] == '\0' ) {
+ if ( scope == LDAP_SCOPE_BASE ) {
+ BER_BVZERO( &ndn );
+
+ } else {
+ ber_str2bv( "", 0, 1, &ndn );
+ }
+
+ } else {
+
+ ber_str2bv( lud->lud_dn, 0, 0, &dn );
+ rc = dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL );
+ }
+
+ ldap_free_urldesc( lud );
+ if ( rc != LDAP_SUCCESS ) {
+ return -1;
+ }
+
+ if ( BER_BVISNULL( &ndn ) ) {
+ /* rootDSE */
+ if ( ao != NULL ) {
+ ch_free( ao->ao_ndn.bv_val );
+ ch_free( ao );
+ on->on_bi.bi_private = NULL;
+ }
+
+ } else {
+ if ( ao == NULL ) {
+ ao = ch_calloc( 1, sizeof( allop_t ) );
+ on->on_bi.bi_private = (void *)ao;
+
+ } else {
+ ch_free( ao->ao_ndn.bv_val );
+ }
+
+ ao->ao_ndn = ndn;
+ ao->ao_scope = scope;
+ }
+
+ } else {
+ return SLAP_CONF_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static int
+allop_db_destroy( BackendDB *be )
+{
+ slap_overinst *on = (slap_overinst *)be->bd_info;
+ allop_t *ao = (allop_t *)on->on_bi.bi_private;
+
+ if ( ao != NULL ) {
+ assert( !BER_BVISNULL( &ao->ao_ndn ) );
+
+ ch_free( ao->ao_ndn.bv_val );
+ ch_free( ao );
+ on->on_bi.bi_private = NULL;
+ }
+
+ return 0;
+}
+
+static int
+allop_op_search( Operation *op, SlapReply *rs )
+{
+ slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
+ allop_t *ao = (allop_t *)on->on_bi.bi_private;
+
+ slap_mask_t mask;
+ int i,
+ add_allUser = 0;
+
+ if ( ao == NULL ) {
+ if ( !BER_BVISEMPTY( &op->o_req_ndn )
+ || op->ors_scope != LDAP_SCOPE_BASE )
+ {
+ return SLAP_CB_CONTINUE;
+ }
+
+ } else {
+ if ( !dnIsSuffix( &op->o_req_ndn, &ao->ao_ndn ) ) {
+ return SLAP_CB_CONTINUE;
+ }
+
+ switch ( ao->ao_scope ) {
+ case LDAP_SCOPE_BASE:
+ if ( op->o_req_ndn.bv_len != ao->ao_ndn.bv_len ) {
+ return SLAP_CB_CONTINUE;
+ }
+ break;
+
+ case LDAP_SCOPE_ONELEVEL:
+ if ( op->ors_scope == LDAP_SCOPE_BASE ) {
+ struct berval rdn = op->o_req_ndn;
+
+ rdn.bv_len -= ao->ao_ndn.bv_len + STRLENOF( "," );
+ if ( !dnIsOneLevelRDN( &rdn ) ) {
+ return SLAP_CB_CONTINUE;
+ }
+
+ break;
+ }
+ return SLAP_CB_CONTINUE;
+
+ case LDAP_SCOPE_SUBTREE:
+ break;
+ }
+ }
+
+ mask = slap_attr_flags( op->ors_attrs );
+ if ( SLAP_OPATTRS( mask ) ) {
+ return SLAP_CB_CONTINUE;
+ }
+
+ if ( !SLAP_USERATTRS( mask ) ) {
+ return SLAP_CB_CONTINUE;
+ }
+
+ i = 0;
+ if ( op->ors_attrs == NULL ) {
+ add_allUser = 1;
+
+ } else {
+ for ( ; !BER_BVISNULL( &op->ors_attrs[ i ].an_name ); i++ )
+ ;
+ }
+
+ op->ors_attrs = op->o_tmprealloc( op->ors_attrs,
+ sizeof( AttributeName ) * ( i + add_allUser + 2 ),
+ op->o_tmpmemctx );
+
+ if ( add_allUser ) {
+ op->ors_attrs[ i ] = slap_anlist_all_user_attributes[ 0 ];
+ i++;
+ }
+
+ op->ors_attrs[ i ] = slap_anlist_all_operational_attributes[ 0 ];
+
+ BER_BVZERO( &op->ors_attrs[ i + 1 ].an_name );
+
+ return SLAP_CB_CONTINUE;
+}
+
+static slap_overinst allop;
+
+int
+allop_init()
+{
+ allop.on_bi.bi_type = "allop";
+
+ allop.on_bi.bi_db_config = allop_db_config;
+ allop.on_bi.bi_db_destroy = allop_db_destroy;
+
+ allop.on_bi.bi_op_search = allop_op_search;
+
+ return overlay_register( &allop );
+}
+
+int
+init_module( int argc, char *argv[] )
+{
+ return allop_init();
+}
+
--- /dev/null
+.TH SLAPO-ALLOP 5 "RELEASEDATE" "OpenLDAP LDVERSION"
+.\" Copyright 2005 The OpenLDAP Foundation All Rights Reserved.
+.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
+.\" $OpenLDAP$
+.SH NAME
+slapo-allop \- All Operational Attributes overlay
+.SH SYNOPSIS
+ETCDIR/slapd.conf
+.SH DESCRIPTION
+The All Operational Attributes overlay is designed to allow slapd to
+interoperate with dumb clients that expect all attributes, including
+operational ones, to be returned when "*" or an empty attribute list
+is requested, as opposed to RFC2251 and RFC3673.
+.SH CONFIGURATION
+These
+.B slapd.conf
+options apply to the All Operational overlay.
+They should appear after the
+.B overlay
+directive and before any subsequent
+.B database
+directive.
+.TP
+.B allop-URI <ldapURI>
+Specify the base and the scope of search operations that trigger the overlay.
+By default, it is "ldap:///??base", i.e. it only applies to the rootDSE.
+This requires the overlay to be instantited as global.
+
+.SH EXAMPLES
+.LP
+default behavior: only affects requests to the rootDSE
+.nf
+ # global
+ overlay allop
+.fi
+.LP
+affects all requests
+.nf
+ # global
+ overlay allop
+ allop-URI "ldap:///??sub"
+.fi
+.LP
+affects only requests directed to the suffix of a database
+.nf
+ # per database
+ database bdb
+ suffix "dc=example,dc=com"
+ # database specific directives ...
+ overlay allop
+ allop-URI "ldap:///dc=example,dc=com??base"
+.fi
+
+.SH FILES
+.TP
+ETCDIR/slapd.conf
+default slapd configuration file
+.SH SEE ALSO
+.BR slapd.conf (5).
+
+.SH ACKNOWLEDGEMENTS
+.P
+This module was written in 2005 by Pierangelo Masarati for SysNet s.n.c.
--- /dev/null
+Copyright 2004-2005 The OpenLDAP Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
+This directory contains a slapd overlay, allop.
+The intended usage is as a global overlay for use with those clients
+that do not make use of the RFC3673 allOp ("+") in the requested
+attribute list, but expect all operational attributes to be returned.
+Usage: add to slapd.conf(5)
+
+moduleload path/to/allop.so
+
+overlay allop
+allop-URI <ldapURI>
+
+if the allop-URI is not given, the rootDSE, i.e. "ldap:///??base",
+is assumed.
+
+No Makefile is provided. Use a command line similar to:
+
+gcc -shared -I../../../include -I../../../servers/slapd -Wall -g \
+ -o allop.so allop.c
+
+to compile this overlay.
+
--- /dev/null
+/* allop.c - returns all operational attributes when appropriate */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2005 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion in
+ * OpenLDAP Software.
+ */
+
+/*
+ * The intended usage is as a global overlay for use with those clients
+ * that do not make use of the RFC3673 allOp ("+") in the requested
+ * attribute list, but expect all operational attributes to be returned.
+ * Usage: add
+ *
+
+overlay allop
+allop-URI <ldapURI>
+
+ *
+ * if the allop-URI is not given, the rootDSE, i.e. "ldap:///??base",
+ * is assumed.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "slap.h"
+
+#define SLAP_OVER_VERSION_REQUIRE(major,minor,patch) \
+ ( \
+ ( LDAP_VENDOR_VERSION_MAJOR == X || LDAP_VENDOR_VERSION_MAJOR >= (major) ) \
+ && ( LDAP_VENDOR_VERSION_MINOR == X || LDAP_VENDOR_VERSION_MINOR >= (minor) ) \
+ && ( LDAP_VENDOR_VERSION_PATCH == X || LDAP_VENDOR_VERSION_PATCH >= (patch) ) \
+ )
+
+#if !SLAP_OVER_VERSION_REQUIRE(2,3,0)
+#error "version mismatch"
+#endif
+
+typedef struct allop_t {
+ struct berval ao_ndn;
+ int ao_scope;
+} allop_t;
+
+static int
+allop_db_config(
+ BackendDB *be,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv )
+{
+ slap_overinst *on = (slap_overinst *)be->bd_info;
+ allop_t *ao = (allop_t *)on->on_bi.bi_private;
+
+ if ( strcasecmp( argv[ 0 ], "allop-uri" ) == 0 ) {
+ LDAPURLDesc *lud;
+ struct berval dn,
+ ndn;
+ int scope,
+ rc = LDAP_SUCCESS;
+
+ if ( argc != 2 ) {
+ fprintf( stderr, "%s line %d: "
+ "need exactly 1 arg "
+ "in \"allop-uri <ldapURI>\" "
+ "directive.\n",
+ fname, lineno );
+ return 1;
+ }
+
+ if ( ldap_url_parse( argv[ 1 ], &lud ) != LDAP_URL_SUCCESS ) {
+ return -1;
+ }
+
+ scope = lud->lud_scope;
+ if ( scope == LDAP_SCOPE_DEFAULT ) {
+ scope = LDAP_SCOPE_BASE;
+ }
+
+ if ( lud->lud_dn == NULL || lud->lud_dn[ 0 ] == '\0' ) {
+ if ( scope == LDAP_SCOPE_BASE ) {
+ BER_BVZERO( &ndn );
+
+ } else {
+ ber_str2bv( "", 0, 1, &ndn );
+ }
+
+ } else {
+
+ ber_str2bv( lud->lud_dn, 0, 0, &dn );
+ rc = dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL );
+ }
+
+ ldap_free_urldesc( lud );
+ if ( rc != LDAP_SUCCESS ) {
+ return -1;
+ }
+
+ if ( BER_BVISNULL( &ndn ) ) {
+ /* rootDSE */
+ if ( ao != NULL ) {
+ ch_free( ao->ao_ndn.bv_val );
+ ch_free( ao );
+ on->on_bi.bi_private = NULL;
+ }
+
+ } else {
+ if ( ao == NULL ) {
+ ao = ch_calloc( 1, sizeof( allop_t ) );
+ on->on_bi.bi_private = (void *)ao;
+
+ } else {
+ ch_free( ao->ao_ndn.bv_val );
+ }
+
+ ao->ao_ndn = ndn;
+ ao->ao_scope = scope;
+ }
+
+ } else {
+ return SLAP_CONF_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static int
+allop_db_destroy( BackendDB *be )
+{
+ slap_overinst *on = (slap_overinst *)be->bd_info;
+ allop_t *ao = (allop_t *)on->on_bi.bi_private;
+
+ if ( ao != NULL ) {
+ assert( !BER_BVISNULL( &ao->ao_ndn ) );
+
+ ch_free( ao->ao_ndn.bv_val );
+ ch_free( ao );
+ on->on_bi.bi_private = NULL;
+ }
+
+ return 0;
+}
+
+static int
+allop_op_search( Operation *op, SlapReply *rs )
+{
+ slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
+ allop_t *ao = (allop_t *)on->on_bi.bi_private;
+
+ slap_mask_t mask;
+ int i,
+ add_allUser = 0;
+
+ if ( ao == NULL ) {
+ if ( !BER_BVISEMPTY( &op->o_req_ndn )
+ || op->ors_scope != LDAP_SCOPE_BASE )
+ {
+ return SLAP_CB_CONTINUE;
+ }
+
+ } else {
+ if ( !dnIsSuffix( &op->o_req_ndn, &ao->ao_ndn ) ) {
+ return SLAP_CB_CONTINUE;
+ }
+
+ switch ( ao->ao_scope ) {
+ case LDAP_SCOPE_BASE:
+ if ( op->o_req_ndn.bv_len != ao->ao_ndn.bv_len ) {
+ return SLAP_CB_CONTINUE;
+ }
+ break;
+
+ case LDAP_SCOPE_ONELEVEL:
+ if ( op->ors_scope == LDAP_SCOPE_BASE ) {
+ struct berval rdn = op->o_req_ndn;
+
+ rdn.bv_len -= ao->ao_ndn.bv_len + STRLENOF( "," );
+ if ( !dnIsOneLevelRDN( &rdn ) ) {
+ return SLAP_CB_CONTINUE;
+ }
+
+ break;
+ }
+ return SLAP_CB_CONTINUE;
+
+ case LDAP_SCOPE_SUBTREE:
+ break;
+ }
+ }
+
+ mask = slap_attr_flags( op->ors_attrs );
+ if ( SLAP_OPATTRS( mask ) ) {
+ return SLAP_CB_CONTINUE;
+ }
+
+ if ( !SLAP_USERATTRS( mask ) ) {
+ return SLAP_CB_CONTINUE;
+ }
+
+ i = 0;
+ if ( op->ors_attrs == NULL ) {
+ add_allUser = 1;
+
+ } else {
+ for ( ; !BER_BVISNULL( &op->ors_attrs[ i ].an_name ); i++ )
+ ;
+ }
+
+ op->ors_attrs = op->o_tmprealloc( op->ors_attrs,
+ sizeof( AttributeName ) * ( i + add_allUser + 2 ),
+ op->o_tmpmemctx );
+
+ if ( add_allUser ) {
+ op->ors_attrs[ i ] = slap_anlist_all_user_attributes[ 0 ];
+ i++;
+ }
+
+ op->ors_attrs[ i ] = slap_anlist_all_operational_attributes[ 0 ];
+
+ BER_BVZERO( &op->ors_attrs[ i + 1 ].an_name );
+
+ return SLAP_CB_CONTINUE;
+}
+
+static slap_overinst allop;
+
+int
+allop_init()
+{
+ allop.on_bi.bi_type = "allop";
+
+ allop.on_bi.bi_db_config = allop_db_config;
+ allop.on_bi.bi_db_destroy = allop_db_destroy;
+
+ allop.on_bi.bi_op_search = allop_op_search;
+
+ return overlay_register( &allop );
+}
+
+int
+init_module( int argc, char *argv[] )
+{
+ return allop_init();
+}
+
--- /dev/null
+.TH SLAPO-ALLOP 5 "RELEASEDATE" "OpenLDAP LDVERSION"
+.\" Copyright 2005 The OpenLDAP Foundation All Rights Reserved.
+.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
+.\" $OpenLDAP$
+.SH NAME
+slapo-allop \- All Operational Attributes overlay
+.SH SYNOPSIS
+ETCDIR/slapd.conf
+.SH DESCRIPTION
+The All Operational Attributes overlay is designed to allow slapd to
+interoperate with dumb clients that expect all attributes, including
+operational ones, to be returned when "*" or an empty attribute list
+is requested, as opposed to RFC2251 and RFC3673.
+.SH CONFIGURATION
+These
+.B slapd.conf
+options apply to the All Operational overlay.
+They should appear after the
+.B overlay
+directive and before any subsequent
+.B database
+directive.
+.TP
+.B allop-URI <ldapURI>
+Specify the base and the scope of search operations that trigger the overlay.
+By default, it is "ldap:///??base", i.e. it only applies to the rootDSE.
+This requires the overlay to be instantited as global.
+
+.SH EXAMPLES
+.LP
+default behavior: only affects requests to the rootDSE
+.nf
+ # global
+ overlay allop
+.fi
+.LP
+affects all requests
+.nf
+ # global
+ overlay allop
+ allop-URI "ldap:///??sub"
+.fi
+.LP
+affects only requests directed to the suffix of a database
+.nf
+ # per database
+ database bdb
+ suffix "dc=example,dc=com"
+ # database specific directives ...
+ overlay allop
+ allop-URI "ldap:///dc=example,dc=com??base"
+.fi
+
+.SH FILES
+.TP
+ETCDIR/slapd.conf
+default slapd configuration file
+.SH SEE ALSO
+.BR slapd.conf (5).
+
+.SH ACKNOWLEDGEMENTS
+.P
+This module was written in 2005 by Pierangelo Masarati for SysNet s.n.c.
+
+
+
Network Working Group J. Sermersheim
Internet-Draft Novell, Inc
-Expires: April 24, 2005 L. Poitou
+Expires: January 18, 2006 L. Poitou
Sun Microsystems
- October 24, 2004
+ July 17, 2005
Password Policy for LDAP Directories
- draft-behera-ldap-password-policy-08.txt
+ draft-behera-ldap-password-policy-09.txt
Status of this Memo
- This document is an Internet-Draft and is subject to all provisions
- of section 3 of RFC 3667. By submitting this Internet-Draft, each
- author represents that any applicable patent or other IPR claims of
- which he or she is aware have been or will be disclosed, and any of
- which he or she become aware will be disclosed, in accordance with
- RFC 3668.
+ By submitting this Internet-Draft, each author represents that any
+ applicable patent or other IPR claims of which he or she is aware
+ have been or will be disclosed, and any of which he or she becomes
+ aware will be disclosed, in accordance with Section 6 of BCP 79.
Internet-Drafts are working documents of the Internet Engineering
Task Force (IETF), its areas, and its working groups. Note that
- other groups may also distribute working documents as
- Internet-Drafts.
+ other groups may also distribute working documents as Internet-
+ Drafts.
Internet-Drafts are draft documents valid for a maximum of six months
and may be updated, replaced, or obsoleted by other documents at any
The list of Internet-Draft Shadow Directories can be accessed at
http://www.ietf.org/shadow.html.
- This Internet-Draft will expire on April 24, 2005.
+ This Internet-Draft will expire on January 18, 2006.
Copyright Notice
- Copyright (C) The Internet Society (2004).
+ Copyright (C) The Internet Society (2005).
Abstract
improve the security of LDAP directories and make it difficult for
password cracking programs to break into directories, it is desirable
to enforce a set of rules on password usage. These rules are made to
+ ensure that users change their passwords periodically, passwords meet
-Sermersheim & Poitou Expires April 24, 2005 [Page 1]
+Sermersheim & Poitou Expires January 18, 2006 [Page 1]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
- ensure that users change their passwords periodically, passwords meet
construction requirements, the re-use of old password is restricted,
and users are locked out after a certain number of failed attempts.
LDAP Extensions mailing list <ldapext@ietf.org>. Please send
editorial comments directly to the authors.
-Table of Contents
- 1. Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
- 2. Conventions . . . . . . . . . . . . . . . . . . . . . . . . . 5
- 3. Application of password policy . . . . . . . . . . . . . . . . 6
- 4. Articles of password policy . . . . . . . . . . . . . . . . . 7
- 4.1 Password Usage Policy . . . . . . . . . . . . . . . . . . . . 7
- 4.2 Password Modification Policy . . . . . . . . . . . . . . . . . 7
- 4.3 Restriction of the Password Policy . . . . . . . . . . . . . . 10
- 5. Schema used for Password Policy . . . . . . . . . . . . . . . 11
- 5.1 The pwdPolicy Object Class . . . . . . . . . . . . . . . . . . 11
- 5.2 Attribute Types used in the pwdPolicy ObjectClass . . . . . . 11
- 5.3 Attribute Types for Password Policy State Information . . . . 16
- 6. Controls used for Password Policy . . . . . . . . . . . . . . 20
- 6.1 Request Control . . . . . . . . . . . . . . . . . . . . . . . 20
- 6.2 Response Control . . . . . . . . . . . . . . . . . . . . . . . 20
- 7. Policy Decision Points . . . . . . . . . . . . . . . . . . . . 22
- 7.1 Locked Account Check . . . . . . . . . . . . . . . . . . . . . 22
- 7.2 Password Must be Changed Now Check . . . . . . . . . . . . . . 22
- 7.3 Password Expiration Check . . . . . . . . . . . . . . . . . . 22
- 7.4 Remaining Grace AuthN Check . . . . . . . . . . . . . . . . . 22
- 7.5 Time Before Expiration Check . . . . . . . . . . . . . . . . . 23
- 7.6 Intruder Detection Check . . . . . . . . . . . . . . . . . . . 23
- 7.7 Password Too Young Check . . . . . . . . . . . . . . . . . . . 23
- 8. Server Policy Enforcement Points . . . . . . . . . . . . . . . 24
- 8.1 Password-based Authentication . . . . . . . . . . . . . . . . 24
- 8.2 Password Update Operations . . . . . . . . . . . . . . . . . . 26
- 8.3 Other Operations . . . . . . . . . . . . . . . . . . . . . . . 29
- 9. Client Policy Enforcement Points . . . . . . . . . . . . . . . 30
- 9.1 Bind Operation . . . . . . . . . . . . . . . . . . . . . . . . 30
- 9.2 Modify Operations . . . . . . . . . . . . . . . . . . . . . . 30
- 9.3 Add Operation . . . . . . . . . . . . . . . . . . . . . . . . 31
- 9.4 Compare Operation . . . . . . . . . . . . . . . . . . . . . . 32
- 9.5 Other Operations . . . . . . . . . . . . . . . . . . . . . . . 32
- 10. Administration of the Password Policy . . . . . . . . . . . . 33
- 11. Password Policy and Replication . . . . . . . . . . . . . . . 34
- 12. Security Considerations . . . . . . . . . . . . . . . . . . . 35
- 13. Acknowledgement . . . . . . . . . . . . . . . . . . . . . . . 36
-
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 2]
-\f
-Internet-Draft Password Policy for LDAP Directories October 2004
- 14. Normative References . . . . . . . . . . . . . . . . . . . . . 36
- Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 37
- Intellectual Property and Copyright Statements . . . . . . . . 38
+Sermersheim & Poitou Expires January 18, 2006 [Page 2]
+\f
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
+Table of Contents
+
+ 1. Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
+ 2. Conventions . . . . . . . . . . . . . . . . . . . . . . . . . 5
+ 3. Application of password policy . . . . . . . . . . . . . . . . 6
+ 4. Articles of password policy . . . . . . . . . . . . . . . . . 7
+ 4.1 Password Usage Policy . . . . . . . . . . . . . . . . . . . . 7
+ 4.2 Password Modification Policy . . . . . . . . . . . . . . . . . 7
+ 4.3 Restriction of the Password Policy . . . . . . . . . . . . . . 10
+ 5. Schema used for Password Policy . . . . . . . . . . . . . . . 11
+ 5.1 The pwdPolicy Object Class . . . . . . . . . . . . . . . . . . 11
+ 5.2 Attribute Types used in the pwdPolicy ObjectClass . . . . . . 11
+ 5.3 Attribute Types for Password Policy State Information . . . . 16
+ 6. Controls used for Password Policy . . . . . . . . . . . . . . 21
+ 6.1 Request Control . . . . . . . . . . . . . . . . . . . . . . . 21
+ 6.2 Response Control . . . . . . . . . . . . . . . . . . . . . . . 21
+ 7. Policy Decision Points . . . . . . . . . . . . . . . . . . . . 23
+ 7.1 Locked Account Check . . . . . . . . . . . . . . . . . . . . . 23
+ 7.2 Password Must be Changed Now Check . . . . . . . . . . . . . . 23
+ 7.3 Password Expiration Check . . . . . . . . . . . . . . . . . . 23
+ 7.4 Remaining Grace AuthN Check . . . . . . . . . . . . . . . . . 23
+ 7.5 Time Before Expiration Check . . . . . . . . . . . . . . . . . 24
+ 7.6 Intruder Detection Check . . . . . . . . . . . . . . . . . . . 24
+ 7.7 Password Too Young Check . . . . . . . . . . . . . . . . . . . 24
+ 8. Server Policy Enforcement Points . . . . . . . . . . . . . . . 25
+ 8.1 Password-based Authentication . . . . . . . . . . . . . . . . 25
+ 8.2 Password Update Operations . . . . . . . . . . . . . . . . . . 27
+ 8.3 Other Operations . . . . . . . . . . . . . . . . . . . . . . . 30
+ 9. Client Policy Enforcement Points . . . . . . . . . . . . . . . 31
+ 9.1 Bind Operation . . . . . . . . . . . . . . . . . . . . . . . . 31
+ 9.2 Modify Operations . . . . . . . . . . . . . . . . . . . . . . 32
+ 9.3 Add Operation . . . . . . . . . . . . . . . . . . . . . . . . 33
+ 9.4 Compare Operation . . . . . . . . . . . . . . . . . . . . . . 33
+ 9.5 Other Operations . . . . . . . . . . . . . . . . . . . . . . . 34
+ 10. Administration of the Password Policy . . . . . . . . . . . . 35
+ 11. Password Policy and Replication . . . . . . . . . . . . . . . 36
+ 12. Security Considerations . . . . . . . . . . . . . . . . . . . 37
+ 13. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 38
+ 14. Acknowledgement . . . . . . . . . . . . . . . . . . . . . . . 39
+ 15. Normative References . . . . . . . . . . . . . . . . . . . . . 39
+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 40
+ Intellectual Property and Copyright Statements . . . . . . . . 41
-Sermersheim & Poitou Expires April 24, 2005 [Page 3]
+Sermersheim & Poitou Expires January 18, 2006 [Page 3]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
1. Overview
other things, this policy includes:
o Whether and when passwords expire.
+
o Whether failed bind attempts cause the account to be locked.
+
o If and how users are able to change their passwords.
In order to achieve greater security protection and ensure
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 4]
+Sermersheim & Poitou Expires January 18, 2006 [Page 4]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
2. Conventions
-Sermersheim & Poitou Expires April 24, 2005 [Page 5]
+Sermersheim & Poitou Expires January 18, 2006 [Page 5]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
3. Application of password policy
-Sermersheim & Poitou Expires April 24, 2005 [Page 6]
+Sermersheim & Poitou Expires January 18, 2006 [Page 6]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
4. Articles of password policy
4.1.1 Password Guessing Limit
In order to prevent intruders from guessing a user's password, a
- mechanism exists to track the number of failed authentication
- attempts, and take action when a limit is reached. This policy
- consists of five parts:
+ mechanism exists to track the number of consecutive failed
+ authentication attempts, and take action when a limit is reached.
+ This policy consists of five parts:
o A configurable limit on failed authentication attempts.
+
o A counter to track the number of failed authentication attempts.
+
o A timeframe in which the limit of consecutive failed
authentication attempts must happen before action is taken.
+
o The action to be taken when the limit is reached. The action will
either be nothing, or the account will be locked.
+
o An amount of time the account is locked (if it is to be locked).
This can be indefinite.
+
4.2 Password Modification Policy
This section describes policy enforced while users are modifying
password attribute during an add or modify operation, but MAY be done
by other means such as an extended operation.
-4.2.1 Password Expiration, Expiration Warning, and Grace
- Authentications
- One of the key properties of a password is the fact that it is not
- well known. If a password is frequently changed, the chances of that
- user's account being broken into are minimized.
-Sermersheim & Poitou Expires April 24, 2005 [Page 7]
+Sermersheim & Poitou Expires January 18, 2006 [Page 7]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
+4.2.1 Password Expiration, Expiration Warning, and Grace
+ Authentications
+ One of the key properties of a password is the fact that it is not
+ well known. If a password is frequently changed, the chances of that
+ user's account being broken into are minimized.
Password policy administrators may deploy a password policy that
causes passwords to expire after a given amount of time - thus
o A warning may be returned to the user sometime before his password
is due to expire. If the user fails to heed this warning before
the expiration time, his account will be locked.
+
o The user may bind to the directory a preset number of times after
her password has expired. If she fails to change her password
during one of her 'grace' authentications, her account will be
locked.
+
4.2.2 Password History
When the Password Expiration policy is used, an additional mechanism
This process may be made less attractive to users by employing a
minimum age for passwords. If users are forced to wait 24 hours
+
+
+
+Sermersheim & Poitou Expires January 18, 2006 [Page 8]
+\f
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
between password changes, they may be less likely to cycle through a
history of 10 passwords.
are easy to guess, a password quality policy may be employed. This
policy consists of two general mechanisms - ensuring that passwords
conform to a defined quality criterion and ensuring that they are of
-
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 8]
-\f
-Internet-Draft Password Policy for LDAP Directories October 2004
-
-
a minimum length.
Forcing a password to comply with the quality policy may imply a
variety of things including:
o Disallowing trivial or well-known words make up the password.
+
o Forcing a certain number of digits be used.
+
o Disallowing anagrams of the user's name.
The implementation of this policy meets with the following problems:
before being sent, the server has no way of enforcing this policy.
Therefore, the onus of enforcing this policy falls upon client
implementations.
+
o There are no specific definitions of what 'quality checking'
means. This can lead to unexpected behavior in a heterogeneous
environment.
+
4.2.5 User Defined Passwords
In some cases, it is desirable to disallow users from adding and
updating their own passwords. This policy makes this functionality
possible.
- This implies that certain other policy, such as password expiration
- is not enforced.
-
4.2.6 Password Change after Reset
This policy forces the user to update her password after it has been
This is needed in scenarios where a password administrator has set or
reset the password to a well-known value.
+
+
+
+
+Sermersheim & Poitou Expires January 18, 2006 [Page 9]
+\f
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
4.2.7 Safe Modification
As directories become more commonly used, it will not be unusual for
This policy forces the user to prove his identity by specifying the
old password during a password modify operation.
-
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 9]
-\f
-Internet-Draft Password Policy for LDAP Directories October 2004
-
-
{TODO: This allows a dictionary attack unless we specify that this is
- also subject to intruder detection}
+ also subject to intruder detection. One solution is to require users
+ to authN prior to changing password. Another solution is to perform
+ intruder detection checks when the password for a non-authenticated
+ identity is being updated}
4.3 Restriction of the Password Policy
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 10]
+Sermersheim & Poitou Expires January 18, 2006 [Page 10]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
5. Schema used for Password Policy
$ pwdLockoutDuration $ pwdMaxFailure $ pwdFailureCountInterval $
pwdMustChange $ pwdAllowUserChange $ pwdSafeModify ) )
+
5.2 Attribute Types used in the pwdPolicy ObjectClass
Following are the attribute types used by the pwdPolicy object class.
EQUALITY objectIdentifierMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
+
5.2.2 pwdMinAge
This attribute holds the number of seconds that must elapse between
modifications to the password. If this attribute is not present, 0
seconds is assumed.
- ( 1.3.6.1.4.1.42.2.27.8.1.2
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 11]
+Sermersheim & Poitou Expires January 18, 2006 [Page 11]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
+ ( 1.3.6.1.4.1.42.2.27.8.1.2
NAME 'pwdMinAge'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
+
5.2.3 pwdMaxAge
This attribute holds the number of seconds after which a modified
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
+
5.2.4 pwdInHistory
This attribute specifies the maximum number of used passwords stored
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
+
5.2.5 pwdCheckQuality
{TODO: Consider changing the syntax to OID. Each OID will list a
quality rule (like min len, # of special characters, etc). These
- rules can be specified outsid ethis document.}
+ rules can be specified outside this document.}
{TODO: Note that even though this is meant to be a check that happens
during password modification, it may also be allowed to happen during
authN. This is useful for situations where the password is encrypted
- when modified, but decrypted when used to authN.}
-
- This attribute indicates how the password quality will be verified
- while being modified or added. If this attribute is not present, or
-Sermersheim & Poitou Expires April 24, 2005 [Page 12]
+Sermersheim & Poitou Expires January 18, 2006 [Page 12]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
+ when modified, but decrypted when used to authN.}
+
+ This attribute indicates how the password quality will be verified
+ while being modified or added. If this attribute is not present, or
if the value is '0', quality checking will not be enforced. A value
of '1' indicates that the server will check the quality, and if the
server is unable to check it (due to a hashed password or other
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
+
5.2.6 pwdMinLength
When quality checking is enabled, this attribute holds the minimum
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
+
5.2.7 pwdExpireWarning
This attribute specifies the maximum number of seconds before a
( 1.3.6.1.4.1.42.2.27.8.1.7
NAME 'pwdExpireWarning'
EQUALITY integerMatch
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
- SINGLE-VALUE )
-5.2.8 pwdGraceAuthNLimit
- This attribute specifies the number of times an expired password can
+Sermersheim & Poitou Expires January 18, 2006 [Page 13]
+\f
+Internet-Draft Password Policy for LDAP Directories July 2005
-Sermersheim & Poitou Expires April 24, 2005 [Page 13]
-\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE )
+
+5.2.8 pwdGraceAuthNLimit
+ This attribute specifies the number of times an expired password can
be used to authenticate. If this attribute is not present or if the
value is 0, authentication will fail.
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
+
5.2.9 pwdLockout
This attribute indicates, when its value is "TRUE", that the password
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE )
+
5.2.10 pwdLockoutDuration
This attribute holds the number of seconds that the password cannot
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
+
+
+Sermersheim & Poitou Expires January 18, 2006 [Page 14]
+\f
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
5.2.11 pwdMaxFailure
This attribute specifies the number of consecutive failed bind
If this attribute is not present, or if the value is 0, this policy
is not checked, and the value of pwdLockout will be ignored.
-
-
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 14]
-\f
-Internet-Draft Password Policy for LDAP Directories October 2004
-
-
( 1.3.6.1.4.1.42.2.27.8.1.11
NAME 'pwdMaxFailure'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
+
5.2.12 pwdFailureCountInterval
This attribute holds the number of seconds after which the password
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
+
5.2.13 pwdMustChange
This attribute specifies with a value of "TRUE" that users must
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE )
+
+
+
+
+Sermersheim & Poitou Expires January 18, 2006 [Page 15]
+\f
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
5.2.14 pwdAllowUserChange
This attribute indicates whether users can change their own
access control mechanism.
( 1.3.6.1.4.1.42.2.27.8.1.14
-
-
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 15]
-\f
-Internet-Draft Password Policy for LDAP Directories October 2004
-
-
NAME 'pwdAllowUserChange'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE )
+
5.2.15 pwdSafeModify
This attribute specifies whether or not the existing password must be
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE )
+
5.3 Attribute Types for Password Policy State Information
Password policy state information must be maintained for each user.
(1.3.6.1.4.1.1466.115.121.1.38). The attribute type descriptor
(short name) MUST be used.
+
+
+Sermersheim & Poitou Expires January 18, 2006 [Page 16]
+\f
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
For example, if the pwdPolicy object has for pwdAttribute
"userPassword" then the pwdChangedTime operational attribute, in a
user entry, will be:
operation, and does not specify an option, all subtypes of that
policy state attribute are returned.
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 16]
-\f
-Internet-Draft Password Policy for LDAP Directories October 2004
-
-
5.3.2 pwdChangedTime
This attribute specifies the last time the entry's password was
ORDERING generalizedTimeOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE
+ NO-USER-MODIFICATION
USAGE directoryOperation )
+
5.3.3 pwdAccountLockedTime
This attribute holds the time that the user's account was locked. A
ORDERING generalizedTimeOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE
+ NO-USER-MODIFICATION
USAGE directoryOperation )
+
+
+
+
+
+Sermersheim & Poitou Expires January 18, 2006 [Page 17]
+\f
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
5.3.4 pwdFailureTime
This attribute holds the timestamps of the consecutive authentication
EQUALITY generalizedTimeMatch
ORDERING generalizedTimeOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
+ NO-USER-MODIFICATION
USAGE directoryOperation )
-
-
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 17]
-\f
-Internet-Draft Password Policy for LDAP Directories October 2004
-
-
5.3.5 pwdHistory
This attribute holds a history of previously used passwords. Values
( 1.3.6.1.4.1.42.2.27.8.1.20
NAME 'pwdHistory'
DESC 'The history of user s passwords'
+
+
+
+Sermersheim & Poitou Expires January 18, 2006 [Page 18]
+\f
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
EQUALITY octetStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
+ NO-USER-MODIFICATION
USAGE directoryOperation )
+
5.3.6 pwdGraceUseTime
This attribute holds the timestamps of grace authentications after a
password has expired'
EQUALITY generalizedTimeMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
-
-
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 18]
-\f
-Internet-Draft Password Policy for LDAP Directories October 2004
-
-
+ NO-USER-MODIFICATION
USAGE directoryOperation )
+
5.3.7 pwdReset
This attribute holds a flag to indicate (when TRUE) that the password
has been updated by the password administrator and must be changed by
- the user on first authentication.
+ the user.
( 1.3.6.1.4.1.42.2.27.8.1.22
NAME 'pwdReset'
SINGLE-VALUE
USAGE directoryOperation )
+
5.3.8 pwdPolicySubentry
This attribute points to the pwdPolicy subentry in effect for this
EQUALITY distinguishedNameMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
SINGLE-VALUE
+ NO-USER-MODIFICATION
+
+
+
+Sermersheim & Poitou Expires January 18, 2006 [Page 19]
+\f
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
USAGE directoryOperation )
-Sermersheim & Poitou Expires April 24, 2005 [Page 19]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Sermersheim & Poitou Expires January 18, 2006 [Page 20]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
6. Controls used for Password Policy
response control contains various warnings and errors associated with
password policy.
+ {TODO: add a note about advertisement and discovery}
+
6.1 Request Control
This control MAY be sent with any LDAP request message in order to
passwordInHistory (8) } OPTIONAL }
The timeBeforeExpiration warning specifies the number of seconds
- before a password will expire. The graceAuthNsRemaining warning
- specifies the remaining number of times a user will be allowed to
-Sermersheim & Poitou Expires April 24, 2005 [Page 20]
+Sermersheim & Poitou Expires January 18, 2006 [Page 21]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
+ before a password will expire. The graceAuthNsRemaining warning
+ specifies the remaining number of times a user will be allowed to
authenticate with an expired password. The passwordExpired error
signifies that the password has expired and must be reset. The
changeAfterReset error signifies that the password must be changed
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 21]
+Sermersheim & Poitou Expires January 18, 2006 [Page 22]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
7. Policy Decision Points
if any of these conditions are met:
o The value of the pwdAccountLockedTime attribute is 000001010000Z.
+
o The current time is less than the value of the
pwdAccountLockedTime attribute added to the value of the
pwdLockoutDuration.
if all of these conditions are met:
The pwdMustChange attribute is set to TRUE.
+
The pwdReset attribute is set to TRUE.
Otherwise a status of false is returned.
7.3 Password Expiration Check
A status of true is returned indicating that the password has expired
- if the value of the pwdExpireWarning attribute is 0, and the current
- time minus the value of pwdChangedTime is greater than the value of
- the pwdMaxAge.
+ if the current time minus the value of pwdChangedTime is greater than
+ the value of the pwdMaxAge.
Otherwise, a status of false is returned.
If the pwdGraceUseTime attribute is present, the number of values in
that attribute subtracted from the value of pwdGraceAuthNLimit is
returned. Otherwise zero is returned. A positive result specifies
- the number of remaining grace authentications.
-Sermersheim & Poitou Expires April 24, 2005 [Page 22]
+Sermersheim & Poitou Expires January 18, 2006 [Page 23]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
+ the number of remaining grace authentications.
+
7.5 Time Before Expiration Check
If the pwdExpireWarning attribute is not present a zero status is
returned if the following conditions are met:
The pwdLockout attribute is TRUE.
+
The number of values in the pwdFailureTime attribute that are
younger than pwdFailureCountInterval is greater or equal to the
pwdMaxFailure attribute.
password was last updated is returned if:
The value of pwdMinAge is non-zero and pwdChangedTime is present.
+
The value of pwdMinAge is greater than the current time minus the
value of pwdChangedTime.
-
-
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 23]
+Sermersheim & Poitou Expires January 18, 2006 [Page 24]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
8. Server Policy Enforcement Points
updates used while validating a password. Operations that validate
passwords include, but are not limited to, the Bind operation where
the simple choice specifies a password, and the compare operation
- where the attribute being compared holds a password.
+ where the attribute being compared holds a password. Note that while
+ the compare operation does not authenticate a user to the LDAP
+ server, it may be used by an external application for purposes of
+ authentication.
8.1.1 Fail if the account is locked
the error: accountLocked (1) in the passwordPolicyResponse in the
controls field of the message.
-8.1.2 AuthN Passed Procedures
+8.1.2 Validated Password Procedures
- If the authentication process indicates that the password validated,
+ If the validation operation indicates that the password validated,
these procedures are followed in order:
8.1.2.1 Policy state updates
If the decision in Section 7.2 returns true, the server sends to the
client a response with an appropriate successful resultCode (i.e.
- success (0), compareTrue (6), etc.), and includes the
- passwordPolicyResponse in the controls field of the bindResponse
- message with the warning: changeAfterReset specified.
-Sermersheim & Poitou Expires April 24, 2005 [Page 24]
+Sermersheim & Poitou Expires January 18, 2006 [Page 25]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
+ success (0), compareTrue (6), etc.), and includes the
+ passwordPolicyResponse in the controls field of the bindResponse
+ message with the warning: changeAfterReset specified.
+
For bind, the server MUST then disallow all operations issued by this
user except modify password, bind, unbind, abandon and StartTLS
extended operation.
If there are remaining grace authentications as per Section 7.4, the
server adds a new value with the current time in pwdGraceUseTime.
Then it sends to the client a response with an appropriate successful
- resultCode (i.e. success (0), compareTrue (6), etc.), and includes
+ resultCode (i.e. success (0), compareTrue (6), etc.), and includes
the passwordPolicyResponse in the controls field of the response
message with the warning: graceAuthNsRemaining choice set to the
number of grace authentications left.
If the result of Section 7.5 is a positive number, the server sends
to the client a response with an appropriate successful resultCode
- (i.e. success (0), compareTrue (6), etc.), and includes the
+ (i.e. success (0), compareTrue (6), etc.), and includes the
passwordPolicyResponse in the controls field of the bindResponse
message with the warning: timeBeforeExiration set to the value as
described above. Otherwise, the server sends a successful response,
and omits the passwordPolicyResponse.
-8.1.2.5 AuthN Failed Procedures
- If the authentication process indicates that the password failed
- validation due to invalid credentials, these procedures are followed:
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 25]
+Sermersheim & Poitou Expires January 18, 2006 [Page 26]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
+8.1.2.5 AuthN Failed Procedures
+ If the authentication process indicates that the password failed
+ validation due to invalid credentials, these procedures are followed:
8.1.2.5.1 Policy state update
When the LDAP modify operation is used to modify a password, this is
done by specifying both a delete action and an add or replace action,
- where the delete action is first, and specifies the existing
- password, and the add or replace action specifies the new password.
- Other password update operations SHOULD employ a similar mechanism.
- Otherwise this policy will fail.
+ where the delete action specifies the existing password, and the add
+ or replace action specifies the new password. Other password update
+ operations SHOULD employ a similar mechanism. Otherwise this policy
+ will fail.
- If the existing password is not specified, the server does not
- process the operation and sends the appropriate response message to
- the client with the resultCode: insufficientAccessRights (50), and
- includes the passwordPolicyResponse in the controls field of the
- response message with the error: mustSupplyOldPassword (4).
-Sermersheim & Poitou Expires April 24, 2005 [Page 26]
+Sermersheim & Poitou Expires January 18, 2006 [Page 27]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+ If the existing password is not specified, the server does not
+ process the operation and sends the appropriate response message to
+ the client with the resultCode: insufficientAccessRights (50), and
+ includes the passwordPolicyResponse in the controls field of the
+ response message with the error: mustSupplyOldPassword (4).
8.2.2 Change After Reset
If the value is 1, operation continues. If the value is 2, the
server sends a response message to the client with the resultCode:
constraintViolation (19), and includes the passwordPolicyResponse
- in the controls field of the response message with the error:
- insufficientPasswordQuality (5).
- If the server is able to check the password quality, and the check
- fails, the server sends a response message to the client with the
- resultCode: constraintViolation (19), and includes the
- passwordPolicyResponse in the controls field of the response
-Sermersheim & Poitou Expires April 24, 2005 [Page 27]
+Sermersheim & Poitou Expires January 18, 2006 [Page 28]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
+ in the controls field of the response message with the error:
+ insufficientPasswordQuality (5).
+ If the server is able to check the password quality, and the check
+ fails, the server sends a response message to the client with the
+ resultCode: constraintViolation (19), and includes the
+ passwordPolicyResponse in the controls field of the response
message with the error: insufficientPasswordQuality (5).
+
o checks the value of the pwdMinLength attribute. If the value is
non-zero, it ensures that the new password is of at least the
minimum length.
passwordPolicyResponse in the controls field of the response
message with the error: passwordTooShort (6).
+
8.2.6 Invalid Reuse
If pwdInHistory is present and its value is non-zero, the server
If the value of pwdInHistory is non-zero, the server adds the
previous password (if one existed) to the pwdHistory attribute. If
+
+
+
+Sermersheim & Poitou Expires January 18, 2006 [Page 29]
+\f
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
the number of attributes held in the pwdHistory attribute exceeds the
value of pwdInHistory, the server removes the oldest excess
passwords.
set to TRUE. Otherwise, the pwdReset is removed from the user's
entry if it exists.
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 28]
-\f
-Internet-Draft Password Policy for LDAP Directories October 2004
-
-
- The pwdFailureTime, pwdGraceUseTime and pwdExpirationWarned
- attributes is removed from the user's entry if they exist.
+ The pwdFailureTime and pwdGraceUseTime attributes is removed from the
+ user's entry if they exist.
8.3 Other Operations
-
-
-
-
-
-
-
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 29]
+Sermersheim & Poitou Expires January 18, 2006 [Page 30]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
9. Client Policy Enforcement Points
failure limit has been reached and the account is locked. The
user needs to retry later or contact the password administrator to
reset the password.
+
o bindResponse.resultCode = success (0),
passwordPolicyResponse.error = changeAfterReset (2): The user is
binding for the first time after the password administrator set
the password. In this scenario, the client SHOULD prompt the user
to change his password immediately.
+
o bindResponse.resultCode = success (0),
passwordPolicyResponse.warning = graceAuthNsRemaining: The
password has expired but there are remaining grace
authentications. The user needs to change it.
+
o bindResponse.resultCode = invalidCredentials (49),
passwordPolicyResponse.error = passwordExpired (0): The password
has expired and there are no more grace authentications. The user
contacts the password administrator in order to have its password
reset.
+
o bindResponse.resultCode = success (0),
passwordPolicyResponse.warning = timeBeforeExpiration: The user's
password will expire in n number of seconds.
-9.2 Modify Operations
-9.2.1 Modify Request
- If the application or client encrypts the password prior to sending
- it in a password modification operation (whether done through
-Sermersheim & Poitou Expires April 24, 2005 [Page 30]
+Sermersheim & Poitou Expires January 18, 2006 [Page 31]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
+9.2 Modify Operations
+
+9.2.1 Modify Request
+
+ If the application or client encrypts the password prior to sending
+ it in a password modification operation (whether done through
modifyRequest or another password modification mechanism), it SHOULD
check the values of the pwdMinLength, and pwdCheckQuality attributes
and SHOULD enforce these policies.
passwordPolicyResponse.error = mustSupplyOldPassword (4): The user
attempted to change her password without specifying the old
password but the password policy requires this.
+
o <pwdModResponse>.resultCode = insufficientAccessRights (50),
passwordPolicyResponse.error = changeAfterReset (2): The user must
change her password before submitting any other LDAP requests.
+
o <pwdModResponse>.resultCode = insufficientAccessRights (50),
passwordPolicyResponse.error = passwordModNotAllowed (3): The user
doesn't have sufficient rights to change his password.
+
o <pwdModResponse>.resultCode = constraintViolation (19),
passwordPolicyResponse.error = passwordTooYoung (7): It is too
soon after the last password modification to change the password.
+
o <pwdModResponse>.resultCode = constraintViolation (19),
passwordPolicyResponse.error = insufficientPasswordQuality (5):
The password failed quality checking.
+
o <pwdModResponse>.resultCode = constraintViolation (19),
passwordPolicyResponse.error = passwordTooShort (6): The length of
the password is too short.
+
o <pwdModResponse>.resultCode = constraintViolation (19),
passwordPolicyResponse.error = passwordInHistory (8): The password
has already been used; the user must choose a different one.
+
+
+Sermersheim & Poitou Expires January 18, 2006 [Page 32]
+\f
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
9.3 Add Operation
If a password is specified in an addRequest, the client checks the
passwordPolicyResponse.error = passwordModNotAllowed (3): The user
doesn't have sufficient rights to add this password.
-
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 31]
-\f
-Internet-Draft Password Policy for LDAP Directories October 2004
-
-
o addResponse.resultCode = constraintViolation (19),
passwordPolicyResponse.error = insufficientPasswordQuality (5):
The password failed quality checking.
+
o addResponse.resultCode = constraintViolation (19),
passwordPolicyResponse.error = passwordTooShort (6): The length of
the password is too short.
+
9.4 Compare Operation
When a compare operation is used to compare a password, the client
failure limit has been reached and the account is locked. The
user needs to retry later or contact the password administrator to
reset the password.
+
o compareResponse.resultCode = compareTrue (6),
passwordPolicyResponse.warning = graceAuthNsRemaining: The
password has expired but there are remaining grace
authentications. The user needs to change it.
+
o compareResponse.resultCode = compareFalse (5),
passwordPolicyResponse.error = passwordExpired (0): The password
has expired and there are no more grace authentications. The user
must contact the password administrator to reset the password.
+
o compareResponse.resultCode = compareTrue (6),
passwordPolicyResponse.warning = timeBeforeExpiration: The user's
password will expire in n number of seconds.
+
+
+
+Sermersheim & Poitou Expires January 18, 2006 [Page 33]
+\f
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
9.5 Other Operations
For operations other than bind, unbind, abandon or StartTLS, the
-Sermersheim & Poitou Expires April 24, 2005 [Page 32]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Sermersheim & Poitou Expires January 18, 2006 [Page 34]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
10. Administration of the Password Policy
-Sermersheim & Poitou Expires April 24, 2005 [Page 33]
+Sermersheim & Poitou Expires January 18, 2006 [Page 35]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
11. Password Policy and Replication
+ {TODO: This section needs to be changed to highlight the pitfals of
+ replication, sugest some implementation choices to overcome those
+ pitfals, but remove prescriptive language relating to the update of
+ state information}
+
The pwdPolicy object defines the password policy for a portion of the
DIT and MUST be replicated on all the replicas of this subtree, as
any subentry would be, in order to have a consistent policy among all
doesn't have to be replicated to a read-only replica, since the
password will never be directly modified on this server.
- The pwdAccountLockedTime, pwdExpirationWarned, pwdFailureTime and
- pwdGraceUseTime attributes MUST be replicated to writable replicas,
- making the password policy global for all servers. When the user
- entry is replicated to a read-only replica, these attributes SHOULD
- NOT be replicated. This means that the number of failures, of grace
+ The pwdAccountLockedTime, pwdFailureTime and pwdGraceUseTime
+ attributes MUST be replicated to writable replicas, making the
+ password policy global for all servers. When the user entry is
+ replicated to a read-only replica, these attributes SHOULD NOT be
+ replicated. This means that the number of failures, of grace
authentications and the locking will take place on each replicated
server. For example, the effective number of failed attempts on a
user password will be N x M (where N is the number of servers and M
-
-
-
-
-
-Sermersheim & Poitou Expires April 24, 2005 [Page 34]
+Sermersheim & Poitou Expires January 18, 2006 [Page 36]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
12. Security Considerations
-Sermersheim & Poitou Expires April 24, 2005 [Page 35]
+Sermersheim & Poitou Expires January 18, 2006 [Page 37]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
+13. IANA Considerations
+
+ <<<TBD>>>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-13. Acknowledgement
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Sermersheim & Poitou Expires January 18, 2006 [Page 38]
+\f
+Internet-Draft Password Policy for LDAP Directories July 2005
+
+
+14. Acknowledgement
This document is based in part on prior work done by Valerie Chu from
Netscape Communications Corp, published as
draft-vchu-ldap-pwd-policy-00.txt (December 1998). Prasanta Behera
participated in early revisions of this document.
-14 Normative References
+15. Normative References
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
- [RFC2195] Klensin, J., Catoe, R. and P. Krumviede, "IMAP/POP
- AUTHorize Extension for Simple Challenge/Response", RFC
- 2195, September 1997.
+ [RFC2195] Klensin, J., Catoe, R., and P. Krumviede, "IMAP/POP
+ AUTHorize Extension for Simple Challenge/Response",
+ RFC 2195, September 1997.
[RFC2222] Myers, J., "Simple Authentication and Security Layer
(SASL)", RFC 2222, October 1997.
- [RFC2251] Wahl, M., Howes, T. and S. Kille, "Lightweight Directory
+ [RFC2251] Wahl, M., Howes, T., and S. Kille, "Lightweight Directory
Access Protocol (v3)", RFC 2251, December 1997.
- [RFC2252] Wahl, M., Coulbeck, A., Howes, T. and S. Kille,
+ [RFC2252] Wahl, M., Coulbeck, A., Howes, T., and S. Kille,
"Lightweight Directory Access Protocol (v3): Attribute
Syntax Definitions", RFC 2252, December 1997.
- [RFC2829] Wahl, M., Alvestrand, H., Hodges, J. and R. Morgan,
+ [RFC2829] Wahl, M., Alvestrand, H., Hodges, J., and R. Morgan,
"Authentication Methods for LDAP", RFC 2829, May 2000.
[RFC2831] Leach, P. and C. Newman, "Using Digest Authentication as a
-Sermersheim & Poitou Expires April 24, 2005 [Page 36]
+Sermersheim & Poitou Expires January 18, 2006 [Page 39]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
Encoding Rules (BER), Canonical Encoding Rules (CER) and
USA
Phone: +1 801 861-3088
- EMail: jimse@novell.com
+ Email: jimse@novell.com
Ludovic Poitou
France
Phone: +33 476 188 212
- EMail: ludovic.poitou@sun.com
+ Email: ludovic.poitou@sun.com
-Sermersheim & Poitou Expires April 24, 2005 [Page 37]
+Sermersheim & Poitou Expires January 18, 2006 [Page 40]
\f
-Internet-Draft Password Policy for LDAP Directories October 2004
+Internet-Draft Password Policy for LDAP Directories July 2005
Intellectual Property Statement
Copyright Statement
- Copyright (C) The Internet Society (2004). This document is subject
+ Copyright (C) The Internet Society (2005). This document is subject
to the rights, licenses and restrictions contained in BCP 78, and
except as set forth therein, the authors retain all their rights.
-Sermersheim & Poitou Expires April 24, 2005 [Page 38]
+Sermersheim & Poitou Expires January 18, 2006 [Page 41]
\f
+
--- /dev/null
+
+
+
+
+
+INTERNET-DRAFT Kurt D. Zeilenga
+Intended Category: Standard Track OpenLDAP Foundation
+Expires in six months 10 February 2005
+
+
+
+ The LDAP No-Op Control
+ <draft-zeilenga-ldap-noop-06.txt>
+
+
+Status of this Memo
+
+ This document is intended to be, after appropriate review and
+ revision, submitted to the IESG for consideration as a Standard Track
+ document. Distribution of this memo is unlimited. Technical
+ discussion of this document will take place on the IETF LDAP
+ Extensions mailing list <ldapext@ietf.org>. Please send editorial
+ comments directly to the author <Kurt@OpenLDAP.org>.
+
+ By submitting this Internet-Draft, I accept the provisions of Section
+ 4 of RFC 3667. By submitting this Internet-Draft, I certify that any
+ applicable patent or other IPR claims of which I am aware have been
+ disclosed, or will be disclosed, and any of which I become aware will
+ be disclosed, in accordance with RFC 3668.
+
+ Internet-Drafts are working documents of the Internet Engineering Task
+ Force (IETF), its areas, and its working groups. Note that other
+ groups may also distribute working documents as Internet-Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference material
+ or to cite them other than as "work in progress."
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/1id-abstracts.html
+
+ The list of Internet-Draft Shadow Directories can be accessed at
+ http://www.ietf.org/shadow.html
+
+
+ Copyright (C) The Internet Society (2005). All Rights Reserved.
+
+ Please see the Full Copyright section near the end of this document
+ for more information.
+
+
+
+
+
+
+Zeilenga LDAP No-Op Control [Page 1]
+\f
+INTERNET-DRAFT draft-zeilenga-ldap-noop-06 10 February 2005
+
+
+Abstract
+
+ This document defines the Lightweight Directory Access Protocol (LDAP)
+ No-Op control which can be used to disable the normal effect of an
+ operation. The control can be used to discover how a server might
+ react to a particular update request without updating the directory.
+
+
+1. Overview
+
+ It is often desirable to be able to determine if a directory operation
+ [Protocol] would successful complete or not without having the normal
+ effect of the operation take place. For example, an administrative
+ client might want to verify that new user could update their entry
+ (and not other entries) without the directory actually being updated.
+ The mechanism could be used to build more sophisticated security
+ auditing tools.
+
+ This document defines the Lightweight Directory Access Protocol (LDAP)
+ [Roadmap] No-Op control extension. The presence of the No-Op control
+ in an operation request message disables its normal effect upon the
+ directory which operation would otherwise have. Instead of updating
+ the directory and return the normal indication of success, the server
+ does not update the directory and indicates so by returning the
+ noOperation resultCode (introduced below).
+
+ For example, when the No-Op control is present in a LDAP modify
+ operation [Protocol], the server is do all processing necessary to
+ perform the operation without actually updating the directory. If it
+ detects an error during this processing, it returns a non-success
+ (other than noOperation) resultCode as it normally would. Otherwise,
+ it returns the noOperation. In either case, the directory is left
+ unchanged.
+
+ This No-Op control is not intended to be to an "effective access"
+ mechanism [RFC2820, U12].
+
+
+1.1. Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in BCP 14 [RFC2119].
+
+ DN stands for Distinguished Name.
+ DSA stands for Directory System Agent.
+ DSE stands for DSA-specific entry.
+
+
+
+
+Zeilenga LDAP No-Op Control [Page 2]
+\f
+INTERNET-DRAFT draft-zeilenga-ldap-noop-06 10 February 2005
+
+
+2. No-Op Control
+
+ The No-Op control is an LDAP Control [Protocol] whose controlType is
+ IANA-ASSIGNED-OID and controlValue is absent. Clients MUST provide a
+ criticality value of TRUE to prevent unintended modification of the
+ directory.
+
+ The control is appropriate for request messages of LDAP Add, Delete,
+ Modify and ModifyDN operations [Protocol]. The control is also
+ appropriate for requests of extended operations which update the
+ directory (or other data stores), such as Password Modify Extended
+ Operation [RFC3062]. There is no corresponding response control.
+
+ When the control is attached to an LDAP request, the server does all
+ normal processing possible for the operation without modification of
+ the directory. That is, when the control is attached to an LDAP
+ request, the directory SHALL NOT be updated and the response SHALL NOT
+ have a resultCode of success (0).
+
+ A result code other than noOperation (IANA-ASSIGNED-CODE) means that
+ the server is unable or unwilling to complete the processing for the
+ reason indicated by the result code. A result code of noOperation
+ (IANA-ASSIGNED-CODE) indicates that the server discovered no reason
+ why the operation would fail if submitted without the No-Op control.
+
+ Servers SHOULD indicate their support for this control by providing
+ IANA-ASSIGNED-OID as a value of the 'supportedControl' attribute type
+ [Models] in their root DSE entry. A server MAY choose to advertise
+ this extension only when the client is authorized to use this
+ operation.
+
+
+3. Security Considerations
+
+ The No-Op control mechanism allows directory administrators and users
+ to verify that access control and other administrative policy controls
+ are properly configured. The mechanism may also lead to the
+ development (and deployment) of more effective security auditing
+ tools.
+
+ Implementors of this LDAP extension should be familiar with security
+ considerations applicable to the LDAP operations [Protocol] extended
+ by this control, as well as general LDAP security considerations
+ [Roadmap].
+
+
+4. IANA Considerations
+
+
+
+
+Zeilenga LDAP No-Op Control [Page 3]
+\f
+INTERNET-DRAFT draft-zeilenga-ldap-noop-06 10 February 2005
+
+
+4.1. Object Identifier
+
+ It is requested that IANA assign an LDAP Object Identifier [BCP64bis]
+ to identify the LDAP No-Op Control defined in this document.
+
+ Subject: Request for LDAP Object Identifier Registration
+ Person & email address to contact for further information:
+ Kurt Zeilenga <kurt@OpenLDAP.org>
+ Specification: RFC XXXX
+ Author/Change Controller: IESG
+ Comments:
+ Identifies the LDAP No-Op Control
+
+
+4.2 LDAP Protocol Mechanism
+
+ Registration of this protocol mechanism is requested [RFC3383].
+
+ Subject: Request for LDAP Protocol Mechanism Registration
+ Object Identifier: IANA-ASSIGNED-OID
+ Description: No-Op Control
+ Person & email address to contact for further information:
+ Kurt Zeilenga <kurt@openldap.org>
+ Usage: Control
+ Specification: RFC XXXX
+ Author/Change Controller: IESG
+ Comments: none
+
+
+4.3 LDAP Result Code
+
+ Assignment of an LDAP Result Code called 'noOperation' is requested.
+
+ Subject: LDAP Result Code Registration
+ Person & email address to contact for further information:
+ Kurt Zeilenga <kurt@OpenLDAP.org>
+ Result Code Name: noOperation
+ Specification: RFC XXXX
+ Author/Change Controller: IESG
+ Comments: none
+
+
+5. Author's Address
+
+ Kurt D. Zeilenga
+ OpenLDAP Foundation
+
+ Email: Kurt@OpenLDAP.org
+
+
+
+Zeilenga LDAP No-Op Control [Page 4]
+\f
+INTERNET-DRAFT draft-zeilenga-ldap-noop-06 10 February 2005
+
+
+6. References
+
+ [[Note to the RFC Editor: please replace the citation tags used in
+ referencing Internet-Drafts with tags of the form RFCnnnn where
+ possible.]]
+
+
+6.1. Normative References
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14 (also RFC 2119), March 1997.
+
+ [Protocol] Sermersheim, J. (editor), "LDAP: The Protocol",
+ draft-ietf-ldapbis-protocol-xx.txt, a work in progress.
+
+ [Roadmap] Zeilenga, K. (editor), "LDAP: Technical Specification
+ Road Map", draft-ietf-ldapbis-roadmap-xx.txt, a work in
+ progress.
+
+ [Models] Zeilenga, K. (editor), "LDAP: Directory Information
+ Models", draft-ietf-ldapbis-models-xx.txt, a work in
+ progress.
+
+
+6.2. Informative References
+
+ [X.500] International Telecommunication Union -
+ Telecommunication Standardization Sector, "The Directory
+ -- Overview of concepts, models and services,"
+ X.500(1993) (also ISO/IEC 9594-1:1994).
+
+ [RFC2820] Stokes, E., et. al., "Access Control Requirements for
+ LDAP", RFC 2820, May 2000.
+
+ [RFC3062] Zeilenga, K., "LDAP Password Modify Extended Operation",
+ RFC 3062, February 2000.
+
+ [BCP64bis] Zeilenga, K., "IANA Considerations for LDAP",
+ draft-ietf-ldapbis-bcp64-xx.txt, a work in progress.
+
+
+
+Intellectual Property Rights
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+
+
+
+Zeilenga LDAP No-Op Control [Page 5]
+\f
+INTERNET-DRAFT draft-zeilenga-ldap-noop-06 10 February 2005
+
+
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the procedures with respect to rights in RFC documents can be found
+ in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this specification
+ can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at
+ ietf-ipr@ietf.org.
+
+
+
+Full Copyright
+
+ Copyright (C) The Internet Society (2005). This document is subject
+ to the rights, licenses and restrictions contained in BCP 78, and
+ except as set forth therein, the authors retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Zeilenga LDAP No-Op Control [Page 6]
+\f
+
+
!block nofill
-Portions [[copyright]] 1999-2003 Howard Y.H. Chu.
-Portions [[copyright]] 1999-2003 Symas Corporation.
+Portions [[copyright]] 1999-2005 Howard Y.H. Chu.
+Portions [[copyright]] 1999-2005 Symas Corporation.
Portions [[copyright]] 1998-2003 Hallvard B. Furuseth.
{{All rights reserved.}}
!endblock
sasl_ssf=<n>
aci[=<attrname>]
- dynacl/name[.<dynstyle>][=<pattern>]
+ dynacl/name[/<options>][.<dynstyle>][=<pattern>]
.fi
.LP
with
ACIs are experimental; they must be enabled at compile time.
.LP
The statement
-.B dynacl/<name>[.<dynstyle>][=<pattern>]
+.B dynacl/<name>[/<options>][.<dynstyle>][=<pattern>]
means that access checking is delegated to the admin-defined method
indicated by
.BR <name> ,
.B moduleload
statement.
The fields
+.BR <options> ,
.B <dynstyle>
and
.B <pattern>
.SH SEE ALSO
.BR slapd.conf (5),
.BR slapd (8).
-.SH AUTHOR
-Originally implemented by Pierangelo Masarati.
+.SH ACKNOWLEDGEMENTS
+.P
+This module was written in 2004 by Pierangelo Masarati for SysNet s.n.c.
EQUALITY distinguishedNameMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
SINGLE-VALUE
+ NO-USER-MODIFICATION
USAGE directoryOperation)
.RE
EQUALITY generalizedTimeMatch
ORDERING generalizedTimeOrderingMatch
SINGLE-VALUE
+ NO-USER-MODIFICATION
USAGE directoryOperation)
.RE
EQUALITY generalizedTimeMatch
ORDERING generalizedTimeOrderingMatch
SINGLE-VALUE
+ NO-USER-MODIFICATION
USAGE directoryOperation)
.RE
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
EQUALITY generalizedTimeMatch
ORDERING generalizedTimeOrderingMatch
+ NO-USER-MODIFICATION
USAGE directoryOperation )
.RE
DESC 'The history of user passwords'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
EQUALITY octetStringMatch
+ NO-USER-MODIFICATION
USAGE directoryOperation)
.RE
DESC 'The timestamps of the grace login once the password has expired'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
EQUALITY generalizedTimeMatch
+ NO-USER-MODIFICATION
USAGE directoryOperation)
.RE
.LP
IETF LDAP password policy proposal by P. Behera, L. Poitou and J.
Sermersheim: documented in IETF document
-"draft-behera-ldap-password-policy-08.txt".
+"draft-behera-ldap-password-policy-09.txt".
.SH BUGS
The LDAP Password Policy specification is not yet an approved standard,
Poitou and J. Sermersheim.
The proposal is fully documented in
the
-IETF document named draft-behera-ldap-password-policy-08.txt,
-written in October of 2004.
+IETF document named draft-behera-ldap-password-policy-09.txt,
+written in July of 2005.
.P
.B OpenLDAP
is developed and maintained by The OpenLDAP Project (http://www.openldap.org/).
in \fBretcode.conf\fP, which can be included after instantiating
the overlay.
.LP
-In the second case, objects of the \fBerrObject\fP class, when returned
-as intermediate responses of a search request, are changed into
-the response dictated by their content.
+In the second case, objects of classes inherited from
+the \fBerrAbsObject\fP, like \fBerrObject\fP or \fBerrAuxObject\fP,
+when returned as intermediate responses of a search request, are changed
+into the response dictated by their content.
.LP
A third mode causes objects to be looked up from the underlying database
-to discover if their class is \fBerrObject\fP; in that case, their content
-is used to compute the corresponding response.
+to discover if their class inherits from \fBerrABsObject\fP;
+in that case, their content is used to compute the corresponding response.
.LP
The behavior is disabled by using the \fBmanageDSAit\fP control (RFC 3296);
in that case, the resulting object, either present in the directory
.RE
.TP
.B retcode\-indir
-Enables exploitation of in-directory stored errObjects. May result
-in lots of unnecessary overhead.
+Enables exploitation of in-directory stored errAbsObject.
+May result in a lot of unnecessary overhead.
.SH SCHEMA
The following schema items are created and used by the overlay:
SINGLE-VALUE )
.RE
.LP
-The objectclass:
+The abstract class that triggers the overlay:
.RS 4
-( 1.3.6.1.4.1.4203.666.11.4.3.1
- NAME ( 'errObject' )
- SUP top STRUCTURAL
+( 1.3.6.1.4.1.4203.666.11.4.3.0
+ NAME ( 'errAbsObject' )
+ SUP top ABSTRACT
MUST ( errCode )
MAY ( cn $ description $ errOp $ errText $ errSleepTime ) )
.RE
+.LP
+The standalone structural objectclass for specifically created data:
+.RS 4
+( 1.3.6.1.4.1.4203.666.11.4.3.1
+ NAME ( 'errObject' )
+ SUP errAbsObject STRUCTURAL )
+.RE
+.LP
+The auxiliary objectclass to alter the behavior of existing objects:
+.RS 4
+( 1.3.6.1.4.1.4203.666.11.4.3.2
+ NAME ( 'errAuxObject' )
+ SUP errAbsObject AUXILIARY )
+.RE
.SH EXAMPLE
.LP
.SH SEE ALSO
.BR slapd.conf (5),
.BR slapd (8),
-.SH AUTHOR
-Pierangelo Masarati
+.SH ACKNOWLEDGEMENTS
+.P
+This module was written in 2005 by Pierangelo Masarati for SysNet s.n.c.
.TP
.B syncprov-checkpoint <ops> <minutes>
After a write operation has succeeded, write the contextCSN to the underlying
-database if <ops> write operations or more than <minutes> time have passed
+database if
+.B <ops>
+write operations or more than
+.B <minutes>
+time have passed
since the last checkpoint. Checkpointing is disabled by default.
.TP
-.B syncprov-sessionlog <sid> <size>
-Specify a session log for recording information about entries that have been
-scoped out of the content identified by
-.BR <sid> .
-The number of entries in the log is limited by
-.BR <size> .
-Both
-.B <sid>
-and
-.B <size>
-must be non-negative integers, and
-.B <sid>
-can have no more than three decimal digits.
+.B syncprov-sessionlog <ops>
+Specify a session log for recording information about write operations made
+on the database. The
+.B <ops>
+specifies the number of operations that are recorded in the log. All write
+operations (except Adds) are recorded in the log.
When using the session log, it is helpful to set an eq index on the
entryUUID attribute in the underlying database.
.SH FILES
attributes.
.TP
.B unique_attributes <attribute...>
-Specify one or more attributes which for which uniqueness will be enforced.
+Specify one or more attributes for which uniqueness will be enforced.
If not specified, all attributes which are not operational (eg, system
attributes such as
.B entryUUID )
list, and included in the
.B unique_attributes
list, in that order. This makes it possible to create interesting and
-unusable configurations.
+unusable configurations. Usually only one of
+.B unique_ignore
+or
+.B unique_attributes
+should be configured; use
+.B unique_ignore
+if the majority of attributes should be unique, and use
+.B unique_attributes
+if only a small set of attributes should be unique.
.LP
Typical attributes for the
.B unique_ignore
--- /dev/null
+.TH SLAPO-VALSORT 5 "RELEASEDATE" "OpenLDAP LDVERSION"
+.\" Copyright 2005 The OpenLDAP Foundation All Rights Reserved.
+.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
+.\" $OpenLDAP$
+.SH NAME
+slapo-valsort \- Value Sorting overlay
+.SH SYNOPSIS
+ETCDIR/slapd.conf
+.SH DESCRIPTION
+The Value Sorting overlay can be used with a backend database to sort the
+values of specific multi-valued attributes within a subtree. The sorting
+occurs whenever the attributes are returned in a search response.
+.LP
+Sorting can be specified in ascending or descending order, using either
+numeric or alphanumeric sort methods. Additionally, a "weighted" sort can
+be specified, which uses a numeric weight prepended to the attribute values.
+The weighted sort is always performed in ascending order, but may be combined
+with the other methods for values that all have equal weights. The weight
+is specified by prepending an integer weight
+.B {<weight>}
+in front of each value of the attribute for which weighted sorting is
+desired. This weighting factor is stripped off and never returned in
+search results.
+
+.SH CONFIGURATION
+These
+.B slapd.conf
+options apply to the Value Sorting overlay.
+They should appear after the
+.B overlay
+directive and before any subsequent
+.B database
+directive.
+.TP
+.B valsort-attr <attribute> <baseDN> (<sort-method> | weighted [<sort-method>])
+Configure a sorting method for the specified
+.B attribute
+in the subtree rooted at
+.BR baseDN .
+The
+.B sort-method
+may be one of
+.BR alpha-ascend ,
+.BR alpha-descend ,
+.BR numeric-ascend ,
+or
+.BR numeric-descend .
+If the special
+.B weighted
+method is specified, a secondary sort-method may also be specified. It is an
+error to specify an alphanumeric sort-method for an attribute with Integer
+or NumericString syntax, and it is an error to specify a numeric sort for
+an attribute with a syntax other than Integer or NumericString.
+.SH EXAMPLES
+.LP
+.nf
+ database bdb
+ suffix dc=example,dc=com
+ ...
+ overlay valsort
+ valsort-attr member ou=groups,dc=example,dc=com alpha-ascend
+.fi
+
+.SH FILES
+.TP
+ETCDIR/slapd.conf
+default slapd configuration file
+.SH SEE ALSO
+.BR slapd.conf (5).
+.SH ACKNOWLEDGEMENTS
+.P
+This module was written in 2005 by Howard Chu of Symas Corporation. The
+work was sponsored by Stanford University.
option.
.TP
.BI \-a " filter"
-Only dump entries matching the asserted filter.
+Only dump entries matching the asserted filter.
+For example
+
+slapcat -a \\
+ "(!(entryDN:dnSubtreeMatch:=ou=People,dc=example,dc=com))"
+
+will dump all but the "ou=People,dc=example,dc=com" subtree
+of the "dc=example,dc=com" database.
.TP
.BI \-s " subtree-dn"
Only dump entries in the subtree specified by this DN.
#define LDAP_CONTROL_SUBENTRIES "1.3.6.1.4.1.4203.1.10.1" /* RFC 3672 */
#define LDAP_CONTROL_PAGEDRESULTS "1.2.840.113556.1.4.319" /* RFC 2696 */
#define LDAP_CONTROL_VALUESRETURNFILTER "1.2.826.0.1.334810.2.3" /* RFC 3876 */
+#define LDAP_CONTROL_ASSERT "1.3.6.1.1.12"
+#define LDAP_CONTROL_PRE_READ "1.3.6.1.1.13.1"
+#define LDAP_CONTROL_POST_READ "1.3.6.1.1.13.2"
/* standard track - not implemented in slapd(8) */
#define LDAP_CONTROL_SORTREQUEST "1.2.840.113556.1.4.473" /* RFC 2891 */
#define LDAP_CONTROL_PROXY_AUTHZ "2.16.840.1.113730.3.4.18"
/* various works in progress */
-#define LDAP_CONTROL_ASSERT "1.3.6.1.4.1.4203.666.5.9"
#define LDAP_CONTROL_NOOP "1.3.6.1.4.1.4203.666.5.2"
-#define LDAP_CONTROL_PRE_READ "1.3.6.1.4.1.4203.666.5.10.1"
-#define LDAP_CONTROL_POST_READ "1.3.6.1.4.1.4203.666.5.10.2"
#define LDAP_CONTROL_NO_SUBORDINATES "1.3.6.1.4.1.4203.666.5.11"
#define LDAP_CONTROL_MANAGEDIT "1.3.6.1.4.1.4203.666.5.12"
#define LDAP_CONTROL_SLURP "1.3.6.1.4.1.4203.666.5.13"
+#define LDAP_CONTROL_VALSORT "1.3.6.1.4.1.4203.666.5.14"
/* LDAP Duplicated Entry Control Extension *//* not implemented in slapd(8) */
#define LDAP_CONTROL_DUPENT_REQUEST "2.16.840.1.113719.1.27.101.1"
#define LDAP_CONTROL_VLVRESPONSE "2.16.840.1.113730.3.4.10"
/* Password policy Controls *//* work in progress */
-/* ITS#3458: released, but not to latest draft; disabled by default */
+/* ITS#3458: released; disabled by default */
#define LDAP_CONTROL_PASSWORDPOLICYREQUEST "1.3.6.1.4.1.42.2.27.8.5.1"
#define LDAP_CONTROL_PASSWORDPOLICYRESPONSE "1.3.6.1.4.1.42.2.27.8.5.1"
#define LDAP_FEATURE_ABSOLUTE_FILTERS "1.3.6.1.4.1.4203.1.5.3" /* (&) (|) */
#define LDAP_FEATURE_LANGUAGE_TAG_OPTIONS "1.3.6.1.4.1.4203.1.5.4"
#define LDAP_FEATURE_LANGUAGE_RANGE_OPTIONS "1.3.6.1.4.1.4203.1.5.5"
+#define LDAP_FEATURE_MODIFY_INCREMENT "1.3.6.1.1.14"
#ifdef LDAP_DEVEL
/* LDAP Experimental (works in progress) Features */
-#define LDAP_FEATURE_MODIFY_INCREMENT "1.3.6.1.4.1.4203.666.8.2"
#define LDAP_FEATURE_SUBORDINATE_SCOPE \
"1.3.6.1.4.1.4203.666.8.1" /* "children" */
#define LDAP_FEATURE_CHILDREN_SCOPE LDAP_FEATURE_SUBORDINATE_SCOPE
LDAP_F( void *)
ldap_pvt_thread_pool_context LDAP_P(( void ));
+LDAP_F( void )
+ldap_pvt_thread_pool_context_reset LDAP_P(( void *key ));
+
LDAP_END_DECL
#endif /* _LDAP_THREAD_H */
/* define for Attribute Uniqueness overlay */
#undef SLAPD_OVER_UNIQUE
+/* define for Value Sorting overlay */
+#undef SLAPD_OVER_VALSORT
+
/* define to support PASSWD backend */
#undef SLAPD_PASSWD
#define SLAPI_X_OPERATION_DELETE_GLUE_PARENT 1305
#define SLAPI_X_MANAGEDIT 1306
#define SLAPI_X_OPERATION_NO_SCHEMA_CHECK 1307
+#define SLAPI_X_ADD_STRUCTURAL_CLASS 1308
/* Authentication types */
#define SLAPD_AUTH_NONE "none"
sprops[j].key.bv_len )) continue;
if ( sprops[j].ival ) {
int v;
- if ( props[i][sprops[j].key.bv_len] != '=' ) continue;
- if ( !isdigit( props[i][sprops[j].key.bv_len+1] )) continue;
- v = atoi( props[i]+sprops[j].key.bv_len+1 );
+ char *next = NULL;
+ if ( !isdigit( props[i][sprops[j].key.bv_len] )) continue;
+ v = strtoul( &props[i][sprops[j].key.bv_len], &next, 10 );
+ if ( next == NULL || next[ 0 ] != '\0' ) continue;
switch( sprops[j].ival ) {
case GOT_MINSSF:
min_ssf = v; got_min_ssf++; break;
case LDAP_DN_FORMAT_LDAPV3:
case LDAP_DN_FORMAT_LDAPV2:
n = ldap_dn2domain( strin, &tmp );
- if( n ) {
+ if ( n ) {
fprintf( stdout, "\nldap_dn2domain(\"%s\") FAILED\n", strin );
} else {
fprintf( stdout, "\nldap_dn2domain(\"%s\")\n"
- "\t= \"%s\"\n", strin, tmp );
+ "\t= \"%s\"\n", strin, tmp ? tmp : "" );
}
ldap_memfree( tmp );
tmp = ldap_dn2ufn( strin );
fprintf( stdout, "\nldap_dn2ufn(\"%s\")\n"
- "\t= \"%s\"\n", strin, tmp );
+ "\t= \"%s\"\n", strin, tmp ? tmp : "" );
ldap_memfree( tmp );
tmp = ldap_dn2dcedn( strin );
fprintf( stdout, "\nldap_dn2dcedn(\"%s\")\n"
- "\t= \"%s\"\n", strin, tmp );
+ "\t= \"%s\"\n", strin, tmp ? tmp : "" );
tmp2 = ldap_dcedn2dn( tmp );
fprintf( stdout, "\nldap_dcedn2dn(\"%s\")\n"
- "\t= \"%s\"\n", tmp, tmp2 );
+ "\t= \"%s\"\n",
+ tmp ? tmp : "", tmp2 ? tmp2 : "" );
ldap_memfree( tmp );
ldap_memfree( tmp2 );
tmp = ldap_dn2ad_canonical( strin );
fprintf( stdout, "\nldap_dn2ad_canonical(\"%s\")\n"
- "\t= \"%s\"\n", strin, tmp );
+ "\t= \"%s\"\n", strin, tmp ? tmp : "" );
ldap_memfree( tmp );
fprintf( stdout, "\nldap_explode_dn(\"%s\"):\n", str );
* v3ref = flag for V3 referral / search reference
* 0 = not a ref, 1 = sucessfully chased ref, -1 = pass ref to application
*/
- int v3ref;
+ enum {
+ V3REF_NOREF = 0,
+ V3REF_SUCCESS = 1,
+ V3REF_TOAPP = -1
+ } v3ref;
assert( ld != NULL );
assert( lcp != NULL );
* This code figures out if we are going to chase a
* referral / search reference, or pass it back to the application
*/
- v3ref = 0; /* Assume not a V3 search reference or referral */
+ v3ref = V3REF_NOREF; /* Assume not a V3 search reference/referral */
if( (tag != LDAP_RES_SEARCH_ENTRY) && (ld->ld_version > LDAP_VERSION2) ) {
BerElement tmpber = *ber; /* struct copy */
char **refs = NULL;
- if( tag == LDAP_RES_SEARCH_REFERENCE) {
+ if( tag == LDAP_RES_SEARCH_REFERENCE ) {
/* This is a V3 search reference */
- /* Assume we do not chase the reference, but pass it to application */
- v3ref = -1;
+ /* Assume we do not chase the reference,
+ * but pass it to application */
+ v3ref = V3REF_TOAPP;
if( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ||
(lr->lr_parent != NULL) )
{
if ( ber_scanf( &tmpber, "{v}", &refs ) == LBER_ERROR ) {
rc = LDAP_DECODING_ERROR;
} else {
- /* Note: refs arrary is freed by ldap_chase_v3referrals */
+ /* Note: refs array is freed by ldap_chase_v3referrals */
refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
1, &lr->lr_res_error, &hadref );
- if ( refer_cnt > 0 ) { /* sucessfully chased reference */
+ if ( refer_cnt > 0 ) {
+ /* sucessfully chased reference */
/* If haven't got end search, set chasing referrals */
if( lr->lr_status != LDAP_REQST_COMPLETED) {
lr->lr_status = LDAP_REQST_CHASINGREFS;
Debug( LDAP_DEBUG_TRACE,
- "read1msg: search ref chased, mark request chasing refs, id = %d\n",
- lr->lr_msgid, 0, 0);
+ "read1msg: search ref chased, "
+ "mark request chasing refs, "
+ "id = %d\n",
+ lr->lr_msgid, 0, 0);
}
- v3ref = 1; /* We sucessfully chased the reference */
+
+ /* We sucessfully chased the reference */
+ v3ref = V3REF_SUCCESS;
}
}
}
/* Check if V3 referral */
if ( ber_peek_tag( &tmpber, &len ) == LDAP_TAG_REFERRAL ) {
/* We have a V3 referral, assume we cannot chase it */
- v3ref = -1;
+ v3ref = V3REF_TOAPP;
if( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS)
|| (lr->lr_parent != NULL) )
{
- v3ref = -1; /* Assume referral not chased and return it to app */
+ /* Assume referral not chased and return it to app */
+ v3ref = V3REF_TOAPP;
+
/* Get the referral list */
if( ber_scanf( &tmpber, "{v}", &refs) == LBER_ERROR) {
rc = LDAP_DECODING_ERROR;
"read1msg: referral chased, mark request completed, id = %d\n",
lr->lr_msgid, 0, 0);
if( refer_cnt > 0) {
- v3ref = 1; /* Referral successfully chased */
+ /* Referral successfully chased */
+ v3ref = V3REF_SUCCESS;
}
}
}
* go through the following code. This code also chases V2 referrals
* and checks if all referrals have been chased.
*/
- if ( (tag != LDAP_RES_SEARCH_ENTRY) && (v3ref > -1) &&
+ if ( (tag != LDAP_RES_SEARCH_ENTRY) && (v3ref != V3REF_TOAPP) &&
(tag != LDAP_RES_INTERMEDIATE ))
{
/* For a v3 search referral/reference, only come here if already chased it */
char *lr_res_error = NULL;
tmpber = *ber; /* struct copy */
- if ( v3ref == 1 ) {
+ if ( v3ref == V3REF_SUCCESS ) {
/* V3 search reference or V3 referral
* sucessfully chased. If this message
* is a search result, then it has no more
} else {
lr->lr_res_error = lr_res_error;
}
+ lr_res_error = NULL;
}
- if ( lderr != LDAP_SUCCESS ) {
+ switch ( lderr ) {
+ case LDAP_SUCCESS:
+ case LDAP_COMPARE_TRUE:
+ case LDAP_COMPARE_FALSE:
+ break;
+
+ default:
+ if ( lr->lr_res_error == NULL
+ || lr->lr_res_error[ 0 ] == '\0' )
+ {
+ break;
+ }
+
/* referrals are in error string */
refer_cnt = ldap_chase_referrals( ld, lr,
&lr->lr_res_error, -1, &hadref );
lr->lr_status = LDAP_REQST_COMPLETED;
Debug( LDAP_DEBUG_TRACE,
- "read1msg: V2 referral chased, mark request completed, id = %d\n", lr->lr_msgid, 0, 0);
+ "read1msg: V2 referral chased, "
+ "mark request completed, id = %d\n",
+ lr->lr_msgid, 0, 0 );
+ break;
}
/* save errno, message, and matched string */
* interpretation of the specs).
*/
-#define TK_NOENDQUOTE -2
-#define TK_OUTOFMEM -1
-#define TK_EOS 0
-#define TK_UNEXPCHAR 1
-#define TK_BAREWORD 2
-#define TK_QDSTRING 3
-#define TK_LEFTPAREN 4
-#define TK_RIGHTPAREN 5
-#define TK_DOLLAR 6
-#define TK_QDESCR TK_QDSTRING
-
-static int
+typedef enum tk_t {
+ TK_NOENDQUOTE = -2,
+ TK_OUTOFMEM = -1,
+ TK_EOS = 0,
+ TK_UNEXPCHAR = 1,
+ TK_BAREWORD = 2,
+ TK_QDSTRING = 3,
+ TK_LEFTPAREN = 4,
+ TK_RIGHTPAREN = 5,
+ TK_DOLLAR = 6,
+ TK_QDESCR = TK_QDSTRING
+} tk_t;
+
+static tk_t
get_token( const char ** sp, char ** token_val )
{
- int kind;
+ tk_t kind;
const char * p;
const char * q;
char * res;
{
char ** res;
char ** res1;
- int kind;
+ tk_t kind;
char * sval;
int size;
int pos;
parse_woid(const char **sp, int *code)
{
char * sval;
- int kind;
+ tk_t kind;
parse_whsp(sp);
kind = get_token(sp, &sval);
/* Parse a noidlen */
static char *
-parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
+parse_noidlen(const char **sp, int *code, int *len, int flags)
{
char * sval;
+ const char *savepos;
int quoted = 0;
+ int allow_quoted = ( flags & LDAP_SCHEMA_ALLOW_QUOTED );
+ int allow_oidmacro = ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO );
*len = 0;
/* Netscape puts the SYNTAX value in quotes (incorrectly) */
quoted = 1;
(*sp)++;
}
+ savepos = *sp;
sval = ldap_int_parse_numericoid(sp, code, 0);
if ( !sval ) {
- return NULL;
+ if ( allow_oidmacro
+ && *sp == savepos
+ && *code == LDAP_SCHERR_NODIGIT )
+ {
+ if ( get_token(sp, &sval) != TK_BAREWORD ) {
+ if ( sval != NULL ) {
+ LDAP_FREE(sval);
+ }
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
}
if ( **sp == '{' /*}*/ ) {
(*sp)++;
{
char ** res;
char ** res1;
- int kind;
+ tk_t kind;
char * sval;
int size;
int pos;
LDAP_CONST char ** errp,
LDAP_CONST unsigned flags )
{
- int kind;
+ tk_t kind;
const char * ss = s;
char * sval;
int seen_name = 0;
LDAP_CONST char ** errp,
LDAP_CONST unsigned flags )
{
- int kind;
+ tk_t kind;
const char * ss = s;
char * sval;
int seen_name = 0;
LDAP_CONST char ** errp,
LDAP_CONST unsigned flags )
{
- int kind;
+ tk_t kind;
const char * ss = s;
char * sval;
int seen_name = 0;
LDAP_CONST char ** errp,
LDAP_CONST unsigned flags )
{
- int kind;
+ tk_t kind;
const char * ss = s;
char * sval;
int seen_name = 0;
LDAP_CONST char ** errp,
LDAP_CONST unsigned flags )
{
- int kind;
+ tk_t kind;
const char * ss = s;
char * sval;
int seen_name = 0;
}
}
LDAP_FREE(sval);
+ *code = 0;
} else {
*errp = ss;
ldap_objectclass_free(oc);
ldap_objectclass_free(oc);
return NULL;
}
+ *code = 0;
} else if ( !strcasecmp(sval,"ABSTRACT") ) {
LDAP_FREE(sval);
if ( seen_kind ) {
ldap_objectclass_free(oc);
return NULL;
}
+ *code = 0;
parse_whsp(&ss);
} else if ( !strcasecmp(sval,"MAY") ) {
LDAP_FREE(sval);
ldap_objectclass_free(oc);
return NULL;
}
+ *code = 0;
parse_whsp(&ss);
} else if ( sval[0] == 'X' && sval[1] == '-' ) {
/* Should be parse_qdstrings */
ext_vals = parse_qdescrs(&ss, code);
+ *code = 0;
if ( !ext_vals ) {
*errp = ss;
ldap_objectclass_free(oc);
LDAP_CONST char ** errp,
LDAP_CONST unsigned flags )
{
- int kind;
+ tk_t kind;
const char * ss = s;
char * sval;
int seen_name = 0;
LDAP_CONST char ** errp,
LDAP_CONST unsigned flags )
{
- int kind, ret;
+ tk_t kind;
+ int ret;
const char * ss = s;
char * sval;
int seen_name = 0;
LDAP_CONST char ** errp,
LDAP_CONST unsigned flags )
{
- int kind;
+ tk_t kind;
const char * ss = s;
char * sval;
int seen_name = 0;
return dest;
}
-int
-ldap_url_parselist (LDAPURLDesc **ludlist, const char *url )
-{
- return ldap_url_parselist_ext( ludlist, url, ", " );
-}
-
-int
-ldap_url_parselist_ext (LDAPURLDesc **ludlist, const char *url, const char *sep )
+static int
+ldap_url_parselist_int (LDAPURLDesc **ludlist, const char *url, const char *sep,
+ int (*url_parse)( const char *, LDAPURLDesc ** ) )
{
int i, rc;
LDAPURLDesc *ludp;
for (i = 0; urls[i] != NULL; i++) ;
/* ...and put them in the "stack" backward */
while (--i >= 0) {
- rc = ldap_url_parse( urls[i], &ludp );
+ rc = url_parse( urls[i], &ludp );
if ( rc != 0 ) {
ldap_charray_free(urls);
ldap_free_urllist(*ludlist);
return LDAP_URL_SUCCESS;
}
+int
+ldap_url_parselist (LDAPURLDesc **ludlist, const char *url )
+{
+ return ldap_url_parselist_int( ludlist, url, ", ", ldap_url_parse );
+}
+
+int
+ldap_url_parselist_ext (LDAPURLDesc **ludlist, const char *url, const char *sep )
+{
+ return ldap_url_parselist_int( ludlist, url, sep, ldap_url_parse_ext );
+}
+
int
ldap_url_parsehosts(
LDAPURLDesc **ludlist,
static void *ldap_int_thread_pool_wrapper( void *pool );
+static ldap_pvt_thread_t ldap_int_main_tid;
+
+static ldap_int_thread_key_t ldap_int_main_thrctx[LDAP_MAXTHR];
+
int
ldap_int_thread_pool_startup ( void )
{
+ ldap_int_main_tid = ldap_pvt_thread_self();
+
return ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex);
}
int i, hash;
tid = ldap_pvt_thread_self();
+ if ( TID_EQ( tid, ldap_int_main_tid ))
+ return ldap_int_main_thrctx;
TID_HASH( tid, hash );
for (i = hash & (LDAP_MAXTHR-1); !TID_EQ(thread_keys[i].id, tid_zero) &&
return thread_keys[i].ctx;
}
+void ldap_pvt_thread_pool_context_reset( void *vctx )
+{
+ ldap_int_thread_key_t *ctx = vctx;
+ int i;
+
+ for ( i=0; i<MAXKEYS && ctx[i].ltk_key; i++) {
+ if ( ctx[i].ltk_free )
+ ctx[i].ltk_free( ctx[i].ltk_key, ctx[i].ltk_data );
+ ctx[i].ltk_key = NULL;
+ }
+}
#endif /* LDAP_THREAD_HAVE_TPOOL */
}
#ifdef SLAPD_CLEARTEXT
+ /* Do we think there is a scheme specifier here that we
+ * didn't recognize? Assume a scheme name is at least 1 character.
+ */
+ if (( passwd->bv_val[0] == '{' ) &&
+ ( strchr( passwd->bv_val, '}' ) > passwd->bv_val+1 ))
+ return 1;
if( is_allowed_scheme("{CLEARTEXT}", schemes ) ) {
- return (( passwd->bv_len == cred->bv_len ) &&
- ( passwd->bv_val[0] != '{' /*'}'*/ ))
- ? memcmp( passwd->bv_val, cred->bv_val, passwd->bv_len )
+ return ( passwd->bv_len == cred->bv_len ) ?
+ memcmp( passwd->bv_val, cred->bv_val, passwd->bv_len )
: 1;
}
#endif
char *lr_pattern;
char *lr_subststring;
char *lr_flagstring;
- regex_t lr_regex;
+ regex_t lr_regex;
/*
* I was thinking about some kind of per-rule mutex, but there's
rule->lr_pattern, string, strcnt + 1 );
op->lo_num_passes++;
- if ( regexec( &rule->lr_regex, string, nmatch, match, 0 ) != 0 ) {
+
+ rc = regexec( &rule->lr_regex, string, nmatch, match, 0 );
+ if ( rc != 0 ) {
if ( *result == NULL && string != arg ) {
free( string );
}
backover.c ctxcsn.c ldapsync.c frontend.c \
slapadd.c slapcat.c slapcommon.c slapdn.c slapindex.c \
slappasswd.c slaptest.c slapauth.c slapacl.c component.c \
+ aci.c \
$(@PLAT@_SRCS)
OBJS = main.o globals.o bconfig.o config.o daemon.o \
backover.o ctxcsn.o ldapsync.o frontend.o \
slapadd.o slapcat.o slapcommon.o slapdn.o slapindex.o \
slappasswd.o slaptest.o slapauth.o slapacl.o component.o \
+ aci.o \
$(@PLAT@_OBJS)
LDAP_INCDIR= ../../include -I$(srcdir) -I$(srcdir)/slapi -I.
return SLAPD_DISCONNECT;
}
+ Statslog( LDAP_DEBUG_STATS, "%s ABANDON msg=%ld\n",
+ op->o_log_prefix, (long) id, 0, 0, 0 );
+
if( get_ctrls( op, rs, 0 ) != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "do_abandon: get_ctrls failed\n", 0, 0 ,0 );
return rs->sr_err;
--- /dev/null
+/* aci.c - routines to parse and check acl's */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2005 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* Portions Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include "portable.h"
+
+#ifdef SLAPD_ACI_ENABLED
+
+#include <stdio.h>
+
+#include <ac/ctype.h>
+#include <ac/regex.h>
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+
+#include "slap.h"
+#include "lber_pvt.h"
+#include "lutil.h"
+
+#define ACI_BUF_SIZE 1024 /* use most appropriate size */
+
+#ifdef SLAP_DYNACL
+static
+#endif /* SLAP_DYNACL */
+AttributeDescription *slap_ad_aci;
+
+static int
+OpenLDAPaciValidate(
+ Syntax *syntax,
+ struct berval *val );
+
+static int
+OpenLDAPaciPretty(
+ Syntax *syntax,
+ struct berval *val,
+ struct berval *out,
+ void *ctx );
+
+static int
+OpenLDAPaciNormalize(
+ slap_mask_t use,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *val,
+ struct berval *out,
+ void *ctx );
+
+#define OpenLDAPaciMatch octetStringMatch
+
+static int
+aci_list_map_rights(
+ struct berval *list )
+{
+ struct berval bv;
+ slap_access_t mask;
+ int i;
+
+ ACL_INIT( mask );
+ for ( i = 0; acl_get_part( list, i, ',', &bv ) >= 0; i++ ) {
+ if ( bv.bv_len <= 0 ) {
+ continue;
+ }
+
+ switch ( *bv.bv_val ) {
+ case 'x':
+ /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt does not
+ * define any equivalent to the AUTH right, so I've just used
+ * 'x' for now.
+ */
+ ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
+ break;
+ case 'd':
+ /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt defines
+ * the right 'd' to mean "delete"; we hijack it to mean
+ * "disclose" for consistency wuith the rest of slapd.
+ */
+ ACL_PRIV_SET(mask, ACL_PRIV_DISCLOSE);
+ break;
+ case 'c':
+ ACL_PRIV_SET(mask, ACL_PRIV_COMPARE);
+ break;
+ case 's':
+ /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt defines
+ * the right 's' to mean "set", but in the examples states
+ * that the right 's' means "search". The latter definition
+ * is used here.
+ */
+ ACL_PRIV_SET(mask, ACL_PRIV_SEARCH);
+ break;
+ case 'r':
+ ACL_PRIV_SET(mask, ACL_PRIV_READ);
+ break;
+ case 'w':
+ ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ return mask;
+}
+
+static int
+aci_list_has_attr(
+ struct berval *list,
+ const struct berval *attr,
+ struct berval *val )
+{
+ struct berval bv, left, right;
+ int i;
+
+ for ( i = 0; acl_get_part( list, i, ',', &bv ) >= 0; i++ ) {
+ if ( acl_get_part(&bv, 0, '=', &left ) < 0
+ || acl_get_part( &bv, 1, '=', &right ) < 0 )
+ {
+ if ( ber_bvstrcasecmp( attr, &bv ) == 0 ) {
+ return(1);
+ }
+
+ } else if ( val == NULL ) {
+ if ( ber_bvstrcasecmp( attr, &left ) == 0 ) {
+ return(1);
+ }
+
+ } else {
+ if ( ber_bvstrcasecmp( attr, &left ) == 0 ) {
+ /* FIXME: this is also totally undocumented! */
+ /* this is experimental code that implements a
+ * simple (prefix) match of the attribute value.
+ * the ACI draft does not provide for aci's that
+ * apply to specific values, but it would be
+ * nice to have. If the <attr> part of an aci's
+ * rights list is of the form <attr>=<value>,
+ * that means the aci applies only to attrs with
+ * the given value. Furthermore, if the attr is
+ * of the form <attr>=<value>*, then <value> is
+ * treated as a prefix, and the aci applies to
+ * any value with that prefix.
+ *
+ * Ideally, this would allow r.e. matches.
+ */
+ if ( acl_get_part( &right, 0, '*', &left ) < 0
+ || right.bv_len <= left.bv_len )
+ {
+ if ( ber_bvstrcasecmp( val, &right ) == 0 ) {
+ return 1;
+ }
+
+ } else if ( val->bv_len >= left.bv_len ) {
+ if ( strncasecmp( val->bv_val, left.bv_val, left.bv_len ) == 0 ) {
+ return(1);
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static slap_access_t
+aci_list_get_attr_rights(
+ struct berval *list,
+ const struct berval *attr,
+ struct berval *val )
+{
+ struct berval bv;
+ slap_access_t mask;
+ int i;
+
+ /* loop through each rights/attr pair, skip first part (action) */
+ ACL_INIT(mask);
+ for ( i = 1; acl_get_part( list, i + 1, ';', &bv ) >= 0; i += 2 ) {
+ if ( aci_list_has_attr( &bv, attr, val ) == 0 ) {
+ continue;
+ }
+
+ if ( acl_get_part( list, i, ';', &bv ) < 0 ) {
+ continue;
+ }
+
+ mask |= aci_list_map_rights( &bv );
+ }
+
+ return mask;
+}
+
+static int
+aci_list_get_rights(
+ struct berval *list,
+ const struct berval *attr,
+ struct berval *val,
+ slap_access_t *grant,
+ slap_access_t *deny )
+{
+ struct berval perm, actn;
+ slap_access_t *mask;
+ int i, found;
+
+ if ( attr == NULL || BER_BVISEMPTY( attr )
+ || ber_bvstrcasecmp( attr, &aci_bv[ ACI_BV_ENTRY ] ) == 0 )
+ {
+ attr = &aci_bv[ ACI_BV_BR_ENTRY ];
+ }
+
+ found = 0;
+ ACL_INIT(*grant);
+ ACL_INIT(*deny);
+ /* loop through each permissions clause */
+ for ( i = 0; acl_get_part( list, i, '$', &perm ) >= 0; i++ ) {
+ if ( acl_get_part( &perm, 0, ';', &actn ) < 0 ) {
+ continue;
+ }
+
+ if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_GRANT ], &actn ) == 0 ) {
+ mask = grant;
+
+ } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_DENY ], &actn ) == 0 ) {
+ mask = deny;
+
+ } else {
+ continue;
+ }
+
+ found = 1;
+ *mask |= aci_list_get_attr_rights( &perm, attr, val );
+ *mask |= aci_list_get_attr_rights( &perm, &aci_bv[ ACI_BV_BR_ALL ], NULL );
+ }
+
+ return found;
+}
+
+static int
+aci_group_member (
+ struct berval *subj,
+ const struct berval *defgrpoc,
+ const struct berval *defgrpat,
+ Operation *op,
+ Entry *e,
+ int nmatch,
+ regmatch_t *matches
+)
+{
+ struct berval subjdn;
+ struct berval grpoc;
+ struct berval grpat;
+ ObjectClass *grp_oc = NULL;
+ AttributeDescription *grp_ad = NULL;
+ const char *text;
+ int rc;
+
+ /* format of string is "{group|role}/objectClassValue/groupAttrName" */
+ if ( acl_get_part( subj, 0, '/', &subjdn ) < 0 ) {
+ return 0;
+ }
+
+ if ( acl_get_part( subj, 1, '/', &grpoc ) < 0 ) {
+ grpoc = *defgrpoc;
+ }
+
+ if ( acl_get_part( subj, 2, '/', &grpat ) < 0 ) {
+ grpat = *defgrpat;
+ }
+
+ rc = slap_bv2ad( &grpat, &grp_ad, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ rc = 0;
+ goto done;
+ }
+ rc = 0;
+
+ grp_oc = oc_bvfind( &grpoc );
+
+ if ( grp_oc != NULL && grp_ad != NULL ) {
+ char buf[ ACI_BUF_SIZE ];
+ struct berval bv, ndn;
+
+ bv.bv_len = sizeof( buf ) - 1;
+ bv.bv_val = (char *)&buf;
+ if ( acl_string_expand( &bv, &subjdn,
+ e->e_ndn, nmatch, matches ) )
+ {
+ rc = LDAP_OTHER;
+ goto done;
+ }
+
+ if ( dnNormalize( 0, NULL, NULL, &bv, &ndn, op->o_tmpmemctx ) == LDAP_SUCCESS )
+ {
+ rc = ( backend_group( op, e, &ndn, &op->o_ndn,
+ grp_oc, grp_ad ) == 0 );
+ slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
+ }
+ }
+
+done:
+ return rc;
+}
+
+int
+aci_mask(
+ Operation *op,
+ Entry *e,
+ AttributeDescription *desc,
+ struct berval *val,
+ struct berval *aci,
+ int nmatch,
+ regmatch_t *matches,
+ slap_access_t *grant,
+ slap_access_t *deny,
+ slap_aci_scope_t asserted_scope )
+{
+ struct berval bv,
+ scope,
+ perms,
+ type,
+ opts,
+ sdn;
+ int rc;
+
+
+ assert( !BER_BVISNULL( &desc->ad_cname ) );
+
+ /* parse an aci of the form:
+ oid # scope # action;rights;attr;rights;attr
+ $ action;rights;attr;rights;attr # type # subject
+
+ [NOTE: the following comment is very outdated,
+ as the draft version it refers to (Ando, 2004-11-20)].
+
+ See draft-ietf-ldapext-aci-model-04.txt section 9.1 for
+ a full description of the format for this attribute.
+ Differences: "this" in the draft is "self" here, and
+ "self" and "public" is in the position of type.
+
+ <scope> = {entry|children|subtree}
+ <type> = {public|users|access-id|subtree|onelevel|children|
+ self|dnattr|group|role|set|set-ref}
+
+ This routine now supports scope={ENTRY,CHILDREN}
+ with the semantics:
+ - ENTRY applies to "entry" and "subtree";
+ - CHILDREN aplies to "children" and "subtree"
+ */
+
+ /* check that the aci has all 5 components */
+ if ( acl_get_part( aci, 4, '#', NULL ) < 0 ) {
+ return 0;
+ }
+
+ /* check that the aci family is supported */
+ /* FIXME: the OID is ignored? */
+ if ( acl_get_part( aci, 0, '#', &bv ) < 0 ) {
+ return 0;
+ }
+
+ /* check that the scope matches */
+ if ( acl_get_part( aci, 1, '#', &scope ) < 0 ) {
+ return 0;
+ }
+
+ /* note: scope can be either ENTRY or CHILDREN;
+ * they respectively match "entry" and "children" in bv
+ * both match "subtree" */
+ switch ( asserted_scope ) {
+ case SLAP_ACI_SCOPE_ENTRY:
+ if ( ber_bvcmp( &scope, &aci_bv[ ACI_BV_ENTRY ] ) != 0
+ && ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_SUBTREE ] ) != 0 )
+ {
+ return 0;
+ }
+ break;
+
+ case SLAP_ACI_SCOPE_CHILDREN:
+ if ( ber_bvcmp( &scope, &aci_bv[ ACI_BV_CHILDREN ] ) != 0
+ && ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_SUBTREE ] ) != 0 )
+ {
+ return 0;
+ }
+ break;
+
+ case SLAP_ACI_SCOPE_SUBTREE:
+ /* TODO: add assertion? */
+ return 0;
+ }
+
+ /* get the list of permissions clauses, bail if empty */
+ if ( acl_get_part( aci, 2, '#', &perms ) <= 0 ) {
+ assert( 0 );
+ return 0;
+ }
+
+ /* check if any permissions allow desired access */
+ if ( aci_list_get_rights( &perms, &desc->ad_cname, val, grant, deny ) == 0 ) {
+ return 0;
+ }
+
+ /* see if we have a DN match */
+ if ( acl_get_part( aci, 3, '#', &type ) < 0 ) {
+ assert( 0 );
+ return 0;
+ }
+
+ /* see if we have a public (i.e. anonymous) access */
+ if ( ber_bvcmp( &aci_bv[ ACI_BV_PUBLIC ], &type ) == 0 ) {
+ return 1;
+ }
+
+ /* otherwise require an identity */
+ if ( BER_BVISNULL( &op->o_ndn ) || BER_BVISEMPTY( &op->o_ndn ) ) {
+ return 0;
+ }
+
+ /* see if we have a users access */
+ if ( ber_bvcmp( &aci_bv[ ACI_BV_USERS ], &type ) == 0 ) {
+ return 1;
+ }
+
+ /* NOTE: this may fail if a DN contains a valid '#' (unescaped);
+ * just grab all the berval up to its end (ITS#3303).
+ * NOTE: the problem could be solved by providing the DN with
+ * the embedded '#' encoded as hexpairs: "cn=Foo#Bar" would
+ * become "cn=Foo\23Bar" and be safely used by aci_mask(). */
+#if 0
+ if ( acl_get_part( aci, 4, '#', &sdn ) < 0 ) {
+ return 0;
+ }
+#endif
+ sdn.bv_val = type.bv_val + type.bv_len + STRLENOF( "#" );
+ sdn.bv_len = aci->bv_len - ( sdn.bv_val - aci->bv_val );
+
+ /* get the type options, if any */
+ if ( acl_get_part( &type, 1, '/', &opts ) > 0 ) {
+ opts.bv_len = type.bv_len - ( opts.bv_val - type.bv_val );
+ type.bv_len = opts.bv_val - type.bv_val - 1;
+
+ } else {
+ BER_BVZERO( &opts );
+ }
+
+ if ( ber_bvcmp( &aci_bv[ ACI_BV_ACCESS_ID ], &type ) == 0 ) {
+ return dn_match( &op->o_ndn, &sdn );
+
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SUBTREE ], &type ) == 0 ) {
+ return dnIsSuffix( &op->o_ndn, &sdn );
+
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_ONELEVEL ], &type ) == 0 ) {
+ struct berval pdn;
+
+ dnParent( &sdn, &pdn );
+
+ return dn_match( &op->o_ndn, &pdn );
+
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_CHILDREN ], &type ) == 0 ) {
+ return ( !dn_match( &op->o_ndn, &sdn ) && dnIsSuffix( &op->o_ndn, &sdn ) );
+
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SELF ], &type ) == 0 ) {
+ return dn_match( &op->o_ndn, &e->e_nname );
+
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_DNATTR ], &type ) == 0 ) {
+ Attribute *at;
+ AttributeDescription *ad = NULL;
+ const char *text;
+
+ rc = slap_bv2ad( &sdn, &ad, &text );
+ assert( rc == LDAP_SUCCESS );
+
+ rc = 0;
+ for ( at = attrs_find( e->e_attrs, ad );
+ at != NULL;
+ at = attrs_find( at->a_next, ad ) )
+ {
+ if ( value_find_ex( ad,
+ SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
+ SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
+ at->a_nvals,
+ &op->o_ndn, op->o_tmpmemctx ) == 0 )
+ {
+ rc = 1;
+ break;
+ }
+ }
+
+ return rc;
+
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_GROUP ], &type ) == 0 ) {
+ struct berval oc,
+ at;
+
+ if ( BER_BVISNULL( &opts ) ) {
+ oc = aci_bv[ ACI_BV_GROUP_CLASS ];
+ at = aci_bv[ ACI_BV_GROUP_ATTR ];
+
+ } else {
+ if ( acl_get_part( &opts, 0, '/', &oc ) < 0 ) {
+ assert( 0 );
+ }
+
+ if ( acl_get_part( &opts, 1, '/', &at ) < 0 ) {
+ at = aci_bv[ ACI_BV_GROUP_ATTR ];
+ }
+ }
+
+ if ( aci_group_member( &sdn, &oc, &at, op, e, nmatch, matches ) )
+ {
+ return 1;
+ }
+
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_ROLE ], &type ) == 0 ) {
+ struct berval oc,
+ at;
+
+ if ( BER_BVISNULL( &opts ) ) {
+ oc = aci_bv[ ACI_BV_ROLE_CLASS ];
+ at = aci_bv[ ACI_BV_ROLE_ATTR ];
+
+ } else {
+ if ( acl_get_part( &opts, 0, '/', &oc ) < 0 ) {
+ assert( 0 );
+ }
+
+ if ( acl_get_part( &opts, 1, '/', &at ) < 0 ) {
+ at = aci_bv[ ACI_BV_ROLE_ATTR ];
+ }
+ }
+
+ if ( aci_group_member( &sdn, &oc, &at, op, e, nmatch, matches ) )
+ {
+ return 1;
+ }
+
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SET ], &type ) == 0 ) {
+ if ( acl_match_set( &sdn, op, e, 0 ) ) {
+ return 1;
+ }
+
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SET_REF ], &type ) == 0 ) {
+ if ( acl_match_set( &sdn, op, e, 1 ) ) {
+ return 1;
+ }
+
+ } else {
+ /* it passed normalization! */
+ assert( 0 );
+ }
+
+ return 0;
+}
+
+int
+aci_init( void )
+{
+ /* OpenLDAP Experimental Syntax */
+ static slap_syntax_defs_rec aci_syntax_def = {
+ "( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
+ SLAP_SYNTAX_HIDE,
+ OpenLDAPaciValidate,
+ OpenLDAPaciPretty
+ };
+ static slap_mrule_defs_rec aci_mr_def = {
+ "( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
+ "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
+ SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
+ NULL, OpenLDAPaciNormalize, OpenLDAPaciMatch,
+ NULL, NULL,
+ NULL
+ };
+ static struct {
+ char *name;
+ char *desc;
+ slap_mask_t flags;
+ AttributeDescription **ad;
+ } aci_at = {
+ "OpenLDAPaci", "( 1.3.6.1.4.1.4203.666.1.5 "
+ "NAME 'OpenLDAPaci' "
+ "DESC 'OpenLDAP access control information (experimental)' "
+ "EQUALITY OpenLDAPaciMatch "
+ "SYNTAX 1.3.6.1.4.1.4203.666.2.1 "
+ "USAGE directoryOperation )",
+ SLAP_AT_HIDE,
+ &slap_ad_aci
+ };
+
+ LDAPAttributeType *at;
+ AttributeType *sat;
+ int rc;
+ const char *text;
+
+ /* ACI syntax */
+ rc = register_syntax( &aci_syntax_def );
+ if ( rc != 0 ) {
+ return rc;
+ }
+
+ /* ACI equality rule */
+ rc = register_matching_rule( &aci_mr_def );
+ if ( rc != 0 ) {
+ return rc;
+ }
+
+ /* ACI attribute */
+ at = ldap_str2attributetype( aci_at.desc,
+ &rc, &text, LDAP_SCHEMA_ALLOW_ALL );
+ if ( !at ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s AttributeType load failed: %s %s\n",
+ aci_at.name, ldap_scherr2str( rc ), text );
+ return rc;
+ }
+
+ rc = at_add( at, 0, &sat, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ ldap_attributetype_free( at );
+ fprintf( stderr, "iMUX_monitor_schema_init: "
+ "AttributeType load failed: %s %s\n",
+ scherr2str( rc ), text );
+ return rc;
+ }
+ ldap_memfree( at );
+
+ rc = slap_str2ad( aci_at.name,
+ aci_at.ad, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY,
+ "unable to find AttributeDescription "
+ "\"%s\": %d (%s)\n",
+ aci_at.name, rc, text );
+ return 1;
+ }
+
+ /* install flags */
+ sat->sat_flags |= aci_at.flags;
+
+ return rc;
+}
+
+#ifdef SLAP_DYNACL
+/*
+ * FIXME: there is a silly dependence that makes it difficult
+ * to move ACIs in a run-time loadable module under the "dynacl"
+ * umbrella, because sets share some helpers with ACIs.
+ */
+static int
+dynacl_aci_parse(
+ const char *fname,
+ int lineno,
+ const char *opts,
+ slap_style_t sty,
+ const char *right,
+ void **privp )
+{
+ AttributeDescription *ad = NULL;
+ const char *text = NULL;
+
+ if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
+ fprintf( stderr, "%s: line %d: "
+ "inappropriate style \"%s\" in \"aci\" by clause\n",
+ fname, lineno, style_strings[sty] );
+ return -1;
+ }
+
+ if ( right != NULL && *right != '\0' ) {
+ if ( slap_str2ad( right, &ad, &text ) != LDAP_SUCCESS ) {
+ fprintf( stderr,
+ "%s: line %d: aci \"%s\": %s\n",
+ fname, lineno, right, text );
+ return -1;
+ }
+
+ } else {
+ ad = slap_ad_aci;
+ }
+
+ if ( !is_at_syntax( ad->ad_type, SLAPD_ACI_SYNTAX) ) {
+ fprintf( stderr, "%s: line %d: "
+ "aci \"%s\": inappropriate syntax: %s\n",
+ fname, lineno, right,
+ ad->ad_type->sat_syntax_oid );
+ return -1;
+ }
+
+ *privp = (void *)ad;
+
+ return 0;
+}
+
+static int
+dynacl_aci_unparse( void *priv, struct berval *bv )
+{
+ AttributeDescription *ad = ( AttributeDescription * )priv;
+ char *ptr;
+
+ assert( ad != NULL );
+
+ bv->bv_val = ch_malloc( STRLENOF(" aci=") + ad->ad_cname.bv_len + 1 );
+ ptr = lutil_strcopy( bv->bv_val, " aci=" );
+ ptr = lutil_strcopy( ptr, ad->ad_cname.bv_val );
+ bv->bv_len = ptr - bv->bv_val;
+
+ return 0;
+}
+
+static int
+dynacl_aci_mask(
+ void *priv,
+ Operation *op,
+ Entry *e,
+ AttributeDescription *desc,
+ struct berval *val,
+ int nmatch,
+ regmatch_t *matches,
+ slap_access_t *grantp,
+ slap_access_t *denyp )
+{
+ AttributeDescription *ad = ( AttributeDescription * )priv;
+ Attribute *at;
+ slap_access_t tgrant, tdeny, grant, deny;
+#ifdef LDAP_DEBUG
+ char accessmaskbuf[ACCESSMASK_MAXLEN];
+ char accessmaskbuf1[ACCESSMASK_MAXLEN];
+#endif /* LDAP_DEBUG */
+
+ /* start out with nothing granted, nothing denied */
+ ACL_INIT(tgrant);
+ ACL_INIT(tdeny);
+
+ /* get the aci attribute */
+ at = attr_find( e->e_attrs, ad );
+ if ( at != NULL ) {
+ int i;
+
+ /* the aci is an multi-valued attribute. The
+ * rights are determined by OR'ing the individual
+ * rights given by the acis.
+ */
+ for ( i = 0; !BER_BVISNULL( &at->a_nvals[i] ); i++ ) {
+ if ( aci_mask( op, e, desc, val, &at->a_nvals[i],
+ nmatch, matches, &grant, &deny,
+ SLAP_ACI_SCOPE_ENTRY ) != 0 )
+ {
+ tgrant |= grant;
+ tdeny |= deny;
+ }
+ }
+
+ Debug( LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
+ accessmask2str( tgrant, accessmaskbuf, 1 ),
+ accessmask2str( tdeny, accessmaskbuf1, 1 ), 0 );
+ }
+
+ /* If the entry level aci didn't contain anything valid for the
+ * current operation, climb up the tree and evaluate the
+ * acis with scope set to subtree
+ */
+ if ( tgrant == ACL_PRIV_NONE && tdeny == ACL_PRIV_NONE ) {
+ struct berval parent_ndn;
+
+#if 1
+ /* to solve the chicken'n'egg problem of accessing
+ * the OpenLDAPaci attribute, the direct access
+ * to the entry's attribute is unchecked; however,
+ * further accesses to OpenLDAPaci values in the
+ * ancestors occur through backend_attribute(), i.e.
+ * with the identity of the operation, requiring
+ * further access checking. For uniformity, this
+ * makes further requests occur as the rootdn, if
+ * any, i.e. searching for the OpenLDAPaci attribute
+ * is considered an internal search. If this is not
+ * acceptable, then the same check needs be performed
+ * when accessing the entry's attribute. */
+ Operation op2 = *op;
+
+ if ( !BER_BVISNULL( &op->o_bd->be_rootndn ) ) {
+ op2.o_dn = op->o_bd->be_rootdn;
+ op2.o_ndn = op->o_bd->be_rootndn;
+ }
+#endif
+
+ dnParent( &e->e_nname, &parent_ndn );
+ while ( !BER_BVISEMPTY( &parent_ndn ) ){
+ int i;
+ BerVarray bvals = NULL;
+ int ret, stop;
+
+ Debug( LDAP_DEBUG_ACL, "checking ACI of \"%s\"\n", parent_ndn.bv_val, 0, 0 );
+ ret = backend_attribute( &op2, NULL, &parent_ndn, ad, &bvals, ACL_AUTH );
+
+ switch ( ret ) {
+ case LDAP_SUCCESS :
+ stop = 0;
+ if ( !bvals ) {
+ break;
+ }
+
+ for ( i = 0; !BER_BVISNULL( &bvals[i] ); i++ ) {
+ if ( aci_mask( op, e, desc, val,
+ &bvals[i],
+ nmatch, matches,
+ &grant, &deny,
+ SLAP_ACI_SCOPE_CHILDREN ) != 0 )
+ {
+ tgrant |= grant;
+ tdeny |= deny;
+ /* evaluation stops as soon as either a "deny" or a
+ * "grant" directive matches.
+ */
+ if ( tgrant != ACL_PRIV_NONE || tdeny != ACL_PRIV_NONE ) {
+ stop = 1;
+ }
+ }
+ Debug( LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
+ accessmask2str( tgrant, accessmaskbuf, 1 ),
+ accessmask2str( tdeny, accessmaskbuf1, 1 ), 0 );
+ }
+ break;
+
+ case LDAP_NO_SUCH_ATTRIBUTE:
+ /* just go on if the aci-Attribute is not present in
+ * the current entry
+ */
+ Debug( LDAP_DEBUG_ACL, "no such attribute\n", 0, 0, 0 );
+ stop = 0;
+ break;
+
+ case LDAP_NO_SUCH_OBJECT:
+ /* We have reached the base object */
+ Debug( LDAP_DEBUG_ACL, "no such object\n", 0, 0, 0 );
+ stop = 1;
+ break;
+
+ default:
+ stop = 1;
+ break;
+ }
+
+ if ( stop ) {
+ break;
+ }
+ dnParent( &parent_ndn, &parent_ndn );
+ }
+ }
+
+ *grantp = tgrant;
+ *denyp = tdeny;
+
+ return 0;
+}
+
+/* need to register this at some point */
+static slap_dynacl_t dynacl_aci = {
+ "aci",
+ dynacl_aci_parse,
+ dynacl_aci_unparse,
+ dynacl_aci_mask,
+ NULL,
+ NULL,
+ NULL
+};
+
+int
+dynacl_aci_init( void )
+{
+ int rc;
+
+ rc = aci_init();
+
+ if ( rc == 0 ) {
+ rc = slap_dynacl_register( &dynacl_aci );
+ }
+
+ return rc;
+}
+
+#endif /* SLAP_DYNACL */
+
+/* ACI syntax validation */
+
+/*
+ * Matches given berval to array of bervals
+ * Returns:
+ * >=0 if one if the array elements equals to this berval
+ * -1 if string was not found in array
+ */
+static int
+bv_getcaseidx(
+ struct berval *bv,
+ const struct berval *arr[] )
+{
+ int i;
+
+ if ( BER_BVISEMPTY( bv ) ) {
+ return -1;
+ }
+
+ for ( i = 0; arr[ i ] != NULL ; i++ ) {
+ if ( ber_bvstrcasecmp( bv, arr[ i ] ) == 0 ) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+
+/* Returns what have left in input berval after current sub */
+static void
+bv_get_tail(
+ struct berval *val,
+ struct berval *sub,
+ struct berval *tail )
+{
+ int head_len;
+
+ tail->bv_val = sub->bv_val + sub->bv_len;
+ head_len = (unsigned long) tail->bv_val - (unsigned long) val->bv_val;
+ tail->bv_len = val->bv_len - head_len;
+}
+
+
+/*
+ * aci is accepted in following form:
+ * oid#scope#rights#type#subject
+ * Where:
+ * oid := numeric OID
+ * scope := entry|children
+ * rights := right[[$right]...]
+ * right := (grant|deny);action
+ * action := perms;attr[[;perms;attr]...]
+ * perms := perm[[,perm]...]
+ * perm := c|s|r|w|x
+ * attr := attributeType|[all]
+ * type := public|users|self|dnattr|group|role|set|set-ref|
+ * access_id|subtree|onelevel|children
+ */
+static int
+OpenLDAPaciValidatePerms(
+ struct berval *perms )
+{
+ int i;
+
+ for ( i = 0; i < perms->bv_len; ) {
+ switch ( perms->bv_val[ i ] ) {
+ case 'x':
+ case 'd':
+ case 'c':
+ case 's':
+ case 'r':
+ case 'w':
+ break;
+
+ default:
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ if ( ++i == perms->bv_len ) {
+ return LDAP_SUCCESS;
+ }
+
+ while ( i < perms->bv_len && perms->bv_val[ i ] == ' ' )
+ i++;
+
+ assert( i != perms->bv_len );
+
+ if ( perms->bv_val[ i ] != ',' ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ do {
+ i++;
+ } while ( perms->bv_val[ i ] == ' ' );
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static const struct berval *ACIgrantdeny[] = {
+ &aci_bv[ ACI_BV_GRANT ],
+ &aci_bv[ ACI_BV_DENY ],
+ NULL
+};
+
+static int
+OpenLDAPaciValidateRight(
+ struct berval *action )
+{
+ struct berval bv = BER_BVNULL;
+ int i;
+
+ /* grant|deny */
+ if ( acl_get_part( action, 0, ';', &bv ) < 0 ||
+ bv_getcaseidx( &bv, ACIgrantdeny ) == -1 )
+ {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ for ( i = 0; acl_get_part( action, i + 1, ';', &bv ) >= 0; i++ ) {
+ if ( i & 1 ) {
+ /* perms */
+ if ( OpenLDAPaciValidatePerms( &bv ) != LDAP_SUCCESS )
+ {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ } else {
+ /* attr */
+ AttributeDescription *ad = NULL;
+ const char *text = NULL;
+
+ /* could be "[all]" or an attribute description */
+ if ( ber_bvstrcasecmp( &bv, &aci_bv[ ACI_BV_BR_ALL ] ) == 0 ) {
+ continue;
+ }
+
+ if ( slap_bv2ad( &bv, &ad, &text ) != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+ }
+
+ /* "perms;attr" go in pairs */
+ if ( i > 0 && ( i & 1 ) == 0 ) {
+ return LDAP_SUCCESS;
+
+ } else {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+OpenLDAPaciNormalizeRight(
+ struct berval *action,
+ struct berval *naction,
+ void *ctx )
+{
+ struct berval grantdeny,
+ perms = BER_BVNULL,
+ bv = BER_BVNULL;
+ int idx,
+ i;
+
+ /* grant|deny */
+ if ( acl_get_part( action, 0, ';', &grantdeny ) < 0 ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ idx = bv_getcaseidx( &grantdeny, ACIgrantdeny );
+ if ( idx == -1 ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ ber_dupbv_x( naction, (struct berval *)ACIgrantdeny[ idx ], ctx );
+
+ for ( i = 1; acl_get_part( action, i, ';', &bv ) >= 0; i++ ) {
+ if ( i & 1 ) {
+ /* perms */
+ if ( OpenLDAPaciValidatePerms( &bv ) != LDAP_SUCCESS )
+ {
+ return LDAP_INVALID_SYNTAX;
+ }
+ perms = bv;
+
+ } else {
+ /* attr */
+ char *ptr;
+
+ /* could be "[all]" or an attribute description */
+ if ( ber_bvstrcasecmp( &bv, &aci_bv[ ACI_BV_BR_ALL ] ) == 0 ) {
+ bv = aci_bv[ ACI_BV_BR_ALL ];
+
+ } else {
+ AttributeDescription *ad = NULL;
+ const char *text = NULL;
+ int rc;
+
+ rc = slap_bv2ad( &bv, &ad, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ bv = ad->ad_cname;
+ }
+
+ naction->bv_val = ber_memrealloc_x( naction->bv_val,
+ naction->bv_len + STRLENOF( ";" )
+ + perms.bv_len + STRLENOF( ";" )
+ + bv.bv_len + 1,
+ ctx );
+
+ ptr = &naction->bv_val[ naction->bv_len ];
+ ptr[ 0 ] = ';';
+ ptr++;
+ ptr = lutil_strncopy( ptr, perms.bv_val, perms.bv_len );
+ ptr[ 0 ] = ';';
+ ptr++;
+ ptr = lutil_strncopy( ptr, bv.bv_val, bv.bv_len );
+ ptr[ 0 ] = '\0';
+ naction->bv_len += STRLENOF( ";" ) + perms.bv_len
+ + STRLENOF( ";" ) + bv.bv_len;
+ }
+ }
+
+ /* perms;attr go in pairs */
+ if ( i > 1 && ( i & 1 ) ) {
+ return LDAP_SUCCESS;
+
+ } else {
+ return LDAP_INVALID_SYNTAX;
+ }
+}
+
+static int
+OpenLDAPaciValidateRights(
+ struct berval *actions )
+
+{
+ struct berval bv = BER_BVNULL;
+ int i;
+
+ for ( i = 0; acl_get_part( actions, i, '$', &bv ) >= 0; i++ ) {
+ if ( OpenLDAPaciValidateRight( &bv ) != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+OpenLDAPaciNormalizeRights(
+ struct berval *actions,
+ struct berval *nactions,
+ void *ctx )
+
+{
+ struct berval bv = BER_BVNULL;
+ int i;
+
+ BER_BVZERO( nactions );
+ for ( i = 0; acl_get_part( actions, i, '$', &bv ) >= 0; i++ ) {
+ int rc;
+ struct berval nbv;
+
+ rc = OpenLDAPaciNormalizeRight( &bv, &nbv, ctx );
+ if ( rc != LDAP_SUCCESS ) {
+ ber_memfree_x( nactions->bv_val, ctx );
+ BER_BVZERO( nactions );
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ if ( i == 0 ) {
+ *nactions = nbv;
+
+ } else {
+ nactions->bv_val = ber_memrealloc_x( nactions->bv_val,
+ nactions->bv_len + STRLENOF( "$" )
+ + nbv.bv_len + 1,
+ ctx );
+ nactions->bv_val[ nactions->bv_len ] = '$';
+ AC_MEMCPY( &nactions->bv_val[ nactions->bv_len + 1 ],
+ nbv.bv_val, nbv.bv_len + 1 );
+ ber_memfree_x( nbv.bv_val, ctx );
+ nactions->bv_len += STRLENOF( "$" ) + nbv.bv_len;
+ }
+ BER_BVZERO( &nbv );
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static const struct berval *OpenLDAPaciscopes[] = {
+ &aci_bv[ ACI_BV_ENTRY ],
+ &aci_bv[ ACI_BV_CHILDREN ],
+ &aci_bv[ ACI_BV_SUBTREE ],
+
+ NULL
+};
+
+static const struct berval *OpenLDAPacitypes[] = {
+ /* DN-valued */
+ &aci_bv[ ACI_BV_GROUP ],
+ &aci_bv[ ACI_BV_ROLE ],
+
+/* set to one past the last DN-valued type with options (/) */
+#define LAST_OPTIONAL 2
+
+ &aci_bv[ ACI_BV_ACCESS_ID ],
+ &aci_bv[ ACI_BV_SUBTREE ],
+ &aci_bv[ ACI_BV_ONELEVEL ],
+ &aci_bv[ ACI_BV_CHILDREN ],
+
+/* set to one past the last DN-valued type */
+#define LAST_DNVALUED 6
+
+ /* non DN-valued */
+ &aci_bv[ ACI_BV_DNATTR ],
+ &aci_bv[ ACI_BV_PUBLIC ],
+ &aci_bv[ ACI_BV_USERS ],
+ &aci_bv[ ACI_BV_SELF ],
+ &aci_bv[ ACI_BV_SET ],
+ &aci_bv[ ACI_BV_SET_REF ],
+
+ NULL
+};
+
+static int
+OpenLDAPaciValidate(
+ Syntax *syntax,
+ struct berval *val )
+{
+ struct berval oid = BER_BVNULL,
+ scope = BER_BVNULL,
+ rights = BER_BVNULL,
+ type = BER_BVNULL,
+ subject = BER_BVNULL;
+ int idx;
+
+ if ( BER_BVISEMPTY( val ) ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ /* oid */
+ if ( acl_get_part( val, 0, '#', &oid ) < 0 ||
+ numericoidValidate( NULL, &oid ) != LDAP_SUCCESS )
+ {
+ /* NOTE: the numericoidValidate() is rather pedantic;
+ * I'd replace it with X-ORDERED VALUES so that
+ * it's guaranteed values are maintained and used
+ * in the desired order */
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ /* scope */
+ if ( acl_get_part( val, 1, '#', &scope ) < 0 ||
+ bv_getcaseidx( &scope, OpenLDAPaciscopes ) == -1 )
+ {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ /* rights */
+ if ( acl_get_part( val, 2, '#', &rights ) < 0 ||
+ OpenLDAPaciValidateRights( &rights ) != LDAP_SUCCESS )
+ {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ /* type */
+ if ( acl_get_part( val, 3, '#', &type ) < 0 ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ idx = bv_getcaseidx( &type, OpenLDAPacitypes );
+ if ( idx == -1 ) {
+ struct berval isgr;
+
+ if ( acl_get_part( &type, 0, '/', &isgr ) < 0 ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ idx = bv_getcaseidx( &isgr, OpenLDAPacitypes );
+ if ( idx == -1 || idx >= LAST_OPTIONAL ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ /* subject */
+ bv_get_tail( val, &type, &subject );
+ if ( subject.bv_val[ 0 ] != '#' ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ if ( idx >= LAST_DNVALUED ) {
+ if ( OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_DNATTR ] ) {
+ AttributeDescription *ad = NULL;
+ const char *text = NULL;
+ int rc;
+
+ rc = slap_bv2ad( &subject, &ad, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ if ( ad->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) {
+ /* FIXME: allow nameAndOptionalUID? */
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ /* not a DN */
+ return LDAP_SUCCESS;
+
+ } else if ( OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_GROUP ]
+ || OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_ROLE ] )
+ {
+ /* do {group|role}/oc/at check */
+ struct berval ocbv = BER_BVNULL,
+ atbv = BER_BVNULL;
+
+ ocbv.bv_val = strchr( type.bv_val, '/' );
+ if ( ocbv.bv_val != NULL ) {
+ ocbv.bv_val++;
+
+ atbv.bv_val = strchr( ocbv.bv_val, '/' );
+ if ( atbv.bv_val != NULL ) {
+ AttributeDescription *ad = NULL;
+ const char *text = NULL;
+ int rc;
+
+ atbv.bv_val++;
+ atbv.bv_len = type.bv_len
+ - ( atbv.bv_val - type.bv_val );
+ ocbv.bv_len = atbv.bv_val - ocbv.bv_val - 1;
+
+ rc = slap_bv2ad( &atbv, &ad, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ } else {
+ ocbv.bv_len = type.bv_len
+ - ( ocbv.bv_val - type.bv_val );
+ }
+
+ if ( oc_bvfind( &ocbv ) == NULL ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+ }
+
+ if ( BER_BVISEMPTY( &subject ) ) {
+ /* empty DN invalid */
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ subject.bv_val++;
+ subject.bv_len--;
+
+ /* FIXME: pass DN syntax? */
+ return dnValidate( NULL, &subject );
+}
+
+static int
+OpenLDAPaciPrettyNormal(
+ struct berval *val,
+ struct berval *out,
+ void *ctx,
+ int normalize )
+{
+ struct berval oid = BER_BVNULL,
+ scope = BER_BVNULL,
+ rights = BER_BVNULL,
+ nrights = BER_BVNULL,
+ type = BER_BVNULL,
+ ntype = BER_BVNULL,
+ subject = BER_BVNULL,
+ nsubject = BER_BVNULL;
+ int idx,
+ rc = LDAP_SUCCESS,
+ freesubject = 0,
+ freetype = 0;
+ char *ptr;
+
+ if ( BER_BVISEMPTY( val ) ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ /* oid: if valid, it's already normalized */
+ if ( acl_get_part( val, 0, '#', &oid ) < 0 ||
+ numericoidValidate( NULL, &oid ) != LDAP_SUCCESS )
+ {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ /* scope: normalize by replacing with OpenLDAPaciscopes */
+ if ( acl_get_part( val, 1, '#', &scope ) < 0 ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ idx = bv_getcaseidx( &scope, OpenLDAPaciscopes );
+ if ( idx == -1 ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ scope = *OpenLDAPaciscopes[ idx ];
+
+ /* rights */
+ if ( acl_get_part( val, 2, '#', &rights ) < 0 ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ if ( OpenLDAPaciNormalizeRights( &rights, &nrights, ctx )
+ != LDAP_SUCCESS )
+ {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ /* type */
+ if ( acl_get_part( val, 3, '#', &type ) < 0 ) {
+ rc = LDAP_INVALID_SYNTAX;
+ goto cleanup;
+ }
+ idx = bv_getcaseidx( &type, OpenLDAPacitypes );
+ if ( idx == -1 ) {
+ struct berval isgr;
+
+ if ( acl_get_part( &type, 0, '/', &isgr ) < 0 ) {
+ rc = LDAP_INVALID_SYNTAX;
+ goto cleanup;
+ }
+
+ idx = bv_getcaseidx( &isgr, OpenLDAPacitypes );
+ if ( idx == -1 || idx >= LAST_OPTIONAL ) {
+ rc = LDAP_INVALID_SYNTAX;
+ goto cleanup;
+ }
+ }
+ ntype = *OpenLDAPacitypes[ idx ];
+
+ /* subject */
+ bv_get_tail( val, &type, &subject );
+
+ if ( BER_BVISEMPTY( &subject ) || subject.bv_val[ 0 ] != '#' ) {
+ rc = LDAP_INVALID_SYNTAX;
+ goto cleanup;
+ }
+
+ subject.bv_val++;
+ subject.bv_len--;
+
+ if ( idx < LAST_DNVALUED ) {
+ /* FIXME: pass DN syntax? */
+ if ( normalize ) {
+ rc = dnNormalize( 0, NULL, NULL,
+ &subject, &nsubject, ctx );
+ } else {
+ rc = dnPretty( NULL, &subject, &nsubject, ctx );
+ }
+
+ if ( rc == LDAP_SUCCESS ) {
+ freesubject = 1;
+
+ } else {
+ goto cleanup;
+ }
+
+ if ( OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_GROUP ]
+ || OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_ROLE ] )
+ {
+ /* do {group|role}/oc/at check */
+ struct berval ocbv = BER_BVNULL,
+ atbv = BER_BVNULL;
+
+ ocbv.bv_val = strchr( type.bv_val, '/' );
+ if ( ocbv.bv_val != NULL ) {
+ ObjectClass *oc = NULL;
+ AttributeDescription *ad = NULL;
+ const char *text = NULL;
+ int rc;
+ struct berval bv;
+
+ bv.bv_len = ntype.bv_len;
+
+ ocbv.bv_val++;
+
+ atbv.bv_val = strchr( ocbv.bv_val, '/' );
+ if ( atbv.bv_val != NULL ) {
+ atbv.bv_val++;
+ atbv.bv_len = type.bv_len
+ - ( atbv.bv_val - type.bv_val );
+ ocbv.bv_len = atbv.bv_val - ocbv.bv_val - 1;
+
+ rc = slap_bv2ad( &atbv, &ad, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ rc = LDAP_INVALID_SYNTAX;
+ goto cleanup;
+ }
+
+ bv.bv_len += STRLENOF( "/" ) + ad->ad_cname.bv_len;
+
+ } else {
+ ocbv.bv_len = type.bv_len
+ - ( ocbv.bv_val - type.bv_val );
+ }
+
+ oc = oc_bvfind( &ocbv );
+ if ( oc == NULL ) {
+ rc = LDAP_INVALID_SYNTAX;
+ goto cleanup;
+ }
+
+ bv.bv_len += STRLENOF( "/" ) + oc->soc_cname.bv_len;
+ bv.bv_val = ber_memalloc_x( bv.bv_len + 1, ctx );
+
+ ptr = bv.bv_val;
+ ptr = lutil_strncopy( ptr, ntype.bv_val, ntype.bv_len );
+ ptr[ 0 ] = '/';
+ ptr++;
+ ptr = lutil_strncopy( ptr,
+ oc->soc_cname.bv_val,
+ oc->soc_cname.bv_len );
+ if ( ad != NULL ) {
+ ptr[ 0 ] = '/';
+ ptr++;
+ ptr = lutil_strncopy( ptr,
+ ad->ad_cname.bv_val,
+ ad->ad_cname.bv_len );
+ }
+ ptr[ 0 ] = '\0';
+
+ ntype = bv;
+ freetype = 1;
+ }
+ }
+
+ } else if ( OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_DNATTR ] ) {
+ AttributeDescription *ad = NULL;
+ const char *text = NULL;
+ int rc;
+
+ rc = slap_bv2ad( &subject, &ad, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ rc = LDAP_INVALID_SYNTAX;
+ goto cleanup;
+ }
+
+ if ( ad->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) {
+ /* FIXME: allow nameAndOptionalUID? */
+ rc = LDAP_INVALID_SYNTAX;
+ goto cleanup;
+ }
+
+ nsubject = ad->ad_cname;
+ }
+
+
+ out->bv_len =
+ oid.bv_len + STRLENOF( "#" )
+ + scope.bv_len + STRLENOF( "#" )
+ + rights.bv_len + STRLENOF( "#" )
+ + ntype.bv_len + STRLENOF( "#" )
+ + nsubject.bv_len;
+
+ out->bv_val = ber_memalloc_x( out->bv_len + 1, ctx );
+ ptr = lutil_strncopy( out->bv_val, oid.bv_val, oid.bv_len );
+ ptr[ 0 ] = '#';
+ ptr++;
+ ptr = lutil_strncopy( ptr, scope.bv_val, scope.bv_len );
+ ptr[ 0 ] = '#';
+ ptr++;
+ ptr = lutil_strncopy( ptr, nrights.bv_val, nrights.bv_len );
+ ptr[ 0 ] = '#';
+ ptr++;
+ ptr = lutil_strncopy( ptr, ntype.bv_val, ntype.bv_len );
+ ptr[ 0 ] = '#';
+ ptr++;
+ if ( !BER_BVISNULL( &nsubject ) ) {
+ ptr = lutil_strncopy( ptr, nsubject.bv_val, nsubject.bv_len );
+ }
+ ptr[ 0 ] = '\0';
+
+cleanup:;
+ if ( freesubject ) {
+ ber_memfree_x( nsubject.bv_val, ctx );
+ }
+
+ if ( freetype ) {
+ ber_memfree_x( ntype.bv_val, ctx );
+ }
+
+ if ( !BER_BVISNULL( &nrights ) ) {
+ ber_memfree_x( nrights.bv_val, ctx );
+ }
+
+ return rc;
+}
+
+static int
+OpenLDAPaciPretty(
+ Syntax *syntax,
+ struct berval *val,
+ struct berval *out,
+ void *ctx )
+{
+ return OpenLDAPaciPrettyNormal( val, out, ctx, 0 );
+}
+
+static int
+OpenLDAPaciNormalize(
+ slap_mask_t use,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *val,
+ struct berval *out,
+ void *ctx )
+{
+ return OpenLDAPaciPrettyNormal( val, out, ctx, 1 );
+}
+
+#endif /* SLAPD_ACI_ENABLED */
+
/*
* speed up compares
*/
-static struct berval
- aci_bv_entry = BER_BVC("entry"),
- aci_bv_children = BER_BVC("children"),
- aci_bv_onelevel = BER_BVC("onelevel"),
- aci_bv_subtree = BER_BVC("subtree"),
- aci_bv_br_entry = BER_BVC("[entry]"),
- aci_bv_br_all = BER_BVC("[all]"),
- aci_bv_access_id = BER_BVC("access-id"),
+const struct berval aci_bv[] = {
+ BER_BVC("entry"),
+ BER_BVC("children"),
+ BER_BVC("onelevel"),
+ BER_BVC("subtree"),
+ BER_BVC("[entry]"),
+ BER_BVC("[all]"),
+ BER_BVC("access-id"),
#if 0
- aci_bv_anonymous = BER_BVC("anonymous"),
+ BER_BVC("anonymous"),
#endif
- aci_bv_public = BER_BVC("public"),
- aci_bv_users = BER_BVC("users"),
- aci_bv_self = BER_BVC("self"),
- aci_bv_dnattr = BER_BVC("dnattr"),
- aci_bv_group = BER_BVC("group"),
- aci_bv_role = BER_BVC("role"),
- aci_bv_set = BER_BVC("set"),
- aci_bv_set_ref = BER_BVC("set-ref"),
- aci_bv_grant = BER_BVC("grant"),
- aci_bv_deny = BER_BVC("deny"),
-
- aci_bv_ip_eq = BER_BVC("IP="),
+ BER_BVC("public"),
+ BER_BVC("users"),
+ BER_BVC("self"),
+ BER_BVC("dnattr"),
+ BER_BVC("group"),
+ BER_BVC("role"),
+ BER_BVC("set"),
+ BER_BVC("set-ref"),
+ BER_BVC("grant"),
+ BER_BVC("deny"),
+
+ BER_BVC("IP="),
#ifdef LDAP_PF_LOCAL
- aci_bv_path_eq = BER_BVC("PATH="),
+ BER_BVC("PATH="),
#if 0
- aci_bv_dirsep = BER_BVC(LDAP_DIRSEP),
+ BER_BVC(LDAP_DIRSEP),
#endif
#endif /* LDAP_PF_LOCAL */
- aci_bv_group_class = BER_BVC(SLAPD_GROUP_CLASS),
- aci_bv_group_attr = BER_BVC(SLAPD_GROUP_ATTR),
- aci_bv_role_class = BER_BVC(SLAPD_ROLE_CLASS),
- aci_bv_role_attr = BER_BVC(SLAPD_ROLE_ATTR),
- aci_bv_set_attr = BER_BVC(SLAPD_ACI_SET_ATTR);
-
-typedef enum slap_aci_scope_t {
- SLAP_ACI_SCOPE_ENTRY = 0x1,
- SLAP_ACI_SCOPE_CHILDREN = 0x2,
- SLAP_ACI_SCOPE_SUBTREE = ( SLAP_ACI_SCOPE_ENTRY | SLAP_ACI_SCOPE_CHILDREN )
-} slap_aci_scope_t;
+ BER_BVC(SLAPD_GROUP_CLASS),
+ BER_BVC(SLAPD_GROUP_ATTR),
+ BER_BVC(SLAPD_ROLE_CLASS),
+ BER_BVC(SLAPD_ROLE_ATTR),
+
+ BER_BVC(SLAPD_ACI_SET_ATTR)
+};
static AccessControl * slap_acl_get(
AccessControl *ac, int *count,
int count,
AccessControlState *state );
-#ifdef SLAPD_ACI_ENABLED
-static int aci_mask(
- Operation *op, Entry *e,
- AttributeDescription *desc,
- struct berval *val,
- struct berval *aci,
- int nmatch,
- regmatch_t *matches,
- slap_access_t *grant,
- slap_access_t *deny,
- slap_aci_scope_t scope);
-#endif /* SLAPD_ACI_ENABLED */
-
static int regex_matches(
struct berval *pat, char *str, char *buf,
int nmatch, regmatch_t *matches);
-static int string_expand(
- struct berval *newbuf, struct berval *pattern,
- char *match, int nmatch, regmatch_t *matches);
-typedef struct AciSetCookie {
+typedef struct AclSetCookie {
Operation *op;
Entry *e;
-} AciSetCookie;
+} AclSetCookie;
-SLAP_SET_GATHER aci_set_gather;
-SLAP_SET_GATHER aci_set_gather2;
-static int aci_match_set ( struct berval *subj, Operation *op,
- Entry *e, int setref );
+SLAP_SET_GATHER acl_set_gather;
+SLAP_SET_GATHER acl_set_gather2;
/*
* access_allowed - check whether op->o_ndn is allowed the requested access
* no-user-modification operational attributes are ignored
* by ACL_WRITE checking as any found here are not provided
* by the user
+ *
+ * NOTE: but they are not ignored for ACL_MANAGE, because
+ * if we get here it means a non-root user is trying to
+ * manage data, so we need to check its privileges.
*/
- if ( access_level >= ACL_WRITE && is_at_no_user_mod( desc->ad_type )
+ if ( access_level == ACL_WRITE && is_at_no_user_mod( desc->ad_type )
&& desc != slap_schema.si_ad_entry
&& desc != slap_schema.si_ad_children )
{
assert( attr != NULL );
- if ( op && op->o_is_auth_check &&
- ( access_level == ACL_SEARCH || access_level == ACL_READ ) )
- {
- access = ACL_AUTH;
+ if ( op ) {
+ if ( op->o_is_auth_check &&
+ ( access_level == ACL_SEARCH || access_level == ACL_READ ) )
+ {
+ access = ACL_AUTH;
+
+ } else if ( get_manageDIT( op ) && access_level == ACL_WRITE &&
+ desc == slap_schema.si_ad_entry )
+ {
+ access = ACL_MANAGE;
+ }
}
if ( state ) {
assert( attr != NULL );
- if ( op && op->o_is_auth_check &&
- ( access_level == ACL_SEARCH || access_level == ACL_READ ) )
- {
- access = ACL_AUTH;
+ if ( op ) {
+ if ( op->o_is_auth_check &&
+ ( access_level == ACL_SEARCH || access_level == ACL_READ ) )
+ {
+ access = ACL_AUTH;
+
+ } else if ( get_manageDIT( op ) && access_level == ACL_WRITE &&
+ desc == slap_schema.si_ad_entry )
+ {
+ access = ACL_MANAGE;
+ }
}
if ( state ) {
* no-user-modification operational attributes are ignored
* by ACL_WRITE checking as any found here are not provided
* by the user
+ *
+ * NOTE: but they are not ignored for ACL_MANAGE, because
+ * if we get here it means a non-root user is trying to
+ * manage data, so we need to check its privileges.
*/
- if ( access_level >= ACL_WRITE && is_at_no_user_mod( desc->ad_type )
+ if ( access_level == ACL_WRITE && is_at_no_user_mod( desc->ad_type )
&& desc != slap_schema.si_ad_entry
&& desc != slap_schema.si_ad_children )
{
return 1;
}
- if ( string_expand( &bv, &b->a_pat,
+ if ( acl_string_expand( &bv, &b->a_pat,
e->e_nname.bv_val,
tmp_nmatch, tmp_matchesp ) )
{
AccessControlState *state )
{
int i;
- Access *b;
+ Access *b;
#ifdef LDAP_DEBUG
- char accessmaskbuf[ACCESSMASK_MAXLEN];
+ char accessmaskbuf[ACCESSMASK_MAXLEN];
#if !defined( SLAP_DYNACL ) && defined( SLAPD_ACI_ENABLED )
- char accessmaskbuf1[ACCESSMASK_MAXLEN];
+ char accessmaskbuf1[ACCESSMASK_MAXLEN];
#endif /* !SLAP_DYNACL && SLAPD_ACI_ENABLED */
#endif /* DEBUG */
- const char *attr;
+ const char *attr;
+ slap_mask_t a2pmask = ACL_ACCESS2PRIV( *mask );
assert( a != NULL );
assert( mask != NULL );
bv.bv_len = sizeof( buf ) - 1;
bv.bv_val = buf;
- if ( string_expand( &bv, &b->a_sockurl_pat,
+ if ( acl_string_expand( &bv, &b->a_sockurl_pat,
e->e_ndn, nmatch, matches ) )
{
continue;
bv.bv_len = sizeof(buf) - 1;
bv.bv_val = buf;
- if ( string_expand(&bv, &b->a_domain_pat,
+ if ( acl_string_expand(&bv, &b->a_domain_pat,
e->e_ndn, nmatch, matches) )
{
continue;
bv.bv_len = sizeof( buf ) - 1;
bv.bv_val = buf;
- if ( string_expand( &bv, &b->a_peername_pat,
+ if ( acl_string_expand( &bv, &b->a_peername_pat,
e->e_ndn, nmatch, matches ) )
{
continue;
int port_number = -1;
if ( strncasecmp( op->o_conn->c_peer_name.bv_val,
- aci_bv_ip_eq.bv_val, aci_bv_ip_eq.bv_len ) != 0 )
+ aci_bv[ ACI_BV_IP_EQ ].bv_val,
+ aci_bv[ ACI_BV_IP_EQ ].bv_len ) != 0 )
continue;
- ip.bv_val = op->o_conn->c_peer_name.bv_val + aci_bv_ip_eq.bv_len;
- ip.bv_len = op->o_conn->c_peer_name.bv_len - aci_bv_ip_eq.bv_len;
+ ip.bv_val = op->o_conn->c_peer_name.bv_val + aci_bv[ ACI_BV_IP_EQ ].bv_len;
+ ip.bv_len = op->o_conn->c_peer_name.bv_len - aci_bv[ ACI_BV_IP_EQ ].bv_len;
port = strrchr( ip.bv_val, ':' );
if ( port ) {
struct berval path;
if ( strncmp( op->o_conn->c_peer_name.bv_val,
- aci_bv_path_eq.bv_val, aci_bv_path_eq.bv_len ) != 0 )
+ aci_bv[ ACI_BV_PATH_EQ ].bv_val,
+ aci_bv[ ACI_BV_PATH_EQ ].bv_len ) != 0 )
continue;
- path.bv_val = op->o_conn->c_peer_name.bv_val + aci_bv_path_eq.bv_len;
- path.bv_len = op->o_conn->c_peer_name.bv_len - aci_bv_path_eq.bv_len;
+ path.bv_val = op->o_conn->c_peer_name.bv_val
+ + aci_bv[ ACI_BV_PATH_EQ ].bv_len;
+ path.bv_len = op->o_conn->c_peer_name.bv_len
+ - aci_bv[ ACI_BV_PATH_EQ ].bv_len;
if ( ber_bvcmp( &b->a_peername_pat, &path ) != 0 )
continue;
bv.bv_len = sizeof( buf ) - 1;
bv.bv_val = buf;
- if ( string_expand( &bv, &b->a_sockname_pat,
+ if ( acl_string_expand( &bv, &b->a_sockname_pat,
e->e_ndn, nmatch, matches ) )
{
continue;
continue;
}
- if ( string_expand( &bv, &b->a_group_pat,
+ if ( acl_string_expand( &bv, &b->a_group_pat,
e->e_nname.bv_val,
tmp_nmatch, tmp_matchesp ) )
{
continue;
}
- if ( string_expand( &bv, &b->a_set_pat,
+ if ( acl_string_expand( &bv, &b->a_set_pat,
e->e_nname.bv_val,
tmp_nmatch, tmp_matchesp ) )
{
bv = b->a_set_pat;
}
- if ( aci_match_set( &bv, op, e, 0 ) == 0 ) {
+ if ( acl_match_set( &bv, op, e, 0 ) == 0 ) {
continue;
}
}
/* first check if the right being requested
* is allowed by the ACL clause.
*/
- if ( ! ACL_GRANT( b->a_access_mask, *mask ) ) {
+ if ( ! ACL_PRIV_ISSET( b->a_access_mask, a2pmask ) ) {
continue;
}
ACL_INIT(tdeny);
for ( da = b->a_dynacl; da; da = da->da_next ) {
- slap_access_t grant, deny;
+ slap_access_t grant,
+ deny;
+
+ ACL_INIT(grant);
+ ACL_INIT(deny);
Debug( LDAP_DEBUG_ACL, " <= check a_dynacl: %s\n",
da->da_name, 0, 0 );
* rights given by the acis.
*/
for ( i = 0; !BER_BVISNULL( &at->a_nvals[i] ); i++ ) {
- if (aci_mask( op,
+ if ( aci_mask( op,
e, desc, val,
&at->a_nvals[i],
nmatch, matches,
- &grant, &deny, SLAP_ACI_SCOPE_ENTRY ) != 0)
+ &grant, &deny, SLAP_ACI_SCOPE_ENTRY ) != 0 )
{
tgrant |= grant;
tdeny |= deny;
break;
}
- for( i = 0; bvals[i].bv_val != NULL; i++){
+ for ( i = 0; !BER_BVISNULL( &bvals[i] ); i++ ) {
#if 0
/* FIXME: this breaks acl caching;
* see also ACL_RECORD_VALUE_STATE above */
ACL_RECORD_VALUE_STATE;
#endif
- if (aci_mask(op, e, desc, val, &bvals[i],
+ if ( aci_mask( op, e, desc, val, &bvals[i],
nmatch, matches,
&grant, &deny, SLAP_ACI_SCOPE_CHILDREN ) != 0 )
{
*mask = modmask;
}
+ a2pmask = *mask;
+
Debug( LDAP_DEBUG_ACL,
"<= acl_mask: [%d] mask: %s\n",
i, accessmask2str(*mask, accessmaskbuf, 1), 0 );
acl_check_modlist(
Operation *op,
Entry *e,
- Modifications *mlist
-)
+ Modifications *mlist )
{
struct berval *bv;
AccessControlState state = ACL_STATE_INIT;
* by ACL_WRITE checking as any found here are not provided
* by the user
*/
- if ( is_at_no_user_mod( mlist->sml_desc->ad_type ) ) {
+ if ( is_at_no_user_mod( mlist->sml_desc->ad_type )
+ && ! ( mlist->sml_flags & SLAP_MOD_MANAGING ) )
+ {
Debug( LDAP_DEBUG_ACL, "acl: no-user-mod %s:"
" modify access granted\n",
mlist->sml_desc->ad_cname.bv_val, 0, 0 );
* This prevents abuse from selfwriters.
*/
if ( ! access_allowed( op, e,
- mlist->sml_desc, NULL, ACL_WDEL, &state ) )
+ mlist->sml_desc, NULL,
+ ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL,
+ &state ) )
{
ret = 0;
goto done;
bv->bv_val != NULL; bv++ )
{
if ( ! access_allowed( op, e,
- mlist->sml_desc, bv, ACL_WADD, &state ) )
+ mlist->sml_desc, bv,
+ ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WADD,
+ &state ) )
{
ret = 0;
goto done;
case LDAP_MOD_DELETE:
if ( mlist->sml_values == NULL ) {
if ( ! access_allowed( op, e,
- mlist->sml_desc, NULL, ACL_WDEL, NULL ) )
+ mlist->sml_desc, NULL,
+ ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL,
+ NULL ) )
{
ret = 0;
goto done;
bv->bv_val != NULL; bv++ )
{
if ( ! access_allowed( op, e,
- mlist->sml_desc, bv, ACL_WDEL, &state ) )
+ mlist->sml_desc, bv,
+ ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL,
+ &state ) )
{
ret = 0;
goto done;
return( ret );
}
-static int
-aci_get_part(
+int
+acl_get_part(
struct berval *list,
int ix,
char sep,
return bv->bv_len;
}
-typedef struct aci_set_gather_t {
+typedef struct acl_set_gather_t {
SetCookie *cookie;
BerVarray bvals;
-} aci_set_gather_t;
+} acl_set_gather_t;
static int
-aci_set_cb_gather( Operation *op, SlapReply *rs )
+acl_set_cb_gather( Operation *op, SlapReply *rs )
{
- aci_set_gather_t *p = (aci_set_gather_t *)op->o_callback->sc_private;
+ acl_set_gather_t *p = (acl_set_gather_t *)op->o_callback->sc_private;
if ( rs->sr_type == REP_SEARCH ) {
BerValue bvals[ 2 ];
}
BerVarray
-aci_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *desc )
+acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *desc )
{
- AciSetCookie *cp = (AciSetCookie *)cookie;
+ AclSetCookie *cp = (AclSetCookie *)cookie;
int rc = 0;
LDAPURLDesc *ludp = NULL;
Operation op2 = { 0 };
SlapReply rs = {REP_RESULT};
AttributeName anlist[ 2 ], *anlistp = NULL;
int nattrs = 0;
- slap_callback cb = { NULL, aci_set_cb_gather, NULL, NULL };
- aci_set_gather_t p = { 0 };
+ slap_callback cb = { NULL, acl_set_cb_gather, NULL, NULL };
+ acl_set_gather_t p = { 0 };
const char *text = NULL;
static struct berval defaultFilter_bv = BER_BVC( "(objectClass=*)" );
* also return the syntax or some "comparison cookie".
*/
if ( strncasecmp( name->bv_val, "ldap:///", STRLENOF( "ldap:///" ) ) != 0 ) {
- return aci_set_gather2( cookie, name, desc );
+ return acl_set_gather2( cookie, name, desc );
}
rc = ldap_url_parse( name->bv_val, &ludp );
}
BerVarray
-aci_set_gather2( SetCookie *cookie, struct berval *name, AttributeDescription *desc )
+acl_set_gather2( SetCookie *cookie, struct berval *name, AttributeDescription *desc )
{
- AciSetCookie *cp = (AciSetCookie *)cookie;
+ AclSetCookie *cp = (AclSetCookie *)cookie;
BerVarray bvals = NULL;
struct berval ndn;
int rc = 0;
return bvals;
}
-static int
-aci_match_set (
+int
+acl_match_set (
struct berval *subj,
Operation *op,
Entry *e,
- int setref
-)
+ int setref )
{
struct berval set = BER_BVNULL;
int rc = 0;
- AciSetCookie cookie;
+ AclSetCookie cookie;
if ( setref == 0 ) {
ber_dupbv_x( &set, subj, op->o_tmpmemctx );
AttributeDescription *desc = NULL;
/* format of string is "entry/setAttrName" */
- if ( aci_get_part( subj, 0, '/', &subjdn ) < 0 ) {
+ if ( acl_get_part( subj, 0, '/', &subjdn ) < 0 ) {
return 0;
}
- if ( aci_get_part( subj, 1, '/', &setat ) < 0 ) {
- setat = aci_bv_set_attr;
+ if ( acl_get_part( subj, 1, '/', &setat ) < 0 ) {
+ setat = aci_bv[ ACI_BV_SET_ATTR ];
}
/*
if ( !BER_BVISNULL( &set ) ) {
cookie.op = op;
cookie.e = e;
- rc = ( slap_set_filter( aci_set_gather, (SetCookie *)&cookie, &set,
+ rc = ( slap_set_filter( acl_set_gather, (SetCookie *)&cookie, &set,
&op->o_ndn, &e->e_nname, NULL ) > 0 );
slap_sl_free( set.bv_val, op->o_tmpmemctx );
}
return(rc);
}
-#ifdef SLAPD_ACI_ENABLED
-static int
-aci_list_map_rights(
- struct berval *list )
-{
- struct berval bv;
- slap_access_t mask;
- int i;
-
- ACL_INIT(mask);
- for (i = 0; aci_get_part(list, i, ',', &bv) >= 0; i++) {
- if (bv.bv_len <= 0)
- continue;
- switch (*bv.bv_val) {
- case 'c':
- ACL_PRIV_SET(mask, ACL_PRIV_COMPARE);
- break;
- case 's':
- /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt defines
- * the right 's' to mean "set", but in the examples states
- * that the right 's' means "search". The latter definition
- * is used here.
- */
- ACL_PRIV_SET(mask, ACL_PRIV_SEARCH);
- break;
- case 'r':
- ACL_PRIV_SET(mask, ACL_PRIV_READ);
- break;
- case 'w':
- ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
- break;
- case 'x':
- /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt does not
- * define any equivalent to the AUTH right, so I've just used
- * 'x' for now.
- */
- ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
- break;
- default:
- break;
- }
-
- }
- return(mask);
-}
-
-static int
-aci_list_has_attr(
- struct berval *list,
- const struct berval *attr,
- struct berval *val )
-{
- struct berval bv, left, right;
- int i;
-
- for (i = 0; aci_get_part(list, i, ',', &bv) >= 0; i++) {
- if (aci_get_part(&bv, 0, '=', &left) < 0
- || aci_get_part(&bv, 1, '=', &right) < 0)
- {
- if (ber_bvstrcasecmp(attr, &bv) == 0)
- return(1);
- } else if (val == NULL) {
- if (ber_bvstrcasecmp(attr, &left) == 0)
- return(1);
- } else {
- if (ber_bvstrcasecmp(attr, &left) == 0) {
- /* this is experimental code that implements a
- * simple (prefix) match of the attribute value.
- * the ACI draft does not provide for aci's that
- * apply to specific values, but it would be
- * nice to have. If the <attr> part of an aci's
- * rights list is of the form <attr>=<value>,
- * that means the aci applies only to attrs with
- * the given value. Furthermore, if the attr is
- * of the form <attr>=<value>*, then <value> is
- * treated as a prefix, and the aci applies to
- * any value with that prefix.
- *
- * Ideally, this would allow r.e. matches.
- */
- if (aci_get_part(&right, 0, '*', &left) < 0
- || right.bv_len <= left.bv_len)
- {
- if (ber_bvstrcasecmp(val, &right) == 0)
- return(1);
- } else if (val->bv_len >= left.bv_len) {
- if (strncasecmp( val->bv_val, left.bv_val, left.bv_len ) == 0)
- return(1);
- }
- }
- }
- }
- return(0);
-}
-
-static slap_access_t
-aci_list_get_attr_rights(
- struct berval *list,
- const struct berval *attr,
- struct berval *val )
-{
- struct berval bv;
- slap_access_t mask;
- int i;
-
- /* loop through each rights/attr pair, skip first part (action) */
- ACL_INIT(mask);
- for (i = 1; aci_get_part(list, i + 1, ';', &bv) >= 0; i += 2) {
- if (aci_list_has_attr(&bv, attr, val) == 0)
- continue;
- if (aci_get_part(list, i, ';', &bv) < 0)
- continue;
- mask |= aci_list_map_rights(&bv);
- }
- return(mask);
-}
-
-static int
-aci_list_get_rights(
- struct berval *list,
- const struct berval *attr,
- struct berval *val,
- slap_access_t *grant,
- slap_access_t *deny )
-{
- struct berval perm, actn;
- slap_access_t *mask;
- int i, found;
-
- if (attr == NULL || attr->bv_len == 0
- || ber_bvstrcasecmp( attr, &aci_bv_entry ) == 0) {
- attr = &aci_bv_br_entry;
- }
-
- found = 0;
- ACL_INIT(*grant);
- ACL_INIT(*deny);
- /* loop through each permissions clause */
- for (i = 0; aci_get_part(list, i, '$', &perm) >= 0; i++) {
- if (aci_get_part(&perm, 0, ';', &actn) < 0)
- continue;
- if (ber_bvstrcasecmp( &aci_bv_grant, &actn ) == 0) {
- mask = grant;
- } else if (ber_bvstrcasecmp( &aci_bv_deny, &actn ) == 0) {
- mask = deny;
- } else {
- continue;
- }
-
- found = 1;
- *mask |= aci_list_get_attr_rights(&perm, attr, val);
- *mask |= aci_list_get_attr_rights(&perm, &aci_bv_br_all, NULL);
- }
- return(found);
-}
-
-static int
-aci_group_member (
- struct berval *subj,
- struct berval *defgrpoc,
- struct berval *defgrpat,
- Operation *op,
- Entry *e,
- int nmatch,
- regmatch_t *matches
-)
-{
- struct berval subjdn;
- struct berval grpoc;
- struct berval grpat;
- ObjectClass *grp_oc = NULL;
- AttributeDescription *grp_ad = NULL;
- const char *text;
- int rc;
-
- /* format of string is "group/objectClassValue/groupAttrName" */
- if (aci_get_part(subj, 0, '/', &subjdn) < 0) {
- return(0);
- }
-
- if (aci_get_part(subj, 1, '/', &grpoc) < 0) {
- grpoc = *defgrpoc;
- }
-
- if (aci_get_part(subj, 2, '/', &grpat) < 0) {
- grpat = *defgrpat;
- }
-
- rc = slap_bv2ad( &grpat, &grp_ad, &text );
- if( rc != LDAP_SUCCESS ) {
- rc = 0;
- goto done;
- }
- rc = 0;
-
- grp_oc = oc_bvfind( &grpoc );
-
- if (grp_oc != NULL && grp_ad != NULL ) {
- char buf[ACL_BUF_SIZE];
- struct berval bv, ndn;
- bv.bv_len = sizeof( buf ) - 1;
- bv.bv_val = (char *)&buf;
- if ( string_expand(&bv, &subjdn,
- e->e_ndn, nmatch, matches) )
- {
- rc = LDAP_OTHER;
- goto done;
- }
- if ( dnNormalize( 0, NULL, NULL, &bv, &ndn, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
- rc = ( backend_group( op, e, &ndn, &op->o_ndn,
- grp_oc, grp_ad ) == 0 );
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
- }
- }
-
-done:
- return(rc);
-}
-
-static int
-aci_mask(
- Operation *op,
- Entry *e,
- AttributeDescription *desc,
- struct berval *val,
- struct berval *aci,
- int nmatch,
- regmatch_t *matches,
- slap_access_t *grant,
- slap_access_t *deny,
- slap_aci_scope_t asserted_scope
-)
-{
- struct berval bv, scope, perms, type, sdn;
- int rc;
-
-
- assert( !BER_BVISNULL( &desc->ad_cname ) );
-
- /* parse an aci of the form:
- oid # scope # action;rights;attr;rights;attr
- $ action;rights;attr;rights;attr # type # subject
-
- [NOTE: the following comment is very outdated,
- as the draft version it refers to (Ando, 2004-11-20)].
-
- See draft-ietf-ldapext-aci-model-04.txt section 9.1 for
- a full description of the format for this attribute.
- Differences: "this" in the draft is "self" here, and
- "self" and "public" is in the position of type.
-
- <scope> = {entry|children|subtree}
- <type> = {public|users|access-id|subtree|onelevel|children|
- self|dnattr|group|role|set|set-ref}
-
- This routine now supports scope={ENTRY,CHILDREN}
- with the semantics:
- - ENTRY applies to "entry" and "subtree";
- - CHILDREN aplies to "children" and "subtree"
- */
-
- /* check that the aci has all 5 components */
- if ( aci_get_part( aci, 4, '#', NULL ) < 0 ) {
- return 0;
- }
-
- /* check that the aci family is supported */
- if ( aci_get_part( aci, 0, '#', &bv ) < 0 ) {
- return 0;
- }
-
- /* check that the scope matches */
- if ( aci_get_part( aci, 1, '#', &scope ) < 0 ) {
- return 0;
- }
-
- /* note: scope can be either ENTRY or CHILDREN;
- * they respectively match "entry" and "children" in bv
- * both match "subtree" */
- switch ( asserted_scope ) {
- case SLAP_ACI_SCOPE_ENTRY:
- if ( ber_bvstrcasecmp( &scope, &aci_bv_entry ) != 0
- && ber_bvstrcasecmp( &scope, &aci_bv_subtree ) != 0 )
- {
- return 0;
- }
- break;
-
- case SLAP_ACI_SCOPE_CHILDREN:
- if ( ber_bvstrcasecmp( &scope, &aci_bv_children ) != 0
- && ber_bvstrcasecmp( &scope, &aci_bv_subtree ) != 0 )
- {
- return 0;
- }
- break;
-
- default:
- return 0;
- }
-
- /* get the list of permissions clauses, bail if empty */
- if ( aci_get_part( aci, 2, '#', &perms ) <= 0 ) {
- return 0;
- }
-
- /* check if any permissions allow desired access */
- if ( aci_list_get_rights( &perms, &desc->ad_cname, val, grant, deny ) == 0 ) {
- return 0;
- }
-
- /* see if we have a DN match */
- if ( aci_get_part( aci, 3, '#', &type ) < 0 ) {
- return 0;
- }
-
- /* see if we have a public (i.e. anonymous) access */
- if ( ber_bvstrcasecmp( &aci_bv_public, &type ) == 0 ) {
- return 1;
- }
-
- /* otherwise require an identity */
- if ( BER_BVISNULL( &op->o_ndn ) || BER_BVISEMPTY( &op->o_ndn ) ) {
- return 0;
- }
-
- /* see if we have a users access */
- if ( ber_bvstrcasecmp( &aci_bv_users, &type ) == 0 ) {
- return 1;
- }
-
- /* NOTE: this may fail if a DN contains a valid '#' (unescaped);
- * just grab all the berval up to its end (ITS#3303).
- * NOTE: the problem could be solved by providing the DN with
- * the embedded '#' encoded as hexpairs: "cn=Foo#Bar" would
- * become "cn=Foo\23Bar" and be safely used by aci_mask(). */
-#if 0
- if ( aci_get_part( aci, 4, '#', &sdn ) < 0 ) {
- return 0;
- }
-#endif
- sdn.bv_val = type.bv_val + type.bv_len + STRLENOF( "#" );
- sdn.bv_len = aci->bv_len - ( sdn.bv_val - aci->bv_val );
-
- if ( ber_bvstrcasecmp( &aci_bv_access_id, &type ) == 0 ) {
- struct berval ndn;
-
- rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
- if ( rc != LDAP_SUCCESS ) {
- return 0;
- }
-
- if ( dn_match( &op->o_ndn, &ndn ) ) {
- rc = 1;
- }
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
-
- return rc;
-
- } else if ( ber_bvstrcasecmp( &aci_bv_subtree, &type ) == 0 ) {
- struct berval ndn;
-
- rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
- if ( rc != LDAP_SUCCESS ) {
- return 0;
- }
-
- if ( dnIsSuffix( &op->o_ndn, &ndn ) ) {
- rc = 1;
- }
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
-
- return rc;
-
- } else if ( ber_bvstrcasecmp( &aci_bv_onelevel, &type ) == 0 ) {
- struct berval ndn, pndn;
-
- rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
- if ( rc != LDAP_SUCCESS ) {
- return 0;
- }
-
- dnParent( &ndn, &pndn );
-
- if ( dn_match( &op->o_ndn, &pndn ) ) {
- rc = 1;
- }
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
-
- return rc;
-
- } else if ( ber_bvstrcasecmp( &aci_bv_children, &type ) == 0 ) {
- struct berval ndn;
-
- rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
- if ( rc != LDAP_SUCCESS ) {
- return 0;
- }
-
- if ( !dn_match( &op->o_ndn, &ndn )
- && dnIsSuffix( &op->o_ndn, &ndn ) )
- {
- rc = 1;
- }
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
-
- return rc;
-
- } else if ( ber_bvstrcasecmp( &aci_bv_self, &type ) == 0 ) {
- if ( dn_match( &op->o_ndn, &e->e_nname ) ) {
- return 1;
- }
-
- } else if ( ber_bvstrcasecmp( &aci_bv_dnattr, &type ) == 0 ) {
- Attribute *at;
- AttributeDescription *ad = NULL;
- const char *text;
-
- rc = slap_bv2ad( &sdn, &ad, &text );
-
- if( rc != LDAP_SUCCESS ) {
- return 0;
- }
-
- rc = 0;
-
- for ( at = attrs_find( e->e_attrs, ad );
- at != NULL;
- at = attrs_find( at->a_next, ad ) )
- {
- if ( value_find_ex( ad,
- SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
- SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
- at->a_nvals,
- &op->o_ndn, op->o_tmpmemctx ) == 0 )
- {
- rc = 1;
- break;
- }
- }
-
- return rc;
-
- } else if ( ber_bvstrcasecmp( &aci_bv_group, &type ) == 0 ) {
- if ( aci_group_member( &sdn, &aci_bv_group_class,
- &aci_bv_group_attr, op, e, nmatch, matches ) )
- {
- return 1;
- }
-
- } else if ( ber_bvstrcasecmp( &aci_bv_role, &type ) == 0 ) {
- if ( aci_group_member( &sdn, &aci_bv_role_class,
- &aci_bv_role_attr, op, e, nmatch, matches ) )
- {
- return 1;
- }
-
- } else if ( ber_bvstrcasecmp( &aci_bv_set, &type ) == 0 ) {
- if ( aci_match_set( &sdn, op, e, 0 ) ) {
- return 1;
- }
-
- } else if ( ber_bvstrcasecmp( &aci_bv_set_ref, &type ) == 0 ) {
- if ( aci_match_set( &sdn, op, e, 1 ) ) {
- return 1;
- }
- }
-
- return 0;
-}
-
-#ifdef SLAP_DYNACL
-/*
- * FIXME: there is a silly dependence that makes it difficult
- * to move ACIs in a run-time loadable module under the "dynacl"
- * umbrella, because sets share some helpers with ACIs.
- */
-static int
-dynacl_aci_parse( const char *fname, int lineno, slap_style_t sty, const char *right, void **privp )
-{
- AttributeDescription *ad = NULL;
- const char *text = NULL;
-
- if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
- fprintf( stderr, "%s: line %d: "
- "inappropriate style \"%s\" in \"aci\" by clause\n",
- fname, lineno, style_strings[sty] );
- return -1;
- }
-
- if ( right != NULL && *right != '\0' ) {
- if ( slap_str2ad( right, &ad, &text ) != LDAP_SUCCESS ) {
- fprintf( stderr,
- "%s: line %d: aci \"%s\": %s\n",
- fname, lineno, right, text );
- return -1;
- }
-
- } else {
- ad = slap_schema.si_ad_aci;
- }
-
- if ( !is_at_syntax( ad->ad_type, SLAPD_ACI_SYNTAX) ) {
- fprintf( stderr, "%s: line %d: "
- "aci \"%s\": inappropriate syntax: %s\n",
- fname, lineno, right,
- ad->ad_type->sat_syntax_oid );
- return -1;
- }
-
- *privp = (void *)ad;
-
- return 0;
-}
-
-static int
-dynacl_aci_unparse( void *priv, struct berval *bv )
-{
- AttributeDescription *ad = ( AttributeDescription * )priv;
- char *ptr;
-
- assert( ad != NULL );
-
- bv->bv_val = ch_malloc( STRLENOF(" aci=") + ad->ad_cname.bv_len + 1 );
- ptr = lutil_strcopy( bv->bv_val, " aci=" );
- ptr = lutil_strcopy( ptr, ad->ad_cname.bv_val );
- bv->bv_len = ptr - bv->bv_val;
-
- return 0;
-}
-
-
-static int
-dynacl_aci_mask(
- void *priv,
- Operation *op,
- Entry *e,
- AttributeDescription *desc,
- struct berval *val,
- int nmatch,
- regmatch_t *matches,
- slap_access_t *grantp,
- slap_access_t *denyp )
-{
- AttributeDescription *ad = ( AttributeDescription * )priv;
- Attribute *at;
- slap_access_t tgrant, tdeny, grant, deny;
-#ifdef LDAP_DEBUG
- char accessmaskbuf[ACCESSMASK_MAXLEN];
- char accessmaskbuf1[ACCESSMASK_MAXLEN];
-#endif /* LDAP_DEBUG */
-
- /* start out with nothing granted, nothing denied */
- ACL_INIT(tgrant);
- ACL_INIT(tdeny);
-
- /* get the aci attribute */
- at = attr_find( e->e_attrs, ad );
- if ( at != NULL ) {
- int i;
-
- /* the aci is an multi-valued attribute. The
- * rights are determined by OR'ing the individual
- * rights given by the acis.
- */
- for ( i = 0; !BER_BVISNULL( &at->a_nvals[i] ); i++ ) {
- if ( aci_mask( op, e, desc, val, &at->a_nvals[i],
- nmatch, matches, &grant, &deny,
- SLAP_ACI_SCOPE_ENTRY ) != 0 )
- {
- tgrant |= grant;
- tdeny |= deny;
- }
- }
-
- Debug( LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
- accessmask2str( tgrant, accessmaskbuf, 1 ),
- accessmask2str( tdeny, accessmaskbuf1, 1 ), 0 );
- }
-
- /* If the entry level aci didn't contain anything valid for the
- * current operation, climb up the tree and evaluate the
- * acis with scope set to subtree
- */
- if ( tgrant == ACL_PRIV_NONE && tdeny == ACL_PRIV_NONE ) {
- struct berval parent_ndn;
-
-#if 1
- /* to solve the chicken'n'egg problem of accessing
- * the OpenLDAPaci attribute, the direct access
- * to the entry's attribute is unchecked; however,
- * further accesses to OpenLDAPaci values in the
- * ancestors occur through backend_attribute(), i.e.
- * with the identity of the operation, requiring
- * further access checking. For uniformity, this
- * makes further requests occur as the rootdn, if
- * any, i.e. searching for the OpenLDAPaci attribute
- * is considered an internal search. If this is not
- * acceptable, then the same check needs be performed
- * when accessing the entry's attribute. */
- Operation op2 = *op;
-
- if ( !BER_BVISNULL( &op->o_bd->be_rootndn ) ) {
- op2.o_dn = op->o_bd->be_rootdn;
- op2.o_ndn = op->o_bd->be_rootndn;
- }
-#endif
-
- dnParent( &e->e_nname, &parent_ndn );
- while ( !BER_BVISEMPTY( &parent_ndn ) ){
- int i;
- BerVarray bvals = NULL;
- int ret, stop;
-
- Debug( LDAP_DEBUG_ACL, "checking ACI of \"%s\"\n", parent_ndn.bv_val, 0, 0 );
- ret = backend_attribute( &op2, NULL, &parent_ndn, ad, &bvals, ACL_AUTH );
-
- switch ( ret ) {
- case LDAP_SUCCESS :
- stop = 0;
- if ( !bvals ) {
- break;
- }
-
- for ( i = 0; !BER_BVISNULL( &bvals[i] ); i++) {
- if ( aci_mask( op, e, desc, val,
- &bvals[i],
- nmatch, matches,
- &grant, &deny,
- SLAP_ACI_SCOPE_CHILDREN ) != 0 )
- {
- tgrant |= grant;
- tdeny |= deny;
- /* evaluation stops as soon as either a "deny" or a
- * "grant" directive matches.
- */
- if ( tgrant != ACL_PRIV_NONE || tdeny != ACL_PRIV_NONE ) {
- stop = 1;
- }
- }
- Debug( LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
- accessmask2str( tgrant, accessmaskbuf, 1 ),
- accessmask2str( tdeny, accessmaskbuf1, 1 ), 0 );
- }
- break;
-
- case LDAP_NO_SUCH_ATTRIBUTE:
- /* just go on if the aci-Attribute is not present in
- * the current entry
- */
- Debug( LDAP_DEBUG_ACL, "no such attribute\n", 0, 0, 0 );
- stop = 0;
- break;
-
- case LDAP_NO_SUCH_OBJECT:
- /* We have reached the base object */
- Debug( LDAP_DEBUG_ACL, "no such object\n", 0, 0, 0 );
- stop = 1;
- break;
-
- default:
- stop = 1;
- break;
- }
-
- if ( stop ) {
- break;
- }
- dnParent( &parent_ndn, &parent_ndn );
- }
- }
-
- *grantp = tgrant;
- *denyp = tdeny;
-
- return 0;
-}
-
-/* need to register this at some point */
-static slap_dynacl_t dynacl_aci = {
- "aci",
- dynacl_aci_parse,
- dynacl_aci_unparse,
- dynacl_aci_mask,
- NULL,
- NULL,
- NULL
-};
-
-#endif /* SLAP_DYNACL */
-
-#endif /* SLAPD_ACI_ENABLED */
-
#ifdef SLAP_DYNACL
/*
int
acl_init( void )
{
-#ifdef SLAP_DYNACL
- int i, rc;
- slap_dynacl_t *known_dynacl[] = {
-#ifdef SLAPD_ACI_ENABLED
- &dynacl_aci,
-#endif /* SLAPD_ACI_ENABLED */
- NULL
- };
+ int rc = 0;
- for ( i = 0; known_dynacl[ i ]; i++ ) {
- rc = slap_dynacl_register( known_dynacl[ i ] );
- if ( rc ) {
- return rc;
- }
+#ifdef SLAPD_ACI_ENABLED
+#ifdef SLAP_DYNACL
+ rc = dynacl_aci_init();
+#else /* !SLAP_DYNACL */
+ rc = aci_init();
+#endif /* !SLAP_DYNACL */
+ if ( rc != 0 ) {
+ return rc;
}
-#endif /* SLAP_DYNACL */
+#endif /* SLAPD_ACI_ENABLED */
- return 0;
+ return rc;
}
-static int
-string_expand(
+int
+acl_string_expand(
struct berval *bv,
struct berval *pat,
char *match,
*dp = '\0';
bv->bv_len = size;
- Debug( LDAP_DEBUG_TRACE, "=> string_expand: pattern: %.*s\n", (int)pat->bv_len, pat->bv_val, 0 );
- Debug( LDAP_DEBUG_TRACE, "=> string_expand: expanded: %s\n", bv->bv_val, 0, 0 );
+ Debug( LDAP_DEBUG_TRACE, "=> acl_string_expand: pattern: %.*s\n", (int)pat->bv_len, pat->bv_val, 0 );
+ Debug( LDAP_DEBUG_TRACE, "=> acl_string_expand: expanded: %s\n", bv->bv_val, 0, 0 );
return 0;
}
str = "";
};
- string_expand( &bv, pat, buf, nmatch, matches );
+ acl_string_expand( &bv, pat, buf, nmatch, matches );
rc = regcomp( &re, newbuf, REG_EXTENDED|REG_ICASE );
if ( rc ) {
char error[ACL_BUF_SIZE];
#ifdef SLAP_DYNACL
static int
-slap_dynacl_config( const char *fname, int lineno, Access *b, const char *name, slap_style_t sty, const char *right )
+slap_dynacl_config(
+ const char *fname,
+ int lineno,
+ Access *b,
+ const char *name,
+ const char *opts,
+ slap_style_t sty,
+ const char *right )
{
slap_dynacl_t *da, *tmp;
int rc = 0;
*tmp = *da;
if ( tmp->da_parse ) {
- rc = ( *tmp->da_parse )( fname, lineno, sty, right, &tmp->da_private );
+ rc = ( *tmp->da_parse )( fname, lineno, opts, sty, right, &tmp->da_private );
if ( rc ) {
ch_free( tmp );
return rc;
}
} else {
- b->a_group_oc = oc_find(SLAPD_GROUP_CLASS);
+ b->a_group_oc = oc_find( SLAPD_GROUP_CLASS );
if( b->a_group_oc == NULL ) {
fprintf( stderr,
#ifdef SLAP_DYNACL
{
- char *name = NULL;
+ char *name = NULL,
+ *opts = NULL;
if ( strcasecmp( left, "aci" ) == 0 ) {
name = "aci";
} else if ( strncasecmp( left, "dynacl/", STRLENOF( "dynacl/" ) ) == 0 ) {
name = &left[ STRLENOF( "dynacl/" ) ];
+ opts = strchr( name, '/' );
+ if ( opts ) {
+ opts[ 0 ] = '\0';
+ opts++;
+ }
}
if ( name ) {
- if ( slap_dynacl_config( fname, lineno, b, name, sty, right ) ) {
+ if ( slap_dynacl_config( fname, lineno, b, name, opts, sty, right ) ) {
fprintf( stderr, "%s: line %d: "
"unable to configure dynacl \"%s\"\n",
fname, lineno, name );
}
} else {
- b->a_aci_at = slap_schema.si_ad_aci;
+ b->a_aci_at = slap_ad_aci;
}
if( !is_at_syntax( b->a_aci_at->ad_type,
"\t[peername[.<peernamestyle>]=<peer>] [sockname[.<style>]=<name>]\n"
"\t[domain[.<domainstyle>]=<domain>] [sockurl[.<style>]=<url>]\n"
#ifdef SLAPD_ACI_ENABLED
- "\t[aci=[<attrname>]]\n"
+ "\t[aci[=<attrname>]]\n"
#endif
#ifdef SLAP_DYNACL
- "\t[dynacl/<name>[.<dynstyle>][=<pattern>]]\n"
+ "\t[dynacl/<name>[/<options>][.<dynstyle>][=<pattern>]]\n"
#endif /* SLAP_DYNACL */
"\t[ssf=<n>] [transport_ssf=<n>] [tls_ssf=<n>] [sasl_ssf=<n>]\n",
"<style> ::= exact | regex | base(Object)\n"
if ( !BER_BVISNULL( &a->a_group_pat ) ) {
free( a->a_group_pat.bv_val );
}
+#ifdef SLAP_DYNACL
+ if ( a->a_dynacl != NULL ) {
+ slap_dynacl_t *da;
+ for ( da = a->a_dynacl; da; ) {
+ slap_dynacl_t *tmp = da;
+
+ da = da->da_next;
+
+ if ( tmp->da_destroy ) {
+ tmp->da_destroy( tmp->da_private );
+ }
+
+ ch_free( tmp );
+ }
+ }
+#endif /* SLAP_DYNACL */
free( a );
}
filter_free( a->acl_filter );
}
if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
+ if ( a->acl_dn_style == ACL_STYLE_REGEX ) {
+ regfree( &a->acl_dn_re );
+ }
free ( a->acl_dn_pat.bv_val );
}
if ( a->acl_attrs ) {
for ( da = b->a_dynacl; da; da = da->da_next ) {
if ( da->da_unparse ) {
- struct berval bv;
+ struct berval bv = BER_BVNULL;
(void)( *da->da_unparse )( da->da_private, &bv );
+ assert( !BER_BVISNULL( &bv ) );
ptr = lutil_strcopy( ptr, bv.bv_val );
ch_free( bv.bv_val );
}
continue;
}
+ if ( ber_bvccmp( &attrs->an_name, '*' ) ) {
+ if ( !is_at_operational( desc->ad_type ) ) {
+ return 1;
+ }
+ continue;
+ }
+
+ if ( ber_bvccmp( &attrs->an_name, '+' ) ) {
+ if ( is_at_operational( desc->ad_type ) ) {
+ return 1;
+ }
+ continue;
+ }
+
/*
* EXTENSION: see if requested description is @objectClass
* if so, return attributes which the class requires/allows
/* canonical to upper case */
ldap_pvt_str2upper( desc->ad_cname.bv_val );
+ /* shouldn't we protect this for concurrency? */
desc->ad_type = slap_schema.si_at_undefined;
+ ldap_pvt_thread_mutex_lock( &ad_undef_mutex );
desc->ad_next = desc->ad_type->sat_ad;
desc->ad_type->sat_ad = desc;
+ ldap_pvt_thread_mutex_unlock( &ad_undef_mutex );
}
if( !*ad ) {
tmp = attr_alloc( a->a_desc );
if ( a->a_vals != NULL ) {
- int i;
+ int i;
for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) {
/* EMPTY */ ;
assert( a->a_nvals != NULL );
if ( a->a_nvals != a->a_vals ) {
+ int j;
+
tmp->a_nvals = ch_malloc( (i + 1) * sizeof(struct berval) );
- for ( i = 0; !BER_BVISNULL( &a->a_nvals[i] ); i++ ) {
- ber_dupbv( &tmp->a_nvals[i], &a->a_nvals[i] );
- if ( BER_BVISNULL( &tmp->a_nvals[i] ) ) break;
+ for ( j = 0; !BER_BVISNULL( &a->a_nvals[j] ); j++ ) {
+ assert( j < i );
+ ber_dupbv( &tmp->a_nvals[j], &a->a_nvals[j] );
+ if ( BER_BVISNULL( &tmp->a_nvals[j] ) ) break;
/* FIXME: error? */
}
- BER_BVZERO( &tmp->a_nvals[i] );
+ assert( j == i );
+ BER_BVZERO( &tmp->a_nvals[j] );
} else {
tmp->a_nvals = tmp->a_vals;
#include <ac/stdlib.h>
#include <ac/errno.h>
#include <sys/stat.h>
-#ifdef HAVE_UTIME_H
-# ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-# endif
-# include <utime.h>
-#endif /* HAVE_UTIME_H */
#include "back-bdb.h"
#include <lutil.h>
#include <ldap_rq.h>
return 0;
}
-/*
- * Unconditionally perform a database recovery. Only works on
- * databases that were previously opened with transactions and
- * logs enabled.
- */
-static int
-bdb_do_recovery( BackendDB *be )
-{
- struct bdb_info *bdb = (struct bdb_info *) be->be_private;
- DB_ENV *re_dbenv;
- u_int32_t flags;
- int rc;
- char path[MAXPATHLEN], *ptr;
-
- /* Create and init the recovery environment */
- rc = db_env_create( &re_dbenv, 0 );
- if( rc != 0 ) {
- Debug( LDAP_DEBUG_ANY,
- "bdb_do_recovery: db_env_create failed: %s (%d)\n",
- db_strerror(rc), rc, 0 );
- return rc;
- }
- re_dbenv->set_errpfx( re_dbenv, be->be_suffix[0].bv_val );
- re_dbenv->set_errcall( re_dbenv, bdb_errcall );
- (void)re_dbenv->set_verbose(re_dbenv, DB_VERB_RECOVERY, 1);
-#if DB_VERSION_FULL < 0x04030000
- (void)re_dbenv->set_verbose(re_dbenv, DB_VERB_CHKPOINT, 1);
-#else
- re_dbenv->set_msgcall( re_dbenv, bdb_msgcall );
-#endif
-
- flags = DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL |
- DB_INIT_TXN | DB_USE_ENVIRON | DB_RECOVER;
-
- /* If a key was set, use shared memory for the BDB environment */
- if ( bdb->bi_shm_key ) {
- re_dbenv->set_shm_key( re_dbenv, bdb->bi_shm_key );
- flags |= DB_SYSTEM_MEM;
- }
-
- /* Open the environment, which will also perform the recovery */
-#ifdef HAVE_EBCDIC
- strcpy( path, bdb->bi_dbenv_home );
- __atoe( path );
- rc = re_dbenv->open( re_dbenv,
- path,
- flags,
- bdb->bi_dbenv_mode );
-#else
- rc = re_dbenv->open( re_dbenv,
- bdb->bi_dbenv_home,
- flags,
- bdb->bi_dbenv_mode );
-#endif
- if( rc != 0 ) {
- Debug( LDAP_DEBUG_ANY,
- "bdb_do_recovery: dbenv_open failed: %s (%d)\n",
- db_strerror(rc), rc, 0 );
- return rc;
- }
- (void) re_dbenv->close( re_dbenv, 0 );
-
- /* By convention we reset the mtime for id2entry.bdb to the current time */
- ptr = lutil_strcopy( path, bdb->bi_dbenv_home);
- *ptr++ = LDAP_DIRSEP[0];
- strcpy( ptr, bdbi_databases[0].file);
- (void) utime( path, NULL);
-
- return 0;
-}
-
-/*
- * Database recovery logic:
- * This function is called whenever the database appears to have been
- * shut down uncleanly, as determined by the alock functions.
- * Because of the -q function in slapadd, there is also the possibility
- * that the shutdown happened when transactions weren't being used and
- * the database is likely to be corrupt. The function checks for this
- * condition by examining the environment to make sure it had previously
- * been opened with transactions enabled. If this is the case, the
- * database is recovered as usual. If transactions were not enabled,
- * then this function will return a fail.
- */
-static int
-bdb_db_recover( BackendDB *be )
-{
- struct bdb_info *bdb = (struct bdb_info *) be->be_private;
- DB_ENV *re_dbenv;
- u_int32_t flags;
- int rc;
-#ifdef HAVE_EBCDIC
- char path[MAXPATHLEN];
-#endif
-
- /* Create the recovery environment, then open it.
- * We use the DB_JOIN in combination with a flags value of
- * zero so we join an existing environment and can read the
- * value of the flags that were used the last time the
- * environment was opened. DB_CREATE is added because the
- * open would fail if the only thing that had been done
- * was an open with transactions and logs disabled.
- */
- rc = db_env_create( &re_dbenv, 0 );
- if( rc != 0 ) {
- Debug( LDAP_DEBUG_ANY,
- "bdb_db_recover: db_env_create failed: %s (%d)\n",
- db_strerror(rc), rc, 0 );
- return rc;
- }
- re_dbenv->set_errpfx( re_dbenv, be->be_suffix[0].bv_val );
- re_dbenv->set_errcall( re_dbenv, bdb_errcall );
-
- Debug( LDAP_DEBUG_TRACE,
- "bdb_db_recover: dbenv_open(%s)\n",
- bdb->bi_dbenv_home, 0, 0);
-
-#ifdef HAVE_EBCDIC
- strcpy( path, bdb->bi_dbenv_home );
- __atoe( path );
- rc = re_dbenv->open( re_dbenv,
- path,
- DB_JOINENV,
- bdb->bi_dbenv_mode );
-#else
- rc = re_dbenv->open( re_dbenv,
- bdb->bi_dbenv_home,
- DB_JOINENV,
- bdb->bi_dbenv_mode );
-#endif
-
- if( rc == ENOENT ) {
- Debug( LDAP_DEBUG_TRACE,
- "bdb_db_recover: DB environment files are missing, assuming it was "
- "manually recovered\n", 0, 0, 0 );
- return 0;
- }
- else if( rc != 0 ) {
- Debug( LDAP_DEBUG_ANY,
- "bdb_db_recover: dbenv_open failed: %s (%d)\n",
- db_strerror(rc), rc, 0 );
- return rc;
- }
-
- /*
- * Check the flags that had been used in the previous open.
- * The environment needed to have had both
- * DB_INIT_LOG and DB_INIT_TXN set for us to be willing to
- * recover the database. Otherwise the an app failed while running
- * without transactions and logs enabled and the dn2id and id2entry
- * mapping is likely to be corrupt.
- */
- rc = re_dbenv->get_open_flags( re_dbenv, &flags );
- if( rc != 0 ) {
- Debug( LDAP_DEBUG_ANY,
- "bdb_db_recover: get_open_flags failed: %s (%d)\n",
- db_strerror(rc), rc, 0 );
- return rc;
- }
-
- (void) re_dbenv->close( re_dbenv, 0 );
-
- if( (flags & DB_INIT_LOG) && (flags & DB_INIT_TXN) ) {
- return bdb_do_recovery( be );
- }
-
- Debug( LDAP_DEBUG_ANY,
- "bdb_db_recover: Database cannot be recovered. "\
- "Restore from backup!\n", 0, 0, 0);
- return -1;
-
-}
-
-
static int
bdb_db_open( BackendDB *be )
{
struct stat stat1, stat2;
u_int32_t flags;
char path[MAXPATHLEN];
- char *ptr;
+ char *dbhome;
+ int do_recover = 0, do_alock_recover = 0, open_env = 1, got_env = 0;
if ( be->be_suffix == NULL ) {
Debug( LDAP_DEBUG_ANY,
bdb->bi_dbenv_home, errno, 0 );
return -1;
}
-
+
/* Perform database use arbitration/recovery logic */
rc = alock_open( &bdb->bi_alock_info,
"slapd",
"bdb_db_open: unclean shutdown detected;"
" attempting recovery.\n",
0, 0, 0 );
- if( bdb_db_recover( be ) != 0 ) {
- Debug( LDAP_DEBUG_ANY,
- "bdb_db_open: DB recovery failed.\n",
- 0, 0, 0 );
- return -1;
- }
- if( alock_recover (&bdb->bi_alock_info) != 0 ) {
- Debug( LDAP_DEBUG_ANY,
- "bdb_db_open: alock_recover failed\n",
- 0, 0, 0 );
- return -1;
- }
-
+ do_alock_recover = 1;
+ do_recover = 1;
} else if( rc == ALOCK_BUSY ) {
Debug( LDAP_DEBUG_ANY,
"bdb_db_open: database already in use\n",
0, 0, 0 );
return -1;
}
-
+
/*
* The DB_CONFIG file may have changed. If so, recover the
* database so that new settings are put into effect. Also
* note the possible absence of DB_CONFIG in the log.
*/
if( stat( bdb->bi_db_config_path, &stat1 ) == 0 ) {
- ptr = lutil_strcopy(path, bdb->bi_dbenv_home);
- *ptr++ = LDAP_DIRSEP[0];
- strcpy( ptr, bdbi_databases[0].file);
- if( stat( path, &stat2 ) == 0 ) {
- if( stat2.st_mtime <= stat1.st_mtime ) {
- Debug( LDAP_DEBUG_ANY,
- "bdb_db_open: DB_CONFIG for suffix %s has changed.\n"
- "Performing database recovery to activate new settings.\n",
- be->be_suffix[0].bv_val, 0, 0 );
- if( bdb_do_recovery( be ) != 0) {
+ if ( !do_recover ) {
+ char *ptr = lutil_strcopy(path, bdb->bi_dbenv_home);
+ *ptr++ = LDAP_DIRSEP[0];
+ strcpy( ptr, "__db.001" );
+ if( stat( path, &stat2 ) == 0 ) {
+ if( stat2.st_mtime <= stat1.st_mtime ) {
Debug( LDAP_DEBUG_ANY,
- "bdb_db_open: db recovery failed.\n",
- 0, 0, 0 );
- return -1;
+ "bdb_db_open: DB_CONFIG for suffix %s has changed.\n"
+ "Performing database recovery to activate new settings.\n",
+ be->be_suffix[0].bv_val, 0, 0 );
+ do_recover = 1;
}
}
-
}
}
else {
"Expect poor performance for suffix %s.\n",
bdb->bi_dbenv_home, errno, be->be_suffix[0].bv_val );
}
-
- flags = DB_INIT_MPOOL | DB_THREAD | DB_CREATE;
- if ( !( slapMode & SLAP_TOOL_QUICK ))
- flags |= DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN;
rc = db_env_create( &bdb->bi_dbenv, 0 );
if( rc != 0 ) {
return rc;
}
- /* If a key was set, use shared memory for the BDB environment */
- if ( bdb->bi_shm_key ) {
- bdb->bi_dbenv->set_shm_key( bdb->bi_dbenv, bdb->bi_shm_key );
- flags |= DB_SYSTEM_MEM;
- }
-
bdb->bi_dbenv->set_errpfx( bdb->bi_dbenv, be->be_suffix[0].bv_val );
bdb->bi_dbenv->set_errcall( bdb->bi_dbenv, bdb_errcall );
+
bdb->bi_dbenv->set_lk_detect( bdb->bi_dbenv, bdb->bi_lock_detect );
/* One long-lived TXN per thread, two TXNs per write op */
bdb->bi_dbenv->set_tx_max( bdb->bi_dbenv, connection_pool_max * 3 );
-#ifdef SLAP_ZONE_ALLOC
- if ( bdb->bi_cache.c_maxsize ) {
- bdb->bi_cache.c_zctx = slap_zn_mem_create(
- SLAP_ZONE_INITSIZE,
- SLAP_ZONE_MAXSIZE,
- SLAP_ZONE_DELTA,
- SLAP_ZONE_SIZE);
- }
-#endif
-
- if ( bdb->bi_idl_cache_max_size ) {
- bdb->bi_idl_tree = NULL;
- bdb->bi_idl_cache_size = 0;
- }
-
if( bdb->bi_dbenv_xflags != 0 ) {
rc = bdb->bi_dbenv->set_flags( bdb->bi_dbenv,
bdb->bi_dbenv_xflags, 1);
}
}
- Debug( LDAP_DEBUG_TRACE,
- "bdb_db_open: dbenv_open(%s)\n",
- bdb->bi_dbenv_home, 0, 0);
+#define BDB_TXN_FLAGS (DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN)
#ifdef HAVE_EBCDIC
strcpy( path, bdb->bi_dbenv_home );
__atoe( path );
- rc = bdb->bi_dbenv->open( bdb->bi_dbenv,
- path,
- flags,
- bdb->bi_dbenv_mode );
+ dbhome = path;
#else
- rc = bdb->bi_dbenv->open( bdb->bi_dbenv,
- bdb->bi_dbenv_home,
- flags,
- bdb->bi_dbenv_mode );
+ dbhome = bdb->bi_dbenv_home;
#endif
- if( rc != 0 ) {
+
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_db_open: dbenv_open(%s)\n",
+ bdb->bi_dbenv_home, 0, 0);
+
+ /* Check if there is a usable existing environment */
+ flags = DB_JOINENV | DB_THREAD;
+
+ rc = bdb->bi_dbenv->open( bdb->bi_dbenv, dbhome,
+ flags, bdb->bi_dbenv_mode );
+ if( rc == 0 ) {
+ int flags_ok = 0;
+
+ got_env = 1;
+
+ rc = bdb->bi_dbenv->get_open_flags( bdb->bi_dbenv, &flags );
+ if ( rc == 0 ) {
+ int flag2 = flags & BDB_TXN_FLAGS;
+
+ /* In quick mode, none of these flags are allowed */
+ if ( slapMode & SLAP_TOOL_QUICK ) {
+ if ( !flag2 )
+ flags_ok = 1;
+ } else {
+ /* In normal mode, all of these flags are required */
+ if ( flag2 == BDB_TXN_FLAGS )
+ flags_ok = 1;
+ }
+ }
+
+ /* In Quick mode, we cannot Recover... */
+ if ( slapMode & SLAP_TOOL_QUICK ) {
+ /* If we need to recover but we had no TXNs, just fail */
+ if ( do_recover && flags_ok ) {
+ Debug( LDAP_DEBUG_ANY,
+ "bdb_db_open: Database cannot be recovered. "
+ "Restore from backup!\n", 0, 0, 0);
+ return -1;
+ }
+ /* We need to recover, and we had TXN support before:
+ * Close this env, open a new one with recovery flags.
+ */
+ if ( do_recover ) {
+ bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
+ bdb->bi_dbenv = NULL;
+ rc = db_env_create( &bdb->bi_dbenv, 0 );
+ if( rc != 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "bdb_db_open: db_env_create failed: %s (%d)\n",
+ db_strerror(rc), rc, 0 );
+ return rc;
+ }
+ bdb->bi_dbenv->set_errpfx( bdb->bi_dbenv,
+ be->be_suffix[0].bv_val );
+ bdb->bi_dbenv->set_errcall( bdb->bi_dbenv, bdb_errcall );
+ rc = bdb->bi_dbenv->open( bdb->bi_dbenv, dbhome,
+ flags | DB_RECOVER, bdb->bi_dbenv_mode );
+ if( rc != 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "bdb_db_open: recovery failed: %s (%d)\n",
+ db_strerror(rc), rc, 0 );
+ return rc;
+ }
+ do_recover = 0;
+ }
+ /* Prev environment had TXN support, get rid of it */
+ if ( !flags_ok ) {
+ bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
+ bdb->bi_dbenv = NULL;
+ rc = db_env_create( &bdb->bi_dbenv, 0 );
+ if( rc != 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "bdb_db_open: db_env_create failed: %s (%d)\n",
+ db_strerror(rc), rc, 0 );
+ return rc;
+ }
+ bdb->bi_dbenv->remove( bdb->bi_dbenv, dbhome, 0 );
+ bdb->bi_dbenv = NULL;
+ }
+ /* Normal TXN mode */
+ } else {
+ /* If we need to recover but we had no TXNs, just fail */
+ if ( do_recover && !flags_ok ) {
+ Debug( LDAP_DEBUG_ANY,
+ "bdb_db_open: Database cannot be recovered. "
+ "Restore from backup!\n", 0, 0, 0);
+ return -1;
+ }
+ /* Prev environment had no TXN support, close it */
+ if ( !flags_ok ) {
+ bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
+ bdb->bi_dbenv = NULL;
+ do_recover = 1;
+ }
+ }
+
+ if ( flags_ok && !do_recover ) {
+ /* This environment is fine, don't reopen it */
+ open_env = 0;
+ } else {
+ /* Create a new env that can take the desired settings */
+ rc = db_env_create( &bdb->bi_dbenv, 0 );
+ if( rc != 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "bdb_db_open: db_env_create failed: %s (%d)\n",
+ db_strerror(rc), rc, 0 );
+ return rc;
+ }
+
+ bdb->bi_dbenv->set_errpfx( bdb->bi_dbenv, be->be_suffix[0].bv_val );
+ bdb->bi_dbenv->set_errcall( bdb->bi_dbenv, bdb_errcall );
+ bdb->bi_dbenv->set_lk_detect( bdb->bi_dbenv, bdb->bi_lock_detect );
+
+ /* One long-lived TXN per thread, two TXNs per write op */
+ bdb->bi_dbenv->set_tx_max( bdb->bi_dbenv, connection_pool_max * 3 );
+
+ if( bdb->bi_dbenv_xflags != 0 ) {
+ rc = bdb->bi_dbenv->set_flags( bdb->bi_dbenv,
+ bdb->bi_dbenv_xflags, 1);
+ if( rc != 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "bdb_db_open: dbenv_set_flags failed: %s (%d)\n",
+ db_strerror(rc), rc, 0 );
+ return rc;
+ }
+ }
+ }
+ }
+
+ /* If we need to recover but there was no existing environment,
+ * then we assume that someone has already manually recovered using
+ * db_recover. Just ignore it.
+ */
+ if ( do_recover && !got_env ) {
+ do_recover = 0;
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_db_open: Recovery needed but environment is missing - "
+ "assuming recovery was done manually...\n", 0, 0, 0 );
+ }
+
+ if ( open_env ) {
+ flags = DB_INIT_MPOOL | DB_THREAD | DB_CREATE;
+ if ( !( slapMode & SLAP_TOOL_QUICK ))
+ flags |= BDB_TXN_FLAGS;
+
+ if ( do_recover )
+ flags |= DB_RECOVER;
+
+ /* If a key was set, use shared memory for the BDB environment */
+ if ( bdb->bi_shm_key ) {
+ bdb->bi_dbenv->set_shm_key( bdb->bi_dbenv, bdb->bi_shm_key );
+ flags |= DB_SYSTEM_MEM;
+ }
+
+ rc = bdb->bi_dbenv->open( bdb->bi_dbenv, dbhome,
+ flags, bdb->bi_dbenv_mode );
+ if( rc != 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "bdb_db_open: dbenv_open failed: %s (%d)\n",
+ db_strerror(rc), rc, 0 );
+ return rc;
+ }
+ }
+
+ if ( do_alock_recover && alock_recover (&bdb->bi_alock_info) != 0 ) {
Debug( LDAP_DEBUG_ANY,
- "bdb_db_open: dbenv_open failed: %s (%d)\n",
- db_strerror(rc), rc, 0 );
- return rc;
+ "bdb_db_open: alock_recover failed\n",
+ 0, 0, 0 );
+ return -1;
+ }
+
+#ifdef SLAP_ZONE_ALLOC
+ if ( bdb->bi_cache.c_maxsize ) {
+ bdb->bi_cache.c_zctx = slap_zn_mem_create(
+ SLAP_ZONE_INITSIZE,
+ SLAP_ZONE_MAXSIZE,
+ SLAP_ZONE_DELTA,
+ SLAP_ZONE_SIZE);
+ }
+#endif
+
+ if ( bdb->bi_idl_cache_max_size ) {
+ bdb->bi_idl_tree = NULL;
+ bdb->bi_idl_cache_size = 0;
}
flags = DB_THREAD | bdb->bi_db_opflags;
return rc;
}
+#if 0
+ if( i == BDB_ID2ENTRY && ( slapMode & SLAP_TOOL_MODE )) {
+ db->bdi_db->mpf->set_priority( db->bdi_db->mpf,
+ DB_PRIORITY_VERY_LOW );
+ }
+#endif
+
flags &= ~(DB_CREATE | DB_RDONLY);
db->bdi_name = bdbi_databases[i].name;
bdb->bi_databases[i] = db;
db_strerror(rc), rc, 0 );
return rc;
}
-
-#if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 2
- /* Delete the environment if we were in quick mode. This
- * works around a bug in bdb4.2 that interferes with the
- * operation of db_stat and other tools after a slapadd -q
- * or slapindex -q has taken place.
- */
- if( slapMode & SLAP_TOOL_QUICK ) {
- rc = db_env_create( &bdb->bi_dbenv, 0 );
- if( rc != 0 ) {
- Debug( LDAP_DEBUG_ANY,
- "bdb_db_close: db_env_create failed: %s (%d)\n",
- db_strerror(rc), rc, 0 );
- return rc;
- }
- rc = bdb->bi_dbenv->remove(bdb->bi_dbenv, bdb->bi_dbenv_home,
- DB_FORCE);
- bdb->bi_dbenv = NULL;
- if( rc != 0 ) {
- Debug( LDAP_DEBUG_ANY,
- "bdb_db_close: dbenv_remove failed: %s (%d)\n",
- db_strerror(rc), rc, 0 );
- return rc;
- }
- }
-#endif
}
rc = alock_close( &bdb->bi_alock_info );
bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
}
send_ldap_result( op, rs );
- return 1;
+ return rs->sr_err;
}
#endif /* SLAP_ACL_HONOR_DISCLOSE */
if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) {
if ( rs->sr_nentries >= ((PagedResultsState *)op->o_pagedresults_state)->ps_size ) {
+#ifdef SLAP_ZONE_ALLOC
+ slap_zn_runlock(bdb->bi_cache.c_zctx, e);
+#endif
+ bdb_cache_return_entry_r( bdb->bi_dbenv,
+ &bdb->bi_cache, e, &lock );
+ e = NULL;
send_paged_response( op, rs, &lastid, tentries );
goto done;
}
isupdate = be_shadow_update( op );
for ( i = 0, a = op->oq_add.rs_e->e_attrs; a; a = a->a_next ) {
- if ( !isupdate && a->a_desc->ad_type->sat_no_user_mod ) {
+ if ( !isupdate && !get_manageDIT( op ) && a->a_desc->ad_type->sat_no_user_mod )
+ {
continue;
}
/* wait for all other ops to release the connection */
retry_lock:;
- switch ( ldap_pvt_thread_mutex_trylock( &li->conn_mutex ) ) {
- case LDAP_PVT_THREAD_EBUSY:
- default:
+ ldap_pvt_thread_mutex_lock( &li->conn_mutex );
+ if ( lc->lc_refcnt > 1 ) {
+ ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
ldap_pvt_thread_yield();
goto retry_lock;
-
- case 0:
- if ( lc->lc_refcnt > 1 ) {
- ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
- ldap_pvt_thread_yield();
- goto retry_lock;
- }
- break;
}
assert( lc->lc_refcnt == 1 );
if ( rc == LDAP_SUCCESS ) {
LDAPMessage *res = NULL;
int retries = 1;
- struct timeval tv = { 0, 0 };
+ struct timeval tv = { 0, 100000 };
retry:;
rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res );
*is_tls = 0;
}
-error_return:;
return rc;
}
#endif /* HAVE_TLS */
struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
int vers = op->o_protocol;
LDAP *ld = NULL;
+#ifdef HAVE_TLS
int is_tls = op->o_conn->c_is_tls;
+#endif /* HAVE_TLS */
assert( lcp != NULL );
}
(*lcp)->lc_ld = ld;
(*lcp)->lc_refcnt = 1;
+#ifdef HAVE_TLS
(*lcp)->lc_is_tls = is_tls;
+#endif /* HAVE_TLS */
error_return:;
if ( rs->sr_err != LDAP_SUCCESS ) {
lc_curr.lc_conn = op->o_conn;
} else {
- lc_curr.lc_conn = op->o_conn->c_is_tls ?
- LDAP_BACK_PRIV_CONN_TLS : LDAP_BACK_PRIV_CONN;
+#ifdef HAVE_TLS
+ if ( op->o_conn->c_is_tls ) {
+ lc_curr.lc_conn = LDAP_BACK_PRIV_CONN_TLS;
+ } else
+#endif /* HAVE_TLS */
+ {
+ lc_curr.lc_conn = LDAP_BACK_PRIV_CONN;
+ }
}
/* Internal searches are privileged and shared. So is root. */
/* FIXME: there seem to be concurrency issues */
if ( op->o_do_not_cache || be_isroot( op ) ) {
lc_curr.lc_local_ndn = op->o_bd->be_rootndn;
- lc_curr.lc_conn = op->o_conn->c_is_tls ?
- LDAP_BACK_PRIV_CONN_TLS : LDAP_BACK_PRIV_CONN;
+#ifdef HAVE_TLS
+ if ( op->o_conn->c_is_tls ) {
+ lc_curr.lc_conn = LDAP_BACK_PRIV_CONN_TLS;
+ } else
+#endif /* HAVE_TLS */
+ {
+ lc_curr.lc_conn = LDAP_BACK_PRIV_CONN;
+ }
lc_curr.lc_ispriv = 1;
} else {
}
}
+#ifdef HAVE_TLS
/* if start TLS failed but it was not mandatory,
* check if the non-TLS connection was already
* in cache; in case, destroy the newly created
goto done;
}
}
+#endif /* HAVE_TLS */
lc->lc_bound = 0;
* remote server response */
if ( ERR_OK( rs->sr_err ) ) {
int rc;
- struct timeval tv = { 0, 0 };
+ struct timeval tv = { 0, 100000 };
retry:;
/* if result parsing fails, note the failure reason */
ldap_memfree( text );
}
rs->sr_text = NULL;
- return( ERR_OK( rs->sr_err ) ? 0 : -1 );
+ return( ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
}
/* return true if bound, false if failed */
return rs->sr_err = LDAP_PROTOCOL_ERROR;
}
+ Statslog( LDAP_DEBUG_STATS, "%s WHOAMI\n",
+ op->o_log_prefix, 0, 0, 0, 0 );
+
rs->sr_err = backend_check_restrictions( op, rs,
(struct berval *)&slap_EXOP_WHOAMI );
if( rs->sr_err != LDAP_SUCCESS ) return rs->sr_err;
isupdate = be_shadow_update( op );
for ( i = 0, ml = op->oq_modify.rs_modlist; ml; ml = ml->sml_next ) {
- if ( !isupdate && ml->sml_desc->ad_type->sat_no_user_mod ) {
+ if ( !isupdate && !!get_manageDIT( op ) && ml->sml_desc->ad_type->sat_no_user_mod )
+ {
continue;
}
} else {
tv.tv_sec = 0;
+ tv.tv_usec = 100000;
}
if ( op->ors_attrs ) {
BER_BVZERO( &rs->sr_ref[ cnt ] );
}
+ if ( match.bv_val != NULL ) {
+ if ( match.bv_val[ 0 ] == '\0' ) {
+ LDAP_FREE( match.bv_val );
+ BER_BVZERO( &match );
+ } else {
+ match.bv_len = strlen( match.bv_val );
+ }
+ }
+
/* cleanup */
if ( references ) {
ldap_value_free( references );
}
/* no subschemaSubentry */
- if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry ) {
+ if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
+ || attr->a_desc == slap_schema.si_ad_entryDN )
+ {
/*
* We eat target's subschemaSubentry because
* to resolve to the appropriate backend;
* later, the local subschemaSubentry is
* added.
+ *
+ * We also eat entryDN because the frontend
+ * will reattach it without checking if already
+ * present...
*/
( void )ber_scanf( &ber, "x" /* [W] */ );
Entry *matched = NULL;
struct berval realbase = BER_BVNULL;
int manageDSAit = get_manageDSAit( op );
+#ifdef SLAP_ACL_HONOR_DISCLOSE
+ slap_mask_t mask;
+#endif
Debug(LDAP_DEBUG_TRACE, "=> ldbm_back_search\n", 0, 0, 0);
}
#ifdef SLAP_ACL_HONOR_DISCLOSE
- if ( ! access_allowed( op, e, slap_schema.si_ad_entry,
- NULL, ACL_DISCLOSE, NULL ) )
+ /* NOTE: __NEW__ "search" access is required
+ * on searchBase object */
+ if ( ! access_allowed_mask( op, e, slap_schema.si_ad_entry,
+ NULL, ACL_SEARCH, NULL, &mask ) )
{
- rs->sr_err = LDAP_NO_SUCH_OBJECT;
+ if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) {
+ rs->sr_err = LDAP_NO_SUCH_OBJECT;
+ } else {
+ rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
+ }
cache_return_entry_r( &li->li_cache, e );
ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
for ( i = 0, a = op->ora_e->e_attrs; a; a = a->a_next ) {
int j, is_oc = 0;
- if ( !isupdate && a->a_desc->ad_type->sat_no_user_mod ) {
+ if ( !isupdate && !get_manageDIT( op ) && a->a_desc->ad_type->sat_no_user_mod )
+ {
continue;
}
typedef struct metatarget_t {
char *mt_uri;
+ int mt_scope;
struct berval mt_psuffix; /* pretty suffix */
struct berval mt_nsuffix; /* normalized suffix */
extern int
meta_back_is_candidate(
struct berval *nsuffix,
+ int suffixscope,
struct berval *ndn,
int scope );
rs->sr_err = lerr;
candidates[ i ].sr_tag = META_NOT_CANDIDATE;
+ if ( META_BACK_ONERR_STOP( mi ) ) {
+ rc = rs->sr_err;
+ break;
+ }
+
} else {
rc = LDAP_SUCCESS;
}
op->o_ctrls, NULL, &msgid );
if ( rs->sr_err == LDAP_SUCCESS ) {
LDAPMessage *res;
- struct timeval tv;
+ struct timeval tv = { 0, 100000 };
int rc;
int nretries = mt->mt_nretries;
if ( nretries > 0 ) {
nretries--;
}
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
goto retry;
}
rs->sr_err = LDAP_BUSY;
NULL, NULL, &msgid );
if ( rc == LDAP_SUCCESS ) {
LDAPMessage *res;
- struct timeval tv;
+ struct timeval tv = { 0, 100000 };
/*
* handle response!!!
if ( nretries > 0 ) {
nretries--;
}
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
goto retry;
}
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
- int bound = 0, i;
+ int bound = 0,
+ i,
+ isroot = 0;
SlapReply *candidates = meta_back_candidates_get( op );
- ldap_pvt_thread_mutex_lock( &mc->mc_mutex );
+ if ( be_isroot( op ) ) {
+ isroot = 1;
+ }
Debug( LDAP_DEBUG_TRACE,
- "%s meta_back_dobind: conn=%ld\n",
- op->o_log_prefix, mc->mc_conn->c_connid, 0 );
+ "%s meta_back_dobind: conn=%ld%s\n",
+ op->o_log_prefix, mc->mc_conn->c_connid,
+ isroot ? " (isroot)" : "" );
+
+ ldap_pvt_thread_mutex_lock( &mc->mc_mutex );
/*
* all the targets are bound as pseudoroot
continue;
}
- rc = meta_back_single_dobind( op, rs, mc, i,
+ if ( isroot && !BER_BVISNULL( &mi->mi_targets[ i ].mt_pseudorootdn ) )
+ {
+ Operation op2 = *op;
+
+ op2.o_tag = LDAP_REQ_BIND;
+ op2.o_req_dn = mi->mi_targets[ i ].mt_pseudorootdn;
+ op2.o_req_ndn = mi->mi_targets[ i ].mt_pseudorootdn;
+ op2.orb_cred = mi->mi_targets[ i ].mt_pseudorootpw;
+ op2.orb_method = LDAP_AUTH_SIMPLE;
+
+ rc = meta_back_single_bind( &op2, rs, mc, i );
+
+ } else {
+ rc = meta_back_single_dobind( op, rs, mc, i,
LDAP_BACK_DONTSEND, mt->mt_nretries, 1 );
+ }
+
if ( rc != LDAP_SUCCESS ) {
rs->sr_err = slap_map_api2result( rs );
* so better clear the handle
*/
candidates[ i ].sr_tag = META_NOT_CANDIDATE;
+ if ( META_BACK_ONERR_STOP( mi ) ) {
+ bound = 0;
+ goto done;
+ }
continue;
} /* else */
#include "portable.h"
#include <stdio.h>
+#include "ac/string.h"
#include "slap.h"
#include "../back-ldap/back-ldap.h"
int
meta_back_is_candidate(
struct berval *nsuffix,
+ int suffixscope,
struct berval *ndn,
int scope )
{
if ( dnIsSuffix( ndn, nsuffix ) ) {
- return META_CANDIDATE;
+ switch ( suffixscope ) {
+ case LDAP_SCOPE_SUBTREE:
+ default:
+ return META_CANDIDATE;
+
+#ifdef LDAP_SCOPE_SUBORDINATE
+ case LDAP_SCOPE_SUBORDINATE:
+ if ( ndn->bv_len > nsuffix->bv_len ) {
+ return META_CANDIDATE;
+ }
+ break;
+#endif /* LDAP_SCOPE_SUBORDINATE */
+
+ /* nearly useless; not allowed by config */
+ case LDAP_SCOPE_ONELEVEL:
+ if ( ndn->bv_len > nsuffix->bv_len ) {
+ struct berval rdn = *ndn;
+
+ rdn.bv_len -= nsuffix->bv_len
+ + STRLENOF( "," );
+ if ( dnIsOneLevelRDN( &rdn ) ) {
+ return META_CANDIDATE;
+ }
+ }
+ break;
+
+ /* nearly useless; not allowed by config */
+ case LDAP_SCOPE_BASE:
+ if ( ndn->bv_len == nsuffix->bv_len ) {
+ return META_CANDIDATE;
+ }
+ break;
+ }
+
+ return META_NOT_CANDIDATE;
}
if ( scope == LDAP_SCOPE_SUBTREE && dnIsSuffix( nsuffix, ndn ) ) {
return META_NOT_CANDIDATE;
}
-#if 0
-/*
- * meta_back_is_candidate_unique
- *
- * checks whether a candidate is unique
- * Note: dn MUST be normalized
- */
-static int
-meta_back_is_candidate_unique(
- metainfo_t *mi,
- struct berval *ndn )
-{
- switch ( meta_back_select_unique_candidate( mi, ndn ) ) {
- case META_TARGET_MULTIPLE:
- case META_TARGET_NONE:
- return 0;
- }
-
- return 1;
-}
-#endif /* 0 */
-
/*
* meta_back_select_unique_candidate
*
int i, candidate = META_TARGET_NONE;
for ( i = 0; i < mi->mi_ntargets; ++i ) {
- if ( meta_back_is_candidate( &mi->mi_targets[ i ].mt_nsuffix, ndn, LDAP_SCOPE_BASE ) )
+ if ( meta_back_is_candidate( &mi->mi_targets[ i ].mt_nsuffix,
+ mi->mi_targets[ i ].mt_scope,
+ ndn, LDAP_SCOPE_BASE ) )
{
if ( candidate == META_TARGET_NONE ) {
candidate = i;
struct timeval tv = { 0 };
tv.tv_sec = 0;
- tv.tv_usec = 0;
+ tv.tv_usec = 100000; /* 0.1 s */
if ( msgid[ i ] == -1 ) {
continue;
/*
* copies and stores uri and suffix
*/
- dn.bv_val = ludp->lud_dn;
- dn.bv_len = strlen( ludp->lud_dn );
-
+ ber_str2bv( ludp->lud_dn, 0, 0, &dn );
rc = dnPrettyNormal( NULL, &dn, &mi->mi_targets[ i ].mt_psuffix,
&mi->mi_targets[ i ].mt_nsuffix, NULL );
if( rc != LDAP_SUCCESS ) {
ludp->lud_dn[ 0 ] = '\0';
+ switch ( ludp->lud_scope ) {
+ case LDAP_SCOPE_DEFAULT:
+ mi->mi_targets[ i ].mt_scope = LDAP_SCOPE_SUBTREE;
+ break;
+
+ case LDAP_SCOPE_SUBTREE:
+#ifdef LDAP_SCOPE_SUBORDINATE
+ case LDAP_SCOPE_SUBORDINATE:
+#endif /* LDAP_SCOPE_SUBORDINATE */
+ mi->mi_targets[ i ].mt_scope = ludp->lud_scope;
+ break;
+
+ default:
+ fprintf( stderr, "%s: line %d: "
+ "invalid scope for target '%s'\n",
+ fname, lineno, argv[ 1 ] );
+ return( 1 );
+ }
+
/* check all, to apply the scope check on the first one */
for ( tmpludp = ludp; tmpludp; tmpludp = tmpludp->lud_next ) {
if ( tmpludp->lud_dn != NULL && tmpludp->lud_dn[ 0 ] != '\0' ) {
return( 1 );
}
-
- if ( tmpludp->lud_scope == LDAP_SCOPE_BASE ) {
- tmpludp->lud_scope = LDAP_SCOPE_DEFAULT;
- }
}
mi->mi_targets[ i ].mt_uri = ldap_url_list2urls( ludp );
* a candidate, try using it (FIXME: YMMV) */
if ( mi->mi_defaulttarget != META_DEFAULT_TARGET_NONE
&& meta_back_is_candidate( &mi->mi_targets[ mi->mi_defaulttarget ].mt_nsuffix,
+ mi->mi_targets[ mi->mi_defaulttarget ].mt_scope,
ndn, op->o_tag == LDAP_REQ_SEARCH ? op->ors_scope : LDAP_SCOPE_BASE ) )
{
candidate = mi->mi_defaulttarget;
}
break;
}
+
+ } else {
+ rs->sr_err = LDAP_SUCCESS;
}
return candidate;
}
if ( rs->sr_err != LDAP_SUCCESS ) {
+ if ( new_conn ) {
+ meta_back_freeconn( op, mc );
+
+ } else {
+ meta_back_release_conn( op, mc );
+ }
+
if ( sendok & LDAP_BACK_SENDERR ) {
if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val;
rs->sr_text = NULL;
rs->sr_matched = NULL;
}
+
return NULL;
}
}
if ( newparent && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i )
{
+ if ( new_conn ) {
+ meta_back_freeconn( op, mc );
+
+ } else {
+ meta_back_release_conn( op, mc );
+ }
+
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
rs->sr_text = "cross-target rename not supported";
if ( sendok & LDAP_BACK_SENDERR ) {
send_ldap_result( op, rs );
rs->sr_text = NULL;
}
+
return NULL;
}
for ( i = 0; i < mi->mi_ntargets; i++ ) {
if ( i == cached
|| meta_back_is_candidate( &mi->mi_targets[ i ].mt_nsuffix,
+ mi->mi_targets[ i ].mt_scope,
&op->o_req_ndn, LDAP_SCOPE_SUBTREE ) )
{
for ( i = 0, ml = op->orm_modlist; ml; ml = ml->sml_next ) {
int j, is_oc = 0;
- if ( !isupdate && ml->sml_desc->ad_type->sat_no_user_mod ) {
+ if ( !isupdate && !get_manageDIT( op ) && ml->sml_desc->ad_type->sat_no_user_mod )
+ {
continue;
}
&op->o_req_ndn ) )
{
realbase = mi->mi_targets[ candidate ].mt_nsuffix;
+#ifdef LDAP_SCOPE_SUBORDINATE
+ if ( mi->mi_targets[ candidate ].mt_scope == LDAP_SCOPE_SUBORDINATE ) {
+ realscope = LDAP_SCOPE_SUBORDINATE;
+ }
+#endif /* LDAP_SCOPE_SUBORDINATE */
} else {
/*
realbase = mi->mi_targets[ candidate ].mt_nsuffix;
#ifdef LDAP_SCOPE_SUBORDINATE
if ( op->ors_scope == LDAP_SCOPE_SUBORDINATE ) {
- realscope = LDAP_SCOPE_SUBTREE;
+ if ( mi->mi_targets[ candidate ].mt_scope == LDAP_SCOPE_SUBORDINATE ) {
+ realscope = LDAP_SCOPE_SUBORDINATE;
+ } else {
+ realscope = LDAP_SCOPE_SUBTREE;
+ }
} else
#endif /* LDAP_SCOPE_SUBORDINATE */
{
#endif
if ( initial_candidates == 0 ) {
+ /* NOTE: here we are not sending any matchedDN;
+ * this is intended, because if the back-meta
+ * is serving this search request, but no valid
+ * candidate could be looked up, it means that
+ * there is a hole in the mapping of the targets
+ * and thus no knowledge of any remote superior
+ * is available */
+ Debug( LDAP_DEBUG_ANY, "%s meta_back_search: "
+ "base=\"%s\" scope=%d: "
+ "no candidate could be selected\n",
+ op->o_log_prefix, op->o_req_dn.bv_val,
+ op->ors_scope );
+
send_ldap_error( op, rs, LDAP_NO_SUCH_OBJECT, NULL );
- /* FIXME: find a way to look up the best match */
rc = LDAP_NO_SUCH_OBJECT;
goto finish;
*
* FIXME: only the last one gets caught!
*/
- if ( candidate_match > 0 && rs->sr_nentries > 0 ) {
+ savepriv = op->o_private;
+ op->o_private = (void *)mi->mi_ntargets;
+ if ( candidate_match > 0 ) {
+ struct berval pmatched = BER_BVNULL;
+
/* we use the first one */
for ( i = 0; i < mi->mi_ntargets; i++ ) {
if ( candidates[ i ].sr_tag == META_CANDIDATE
&& candidates[ i ].sr_matched )
{
- matched = (char *)candidates[ i ].sr_matched;
- candidates[ i ].sr_matched = NULL;
- break;
+ struct berval bv, pbv;
+ int rc;
+
+ ber_str2bv( candidates[ i ].sr_matched, 0, 0, &bv );
+ rc = dnPretty( NULL, &bv, &pbv, op->o_tmpmemctx );
+
+ if ( rc == LDAP_SUCCESS ) {
+
+ /* NOTE: if they all are superiors
+ * of the baseDN, the shorter is also
+ * superior of the longer... */
+ if ( pbv.bv_len > pmatched.bv_len ) {
+ if ( !BER_BVISNULL( &pmatched ) ) {
+ op->o_tmpfree( pmatched.bv_val, op->o_tmpmemctx );
+ }
+ pmatched = pbv;
+ op->o_private = (void *)i;
+
+ } else {
+ op->o_tmpfree( pbv.bv_val, op->o_tmpmemctx );
+ }
+ }
+
+ if ( candidates[ i ].sr_matched != NULL ) {
+ free( (char *)candidates[ i ].sr_matched );
+ candidates[ i ].sr_matched = NULL;
+ }
}
}
+
+ if ( !BER_BVISNULL( &pmatched ) ) {
+ matched = pmatched.bv_val;
+ }
+
+ } else if ( sres == LDAP_NO_SUCH_OBJECT ) {
+ matched = ch_strdup( op->o_bd->be_suffix[ 0 ].bv_val );
}
#if 0
rs->sr_err = sres;
rs->sr_matched = matched;
rs->sr_ref = ( sres == LDAP_REFERRAL ? rs->sr_v2ref : NULL );
- savepriv = op->o_private;
- op->o_private = (void *)mi->mi_ntargets;
send_ldap_result( op, rs );
op->o_private = savepriv;
rs->sr_matched = NULL;
finish:;
if ( matched ) {
- free( matched );
+ op->o_tmpfree( matched, op->o_tmpmemctx );
}
if ( rs->sr_v2ref ) {
meta_back_release_conn( op, mc );
- return rc;
+ return rs->sr_err;
}
static int
dc.ctx = "searchAttrDN";
while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
- int last = 0;
+ int last = 0;
+ slap_syntax_validate_func *validate;
+ slap_syntax_transform_func *pretty;
ldap_back_map( &mi->mi_targets[ target ].mt_rwmap.rwm_at,
&a, &mapped, BACKLDAP_REMAP );
}
/* no subschemaSubentry */
- if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry ) {
+ if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
+ || attr->a_desc == slap_schema.si_ad_entryDN )
+ {
/*
* We eat target's subschemaSubentry because
* to resolve to the appropriate backend;
* later, the local subschemaSubentry is
* added.
+ *
+ * We also eat entryDN because the frontend
+ * will reattach it without checking if already
+ * present...
*/
( void )ber_scanf( &ber, "x" /* [W] */ );
{
attr->a_vals = (struct berval *)&slap_dummy_bv;
- } else if ( attr->a_desc == slap_schema.si_ad_objectClass
+ } else {
+ for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last )
+ ;
+ }
+
+ validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
+ pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
+
+ if ( !validate && !pretty ) {
+ attr->a_nvals = NULL;
+ attr_free( attr );
+ goto next_attr;
+ }
+
+ if ( attr->a_desc == slap_schema.si_ad_objectClass
|| attr->a_desc == slap_schema.si_ad_structuralObjectClass )
{
- for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last );
-
for ( bv = attr->a_vals; !BER_BVISNULL( bv ); bv++ ) {
ldap_back_map( &mi->mi_targets[ target ].mt_rwmap.rwm_oc,
bv, &mapped, BACKLDAP_REMAP );
} else if ( attr->a_desc == slap_schema.si_ad_ref ) {
ldap_back_referral_result_rewrite( &dc, attr->a_vals );
+
+ } else {
+ int i;
+
+ for ( i = 0; i < last; i++ ) {
+ struct berval pval;
+ int rc;
+
+ if ( pretty ) {
+ rc = pretty( attr->a_desc->ad_type->sat_syntax,
+ &attr->a_vals[i], &pval, NULL );
+
+ } else {
+ rc = validate( attr->a_desc->ad_type->sat_syntax,
+ &attr->a_vals[i] );
+ }
+
+ if ( pretty ) {
+ LBER_FREE( attr->a_vals[i].bv_val );
+ attr->a_vals[i] = pval;
+ }
+ }
}
if ( last && attr->a_desc->ad_type->sat_equality &&
- attr->a_desc->ad_type->sat_equality->smr_normalize ) {
+ attr->a_desc->ad_type->sat_equality->smr_normalize )
+ {
int i;
attr->a_nvals = ch_malloc( ( last + 1 ) * sizeof( struct berval ) );
*attrp = attr;
attrp = &attr->a_next;
+next_attr:;
}
rs->sr_entry = &ent;
rs->sr_attrs = op->ors_attrs;
}
}
+ /* temporarily removed */
+#if 0
/* check should be generalized */
if( get_manageDIT(op) && !be_isroot(op)) {
rs->sr_text = "requires manager authorization";
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
}
+#endif
done:;
return rs->sr_err;
/* Let the overlays have a chance at this */
be_orig = op->o_bd;
op->o_bd = select_backend( &op->o_req_ndn, 0, 0 );
- if ( op->o_bd != frontendDB &&
+ if ( !be_match( op->o_bd, frontendDB ) &&
( SLAP_OPATTRS( rs->sr_attr_flags ) || rs->sr_attrs ) &&
op->o_bd != NULL && op->o_bd->be_operational != NULL )
{
return 1;
if ( readit ) {
+ void *thrctx = ldap_pvt_thread_pool_context();
+
op = (Operation *)opbuf;
- connection_fake_init( &conn, op, cfb );
+ connection_fake_init( &conn, op, thrctx );
filter.f_desc = slap_schema.si_ad_objectClass;
op->o_bd = &cfb->cb_db;
rc = op->o_bd->be_search( op, &rs );
- slap_sl_mem_destroy( NULL, op->o_tmpmemctx );
+ ldap_pvt_thread_pool_context_reset( thrctx );
}
cfb->cb_use_ldif = 1;
Operation *op;
slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
SlapReply rs = {REP_RESULT};
+ void *thrctx = NULL;
/* If we read the config from back-ldif, nothing to do here */
if ( cfb->cb_got_ldif )
return 0;
if ( cfb->cb_use_ldif ) {
+ thrctx = ldap_pvt_thread_pool_context();
op = (Operation *)opbuf;
- connection_fake_init( &conn, op, cfb );
+ connection_fake_init( &conn, op, thrctx );
op->o_dn = be->be_rootdn;
op->o_ndn = be->be_rootndn;
}
}
}
- if ( op )
- slap_sl_mem_destroy( NULL, op->o_tmpmemctx );
+ if ( thrctx )
+ ldap_pvt_thread_pool_context_reset( thrctx );
return 0;
}
return LDAP_PROTOCOL_ERROR;
}
+ Statslog( LDAP_DEBUG_STATS, "%s CANCEL msg=%d\n",
+ op->o_log_prefix, opid, 0, 0, 0 );
+
ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
LDAP_STAILQ_FOREACH( o, &op->o_conn->c_pending_ops, o_next ) {
if ( o->o_msgid == opid ) {
static ldap_pvt_thread_mutex_t conn_nextid_mutex;
static unsigned long conn_nextid = 0;
+static const char conn_lost_str[] = "connection lost";
+
/* structure state (protected by connections_mutex) */
#define SLAP_C_UNINITIALIZED 0x00 /* MUST BE ZERO (0) */
#define SLAP_C_UNUSED 0x01
ldap_pvt_thread_mutex_lock( &connections[i].c_mutex );
/* connections_mutex and c_mutex are locked */
- connection_closing( &connections[i] );
+ connection_closing( &connections[i], "slapd shutdown" );
connection_close( &connections[i] );
ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex );
if( difftime( c->c_activitytime+global_idletimeout, now) < 0 ) {
/* close it */
- connection_closing( c );
+ connection_closing( c, "idletimeout" );
connection_close( c );
i++;
}
if ( flags == CONN_IS_CLIENT ) {
c->c_conn_state = SLAP_C_CLIENT;
c->c_struct_state = SLAP_C_USED;
+ c->c_close_reason = "?"; /* should never be needed */
ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_FD, &s );
ldap_pvt_thread_mutex_unlock( &c->c_mutex );
ldap_pvt_thread_mutex_unlock( &connections_mutex );
c->c_conn_state = SLAP_C_INACTIVE;
c->c_struct_state = SLAP_C_USED;
+ c->c_close_reason = "?"; /* should never be needed */
c->c_ssf = c->c_transport_ssf = ssf;
c->c_tls_ssf = 0;
/* note: connections_mutex should be locked by caller */
ber_socket_t sd;
unsigned long connid;
+ const char *close_reason;
assert( connections != NULL );
assert( c != NULL );
/* only for stats (print -1 as "%lu" may give unexpected results ;) */
connid = c->c_connid;
+ close_reason = c->c_close_reason;
backend_connection_destroy(c);
if ( sd != AC_SOCKET_INVALID ) {
slapd_remove( sd, 1, 0 );
- Statslog( LDAP_DEBUG_STATS,
- "conn=%lu fd=%ld closed\n",
- connid, (long) sd, 0, 0, 0 );
+ Statslog( LDAP_DEBUG_STATS, (close_reason
+ ? "conn=%lu fd=%ld closed (%s)\n"
+ : "conn=%lu fd=%ld closed\n"),
+ connid, (long) sd, close_reason, 0, 0 );
}
ber_sockbuf_free( c->c_sb );
c->c_conn_state = SLAP_C_INVALID;
c->c_struct_state = SLAP_C_UNUSED;
+ c->c_close_reason = "?"; /* should never be needed */
#ifdef LDAP_SLAPI
/* call destructors, then constructors; avoids unnecessary allocation */
}
}
-void connection_closing( Connection *c )
+void connection_closing( Connection *c, const char *why )
{
assert( connections != NULL );
assert( c != NULL );
c->c_connid, sd, 0 );
/* update state to closing */
c->c_conn_state = SLAP_C_CLOSING;
+ c->c_close_reason = why;
/* don't listen on this port anymore */
slapd_clr_read( sd, 1 );
ldap_pvt_thread_yield();
ldap_pvt_thread_mutex_lock( &c->c_mutex );
}
+ } else if( why == NULL && c->c_close_reason == conn_lost_str ) {
+ /* Client closed connection after doing Unbind. */
+ c->c_close_reason = NULL;
}
}
case LBER_ERROR:
case LDAP_REQ_UNBIND:
/* c_mutex is locked */
- connection_closing( conn );
+ connection_closing(
+ conn, tag == LDAP_REQ_UNBIND ? NULL : "operations error" );
break;
case LDAP_REQ_BIND:
c->c_listener = NULL;
c->c_conn_state = SLAP_C_INVALID;
c->c_struct_state = SLAP_C_UNUSED;
+ c->c_close_reason = "?"; /* should never be needed */
connection_return( c );
slapd_remove( s, 0, 1 );
}
s, rc, c->c_connid );
c->c_needs_tls_accept = 0;
/* connections_mutex and c_mutex are locked */
- connection_closing( c );
+ connection_closing( c, "TLS negotiation failure" );
#if 0
/* Drain input before close, to allow SSL error codes
"unable to get TLS client DN, error=%d id=%lu\n",
s, rc, c->c_connid );
}
+ Statslog( LDAP_DEBUG_STATS,
+ "conn=%lu TLS established tls_ssf=%u ssf=%u\n",
+ c->c_connid, c->c_tls_ssf, c->c_ssf, 0, 0 );
slap_sasl_external( c, c->c_tls_ssf, &authid );
if ( authid.bv_val ) free( authid.bv_val );
}
"error=%d id=%lu, closing\n",
s, rc, c->c_connid );
/* connections_mutex and c_mutex are locked */
- connection_closing( c );
+ connection_closing( c, "SASL layer install failure" );
connection_close( c );
connection_return( c );
ldap_pvt_thread_mutex_unlock( &connections_mutex );
"connection_read(%d): input error=%d id=%lu, closing.\n",
s, rc, c->c_connid );
/* connections_mutex and c_mutex are locked */
- connection_closing( c );
+ connection_closing( c, conn_lost_str );
connection_close( c );
connection_return( c );
ldap_pvt_thread_mutex_unlock( &connections_mutex );
static SLAP_CTRL_PARSE_FN parseManageDIT;
#endif
static SLAP_CTRL_PARSE_FN parseManageDSAit;
-#ifdef LDAP_CONTROL_MODIFY_INCREMENT
-static SLAP_CTRL_PARSE_FN parseModifyIncrement;
-#endif
static SLAP_CTRL_PARSE_FN parseNoOp;
static SLAP_CTRL_PARSE_FN parsePagedResults;
#ifdef LDAP_DEVEL
static struct slap_control control_defs[] = {
{ LDAP_CONTROL_ASSERT,
(int)offsetof(struct slap_control_ids, sc_assert),
- SLAP_CTRL_HIDE|SLAP_CTRL_ACCESS, NULL,
+ SLAP_CTRL_ACCESS, NULL,
parseAssert, LDAP_SLIST_ENTRY_INITIALIZER(next) },
{ LDAP_CONTROL_PRE_READ,
(int)offsetof(struct slap_control_ids, sc_preRead),
- SLAP_CTRL_HIDE|SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME, NULL,
+ SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME, NULL,
parsePreRead, LDAP_SLIST_ENTRY_INITIALIZER(next) },
{ LDAP_CONTROL_POST_READ,
(int)offsetof(struct slap_control_ids, sc_postRead),
- SLAP_CTRL_HIDE|SLAP_CTRL_ADD|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME, NULL,
+ SLAP_CTRL_ADD|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME, NULL,
parsePostRead, LDAP_SLIST_ENTRY_INITIALIZER(next) },
{ LDAP_CONTROL_VALUESRETURNFILTER,
(int)offsetof(struct slap_control_ids, sc_valuesReturnFilter),
(int)offsetof(struct slap_control_ids, sc_noOp),
SLAP_CTRL_HIDE|SLAP_CTRL_ACCESS, NULL,
parseNoOp, LDAP_SLIST_ENTRY_INITIALIZER(next) },
-#ifdef LDAP_CONTROL_MODIFY_INCREMENT
- { LDAP_CONTROL_MODIFY_INCREMENT,
- (int)offsetof(struct slap_control_ids, sc_modifyIncrement),
- SLAP_CTRL_HIDE|SLAP_CTRL_MODIFY, NULL,
- parseModifyIncrement, LDAP_SLIST_ENTRY_INITIALIZER(next) },
-#endif
#ifdef LDAP_DEVEL
{ LDAP_CONTROL_MANAGEDIT,
(int)offsetof(struct slap_control_ids, sc_manageDIT),
return rs->sr_err;
}
-#ifdef LDAP_CONTROL_MODIFY_INCREMENT
-static int parseModifyIncrement (
- Operation *op,
- SlapReply *rs,
- LDAPControl *ctrl )
-{
-#if 0
- if ( op->o_modifyIncrement != SLAP_CONTROL_NONE ) {
- rs->sr_text = "modifyIncrement control specified multiple times";
- return LDAP_PROTOCOL_ERROR;
- }
-#endif
-
- if ( ctrl->ldctl_value.bv_len ) {
- rs->sr_text = "modifyIncrement control value not empty";
- return LDAP_PROTOCOL_ERROR;
- }
-
-#if 0
- op->o_modifyIncrement = ctrl->ldctl_iscritical
- ? SLAP_CONTROL_CRITICAL
- : SLAP_CONTROL_NONCRITICAL;
-#endif
-
- return LDAP_SUCCESS;
-}
-#endif
-
#ifdef LDAP_DEVEL
static int parseManageDIT (
Operation *op,
asserted->bv_val,
asserted->bv_len );
} else {
- return 1;
+ match = 1;
}
}
asserted->bv_val,
asserted->bv_len );
} else {
- return 1;
+ match = 1;
}
}
match = dnIsOneLevelRDN( &rdn ) ? 0 : 1;
}
} else {
- return 1;
+ match = 1;
}
}
/* check for controls inappropriate for all extended operations */
if( get_manageDSAit( op ) == SLAP_CONTROL_CRITICAL ) {
+ Statslog( LDAP_DEBUG_STATS, "%s EXT oid=%s\n",
+ op->o_log_prefix, op->ore_reqoid.bv_val, 0, 0, 0 );
send_ldap_error( op, rs,
LDAP_UNAVAILABLE_CRITICAL_EXTENSION,
"manageDSAit control inappropriate" );
if( !(ext = find_extop(supp_ext_list, &op->ore_reqoid )))
{
+ Statslog( LDAP_DEBUG_STATS, "%s EXT oid=%s\n",
+ op->o_log_prefix, op->ore_reqoid.bv_val, 0, 0, 0 );
Debug( LDAP_DEBUG_ANY, "do_extended: unsupported operation \"%s\"\n",
op->ore_reqoid.bv_val, 0 ,0 );
send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR,
return LDAP_PROTOCOL_ERROR;
}
+ Statslog( LDAP_DEBUG_STATS, "%s WHOAMI\n",
+ op->o_log_prefix, 0, 0, 0, 0 );
+
op->o_bd = op->o_conn->c_authz_backend;
if( backend_check_restrictions( op, rs,
(struct berval *)&slap_EXOP_WHOAMI ) != LDAP_SUCCESS ) {
slap_debug |= level;
} else {
- slap_debug |= atoi( optarg );
+ int level;
+ char *next = NULL;
+
+ level = strtol( optarg, &next, 0 );
+ if ( next == NULL || next[ 0 ] != '\0' ) {
+ fprintf( stderr,
+ "unrecognized log level "
+ "\"%s\"\n", optarg );
+ goto destroy;
+ }
+ slap_debug |= level;
}
#else
if ( atoi( optarg ) != 0 )
goto cleanup;
}
- if( mod->sml_values[1].bv_val ) {
+ if ( !BER_BVISNULL( &mod->sml_values[ 1 ] ) ) {
Debug( LDAP_DEBUG_ANY, "do_modify: modify/increment "
"operation (%ld) requires single value\n",
(long) mop, 0, 0 );
goto cleanup;
}
- rs->sr_err = slap_mods_check( modlist, &rs->sr_text,
- textbuf, textlen, NULL );
+ rs->sr_err = slap_mods_check( modlist,
+ &rs->sr_text, textbuf, textlen, NULL );
if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
if ( tmp->sml_values == NULL ) {
Debug( LDAP_DEBUG_ARGS, "%s\n",
"\t\tno values", NULL, NULL );
- } else if ( tmp->sml_values[0].bv_val == NULL ) {
+ } else if ( BER_BVISNULL( &tmp->sml_values[ 0 ] ) ) {
Debug( LDAP_DEBUG_ARGS, "%s\n",
"\t\tzero values", NULL, NULL );
- } else if ( tmp->sml_values[1].bv_val == NULL ) {
+ } else if ( BER_BVISNULL( &tmp->sml_values[ 1 ] ) ) {
Debug( LDAP_DEBUG_ARGS, "%s, length %ld\n",
"\t\tone value", (long) tmp->sml_values[0].bv_len, NULL );
} else {
for ( ; ml != NULL; ml = ml->sml_next ) {
if ( !is_at_no_user_mod( ml->sml_desc->ad_type ) ) continue;
- if( get_manageDIT( op )) {
+ if ( get_manageDIT( op ) ) {
if ( ml->sml_desc->ad_type->sat_flags & SLAP_AT_MANAGEABLE ) {
+ ml->sml_flags |= SLAP_MOD_MANAGING;
continue;
}
assert( modtail != NULL );
assert( *modtail == NULL );
- if ( SLAP_LASTMOD( op->o_bd )) {
+ if ( SLAP_LASTMOD( op->o_bd ) ) {
time_t now = slap_get_time();
slap_get_csn( op, csnbuf, sizeof(csnbuf), &csn, manage_ctxcsn );
slap_timestamp( &now, ×tamp );
- if( op->o_dn.bv_len == 0 ) {
+ if ( BER_BVISEMPTY( &op->o_dn ) ) {
BER_BVSTR( &name, SLAPD_ANONYMOUS );
nname = name;
} else {
}
}
- if( op->o_tag == LDAP_REQ_ADD ) {
+ if ( op->o_tag == LDAP_REQ_ADD ) {
struct berval tmpval;
- {
+ mod = *modtail;
+ if ( get_manageDIT( op ) ) {
+ for ( mod = mods; mod != *modtail; mod = mod->sml_next ) {
+ if ( mod->sml_desc == slap_schema.si_ad_structuralObjectClass ) {
+ break;
+ }
+ }
+
+ }
+
+ if ( mod == *modtail ) {
int rc = mods_structural_class( mods, &tmpval,
text, textbuf, textlen );
if( rc != LDAP_SUCCESS ) return rc;
mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
mod->sml_op = mop;
mod->sml_flags = SLAP_MOD_INTERNAL;
- mod->sml_type.bv_val = NULL;
+ BER_BVZERO( &mod->sml_type );
mod->sml_desc = slap_schema.si_ad_structuralObjectClass;
mod->sml_values =
(BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
ber_dupbv( &mod->sml_values[0], &tmpval );
- mod->sml_values[1].bv_len = 0;
- mod->sml_values[1].bv_val = NULL;
- assert( mod->sml_values[0].bv_val != NULL );
+ BER_BVZERO( &mod->sml_values[1] );
+ assert( !BER_BVISNULL( &mod->sml_values[0] ) );
mod->sml_nvalues =
(BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
ber_dupbv( &mod->sml_nvalues[0], &tmpval );
- mod->sml_nvalues[1].bv_len = 0;
- mod->sml_nvalues[1].bv_val = NULL;
- assert( mod->sml_nvalues[0].bv_val != NULL );
+ BER_BVZERO( &mod->sml_nvalues[1] );
+ assert( !BER_BVISNULL( &mod->sml_nvalues[0] ) );
*modtail = mod;
modtail = &mod->sml_next;
}
- if ( SLAP_LASTMOD( op->o_bd )) {
- char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
+ if ( SLAP_LASTMOD( op->o_bd ) ) {
+ mod = *modtail;
+ if ( get_manageDIT( op ) ) {
+ for ( mod = mods; mod != *modtail; mod = mod->sml_next ) {
+ if ( mod->sml_desc == slap_schema.si_ad_entryUUID ) {
+ break;
+ }
+ }
+ }
- tmpval.bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
- tmpval.bv_val = uuidbuf;
-
- mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
- mod->sml_op = mop;
- mod->sml_flags = SLAP_MOD_INTERNAL;
- mod->sml_type.bv_val = NULL;
- mod->sml_desc = slap_schema.si_ad_entryUUID;
- mod->sml_values =
- (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
- ber_dupbv( &mod->sml_values[0], &tmpval );
- mod->sml_values[1].bv_len = 0;
- mod->sml_values[1].bv_val = NULL;
- assert( mod->sml_values[0].bv_val != NULL );
- mod->sml_nvalues =
- (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
- (*mod->sml_desc->ad_type->sat_equality->smr_normalize)(
- SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
- mod->sml_desc->ad_type->sat_syntax,
- mod->sml_desc->ad_type->sat_equality,
- mod->sml_values, mod->sml_nvalues, NULL );
- mod->sml_nvalues[1].bv_len = 0;
- mod->sml_nvalues[1].bv_val = NULL;
- *modtail = mod;
- modtail = &mod->sml_next;
+ if ( mod == *modtail ) {
+ char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
+
+ tmpval.bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
+ tmpval.bv_val = uuidbuf;
+
+ mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
+ mod->sml_op = mop;
+ mod->sml_flags = SLAP_MOD_INTERNAL;
+ BER_BVZERO( &mod->sml_type );
+ mod->sml_desc = slap_schema.si_ad_entryUUID;
+ mod->sml_values =
+ (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+ ber_dupbv( &mod->sml_values[0], &tmpval );
+ BER_BVZERO( &mod->sml_values[1] );
+ assert( !BER_BVISNULL( &mod->sml_values[0] ) );
+ mod->sml_nvalues =
+ (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+ (*mod->sml_desc->ad_type->sat_equality->smr_normalize)(
+ SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
+ mod->sml_desc->ad_type->sat_syntax,
+ mod->sml_desc->ad_type->sat_equality,
+ mod->sml_values, mod->sml_nvalues, NULL );
+ BER_BVZERO( &mod->sml_nvalues[1] );
+ *modtail = mod;
+ modtail = &mod->sml_next;
+ }
+
+ mod = *modtail;
+ if ( get_manageDIT( op ) ) {
+ for ( mod = mods; mod != *modtail; mod = mod->sml_next ) {
+ if ( mod->sml_desc == slap_schema.si_ad_creatorsName ) {
+ break;
+ }
+ }
+ }
+
+ if ( mod == *modtail ) {
+ mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
+ mod->sml_op = mop;
+ mod->sml_flags = SLAP_MOD_INTERNAL;
+ BER_BVZERO( &mod->sml_type );
+ mod->sml_desc = slap_schema.si_ad_creatorsName;
+ mod->sml_values =
+ (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+ ber_dupbv( &mod->sml_values[0], &name );
+ BER_BVZERO( &mod->sml_values[1] );
+ assert( !BER_BVISNULL( &mod->sml_values[0] ) );
+ mod->sml_nvalues =
+ (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+ ber_dupbv( &mod->sml_nvalues[0], &nname );
+ BER_BVZERO( &mod->sml_nvalues[1] );
+ assert( !BER_BVISNULL( &mod->sml_nvalues[0] ) );
+ *modtail = mod;
+ modtail = &mod->sml_next;
+ }
+
+ mod = *modtail;
+ if ( get_manageDIT( op ) ) {
+ for ( mod = mods; mod != *modtail; mod = mod->sml_next ) {
+ if ( mod->sml_desc == slap_schema.si_ad_createTimestamp ) {
+ break;
+ }
+ }
+ }
+
+ if ( mod == *modtail ) {
+ mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
+ mod->sml_op = mop;
+ mod->sml_flags = SLAP_MOD_INTERNAL;
+ BER_BVZERO( &mod->sml_type );
+ mod->sml_desc = slap_schema.si_ad_createTimestamp;
+ mod->sml_values =
+ (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+ ber_dupbv( &mod->sml_values[0], ×tamp );
+ BER_BVZERO( &mod->sml_values[1] );
+ assert( !BER_BVISNULL( &mod->sml_values[0] ) );
+ mod->sml_nvalues = NULL;
+ *modtail = mod;
+ modtail = &mod->sml_next;
+ }
+ }
+ }
+
+ if ( SLAP_LASTMOD( op->o_bd ) ) {
+ mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
+ mod->sml_op = mop;
+ mod->sml_flags = SLAP_MOD_INTERNAL;
+ BER_BVZERO( &mod->sml_type );
+ mod->sml_desc = slap_schema.si_ad_entryCSN;
+ mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+ ber_dupbv( &mod->sml_values[0], &csn );
+ BER_BVZERO( &mod->sml_values[1] );
+ assert( !BER_BVISNULL( &mod->sml_values[0] ) );
+ mod->sml_nvalues = NULL;
+ *modtail = mod;
+ modtail = &mod->sml_next;
+
+ mod = *modtail;
+ if ( get_manageDIT( op ) ) {
+ for ( mod = mods; mod != *modtail; mod = mod->sml_next ) {
+ if ( mod->sml_desc == slap_schema.si_ad_modifiersName ) {
+ break;
+ }
+ }
+ }
+ if ( mod == *modtail ) {
mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
mod->sml_op = mop;
mod->sml_flags = SLAP_MOD_INTERNAL;
- mod->sml_type.bv_val = NULL;
- mod->sml_desc = slap_schema.si_ad_creatorsName;
- mod->sml_values =
- (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+ BER_BVZERO( &mod->sml_type );
+ mod->sml_desc = slap_schema.si_ad_modifiersName;
+ mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
ber_dupbv( &mod->sml_values[0], &name );
- mod->sml_values[1].bv_len = 0;
- mod->sml_values[1].bv_val = NULL;
- assert( mod->sml_values[0].bv_val != NULL );
+ BER_BVZERO( &mod->sml_values[1] );
+ assert( !BER_BVISNULL( &mod->sml_values[0] ) );
mod->sml_nvalues =
(BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
ber_dupbv( &mod->sml_nvalues[0], &nname );
- mod->sml_nvalues[1].bv_len = 0;
- mod->sml_nvalues[1].bv_val = NULL;
- assert( mod->sml_nvalues[0].bv_val != NULL );
+ BER_BVZERO( &mod->sml_nvalues[1] );
+ assert( !BER_BVISNULL( &mod->sml_nvalues[0] ) );
*modtail = mod;
modtail = &mod->sml_next;
+ }
+ mod = *modtail;
+ if ( get_manageDIT( op ) ) {
+ for ( mod = mods; mod != *modtail; mod = mod->sml_next ) {
+ if ( mod->sml_desc == slap_schema.si_ad_modifyTimestamp ) {
+ break;
+ }
+ }
+ }
+
+ if ( mod == *modtail ) {
mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
mod->sml_op = mop;
mod->sml_flags = SLAP_MOD_INTERNAL;
- mod->sml_type.bv_val = NULL;
- mod->sml_desc = slap_schema.si_ad_createTimestamp;
- mod->sml_values =
- (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+ BER_BVZERO( &mod->sml_type );
+ mod->sml_desc = slap_schema.si_ad_modifyTimestamp;
+ mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
ber_dupbv( &mod->sml_values[0], ×tamp );
- mod->sml_values[1].bv_len = 0;
- mod->sml_values[1].bv_val = NULL;
- assert( mod->sml_values[0].bv_val != NULL );
+ BER_BVZERO( &mod->sml_values[1] );
+ assert( !BER_BVISNULL( &mod->sml_values[0] ) );
mod->sml_nvalues = NULL;
*modtail = mod;
modtail = &mod->sml_next;
}
}
- if ( SLAP_LASTMOD( op->o_bd )) {
- mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
- mod->sml_op = mop;
- mod->sml_flags = SLAP_MOD_INTERNAL;
- mod->sml_type.bv_val = NULL;
- mod->sml_desc = slap_schema.si_ad_entryCSN;
- mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
- ber_dupbv( &mod->sml_values[0], &csn );
- mod->sml_values[1].bv_len = 0;
- mod->sml_values[1].bv_val = NULL;
- assert( mod->sml_values[0].bv_val != NULL );
- mod->sml_nvalues = NULL;
- *modtail = mod;
- modtail = &mod->sml_next;
-
- mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
- mod->sml_op = mop;
- mod->sml_flags = SLAP_MOD_INTERNAL;
- mod->sml_type.bv_val = NULL;
- mod->sml_desc = slap_schema.si_ad_modifiersName;
- mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
- ber_dupbv( &mod->sml_values[0], &name );
- mod->sml_values[1].bv_len = 0;
- mod->sml_values[1].bv_val = NULL;
- assert( mod->sml_values[0].bv_val != NULL );
- mod->sml_nvalues =
- (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
- ber_dupbv( &mod->sml_nvalues[0], &nname );
- mod->sml_nvalues[1].bv_len = 0;
- mod->sml_nvalues[1].bv_val = NULL;
- assert( mod->sml_nvalues[0].bv_val != NULL );
- *modtail = mod;
- modtail = &mod->sml_next;
-
- mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
- mod->sml_op = mop;
- mod->sml_flags = SLAP_MOD_INTERNAL;
- mod->sml_type.bv_val = NULL;
- mod->sml_desc = slap_schema.si_ad_modifyTimestamp;
- mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
- ber_dupbv( &mod->sml_values[0], ×tamp );
- mod->sml_values[1].bv_len = 0;
- mod->sml_values[1].bv_val = NULL;
- assert( mod->sml_values[0].bv_val != NULL );
- mod->sml_nvalues = NULL;
- *modtail = mod;
- modtail = &mod->sml_next;
- }
-
*modtail = NULL;
return LDAP_SUCCESS;
}
int is_entry_objectclass(
Entry* e,
ObjectClass *oc,
- int set_flags )
+ unsigned flags )
{
/*
* set_flags should only be true if oc is one of operational
Attribute *attr;
struct berval *bv;
- AttributeDescription *objectClass = slap_schema.si_ad_objectClass;
- assert(!( e == NULL || oc == NULL ));
+ assert( !( e == NULL || oc == NULL ) );
+ assert( ( flags & SLAP_OCF_MASK ) != SLAP_OCF_MASK );
if( e == NULL || oc == NULL ) {
return 0;
}
- if( set_flags && ( e->e_ocflags & SLAP_OC__END )) {
+ if( flags == SLAP_OCF_SET_FLAGS && ( e->e_ocflags & SLAP_OC__END ) )
+ {
/* flags are set, use them */
return (e->e_ocflags & oc->soc_flags & SLAP_OC__MASK) != 0;
}
/*
* find objectClass attribute
*/
- attr = attr_find(e->e_attrs, objectClass);
+ attr = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
if( attr == NULL ) {
/* no objectClass attribute */
Debug( LDAP_DEBUG_ANY, "is_entry_objectclass(\"%s\", \"%s\") "
for( bv=attr->a_vals; bv->bv_val; bv++ ) {
ObjectClass *objectClass = oc_bvfind( bv );
- if ( !set_flags && objectClass == oc ) {
- return 1;
+ if ( objectClass == NULL ) {
+ /* FIXME: is this acceptable? */
+ continue;
}
-
- if ( objectClass != NULL ) {
- e->e_ocflags |= objectClass->soc_flags;
+
+ if ( !( flags & SLAP_OCF_SET_FLAGS ) ) {
+ if ( objectClass == oc ) {
+ return 1;
+ }
+
+ if ( ( flags & SLAP_OCF_CHECK_SUP )
+ && is_object_subclass( oc, objectClass ) )
+ {
+ return 1;
+ }
}
+
+ e->e_ocflags |= objectClass->soc_flags;
}
/* mark flags as set */
e->e_ocflags |= SLAP_OC__END;
- return (e->e_ocflags & oc->soc_flags & SLAP_OC__MASK) != 0;
+ return ( e->e_ocflags & oc->soc_flags & SLAP_OC__MASK ) != 0;
}
AC_MEMCPY( oc->soc_cname.bv_val, ocname->bv_val, ocname->bv_len );
LDAP_STAILQ_NEXT( oc, soc_next ) = NULL;
+ ldap_pvt_thread_mutex_lock( &oc_undef_mutex );
LDAP_STAILQ_INSERT_HEAD( &oc_undef_list, oc, soc_next );
+ ldap_pvt_thread_mutex_unlock( &oc_undef_mutex );
return oc;
}
rwm.c rwmconf.c rwmdn.c rwmmap.c \
syncprov.c \
translucent.c \
- unique.c
+ unique.c \
+ valsort.c
OBJS = overlays.o \
@SLAPD_STATIC_OVERLAYS@
+# Add here the objs that are needed by overlays, but do not make it
+# into SLAPD_STATIC_OVERLAYS...
+OBJDEP=rwm.o rwmconf.o rwmdn.o rwmmap.o
+
LTONLY_MOD = $(LTONLY_mod)
LDAP_INCDIR= ../../../include
LDAP_LIBDIR= ../../../libraries
unique.la : unique.lo
$(LTLINK_MOD) -module -o $@ unique.lo version.lo $(LINK_LIBS)
+valsort.la : valsort.lo
+ $(LTLINK_MOD) -module -o $@ valsort.lo version.lo $(LINK_LIBS)
+
install-local: $(PROGRAMS)
@if test -n "$?" ; then \
$(MKDIR) $(DESTDIR)$(moduledir); \
# Must fixup depends for non-libtool objects
depend-local:
@if test -n "$(OBJS)"; then \
- OBJ2=`echo $(OBJS) | $(SED) -e 's/\.o//g'`; \
+ OBJ2=`echo $(OBJS) $(OBJDEP) | $(SED) -e 's/\.o//g'`; \
SCR=''; for i in $$OBJ2; do SCR="$$SCR -e s/^$$i.lo:/$$i.o:/"; done; \
mv Makefile Makefile.bak; $(SED) $$SCR Makefile.bak > Makefile && \
$(RM) Makefile.bak; fi
#if SLAPD_OVER_UNIQUE == SLAPD_MOD_STATIC
extern int unique_init();
#endif
+#if SLAPD_OVER_VALSORT == SLAPD_MOD_STATIC
+extern int valsort_init();
+#endif
static struct {
char *name;
#endif
#if SLAPD_OVER_UNIQUE == SLAPD_MOD_STATIC
{ "Attribute Uniqueness", unique_init },
+#endif
+#if SLAPD_OVER_VALSORT == SLAPD_MOD_STATIC
+ { "Value Sorting", valsort_init },
#endif
{ NULL, NULL }
};
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2004-2005 The OpenLDAP Foundation.
- * Portions Copyright 2004 Howard Chu, Symas Corporation.
+ * Portions Copyright 2004-2005 Howard Chu, Symas Corporation.
* Portions Copyright 2004 Hewlett-Packard Company.
* All rights reserved.
*
#include "portable.h"
/* This file implements "Password Policy for LDAP Directories",
- * based on draft behera-ldap-password-policy-08
+ * based on draft behera-ldap-password-policy-09
*/
#ifdef SLAPD_OVER_PPOLICY
"EQUALITY generalizedTimeMatch "
"ORDERING generalizedTimeOrderingMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
- "SINGLE-VALUE USAGE directoryOperation NO-USER-MODIFICATION )",
+ "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
&ad_pwdChangedTime },
{ "( 1.3.6.1.4.1.42.2.27.8.1.17 "
"NAME ( 'pwdAccountLockedTime' ) "
"EQUALITY generalizedTimeMatch "
"ORDERING generalizedTimeOrderingMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
- "SINGLE-VALUE USAGE directoryOperation )",
+ "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
&ad_pwdAccountLockedTime },
{ "( 1.3.6.1.4.1.42.2.27.8.1.19 "
"NAME ( 'pwdFailureTime' ) "
"EQUALITY generalizedTimeMatch "
"ORDERING generalizedTimeOrderingMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
- "USAGE directoryOperation )",
+ "NO-USER-MODIFICATION USAGE directoryOperation )",
&ad_pwdFailureTime },
{ "( 1.3.6.1.4.1.42.2.27.8.1.20 "
"NAME ( 'pwdHistory' ) "
"DESC 'The history of users passwords' "
"EQUALITY octetStringMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 "
- "USAGE directoryOperation NO-USER-MODIFICATION )",
+ "NO-USER-MODIFICATION USAGE directoryOperation )",
&ad_pwdHistory },
{ "( 1.3.6.1.4.1.42.2.27.8.1.21 "
"NAME ( 'pwdGraceUseTime' ) "
"DESC 'The timestamps of the grace login once the password has expired' "
"EQUALITY generalizedTimeMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
- "USAGE directoryOperation NO-USER-MODIFICATION )",
+ "NO-USER-MODIFICATION USAGE directoryOperation )",
&ad_pwdGraceUseTime },
{ "( 1.3.6.1.4.1.42.2.27.8.1.22 "
"NAME ( 'pwdReset' ) "
"DESC 'The pwdPolicy subentry in effect for this object' "
"EQUALITY distinguishedNameMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
- "SINGLE-VALUE USAGE directoryOperation )",
+ "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
&ad_pwdPolicySubentry },
{ NULL, NULL }
};
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
+ /* Reset lockout status on all Bind requests */
+ pwcons[op->o_conn->c_conn_idx].restricted = 0;
+
/* Root bypasses policy */
if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn )) {
Entry *e;
/* Reset the restricted flag for the next session on this connection */
static int
-ppolicy_unbind( Operation *op, SlapReply *rs )
+ppolicy_connection_destroy( BackendDB *bd, Connection *conn )
{
- pwcons[op->o_conn->c_conn_idx].restricted = 0;
+ pwcons[conn->c_conn_idx].restricted = 0;
return SLAP_CB_CONTINUE;
}
scherr2str(code), err );
return code;
}
+ /* Allow Manager to set these as needed */
+ if ( is_at_no_user_mod( (*pwd_OpSchema[i].ad)->ad_type )) {
+ (*pwd_OpSchema[i].ad)->ad_type->sat_flags |=
+ SLAP_AT_MANAGEABLE;
+ }
}
code = register_supported_control( LDAP_CONTROL_PASSWORDPOLICYREQUEST,
ppolicy.on_bi.bi_op_add = ppolicy_add;
ppolicy.on_bi.bi_op_bind = ppolicy_bind;
- ppolicy.on_bi.bi_op_unbind = ppolicy_unbind;
ppolicy.on_bi.bi_op_compare = ppolicy_restrict;
ppolicy.on_bi.bi_op_delete = ppolicy_restrict;
ppolicy.on_bi.bi_op_modify = ppolicy_modify;
ppolicy.on_bi.bi_op_search = ppolicy_restrict;
+ ppolicy.on_bi.bi_connection_destroy = ppolicy_connection_destroy;
return overlay_register( &ppolicy );
}
static AttributeDescription *ad_errText;
static AttributeDescription *ad_errOp;
static AttributeDescription *ad_errSleepTime;
+static ObjectClass *oc_errAbsObject;
static ObjectClass *oc_errObject;
+static ObjectClass *oc_errAuxObject;
typedef enum retcode_op_e {
SN_DG_OP_NONE = 0x0000,
typedef struct retcode_cb_t {
unsigned rdc_flags;
ber_tag_t rdc_tag;
+ AttributeName *rdc_attrs;
} retcode_cb_t;
static int
int rc;
op->o_tag = rdc->rdc_tag;
+ if ( op->o_tag == LDAP_REQ_SEARCH ) {
+ rs->sr_attrs = rdc->rdc_attrs;
+ }
rc = retcode_entry_response( op, rs, rs->sr_entry );
op->o_tag = o_tag;
op2.ors_attrsonly = 0;
op2.ors_attrs = slap_anlist_all_attributes;
- ber_str2bv_x( "(objectClass=errObject)", STRLENOF( "(objectClass=errObject)" ),
+ ber_str2bv_x( "(objectClass=errAbsObject)",
+ STRLENOF( "(objectClass=errAbsObject)" ),
1, &op2.ors_filterstr, op2.o_tmpmemctx );
op2.ors_filter = str2filter_x( &op2, op2.ors_filterstr.bv_val );
op2.o_bd = &db;
rdc.rdc_flags = RETCODE_FINDIR;
+ if ( op->o_tag == LDAP_REQ_SEARCH ) {
+ rdc.rdc_attrs = op->ors_attrs;
+ }
rdc.rdc_tag = op->o_tag;
sc.sc_response = retcode_cb_response;
sc.sc_private = &rdc;
send_ldap_result( op, rs );
if ( rs->sr_ref != NULL ) {
ber_bvarray_free( rs->sr_ref );
+ rs->sr_ref = NULL;
}
rs->sr_matched = NULL;
rs->sr_text = NULL;
return SLAP_CB_CONTINUE;
}
- if ( !is_entry_objectclass( e, oc_errObject, 0 ) ) {
+ if ( !is_entry_objectclass_or_sub( e, oc_errAbsObject ) ) {
return SLAP_CB_CONTINUE;
}
char *desc;
ObjectClass **oc;
} retcode_oc[] = {
- { "errObject", "( 1.3.6.1.4.1.4203.666.11.4.3.1 "
- "NAME ( 'errObject' ) "
- "SUP top STRUCTURAL "
+ { "errAbsObject", "( 1.3.6.1.4.1.4203.666.11.4.3.0 "
+ "NAME ( 'errAbsObject' ) "
+ "SUP top ABSTRACT "
"MUST ( errCode ) "
"MAY ( "
"cn "
"$ errText "
"$ errSleepTime "
") )",
+ &oc_errAbsObject },
+ { "errObject", "( 1.3.6.1.4.1.4203.666.11.4.3.1 "
+ "NAME ( 'errObject' ) "
+ "SUP errAbsObject STRUCTURAL "
+ ")",
&oc_errObject },
+ { "errAuxObject", "( 1.3.6.1.4.1.4203.666.11.4.3.2 "
+ "NAME ( 'errAuxObject' ) "
+ "SUP errAbsObject AUXILIARY "
+ ")",
+ &oc_errAuxObject },
{ NULL }
};
}
}
- } else if ( !isupdate && (*ap)->a_desc->ad_type->sat_no_user_mod ) {
+ } else if ( !isupdate && !get_manageDIT( op ) && (*ap)->a_desc->ad_type->sat_no_user_mod )
+ {
goto next_attr;
} else {
{
is_oc = 1;
- } else if ( !isupdate && (*mlp)->sml_desc->ad_type->sat_no_user_mod ) {
+ } else if ( !isupdate && !get_manageDIT( op ) && (*mlp)->sml_desc->ad_type->sat_no_user_mod )
+ {
goto next_mod;
} else {
}
} else if ( !isupdate
+ && !get_manageDIT( op )
&& (*ap)->a_desc->ad_type->sat_no_user_mod
&& (*ap)->a_desc->ad_type != slap_schema.si_at_undefined )
{
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr,
"%s: line %d: destination attributeType '%s': %d (%s)\n",
- fname, lineno, src, rc, text ? text : "null" );
+ fname, lineno, dst, rc, text ? text : "null" );
return 1;
}
}
int fscope; /* if TRUE then fdn is within the psearch scope */
} fbase_cookie;
-static AttributeName csn_anlist[2];
+static AttributeName csn_anlist[3];
static AttributeName uuid_anlist[2];
/* Build a LDAPsync intermediate state control */
}
}
+ /* FIXME: what if entryuuid is NULL or empty ? */
+
if ( send_cookie && cookie ) {
ber_printf( ber, "{eOON}",
entry_sync_state, &entryuuid_bv, cookie );
* was not checkpointed at the previous shutdown.
*
* 2: when the current contextCSN is known and we have a sync cookie, we search
- * for one entry with CSN <= the cookie CSN. (Used to search for =.) If an
- * entry is found, the cookie CSN is valid, otherwise it is stale.
+ * for one entry with CSN = the cookie CSN. If not found, try <= cookie CSN.
+ * If an entry is found, the cookie CSN is valid, otherwise it is stale.
*
* 3: during a refresh phase, we search for all entries with CSN <= the cookie
* CSN, and generate Present records for them. We always collect this result
int i, rc = LDAP_SUCCESS;
fpres_cookie pcookie;
sync_control *srs = NULL;
+ int findcsn_retry = 1;
if ( mode != FIND_MAXCSN ) {
srs = op->o_controls[slap_cids.sc_LDAPsync];
fop.ors_filter = &cf;
fop.ors_filterstr.bv_val = buf;
+again:
switch( mode ) {
case FIND_MAXCSN:
cf.f_choice = LDAP_FILTER_GE;
maxcsn.bv_len = si->si_ctxcsn.bv_len;
break;
case FIND_CSN:
- cf.f_choice = LDAP_FILTER_LE;
cf.f_av_value = srs->sr_state.ctxcsn;
- fop.ors_filterstr.bv_len = sprintf( buf, "(entryCSN<=%s)",
- cf.f_av_value.bv_val );
+ /* Look for exact match the first time */
+ if ( findcsn_retry ) {
+ cf.f_choice = LDAP_FILTER_EQUALITY;
+ fop.ors_filterstr.bv_len = sprintf( buf, "(entryCSN=%s)",
+ cf.f_av_value.bv_val );
+ /* On retry, look for <= */
+ } else {
+ cf.f_choice = LDAP_FILTER_LE;
+ fop.ors_filterstr.bv_len = sprintf( buf, "(entryCSN<=%s)",
+ cf.f_av_value.bv_val );
+ }
fop.ors_attrsonly = 1;
fop.ors_attrs = slap_anlist_no_attrs;
fop.ors_slimit = 1;
break;
case FIND_CSN:
/* If matching CSN was not found, invalidate the context. */
- if ( !cb.sc_private ) rc = LDAP_NO_SUCH_OBJECT;
+ if ( !cb.sc_private ) {
+ /* If we didn't find an exact match, then try for <= */
+ if ( findcsn_retry ) {
+ findcsn_retry = 0;
+ goto again;
+ }
+ rc = LDAP_NO_SUCH_OBJECT;
+ }
break;
case FIND_PRESENT:
op->o_tmpfree( pcookie.uuids, op->o_tmpmemctx );
slap_overinst *ss_on;
syncops *ss_so;
int ss_present;
+ struct berval ss_ctxcsn;
+ char ss_csnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];
} searchstate;
static int
sync_control *srs = op->o_controls[slap_cids.sc_LDAPsync];
if ( rs->sr_type == REP_SEARCH || rs->sr_type == REP_SEARCHREF ) {
+ Attribute *a;
/* If we got a referral without a referral object, there's
* something missing that we cannot replicate. Just ignore it.
* The consumer will abort because we didn't send the expected
Debug( LDAP_DEBUG_ANY, "bogus referral in context\n",0,0,0 );
return SLAP_CB_CONTINUE;
}
- if ( !BER_BVISNULL( &srs->sr_state.ctxcsn )) {
- Attribute *a = attr_find( rs->sr_entry->e_attrs,
- slap_schema.si_ad_entryCSN );
-
+ a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryCSN );
+ if ( a ) {
+ /* Make sure entry is less than the snaphot'd contextCSN */
+ if ( ber_bvcmp( &a->a_nvals[0], &ss->ss_ctxcsn ) > 0 )
+ return LDAP_SUCCESS;
+
/* Don't send the ctx entry twice */
- if ( a && bvmatch( &a->a_nvals[0], &srs->sr_state.ctxcsn ) )
+ if ( !BER_BVISNULL( &srs->sr_state.ctxcsn ) &&
+ bvmatch( &a->a_nvals[0], &srs->sr_state.ctxcsn ) )
return LDAP_SUCCESS;
}
rs->sr_ctrls = op->o_tmpalloc( sizeof(LDAPControl *)*2,
} else if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS ) {
struct berval cookie;
- slap_compose_sync_cookie( op, &cookie,
- &op->ors_filter->f_and->f_ava->aa_value,
+ slap_compose_sync_cookie( op, &cookie, &ss->ss_ctxcsn,
srs->sr_state.rid );
/* Is this a regular refresh? */
syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
slap_callback *cb;
int gotstate = 0, nochange = 0, do_present = 1;
- Filter *fand, *fava;
syncops *sop = NULL;
searchstate *ss;
sync_control *srs;
sop->s_filterstr= op->ors_filterstr;
}
- fand = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
- fand->f_choice = LDAP_FILTER_AND;
- fand->f_next = NULL;
- fava = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
- fava->f_choice = LDAP_FILTER_LE;
- fava->f_ava = op->o_tmpalloc( sizeof(AttributeAssertion), op->o_tmpmemctx );
- fava->f_ava->aa_desc = slap_schema.si_ad_entryCSN;
-#ifdef LDAP_COMP_MATCH
- fava->f_ava->aa_cf = NULL;
-#endif
- ber_dupbv_x( &fava->f_ava->aa_value, &ctxcsn, op->o_tmpmemctx );
- fand->f_and = fava;
- if ( gotstate ) {
- fava->f_next = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
- fava = fava->f_next;
+ /* If something changed, find the changes */
+ if ( gotstate && !nochange ) {
+ Filter *fand, *fava;
+
+ fand = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
+ fand->f_choice = LDAP_FILTER_AND;
+ fand->f_next = NULL;
+ fava = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
+ fand->f_and = fava;
fava->f_choice = LDAP_FILTER_GE;
fava->f_ava = op->o_tmpalloc( sizeof(AttributeAssertion), op->o_tmpmemctx );
fava->f_ava->aa_desc = slap_schema.si_ad_entryCSN;
fava->f_ava->aa_cf = NULL;
#endif
ber_dupbv_x( &fava->f_ava->aa_value, &srs->sr_state.ctxcsn, op->o_tmpmemctx );
+ fava->f_next = op->ors_filter;
+ op->ors_filter = fand;
+ filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
}
- fava->f_next = op->ors_filter;
- op->ors_filter = fand;
- filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
/* Let our callback add needed info to returned entries */
cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(searchstate), op->o_tmpmemctx);
ss->ss_on = on;
ss->ss_so = sop;
ss->ss_present = do_present;
+ ss->ss_ctxcsn.bv_len = ctxcsn.bv_len;
+ ss->ss_ctxcsn.bv_val = ss->ss_csnbuf;
+ strcpy( ss->ss_ctxcsn.bv_val, ctxcsn.bv_val );
cb->sc_response = syncprov_search_response;
cb->sc_cleanup = syncprov_search_cleanup;
cb->sc_private = ss;
sp_cf_gen, "( OLcfgOvAt:1.1 NAME 'olcSpCheckpoint' "
"DESC 'ContextCSN checkpoint interval in ops and minutes' "
"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
- { "syncprov-sessionlog", "size", 2, 2, 0, ARG_INT|ARG_MAGIC|SP_SESSL,
+ { "syncprov-sessionlog", "ops", 2, 2, 0, ARG_INT|ARG_MAGIC|SP_SESSL,
sp_cf_gen, "( OLcfgOvAt:1.2 NAME 'olcSpSessionlog' "
"DESC 'Session log size in ops' "
"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
return rc;
}
-/* Cheating - we have no thread pool context for these functions,
- * so make one.
- */
-typedef struct thread_keys {
- void *key;
- void *data;
- ldap_pvt_thread_pool_keyfree_t *xfree;
-} thread_keys;
-
-#define MAXKEYS 32
-/* A fake thread context */
-static thread_keys thrctx[MAXKEYS];
-
/* ITS#3456 we cannot run this search on the main thread, must use a
* child thread in order to insure we have a big enough stack.
*/
Entry *e;
Attribute *a;
int rc;
+ void *thrctx = NULL;
if ( slapMode & SLAP_TOOL_MODE ) {
return 0;
return rc;
}
+ thrctx = ldap_pvt_thread_pool_context();
connection_fake_init( &conn, op, thrctx );
op->o_bd = be;
op->o_dn = be->be_rootdn;
out:
op->o_bd->bd_info = (BackendInfo *)on;
+ ldap_pvt_thread_pool_context_reset( thrctx );
return 0;
}
char opbuf[OPERATION_BUFFER_SIZE];
Operation *op = (Operation *)opbuf;
SlapReply rs = {REP_RESULT};
+ void *thrctx;
+ thrctx = ldap_pvt_thread_pool_context();
connection_fake_init( &conn, op, thrctx );
op->o_bd = be;
op->o_dn = be->be_rootdn;
op->o_ndn = be->be_rootndn;
syncprov_checkpoint( op, &rs, on );
- }
- for ( i=0; thrctx[i].key; i++) {
- if ( thrctx[i].xfree )
- thrctx[i].xfree( thrctx[i].key, thrctx[i].data );
- thrctx[i].key = NULL;
+ ldap_pvt_thread_pool_context_reset( thrctx );
}
return 0;
csn_anlist[0].an_desc = slap_schema.si_ad_entryCSN;
csn_anlist[0].an_name = slap_schema.si_ad_entryCSN->ad_cname;
+ csn_anlist[1].an_desc = slap_schema.si_ad_entryUUID;
+ csn_anlist[1].an_name = slap_schema.si_ad_entryUUID->ad_cname;
uuid_anlist[0].an_desc = slap_schema.si_ad_entryUUID;
uuid_anlist[0].an_name = slap_schema.si_ad_entryUUID->ad_cname;
--- /dev/null
+/* valsort.c - sort attribute values */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2005 The OpenLDAP Foundation.
+ * Portions copyright 2005 Symas Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Howard Chu for inclusion in
+ * OpenLDAP Software. This work was sponsored by Stanford University.
+ */
+
+/*
+ * This overlay sorts the values of multi-valued attributes when returning
+ * them in a search response.
+ */
+#include "portable.h"
+
+#ifdef SLAPD_OVER_VALSORT
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/ctype.h>
+
+#include "slap.h"
+#include "config.h"
+#include "lutil.h"
+
+#define VALSORT_ASCEND 0
+#define VALSORT_DESCEND 1
+
+#define VALSORT_ALPHA 2
+#define VALSORT_NUMERIC 4
+
+#define VALSORT_WEIGHTED 8
+
+typedef struct valsort_info {
+ struct valsort_info *vi_next;
+ struct berval vi_dn;
+ AttributeDescription *vi_ad;
+ slap_mask_t vi_sort;
+} valsort_info;
+
+static int valsort_cid;
+
+static ConfigDriver valsort_cf_func;
+
+static ConfigTable valsort_cfats[] = {
+ { "valsort-attr", "attribute> <dn> <sort-type", 4, 5, 0, ARG_MAGIC,
+ valsort_cf_func, "( OLcfgOvAt:5.1 NAME 'olcValSortAttr' "
+ "DESC 'Sorting rule for attribute under given DN' "
+ "EQUALITY caseIgnoreMatch "
+ "SYNTAX OMsDirectoryString )", NULL, NULL },
+ { NULL }
+};
+
+static ConfigOCs valsort_cfocs[] = {
+ { "( OLcfgOvOc:5.1 "
+ "NAME 'olcValSortConfig' "
+ "DESC 'Value Sorting configuration' "
+ "SUP olcOverlayConfig "
+ "MUST olcValSortAttr )",
+ Cft_Overlay, valsort_cfats },
+ { NULL }
+};
+
+static slap_verbmasks sorts[] = {
+ { BER_BVC("alpha-ascend"), VALSORT_ASCEND|VALSORT_ALPHA },
+ { BER_BVC("alpha-descend"), VALSORT_DESCEND|VALSORT_ALPHA },
+ { BER_BVC("numeric-ascend"), VALSORT_ASCEND|VALSORT_NUMERIC },
+ { BER_BVC("numeric-descend"), VALSORT_DESCEND|VALSORT_NUMERIC },
+ { BER_BVC("weighted"), VALSORT_WEIGHTED },
+ { BER_BVNULL, 0 }
+};
+
+static Syntax *syn_numericString;
+
+static int
+valsort_cf_func(ConfigArgs *c) {
+ slap_overinst *on = (slap_overinst *)c->bi;
+ valsort_info vitmp, *vi;
+ const char *text = NULL;
+ int i, is_numeric;
+ struct berval bv = BER_BVNULL;
+
+ if ( c->op == SLAP_CONFIG_EMIT ) {
+ for ( vi = on->on_bi.bi_private; vi; vi = vi->vi_next ) {
+ struct berval bv2 = BER_BVNULL, bvret;
+ char *ptr;
+ int len;
+
+ len = vi->vi_ad->ad_cname.bv_len + 1 + vi->vi_dn.bv_len + 2;
+ i = vi->vi_sort;
+ if ( i & VALSORT_WEIGHTED ) {
+ enum_to_verb( sorts, VALSORT_WEIGHTED, &bv2 );
+ len += bv2.bv_len + 1;
+ i ^= VALSORT_WEIGHTED;
+ }
+ if ( i ) {
+ enum_to_verb( sorts, i, &bv );
+ len += bv.bv_len + 1;
+ }
+ bvret.bv_val = ch_malloc( len+1 );
+ bvret.bv_len = len;
+
+ ptr = lutil_strcopy( bvret.bv_val, vi->vi_ad->ad_cname.bv_val );
+ *ptr++ = ' ';
+ *ptr++ = '"';
+ ptr = lutil_strcopy( ptr, vi->vi_dn.bv_val );
+ *ptr++ = '"';
+ if ( vi->vi_sort & VALSORT_WEIGHTED ) {
+ *ptr++ = ' ';
+ ptr = lutil_strcopy( ptr, bv2.bv_val );
+ }
+ if ( i ) {
+ *ptr++ = ' ';
+ strcpy( ptr, bv.bv_val );
+ }
+ ber_bvarray_add( &c->rvalue_vals, &bvret );
+ }
+ i = ( c->rvalue_vals != NULL ) ? 0 : 1;
+ return i;
+ } else if ( c->op == LDAP_MOD_DELETE ) {
+ if ( c->valx < 0 ) {
+ for ( vi = on->on_bi.bi_private; vi; vi = on->on_bi.bi_private ) {
+ on->on_bi.bi_private = vi->vi_next;
+ ch_free( vi->vi_dn.bv_val );
+ ch_free( vi );
+ }
+ } else {
+ valsort_info **prev;
+
+ for (i=0, prev = (valsort_info **)&on->on_bi.bi_private,
+ vi = *prev; vi && i<c->valx;
+ prev = &vi->vi_next, vi = vi->vi_next, i++ );
+ (*prev)->vi_next = vi->vi_next;
+ ch_free( vi->vi_dn.bv_val );
+ ch_free( vi );
+ }
+ return 0;
+ }
+ vitmp.vi_ad = NULL;
+ i = slap_str2ad( c->argv[1], &vitmp.vi_ad, &text );
+ if ( i ) {
+ sprintf( c->msg, "<%s> %s", c->argv[0], text );
+ Debug( LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
+ c->log, c->msg, c->argv[1] );
+ return(1);
+ }
+ if ( is_at_single_value( vitmp.vi_ad->ad_type )) {
+ sprintf( c->msg, "<%s> %s is single-valued, ignoring", c->argv[0],
+ vitmp.vi_ad->ad_cname.bv_val );
+ Debug( LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
+ c->log, c->msg, c->argv[1] );
+ return(0);
+ }
+ is_numeric = ( vitmp.vi_ad->ad_type->sat_syntax == syn_numericString ||
+ vitmp.vi_ad->ad_type->sat_syntax == slap_schema.si_syn_integer ) ? 1
+ : 0;
+ ber_str2bv( c->argv[2], 0, 0, &bv );
+ i = dnNormalize( 0, NULL, NULL, &bv, &vitmp.vi_dn, NULL );
+ if ( i ) {
+ sprintf( c->msg, "<%s> unable to normalize DN", c->argv[0] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
+ c->log, c->msg, c->argv[2] );
+ return(1);
+ }
+ i = verb_to_mask( c->argv[3], sorts );
+ if ( BER_BVISNULL( &sorts[i].word )) {
+ sprintf( c->msg, "<%s> unrecognized sort type", c->argv[0] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
+ c->log, c->msg, c->argv[3] );
+ return(1);
+ }
+ vitmp.vi_sort = sorts[i].mask;
+ if ( sorts[i].mask == VALSORT_WEIGHTED && c->argc == 5 ) {
+ i = verb_to_mask( c->argv[4], sorts );
+ if ( BER_BVISNULL( &sorts[i].word )) {
+ sprintf( c->msg, "<%s> unrecognized sort type", c->argv[0] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
+ c->log, c->msg, c->argv[4] );
+ return(1);
+ }
+ vitmp.vi_sort |= sorts[i].mask;
+ }
+ if (( vitmp.vi_sort & VALSORT_NUMERIC ) && !is_numeric ) {
+ sprintf( c->msg, "<%s> numeric sort specified for non-numeric syntax",
+ c->argv[0] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
+ c->log, c->msg, c->argv[1] );
+ return(1);
+ }
+ vi = ch_malloc( sizeof(valsort_info) );
+ *vi = vitmp;
+ vi->vi_next = on->on_bi.bi_private;
+ on->on_bi.bi_private = vi;
+ return 0;
+}
+
+/* Use Insertion Sort algorithm on selected values */
+static void
+do_sort( Operation *op, Attribute *a, int beg, int num, slap_mask_t sort )
+{
+ int i, j, gotnvals;
+ struct berval tmp, ntmp, *vals, *nvals;
+
+ gotnvals = (a->a_vals != a->a_nvals );
+
+ nvals = a->a_nvals + beg;
+ if ( gotnvals )
+ vals = a->a_vals + beg;
+
+ if ( sort & VALSORT_NUMERIC ) {
+ long *numbers = op->o_tmpalloc( num * sizeof(long), op->o_tmpmemctx ),
+ idx;
+ for (i=0; i<num; i++)
+ numbers[i] = strtol( nvals[i].bv_val, NULL, 0 );
+
+ for (i=1; i<num; i++) {
+ idx = numbers[i];
+ ntmp = nvals[i];
+ if ( gotnvals ) tmp = vals[i];
+ j = i;
+ while ( j>0 ) {
+ int cmp = (sort & VALSORT_DESCEND) ? numbers[j-1] < idx :
+ numbers[j-1] > idx;
+ if ( !cmp ) break;
+ numbers[j] = numbers[j-1];
+ nvals[j] = nvals[j-1];
+ if ( gotnvals ) vals[j] = vals[j-1];
+ j--;
+ }
+ numbers[j] = idx;
+ nvals[j] = ntmp;
+ if ( gotnvals ) vals[j] = tmp;
+ }
+ op->o_tmpfree( numbers, op->o_tmpmemctx );
+ } else {
+ for (i=1; i<num; i++) {
+ ntmp = nvals[i];
+ if ( gotnvals ) tmp = vals[i];
+ j = i;
+ while ( j>0 ) {
+ int cmp = strcmp( nvals[j-1].bv_val, ntmp.bv_val );
+ cmp = (sort & VALSORT_DESCEND) ? (cmp < 0) : (cmp > 0);
+ if ( !cmp ) break;
+
+ nvals[j] = nvals[j-1];
+ if ( gotnvals ) vals[j] = vals[j-1];
+ j--;
+ }
+ nvals[j] = ntmp;
+ if ( gotnvals ) vals[j] = tmp;
+ }
+ }
+}
+
+static int
+valsort_response( Operation *op, SlapReply *rs )
+{
+ slap_overinst *on;
+ valsort_info *vi;
+ Attribute *a;
+
+ /* We only want search responses */
+ if ( rs->sr_type != REP_SEARCH ) return SLAP_CB_CONTINUE;
+
+ /* If this is a syncrepl response, pass thru unmodified */
+ if ( op->o_sync > SLAP_CONTROL_IGNORED ) return SLAP_CB_CONTINUE;
+
+ on = (slap_overinst *) op->o_bd->bd_info;
+ vi = on->on_bi.bi_private;
+
+ /* And we must have something configured */
+ if ( !vi ) return SLAP_CB_CONTINUE;
+
+ /* Find a rule whose baseDN matches this entry */
+ for (; vi; vi = vi->vi_next ) {
+ int i, n;
+
+ if ( !dnIsSuffix( &rs->sr_entry->e_nname, &vi->vi_dn ))
+ continue;
+
+ /* Find attr that this rule affects */
+ a = attr_find( rs->sr_entry->e_attrs, vi->vi_ad );
+ if ( !a ) continue;
+
+ if (( rs->sr_flags & ( REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED )) !=
+ ( REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED )) {
+ rs->sr_entry = entry_dup( rs->sr_entry );
+ rs->sr_flags |= REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED;
+ a = attr_find( rs->sr_entry->e_attrs, vi->vi_ad );
+ }
+
+ /* count values */
+ for ( n = 0; !BER_BVISNULL( &a->a_vals[n] ); n++ );
+
+ if ( vi->vi_sort & VALSORT_WEIGHTED ) {
+ int j, gotnvals;
+ long *index = op->o_tmpalloc( n * sizeof(long), op->o_tmpmemctx );
+
+ gotnvals = (a->a_vals != a->a_nvals );
+
+ for (i=0; i<n; i++) {
+ char *ptr = strchr( a->a_nvals[i].bv_val, '{' );
+ char *end = NULL;
+ if ( !ptr ) {
+ Debug(LDAP_DEBUG_TRACE, "weights missing from attr %s "
+ "in entry %s\n", vi->vi_ad->ad_cname.bv_val,
+ rs->sr_entry->e_name.bv_val, 0 );
+ break;
+ }
+ index[i] = strtol( ptr+1, &end, 0 );
+ if ( *end != '}' ) {
+ Debug(LDAP_DEBUG_TRACE, "weights misformatted "
+ "in entry %s\n",
+ rs->sr_entry->e_name.bv_val, 0, 0 );
+ break;
+ }
+ /* Strip out weights */
+ ptr = a->a_nvals[i].bv_val;
+ end++;
+ for (;*end;)
+ *ptr++ = *end++;
+ *ptr = '\0';
+ a->a_nvals[i].bv_len = ptr - a->a_nvals[i].bv_val;
+
+ if ( a->a_vals != a->a_nvals ) {
+ ptr = a->a_vals[i].bv_val;
+ end = strchr( ptr, '}' ) + 1;
+ for (;*end;)
+ *ptr++ = *end++;
+ *ptr = '\0';
+ a->a_vals[i].bv_len = ptr - a->a_vals[i].bv_val;
+ }
+ }
+ /* An attr was missing weights here, ignore it */
+ if ( i<n ) {
+ op->o_tmpfree( index, op->o_tmpmemctx );
+ continue;
+ }
+ /* Insertion sort */
+ for ( i=1; i<n; i++) {
+ long idx = index[i];
+ struct berval tmp = a->a_vals[i], ntmp;
+ if ( gotnvals ) ntmp = a->a_nvals[i];
+ j = i;
+ while (( j>0 ) && (index[j-1] > idx )) {
+ index[j] = index[j-1];
+ a->a_vals[j] = a->a_vals[j-1];
+ if ( gotnvals ) a->a_nvals[j] = a->a_nvals[j-1];
+ j--;
+ }
+ index[j] = idx;
+ a->a_vals[j] = tmp;
+ if ( gotnvals ) a->a_nvals[j] = ntmp;
+ }
+ /* Check for secondary sort */
+ if ( vi->vi_sort ^ VALSORT_WEIGHTED ) {
+ for ( i=0; i<n;) {
+ for (j=i+1; j<n; j++) {
+ if (index[i] != index[j])
+ break;
+ }
+ if( j-i > 1 )
+ do_sort( op, a, i, j-i, vi->vi_sort );
+ i = j;
+ }
+ }
+ op->o_tmpfree( index, op->o_tmpmemctx );
+ } else {
+ do_sort( op, a, 0, n, vi->vi_sort );
+ }
+ }
+ return SLAP_CB_CONTINUE;
+}
+
+static int
+valsort_add( Operation *op, SlapReply *rs )
+{
+ slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
+ valsort_info *vi = on->on_bi.bi_private;
+
+ Attribute *a;
+ int i;
+ char *ptr, *end;
+
+ /* See if any weighted sorting applies to this entry */
+ for ( ;vi;vi=vi->vi_next ) {
+ if ( !dnIsSuffix( &op->o_req_ndn, &vi->vi_dn ))
+ continue;
+ if ( !(vi->vi_sort & VALSORT_WEIGHTED ))
+ continue;
+ a = attr_find( op->ora_e->e_attrs, vi->vi_ad );
+ if ( !a )
+ continue;
+ for (i=0; !BER_BVISNULL( &a->a_vals[i] ); i++) {
+ ptr = strchr(a->a_vals[i].bv_val, '{' );
+ if ( !ptr ) {
+ Debug(LDAP_DEBUG_TRACE, "weight missing from attribute %s\n",
+ vi->vi_ad->ad_cname.bv_val, 0, 0);
+ send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION,
+ "weight missing from attribute" );
+ return rs->sr_err;
+ }
+ strtol( ptr+1, &end, 0 );
+ if ( *end != '}' ) {
+ Debug(LDAP_DEBUG_TRACE, "weight is misformatted in %s\n",
+ vi->vi_ad->ad_cname.bv_val, 0, 0);
+ send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION,
+ "weight is misformatted" );
+ return rs->sr_err;
+ }
+ }
+ }
+ return SLAP_CB_CONTINUE;
+}
+
+static int
+valsort_modify( Operation *op, SlapReply *rs )
+{
+ slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
+ valsort_info *vi = on->on_bi.bi_private;
+
+ Modifications *ml;
+ int i;
+ char *ptr, *end;
+
+ /* See if any weighted sorting applies to this entry */
+ for ( ;vi;vi=vi->vi_next ) {
+ if ( !dnIsSuffix( &op->o_req_ndn, &vi->vi_dn ))
+ continue;
+ if ( !(vi->vi_sort & VALSORT_WEIGHTED ))
+ continue;
+ for (ml = op->orm_modlist; ml; ml=ml->sml_next ) {
+ if ( ml->sml_desc == vi->vi_ad )
+ break;
+ }
+ if ( !ml )
+ continue;
+ for (i=0; !BER_BVISNULL( &ml->sml_values[i] ); i++) {
+ ptr = strchr(ml->sml_values[i].bv_val, '{' );
+ if ( !ptr ) {
+ Debug(LDAP_DEBUG_TRACE, "weight missing from attribute %s\n",
+ vi->vi_ad->ad_cname.bv_val, 0, 0);
+ send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION,
+ "weight missing from attribute" );
+ return rs->sr_err;
+ }
+ strtol( ptr+1, &end, 0 );
+ if ( *end != '}' ) {
+ Debug(LDAP_DEBUG_TRACE, "weight is misformatted in %s\n",
+ vi->vi_ad->ad_cname.bv_val, 0, 0);
+ send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION,
+ "weight is misformatted" );
+ return rs->sr_err;
+ }
+ }
+ }
+ return SLAP_CB_CONTINUE;
+}
+
+static int
+valsort_destroy(
+ BackendDB *be
+)
+{
+ slap_overinst *on = (slap_overinst *)be->bd_info;
+ valsort_info *vi = on->on_bi.bi_private, *next;
+
+ for (; vi; vi = next) {
+ next = vi->vi_next;
+ ch_free( vi->vi_dn.bv_val );
+ ch_free( vi );
+ }
+
+ return 0;
+}
+
+static int
+valsort_parseCtrl(
+ Operation *op,
+ SlapReply *rs,
+ LDAPControl *ctrl )
+{
+ if ( ctrl->ldctl_value.bv_len ) {
+ rs->sr_text = "valSort control value not empty";
+ return LDAP_PROTOCOL_ERROR;
+ }
+ op->o_ctrlflag[valsort_cid] = ctrl->ldctl_iscritical ?
+ SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
+
+ return LDAP_SUCCESS;
+}
+
+static slap_overinst valsort;
+
+int valsort_init()
+{
+ int i, rc;
+
+ valsort.on_bi.bi_type = "valsort";
+ valsort.on_bi.bi_db_destroy = valsort_destroy;
+
+ valsort.on_bi.bi_op_add = valsort_add;
+ valsort.on_bi.bi_op_modify = valsort_modify;
+
+ valsort.on_response = valsort_response;
+
+ valsort.on_bi.bi_cf_ocs = valsort_cfocs;
+
+ rc = register_supported_control( LDAP_CONTROL_VALSORT,
+ SLAP_CTRL_SEARCH | SLAP_CTRL_HIDE, NULL, valsort_parseCtrl,
+ &valsort_cid );
+ if ( rc != LDAP_SUCCESS ) {
+ fprintf( stderr, "Failed to register control %d\n", rc );
+ return rc;
+ }
+
+ syn_numericString = syn_find( "1.3.6.1.4.1.1466.115.121.1.36" );
+
+ rc = config_register_schema( valsort_cfats, valsort_cfocs );
+ if ( rc ) return rc;
+
+ return overlay_register(&valsort);
+}
+
+#if SLAPD_OVER_VALSORT == SLAPD_MOD_DYNAMIC
+int init_module( int argc, char *argv[]) {
+ return valsort_init();
+}
+#endif
+
+#endif /* SLAPD_OVER_VALSORT */
assert( ber_bvcmp( &slap_EXOP_MODIFY_PASSWD, &op->ore_reqoid ) == 0 );
if( op->o_dn.bv_len == 0 ) {
+ Statslog( LDAP_DEBUG_STATS, "%s PASSMOD\n",
+ op->o_log_prefix, 0, 0, 0, 0 );
rs->sr_text = "only authenticated users may change passwords";
return LDAP_STRONG_AUTH_REQUIRED;
}
rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id, &qpw->rs_old,
&qpw->rs_new, &rs->sr_text );
+ if ( rs->sr_err == LDAP_SUCCESS && !BER_BVISEMPTY( &id ) ) {
+ Statslog( LDAP_DEBUG_STATS, "%s PASSMOD id=\"%s\"%s%s\n",
+ op->o_log_prefix, id.bv_val,
+ qpw->rs_old.bv_val ? " old" : "",
+ qpw->rs_new.bv_val ? " new" : "", 0 );
+ } else {
+ Statslog( LDAP_DEBUG_STATS, "%s PASSMOD\n",
+ op->o_log_prefix, 0, 0, 0, 0 );
+ }
+
if ( rs->sr_err != LDAP_SUCCESS ) {
return rs->sr_err;
}
LDAP_BEGIN_DECL
+/*
+ * aci.c
+ */
+#ifdef SLAPD_ACI_ENABLED
+LDAP_SLAPD_F (int) aci_mask LDAP_P((
+ Operation *op, Entry *e,
+ AttributeDescription *desc,
+ struct berval *val,
+ struct berval *aci,
+ int nmatch,
+ regmatch_t *matches,
+ slap_access_t *grant,
+ slap_access_t *deny,
+ slap_aci_scope_t scope));
+#ifdef SLAP_DYNACL
+LDAP_SLAPD_F (int) dynacl_aci_init LDAP_P(( void ));
+#else /* !SLAP_DYNACL */
+LDAP_SLAPD_F (int) aci_init LDAP_P(( void ));
+LDAP_SLAPD_V (AttributeDescription *) slap_ad_aci;
+#endif /* !SLAP_DYNACL */
+#endif /* SLAPD_ACI_ENABLED */
+
/*
* acl.c
*/
#endif /* SLAP_DYNACL */
LDAP_SLAPD_F (int) acl_init LDAP_P(( void ));
+LDAP_SLAPD_V (const struct berval) aci_bv[];
+
+LDAP_SLAPD_F (int) acl_get_part LDAP_P((
+ struct berval *list,
+ int ix,
+ char sep,
+ struct berval *bv ));
+LDAP_SLAPD_F (int) acl_match_set LDAP_P((
+ struct berval *subj,
+ Operation *op,
+ Entry *e,
+ int setref ));
+LDAP_SLAPD_F (int) acl_string_expand LDAP_P((
+ struct berval *newbuf, struct berval *pattern,
+ char *match, int nmatch, regmatch_t *matches ));
+
/*
* aclparse.c
*/
/*
* backend.c
*/
+
+#define be_match( be1, be2 ) ( (be1) == (be2) || \
+ ( (be1) && (be2) && (be1)->be_nsuffix == (be2)->be_nsuffix ) )
+
LDAP_SLAPD_F (int) backend_init LDAP_P((void));
LDAP_SLAPD_F (int) backend_add LDAP_P((BackendInfo *aBackendInfo));
LDAP_SLAPD_F (int) backend_num LDAP_P((Backend *be));
slap_ssf_t ssf,
struct berval *id ));
-LDAP_SLAPD_F (void) connection_closing LDAP_P(( Connection *c ));
+LDAP_SLAPD_F (void) connection_closing LDAP_P((
+ Connection *c, const char *why ));
LDAP_SLAPD_F (int) connection_state_closing LDAP_P(( Connection *c ));
LDAP_SLAPD_F (const char *) connection_state2str LDAP_P(( int state ))
LDAP_GCCATTR((const));
ObjectClass *sub ));
LDAP_SLAPD_F (int) is_entry_objectclass LDAP_P((
- Entry *, ObjectClass *oc, int set_flags ));
+ Entry *, ObjectClass *oc, unsigned flags ));
+#define is_entry_objectclass_or_sub(e,oc) \
+ (is_entry_objectclass((e),(oc),SLAP_OCF_CHECK_SUP))
#define is_entry_alias(e) \
(((e)->e_ocflags & SLAP_OC__END) \
? (((e)->e_ocflags & SLAP_OC_ALIAS) != 0) \
- : is_entry_objectclass((e), slap_schema.si_oc_alias, 1))
+ : is_entry_objectclass((e), slap_schema.si_oc_alias, SLAP_OCF_SET_FLAGS))
#define is_entry_referral(e) \
(((e)->e_ocflags & SLAP_OC__END) \
? (((e)->e_ocflags & SLAP_OC_REFERRAL) != 0) \
- : is_entry_objectclass((e), slap_schema.si_oc_referral, 1))
+ : is_entry_objectclass((e), slap_schema.si_oc_referral, SLAP_OCF_SET_FLAGS))
#define is_entry_subentry(e) \
(((e)->e_ocflags & SLAP_OC__END) \
? (((e)->e_ocflags & SLAP_OC_SUBENTRY) != 0) \
- : is_entry_objectclass((e), slap_schema.si_oc_subentry, 1))
+ : is_entry_objectclass((e), slap_schema.si_oc_subentry, SLAP_OCF_SET_FLAGS))
#define is_entry_collectiveAttributeSubentry(e) \
(((e)->e_ocflags & SLAP_OC__END) \
? (((e)->e_ocflags & SLAP_OC_COLLECTIVEATTRIBUTESUBENTRY) != 0) \
- : is_entry_objectclass((e), slap_schema.si_oc_collectiveAttributeSubentry, 1))
+ : is_entry_objectclass((e), slap_schema.si_oc_collectiveAttributeSubentry, SLAP_OCF_SET_FLAGS))
#define is_entry_dynamicObject(e) \
(((e)->e_ocflags & SLAP_OC__END) \
? (((e)->e_ocflags & SLAP_OC_DYNAMICOBJECT) != 0) \
- : is_entry_objectclass((e), slap_schema.si_oc_dynamicObject, 1))
+ : is_entry_objectclass((e), slap_schema.si_oc_dynamicObject, SLAP_OCF_SET_FLAGS))
#define is_entry_glue(e) \
(((e)->e_ocflags & SLAP_OC__END) \
? (((e)->e_ocflags & SLAP_OC_GLUE) != 0) \
- : is_entry_objectclass((e), slap_schema.si_oc_glue, 1))
+ : is_entry_objectclass((e), slap_schema.si_oc_glue, SLAP_OCF_SET_FLAGS))
#define is_entry_syncProviderSubentry(e) \
(((e)->e_ocflags & SLAP_OC__END) \
? (((e)->e_ocflags & SLAP_OC_SYNCPROVIDERSUBENTRY) != 0) \
- : is_entry_objectclass((e), slap_schema.si_oc_syncProviderSubentry, 1))
+ : is_entry_objectclass((e), slap_schema.si_oc_syncProviderSubentry, SLAP_OCF_SET_FLAGS))
#define is_entry_syncConsumerSubentry(e) \
(((e)->e_ocflags & SLAP_OC__END) \
? (((e)->e_ocflags & SLAP_OC_SYNCCONSUMERSUBENTRY) != 0) \
- : is_entry_objectclass((e), slap_schema.si_oc_syncConsumerSubentry, 1))
+ : is_entry_objectclass((e), slap_schema.si_oc_syncConsumerSubentry, SLAP_OCF_SET_FLAGS))
LDAP_SLAPD_F (int) oc_schema_info( Entry *e );
LDAP_SLAPD_F (void) oc_unparse LDAP_P((
LDAP_SLAPD_F( slap_mr_indexer_func ) octetStringIndexer;
LDAP_SLAPD_F( slap_mr_filter_func ) octetStringFilter;
+LDAP_SLAPD_F( int ) numericoidValidate LDAP_P((
+ struct slap_syntax *syntax,
+ struct berval *in ));
+LDAP_SLAPD_F( int ) octetStringMatch LDAP_P((
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue ));
/*
* schema_prep.c
LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) gmtime_mutex;
#endif
+LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) ad_undef_mutex;
+LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) oc_undef_mutex;
+
LDAP_SLAPD_V (ber_socket_t) dtblsize;
LDAP_SLAPD_V (int) use_reverse_lookup;
err, sock_errstr(err), 0 );
if ( err != EWOULDBLOCK && err != EAGAIN ) {
- connection_closing( conn );
+ connection_closing( conn, "connection lost on write" );
ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
rs->sr_tag = req2res( op->o_tag );
rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0;
- send_ldap_response( op, rs );
+ if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) {
+ Statslog( LDAP_DEBUG_STATS,
+ "%s RESULT tag=%lu err=%d text=%s\n",
+ op->o_log_prefix, rs->sr_tag, rs->sr_err,
+ rs->sr_text ? rs->sr_text : "", 0 );
+ }
}
void
rs->sr_tag = req2res( op->o_tag );
rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0;
- send_ldap_response( op, rs );
+ if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) {
+ Statslog( LDAP_DEBUG_STATS,
+ "%s RESULT oid=%s err=%d text=%s\n",
+ op->o_log_prefix, rs->sr_rspoid ? rs->sr_rspoid : "",
+ rs->sr_err, rs->sr_text ? rs->sr_text : "", 0 );
+ }
}
void
rs->sr_rspdata != NULL ? rs->sr_rspdata->bv_len : 0 );
rs->sr_tag = LDAP_RES_INTERMEDIATE;
rs->sr_msgid = op->o_msgid;
- send_ldap_response( op, rs );
+ if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) {
+ Statslog( LDAP_DEBUG_STATS2,
+ "%s INTERM oid=%s\n",
+ op->o_log_prefix,
+ rs->sr_rspoid ? rs->sr_rspoid : "", 0, 0, 0 );
+ }
}
int
int finish = 0;
if ( rs->sr_attrs == NULL ) {
- /* all attrs request, skip operational attributes */
+ /* all user attrs request, skip operational attributes */
if( is_at_operational( desc->ad_type ) ) {
continue;
}
/* specific attrs requested */
if ( is_at_operational( desc->ad_type ) ) {
if ( !SLAP_OPATTRS( rs->sr_attr_flags ) &&
- !ad_inlist( desc, rs->sr_attrs ) )
+ !ad_inlist( desc, rs->sr_attrs ) )
{
continue;
}
} else {
- if ( !userattrs && !ad_inlist( desc, rs->sr_attrs ) )
- {
+ if ( !userattrs && !ad_inlist( desc, rs->sr_attrs ) ) {
continue;
}
}
AttributeDescription *desc = a->a_desc;
if ( rs->sr_attrs == NULL ) {
- /* all attrs request, skip operational attributes */
+ /* all user attrs request, skip operational attributes */
if( is_at_operational( desc->ad_type ) ) {
continue;
}
/* specific attrs requested */
if( is_at_operational( desc->ad_type ) ) {
if ( !SLAP_OPATTRS( rs->sr_attr_flags ) &&
- !ad_inlist( desc, rs->sr_attrs ) )
+ !ad_inlist( desc, rs->sr_attrs ) )
{
continue;
}
#ifdef LDAP_CONNECTIONLESS
}
#endif
+ if ( rs->sr_ref != NULL ) {
+ int r;
- Statslog( LDAP_DEBUG_STATS2, "%s REF dn=\"%s\"\n",
- op->o_log_prefix, rs->sr_entry ? rs->sr_entry->e_dn : "(null)",
- 0, 0, 0 );
+ for ( r = 0; !BER_BVISNULL( &rs->sr_ref[ r ] ); r++ ) {
+ Statslog( LDAP_DEBUG_STATS2, "%s REF #%d \"%s\"\n",
+ op->o_log_prefix, r, rs->sr_ref[0].bv_val,
+ 0, 0 );
+ }
+
+ } else {
+ Statslog( LDAP_DEBUG_STATS2, "%s REF \"(null)\"\n",
+ op->o_log_prefix, 0, 0, 0, 0 );
+ }
Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 );
#endif
static struct berval supportedFeatures[] = {
+ BER_BVC(LDAP_FEATURE_MODIFY_INCREMENT), /* Modify/increment */
BER_BVC(LDAP_FEATURE_ALL_OP_ATTRS), /* All Op Attrs (+) */
BER_BVC(LDAP_FEATURE_OBJECTCLASS_ATTRS), /* OCs in Attrs List (@class) */
BER_BVC(LDAP_FEATURE_ABSOLUTE_FILTERS), /* (&) and (|) search filters */
BER_BVC(LDAP_FEATURE_LANGUAGE_RANGE_OPTIONS),/* Language Range Options */
#ifdef LDAP_FEATURE_SUBORDINATE_SCOPE
BER_BVC(LDAP_FEATURE_SUBORDINATE_SCOPE), /* "children" search scope */
-#endif
-#ifdef LDAP_FEATURE_MODIFY_INCREMENT
- BER_BVC(LDAP_FEATURE_MODIFY_INCREMENT), /* Modify/increment */
#endif
{0,NULL}
};
"slap_ap_lookup: str2ad(%s): %s\n", name, text, 0 );
continue;
}
+
+ /* If it's the rootdn and a rootpw was present, we already set
+ * it so don't override it here.
+ */
+ if ( ad == slap_schema.si_ad_userPassword && sl->list[i].values &&
+ be_isroot_dn( op->o_bd, &op->o_req_ndn ))
+ continue;
+
a = attr_find( rs->sr_entry->e_attrs, ad );
if ( !a ) continue;
if ( ! access_allowed( op, rs->sr_entry, ad, NULL, ACL_AUTH, NULL ) ) {
op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
- if ( op.o_bd && op.o_bd->be_search ) {
- SlapReply rs = {REP_RESULT};
- op.o_hdr = conn->c_sasl_bindop->o_hdr;
- op.o_tag = LDAP_REQ_SEARCH;
- op.o_ndn = conn->c_ndn;
- op.o_callback = &cb;
- op.o_time = slap_get_time();
- op.o_do_not_cache = 1;
- op.o_is_auth_check = 1;
- op.o_req_dn = op.o_req_ndn;
- op.ors_scope = LDAP_SCOPE_BASE;
- op.ors_deref = LDAP_DEREF_NEVER;
- op.ors_tlimit = SLAP_NO_LIMIT;
- op.ors_slimit = 1;
- op.ors_filter = &generic_filter;
- op.ors_filterstr = generic_filterstr;
- /* FIXME: we want all attributes, right? */
- op.ors_attrs = NULL;
-
- op.o_bd->be_search( &op, &rs );
+ if ( op.o_bd ) {
+ /* For rootdn, see if we can use the rootpw */
+ if ( be_isroot_dn( op.o_bd, &op.o_req_ndn ) &&
+ !BER_BVISEMPTY( &op.o_bd->be_rootpw )) {
+ struct berval cbv = BER_BVNULL;
+
+ /* If there's a recognized scheme, see if it's CLEARTEXT */
+ if ( lutil_passwd_scheme( op.o_bd->be_rootpw.bv_val )) {
+ if ( !strncasecmp( op.o_bd->be_rootpw.bv_val,
+ sc_cleartext.bv_val, sc_cleartext.bv_len )) {
+
+ /* If it's CLEARTEXT, skip past scheme spec */
+ cbv.bv_len = op.o_bd->be_rootpw.bv_len -
+ sc_cleartext.bv_len;
+ if ( cbv.bv_len ) {
+ cbv.bv_val = op.o_bd->be_rootpw.bv_val +
+ sc_cleartext.bv_len;
+ }
+ }
+ /* No scheme, use the whole value */
+ } else {
+ cbv = op.o_bd->be_rootpw;
+ }
+ if ( !BER_BVISEMPTY( &cbv )) {
+ for( i = 0; sl.list[i].name; i++ ) {
+ const char *name = sl.list[i].name;
+
+ if ( name[0] == '*' ) {
+ if ( flags & SASL_AUXPROP_AUTHZID ) continue;
+ name++;
+ } else if ( !(flags & SASL_AUXPROP_AUTHZID ) )
+ continue;
+
+ if ( !strcasecmp(name,"userPassword") ) {
+ sl.sparams->utils->prop_set( sl.sparams->propctx,
+ sl.list[i].name, cbv.bv_val, cbv.bv_len );
+ break;
+ }
+ }
+ }
+ }
+
+ if ( op.o_bd->be_search ) {
+ SlapReply rs = {REP_RESULT};
+ op.o_hdr = conn->c_sasl_bindop->o_hdr;
+ op.o_tag = LDAP_REQ_SEARCH;
+ op.o_ndn = conn->c_ndn;
+ op.o_callback = &cb;
+ op.o_time = slap_get_time();
+ op.o_do_not_cache = 1;
+ op.o_is_auth_check = 1;
+ op.o_req_dn = op.o_req_ndn;
+ op.ors_scope = LDAP_SCOPE_BASE;
+ op.ors_deref = LDAP_DEREF_NEVER;
+ op.ors_tlimit = SLAP_NO_LIMIT;
+ op.ors_slimit = 1;
+ op.ors_filter = &generic_filter;
+ op.ors_filterstr = generic_filterstr;
+ /* FIXME: we want all attributes, right? */
+ op.ors_attrs = NULL;
+
+ op.o_bd->be_search( &op, &rs );
+ }
}
}
}
}
/* Grab the searchbase */
- assert( ludp->lud_dn );
+ assert( ludp->lud_dn != NULL );
ber_str2bv( ludp->lud_dn, 0, 0, &bv );
rc = dnValidate( NULL, &bv );
}
/* Grab the searchbase */
- assert( ludp->lud_dn );
+ assert( ludp->lud_dn != NULL );
if ( ludp->lud_dn ) {
struct berval out = BER_BVNULL;
objectclass ( 1.3.6.1.1.1.2.2 NAME 'posixGroup'
DESC 'Abstraction of a group of accounts'
- SUP top AUXILIARY
+ SUP top STRUCTURAL
MUST ( cn $ gidNumber )
MAY ( userPassword $ memberUid $ description ) )
#define HASH_Update(c,buf,len) lutil_HASHUpdate(c,buf,len)
#define HASH_Final(d,c) lutil_HASHFinal(d,c)
-#define OpenLDAPaciMatch NULL
-
/* approx matching rules */
#define directoryStringApproxMatchOID "1.3.6.1.4.1.4203.666.4.4"
#define directoryStringApproxMatch approxMatch
unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
+ldap_pvt_thread_mutex_t ad_undef_mutex;
+ldap_pvt_thread_mutex_t oc_undef_mutex;
+
static int
inValidate(
Syntax *syntax,
#define certificateValidate sequenceValidate
#endif
-static int
+int
octetStringMatch(
int *matchp,
slap_mask_t flags,
return LDAP_SUCCESS;
}
-static int
+int
numericoidValidate(
Syntax *syntax,
struct berval *in )
serialNumberAndIssuerValidate,
serialNumberAndIssuerPretty},
-#ifdef SLAPD_ACI_ENABLED
- /* OpenLDAP Experimental Syntaxes */
- {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
- SLAP_SYNTAX_HIDE,
- UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
- NULL},
-#endif
-
#ifdef SLAPD_AUTHPASSWD
/* needs updating */
{"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
NULL},
#endif
-#ifdef SLAPD_ACI_ENABLED
- {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
- "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
- SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
- NULL, NULL, OpenLDAPaciMatch,
- NULL, NULL,
- NULL},
-#endif
-
{"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
SLAP_MR_EXT, NULL,
mr_destroy();
mru_destroy();
syn_destroy();
+
+ ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
+ ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
}
"ORDERING UUIDOrderingMatch "
"SYNTAX 1.3.6.1.4.1.4203.666.2.6 "
"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
- NULL, SLAP_AT_HIDE,
+ NULL, SLAP_AT_HIDE|SLAP_AT_MANAGEABLE,
NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
offsetof(struct slap_internal_schema, si_ad_entryUUID) },
NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
offsetof(struct slap_internal_schema, si_ad_saslAuthzFrom) },
-#ifdef SLAPD_ACI_ENABLED
- { "OpenLDAPaci", "( 1.3.6.1.4.1.4203.666.1.5 "
- "NAME 'OpenLDAPaci' "
- "DESC 'OpenLDAP access control information (experimental)' "
- "EQUALITY OpenLDAPaciMatch "
- "SYNTAX 1.3.6.1.4.1.4203.666.2.1 "
- "USAGE directoryOperation )",
- NULL, SLAP_AT_HIDE,
- NULL, NULL,
- NULL, NULL, NULL, NULL, NULL,
- offsetof(struct slap_internal_schema, si_ad_aci) },
-#endif
#ifdef LDAP_DYNAMIC_OBJECTS
{ "entryTtl", "( 1.3.6.1.4.1.1466.101.119.3 NAME 'entryTtl' "
};
static AttributeType slap_at_undefined = {
- { "1.1.1", NULL, NULL, 1, NULL,
+ { "1.1.1", NULL, "Catchall for undefined attribute types", 1, NULL,
NULL, NULL, NULL, NULL,
- 0, 0, 0, 1, 3, NULL }, /* LDAPAttributeType */
+ 0, 0, 0, 1, LDAP_SCHEMA_DSA_OPERATION, NULL }, /* LDAPAttributeType */
BER_BVC("UNDEFINED"), /* cname */
NULL, /* sup */
NULL, /* subtypes */
}
}
+ slap_at_undefined.sat_syntax = slap_schema.si_syn_octetString;
+ slap_schema.si_at_undefined = &slap_at_undefined;
+
+ ldap_pvt_thread_mutex_init( &ad_undef_mutex );
+ ldap_pvt_thread_mutex_init( &oc_undef_mutex );
+
for( i=0; ad_map[i].ssam_name; i++ ) {
assert( ad_map[i].ssam_defn != NULL );
{
}
}
- slap_at_undefined.sat_syntax = slap_schema.si_syn_octetString;
- slap_schema.si_at_undefined = &slap_at_undefined;
-
return LDAP_SUCCESS;
}
LDAP_STAILQ_ENTRY(slap_object_class) soc_next;
} ObjectClass;
+#define SLAP_OCF_SET_FLAGS 0x1
+#define SLAP_OCF_CHECK_SUP 0x2
+#define SLAP_OCF_MASK (SLAP_OCF_SET_FLAGS|SLAP_OCF_CHECK_SUP)
+
#define SLAP_OC_ALIAS 0x0001
#define SLAP_OC_REFERRAL 0x0002
#define SLAP_OC_SUBENTRY 0x0004
AttributeDescription *si_ad_children;
AttributeDescription *si_ad_saslAuthzTo;
AttributeDescription *si_ad_saslAuthzFrom;
-#ifdef SLAPD_ACI_ENABLED
- AttributeDescription *si_ad_aci;
-#endif /* SLAPD_ACI_ENABLED */
/* dynamic entries */
AttributeDescription *si_ad_entryTtl;
#endif
AttributeDescription *si_ad_description;
AttributeDescription *si_ad_seeAlso;
-
+
/* Undefined Attribute Type */
AttributeType *si_at_undefined;
* running as non-root user, for user modifiable attributes.
*/
#define SLAP_MOD_INTERNAL 0x01
+#define SLAP_MOD_MANAGING 0x02
AttributeDescription *sm_desc;
struct berval sm_type;
/*
* "dynamic" ACL infrastructure (for ACIs and more)
*/
-typedef int (slap_dynacl_parse)( const char *fname, int lineno, slap_style_t, const char *, void **privp );
-typedef int (slap_dynacl_unparse)( void *priv, struct berval *bv );
-typedef int (slap_dynacl_mask)(
+typedef int (slap_dynacl_parse) LDAP_P(( const char *fname, int lineno,
+ const char *opts, slap_style_t, const char *, void **privp ));
+typedef int (slap_dynacl_unparse) LDAP_P(( void *priv, struct berval *bv ));
+typedef int (slap_dynacl_mask) LDAP_P((
void *priv,
struct slap_op *op,
Entry *e,
int nmatch,
regmatch_t *matches,
slap_access_t *grant,
- slap_access_t *deny );
-typedef int (slap_dynacl_destroy)( void *priv );
+ slap_access_t *deny ));
+typedef int (slap_dynacl_destroy) LDAP_P(( void *priv ));
typedef struct slap_dynacl_t {
char *da_name;
#define ACL_STATE_INIT { ACL_STATE_NOT_RECORDED, NULL, NULL, 0UL, \
{ { 0, 0 } }, 0, NULL, 0, 0, NULL }
+#ifdef SLAPD_ACI_ENABLED
+typedef enum slap_aci_scope_t {
+ SLAP_ACI_SCOPE_ENTRY = 0x1,
+ SLAP_ACI_SCOPE_CHILDREN = 0x2,
+ SLAP_ACI_SCOPE_SUBTREE = ( SLAP_ACI_SCOPE_ENTRY | SLAP_ACI_SCOPE_CHILDREN )
+} slap_aci_scope_t;
+#endif /* SLAPD_ACI_ENABLED */
+
+enum {
+ ACI_BV_ENTRY,
+ ACI_BV_CHILDREN,
+ ACI_BV_ONELEVEL,
+ ACI_BV_SUBTREE,
+ ACI_BV_BR_ENTRY,
+ ACI_BV_BR_ALL,
+ ACI_BV_ACCESS_ID,
+#if 0
+ ACI_BV_ANONYMOUS = BER_BVC("anonymous"),
+#endif
+ ACI_BV_PUBLIC,
+ ACI_BV_USERS,
+ ACI_BV_SELF,
+ ACI_BV_DNATTR,
+ ACI_BV_GROUP,
+ ACI_BV_ROLE,
+ ACI_BV_SET,
+ ACI_BV_SET_REF,
+ ACI_BV_GRANT,
+ ACI_BV_DENY,
+
+ ACI_BV_IP_EQ,
+#ifdef LDAP_PF_LOCAL
+ ACI_BV_PATH_EQ,
+#if 0
+ ACI_BV_DIRSEP,
+#endif
+#endif /* LDAP_PF_LOCAL */
+
+ ACI_BV_GROUP_CLASS,
+ ACI_BV_GROUP_ATTR,
+ ACI_BV_ROLE_CLASS,
+ ACI_BV_ROLE_ATTR,
+ ACI_BV_SET_ATTR,
+
+ ACI_BV_LAST
+};
+
/*
* Backend-info
* represents a backend
int c_struct_state; /* structure management state */
int c_conn_state; /* connection state */
int c_conn_idx; /* slot in connections array */
+ const char *c_close_reason; /* why connection is closing */
ldap_pvt_thread_mutex_t c_mutex; /* protect the connection */
Sockbuf *c_sb; /* ber connection stuff */
#define sl_addr sl_sa.sa_in_addr
};
-#ifdef SLAPD_MONITOR
/*
* Operation indices
*/
SLAP_OP_EXTENDED,
SLAP_OP_LAST
};
-#endif /* SLAPD_MONITOR */
typedef struct slap_counters_t {
ldap_pvt_thread_mutex_t sc_sent_mutex;
exit( EXIT_FAILURE );
}
+#ifdef SLAP_DYNACL
+ if ( acl_init() ) {
+ fprintf( stderr, "%s: acl_init failed!\n", progname );
+ exit( EXIT_FAILURE );
+ }
+#endif /* SLAP_DYNACL */
+
rc = read_config( conffile, confdir );
if ( rc != 0 ) {
{
struct berval parent_dn;
- dnParent( (struct berval *)&sdn->dn, &parent_dn );
-
- slapi_sdn_set_dn_byval( sdn_parent, parent_dn.bv_val );
+ if ( !(sdn->flag & FLAG_DN) ) {
+ dnParent( (struct berval *)&sdn->ndn, &parent_dn );
+ slapi_sdn_set_ndn_byval( sdn_parent, parent_dn.bv_val );
+ } else {
+ dnParent( (struct berval *)&sdn->dn, &parent_dn );
+ slapi_sdn_set_dn_byval( sdn_parent, parent_dn.bv_val );
+ }
}
void slapi_sdn_get_backend_parent( const Slapi_DN *sdn,
PBLOCK_ASSERT_OP( pb, 0 );
op = pb->pb_op;
- if ( op->o_bd != frontendDB ) {
+ if ( !be_match( op->o_bd, frontendDB ) ) {
rc = slapi_int_call_plugins( frontendDB, type, pb );
}
if ( rc >= 0 ) {
case SLAPI_X_GROUP_ATTRIBUTE:
case SLAPI_X_GROUP_OPERATION_DN:
case SLAPI_X_GROUP_TARGET_ENTRY:
+ case SLAPI_X_ADD_STRUCTURAL_CLASS:
case SLAPI_PLUGIN_AUDIT_DATA:
case SLAPI_IBM_PBLOCK:
case SLAPI_PLUGIN_VERSION:
PBLOCK_ASSERT_OP( pb, 0 );
*((int *)value) = get_no_schema_check( pb->pb_op );
break;
+ case SLAPI_X_ADD_STRUCTURAL_CLASS:
+ PBLOCK_ASSERT_OP( pb, 0 );
+
+ if ( pb->pb_op->o_tag == LDAP_REQ_ADD ) {
+ struct berval tmpval = BER_BVNULL;
+
+ rc = mods_structural_class( pb->pb_op->ora_modlist,
+ &tmpval, &pb->pb_rs->sr_text,
+ pb->pb_textbuf, sizeof( pb->pb_textbuf ));
+ *((char **)value) = tmpval.bv_val;
+ } else {
+ rc = PBLOCK_ERROR;
+ }
+ break;
case SLAPI_REQCONTROLS:
PBLOCK_ASSERT_OP( pb, 0 );
*((LDAPControl ***)value) = pb->pb_op->o_ctrls;
case SLAPI_X_CONN_CLIENTPATH:
case SLAPI_CONN_SERVERIP:
case SLAPI_X_CONN_SERVERPATH:
+ case SLAPI_X_ADD_STRUCTURAL_CLASS:
/* These parameters cannot be set */
rc = PBLOCK_ERROR;
break;
{
int rc;
+ Statslog( LDAP_DEBUG_STATS, "%s STARTTLS\n",
+ op->o_log_prefix, 0, 0, 0, 0 );
+
if ( op->ore_reqdata != NULL ) {
/* no request data should be provided */
rs->sr_text = "no request data expected";
rctrlp = *rctrls;
ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID );
+ /* FIXME: what if syncUUID is NULL or empty? */
if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
ber_scanf( ber, /*"{"*/ "m}", &cookie );
if ( !BER_BVISNULL( &cookie ) ) {
code = syn_add( syn, def, &err );
- ldap_memfree( syn );
-
if ( code ) {
Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s %s in %s\n",
scherr2str(code), err, def->sd_desc );
+ ldap_syntax_free( syn );
return( -1 );
}
+ ldap_memfree( syn );
+
return( 0 );
}
-$(RM) -r testrun *leak *gmon *core
veryclean-local: FORCE
- @-$(RM) run data schema ucdata
+ @-$(RM) run testdata schema ucdata
--- /dev/null
+# Searching "dc=example,dc=com" (should fail)...
+# Searching "dc=example,dc=com" (should succeed with no results)...
+# Searching "dc=example,dc=com" as "cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com" (should succeed)...
+dn: dc=example,dc=com
+objectClass: top
+objectClass: organization
+objectClass: domainRelatedObject
+objectClass: dcObject
+dc: example
+l: Anytown, Michigan
+st: Michigan
+o: Example, Inc.
+o: EX
+o: Ex.
+description: The Example, Inc. at Anytown
+postalAddress: Example, Inc. $ 535 W. William St. $ Anytown, MI 48109 $ US
+telephoneNumber: +1 313 555 1817
+associatedDomain: example.com
+
+# Searching "ou=Groups,dc=example,dc=com" as "cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc=com" (should succeed)...
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+member: cn=Manager,dc=example,dc=com
+member: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=exam
+ ple,dc=com
+member: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc
+ =com
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=James A Jones 2,ou=Information Technology Division,ou=People,dc=exa
+ mple,dc=com
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=exampl
+ e,dc=com
+owner: cn=Manager,dc=example,dc=com
+cn: All Staff
+description: Everyone in the sample data
+objectClass: groupOfNames
+
+dn: cn=Alumni Assoc Staff,ou=Groups,dc=example,dc=com
+member: cn=Manager,dc=example,dc=com
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com
+owner: cn=Manager,dc=example,dc=com
+description: All Alumni Assoc Staff
+cn: Alumni Assoc Staff
+objectClass: groupOfNames
+
+dn: cn=ITD Staff,ou=Groups,dc=example,dc=com
+owner: cn=Manager,dc=example,dc=com
+description: All ITD Staff
+cn: ITD Staff
+objectClass: groupOfUniqueNames
+uniqueMember: cn=Manager,dc=example,dc=com
+uniqueMember: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=
+ example,dc=com
+uniqueMember: cn=James A Jones 2,ou=Information Technology Division,ou=People,
+ dc=example,dc=com
+uniqueMember: cn=John Doe,ou=Information Technology Division,ou=People,dc=exam
+ ple,dc=com
+
+# Searching "ou=Groups,dc=example,dc=com" as "cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com" (should succeed with no results)...
+dn: cn=All Staff,dc=example,dc=com
+objectClass: groupOfNames
+cn: All Staff
+member:
+creatorsName: cn=Someone
+modifiersName: cn=Someone Else
+
dn: cn=All Staff,ou=Groups,dc=example,dc=com
member: cn=Manager,dc=example,dc=com
member: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=exam
uniqueMember: cn=John Doe,ou=Information Technology Division,ou=People,dc=exam
ple,dc=com
creatorsName: cn=Manager,dc=example,dc=com
-modifiersName: cn=Manager,dc=example,dc=com
+modifiersName: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc
+ =example,dc=com
dn: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com
objectClass: OpenLDAPperson
creatorsName: cn=Manager,dc=example,dc=com
modifiersName: cn=Manager,dc=example,dc=com
+dn: dc=example,dc=com
+objectClass: top
+objectClass: organization
+objectClass: domainRelatedObject
+objectClass: dcObject
+dc: example
+l: Anytown, Michigan
+st: Michigan
+o: Example, Inc.
+o: EX
+o: Ex.
+description: The Example, Inc. at Anytown
+postalAddress: Example, Inc. $ 535 W. William St. $ Anytown, MI 48109 $ US
+telephoneNumber: +1 313 555 1817
+associatedDomain: example.com
+creatorsName: cn=Manager,dc=example,dc=com
+modifyTimestamp: 19700101000000Z
+createTimestamp: 19700101000000Z
+modifiersName: cn=Manager,dc=example,dc=com
+
+dn: cn=All Staff,dc=example,dc=com
+objectClass: groupOfNames
+cn: All Staff
+member:
+entryUUID: badbadef-dbad-1029-92f7-badbadbadbad
+
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+member: cn=Manager,dc=example,dc=com
+member: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=exam
+ ple,dc=com
+member: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc
+ =com
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=James A Jones 2,ou=Information Technology Division,ou=People,dc=exa
+ mple,dc=com
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=exampl
+ e,dc=com
+owner: cn=Manager,dc=example,dc=com
+cn: All Staff
+description: Everyone in the sample data
+objectClass: groupOfNames
+entryUUID: badbadba-dbad-1029-92f7-badbadbadbad
+
retcode-item "cn=strongerAuthRequired" 0x08 text="same as strongAuthRequired"
#retcode-item "cn=partialResults" 0x09 "LDAPv2+ (not LDAPv3)"
-retcode-item "cn=referral" 0x0a text="LDAPv3"
+retcode-item "cn=referral" 0x0a text="LDAPv3" ref="ldap://:9019"
retcode-item "cn=adminLimitExceeded" 0x0b text="LDAPv3"
retcode-item "cn=unavailableCriticalExtension" 0x0c text="LDAPv3"
retcode-item "cn=confidentialityRequired" 0x0d text="LDAPv3"
--- /dev/null
+# stand-alone slapd config -- for testing (with indexing)
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2005 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+include ./schema/core.schema
+include ./schema/cosine.schema
+include ./schema/inetorgperson.schema
+include ./schema/openldap.schema
+include ./schema/nis.schema
+include ./testdata/test.schema
+
+#
+pidfile ./testrun/slapd.1.pid
+argsfile ./testrun/slapd.1.args
+
+#mod#modulepath ../servers/slapd/back-@BACKEND@/
+#mod#moduleload back_@BACKEND@.la
+#monitormod#modulepath ../servers/slapd/back-monitor/
+#monitormod#moduleload back_monitor.la
+
+#######################################################################
+# database definitions
+#######################################################################
+
+access to dn=""
+ by * read
+access to dn="cn=Subschema"
+ by * read
+
+database @BACKEND@
+suffix "dc=example,dc=com"
+directory ./testrun/db.1.a
+rootdn "cn=Manager,dc=example,dc=com"
+rootpw secret
+#bdb#index objectClass eq
+#bdb#index cn,sn,uid pres,eq,sub
+#hdb#index objectClass eq
+#hdb#index cn,sn,uid pres,eq,sub
+#ldbm#index objectClass eq
+#ldbm#index cn,sn,uid pres,eq,sub
+
+access to dn.subtree="dc=example,dc=com"
+ by aci write
+
+#monitor#database monitor
+
--- /dev/null
+# stand-alone slapd config -- for testing (with unique overlay)
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2004-2005 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+include ./schema/core.schema
+include ./schema/cosine.schema
+include ./schema/inetorgperson.schema
+include ./schema/openldap.schema
+
+#
+pidfile ./testrun/slapd.1.pid
+argsfile ./testrun/slapd.1.args
+
+#mod#modulepath ../servers/slapd/back-@BACKEND@/
+#mod#moduleload back_@BACKEND@.la
+#monitormod#modulepath ../servers/slapd/back-monitor/
+#monitormod#moduleload back_monitor.la
+#valsortmod#moduleload ../servers/slapd/overlays/valsort.la
+
+#######################################################################
+# database definitions
+#######################################################################
+
+database @BACKEND@
+suffix "o=valsort"
+directory ./testrun/db.1.a
+rootdn "cn=Manager,o=valsort"
+rootpw secret
+#bdb#index objectClass eq
+#bdb#index cn,sn,uid pres,eq,sub
+#hdb#index objectClass eq
+#hdb#index cn,sn,uid pres,eq,sub
+#ldbm#index objectClass eq
+#ldbm#index cn,sn,uid pres,eq,sub
+
+overlay valsort
+valsort-attr sn ou=users,o=valsort alpha-ascend
+valsort-attr departmentNumber ou=users,o=valsort alpha-ascend
+valsort-attr mailPreferenceOption ou=users,o=valsort numeric-ascend
+valsort-attr ou ou=users,o=valsort weighted
+valsort-attr employeeType ou=users,o=valsort weighted alpha-ascend
+
+database config
+rootpw secret
+
+#monitor#database monitor
--- /dev/null
+# Searching all database (after add)...
+dn: ou=Another parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Another parent
+
+dn: ou=Child,ou=Parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Child
+
+dn: dc=example,dc=com
+objectClass: organization
+objectClass: dcObject
+o: Example, Inc.
+dc: example
+
+dn: ou=Grandchild,ou=Child,ou=Parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Grandchild
+
+dn: ou=Parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Parent
+
+# Searching all database (after PASS1)...
+dn: ou=Another parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Another parent
+
+dn: dc=example,dc=com
+objectClass: organization
+objectClass: dcObject
+o: Example, Inc.
+dc: example
+
+dn: ou=Grandchild,ou=Renamed child,ou=Parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Grandchild
+
+dn: ou=Parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Parent
+
+dn: ou=Renamed child,ou=Parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Child
+ou: Renamed child
+
+# Searching all database (after PASS2)...
+dn: ou=Another parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Another parent
+
+dn: dc=example,dc=com
+objectClass: organization
+objectClass: dcObject
+o: Example, Inc.
+dc: example
+
+dn: ou=Grandchild,ou=Renamed child,ou=Renamed parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Grandchild
+
+dn: ou=Renamed child,ou=Renamed parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Child
+ou: Renamed child
+
+dn: ou=Renamed parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Parent
+ou: Renamed parent
+
+# Searching all database (after PASS3)...
+dn: ou=Another parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Another parent
+
+dn: dc=example,dc=com
+objectClass: organization
+objectClass: dcObject
+o: Example, Inc.
+dc: example
+
+dn: ou=Grandchild,ou=Renamed child,ou=Another parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Grandchild
+
+dn: ou=Renamed child,ou=Another parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Child
+ou: Renamed child
+
+dn: ou=Renamed parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Parent
+ou: Renamed parent
+
--- /dev/null
+# base
+
+dn: o=valsort
+objectClass: top
+objectClass: organization
+o: valsort
+description: valsort test database
+
+# container
+
+dn: ou=users,o=valsort
+objectClass: top
+objectClass: organizationalUnit
+ou: users
+description: container for test valsort users
+
+# manager
+dn: uid=george,ou=users,o=valsort
+objectClass: OpenLDAPperson
+uid: george
+sn: jungle
+sn: alpha
+sn: zib
+sn: tree
+cn: george
+businessCategory: test
+carLicense: SAMPLE
+departmentNumber: 1
+departmentNumber: 5
+departmentNumber: 3
+departmentNumber: 10
+departmentNumber: 72
+departmentNumber: 37
+departmentNumber: 46
+displayName: George
+employeeNumber: 5150
+employeeType: {1}contractor
+employeeType: {1}staff
+employeeType: {1}anarchist
+givenName: Big G
+ou: {1}Chemistry
+ou: {8}Academia
+ou: {3}Hum Bio
+ou: {2}Computer Science
+mailPreferenceOption: 3
+mailPreferenceOption: 87
+mailPreferenceOption: 22
+mailPreferenceOption: 1
+mailPreferenceOption: 66
--- /dev/null
+dn: o=valsort
+objectClass: top
+objectClass: organization
+o: valsort
+description: valsort test database
+
+dn: ou=users,o=valsort
+objectClass: top
+objectClass: organizationalUnit
+ou: users
+description: container for test valsort users
+
+dn: uid=george,ou=users,o=valsort
+objectClass: OpenLDAPperson
+uid: george
+sn: alpha
+sn: jungle
+sn: tree
+sn: zib
+cn: george
+businessCategory: test
+carLicense: SAMPLE
+departmentNumber: 1
+departmentNumber: 10
+departmentNumber: 3
+departmentNumber: 37
+departmentNumber: 46
+departmentNumber: 5
+departmentNumber: 72
+displayName: George
+employeeNumber: 5150
+employeeType: anarchist
+employeeType: contractor
+employeeType: staff
+givenName: Big G
+ou: Chemistry
+ou: Computer Science
+ou: Hum Bio
+ou: Academia
+mailPreferenceOption: 1
+mailPreferenceOption: 3
+mailPreferenceOption: 22
+mailPreferenceOption: 66
+mailPreferenceOption: 87
+
--- /dev/null
+dn: o=valsort
+objectClass: top
+objectClass: organization
+o: valsort
+description: valsort test database
+
+dn: ou=users,o=valsort
+objectClass: top
+objectClass: organizationalUnit
+ou: users
+description: container for test valsort users
+
+dn: uid=george,ou=users,o=valsort
+objectClass: OpenLDAPperson
+uid: george
+sn: zib
+sn: tree
+sn: jungle
+sn: alpha
+cn: george
+businessCategory: test
+carLicense: SAMPLE
+departmentNumber: 72
+departmentNumber: 5
+departmentNumber: 46
+departmentNumber: 37
+departmentNumber: 3
+departmentNumber: 10
+departmentNumber: 1
+displayName: George
+employeeNumber: 5150
+employeeType: staff
+employeeType: contractor
+employeeType: anarchist
+givenName: Big G
+ou: Chemistry
+ou: Computer Science
+ou: Hum Bio
+ou: Academia
+mailPreferenceOption: 87
+mailPreferenceOption: 66
+mailPreferenceOption: 22
+mailPreferenceOption: 3
+mailPreferenceOption: 1
+
--- /dev/null
+dn: o=valsort
+objectClass: top
+objectClass: organization
+o: valsort
+description: valsort test database
+
+dn: ou=users,o=valsort
+objectClass: top
+objectClass: organizationalUnit
+ou: users
+description: container for test valsort users
+
+dn: uid=george,ou=users,o=valsort
+objectClass: OpenLDAPperson
+uid: george
+sn: zib
+sn: tree
+sn: jungle
+sn: alpha
+cn: george
+businessCategory: test
+carLicense: SAMPLE
+departmentNumber: 72
+departmentNumber: 5
+departmentNumber: 46
+departmentNumber: 37
+departmentNumber: 3
+departmentNumber: 10
+departmentNumber: 1
+displayName: George
+employeeNumber: 5150
+employeeType: staff
+employeeType: contractor
+employeeType: anarchist
+givenName: Big G
+ou: Chemistry
+ou: Computer Science
+ou: Hum Bio
+ou: Academia
+mailPreferenceOption: 87
+mailPreferenceOption: 66
+mailPreferenceOption: 22
+mailPreferenceOption: 3
+mailPreferenceOption: 1
+
+dn: uid=dave,ou=users,o=valsort
+objectClass: OpenLDAPperson
+uid: dave
+sn: nothere
+cn: dave
+businessCategory: otest
+carLicense: TEST
+departmentNumber: 42
+displayName: Dave
+employeeNumber: 69
+employeeType: contractor
+givenName: Dave
+ou: Test
+ou: Is
+ou: Okay
+
static void
do_addel( char *uri, char *host, int port, char *manager, char *passwd,
- char *dn, LDAPMod **attrs, int maxloop, int maxretries );
+ char *dn, LDAPMod **attrs, int maxloop, int maxretries, int delay );
static void
usage( char *name )
{
- fprintf( stderr, "usage: %s [-h <host>] -p port -D <managerDN> -w <passwd> -f <addfile> [-l <loops>]\n",
+ fprintf( stderr,
+ "usage: %s "
+ "-H <uri> | ([-h <host>] -p <port>) "
+ "-D <manager> "
+ "-w <passwd> "
+ "-f <addfile> "
+ "[-l <loops>] "
+ "[-r <maxretries>] "
+ "[-t <delay>]\n",
name );
exit( EXIT_FAILURE );
}
char *entry = NULL;
int loops = LOOPS;
int retries = RETRIES;
+ int delay = 0;
LDAPMod **attrs = NULL;
- while ( (i = getopt( argc, argv, "H:h:p:D:w:f:l:r:" )) != EOF ) {
+ while ( (i = getopt( argc, argv, "H:h:p:D:w:f:l:r:t:" )) != EOF ) {
switch( i ) {
case 'H': /* the server's URI */
uri = strdup( optarg );
loops = atoi( optarg );
break;
- case 'r':
+ case 'r': /* number of retries */
retries = atoi( optarg );
break;
+ case 't': /* delay in seconds */
+ delay = atoi( optarg );
+ break;
+
default:
usage( argv[0] );
break;
}
do_addel( uri, host, port, manager, passwd, entry, attrs,
- loops, retries );
+ loops, retries, delay );
exit( EXIT_SUCCESS );
}
char *entry,
LDAPMod **attrs,
int maxloop,
- int maxretries
+ int maxretries,
+ int delay
)
{
LDAP *ld = NULL;
rc = ldap_bind_s( ld, manager, passwd, LDAP_AUTH_SIMPLE );
if ( rc != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_bind" );
- if ( rc == LDAP_BUSY && do_retry > 0 ) {
- do_retry--;
- goto retry;
+ switch ( rc ) {
+ case LDAP_BUSY:
+ case LDAP_UNAVAILABLE:
+ if ( do_retry > 0 ) {
+ do_retry--;
+ if ( delay != 0 ) {
+ sleep( delay );
+ }
+ goto retry;
+ }
+ /* fallthru */
+ default:
+ break;
}
exit( EXIT_FAILURE );
}
static void
do_modify( char *uri, char *host, int port, char *manager, char *passwd,
char *entry, char *attr, char *value, int maxloop,
- int maxretries );
+ int maxretries, int delay );
static void
usage( char *name )
{
- fprintf( stderr, "usage: %s [-h <host>] -p port -D <managerDN> -w <passwd> -e <entry> [-l <loops>]\n",
+ fprintf( stderr,
+ "usage: %s "
+ "-H <uri> | ([-h <host>] -p <port>) "
+ "-D <manager> "
+ "-w <passwd> "
+ "-e <entry> "
+ "[-l <loops>] "
+ "[-r <maxretries>] "
+ "[-t <delay>]\n",
name );
exit( EXIT_FAILURE );
}
char *value = NULL;
int loops = LOOPS;
int retries = RETRIES;
+ int delay = 0;
- while ( (i = getopt( argc, argv, "H:h:p:D:w:e:a:l:r:" )) != EOF ) {
+ while ( (i = getopt( argc, argv, "H:h:p:D:w:e:a:l:r:t:" )) != EOF ) {
switch( i ) {
case 'H': /* the server uri */
uri = strdup( optarg );
loops = atoi( optarg );
break;
- case 'r':
+ case 'r': /* number of retries */
retries = atoi( optarg );
break;
+ case 't': /* delay in seconds */
+ delay = atoi( optarg );
+ break;
+
default:
usage( argv[0] );
break;
value++;
do_modify( uri, host, port, manager, passwd, entry, ava, value,
- loops, retries );
+ loops, retries, delay );
exit( EXIT_SUCCESS );
}
static void
do_modify( char *uri, char *host, int port, char *manager,
char *passwd, char *entry, char* attr, char* value,
- int maxloop, int maxretries )
+ int maxloop, int maxretries, int delay )
{
LDAP *ld = NULL;
int i = 0, do_retry = maxretries;
rc = ldap_bind_s( ld, manager, passwd, LDAP_AUTH_SIMPLE );
if ( rc != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_bind" );
- if ( rc == LDAP_BUSY && do_retry > 0 ) {
- do_retry--;
- goto retry;
+ switch ( rc ) {
+ case LDAP_BUSY:
+ case LDAP_UNAVAILABLE:
+ if ( do_retry > 0 ) {
+ do_retry--;
+ if ( delay > 0 ) {
+ sleep( delay );
+ }
+ goto retry;
+ }
+ /* fallthru */
+ default:
+ break;
}
exit( EXIT_FAILURE );
}
static void
do_modrdn( char *uri, char *host, int port, char *manager, char *passwd,
- char *entry, int maxloop, int maxretries );
+ char *entry, int maxloop, int maxretries, int delay );
static void
usage( char *name )
{
- fprintf( stderr, "usage: %s [-h <host>] -p port -D <managerDN> -w <passwd> -e <entry> [-l <loops>]\n",
+ fprintf( stderr,
+ "usage: %s "
+ "-H <uri> | ([-h <host>] -p <port>) "
+ "-D <manager> "
+ "-w <passwd> "
+ "-e <entry> "
+ "[-l <loops>] "
+ "[-r <maxretries>] "
+ "[-t <delay>]\n",
name );
exit( EXIT_FAILURE );
}
char *entry = NULL;
int loops = LOOPS;
int retries = RETRIES;
+ int delay = 0;
- while ( (i = getopt( argc, argv, "H:h:p:D:w:e:l:r:" )) != EOF ) {
+ while ( (i = getopt( argc, argv, "H:h:p:D:w:e:l:r:t:" )) != EOF ) {
switch( i ) {
case 'H': /* the server uri */
uri = strdup( optarg );
retries = atoi( optarg );
break;
+ case 't': /* delay in seconds */
+ delay = atoi( optarg );
+ break;
+
default:
usage( argv[0] );
break;
}
- do_modrdn( uri, host, port, manager, passwd, entry, loops, retries );
+ do_modrdn( uri, host, port, manager, passwd, entry, loops, retries, delay );
exit( EXIT_SUCCESS );
}
static void
do_modrdn( char *uri, char *host, int port, char *manager,
- char *passwd, char *entry, int maxloop, int maxretries )
+ char *passwd, char *entry, int maxloop, int maxretries, int delay )
{
LDAP *ld = NULL;
int i = 0, do_retry = maxretries;
rc = ldap_bind_s( ld, manager, passwd, LDAP_AUTH_SIMPLE );
if ( rc != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_bind" );
- if ( rc == LDAP_BUSY && do_retry > 0 ) {
- do_retry--;
- goto retry;
+ switch ( rc ) {
+ case LDAP_BUSY:
+ case LDAP_UNAVAILABLE:
+ if ( do_retry > 0 ) {
+ do_retry--;
+ if ( delay > 0) {
+ sleep( delay );
+ }
+ goto retry;
+ }
+ /* fallthru */
+ default:
+ break;
}
exit( EXIT_FAILURE );
}
static void
do_read( char *uri, char *host, int port, char *entry, int maxloop,
- int maxretries );
+ int maxretries, int delay );
static void
usage( char *name )
{
- fprintf( stderr, "usage: %s [-h <host>] -p port -e <entry> [-l <loops>]\n",
+ fprintf( stderr,
+ "usage: %s "
+ "-H <uri> | ([-h <host>] -p <port>) "
+ "-e <entry> "
+ "[-l <loops>] "
+ "[-r <maxretries>] "
+ "[-t <delay>]\n",
name );
exit( EXIT_FAILURE );
}
char *entry = NULL;
int loops = LOOPS;
int retries = RETRIES;
+ int delay = 0;
- while ( (i = getopt( argc, argv, "H:h:p:e:l:r:" )) != EOF ) {
+ while ( (i = getopt( argc, argv, "H:h:p:e:l:r:t:" )) != EOF ) {
switch( i ) {
case 'H': /* the server uri */
uri = strdup( optarg );
retries = atoi( optarg );
break;
+ case 't': /* delay in seconds */
+ delay = atoi( optarg );
+ break;
+
default:
usage( argv[0] );
break;
exit( EXIT_FAILURE );
}
- do_read( uri, host, port, entry, ( 20 * loops ), retries );
+ do_read( uri, host, port, entry, ( 20 * loops ), retries, delay );
exit( EXIT_SUCCESS );
}
static void
do_read( char *uri, char *host, int port, char *entry, int maxloop,
- int maxretries )
+ int maxretries, int delay )
{
LDAP *ld = NULL;
int i = 0, do_retry = maxretries;
rc = ldap_bind_s( ld, NULL, NULL, LDAP_AUTH_SIMPLE );
if ( rc != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_bind" );
- if ( rc == LDAP_BUSY && do_retry > 0 ) {
- do_retry--;
- goto retry;
+ switch ( rc ) {
+ case LDAP_BUSY:
+ case LDAP_UNAVAILABLE:
+ if ( do_retry > 0 ) {
+ do_retry--;
+ if ( delay > 0 ) {
+ sleep( delay );
+ }
+ goto retry;
+ }
+ /* fallthru */
+ default:
+ break;
}
exit( EXIT_FAILURE );
}
static void
do_search( char *uri, char *host, int port, char *manager, char *passwd,
- char *sbase, char *filter, int maxloop, int maxretries );
+ char *sbase, char *filter, int maxloop, int maxretries, int delay );
static void
usage( char *name )
{
- fprintf( stderr, "usage: %s [-h <host>] -p port -b <searchbase> -f <searchfiter> [-l <loops>]\n",
+ fprintf( stderr,
+ "usage: %s "
+ "-H <uri> | ([-h <host>] -p <port>) "
+ "-D <manager> "
+ "-w <passwd> "
+ "-b <searchbase> "
+ "-f <searchfilter> "
+ "[-l <loops>] "
+ "[-r <maxretries>] "
+ "[-t <delay>]\n",
name );
exit( EXIT_FAILURE );
}
char *filter = NULL;
int loops = LOOPS;
int retries = RETRIES;
+ int delay = 0;
- while ( (i = getopt( argc, argv, "b:D:f:H:h:l:p:w:r:" )) != EOF ) {
+ while ( (i = getopt( argc, argv, "b:D:f:H:h:l:p:w:r:t:" )) != EOF ) {
switch( i ) {
case 'H': /* the server uri */
uri = strdup( optarg );
retries = atoi( optarg );
break;
+ case 't': /* delay in seconds */
+ delay = atoi( optarg );
+ break;
+
default:
usage( argv[0] );
break;
}
do_search( uri, host, port, manager, passwd, sbase, filter,
- ( 10 * loops ), retries );
+ ( 10 * loops ), retries, delay );
exit( EXIT_SUCCESS );
}
static void
do_search( char *uri, char *host, int port, char *manager, char *passwd,
- char *sbase, char *filter, int maxloop, int maxretries )
+ char *sbase, char *filter, int maxloop, int maxretries, int delay )
{
LDAP *ld = NULL;
int i = 0, do_retry = maxretries;
rc = ldap_bind_s( ld, manager, passwd, LDAP_AUTH_SIMPLE );
if ( rc != LDAP_SUCCESS ) {
- if ( rc == LDAP_BUSY && do_retry == 1 ) {
- do_retry = 0;
- goto retry;
- }
ldap_perror( ld, "ldap_bind" );
+ switch ( rc ) {
+ case LDAP_BUSY:
+ case LDAP_UNAVAILABLE:
+ if ( do_retry > 0 ) {
+ do_retry--;
+ if ( delay != 0 ) {
+ sleep( delay );
+ }
+ goto retry;
+ }
+ /* fallthru */
+ default:
+ break;
+ }
exit( EXIT_FAILURE );
}
filter, attrs, 0, &res );
if ( rc != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_search" );
- if ( rc == LDAP_BUSY && do_retry == 1 ) {
- do_retry = 0;
+ if ( rc == LDAP_BUSY && do_retry > 0 ) {
+ do_retry--;
goto retry;
}
if ( rc != LDAP_NO_SUCH_OBJECT ) break;
ldap_unbind( ld );
}
-
-
static void
usage( char *name )
{
- fprintf( stderr, "usage: %s -H <uri> | ([-h <host>] -p <port>) -D <manager> -w <passwd> -d <datadir> [-j <maxchild>] [-l <loops>] -P <progdir>\n", name );
+ fprintf( stderr,
+ "usage: %s "
+ "-H <uri> | ([-h <host>] -p <port>) "
+ "-D <manager> "
+ "-w <passwd> "
+ "-d <datadir> "
+ "[-j <maxchild>] "
+ "[-l <loops>] "
+ "-P <progdir> "
+ "[-r <maxretries>]"
+ "[-t <delay>]\n",
+ name );
exit( EXIT_FAILURE );
}
char *progdir = NULL;
char *loops = LOOPS;
char *retries = RETRIES;
+ char *delay = "0";
DIR *datadir;
struct dirent *file;
char *sfile = NULL;
char *moddn[MAXREQS];
int modnum = 0;
- while ( (i = getopt( argc, argv, "D:d:H:h:j:l:P:p:r:w:" )) != EOF ) {
+ while ( (i = getopt( argc, argv, "D:d:H:h:j:l:P:p:r:t:w:" )) != EOF ) {
switch( i ) {
case 'D': /* slapd manager */
manager = ArgDup( optarg );
port = strdup( optarg );
break;
- case 'r':
+ case 'r': /* the number of retries in case of error */
retries = strdup( optarg );
break;
+ case 't': /* the delay in seconds between each retry */
+ delay = strdup( optarg );
+ break;
+
case 'w': /* the managers passwd */
passwd = ArgDup( optarg );
break;
sargs[sanum++] = loops;
sargs[sanum++] = "-r";
sargs[sanum++] = retries;
+ sargs[sanum++] = "-t";
+ sargs[sanum++] = delay;
sargs[sanum++] = "-b";
sargs[sanum++] = NULL; /* will hold the search base */
sargs[sanum++] = "-f";
rargs[ranum++] = loops;
rargs[ranum++] = "-r";
rargs[ranum++] = retries;
+ rargs[ranum++] = "-t";
+ rargs[ranum++] = delay;
rargs[ranum++] = "-e";
rargs[ranum++] = NULL; /* will hold the read entry */
rargs[ranum++] = NULL;
margs[manum++] = loops;
margs[manum++] = "-r";
margs[manum++] = retries;
+ margs[manum++] = "-t";
+ margs[manum++] = delay;
margs[manum++] = "-e";
margs[manum++] = NULL; /* will hold the modrdn entry */
margs[manum++] = NULL;
modargs[modanum++] = loops;
modargs[modanum++] = "-r";
modargs[modanum++] = retries;
+ modargs[modanum++] = "-t";
+ modargs[modanum++] = delay;
modargs[modanum++] = "-e";
modargs[modanum++] = NULL; /* will hold the modify entry */
modargs[modanum++] = "-a";;
aargs[aanum++] = loops;
aargs[aanum++] = "-r";
aargs[aanum++] = retries;
+ aargs[aanum++] = "-t";
+ aargs[aanum++] = delay;
aargs[aanum++] = "-f";
aargs[aanum++] = NULL; /* will hold the add data file */
aargs[aanum++] = NULL;
AC_unique=unique@BUILD_UNIQUE@
AC_rwm=rwm@BUILD_RWM@
AC_syncprov=syncprov@BUILD_SYNCPROV@
+AC_valsort=valsort@BUILD_VALSORT@
# misc
AC_WITH_SASL=@WITH_SASL@
AC_WITH_TLS=@WITH_TLS@
AC_WITH_MODULES_ENABLED=@WITH_MODULES_ENABLED@
+AC_ACI_ENABLED=aci@SLAPD_ACI_ENABLED@
export AC_bdb AC_hdb AC_ldap AC_ldbm AC_meta AC_monitor AC_relay AC_sql
export AC_glue AC_pcache AC_ppolicy AC_refint AC_retcode AC_rwm AC_unique AC_syncprov
-export AC_translucent AC_WITH_SASL AC_WITH_TLS AC_WITH_MODULES_ENABLED
+export AC_translucent AC_WITH_SASL AC_WITH_TLS AC_WITH_MODULES_ENABLED AC_ACI_ENABLED
+export AC_valsort
if test ! -x ../servers/slapd/slapd ; then
echo "Could not locate slapd(8)"
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.
+MONMOD=nomod
if [ x"$MONITORDB" = xyes -o x"$MONITORDB" = xmod ] ; then
MON=monitor
if [ $MONITORDB = mod ] ; then
MONMOD=monitormod
- else
- MONMOD=nomod
fi
else
MON=nomonitor
-e "s/^#${AC_syncprov}#//" \
-e "s/^#${AC_translucent}#//" \
-e "s/^#${AC_unique}#//" \
+ -e "s/^#${AC_valsort}#//" \
-e "s/^#${MON}#//" \
-e "s/^#${MONMOD}#//" \
-e "s/^#${SASL}#//" \
+ -e "s/^#${ACI}#//" \
-e "s;@URI1@;${URI1};" \
-e "s;@URI2@;${URI2};" \
-e "s;@URI3@;${URI3};" \
WITH_SASL=${AC_WITH_SASL-no}
USE_SASL=${SLAPD_USE_SASL-no}
WITHTLS=${AC_WITHTLS-yes}
+ACI=${AC_ACI_ENABLED-acino}
+VALSORT=${AC_valsort-valsortno}
DATADIR=./testdata
PROGDIR=./progs
METACONF=$DATADIR/slapd-meta.conf
METACONF2=$DATADIR/slapd-meta2.conf
GLUELDAPCONF=$DATADIR/slapd-glue-ldap.conf
+ACICONF=$DATADIR/slapd-aci.conf
+VALSORTCONF=$DATADIR/slapd-valsort.conf
CONF1=$TESTDIR/slapd.1.conf
CONF2=$TESTDIR/slapd.2.conf
SLAPINDEX="../servers/slapd/slapd -Ti $LDAP_VERBOSE"
unset DIFF_OPTIONS
-DIFF="diff -iu"
+# NOTE: -u/-c is not that portable...
+DIFF="diff -i"
CMP="diff -i"
BCMP="diff -iB"
CMPOUT=/dev/null
LDIFTRANSLUCENTADD=$DATADIR/test-translucent-add.ldif
LDIFTRANSLUCENTMERGED=$DATADIR/test-translucent-merged.ldif
LDIFMETA=$DATADIR/test-meta.ldif
+LDIFVALSORT=$DATADIR/test-valsort.ldif
SQLADD=$DATADIR/sql-add.ldif
MONITOR=""
REFDN="c=US"
TRANSLUCENTPASSWD="bindtest"
METABASEDN="ou=Meta,dc=example,dc=com"
METAMANAGERDN="cn=Manager,$METABASEDN"
+VALSORTDN="cn=Manager,o=valsort"
+VALSORTBASEDN="o=valsort"
LOG1=$TESTDIR/slapd.1.log
LOG2=$TESTDIR/slapd.2.log
LDIFFLT=$TESTDIR/ldif.flt
TESTOUT=$TESTDIR/test.out
INITOUT=$TESTDIR/init.out
+VALSORTOUT1=$DATADIR/valsort1.out
+VALSORTOUT2=$DATADIR/valsort2.out
+VALSORTOUT3=$DATADIR/valsort3.out
SERVER1OUT=$TESTDIR/server1.out
SERVER1FLT=$TESTDIR/server1.flt
METAOUT=$DATADIR/meta.out
METACONCURRENCYOUT=$DATADIR/metaconcurrency.out
MANAGEOUT=$DATADIR/manage.out
+SUBTREERENAMEOUT=$DATADIR/subtree-rename.out
+ACIOUT=$DATADIR/aci.out
# Just in case we linked the binaries dynamically
LD_LIBRARY_PATH=`pwd`/../libraries:${LD_LIBRARY_PATH} export LD_LIBRARY_PATH
echo -n "Testing incorrect bind (should fail)... "
$LDAPWHOAMI -h $LOCALHOST -p $PORT1 -D "$BINDDN" -w "XXX"
RC=$?
-if test $RC == 0 ; then
+if test $RC = 0 ; then
echo "ldapwhoami should have failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
+count=2
if test $RC = 0 ; then
if test $MONITORDB = yes -o $MONITORDB = mod ; then
+ count=3
echo "Using ldapsearch to retrieve the cn=Monitor..."
$LDAPSEARCH -b "cn=Monitor" -s base -h $LOCALHOST -p $PORT1 \
'+extensibleObject' >> $SEARCHOUT 2>&1
echo ">>>>> Test failed"
else
RC=`grep '^dn:' $SEARCHOUT | wc -l`
- if test $RC != 3 ; then
- echo ">>>>> Test failed: expected 3 entries, got" $RC
+ if test $RC != $count ; then
+ echo ">>>>> Test failed: expected $count entries, got" $RC
RC=1
else
echo ">>>>> Test succeeded"
exit $RC
fi
-#FILTER="(:rdnMatch:=cn=All Staff)"
-#echo " f=$FILTER ..."
-#echo "# f=$FILTER ..." >> $SEARCHOUT
-#$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
-# "$FILTER" >> $SEARCHOUT 2>&1
-#
-#RC=$?
-#if test $RC != 0 ; then
-# echo "ldapsearch failed ($RC)!"
-# test $KILLSERVERS != no && kill -HUP $KILLPIDS
-# exit $RC
-#fi
+FILTER="(name:dn:=whatever)"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "" -s base -h $LOCALHOST -p $PORT1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
echo "Testing values return filter searching:"
echo "# Testing values return filter searching:" >> $SEARCHOUT
fi
echo "Using ldapadd to populate the database..."
-$LDAPADD -D "$MANAGERDN" -h $LOCALHOST -p $PORT1 -w $PASSWD < \
+$LDAPADD -D "$MANAGERDN" -h $LOCALHOST -p $PORT1 -w $PASSWD -e manageDIT < \
$LDIFPPOLICY > $TESTOUT 2>&1
RC=$?
if test $RC != 0 ; then
fi
echo "Running slapadd to build empty DN slapd database..."
-$SLAPADD -f $CONF1 -n 3 -l $LDIFEMPTYDN2
+$SLAPADD -f $CONF1 -b "" -l $LDIFEMPTYDN2
RC=$?
if test $RC != 0 ; then
echo "slapadd failed ($RC)!"
replace: modifiersName
modifiersName: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com
+dn: dc=example,dc=com
+# change timestamps
+changetype: modify
+replace: modifyTimestamp
+modifyTimestamp: 19700101000000Z
+-
+replace: createTimestamp
+createTimestamp: 19700101000000Z
+-
+
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+# change entryUUID
+changetype: modify
+replace: entryUUID
+entryUUID: badbadba-dbad-1029-92f7-badbadbadbad
+
+dn: cn=All Staff,dc=example,dc=com
+changetype: add
+objectClass: groupOfNames
+cn: All Staff
+member:
+creatorsName: cn=Someone
+createTimestamp: 19700101000000Z
+modifiersName: cn=Someone Else
+modifyTimestamp: 19700101000000Z
+entryUUID: badbadef-dbad-1029-92f7-badbadbadbad
EOMODS
RC=$?
-
add: structuralObjectClass
structuralObjectClass: testPerson
-
EOMODS
RC=$?
$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
'objectClass=*' '*' creatorsName modifiersName > $SEARCHOUT 2>&1
RC=$?
+if test $RC != 0 ; then
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+$LDAPSEARCH -S "" -b "$BASEDN" -s base -h $LOCALHOST -p $PORT1 \
+ 'objectClass=*' '*' creatorsName createTimestamp \
+ modifiersName modifyTimestamp >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
+ '(cn=All Staff)' '*' entryUUID >> $SEARCHOUT 2>&1
+RC=$?
test $KILLSERVERS != no && kill -HUP $KILLPIDS
if test $RC != 0 ; then
echo "ldapsearch failed ($RC)!"
--- /dev/null
+#! /bin/sh
+# $OpenLDAP$ */
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2005 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+case $BACKEND in
+hdb)
+ ;;
+*)
+ echo "subtree rename not supported by back-$BACKEND"
+ exit 0
+esac
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND $MONITORDB < $CONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL $TIMING > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -h $LOCALHOST -p $PORT1 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+cat /dev/null > $TESTOUT
+cat /dev/null > $SEARCHOUT
+
+# Add
+echo "Populating the database..."
+echo "# Populating the database..." >> $TESTOUT
+$LDAPADD -v -D "$MANAGERDN" -h $LOCALHOST -p $PORT1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOMODS0
+dn: dc=example,dc=com
+objectClass: organization
+objectClass: dcObject
+o: Example, Inc.
+dc: example
+
+dn: ou=Parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Parent
+
+dn: ou=Another parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Another parent
+
+dn: ou=Child,ou=Parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Child
+
+dn: ou=Grandchild,ou=Child,ou=Parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Grandchild
+EOMODS0
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Searching all database..."
+echo "# Searching all database (after add)..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
+ '(objectClass=*)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Rename (PASS1)
+echo "Renaming (PASS1)..."
+echo "# Renaming (PASS1)..." >> $TESTOUT
+$LDAPMODIFY -v -D "$MANAGERDN" -h $LOCALHOST -p $PORT1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOMODS1
+dn: ou=Child,ou=Parent,dc=example,dc=com
+changetype: modrdn
+newrdn: ou=Renamed child
+deleteoldrdn: 0
+EOMODS1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Searching all database..."
+echo "# Searching all database (after PASS1)..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
+ '(objectClass=*)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Rename (PASS2)
+echo "Renaming (PASS2)..."
+echo "# Renaming (PASS2)..." >> $TESTOUT
+$LDAPMODIFY -v -D "$MANAGERDN" -h $LOCALHOST -p $PORT1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOMODS2
+dn: ou=Parent,dc=example,dc=com
+changetype: modrdn
+newrdn: ou=Renamed parent
+deleteoldrdn: 0
+EOMODS2
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Searching all database..."
+echo "# Searching all database (after PASS2)..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
+ '(objectClass=*)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Rename (PASS3)
+echo "Renaming (PASS3)..."
+echo "# Renaming (PASS3)..." >> $TESTOUT
+$LDAPMODIFY -v -D "$MANAGERDN" -h $LOCALHOST -p $PORT1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOMODS3
+dn: ou=Renamed child,ou=Renamed parent,dc=example,dc=com
+changetype: modrdn
+newrdn: ou=Renamed child
+deleteoldrdn: 0
+newsuperior: ou=Another parent,dc=example,dc=com
+EOMODS3
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Searching all database..."
+echo "# Searching all database (after PASS3)..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
+ '(objectClass=*)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$SUBTREERENAMEOUT
+
+echo "Filtering ldapsearch results..."
+. $LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+. $LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+exit 0
--- /dev/null
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2005 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+case "$BACKEND" in
+bdb|hdb|ldbm)
+ ;;
+*)
+ echo "Test does not support $BACKEND backend"
+ exit 0
+esac
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+if test "$ACI" = "acino" ; then
+ echo "ACI not enabled; skipping..."
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND $MONITORDB < $ACICONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL $TIMING > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+echo "Testing slapd ACI access control..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -h $LOCALHOST -p $PORT1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+cat /dev/null > $SEARCHOUT
+cat /dev/null > $TESTOUT
+
+# Search must fail
+BASEDN="dc=example,dc=com"
+echo "Searching \"$BASEDN\" (should fail)..."
+echo "# Searching \"$BASEDN\" (should fail)..." >> $SEARCHOUT
+$LDAPSEARCH -s base -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
+ '(objectclass=*)' >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 32 ; then
+ echo "ldapsearch should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Bind must fail
+BINDDN="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjensen
+echo "Testing ldapwhoami as ${BINDDN} (should fail)..."
+$LDAPWHOAMI -h $LOCALHOST -p $PORT1 -D "$BINDDN" -w $BINDPW
+RC=$?
+if test $RC = 0 ; then
+ echo "ldapwhoami should have failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Populate ACIs
+echo "Writing ACIs as \"$MANAGERDN\"..."
+$LDAPMODIFY -D "$MANAGERDN" -w $PASSWD -h $LOCALHOST -p $PORT1 \
+ >> $TESTOUT 2>&1 << EOMODS0
+dn: dc=example,dc=com
+changetype: modify
+add: OpenLDAPaci
+OpenLDAPaci: 0#subtree#grant;d,c,s,r;[all]#group/groupOfUniqueNames/uniqueMe
+ mber#cn=ITD Staff,ou=Groups,dc=example,dc=com
+OpenLDAPaci: 1#entry#grant;d;[all]#public#
+
+dn: ou=People,dc=example,dc=com
+changetype: modify
+add: OpenLDAPaci
+OpenLDAPaci: 0#subtree#grant;x;userPassword#public#
+OpenLDAPaci: 1#subtree#grant;w;userPassword#self#
+OpenLDAPaci: 2#subtree#grant;w;userPassword#access-id#cn=Bjorn Jensen,ou=Inf
+ ormation Technology Division,ou=People,dc=example,dc=com
+
+dn: ou=Groups,dc=example,dc=com
+changetype: modify
+add: OpenLDAPaci
+OpenLDAPaci: 0#entry#grant;s;[all]#public#
+OpenLDAPaci: 1#children#grant;r;member;r;uniqueMember#access-id#cn=Bjorn Jen
+ sen,ou=Information Technology Division,ou=People,dc=example,dc=com
+EOMODS0
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Search must succeed with no results
+BASEDN="dc=example,dc=com"
+echo "Searching \"$BASEDN\" (should succeed with no results)..."
+echo "# Searching \"$BASEDN\" (should succeed with no results)..." >> $SEARCHOUT
+$LDAPSEARCH -s base -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
+ '(objectclass=*)' >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ ### TEMPORARY (see ITS#3963)
+ echo "ldapsearch failed ($RC)! IGNORED..."
+ ###echo "ldapsearch failed ($RC)!"
+ ###test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ ###exit $RC
+fi
+
+BINDDN="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjensen
+echo "Testing ldapwhoami as ${BINDDN}..."
+$LDAPWHOAMI -h $LOCALHOST -p $PORT1 -D "$BINDDN" -w $BINDPW
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Search must succeed
+BINDDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjorn
+BASEDN="dc=example,dc=com"
+echo "Searching \"$BASEDN\" as \"$BINDDN\" (should succeed)..."
+echo "# Searching \"$BASEDN\" as \"$BINDDN\" (should succeed)..." >> $SEARCHOUT
+$LDAPSEARCH -s base -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
+ -D "$BINDDN" -w "$BINDPW" \
+ '(objectClass=*)' >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Passwd must succeed
+BINDDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjorn
+TGT="cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc=com"
+NEWPW=jdoe
+echo "Setting \"$TGT\" password..."
+$LDAPPASSWD -h $LOCALHOST -p $PORT1 \
+ -w "$BINDPW" -s "$NEWPW" \
+ -D "$BINDDN" "$TGT" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Re-change as self...
+echo "Changing self password..."
+BINDDN="$TGT"
+BINDPW=$NEWPW
+TGT="cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc=com"
+NEWPW=newcred
+$LDAPPASSWD -h $LOCALHOST -p $PORT1 \
+ -w "$BINDPW" -s "$NEWPW" \
+ -D "$BINDDN" "$TGT" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Searching groups
+BINDPW=$NEWPW
+BASEDN="ou=Groups,dc=example,dc=com"
+echo "Searching \"$BASEDN\" as \"$BINDDN\" (should succeed)..."
+echo "# Searching \"$BASEDN\" as \"$BINDDN\" (should succeed)..." >> $SEARCHOUT
+$LDAPSEARCH -s one -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
+ -D "$BINDDN" -w "$BINDPW" \
+ '(objectClass=*)' >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Search must fail
+BINDDN="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjensen
+echo "Searching \"$BASEDN\" as \"$BINDDN\" (should succeed with no results)..."
+echo "# Searching \"$BASEDN\" as \"$BINDDN\" (should succeed with no results)..." >> $SEARCHOUT
+$LDAPSEARCH -s one -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
+ -D "$BINDDN" -w "$BINDPW" \
+ '(objectClass=*)' >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$ACIOUT
+
+echo "Filtering ldapsearch results..."
+. $LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+. $LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - operations did not complete correctly"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+exit 0
--- /dev/null
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2004-2005 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+if test $VALSORT = valsortno; then
+ echo "Valsort overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND $MONITORDB < $VALSORTCONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFVALSORT
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL $TIMING > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+echo "Testing slapd sorted values operations..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -h $LOCALHOST -p $PORT1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing ascending and weighted sort"
+
+FILTER="objectClass=*"
+$LDAPSEARCH -b "$VALSORTBASEDN" -h $LOCALHOST -p $PORT1 \
+ "$FILTER" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+. $LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $VALSORTOUT1 > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+echo "Reconfiguring slapd to test valsort descending"
+
+$LDAPMODIFY -x -D cn=config -h $LOCALHOST -p $PORT1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+version: 1
+dn: olcOverlay={0}valsort,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+replace: olcValSortAttr
+olcValSortAttr: employeeType "ou=users,o=valsort" weighted alpha-descend
+olcValSortAttr: ou "ou=users,o=valsort" weighted
+olcValSortAttr: mailPreferenceOption "ou=users,o=valsort" numeric-descend
+olcValSortAttr: departmentNumber "ou=users,o=valsort" alpha-descend
+olcValSortAttr: sn "ou=users,o=valsort" alpha-descend
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing descending and weighted sort"
+
+$LDAPSEARCH -b "$VALSORTBASEDN" -h $LOCALHOST -p $PORT1 \
+ "$FILTER" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+. $LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $VALSORTOUT2 > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+echo "Adding a valsort record with weighted ou..."
+
+$LDAPADD -D "$VALSORTDN" -h $LOCALHOST -p $PORT1 -w $PASSWD \
+ > /dev/null << EOTVALSORT1
+dn: uid=dave,ou=users,o=valsort
+objectClass: OpenLDAPperson
+uid: dave
+sn: nothere
+cn: dave
+businessCategory: otest
+carLicense: TEST
+departmentNumber: 42
+displayName: Dave
+employeeNumber: 69
+employeeType: {1}contractor
+givenName: Dave
+ou: {1}Test
+ou: {3}Okay
+ou: {2}Is
+EOTVALSORT1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo ----------------------
+#$LDAPSEARCH -b "o=valsort" -h $LOCALHOST -p $PORT1
+
+echo "Adding a non-weighted valsort record with ou..."
+
+$LDAPADD -D "$VALSORTDN" -h $LOCALHOST -p $PORT1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOTVALSORT2
+dn: uid=bill,ou=users,o=valsort
+objectClass: OpenLDAPperson
+uid: bill
+sn: johnson
+cn: bill
+businessCategory: rtest
+carLicense: ABC123
+departmentNumber: 42
+displayName: Bill
+employeeNumber: 5150
+employeeType: {1}contractor
+givenName: Bill
+ou: Test
+ou: Okay
+ou: Is
+EOTVALSORT2
+
+RC=$?
+if test $RC != 19 ; then
+ echo "valsort check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit -1
+fi
+
+$LDAPSEARCH -b "$VALSORTBASEDN" -h $LOCALHOST -p $PORT1 \
+ "$FILTER" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+. $LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $VALSORTOUT3 > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+exit 0