+ 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 );
+
+ 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;
+ struct berval old_parent_ndn = BER_BVNULL;
+
+#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 ( parent_ndn.bv_val != old_parent_ndn.bv_val ){
+ int i;
+ BerVarray bvals = NULL;
+ int ret, stop;
+
+ old_parent_ndn = parent_ndn;
+ 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( &old_parent_ndn, &parent_ndn );
+ }
+ }
+
+ *grantp = tgrant;
+ *denyp = tdeny;
+
+ return 0;