]> git.sur5r.net Git - openldap/commitdiff
Update build tools based upon OPENLDAP_AC work
authorKurt Zeilenga <kurt@openldap.org>
Thu, 25 Aug 2005 20:09:26 +0000 (20:09 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Thu, 25 Aug 2005 20:09:26 +0000 (20:09 +0000)
124 files changed:
aclocal.m4
build/man.mk
configure
configure.in
contrib/slapd-modules/acl/README [new file with mode: 0644]
contrib/slapd-modules/acl/posixgroup.c [new file with mode: 0644]
contrib/slapd-modules/allop/README [new file with mode: 0644]
contrib/slapd-modules/allop/allop.c [new file with mode: 0644]
contrib/slapd-modules/allop/slapo-allop.5 [new file with mode: 0644]
contrib/slapd-overlays/allop/README [new file with mode: 0644]
contrib/slapd-overlays/allop/allop.c [new file with mode: 0644]
contrib/slapd-overlays/allop/slapo-allop.5 [new file with mode: 0644]
doc/drafts/draft-behera-ldap-password-policy-xx.txt
doc/drafts/draft-zeilenga-ldap-noop-xx.txt [new file with mode: 0644]
doc/guide/release/copyright.sdf
doc/man/man5/slapd.access.5
doc/man/man5/slapo-dynlist.5
doc/man/man5/slapo-ppolicy.5
doc/man/man5/slapo-retcode.5
doc/man/man5/slapo-syncprov.5
doc/man/man5/slapo-unique.5
doc/man/man5/slapo-valsort.5 [new file with mode: 0644]
doc/man/man8/slapcat.8
include/ldap.h
include/ldap_pvt_thread.h
include/portable.hin
include/slapi-plugin.h
libraries/libldap/cyrus.c
libraries/libldap/dntest.c
libraries/libldap/result.c
libraries/libldap/schema.c
libraries/libldap/url.c
libraries/libldap_r/tpool.c
libraries/liblutil/passwd.c
libraries/librewrite/rewrite-int.h
libraries/librewrite/rule.c
servers/slapd/Makefile.in
servers/slapd/abandon.c
servers/slapd/aci.c [new file with mode: 0644]
servers/slapd/acl.c
servers/slapd/aclparse.c
servers/slapd/ad.c
servers/slapd/attr.c
servers/slapd/back-bdb/init.c
servers/slapd/back-bdb/search.c
servers/slapd/back-ldap/add.c
servers/slapd/back-ldap/bind.c
servers/slapd/back-ldap/config.c
servers/slapd/back-ldap/modify.c
servers/slapd/back-ldap/search.c
servers/slapd/back-ldbm/search.c
servers/slapd/back-meta/add.c
servers/slapd/back-meta/back-meta.h
servers/slapd/back-meta/bind.c
servers/slapd/back-meta/candidates.c
servers/slapd/back-meta/compare.c
servers/slapd/back-meta/config.c
servers/slapd/back-meta/conn.c
servers/slapd/back-meta/modify.c
servers/slapd/back-meta/search.c
servers/slapd/backend.c
servers/slapd/bconfig.c
servers/slapd/cancel.c
servers/slapd/connection.c
servers/slapd/controls.c
servers/slapd/dn.c
servers/slapd/extended.c
servers/slapd/main.c
servers/slapd/modify.c
servers/slapd/oc.c
servers/slapd/overlays/Makefile.in
servers/slapd/overlays/overlays.c
servers/slapd/overlays/ppolicy.c
servers/slapd/overlays/retcode.c
servers/slapd/overlays/rwm.c
servers/slapd/overlays/rwmconf.c
servers/slapd/overlays/syncprov.c
servers/slapd/overlays/valsort.c [new file with mode: 0644]
servers/slapd/passwd.c
servers/slapd/proto-slap.h
servers/slapd/result.c
servers/slapd/root_dse.c
servers/slapd/sasl.c
servers/slapd/saslauthz.c
servers/slapd/schema/nis.schema
servers/slapd/schema_init.c
servers/slapd/schema_prep.c
servers/slapd/slap.h
servers/slapd/slapcommon.c
servers/slapd/slapi/slapi_dn.c
servers/slapd/slapi/slapi_overlay.c
servers/slapd/slapi/slapi_pblock.c
servers/slapd/starttls.c
servers/slapd/syncrepl.c
servers/slapd/syntax.c
tests/Makefile.in
tests/data/aci.out [new file with mode: 0644]
tests/data/manage.out
tests/data/retcode.conf
tests/data/slapd-aci.conf [new file with mode: 0644]
tests/data/slapd-valsort.conf [new file with mode: 0644]
tests/data/subtree-rename.out [new file with mode: 0644]
tests/data/test-valsort.ldif [new file with mode: 0755]
tests/data/valsort1.out [new file with mode: 0755]
tests/data/valsort2.out [new file with mode: 0755]
tests/data/valsort3.out [new file with mode: 0755]
tests/progs/slapd-addel.c
tests/progs/slapd-modify.c
tests/progs/slapd-modrdn.c
tests/progs/slapd-read.c
tests/progs/slapd-search.c
tests/progs/slapd-tester.c
tests/run.in
tests/scripts/conf.sh
tests/scripts/defines.sh
tests/scripts/sql-test000-read
tests/scripts/test000-rootdse
tests/scripts/test015-xsearch
tests/scripts/test022-ppolicy
tests/scripts/test027-emptydn
tests/scripts/test037-manage
tests/scripts/test040-subtree-rename [new file with mode: 0755]
tests/scripts/test041-aci [new file with mode: 0755]
tests/scripts/test042-valsort [new file with mode: 0755]

index cc8e4bf46d397234e8717df10503c8453a53858d..22cdcb9365bd519ced000ed78035146f3bff8d59 100644 (file)
@@ -83,29 +83,6 @@ AC_PREREQ([2.50])dnl
 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
index 6d25337bdb47148b939455c5729c228cbe70cad4..9fe4528e52cc264bff4d474743ca2b058d68ccc7 100644 (file)
@@ -39,14 +39,14 @@ install-common:
        -$(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
index 465d54e0c73bf68e21456d3616cd232b8baa0744..298eb7e7e90b4bb55d78cb6a4ffb2fbabb3f5725 100755 (executable)
--- a/configure
+++ b/configure
@@ -469,7 +469,7 @@ ac_includes_default="\
 # 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.
@@ -1085,6 +1085,7 @@ SLAPD Overlay 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]
@@ -3139,8 +3140,21 @@ else
 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
@@ -3505,6 +3519,30 @@ else
 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
@@ -3848,6 +3886,7 @@ BUILD_RWM=no
 BUILD_SYNCPROV=no
 BUILD_TRANSLUCENT=no
 BUILD_UNIQUE=no
+BUILD_VALSORT=no
 
 SLAPD_STATIC_OVERLAYS=
 SLAPD_DYNAMIC_OVERLAYS=
@@ -5672,7 +5711,7 @@ ia64-*-hpux*)
   ;;
 *-*-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=$?
@@ -7493,7 +7532,7 @@ fi
 
 
 # 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
@@ -8591,11 +8630,11 @@ else
    -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.
@@ -8853,11 +8892,11 @@ else
    -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.
@@ -8915,11 +8954,11 @@ else
    -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
@@ -11155,7 +11194,7 @@ else
   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
@@ -11253,7 +11292,7 @@ else
   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
@@ -13501,11 +13540,11 @@ else
    -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.
@@ -13563,11 +13602,11 @@ else
    -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
@@ -14932,7 +14971,7 @@ else
   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
@@ -15030,7 +15069,7 @@ else
   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
@@ -15915,11 +15954,11 @@ else
    -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.
@@ -15977,11 +16016,11 @@ else
    -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
@@ -18099,11 +18138,11 @@ else
    -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.
@@ -18361,11 +18400,11 @@ else
    -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.
@@ -18423,11 +18462,11 @@ else
    -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
@@ -20663,7 +20702,7 @@ else
   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
@@ -20761,7 +20800,7 @@ else
   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
@@ -52661,7 +52700,7 @@ _ACEOF
 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
@@ -52923,6 +52962,22 @@ _ACEOF
 
 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
@@ -53032,6 +53087,7 @@ fi
 
 
 
+
 
 
 # Check whether --with-xxinstall or --without-xxinstall was given.
@@ -53808,6 +53864,7 @@ s,@BUILD_RWM@,$BUILD_RWM,;t t
 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
index 5204449f85c595e2addd835b07f32758a8ae0155..5947ef1e4efd68947b35ddd9eec4225ac689211a 100644 (file)
@@ -314,8 +314,21 @@ OL_ARG_ENABLE(sql,[    --enable-sql          enable sql backend],
 
 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:])
@@ -350,6 +363,8 @@ OL_ARG_ENABLE(translucent,[    --enable-translucent  Translucent Proxy overlay],
        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
@@ -590,6 +605,7 @@ BUILD_RWM=no
 BUILD_SYNCPROV=no
 BUILD_TRANSLUCENT=no
 BUILD_UNIQUE=no
+BUILD_VALSORT=no
 
 SLAPD_STATIC_OVERLAYS=
 SLAPD_DYNAMIC_OVERLAYS=
@@ -2783,7 +2799,7 @@ if test "$ol_enable_relay" != no ; then
 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
@@ -2980,6 +2996,18 @@ if test "$ol_enable_unique" != no ; then
        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
@@ -3050,6 +3078,7 @@ dnl overlays
   AC_SUBST(BUILD_SYNCPROV)
   AC_SUBST(BUILD_TRANSLUCENT)
   AC_SUBST(BUILD_UNIQUE)
+  AC_SUBST(BUILD_VALSORT)
 AC_SUBST(BUILD_SLURPD)
 
 AC_SUBST(LDAP_LIBS)
diff --git a/contrib/slapd-modules/acl/README b/contrib/slapd-modules/acl/README
new file mode 100644 (file)
index 0000000..b623ab9
--- /dev/null
@@ -0,0 +1,36 @@
+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.
+
diff --git a/contrib/slapd-modules/acl/posixgroup.c b/contrib/slapd-modules/acl/posixgroup.c
new file mode 100644 (file)
index 0000000..f5c8f2f
--- /dev/null
@@ -0,0 +1,323 @@
+/* $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 */
diff --git a/contrib/slapd-modules/allop/README b/contrib/slapd-modules/allop/README
new file mode 100644 (file)
index 0000000..94536ec
--- /dev/null
@@ -0,0 +1,27 @@
+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.
+
diff --git a/contrib/slapd-modules/allop/allop.c b/contrib/slapd-modules/allop/allop.c
new file mode 100644 (file)
index 0000000..56a536d
--- /dev/null
@@ -0,0 +1,260 @@
+/* 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();
+}
+
diff --git a/contrib/slapd-modules/allop/slapo-allop.5 b/contrib/slapd-modules/allop/slapo-allop.5
new file mode 100644 (file)
index 0000000..471c80c
--- /dev/null
@@ -0,0 +1,63 @@
+.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.
diff --git a/contrib/slapd-overlays/allop/README b/contrib/slapd-overlays/allop/README
new file mode 100644 (file)
index 0000000..94536ec
--- /dev/null
@@ -0,0 +1,27 @@
+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.
+
diff --git a/contrib/slapd-overlays/allop/allop.c b/contrib/slapd-overlays/allop/allop.c
new file mode 100644 (file)
index 0000000..56a536d
--- /dev/null
@@ -0,0 +1,260 @@
+/* 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();
+}
+
diff --git a/contrib/slapd-overlays/allop/slapo-allop.5 b/contrib/slapd-overlays/allop/slapo-allop.5
new file mode 100644 (file)
index 0000000..471c80c
--- /dev/null
@@ -0,0 +1,63 @@
+.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.
index d9978abe040742d4ca51ba0e637ef0228e8809b0..3e61917ef2ed66806b96a66daa0cc01a45239523 100644 (file)
@@ -1,27 +1,28 @@
 
+
+
+
 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
@@ -34,11 +35,11 @@ Status of this Memo
    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
 
@@ -48,15 +49,15 @@ 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.
 
@@ -66,55 +67,9 @@ Discussion Forum
    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
 
 
 
@@ -154,6 +109,53 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
 
 
+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
 
 
 
@@ -163,9 +165,9 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
 
 
-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
@@ -181,7 +183,9 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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
@@ -217,11 +221,9 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
 
 
-
-
-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
@@ -275,9 +277,9 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
 
 
-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
@@ -331,9 +333,9 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
 
 
-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
@@ -353,19 +355,24 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 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
@@ -377,20 +384,22 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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
@@ -404,11 +413,13 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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
@@ -431,6 +442,14 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
    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.
 
@@ -440,21 +459,15 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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:
@@ -463,19 +476,18 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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
@@ -485,6 +497,15 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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
@@ -496,16 +517,11 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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
 
@@ -541,23 +557,9 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-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
@@ -585,6 +587,7 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       $ 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.
@@ -600,27 +603,28 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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
@@ -636,6 +640,7 @@ 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.4  pwdInHistory
 
    This attribute specifies the maximum number of used passwords stored
@@ -651,27 +656,28 @@ 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.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 outsidthis 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
@@ -685,6 +691,7 @@ 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.6  pwdMinLength
 
    When quality checking is enabled, this attribute holds the minimum
@@ -701,6 +708,7 @@ 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.7  pwdExpireWarning
 
    This attribute specifies the maximum number of seconds before a
@@ -714,20 +722,21 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       ( 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.
 
@@ -737,6 +746,7 @@ 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.9  pwdLockout
 
    This attribute indicates, when its value is "TRUE", that the password
@@ -754,6 +764,7 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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
@@ -768,6 +779,13 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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
@@ -775,21 +793,13 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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
@@ -805,6 +815,7 @@ 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.13  pwdMustChange
 
    This attribute specifies with a value of "TRUE" that users must
@@ -822,6 +833,15 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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
@@ -831,20 +851,12 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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
@@ -857,6 +869,7 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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.
@@ -878,6 +891,13 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    (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:
@@ -889,13 +909,6 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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
@@ -909,8 +922,10 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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
@@ -926,8 +941,19 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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
@@ -940,18 +966,10 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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
@@ -984,10 +1002,20 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       ( 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
@@ -999,22 +1027,15 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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'
@@ -1024,6 +1045,7 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       SINGLE-VALUE
       USAGE directoryOperation )
 
+
 5.3.8  pwdPolicySubentry
 
    This attribute points to the pwdPolicy subentry in effect for this
@@ -1035,6 +1057,15 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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 )
 
 
@@ -1059,9 +1090,36 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
 
 
-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
@@ -1072,6 +1130,8 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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
@@ -1110,16 +1170,16 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
          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
@@ -1169,11 +1229,9 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
 
 
-
-
-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
@@ -1193,6 +1251,7 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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.
@@ -1205,6 +1264,7 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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.
@@ -1212,9 +1272,8 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 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.
 
@@ -1223,15 +1282,16 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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
@@ -1251,6 +1311,7 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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.
@@ -1266,6 +1327,7 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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.
 
@@ -1279,13 +1341,9 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
 
 
-
-
-
-
-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
@@ -1309,7 +1367,10 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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
 
@@ -1320,9 +1381,9 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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
@@ -1333,17 +1394,18 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
    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.
@@ -1359,7 +1421,7 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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.
@@ -1382,23 +1444,24 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
    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
 
@@ -1438,23 +1501,24 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
    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
 
@@ -1498,21 +1562,22 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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.
@@ -1529,6 +1594,7 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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
@@ -1552,6 +1618,14 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
    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.
@@ -1561,15 +1635,8 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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
 
@@ -1610,18 +1677,9 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
 
 
-
-
-
-
-
-
-
-
-
-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
@@ -1648,38 +1706,44 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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.
@@ -1698,25 +1762,38 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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
@@ -1728,21 +1805,15 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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
@@ -1756,18 +1827,29 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
       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
@@ -1787,9 +1869,41 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
 
 
-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
@@ -1843,13 +1957,18 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
 
 
-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
@@ -1870,11 +1989,11 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
    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
@@ -1894,14 +2013,9 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
 
 
-
-
-
-
-
-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
@@ -1955,38 +2069,94 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
 
 
-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
@@ -2011,9 +2181,9 @@ Internet-Draft    Password Policy for LDAP Directories      October 2004
 
 
 
-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
@@ -2030,7 +2200,7 @@ Authors' Addresses
    USA
 
    Phone: +1 801 861-3088
-   EMail: jimse@novell.com
+   Email: jimse@novell.com
 
 
    Ludovic Poitou
@@ -2040,7 +2210,7 @@ Authors' Addresses
    France
 
    Phone: +33 476 188 212
-   EMail: ludovic.poitou@sun.com
+   Email: ludovic.poitou@sun.com
 
 
 
@@ -2067,9 +2237,9 @@ Authors' Addresses
 
 
 
-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
@@ -2110,7 +2280,7 @@ Disclaimer of Validity
 
 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.
 
@@ -2123,5 +2293,6 @@ Acknowledgment
 
 
 
-Sermersheim & Poitou     Expires April 24, 2005                [Page 38]
+Sermersheim & Poitou    Expires January 18, 2006               [Page 41]
 \f
+
diff --git a/doc/drafts/draft-zeilenga-ldap-noop-xx.txt b/doc/drafts/draft-zeilenga-ldap-noop-xx.txt
new file mode 100644 (file)
index 0000000..9c65f9b
--- /dev/null
@@ -0,0 +1,340 @@
+
+
+
+
+
+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
+
+
index 87ded2740ebabdac85c939b868198ed9f6a5064e..068b1358e1d2f624772e397f077cc79e30f11f53 100644 (file)
@@ -55,8 +55,8 @@ Public License}}.
 
 
 !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
index 7413ee6e07a602817152dbe664d7b0a3a0be8ddf..aa0cfb8b89af0231609943612af900d2ad158d01 100644 (file)
@@ -255,7 +255,7 @@ It can have the forms
        sasl_ssf=<n>
 
        aci[=<attrname>]
-       dynacl/name[.<dynstyle>][=<pattern>]
+       dynacl/name[/<options>][.<dynstyle>][=<pattern>]
 .fi
 .LP
 with
@@ -633,7 +633,7 @@ operational attribute is used.
 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> ,
@@ -641,6 +641,7 @@ which can be registered at run-time by means of the
 .B moduleload
 statement.
 The fields
+.BR <options> ,
 .B <dynstyle>
 and
 .B <pattern>
index c5eb9f0e38b7de56596f9adc13e54a6bc3cb8ab0..fc0cb20d2e84010f8a947be5822147ca1b6535b0 100644 (file)
@@ -106,5 +106,6 @@ default slapd configuration file
 .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.
index cc95469adb33c5ff3c1053ca7989a5ebb9402c15..7cdb3b6910409535cb264ea92f63a773e561aa8b 100644 (file)
@@ -517,6 +517,7 @@ policy rules will be enforced.
    EQUALITY distinguishedNameMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
    SINGLE-VALUE
+   NO-USER-MODIFICATION
    USAGE directoryOperation)
 .RE
 
@@ -537,6 +538,7 @@ does not exist, the user's password will not expire.
    EQUALITY generalizedTimeMatch
    ORDERING generalizedTimeOrderingMatch
    SINGLE-VALUE
+   NO-USER-MODIFICATION
    USAGE directoryOperation)
 .RE
 
@@ -557,6 +559,7 @@ and may only be unlocked by an administrator.
    EQUALITY generalizedTimeMatch
    ORDERING generalizedTimeOrderingMatch
    SINGLE-VALUE
+   NO-USER-MODIFICATION
    USAGE directoryOperation)
 .RE
 
@@ -590,6 +593,7 @@ will be cleansed of entries.
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
    EQUALITY generalizedTimeMatch
    ORDERING generalizedTimeOrderingMatch
+   NO-USER-MODIFICATION
    USAGE directoryOperation )
 .RE
 
@@ -643,6 +647,7 @@ field is in GMT format.
    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
 
@@ -667,6 +672,7 @@ attribute.
    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
 
@@ -712,7 +718,7 @@ ppolicy_default "cn=Standard,ou=Policies,dc=example,dc=com"
 .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,
@@ -731,8 +737,8 @@ IETF LDAP password policy proposal by P. Behera, L.
 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/).
index 13c006ad6ff5b0da440f274de7a9b5f1edef9989..be612cd306737447c5749d143cabaac79dedb06f 100644 (file)
@@ -28,13 +28,14 @@ Well-known response codes from standard track documents are provided
 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 
@@ -68,8 +69,8 @@ response code.
 .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:
@@ -116,14 +117,28 @@ The sleep time before the response is actually returned to the client:
     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
@@ -149,5 +164,6 @@ default slapd configuration file
 .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.
index 6b12b4e7eaa20d7b162c2346653963f12b66a8ac..02cf2337401561edf7256bccbac8a744b5bc6ee6 100644 (file)
@@ -37,22 +37,19 @@ directive.
 .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
index ae30ff1a20e13f70e5a82ea89753af47ed44016c..4ad9dc9162177023b73ff7a5709b7e488d18d22a 100644 (file)
@@ -58,7 +58,7 @@ attributes, as these will generally not be unique, nor are they operational
 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 )
@@ -79,7 +79,15 @@ on the
 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
diff --git a/doc/man/man5/slapo-valsort.5 b/doc/man/man5/slapo-valsort.5
new file mode 100644 (file)
index 0000000..3cd439a
--- /dev/null
@@ -0,0 +1,73 @@
+.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.
index 1609dbf8214c7825a061b3a38d7c09c635f04b85..d6eb2ff77f4f6b50fad9260b0676703e28b8f51e 100644 (file)
@@ -62,7 +62,14 @@ cannot be used in conjunction with the
 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.
index 4678bf57c7f7769a4aa8532c5c65691580ebfc27..05eb052df4942ed28a554d6f6ca2ab867af8f69d 100644 (file)
@@ -207,6 +207,9 @@ typedef struct ldapcontrol {
 #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 */
@@ -216,13 +219,11 @@ typedef struct ldapcontrol {
 #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"
@@ -244,7 +245,7 @@ typedef struct ldapcontrol {
 #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"
 
@@ -346,10 +347,10 @@ typedef struct ldapcontrol {
 #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
index 1ca300bd9861fd79a1d9d0d80c35ca2148cd7dcd..79c821dd659ddf48255392bf7272de4337d6338e 100644 (file)
@@ -208,6 +208,9 @@ ldap_pvt_thread_pool_purgekey LDAP_P(( void *key ));
 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 */
index 3366962007092c196ee7190b89623da2ae7256ed..1a54e8c3e4fd8dc4d8b1030232676395d289ba52 100644 (file)
 /* 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
 
index 8344cf766ab694ade803d9ac1dba21681dbdfbf1..db381da32262a7253d75b7910b6bbcf7b68add3e 100644 (file)
@@ -530,6 +530,7 @@ int slapi_x_backend_get_flags( const Slapi_Backend *be, unsigned long *flags );
 #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"
index 18c493688c262d9eafc5f5d99a03a18abe223dfe..564cee70726c602bc14e93eb788dfcdb5cbe92fd 100644 (file)
@@ -983,9 +983,10 @@ int ldap_pvt_sasl_secprops(
                                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;
index 9e0abe37ee48c44b8da5074f292034b8a1c8e738..e99a0570c61926216117be556f33a4c58160e76c 100644 (file)
@@ -171,31 +171,32 @@ main( int argc, char *argv[] )
                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 );
index 2652c81f2999a264ef9f096c61061c13fd6f6e7d..a4f1093bbe37b2e253cf690582a84e5edee6fa42 100644 (file)
@@ -407,7 +407,11 @@ try_read1msg(
         * 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 );
@@ -519,15 +523,16 @@ nextresp2:
         * 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) )
                        {
@@ -535,18 +540,23 @@ nextresp2:
                                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;
                                        }
                                }
                        }
@@ -572,11 +582,13 @@ nextresp2:
                                /* 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;
@@ -595,7 +607,8 @@ nextresp2:
                                                            "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;
                                                        }
                                                }
                                        }
@@ -617,7 +630,7 @@ nextresp2:
         * 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 */
@@ -628,7 +641,7 @@ nextresp2:
                        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
@@ -647,15 +660,31 @@ nextresp2:
                                        } 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 */
index 07a315a9572ba08e22f4e628dbac2bf789b6787a..bff6c5bdbe11db353cbb016bc8a49f0a14ea314a 100644 (file)
@@ -959,21 +959,23 @@ ldap_attributetype2bv(  LDAPAttributeType * at, struct berval *bv )
  * 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;
@@ -1145,7 +1147,7 @@ parse_qdescrs(const char **sp, int *code)
 {
        char ** res;
        char ** res1;
-       int kind;
+       tk_t kind;
        char * sval;
        int size;
        int pos;
@@ -1212,7 +1214,7 @@ static char *
 parse_woid(const char **sp, int *code)
 {
        char * sval;
-       int kind;
+       tk_t kind;
 
        parse_whsp(sp);
        kind = get_token(sp, &sval);
@@ -1227,10 +1229,13 @@ parse_woid(const char **sp, int *code)
 
 /* 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) */
@@ -1238,9 +1243,22 @@ parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
                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)++;
@@ -1279,7 +1297,7 @@ parse_oids(const char **sp, int *code, const int allow_quoted)
 {
        char ** res;
        char ** res1;
-       int kind;
+       tk_t kind;
        char * sval;
        int size;
        int pos;
@@ -1441,7 +1459,7 @@ ldap_str2syntax( LDAP_CONST char * s,
        LDAP_CONST char ** errp,
        LDAP_CONST unsigned flags )
 {
-       int kind;
+       tk_t kind;
        const char * ss = s;
        char * sval;
        int seen_name = 0;
@@ -1583,7 +1601,7 @@ ldap_str2matchingrule( LDAP_CONST char * s,
        LDAP_CONST char ** errp,
        LDAP_CONST unsigned flags )
 {
-       int kind;
+       tk_t kind;
        const char * ss = s;
        char * sval;
        int seen_name = 0;
@@ -1782,7 +1800,7 @@ ldap_str2matchingruleuse( LDAP_CONST char * s,
        LDAP_CONST char ** errp,
        LDAP_CONST unsigned flags )
 {
-       int kind;
+       tk_t kind;
        const char * ss = s;
        char * sval;
        int seen_name = 0;
@@ -1984,7 +2002,7 @@ ldap_str2attributetype( LDAP_CONST char * s,
        LDAP_CONST char ** errp,
        LDAP_CONST unsigned flags )
 {
-       int kind;
+       tk_t kind;
        const char * ss = s;
        char * sval;
        int seen_name = 0;
@@ -2362,7 +2380,7 @@ ldap_str2objectclass( LDAP_CONST char * s,
        LDAP_CONST char ** errp,
        LDAP_CONST unsigned flags )
 {
-       int kind;
+       tk_t kind;
        const char * ss = s;
        char * sval;
        int seen_name = 0;
@@ -2437,6 +2455,7 @@ ldap_str2objectclass( LDAP_CONST char * s,
                                }
                        }
                        LDAP_FREE(sval);
+                       *code = 0;
                } else {
                        *errp = ss;
                        ldap_objectclass_free(oc);
@@ -2525,6 +2544,7 @@ ldap_str2objectclass( LDAP_CONST char * s,
                                        ldap_objectclass_free(oc);
                                        return NULL;
                                }
+                               *code = 0;
                        } else if ( !strcasecmp(sval,"ABSTRACT") ) {
                                LDAP_FREE(sval);
                                if ( seen_kind ) {
@@ -2573,6 +2593,7 @@ ldap_str2objectclass( LDAP_CONST char * s,
                                        ldap_objectclass_free(oc);
                                        return NULL;
                                }
+                               *code = 0;
                                parse_whsp(&ss);
                        } else if ( !strcasecmp(sval,"MAY") ) {
                                LDAP_FREE(sval);
@@ -2589,10 +2610,12 @@ ldap_str2objectclass( LDAP_CONST char * s,
                                        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);
@@ -2644,7 +2667,7 @@ ldap_str2contentrule( LDAP_CONST char * s,
        LDAP_CONST char ** errp,
        LDAP_CONST unsigned flags )
 {
-       int kind;
+       tk_t kind;
        const char * ss = s;
        char * sval;
        int seen_name = 0;
@@ -2898,7 +2921,8 @@ ldap_str2structurerule( LDAP_CONST char * s,
        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;
@@ -3081,7 +3105,7 @@ ldap_str2nameform( LDAP_CONST char * s,
        LDAP_CONST char ** errp,
        LDAP_CONST unsigned flags )
 {
-       int kind;
+       tk_t kind;
        const char * ss = s;
        char * sval;
        int seen_name = 0;
index 2c1be570f62a2df1c59cafa200ff93af650fd705..ecfb3808b17910fb1c75f137d6c3465334d6cfbd 100644 (file)
@@ -1228,14 +1228,9 @@ ldap_url_duplist (LDAPURLDesc *ludlist)
        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;
@@ -1254,7 +1249,7 @@ ldap_url_parselist_ext (LDAPURLDesc **ludlist, const char *url, const char *sep
        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);
@@ -1268,6 +1263,18 @@ ldap_url_parselist_ext (LDAPURLDesc **ludlist, const char *url, const char *sep
        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,
index 04a71b645c710a9c67a9c0b9c4836f4a6989fdbb..440b5a75e50084021643b9c35b76aedb7b0bfe64 100644 (file)
@@ -96,9 +96,15 @@ static ldap_pvt_thread_mutex_t ldap_pvt_thread_pool_mutex;
 
 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);
 }
 
@@ -652,6 +658,8 @@ void *ldap_pvt_thread_pool_context( )
        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) &&
@@ -660,4 +668,15 @@ void *ldap_pvt_thread_pool_context( )
        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 */
index 940eafd88b4206a60c0992f162765eb198741170..8f6fda6129ccbed43d772e5d594980255de2cfa3 100644 (file)
@@ -303,10 +303,15 @@ lutil_passwd(
        }
 
 #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
index ac616e16d040b5815b0b76b95f21903cfe2fb20d..fb8dbf6ee47d7fd1c3fc3e544bd73bf7acadd44b 100644 (file)
@@ -206,7 +206,7 @@ struct rewrite_rule {
        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
index b3fba216e94aa8b9c1718ea5f5a74dbab97447d4..84ff22b4175918c505e6dd3fad817dc12914d026 100644 (file)
@@ -418,7 +418,9 @@ recurse:;
                        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 );
                }
index 2ae075d17b26ab176a925207dc6eb71e60b80c40..f774b1322c26d2a17554a21b14312773c8a32d63 100644 (file)
@@ -38,6 +38,7 @@ SRCS  = main.c globals.c bconfig.c config.c daemon.c \
                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 \
@@ -55,6 +56,7 @@ 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.
index df2f937f497ad88b3dcadf832bfed1ac6ffc4f57..006a8c8f398eb178aa14f64c559ce7d415a9f1f1 100644 (file)
@@ -51,6 +51,9 @@ do_abandon( Operation *op, SlapReply *rs )
                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;
diff --git a/servers/slapd/aci.c b/servers/slapd/aci.c
new file mode 100644 (file)
index 0000000..6b44e80
--- /dev/null
@@ -0,0 +1,1620 @@
+/* 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 */
+
index d1801f898dc96f698081bac709ae2f2fa75a8292..e89f1406b67a9b8dd4a6ada995c408a8df9e3026 100644 (file)
 /*
  * 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,
@@ -102,35 +98,17 @@ static slap_control_t slap_acl_mask(
        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
@@ -214,8 +192,12 @@ slap_access_allowed(
         * 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 )
        {
@@ -406,10 +388,17 @@ access_allowed_mask(
 
        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 ) {
@@ -550,10 +539,17 @@ access_allowed_mask(
 
        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 ) {
@@ -617,8 +613,12 @@ access_allowed_mask(
         * 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 )
        {
@@ -1148,7 +1148,7 @@ acl_mask_dn(
                                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 ) )
                        {
@@ -1387,14 +1387,15 @@ slap_acl_mask(
        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 );
@@ -1506,7 +1507,7 @@ slap_acl_mask(
 
                                        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;
@@ -1551,7 +1552,7 @@ slap_acl_mask(
                                                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;
@@ -1608,7 +1609,7 @@ slap_acl_mask(
 
                                                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;
@@ -1627,11 +1628,12 @@ slap_acl_mask(
                                                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 ) {
@@ -1670,11 +1672,14 @@ slap_acl_mask(
                                                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;
@@ -1709,7 +1714,7 @@ slap_acl_mask(
 
                                        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;
@@ -1817,7 +1822,7 @@ slap_acl_mask(
                                        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 ) )
                                {
@@ -1902,7 +1907,7 @@ slap_acl_mask(
                                        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 ) )
                                {
@@ -1913,7 +1918,7 @@ slap_acl_mask(
                                bv = b->a_set_pat;
                        }
                        
-                       if ( aci_match_set( &bv, op, e, 0 ) == 0 ) {
+                       if ( acl_match_set( &bv, op, e, 0 ) == 0 ) {
                                continue;
                        }
                }
@@ -1973,7 +1978,7 @@ slap_acl_mask(
                        /* 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;
                        }
 
@@ -1982,7 +1987,11 @@ slap_acl_mask(
                        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 );
@@ -2067,11 +2076,11 @@ slap_acl_mask(
                                * 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;
@@ -2098,13 +2107,13 @@ slap_acl_mask(
                                                        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 )
                                                        {
@@ -2213,6 +2222,8 @@ slap_acl_mask(
                        *mask = modmask;
                }
 
+               a2pmask = *mask;
+
                Debug( LDAP_DEBUG_ACL,
                        "<= acl_mask: [%d] mask: %s\n",
                        i, accessmask2str(*mask, accessmaskbuf, 1), 0 );
@@ -2248,8 +2259,7 @@ int
 acl_check_modlist(
        Operation       *op,
        Entry   *e,
-       Modifications   *mlist
-)
+       Modifications   *mlist )
 {
        struct berval *bv;
        AccessControlState state = ACL_STATE_INIT;
@@ -2301,7 +2311,9 @@ acl_check_modlist(
                 * 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 );
@@ -2316,7 +2328,9 @@ acl_check_modlist(
                         * 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;
@@ -2334,7 +2348,9 @@ acl_check_modlist(
                                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;
@@ -2345,7 +2361,9 @@ acl_check_modlist(
                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;
@@ -2357,7 +2375,9 @@ acl_check_modlist(
                                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;
@@ -2382,8 +2402,8 @@ done:
        return( ret );
 }
 
-static int
-aci_get_part(
+int
+acl_get_part(
        struct berval   *list,
        int             ix,
        char            sep,
@@ -2425,15 +2445,15 @@ aci_get_part(
        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 ];
@@ -2476,17 +2496,17 @@ aci_set_cb_gather( Operation *op, SlapReply *rs )
 }
 
 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=*)" );
 
@@ -2495,7 +2515,7 @@ aci_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de
         * 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 );
@@ -2616,9 +2636,9 @@ url_done:;
 }
 
 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;
@@ -2649,17 +2669,16 @@ aci_set_gather2( SetCookie *cookie, struct berval *name, AttributeDescription *d
        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 );
@@ -2672,12 +2691,12 @@ aci_match_set (
                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 ];
                }
 
                /*
@@ -2707,7 +2726,7 @@ aci_match_set (
        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 );
        }
@@ -2715,698 +2734,6 @@ aci_match_set (
        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
 
 /*
@@ -3467,28 +2794,24 @@ slap_dynacl_get( const char *name )
 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,
@@ -3572,8 +2895,8 @@ string_expand(
        *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;
 }
@@ -3599,7 +2922,7 @@ regex_matches(
                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];
index 30a4b455f62eb25721d7e250bd471da7ff52d540..e307b550c58663d1ad983ac1879b7331c98888ea 100644 (file)
@@ -70,7 +70,14 @@ static int           check_scope( BackendDB *be, AccessControl *a );
 
 #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;
@@ -93,7 +100,7 @@ slap_dynacl_config( const char *fname, int lineno, Access *b, const char *name,
        *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;
@@ -1109,7 +1116,7 @@ parse_acl(
                                                }
 
                                        } 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,
@@ -1490,17 +1497,23 @@ parse_acl(
 
 #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 );
@@ -1539,7 +1552,7 @@ parse_acl(
                                                }
 
                                        } 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,
@@ -2119,10 +2132,10 @@ acl_usage( void )
                        "\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"
@@ -2250,6 +2263,22 @@ access_free( Access *a )
        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 );
 }
 
@@ -2263,6 +2292,9 @@ acl_free( AccessControl *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 ) {
@@ -2523,8 +2555,9 @@ access2text( Access *b, char *ptr )
 
                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 );
                        }
index 5258dc3fc3d2902b4c8a4c9f92ee6532a20eaaed..e3c64a2445cc54f4cc96ead3b6851c0cd3bc2cb8 100644 (file)
@@ -557,6 +557,20 @@ int ad_inlist(
                        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
@@ -723,9 +737,12 @@ int slap_bv2undef_ad(
                /* 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 ) {
index d0738ed01a43da4c6f3cdb19c6eeb965e8d63abd..5b9a5bba0ff8cec039e38946046945ca5b54036e 100644 (file)
@@ -111,7 +111,7 @@ attr_dup( Attribute *a )
        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 */ ;
@@ -129,13 +129,17 @@ attr_dup( Attribute *a )
                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;
index 581fe1abd6354503258d41e932117cc54288d197..33ef87d559249344e0cba3acc4ac78b0dc24d6eb 100644 (file)
 #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>
@@ -87,179 +81,6 @@ bdb_db_init( BackendDB *be )
        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 )
 {
@@ -268,7 +89,8 @@ 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,
@@ -297,7 +119,7 @@ bdb_db_open( BackendDB *be )
                        bdb->bi_dbenv_home, errno, 0 );
                        return -1;
        }
-       
+
        /* Perform database use arbitration/recovery logic */
        rc = alock_open( &bdb->bi_alock_info, 
                                "slapd", 
@@ -310,19 +132,8 @@ bdb_db_open( BackendDB *be )
                        "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", 
@@ -334,30 +145,26 @@ bdb_db_open( BackendDB *be )
                        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 {
@@ -367,10 +174,6 @@ bdb_db_open( BackendDB *be )
                        "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 ) {
@@ -380,34 +183,14 @@ bdb_db_open( BackendDB *be )
                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);
@@ -419,28 +202,199 @@ bdb_db_open( BackendDB *be )
                }
        }
 
-       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;
@@ -524,6 +478,13 @@ bdb_db_open( BackendDB *be )
                        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;
@@ -624,32 +585,6 @@ bdb_db_close( BackendDB *be )
                                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 );
index a7525be1d813774c8ad10c7c6ad86b5d199f3a04..f05b725b2698ad04a5b389049e8a8f3bf58afadf 100644 (file)
@@ -477,7 +477,7 @@ dn2entry_retry:
                        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 */
 
@@ -850,6 +850,12 @@ fetch_entry_retry:
 
                        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;
                                }
index e27e6a0255b8e9b5b57055f5a7d908f4c87e016d..96a9c3b94d089b216d1810a44f701a9abaf6ef71 100644 (file)
@@ -69,7 +69,8 @@ ldap_back_add(
 
        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;
                }
 
index 2d1131f5aabb7e1f0b3442fa38843e9111932fae..5f6960abed0ecc9f2af8f189ba1bb368a8acc67b 100644 (file)
@@ -105,19 +105,11 @@ done:;
 
                /* 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 );
@@ -294,7 +286,7 @@ ldap_back_start_tls(
                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 );
@@ -382,7 +374,6 @@ retry:;
                *is_tls = 0;
        }
 
-error_return:;
        return rc;
 }
 #endif /* HAVE_TLS */
@@ -393,7 +384,9 @@ ldap_back_prepare_conn( struct ldapconn **lcp, Operation *op, SlapReply *rs, lda
        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 );
 
@@ -428,7 +421,9 @@ ldap_back_prepare_conn( struct ldapconn **lcp, Operation *op, SlapReply *rs, lda
        }
        (*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 ) {
@@ -464,16 +459,28 @@ ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok )
                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 {
@@ -513,6 +520,7 @@ ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok )
                        }
                }
 
+#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
@@ -537,6 +545,7 @@ ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok )
                                goto done;
                        }
                }
+#endif /* HAVE_TLS */
 
                lc->lc_bound = 0;
 
@@ -802,7 +811,7 @@ ldap_back_op_result(
         * 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 */
@@ -865,7 +874,7 @@ retry:;
                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 */
index cf8aa6642fe133ab33fc1aaacf1f3b306e19febe..7968dc5331ece72a218cd054e96c080d6fb29e3c 100644 (file)
@@ -1576,6 +1576,9 @@ ldap_back_exop_whoami(
                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;
index 6ba89953ea684b3c0216b386dd2ce080ee224707..adc0b649ad67de3d04ad71f290b73b4cde0c04f7 100644 (file)
@@ -64,7 +64,8 @@ ldap_back_modify(
 
        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;
                }
 
index 85c334f9c98315df16e4eeae8aa1e08eca89b702..09ad79807e647dd5a62fedcc306747acb3b7da50 100644 (file)
@@ -179,6 +179,7 @@ ldap_back_search(
 
        } else {
                tv.tv_sec = 0;
+               tv.tv_usec = 100000;
        }
 
        if ( op->ors_attrs ) {
@@ -394,6 +395,15 @@ fail:;
                                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 );
@@ -536,7 +546,9 @@ ldap_build_entry(
                }
 
                /* 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
@@ -544,6 +556,10 @@ ldap_build_entry(
                         * 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] */ );
 
index 94dd13553f633cf2c0388786d593d17e390bfe13..47e7886ee1a945c131ec298c6c3fd7f866b90fb2 100644 (file)
@@ -47,6 +47,9 @@ ldbm_back_search(
        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);
 
@@ -130,10 +133,16 @@ ldbm_back_search(
        }
 
 #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);
index 9628cdd6ecd4739c1c0c11be478178764f38b8fb..fe383f230cfe99d74f623b10f1fa56a90334c40c 100644 (file)
@@ -83,7 +83,8 @@ meta_back_add( Operation *op, SlapReply *rs )
        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;
                }
 
index daf6e85df9f35567073ccb978bf88b50f68442f6..df9bfdf0237bfbad3791b69c1b225bfb464d0e0f 100644 (file)
@@ -203,6 +203,7 @@ enum {
 
 typedef struct metatarget_t {
        char                    *mt_uri;
+       int                     mt_scope;
 
        struct berval           mt_psuffix;             /* pretty suffix */
        struct berval           mt_nsuffix;             /* normalized suffix */
@@ -351,6 +352,7 @@ meta_back_conn_dup(
 extern int
 meta_back_is_candidate(
        struct berval           *nsuffix,
+       int                     suffixscope,
        struct berval           *ndn,
        int                     scope );
 
index f7bc68ff87d094c882237c39bd563e16de60530e..3ce113c13092dd43d6ad152fde305530b5315b6f 100644 (file)
@@ -129,6 +129,11 @@ meta_back_bind( Operation *op, SlapReply *rs )
                        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;
                }
@@ -211,7 +216,7 @@ rebind:;
                        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;
 
@@ -234,6 +239,8 @@ retry:;
                                if ( nretries > 0 ) {
                                        nretries--;
                                }
+                               tv.tv_sec = 0;
+                               tv.tv_usec = 100000;
                                goto retry;
                        }
                        rs->sr_err = LDAP_BUSY;
@@ -380,7 +387,7 @@ rebind:;
                        NULL, NULL, &msgid );
        if ( rc == LDAP_SUCCESS ) {
                LDAPMessage     *res;
-               struct timeval  tv;
+               struct timeval  tv = { 0, 100000 };
 
                /*
                 * handle response!!!
@@ -401,6 +408,8 @@ retry:;
                                if ( nretries > 0 ) {
                                        nretries--;
                                }
+                               tv.tv_sec = 0;
+                               tv.tv_usec = 100000;
                                goto retry;
                        }
 
@@ -502,15 +511,22 @@ meta_back_dobind(
 {
        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
@@ -546,8 +562,23 @@ meta_back_dobind(
                        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 );
 
@@ -563,6 +594,10 @@ meta_back_dobind(
                         * so better clear the handle
                         */
                        candidates[ i ].sr_tag = META_NOT_CANDIDATE;
+                       if ( META_BACK_ONERR_STOP( mi ) ) {
+                               bound = 0;
+                               goto done;
+                       }
                        continue;
                } /* else */
                
index a59606ff702c67b449f02b1385bb7d0fc38f8b51..aa8c7628df6bdf65931d52121a10919903ff9406 100644 (file)
@@ -23,6 +23,7 @@
 #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 ) ) {
@@ -76,28 +112,6 @@ meta_back_is_candidate(
        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
  *
@@ -114,7 +128,9 @@ 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;
index 9fd06be3e0f0bb68e49dea5e4dbf8c02bcbf8168..0b5adf6b35c9d88787aa80df40f366d1b6bef158 100644 (file)
@@ -179,7 +179,7 @@ meta_back_compare( Operation *op, SlapReply *rs )
                        struct timeval          tv = { 0 };
 
                        tv.tv_sec = 0;
-                       tv.tv_usec = 0;
+                       tv.tv_usec = 100000;    /* 0.1 s */
 
                        if ( msgid[ i ] == -1 ) {
                                continue;
index 24f357ed5ecb4c80fad48f2d4bf450d3e1e88b3f..996161ddedd5851e958319fd7c51871af3f843a0 100644 (file)
@@ -159,9 +159,7 @@ meta_back_db_config(
                /*
                 * 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 ) {
@@ -173,6 +171,25 @@ meta_back_db_config(
 
                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' ) {
@@ -183,10 +200,6 @@ meta_back_db_config(
                                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 );
index 422107d78d7cb82693b8fffc00e4e2dd6ebd30d9..5f10ce40d22098c084969528b92e6015e673d4e2 100644 (file)
@@ -526,6 +526,7 @@ meta_back_get_candidate(
                         * 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;
@@ -538,6 +539,9 @@ meta_back_get_candidate(
                        }
                        break;
                }
+
+       } else {
+               rs->sr_err = LDAP_SUCCESS;
        }
 
        return candidate;
@@ -795,6 +799,13 @@ meta_back_getconn(
                        }
        
                        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;
@@ -803,18 +814,27 @@ meta_back_getconn(
                                        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;
                }
 
@@ -894,6 +914,7 @@ meta_back_getconn(
                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 ) )
                        {
 
index f2b40d24a409d32e08c1b13eb1160affd41373fd..f6d2e9f428d021e8b5bc339067760fc16a764ac4 100644 (file)
@@ -89,7 +89,8 @@ meta_back_modify( Operation *op, SlapReply *rs )
        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;
                }
 
index 30e0d9ba22d5f972efcacab5495677b8e7c3fe15..bad6c95f775e827636a2f7427262c1e14a51797d 100644 (file)
@@ -97,6 +97,11 @@ meta_back_search_start(
                                        &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 {
                                /*
@@ -124,7 +129,11 @@ meta_back_search_start(
                                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 */
                                {
@@ -311,8 +320,20 @@ meta_back_search( Operation *op, SlapReply *rs )
 #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;
@@ -693,17 +714,52 @@ really_bad:;
         * 
         * 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
@@ -742,8 +798,6 @@ really_bad:;
        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;
@@ -751,7 +805,7 @@ really_bad:;
 
 finish:;
        if ( matched ) {
-               free( matched );
+               op->o_tmpfree( matched, op->o_tmpmemctx );
        }
 
        if ( rs->sr_v2ref ) {
@@ -786,7 +840,7 @@ finish:;
 
        meta_back_release_conn( op, mc );
 
-       return rc;
+       return rs->sr_err;
 }
 
 static int
@@ -848,7 +902,9 @@ meta_send_entry(
 
        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 );
@@ -882,7 +938,9 @@ meta_send_entry(
                }
 
                /* 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
@@ -890,6 +948,10 @@ meta_send_entry(
                         * 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] */ );
 
@@ -902,11 +964,23 @@ meta_send_entry(
                {
                        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 );
@@ -943,10 +1017,33 @@ meta_send_entry(
 
                } 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 ) );
@@ -966,6 +1063,7 @@ meta_send_entry(
 
                *attrp = attr;
                attrp = &attr->a_next;
+next_attr:;
        }
        rs->sr_entry = &ent;
        rs->sr_attrs = op->ors_attrs;
index 63a3d00a98c7e4b0fa1b4741f849087794c82446..18feb7df24433419ff42dbc35ad5838084db8fbd 100644 (file)
@@ -835,11 +835,14 @@ backend_check_controls(
                }
        }
 
+       /* 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;
@@ -1663,7 +1666,7 @@ fe_aux_operational(
                /* 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 )
                {
index d050122be294e76f174044fb3474f2d60a8f41bb..8e9156cf378fef583bf284b8994f6662c8ab64c7 100644 (file)
@@ -2600,8 +2600,10 @@ config_setup_ldif( BackendDB *be, const char *dir, int readit ) {
                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;
 
@@ -2631,7 +2633,7 @@ config_setup_ldif( BackendDB *be, const char *dir, int readit ) {
                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;
@@ -3980,14 +3982,16 @@ config_back_db_open( BackendDB *be )
        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;
@@ -4098,8 +4102,8 @@ config_back_db_open( BackendDB *be )
                        }
                }
        }
-       if ( op )
-               slap_sl_mem_destroy( NULL, op->o_tmpmemctx );
+       if ( thrctx )
+               ldap_pvt_thread_pool_context_reset( thrctx );
 
        return 0;
 }
index c1b288c6d52bb5739995d0e6ed4c3f132bb68c73..16289a9d47f7595060d41d9882d0757dbec7637b 100644 (file)
@@ -60,6 +60,9 @@ int cancel_extop( Operation *op, SlapReply *rs )
                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 ) {
index 56c02c2f7a199bf076fc1c228ccc7d21b221a763..217ba8da08812a91fb7035201cb69957c8e85522 100644 (file)
@@ -50,6 +50,8 @@ static Connection *connections = NULL;
 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
@@ -191,7 +193,7 @@ int connections_shutdown(void)
                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 );
@@ -222,7 +224,7 @@ int connections_timeout_idle(time_t now)
 
                if( difftime( c->c_activitytime+global_idletimeout, now) < 0 ) {
                        /* close it */
-                       connection_closing( c );
+                       connection_closing( c, "idletimeout" );
                        connection_close( c );
                        i++;
                }
@@ -492,6 +494,7 @@ long connection_init(
        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 );
@@ -563,6 +566,7 @@ long connection_init(
 
        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;
@@ -625,6 +629,7 @@ connection_destroy( Connection *c )
        /* 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 );
@@ -635,6 +640,7 @@ connection_destroy( Connection *c )
 
        /* 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);
 
@@ -672,9 +678,10 @@ connection_destroy( Connection *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 );
@@ -688,6 +695,7 @@ connection_destroy( Connection *c )
 
        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 */
@@ -740,7 +748,7 @@ static void connection_abandon( Connection *c )
        }
 }
 
-void connection_closing( Connection *c )
+void connection_closing( Connection *c, const char *why )
 {
        assert( connections != NULL );
        assert( c != NULL );
@@ -758,6 +766,7 @@ void connection_closing( Connection *c )
                        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 );
@@ -773,6 +782,9 @@ void connection_closing( Connection *c )
                        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;
        }
 }
 
@@ -1085,7 +1097,8 @@ operations_error:
        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:
@@ -1144,6 +1157,7 @@ void connection_client_stop(
        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 );
 }
@@ -1209,7 +1223,7 @@ int connection_read(ber_socket_t s)
                                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
@@ -1247,6 +1261,9 @@ int connection_read(ber_socket_t s)
                                        "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 );
                }
@@ -1281,7 +1298,7 @@ int connection_read(ber_socket_t s)
                                "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 );
@@ -1310,7 +1327,7 @@ int connection_read(ber_socket_t s)
                        "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 );
index 383b945e0073898b0561518b2cb717194bf6e6eb..3bfbdf179e22a8fb4fc3fda508cff74ddb34bf84 100644 (file)
@@ -32,9 +32,6 @@ static SLAP_CTRL_PARSE_FN parseProxyAuthz;
 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
@@ -104,15 +101,15 @@ static char *proxy_authz_extops[] = {
 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),
@@ -162,12 +159,6 @@ static struct slap_control control_defs[] = {
                (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),
@@ -703,34 +694,6 @@ return_results:
        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,
index 24bc185ff5376d1ab4aab97ddf3ff12948740920..a47d1c418f25e8432cd8a82d8f89913f1d5b29c1 100644 (file)
@@ -996,7 +996,7 @@ dnRelativeMatch(
                                        asserted->bv_val, 
                                        asserted->bv_len );
                        } else {
-                               return 1;
+                               match = 1;
                        }
                }
 
@@ -1022,7 +1022,7 @@ dnRelativeMatch(
                                        asserted->bv_val, 
                                        asserted->bv_len );
                        } else {
-                               return 1;
+                               match = 1;
                        }
                }
 
@@ -1049,7 +1049,7 @@ dnRelativeMatch(
                                        match = dnIsOneLevelRDN( &rdn ) ? 0 : 1;
                                }
                        } else {
-                               return 1;
+                               match = 1;
                        }
                }
 
index 36c42e446ecfc61baa9f6526036eb8cda6ed6a4d..33a8a11807be07f392305a05ac79844c4f1b9b0c 100644 (file)
@@ -166,6 +166,8 @@ do_extended(
 
        /* 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" );
@@ -196,6 +198,8 @@ fe_extended( Operation *op, SlapReply *rs )
 
        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,
@@ -328,6 +332,9 @@ whoami_extop (
                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 ) {
index 1cac009c99b3eaeb9f366d9eae9a0e0fb00efc4f..1096af18fcc3fcd49e88408538b7de54ddf8a478 100644 (file)
@@ -404,7 +404,17 @@ int main( int argc, char **argv )
 
                                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 )
index 56d6c0bf4aaa23b1ae63ef334851ba9b0bc32a56..ba5477b7f8f4845d6065d2822633212f59038c21 100644 (file)
@@ -140,7 +140,7 @@ do_modify(
                                        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 );
@@ -184,8 +184,8 @@ do_modify(
                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 );
@@ -251,10 +251,10 @@ fe_op_modify( Operation *op, SlapReply *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 {
@@ -499,8 +499,9 @@ slap_mods_no_user_mod_check(
        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;
                        }
 
@@ -844,7 +845,7 @@ int slap_mods_opattrs(
        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 );
@@ -854,7 +855,7 @@ int slap_mods_opattrs(
 
                slap_timestamp( &now, &timestamp );
 
-               if( op->o_dn.bv_len == 0 ) {
+               if ( BER_BVISEMPTY( &op->o_dn ) ) {
                        BER_BVSTR( &name, SLAPD_ANONYMOUS );
                        nname = name;
                } else {
@@ -863,10 +864,20 @@ int slap_mods_opattrs(
                }
        }
 
-       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;
@@ -874,139 +885,183 @@ int slap_mods_opattrs(
                        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], &timestamp );
+                               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], &timestamp );
-                       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], &timestamp );
-               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;
 }
index a721a35d6f24be7afe38a54d2be743c22c46c11a..2772d72711fb99387701221a70809497753c91c4 100644 (file)
@@ -57,7 +57,7 @@ int is_object_subclass(
 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
@@ -67,15 +67,16 @@ int is_entry_objectclass(
 
        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;
        }
@@ -83,7 +84,7 @@ int is_entry_objectclass(
        /*
         * 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\") "
@@ -97,19 +98,30 @@ int is_entry_objectclass(
        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;
 }
 
 
@@ -215,7 +227,9 @@ oc_bvfind_undef( struct berval *ocname )
        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;
 }
index 8318ad7ae68387e25c7d2914159f48b8a87863e6..e1caea4dc033d72e99587332903d887028b24b99 100644 (file)
@@ -27,10 +27,15 @@ SRCS = overlays.c \
        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
@@ -97,6 +102,9 @@ translucent.la : translucent.lo
 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); \
@@ -116,7 +124,7 @@ $(LIBRARY): $(OBJS) version.lo
 # 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
index 7a2e66c66a313d84deac1c2c89bb26d285a3afc6..0f46ae2cf2841b44c02a02ea610cfba2aa01f02d 100644 (file)
@@ -65,6 +65,9 @@ extern int translucent_init();
 #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;
@@ -111,6 +114,9 @@ static struct {
 #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 }
 };
index 64daabd22c6ced03217d8f66c3820ed90e474d16..115529014b3d6812e51fc149c3a8153472486eab 100644 (file)
@@ -2,7 +2,7 @@
 /* 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.
  *
@@ -23,7 +23,7 @@
 #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
@@ -111,7 +111,7 @@ static struct schema_info {
                "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' ) "
@@ -119,7 +119,7 @@ static struct schema_info {
                "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' ) "
@@ -127,21 +127,21 @@ static struct schema_info {
                "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' ) "
@@ -155,7 +155,7 @@ static struct schema_info {
                "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 }
 };
@@ -944,6 +944,9 @@ ppolicy_bind( Operation *op, SlapReply *rs )
 {
        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;
@@ -998,9 +1001,9 @@ ppolicy_bind( Operation *op, SlapReply *rs )
 
 /* 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;
 }
 
@@ -1765,6 +1768,11 @@ int ppolicy_init()
                                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,
@@ -1785,11 +1793,11 @@ int ppolicy_init()
 
        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 );
 }
index 5788ccf7b8c7ac247354d8241013ac3ab22eb384..25e12d366fe1f1e24eee27f03dcedefac0b62515 100644 (file)
@@ -39,7 +39,9 @@ static AttributeDescription   *ad_errCode;
 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,
@@ -163,6 +165,7 @@ retcode_op_add( Operation *op, SlapReply *rs )
 typedef struct retcode_cb_t {
        unsigned        rdc_flags;
        ber_tag_t       rdc_tag;
+       AttributeName   *rdc_attrs;
 } retcode_cb_t;
 
 static int
@@ -175,6 +178,9 @@ retcode_cb_response( Operation *op, SlapReply *rs )
                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;
 
@@ -211,7 +217,8 @@ retcode_op_internal( Operation *op, SlapReply *rs )
        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 );
 
@@ -219,6 +226,9 @@ retcode_op_internal( Operation *op, SlapReply *rs )
        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;
@@ -394,6 +404,7 @@ retcode_op_func( Operation *op, SlapReply *rs )
                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;
@@ -448,7 +459,7 @@ retcode_entry_response( Operation *op, SlapReply *rs, Entry *e )
                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;
        }
 
@@ -1025,9 +1036,9 @@ retcode_init( void )
                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 "
@@ -1036,7 +1047,17 @@ retcode_init( void )
                                "$ 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 }
        };
 
index ebe9815438794af469b9c0120ba30b9f642120ae..de1f5a830c40a81d53407b99441ab30a7d5c5567 100644 (file)
@@ -154,7 +154,8 @@ rwm_op_add( Operation *op, SlapReply *rs )
                                }
                        }
 
-               } 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 {
@@ -437,7 +438,8 @@ rwm_op_modify( Operation *op, SlapReply *rs )
                {
                        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 {
@@ -895,6 +897,7 @@ rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN )
                        }
                        
                } 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 )
                {
index 32212d6c6dda5af33f082e3aba9705efd98f4883..f0e9d46b362c0c5d7621d0024dba2e4c31355983 100644 (file)
@@ -206,7 +206,7 @@ rwm_map_config(
                        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;
                        }
                }
index bc8d940615cfcb35733da02a916231e028962615..57d6b466002983ec6f7f8a7efb6fafaa8a9f2d02 100644 (file)
@@ -142,7 +142,7 @@ typedef struct fbase_cookie {
        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 */
@@ -178,6 +178,8 @@ syncprov_state_ctrl(
                }
        }
 
+       /* FIXME: what if entryuuid is NULL or empty ? */
+
        if ( send_cookie && cookie ) {
                ber_printf( ber, "{eOON}",
                        entry_sync_state, &entryuuid_bv, cookie );
@@ -447,8 +449,8 @@ syncprov_findbase( Operation *op, fbase_cookie *fc )
  * 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
@@ -555,6 +557,7 @@ syncprov_findcsn( Operation *op, int mode )
        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];
@@ -579,6 +582,7 @@ syncprov_findcsn( Operation *op, int mode )
        fop.ors_filter = &cf;
        fop.ors_filterstr.bv_val = buf;
 
+again:
        switch( mode ) {
        case FIND_MAXCSN:
                cf.f_choice = LDAP_FILTER_GE;
@@ -595,10 +599,18 @@ syncprov_findcsn( Operation *op, int mode )
                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;
@@ -646,7 +658,14 @@ syncprov_findcsn( Operation *op, int mode )
                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 );
@@ -1592,6 +1611,8 @@ typedef struct searchstate {
        slap_overinst *ss_on;
        syncops *ss_so;
        int ss_present;
+       struct berval ss_ctxcsn;
+       char ss_csnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];
 } searchstate;
 
 static int
@@ -1690,6 +1711,7 @@ syncprov_search_response( Operation *op, SlapReply *rs )
        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
@@ -1700,12 +1722,15 @@ syncprov_search_response( Operation *op, SlapReply *rs )
                        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,
@@ -1716,8 +1741,7 @@ syncprov_search_response( Operation *op, SlapReply *rs )
        } 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? */
@@ -1763,7 +1787,6 @@ syncprov_op_search( Operation *op, SlapReply *rs )
        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;
@@ -1887,21 +1910,15 @@ shortcut:
                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;
@@ -1909,10 +1926,10 @@ shortcut:
                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);
@@ -1920,6 +1937,9 @@ shortcut:
        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;
@@ -2000,7 +2020,7 @@ static ConfigTable spcfg[] = {
                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 },
@@ -2093,19 +2113,6 @@ sp_cf_gen(ConfigArgs *c)
        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.
  */
@@ -2137,6 +2144,7 @@ syncprov_db_open(
        Entry *e;
        Attribute *a;
        int rc;
+       void *thrctx = NULL;
 
        if ( slapMode & SLAP_TOOL_MODE ) {
                return 0;
@@ -2147,6 +2155,7 @@ syncprov_db_open(
                return rc;
        }
 
+       thrctx = ldap_pvt_thread_pool_context();
        connection_fake_init( &conn, op, thrctx );
        op->o_bd = be;
        op->o_dn = be->be_rootdn;
@@ -2200,6 +2209,7 @@ syncprov_db_open(
 
 out:
        op->o_bd->bd_info = (BackendInfo *)on;
+       ldap_pvt_thread_pool_context_reset( thrctx );
        return 0;
 }
 
@@ -2222,17 +2232,15 @@ syncprov_db_close(
                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;
@@ -2255,6 +2263,8 @@ syncprov_db_init(
 
        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;
diff --git a/servers/slapd/overlays/valsort.c b/servers/slapd/overlays/valsort.c
new file mode 100644 (file)
index 0000000..8943452
--- /dev/null
@@ -0,0 +1,544 @@
+/* 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 */
index 738d9add84f0b5ec9970f8ee28d61cb549eced88..3d63e447fe2bf3bc7113e3102aa834c0c8ccfb8d 100644 (file)
@@ -62,6 +62,8 @@ int passwd_extop(
        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;
        }
@@ -74,6 +76,16 @@ int passwd_extop(
        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;
        }
index d25d1f3e238fc75954d6092c55706c3c607f35d1..8881076dd8ce3f4abddee658ad99fa04760ca0df 100644 (file)
 
 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
  */
@@ -71,6 +93,22 @@ LDAP_SLAPD_F (slap_dynacl_t *) slap_dynacl_get LDAP_P(( const char *name ));
 #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
  */
@@ -256,6 +294,10 @@ LDAP_SLAPD_F (void) ava_free LDAP_P((
 /*
  * 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));
@@ -577,7 +619,8 @@ LDAP_SLAPD_F (long) connection_init LDAP_P((
        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));
@@ -1086,39 +1129,41 @@ LDAP_SLAPD_F (int) is_object_subclass LDAP_P((
        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((
@@ -1407,6 +1452,16 @@ LDAP_SLAPD_F (void) schema_destroy LDAP_P(( void ));
 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
@@ -1655,6 +1710,9 @@ LDAP_SLAPD_V (ldap_pvt_thread_mutex_t)    replog_mutex;
 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;
index d1e79bf3396021f4edf08e868b3d673e4ed964d0..6ee58c16a383e08d22a337ddaa91de0727a77059 100644 (file)
@@ -189,7 +189,7 @@ static long send_ldap_ber(
                    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 );
@@ -613,7 +613,12 @@ send_ldap_sasl( Operation *op, SlapReply *rs )
        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
@@ -630,7 +635,12 @@ slap_send_ldap_extended( Operation *op, SlapReply *rs )
        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
@@ -644,7 +654,12 @@ slap_send_ldap_intermediate( Operation *op, SlapReply *rs )
                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
@@ -821,7 +836,7 @@ slap_send_search_entry( Operation *op, SlapReply *rs )
                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;
                        }
@@ -830,14 +845,13 @@ slap_send_search_entry( Operation *op, SlapReply *rs )
                        /* 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;
                                }
                        }
@@ -979,7 +993,7 @@ slap_send_search_entry( Operation *op, SlapReply *rs )
                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;
                        }
@@ -988,7 +1002,7 @@ slap_send_search_entry( Operation *op, SlapReply *rs )
                        /* 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;
                                }
@@ -1319,10 +1333,19 @@ slap_send_search_reference( Operation *op, SlapReply *rs )
 #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 );
 
index 628ddea77cd13aca89dac421590641802f5bfbf0..810c5316c0c823e57500e96748d7157dab463d22 100644 (file)
@@ -29,6 +29,7 @@
 #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 */
@@ -36,9 +37,6 @@ static struct berval supportedFeatures[] = {
        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}
 };
index e92780132f496f81f7342652a0525b062a263328..66c591a956c5496648599ac266b835508f5a078a 100644 (file)
@@ -202,6 +202,14 @@ sasl_ap_lookup( Operation *op, SlapReply *rs )
                                "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 ) ) {
@@ -318,26 +326,69 @@ slap_auxprop_lookup(
 
                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 );
+                       }
                }
        }
 }
index 3e28af1fd6b9bfe390b9b2c573dd8991a2a4feb4..335ae6384383890367ba754ff1d727da232f6dfe 100644 (file)
@@ -452,7 +452,7 @@ is_dn:              bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
        }
 
        /* Grab the searchbase */
-       assert( ludp->lud_dn );
+       assert( ludp->lud_dn != NULL );
        ber_str2bv( ludp->lud_dn, 0, 0, &bv );
        rc = dnValidate( NULL, &bv );
 
@@ -830,7 +830,7 @@ is_dn:              bv.bv_len = val->bv_len - ( bv.bv_val - val->bv_val );
        }
 
        /* Grab the searchbase */
-       assert( ludp->lud_dn );
+       assert( ludp->lud_dn != NULL );
        if ( ludp->lud_dn ) {
                struct berval   out = BER_BVNULL;
 
index d2c3798b419beadfdb208f15e112bad41e150e03..1f1524ec13735e11bd16317d9bc31d9a147fe04c 100644 (file)
@@ -172,7 +172,7 @@ objectclass ( 1.3.6.1.1.1.2.1 NAME 'shadowAccount'
 
 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 ) )
 
index 344acbe974c16145f8f7f71acb7f4b3af42eba50..07fb1f0db647c3a16528b54156e8352f985e283d 100644 (file)
@@ -50,8 +50,6 @@
 #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
@@ -79,6 +77,9 @@ unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
 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,
@@ -126,7 +127,7 @@ static int certificateValidate( Syntax *syntax, struct berval *in )
 #define certificateValidate sequenceValidate
 #endif
 
-static int
+int
 octetStringMatch(
        int *matchp,
        slap_mask_t flags,
@@ -1861,7 +1862,7 @@ telephoneNumberNormalize(
        return LDAP_SUCCESS;
 }
 
-static int
+int
 numericoidValidate(
        Syntax *syntax,
        struct berval *in )
@@ -3423,14 +3424,6 @@ static slap_syntax_defs_rec syntax_defs[] = {
                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' )",
@@ -3847,15 +3840,6 @@ static slap_mrule_defs_rec mrule_defs[] = {
                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,
@@ -3966,4 +3950,7 @@ schema_destroy( void )
        mr_destroy();
        mru_destroy();
        syn_destroy();
+
+       ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
+       ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
 }
index 2b2d8b1e371a4594d479ee97625eec19b7044052..54d16095e674bde82eea7eff2b7bb9535dff79c3 100644 (file)
@@ -551,7 +551,7 @@ static struct slap_schema_ad_map {
                        "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) },
@@ -887,18 +887,6 @@ static struct slap_schema_ad_map {
                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' "
@@ -1028,9 +1016,9 @@ static struct slap_schema_ad_map {
 };
 
 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 */
@@ -1143,6 +1131,12 @@ slap_schema_load( void )
                }
        }
 
+       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 );
                {
@@ -1313,9 +1307,6 @@ slap_schema_load( void )
                }
        }
 
-       slap_at_undefined.sat_syntax = slap_schema.si_syn_octetString;
-       slap_schema.si_at_undefined = &slap_at_undefined;
-
        return LDAP_SUCCESS;
 }
 
index f1d55cab3628a8fc53bd71f9cdea230a4bc91e7a..853ad6a9ec1818b3305fb79e77fca0a1b551f297 100644 (file)
@@ -743,6 +743,10 @@ typedef struct slap_object_class {
        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
@@ -890,9 +894,6 @@ struct slap_internal_schema {
        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;
@@ -914,7 +915,7 @@ struct slap_internal_schema {
 #endif
        AttributeDescription *si_ad_description;
        AttributeDescription *si_ad_seeAlso;
-        
+
        /* Undefined Attribute Type */
        AttributeType   *si_at_undefined;
 
@@ -1158,6 +1159,7 @@ typedef struct slap_mod {
  * 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;
@@ -1257,9 +1259,10 @@ struct slap_op;
 /*
  * "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,
@@ -1268,8 +1271,8 @@ typedef int (slap_dynacl_mask)(
                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;
@@ -1481,6 +1484,53 @@ typedef struct slap_acl_state {
 #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 
@@ -2535,6 +2585,7 @@ typedef struct slap_conn {
        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           */
@@ -2666,7 +2717,6 @@ struct slap_listener {
 #define sl_addr        sl_sa.sa_in_addr
 };
 
-#ifdef SLAPD_MONITOR
 /*
  * Operation indices
  */
@@ -2683,7 +2733,6 @@ enum {
        SLAP_OP_EXTENDED,
        SLAP_OP_LAST
 };
-#endif /* SLAPD_MONITOR */
 
 typedef struct slap_counters_t {
        ldap_pvt_thread_mutex_t sc_sent_mutex;
index 5c273c605d6d4dc1f5b13eeae25194c785b15deb..c6418c9142dab31c8ea1fe5238c7eb1c3843158d 100644 (file)
@@ -424,6 +424,13 @@ slap_tool_init(
                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 ) {
index 4cb4b361a0ab61e98db0ba394599329eb32dc13f..477eb0afe6d427e53fe5f635d74433c5cb2d381b 100644 (file)
@@ -215,9 +215,13 @@ void slapi_sdn_get_parent( const Slapi_DN *sdn, Slapi_DN *sdn_parent )
 {
        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,
index 9670898f4e26d386d651db74bde66aaabf036b2f..48c6d9bc14d0fe325edb5911acdeeaaf2308d0cc 100644 (file)
@@ -190,7 +190,7 @@ slapi_over_call_plugins( Slapi_PBlock *pb, int type )
        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 ) {
index 1b4e5dab5621f1df9b535b7ec607195d104ba132..fa99303b0afc4a13e65137a1a251c029cc5f38f8 100644 (file)
@@ -277,6 +277,7 @@ pblock_get_param_class( int param )
        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:
@@ -472,6 +473,20 @@ pblock_get( Slapi_PBlock *pb, int param, void **value )
                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;
@@ -1203,6 +1218,7 @@ pblock_set( Slapi_PBlock *pb, int param, void *value )
        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;
index 8864b03dd6def0f547f584bcf9eb90ca39328766..2ce38146c6ab14dc447d2cf43a976a8dfc805cdc 100644 (file)
@@ -27,6 +27,9 @@ starttls_extop ( Operation *op, SlapReply *rs )
 {
        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";
index 4ca77f84635cf1356e5011381efd6c6515960dcd..2fdf30b3b4cc8b815e0a7065beabe95c4499ee03 100644 (file)
@@ -609,6 +609,7 @@ do_syncrep2(
                                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 ) ) {
index 0469e308cb9b2a64de156106d7b837252021e6ca..286ece7e2f781fdee859f2f3cef0000f80a36709 100644 (file)
@@ -178,15 +178,16 @@ register_syntax(
 
        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 );
 }
 
index 05f99d66d7c43fac17a93508bef4bd026ca767b6..2726162a01f56314c4ef16f1e143b78ec9bd321c 100644 (file)
@@ -63,5 +63,5 @@ clean-local:  FORCE
        -$(RM) -r testrun *leak *gmon *core
 
 veryclean-local: FORCE
-       @-$(RM) run data schema ucdata
+       @-$(RM) run testdata schema ucdata
 
diff --git a/tests/data/aci.out b/tests/data/aci.out
new file mode 100644 (file)
index 0000000..dd550ef
--- /dev/null
@@ -0,0 +1,68 @@
+# 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)...
index 8e12d5063ec69d198f9882b2e462f10bd81ea820..00b50a84d96b342318f83e3540ff4d31be47af4e 100644 (file)
@@ -1,3 +1,10 @@
+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
@@ -291,7 +298,8 @@ uniqueMember: cn=James A Jones 2,ou=Information Technology Division,ou=People,
 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
@@ -449,3 +457,51 @@ telephoneNumber: +1 313 555 5331
 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
+
index 7a433db11eb265d7d1bc38334641ddee7edbcb8d..e498b0a0cba1e186f01b85ec6cb924fdebccda21 100644 (file)
@@ -31,7 +31,7 @@ retcode-item  "cn=strongAuthRequired"                 0x08
 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"
diff --git a/tests/data/slapd-aci.conf b/tests/data/slapd-aci.conf
new file mode 100644 (file)
index 0000000..1794ec8
--- /dev/null
@@ -0,0 +1,57 @@
+# 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
+
diff --git a/tests/data/slapd-valsort.conf b/tests/data/slapd-valsort.conf
new file mode 100644 (file)
index 0000000..7b8cbf4
--- /dev/null
@@ -0,0 +1,57 @@
+# 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
diff --git a/tests/data/subtree-rename.out b/tests/data/subtree-rename.out
new file mode 100644 (file)
index 0000000..e5f753a
--- /dev/null
@@ -0,0 +1,97 @@
+# 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
+
diff --git a/tests/data/test-valsort.ldif b/tests/data/test-valsort.ldif
new file mode 100755 (executable)
index 0000000..c2c7f3e
--- /dev/null
@@ -0,0 +1,49 @@
+# 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
diff --git a/tests/data/valsort1.out b/tests/data/valsort1.out
new file mode 100755 (executable)
index 0000000..c470762
--- /dev/null
@@ -0,0 +1,45 @@
+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
+
diff --git a/tests/data/valsort2.out b/tests/data/valsort2.out
new file mode 100755 (executable)
index 0000000..c235865
--- /dev/null
@@ -0,0 +1,45 @@
+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
+
diff --git a/tests/data/valsort3.out b/tests/data/valsort3.out
new file mode 100755 (executable)
index 0000000..caefe1e
--- /dev/null
@@ -0,0 +1,61 @@
+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
+
index c96cdccd3528ba2db1f464dff1fba86f36ea58ea..082a7aa3d530e4ab770ca9d34304971ba74aeef4 100644 (file)
@@ -41,12 +41,20 @@ get_add_entry( char *filename, LDAPMod ***mods );
 
 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 );
 }
@@ -64,9 +72,10 @@ main( int argc, char **argv )
        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 );
@@ -96,10 +105,14 @@ main( int argc, char **argv )
                        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;
@@ -128,7 +141,7 @@ main( int argc, char **argv )
        }
 
        do_addel( uri, host, port, manager, passwd, entry, attrs,
-                       loops, retries );
+                       loops, retries, delay );
 
        exit( EXIT_SUCCESS );
 }
@@ -258,7 +271,8 @@ do_addel(
        char *entry,
        LDAPMod **attrs,
        int maxloop,
-       int maxretries
+       int maxretries,
+       int delay
 )
 {
        LDAP    *ld = NULL;
@@ -291,9 +305,19 @@ retry:;
        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 );
        }
index 37e45ec19e339ff26a0639697877782caa0f8f60..c0484dbc5cfa7d6611ff3971a5bbfe17a176b435 100644 (file)
 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 );
 }
@@ -60,8 +68,9 @@ main( int argc, char **argv )
        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 );
@@ -95,10 +104,14 @@ main( int argc, char **argv )
                        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;
@@ -131,7 +144,7 @@ main( int argc, char **argv )
                value++;
 
        do_modify( uri, host, port, manager, passwd, entry, ava, value,
-                       loops, retries );
+                       loops, retries, delay );
        exit( EXIT_SUCCESS );
 }
 
@@ -139,7 +152,7 @@ main( int argc, char **argv )
 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;
@@ -185,9 +198,19 @@ retry:;
        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 );
        }
index 60e85fa77b839f16df3998f1b75ef35784ee9dd7..06b513044269dbbc68033bde43a79533149ab6bf 100644 (file)
 
 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 );
 }
@@ -60,8 +68,9 @@ main( int argc, char **argv )
        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 );
@@ -95,6 +104,10 @@ main( int argc, char **argv )
                        retries = atoi( optarg );
                        break;
 
+               case 't':               /* delay in seconds */
+                       delay = atoi( optarg );
+                       break;
+
                default:
                        usage( argv[0] );
                        break;
@@ -112,14 +125,14 @@ main( int argc, char **argv )
 
        }
 
-       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;
@@ -177,9 +190,19 @@ retry:;
        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 );
        }
index c3c09758b5e6057e03adf611fc2d0b002f1f30a1..c5cb56ce33bd87d9ece5e3acdaa198eeb4a141f2 100644 (file)
 
 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 );
 }
@@ -58,8 +64,9 @@ main( int argc, char **argv )
        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 );
@@ -85,6 +92,10 @@ main( int argc, char **argv )
                        retries = atoi( optarg );
                        break;
 
+               case 't':               /* delay in seconds */
+                       delay = atoi( optarg );
+                       break;
+
                default:
                        usage( argv[0] );
                        break;
@@ -100,14 +111,14 @@ main( int argc, char **argv )
                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;
@@ -140,9 +151,19 @@ retry:;
        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 );
        }
index de42211fca1ef8a8ee28ad3f44f0ff69f166a260..9d9afe1e4fd39b144c1484fd72eca9066edbc585 100644 (file)
 
 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 );
 }
@@ -61,8 +70,9 @@ main( int argc, char **argv )
        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 );
@@ -100,6 +110,10 @@ main( int argc, char **argv )
                        retries = atoi( optarg );
                        break;
 
+               case 't':               /* delay in seconds */
+                       delay = atoi( optarg );
+                       break;
+
                default:
                        usage( argv[0] );
                        break;
@@ -118,14 +132,14 @@ main( int argc, char **argv )
        }
 
        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;
@@ -157,11 +171,21 @@ retry:;
 
        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 );
        }
 
@@ -172,8 +196,8 @@ retry:;
                                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;
@@ -188,5 +212,3 @@ retry:;
 
        ldap_unbind( ld );
 }
-
-
index 7d14de72c6f7eab833bffa36eff9b66e2d569a72..c8d4d57f25cd0efc1568c1f0fa523d5f15f4f268 100644 (file)
@@ -71,7 +71,18 @@ static char argbuf[BUFSIZ];
 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 );
 }
 
@@ -88,6 +99,7 @@ main( int argc, char **argv )
        char            *progdir = NULL;
        char            *loops = LOOPS;
        char            *retries = RETRIES;
+       char            *delay = "0";
        DIR                     *datadir;
        struct dirent   *file;
        char            *sfile = NULL;
@@ -122,7 +134,7 @@ main( int argc, char **argv )
        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 );
@@ -156,10 +168,14 @@ main( int argc, char **argv )
                        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;
@@ -254,6 +270,8 @@ main( int argc, char **argv )
        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";
@@ -281,6 +299,8 @@ main( int argc, char **argv )
        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;
@@ -310,6 +330,8 @@ main( int argc, char **argv )
        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;
@@ -339,6 +361,8 @@ main( int argc, char **argv )
        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";;
@@ -370,6 +394,8 @@ main( int argc, char **argv )
        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;
index f4a46d47ce078b391d17ab5fcaa94648eceb2ea0..363c48703d1594b2ceab86802f97ffb02d98cb55 100644 (file)
@@ -42,15 +42,18 @@ AC_translucent=translucent@BUILD_TRANSLUCENT@
 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)"
index 2eb536b29b3702d11713e1a11ee834cb1791f683..1f78c01ba305b8e338c5bb3797542c4cfe6adb42 100755 (executable)
 ## 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
@@ -51,9 +50,11 @@ sed -e "s/@BACKEND@/${BACKEND}/"                     \
        -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};"                          \
index 1741c291cce98918a2e377fc0b235248c65ef97c..c504790be92a8d039202fc5e0eb91df73589b076 100755 (executable)
@@ -32,6 +32,8 @@ SYNCPROV=${AC_syncprov-syncprovno}
 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
@@ -95,6 +97,8 @@ TRANSLUCENTREMOTECONF=$DATADIR/slapd-translucent-remote.conf
 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
@@ -120,7 +124,8 @@ SLAPCAT="../servers/slapd/slapd -Tc $LDAP_VERBOSE"
 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
@@ -184,6 +189,7 @@ LDIFTRANSLUCENTCONFIG=$DATADIR/test-translucent-config.ldif
 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"
@@ -204,6 +210,8 @@ TRANSLUCENTDN="uid=binder,o=translucent"
 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
@@ -221,6 +229,9 @@ SEARCHFLT2=$TESTDIR/ldapsearch2.flt
 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
@@ -273,6 +284,8 @@ TRANSLUCENTOUT=$DATADIR/translucent.search.out
 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
index 98ebe373267d89916dba9083ae2ce055e44d9cbc..26ebc768460ac0d093d1bf4b8be649c1c61185b8 100755 (executable)
@@ -71,7 +71,7 @@ fi
 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
index 1d6b9aab28b05d92a5b9f2aba3d3c8d2973c0c5f..d6651a67249ee63e941babcfa21aa171aada9a8a 100755 (executable)
@@ -49,8 +49,10 @@ if test $RC = 0 ; then
 
 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
@@ -67,8 +69,8 @@ if test $RC != 0 ; then
        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"
index 5f101d61b30f55b7af228ec48bfeadf799c892c0..0adb6ebbdd17ef398aa61acb213316488914a102 100755 (executable)
@@ -161,18 +161,18 @@ if test $RC != 0 ; then
        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
index 3a3b3ded3ac2e2add427c0f3fa437c0f831321a4..f78e257cd1b9af20caf483e5fd115a18ac43040c 100755 (executable)
@@ -54,7 +54,7 @@ if test $RC != 0 ; then
 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
index 32900758369844ec4d40ac7787a88ed7d6fa8a53..9951fa848b03b590658c6ca5effcb65dd3610921 100755 (executable)
@@ -28,7 +28,7 @@ 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)!"
index 11cf238d42ffbe2752427d0956bf044a59cc9d8f..f28ec6ff0f21e316e2007ed4deb8bea7ce322a02 100755 (executable)
@@ -111,6 +111,32 @@ changetype: modify
 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=$?
@@ -161,7 +187,6 @@ delete: structuralObjectClass
 -
 add: structuralObjectClass
 structuralObjectClass: testPerson
-
 EOMODS
 
 RC=$?
@@ -175,6 +200,25 @@ echo "Using ldapsearch to retrieve all the entries..."
 $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)!"
diff --git a/tests/scripts/test040-subtree-rename b/tests/scripts/test040-subtree-rename
new file mode 100755 (executable)
index 0000000..f212a5c
--- /dev/null
@@ -0,0 +1,207 @@
+#! /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
diff --git a/tests/scripts/test041-aci b/tests/scripts/test041-aci
new file mode 100755 (executable)
index 0000000..0329c5c
--- /dev/null
@@ -0,0 +1,252 @@
+#! /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
diff --git a/tests/scripts/test042-valsort b/tests/scripts/test042-valsort
new file mode 100755 (executable)
index 0000000..fd86e31
--- /dev/null
@@ -0,0 +1,219 @@
+#! /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