]> git.sur5r.net Git - openldap/commitdiff
ACIs almost entirely factored out of slapd
authorPierangelo Masarati <ando@openldap.org>
Wed, 17 Aug 2005 17:14:57 +0000 (17:14 +0000)
committerPierangelo Masarati <ando@openldap.org>
Wed, 17 Aug 2005 17:14:57 +0000 (17:14 +0000)
Added OpenLDAPaciSyntax based on ITS#3877 by Nikita Shulga
aci_mask() doesn't exploit the normalized value yet (next step)
The case #define SLAPD_ACI_ENABLED / #undef SLAP_DYNACL should
be removed

servers/slapd/Makefile.in
servers/slapd/aci.c [new file with mode: 0644]
servers/slapd/acl.c
servers/slapd/proto-slap.h
servers/slapd/schema_init.c
servers/slapd/slap.h

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.
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 265b4cb4a60f83c5dc04725b5b5618339796fe73..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 ) )
                        {
@@ -1507,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;
@@ -1552,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;
@@ -1609,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;
@@ -1628,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 ) {
@@ -1671,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;
@@ -1710,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;
@@ -1818,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 ) )
                                {
@@ -1903,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 ) )
                                {
@@ -1914,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;
                        }
                }
@@ -2389,8 +2371,8 @@ done:
        return( ret );
 }
 
-static int
-aci_get_part(
+int
+acl_get_part(
        struct berval   *list,
        int             ix,
        char            sep,
@@ -2432,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 ];
@@ -2483,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=*)" );
 
@@ -2502,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 );
@@ -2623,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;
@@ -2656,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 );
@@ -2679,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 ];
                }
 
                /*
@@ -2714,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 );
        }
@@ -2722,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
 
 /*
@@ -3475,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,
@@ -3579,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;
 }
@@ -3606,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 06ff2b2ea7a6ca6dbe353f788355ca5b7972b641..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
  */
@@ -1407,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 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 130648a6636a9c1d39575532d3a7c54814ffa59f..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