]> git.sur5r.net Git - openldap/commitdiff
Sync with HEAD
authorKurt Zeilenga <kurt@openldap.org>
Wed, 17 Aug 2005 18:15:34 +0000 (18:15 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Wed, 17 Aug 2005 18:15:34 +0000 (18:15 +0000)
46 files changed:
contrib/slapd-modules/acl/README [new file with mode: 0644]
contrib/slapd-modules/acl/posixgroup.c [new file with mode: 0644]
doc/man/man5/slapo-syncprov.5
doc/man/man5/slapo-unique.5
doc/man/man8/slapcat.8
include/slapi-plugin.h
libraries/libldap/url.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/back-bdb/search.c
servers/slapd/back-ldap/bind.c
servers/slapd/back-ldap/config.c
servers/slapd/back-ldap/search.c
servers/slapd/back-meta/back-meta.h
servers/slapd/back-meta/bind.c
servers/slapd/back-meta/candidates.c
servers/slapd/back-meta/config.c
servers/slapd/back-meta/conn.c
servers/slapd/back-meta/search.c
servers/slapd/cancel.c
servers/slapd/connection.c
servers/slapd/dn.c
servers/slapd/extended.c
servers/slapd/overlays/ppolicy.c
servers/slapd/overlays/syncprov.c
servers/slapd/passwd.c
servers/slapd/proto-slap.h
servers/slapd/result.c
servers/slapd/sasl.c
servers/slapd/saslauthz.c
servers/slapd/schema/nis.schema
servers/slapd/schema_init.c
servers/slapd/slap.h
servers/slapd/slapi/slapi_pblock.c
servers/slapd/starttls.c
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

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..3f06b7f
--- /dev/null
@@ -0,0 +1,320 @@
+/* $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,
+       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;
+       }
+
+       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 */
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
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 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 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 4b5a60bee262ecabf8ba0e82f2adff61088af4f7..fb8dbf6ee47d7fd1c3fc3e544bd73bf7acadd44b 100644 (file)
@@ -206,10 +206,7 @@ struct rewrite_rule {
        char                           *lr_pattern;
        char                           *lr_subststring;
        char                           *lr_flagstring;
-#ifdef USE_REWRITE_LDAP_PVT_THREADS
-       ldap_pvt_thread_mutex_t         lr_mutex;
-#endif /* USE_REWRITE_LDAP_PVT_THREADS */
-       regex_t                         lr_regex;
+       regex_t                         lr_regex;
 
        /*
         * I was thinking about some kind of per-rule mutex, but there's
index 9be1d844cb91677d793a1c0c66f67ea22a3d2d53..84ff22b4175918c505e6dd3fad817dc12914d026 100644 (file)
@@ -346,14 +346,6 @@ rewrite_rule_compile(
                return REWRITE_ERR;
        }
        
-#ifdef USE_REWRITE_LDAP_PVT_THREADS
-        if ( ldap_pvt_thread_mutex_init( &rule->lr_mutex ) ) {
-               regfree( &rule->lr_regex );
-               free( rule );
-               return REWRITE_ERR;
-       }
-#endif /* USE_REWRITE_LDAP_PVT_THREADS */
-
        /*
         * Just to remember them ...
         */
@@ -427,13 +419,7 @@ recurse:;
        
        op->lo_num_passes++;
 
-#ifdef USE_REWRITE_LDAP_PVT_THREADS
-        ldap_pvt_thread_mutex_lock( &rule->lr_mutex );
-#endif /* USE_REWRITE_LDAP_PVT_THREADS */
        rc = regexec( &rule->lr_regex, string, nmatch, match, 0 );
-#ifdef USE_REWRITE_LDAP_PVT_THREADS
-        ldap_pvt_thread_mutex_unlock( &rule->lr_mutex );
-#endif /* USE_REWRITE_LDAP_PVT_THREADS */
        if ( rc != 0 ) {
                if ( *result == NULL && string != arg ) {
                        free( string );
@@ -503,9 +489,6 @@ rewrite_rule_destroy(
        }
 
        regfree( &rule->lr_regex );
-#ifdef USE_REWRITE_LDAP_PVT_THREADS
-        ldap_pvt_thread_mutex_destroy( &rule->lr_mutex );
-#endif /* USE_REWRITE_LDAP_PVT_THREADS */
 
        for ( action = rule->lr_action; action; ) {
                struct rewrite_action *curraction = action;
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..3d587cd
--- /dev/null
@@ -0,0 +1,1502 @@
+/* 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 */
+
+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 '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; 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/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, 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:
+               /* TODO: use ber_bvcmp */
+               if ( ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_ENTRY ] ) != 0
+                               && ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_SUBTREE ] ) != 0 )
+               {
+                       return 0;
+               }
+               break;
+
+       case SLAP_ACI_SCOPE_CHILDREN:
+               /* TODO: use ber_bvcmp */
+               if ( ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_CHILDREN ] ) != 0
+                               && ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_SUBTREE ] ) != 0 )
+               {
+                       return 0;
+               }
+               break;
+
+       default:
+               /* TODO: add assertion */
+               return 0;
+       }
+
+       /* get the list of permissions clauses, bail if empty */
+       if ( acl_get_part( aci, 2, '#', &perms ) <= 0 ) {
+               /* TODO: add assertion */
+               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 ) {
+               /* TODO: add assertion */
+               return 0;
+       }
+
+       /* see if we have a public (i.e. anonymous) access */
+       /* TODO: use ber_bvcmp */
+       if ( ber_bvstrcasecmp( &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 */
+       /* TODO: use ber_bvcmp */
+       if ( ber_bvstrcasecmp( &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 );
+
+       /* TODO: use ber_bvcmp */
+       if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_ACCESS_ID ], &type ) == 0 ) {
+               struct berval ndn;
+               
+               /* TODO: don't normalize */
+               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;
+
+       /* TODO: use ber_bvcmp */
+       } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_SUBTREE ], &type ) == 0 ) {
+               struct berval ndn;
+               
+               /* TODO: don't normalize */
+               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;
+
+       /* TODO: use ber_bvcmp */
+       } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_ONELEVEL ], &type ) == 0 ) {
+               struct berval ndn, pndn;
+               
+               /* TODO: don't normalize */
+               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;
+
+       /* TODO: use ber_bvcmp */
+       } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_CHILDREN ], &type ) == 0 ) {
+               struct berval ndn;
+               
+               /* TODO: don't normalize */
+               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;
+
+       /* TODO: use ber_bvcmp */
+       } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_SELF ], &type ) == 0 ) {
+               if ( dn_match( &op->o_ndn, &e->e_nname ) ) {
+                       return 1;
+               }
+
+       /* TODO: use ber_bvcmp */
+       } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_DNATTR ], &type ) == 0 ) {
+               Attribute               *at;
+               AttributeDescription    *ad = NULL;
+               const char              *text;
+
+               rc = slap_bv2ad( &sdn, &ad, &text );
+               if ( rc != LDAP_SUCCESS ) {
+                       /* TODO: add assertion */
+                       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;
+
+       /* TODO: use ber_bvcmp */
+       } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_GROUP ], &type ) == 0 ) {
+               if ( aci_group_member( &sdn, &aci_bv[ ACI_BV_GROUP_CLASS ],
+                               &aci_bv[ ACI_BV_GROUP_ATTR ], op, e, nmatch, matches ) )
+               {
+                       return 1;
+               }
+
+       /* TODO: use ber_bvcmp */
+       } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_ROLE ], &type ) == 0 ) {
+               if ( aci_group_member( &sdn, &aci_bv[ ACI_BV_ROLE_CLASS ],
+                               &aci_bv[ ACI_BV_ROLE_ATTR ], op, e, nmatch, matches ) )
+               {
+                       return 1;
+               }
+
+       /* TODO: use ber_bvcmp */
+       } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_SET ], &type ) == 0 ) {
+               if ( acl_match_set( &sdn, op, e, 0 ) ) {
+                       return 1;
+               }
+
+       /* TODO: use ber_bvcmp */
+       } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_SET_REF ], &type ) == 0 ) {
+               if ( acl_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
+};
+
+int
+dynacl_aci_init( void )
+{
+       return slap_dynacl_register( &dynacl_aci );
+}
+
+#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 'c':
+               case 's':
+               case 'r':
+               case 'w':
+               case 'x':
+                       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 ],
+
+       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
+};
+
+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,
+                       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 );
+                               }
+
+                               if ( oc_bvfind( &ocbv ) == 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;
+}
+
+int
+OpenLDAPaciPretty(
+       Syntax          *syntax,
+       struct berval   *val,
+       struct berval   *out,
+       void            *ctx )
+{
+       return OpenLDAPaciPrettyNormal( val, out, ctx, 0 );
+}
+
+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..2f27cf5b5fa139ef9932b99308b0f8a233f72125 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
@@ -1148,7 +1126,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 +1365,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 +1485,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 +1530,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 +1587,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 +1606,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 +1650,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 +1692,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 +1800,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 +1885,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 +1896,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 +1956,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 +1965,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 +2054,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 +2085,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 +2200,8 @@ slap_acl_mask(
                        *mask = modmask;
                }
 
+               a2pmask = *mask;
+
                Debug( LDAP_DEBUG_ACL,
                        "<= acl_mask: [%d] mask: %s\n",
                        i, accessmask2str(*mask, accessmaskbuf, 1), 0 );
@@ -2382,8 +2371,8 @@ done:
        return( ret );
 }
 
-static int
-aci_get_part(
+int
+acl_get_part(
        struct berval   *list,
        int             ix,
        char            sep,
@@ -2425,15 +2414,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 +2465,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 +2484,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 +2605,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 +2638,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 +2660,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 +2695,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 +2703,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
 
 /*
@@ -3468,27 +2764,22 @@ 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;
 
-       for ( i = 0; known_dynacl[ i ]; i++ ) {
-               rc = slap_dynacl_register( known_dynacl[ i ] ); 
-               if ( rc ) {
-                       return rc;
-               }
+#ifdef SLAPD_ACI_ENABLED
+       rc = dynacl_aci_init();
+       if ( rc != 0 ) {
+               return rc;
        }
+#endif /* SLAPD_ACI_ENABLED */
+
 #endif /* SLAP_DYNACL */
 
        return 0;
 }
 
-static int
-string_expand(
+int
+acl_string_expand(
        struct berval   *bv,
        struct berval   *pat,
        char            *match,
@@ -3572,8 +2863,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 +2890,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..5c124830d65478af79fca139662ce35be04e881e 100644 (file)
@@ -1109,7 +1109,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,
@@ -2250,6 +2250,20 @@ access_free( Access *a )
        if ( !BER_BVISNULL( &a->a_group_pat ) ) {
                free( a->a_group_pat.bv_val );
        }
+       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 );
+               }
+       }
        free( a );
 }
 
@@ -2263,6 +2277,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 +2540,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 a7525be1d813774c8ad10c7c6ad86b5d199f3a04..12d7ea3eb6f9e503791565bb3f64dde34ca70120 100644 (file)
@@ -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 d9e395d3ed25f189a5101ab4dbcfe7e16abcd526..09b23924d5f11d5313ac508e30c8350be7804559 100644 (file)
@@ -251,34 +251,25 @@ ldap_back_freeconn( Operation *op, struct ldapconn *lc )
        return 0;
 }
 
+#ifdef HAVE_TLS
 static int
-ldap_back_prepare_conn( struct ldapconn **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
+ldap_back_start_tls(
+       LDAP            *ld,
+       int             protocol,
+       int             *is_tls,
+       const char      *url,
+       unsigned        flags,
+       const char      **text )
 {
-       struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
-       int             vers = op->o_protocol;
-       LDAP            *ld = NULL;
-
-       assert( lcp != NULL );
-
-       rs->sr_err = ldap_initialize( &ld, li->url );
-       if ( rs->sr_err != LDAP_SUCCESS ) {
-               goto error_return;
-       }
-
-       /* Set LDAP version. This will always succeed: If the client
-        * bound with a particular version, then so can we.
-        */
-       ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&vers );
+       int             rc = LDAP_SUCCESS;
+       struct ldapinfo li;
 
-       /* automatically chase referrals ("[dont-]chase-referrals" statement) */
-       if ( LDAP_BACK_CHASE_REFERRALS( li ) ) {
-               ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON );
-       }
+       /* this is ridicolous... */
+       li.flags = flags;
 
-#ifdef HAVE_TLS
        /* start TLS ("tls-[try-]{start,propagate}" statements) */
-       if ( ( LDAP_BACK_USE_TLS( li ) || ( op->o_conn->c_is_tls && LDAP_BACK_PROPAGATE_TLS( li ) ) )
-                               && !ldap_is_ldaps_url( li->url ) )
+       if ( ( LDAP_BACK_USE_TLS( &li ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS( &li ) ) )
+                               && !ldap_is_ldaps_url( url ) )
        {
 #ifdef SLAP_STARTTLS_ASYNCHRONOUS
                /*
@@ -287,16 +278,28 @@ ldap_back_prepare_conn( struct ldapconn **lcp, Operation *op, SlapReply *rs, lda
                 */
                int             msgid;
 
-               rs->sr_err = ldap_start_tls( ld, NULL, NULL, &msgid );
-               if ( rs->sr_err == LDAP_SUCCESS ) {
+               if ( protocol == 0 ) {
+                       ldap_get_option( ld, LDAP_OPT_PROTOCOL_VERSION,
+                                       (void *)&protocol );
+               }
+
+               if ( protocol < LDAP_VERSION3 ) {
+                       protocol = LDAP_VERSION3;
+                       /* Set LDAP version */
+                       ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
+                                       (const void *)&protocol );
+               }
+
+               rc = ldap_start_tls( ld, NULL, NULL, &msgid );
+               if ( rc == LDAP_SUCCESS ) {
                        LDAPMessage     *res = NULL;
-                       int             rc, retries = 1;
+                       int             retries = 1;
                        struct timeval  tv = { 0, 0 };
 
 retry:;
                        rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res );
                        if ( rc < 0 ) {
-                               rs->sr_err = LDAP_OTHER;
+                               rc = LDAP_OTHER;
 
                        } else if ( rc == 0 ) {
                                if ( retries ) {
@@ -305,27 +308,27 @@ retry:;
                                        tv.tv_usec = 100000;
                                        goto retry;
                                }
-                               rs->sr_err = LDAP_OTHER;
+                               rc = LDAP_OTHER;
 
                        } else if ( rc == LDAP_RES_EXTENDED ) {
                                struct berval   *data = NULL;
 
-                               rs->sr_err = ldap_parse_extended_result( ld, res,
+                               rc = ldap_parse_extended_result( ld, res,
                                                NULL, &data, 0 );
-                               if ( rs->sr_err == LDAP_SUCCESS ) {
-                                       rs->sr_err = ldap_result2error( ld, res, 1 );
+                               if ( rc == LDAP_SUCCESS ) {
+                                       rc = ldap_result2error( ld, res, 1 );
                                        res = NULL;
                                        
                                        /* FIXME: in case a referral 
                                         * is returned, should we try
                                         * using it instead of the 
                                         * configured URI? */
-                                       if ( rs->sr_err == LDAP_SUCCESS ) {
-                                               ldap_install_tls( ld );
+                                       if ( rc == LDAP_SUCCESS ) {
+                                               rc = ldap_install_tls( ld );
 
-                                       } else if ( rs->sr_err == LDAP_REFERRAL ) {
-                                               rs->sr_err = LDAP_OTHER;
-                                               rs->sr_text = "unwilling to chase referral returned by Start TLS exop";
+                                       } else if ( rc == LDAP_REFERRAL ) {
+                                               rc = LDAP_OTHER;
+                                               *text = "unwilling to chase referral returned by Start TLS exop";
                                        }
 
                                        if ( data ) {
@@ -337,7 +340,7 @@ retry:;
                                }
 
                        } else {
-                               rs->sr_err = LDAP_OTHER;
+                               rc = LDAP_OTHER;
                        }
 
                        if ( res != NULL ) {
@@ -348,30 +351,87 @@ retry:;
                /*
                 * use synchronous StartTLS
                 */
-               rs->sr_err = ldap_start_tls_s( ld, NULL, NULL );
+               rc = ldap_start_tls_s( ld, NULL, NULL );
 #endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */
 
                /* if StartTLS is requested, only attempt it if the URL
                 * is not "ldaps://"; this may occur not only in case
                 * of misconfiguration, but also when used in the chain 
                 * overlay, where the "uri" can be parsed out of a referral */
-               if ( rs->sr_err == LDAP_SERVER_DOWN
-                               || ( rs->sr_err != LDAP_SUCCESS && LDAP_BACK_TLS_CRITICAL( li ) ) )
-               {
-                       ldap_unbind_ext( ld, NULL, NULL );
-                       goto error_return;
+               switch ( rc ) {
+               case LDAP_SUCCESS:
+                       *is_tls = 1;
+                       break;
+
+               case LDAP_SERVER_DOWN:
+                       break;
+
+               default:
+                       if ( LDAP_BACK_TLS_CRITICAL( &li ) ) {
+                               *text = "could not start TLS";
+                               break;
+                       }
+
+                       /* in case Start TLS is not critical */
+                       *is_tls = 0;
+                       rc = LDAP_SUCCESS;
+                       break;
                }
 
-               /* in case Start TLS is not critical */
-               rs->sr_err = LDAP_SUCCESS;
+       } else {
+               *is_tls = 0;
+       }
+
+       return rc;
+}
+#endif /* HAVE_TLS */
+
+static int
+ldap_back_prepare_conn( struct ldapconn **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
+{
+       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 );
+
+       rs->sr_err = ldap_initialize( &ld, li->url );
+       if ( rs->sr_err != LDAP_SUCCESS ) {
+               goto error_return;
+       }
+
+       /* Set LDAP version. This will always succeed: If the client
+        * bound with a particular version, then so can we.
+        */
+       ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&vers );
+
+       /* automatically chase referrals ("[dont-]chase-referrals" statement) */
+       if ( LDAP_BACK_CHASE_REFERRALS( li ) ) {
+               ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON );
+       }
+
+#ifdef HAVE_TLS
+       rs->sr_err = ldap_back_start_tls( ld,
+                       op->o_protocol, &is_tls,
+                       li->url, li->flags, &rs->sr_text );
+       if ( rs->sr_err != LDAP_SUCCESS ) {
+               ldap_unbind_ext( ld, NULL, NULL );
+               goto error_return;
        }
 #endif /* HAVE_TLS */
 
        if ( *lcp == NULL ) {
                *lcp = (struct ldapconn *)ch_calloc( 1, sizeof( struct ldapconn ) );
+               (*lcp)->lc_flags= li->flags;
        }
        (*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 ) {
@@ -407,14 +467,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 = NULL;
+#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 = NULL;
+#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 {
@@ -454,6 +528,33 @@ 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
+                * connection and use the existing one */
+               if ( lc->lc_conn == LDAP_BACK_PRIV_CONN_TLS
+                               && !ldap_tls_inplace( lc->lc_ld ) )
+               {
+                       struct ldapconn *tmplc;
+                       
+                       lc_curr.lc_conn = LDAP_BACK_PRIV_CONN;
+                       ldap_pvt_thread_mutex_lock( &li->conn_mutex );
+                       tmplc = (struct ldapconn *)avl_find( li->conntree, 
+                                       (caddr_t)&lc_curr, ldap_back_conn_cmp );
+                       if ( tmplc != NULL ) {
+                               refcnt = ++tmplc->lc_refcnt;
+                               ldap_back_conn_free( lc );
+                               lc = tmplc;
+                       }
+                       ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
+
+                       if ( tmplc != NULL ) {
+                               goto done;
+                       }
+               }
+#endif /* HAVE_TLS */
+
                lc->lc_bound = 0;
 
                /* Inserts the newly created ldapconn in the avl tree */
@@ -489,7 +590,8 @@ ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok )
                        "=>ldap_back_getconn: conn %p fetched (refcnt=%u)\n",
                        (void *)lc, refcnt, 0 );
        }
-       
+
+done:;
        return lc;
 }
 
@@ -673,6 +775,22 @@ ldap_back_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request,
 {
        struct ldapconn *lc = (struct ldapconn *)params;
 
+#ifdef HAVE_TLS
+       /* ... otherwise we couldn't get here */
+       assert( lc != NULL );
+
+       if ( !ldap_tls_inplace( ld ) ) {
+               int             is_tls = lc->lc_is_tls,
+                               rc;
+               const char      *text = NULL;
+
+               rc = ldap_back_start_tls( ld, 0, &is_tls, url, lc->lc_flags, &text );
+               if ( rc != LDAP_SUCCESS ) {
+                       return rc;
+               }
+       }
+#endif /* HAVE_TLS */
+
        /* FIXME: add checks on the URL/identity? */
 
        return ldap_sasl_bind_s( ld, lc->lc_bound_ndn.bv_val,
index 7a8af5776a7f370d8e2570bdbee09cc9da9ebd05..7968dc5331ece72a218cd054e96c080d6fb29e3c 100644 (file)
@@ -908,8 +908,22 @@ ldap_back_cf_gen( ConfigArgs *c )
 
        case LDAP_BACK_CFG_IDASSERT_AUTHZFROM: {
                struct berval   bv;
+#ifdef SLAP_AUTHZ_SYNTAX
+               struct berval   in;
+               int             rc;
 
+               ber_str2bv( c->argv[ 1 ], 0, 0, &in );
+               rc = authzNormalize( 0, NULL, NULL, &in, &bv, NULL );
+               if ( rc != LDAP_SUCCESS ) {
+                       fprintf( stderr, "%s: %d: "
+                               "\"idassert-authzFrom <authz>\": "
+                               "invalid syntax.\n",
+                               c->fname, c->lineno );
+                       return 1;
+               }
+#else /* !SLAP_AUTHZ_SYNTAX */
                ber_str2bv( c->argv[ 1 ], 0, 1, &bv );
+#endif /* !SLAP_AUTHZ_SYNTAX */
                ber_bvarray_add( &li->idassert_authz, &bv );
                } break;
 
@@ -1562,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 85c334f9c98315df16e4eeae8aa1e08eca89b702..ff9425bb5734c76d2c153f5d05906416ef094398 100644 (file)
@@ -394,6 +394,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 );
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..e211f6363128ac86f7ef1233d2db2115b5b8ef85 100644 (file)
@@ -502,15 +502,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 +553,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 );
 
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 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 30e0d9ba22d5f972efcacab5495677b8e7c3fe15..8437cea8e8232331a24000f921bc3c96898e32b5 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 */
                                {
@@ -693,17 +702,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 +786,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 +793,7 @@ really_bad:;
 
 finish:;
        if ( matched ) {
-               free( matched );
+               op->o_tmpfree( matched, op->o_tmpmemctx );
        }
 
        if ( rs->sr_v2ref ) {
@@ -786,7 +828,7 @@ finish:;
 
        meta_back_release_conn( op, mc );
 
-       return rc;
+       return rs->sr_err;
 }
 
 static int
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 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 64daabd22c6ced03217d8f66c3820ed90e474d16..503a9c63fa108dc643f8ae35c52b21cd67a33c19 100644 (file)
@@ -998,9 +998,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;
 }
 
@@ -1785,11 +1785,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 bc8d940615cfcb35733da02a916231e028962615..4e6ebec2a79d49783112064d4608381c4e3ef850 100644 (file)
@@ -447,8 +447,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 +555,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 +580,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 +597,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 +656,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 +1609,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 +1709,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 +1720,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 +1739,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 +1785,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 +1908,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 +1924,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 +1935,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 +2018,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 },
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..08b9668d32271a7dbd7dbcd7b08cc5211f368caf 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));
+LDAP_SLAPD_F (int) OpenLDAPaciValidate LDAP_P((
+       Syntax *syn, struct berval *in ));
+LDAP_SLAPD_F (int) OpenLDAPaciPretty LDAP_P((
+       Syntax *syn, struct berval *val, struct berval *out, void *ctx ));
+LDAP_SLAPD_F (slap_mr_normalize_func) OpenLDAPaciNormalize;
+#ifdef SLAP_DYNACL
+LDAP_SLAPD_F (int) dynacl_aci_init LDAP_P(( void ));
+#endif /* SLAP_DYNACL */
+#endif /* SLAPD_ACI_ENABLED */
+
 /*
  * acl.c
  */
@@ -71,6 +95,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
  */
@@ -577,7 +617,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));
@@ -1406,7 +1447,9 @@ 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 ));
 
 /*
  * schema_prep.c
index d1e79bf3396021f4edf08e868b3d673e4ed964d0..1593e22bb0fc9d0db62590182c1771e428d6162e 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
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..183d1875bfa45a3dcd3e7a546c402d6bde881c52 100644 (file)
@@ -50,7 +50,7 @@
 #define HASH_Update(c,buf,len) lutil_HASHUpdate(c,buf,len)
 #define HASH_Final(d,c)                        lutil_HASHFinal(d,c)
 
-#define        OpenLDAPaciMatch                        NULL
+#define        OpenLDAPaciMatch                        octetStringMatch
 
 /* approx matching rules */
 #define directoryStringApproxMatchOID  "1.3.6.1.4.1.4203.666.4.4"
@@ -1861,7 +1861,7 @@ telephoneNumberNormalize(
        return LDAP_SUCCESS;
 }
 
-static int
+int
 numericoidValidate(
        Syntax *syntax,
        struct berval *in )
@@ -3427,8 +3427,8 @@ static slap_syntax_defs_rec syntax_defs[] = {
        /* 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},
+               OpenLDAPaciValidate,
+               OpenLDAPaciPretty},
 #endif
 
 #ifdef SLAPD_AUTHPASSWD
@@ -3851,7 +3851,7 @@ static slap_mrule_defs_rec mrule_defs[] = {
        {"( 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, OpenLDAPaciNormalize, OpenLDAPaciMatch,
                NULL, NULL,
                NULL},
 #endif
index f1d55cab3628a8fc53bd71f9cdea230a4bc91e7a..0d9fc9ce9da9365383500db77ba8d213b62651be 100644 (file)
@@ -914,7 +914,7 @@ struct slap_internal_schema {
 #endif
        AttributeDescription *si_ad_description;
        AttributeDescription *si_ad_seeAlso;
-        
+
        /* Undefined Attribute Type */
        AttributeType   *si_at_undefined;
 
@@ -1481,6 +1481,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 +2582,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           */
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 c96cdccd3528ba2db1f464dff1fba86f36ea58ea..6b8caacc0633293494a111f4bcaf02a67e9baba7 100644 (file)
@@ -291,9 +291,17 @@ 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 == 1 ) {
+                               do_retry = 0;
+                               sleep( 1 );
+                               goto retry;
+                       }
+               /* fallthru */
+               default:
+                       break;
                }
                exit( EXIT_FAILURE );
        }
index 37e45ec19e339ff26a0639697877782caa0f8f60..b639df553908dd065281e8020b2e37334780b25a 100644 (file)
@@ -185,9 +185,17 @@ 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 == 1 ) {
+                               do_retry = 0;
+                               sleep( 1 );
+                               goto retry;
+                       }
+               /* fallthru */
+               default:
+                       break;
                }
                exit( EXIT_FAILURE );
        }
index 60e85fa77b839f16df3998f1b75ef35784ee9dd7..2e95ddfa038e126f7ee1319f9d897d02f069da08 100644 (file)
@@ -177,9 +177,17 @@ 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 == 1 ) {
+                               do_retry = 0;
+                               sleep( 1 );
+                               goto retry;
+                       }
+               /* fallthru */
+               default:
+                       break;
                }
                exit( EXIT_FAILURE );
        }
index c3c09758b5e6057e03adf611fc2d0b002f1f30a1..e2c07686794808b4508b2580f3c2349e9e03d1e4 100644 (file)
@@ -140,9 +140,17 @@ 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 == 1 ) {
+                               do_retry = 0;
+                               sleep( 1 );
+                               goto retry;
+                       }
+               /* fallthru */
+               default:
+                       break;
                }
                exit( EXIT_FAILURE );
        }
index de42211fca1ef8a8ee28ad3f44f0ff69f166a260..71588310565c47fd78f7d627fbb05aba0a1022de 100644 (file)
@@ -157,11 +157,19 @@ 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--;
+                               sleep( 1 );
+                               goto retry;
+                       }
+               /* fallthru */
+               default:
+                       break;
+               }
                exit( EXIT_FAILURE );
        }
 
@@ -172,8 +180,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;
index 7d14de72c6f7eab833bffa36eff9b66e2d569a72..4121b4d17454a45d3be0998025618622eda084f1 100644 (file)
@@ -71,7 +71,17 @@ 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>]\n",
+               name );
        exit( EXIT_FAILURE );
 }