+ } else
+#else /* !SLAP_DYNACL */
+
+ /* NOTE: this entire block can be eliminated when SLAP_DYNACL
+ * moves outside of LDAP_DEVEL */
+#ifdef SLAPD_ACI_ENABLED
+ if ( b->a_aci_at != NULL ) {
+ Attribute *at;
+ slap_access_t grant, deny, tgrant, tdeny;
+ struct berval parent_ndn;
+ BerVarray bvals = NULL;
+ int ret, stop;
+#ifdef LDAP_DEBUG
+ char accessmaskbuf1[ACCESSMASK_MAXLEN];
+#endif /* DEBUG */
+
+ Debug( LDAP_DEBUG_ACL, " <= check a_aci_at: %s\n",
+ b->a_aci_at->ad_cname.bv_val, 0, 0 );
+
+ /* this case works different from the others above.
+ * since aci's themselves give permissions, we need
+ * to first check b->a_access_mask, the ACL's access level.
+ */
+
+ if ( BER_BVISEMPTY( &e->e_nname ) ) {
+ /* no ACIs in the root DSE */
+ continue;
+ }
+
+ /* first check if the right being requested
+ * is allowed by the ACL clause.
+ */
+ if ( ! ACL_GRANT( b->a_access_mask, *mask ) ) {
+ continue;
+ }
+ /* start out with nothing granted, nothing denied */
+ ACL_INIT(tgrant);
+ ACL_INIT(tdeny);
+
+ /* get the aci attribute */
+ at = attr_find( e->e_attrs, b->a_aci_at );
+ if ( at != NULL ) {
+#if 0
+ /* FIXME: this breaks acl caching;
+ * see also ACL_RECORD_VALUE_STATE below */
+ ACL_RECORD_VALUE_STATE;
+#endif
+ /* 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) ) {
+ dnParent( &e->e_nname, &parent_ndn );
+ while ( !BER_BVISEMPTY( &parent_ndn ) ) {
+ Debug(LDAP_DEBUG_ACL, "checking ACI of %s\n", parent_ndn.bv_val, 0, 0);
+ ret = backend_attribute(op, NULL, &parent_ndn, b->a_aci_at, &bvals, ACL_AUTH);
+ switch(ret){
+ case LDAP_SUCCESS :
+ stop = 0;
+ if (!bvals){
+ break;
+ }
+
+ for ( i = 0; !BER_BVISNULL( &bvals[i] ); i++ ) {
+#if 0
+ /* FIXME: this breaks acl caching;
+ * see also ACL_RECORD_VALUE_STATE above */
+ ACL_RECORD_VALUE_STATE;
+#endif
+ if ( aci_mask( op, e, desc, val, &bvals[i],
+ 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;