+ }
+
+ ret = 0;
+ control = ACL_BREAK;
+
+ if ( st_same_attr ) {
+ assert( state->as_vd_acl != NULL );
+
+ a = state->as_vd_acl;
+ count = state->as_vd_acl_count;
+ if ( !ACL_IS_INVALID( state->as_vd_acl_mask ) ) {
+ mask = state->as_vd_acl_mask;
+ AC_MEMCPY( matches, state->as_vd_acl_matches, sizeof(matches) );
+ goto vd_access;
+ }
+
+ } else {
+ if ( state ) state->as_vi_acl = NULL;
+ a = NULL;
+ ACL_INIT(mask);
+ count = 0;
+ memset( matches, '\0', sizeof(matches) );
+ }
+
+ while ( ( a = slap_acl_get( a, &count, op, e, desc, val,
+ MAXREMATCHES, matches, state ) ) != NULL )
+ {
+ int i;
+
+ for ( i = 0; i < MAXREMATCHES && matches[i].rm_so > 0; i++ ) {
+ Debug( LDAP_DEBUG_ACL, "=> match[%d]: %d %d ", i,
+ (int)matches[i].rm_so, (int)matches[i].rm_eo );
+ if ( matches[i].rm_so <= matches[0].rm_eo ) {
+ int n;
+ for ( n = matches[i].rm_so; n < matches[i].rm_eo; n++ ) {
+ Debug( LDAP_DEBUG_ACL, "%c", e->e_ndn[n], 0, 0 );
+ }
+ }
+ Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 );
+ }
+
+ if ( state ) {
+ if ( state->as_vi_acl == a &&
+ ( state->as_recorded & ACL_STATE_RECORDED_NV ) )
+ {
+ Debug( LDAP_DEBUG_ACL,
+ "access_allowed: result from state (%s)\n",
+ attr, 0, 0 );
+ ret = state->as_result;
+ goto done;
+ } else {
+ Debug( LDAP_DEBUG_ACL,
+ "access_allowed: no res from state (%s)\n",
+ attr, 0, 0 );
+ }
+ }
+
+vd_access:
+ control = slap_acl_mask( a, &mask, op,
+ e, desc, val, MAXREMATCHES, matches, count, state );
+
+ if ( control != ACL_BREAK ) {
+ break;
+ }
+
+ memset( matches, '\0', sizeof(matches) );
+ }
+
+ if ( ACL_IS_INVALID( mask ) ) {
+ Debug( LDAP_DEBUG_ACL,
+ "=> access_allowed: \"%s\" (%s) invalid!\n",
+ e->e_dn, attr, 0 );
+ ACL_INIT(mask);
+
+ } else if ( control == ACL_BREAK ) {
+ Debug( LDAP_DEBUG_ACL,
+ "=> access_allowed: no more rules\n", 0, 0, 0 );
+
+ goto done;
+ }
+
+ Debug( LDAP_DEBUG_ACL,
+ "=> access_allowed: %s access %s by %s\n",
+ access2str( access ),
+ ACL_GRANT(mask, access) ? "granted" : "denied",
+ accessmask2str( mask, accessmaskbuf, 1 ) );
+
+ ret = ACL_GRANT(mask, access);
+
+done:
+ if ( state != NULL ) {
+ /* If not value-dependent, save ACL in case of more attrs */
+ if ( !( state->as_recorded & ACL_STATE_RECORDED_VD ) ) {
+ state->as_vi_acl = a;
+ state->as_result = ret;
+ }
+ state->as_recorded |= ACL_STATE_RECORDED;
+ }
+ if ( be_null ) op->o_bd = NULL;
+ if ( maskp ) *maskp = mask;
+ return ret;
+}
+
+#endif /* SLAP_OVERLAY_ACCESS */
+
+/*
+ * slap_acl_get - return the acl applicable to entry e, attribute
+ * attr. the acl returned is suitable for use in subsequent calls to
+ * acl_access_allowed().
+ */
+
+static AccessControl *
+slap_acl_get(
+ AccessControl *a,
+ int *count,
+ Operation *op,
+ Entry *e,
+ AttributeDescription *desc,
+ struct berval *val,
+ int nmatch,
+ regmatch_t *matches,
+ AccessControlState *state )
+{
+ const char *attr;
+ int dnlen, patlen;
+ AccessControl *prev;
+
+ assert( e != NULL );
+ assert( count != NULL );
+ assert( desc != NULL );
+
+ attr = desc->ad_cname.bv_val;
+
+ assert( attr != NULL );
+
+ if( a == NULL ) {
+ if( op->o_bd == NULL ) {
+ a = frontendDB->be_acl;
+ } else {
+ a = op->o_bd->be_acl;
+ }
+ prev = NULL;
+
+ assert( a != NULL );
+
+ } else {
+ prev = a;
+ a = a->acl_next;
+ }
+
+ dnlen = e->e_nname.bv_len;
+
+ for ( ; a != NULL; a = a->acl_next ) {
+ (*count) ++;
+
+ if ( a->acl_dn_pat.bv_len || ( a->acl_dn_style != ACL_STYLE_REGEX )) {
+ if ( a->acl_dn_style == ACL_STYLE_REGEX ) {
+ Debug( LDAP_DEBUG_ACL, "=> dnpat: [%d] %s nsub: %d\n",
+ *count, a->acl_dn_pat.bv_val, (int) a->acl_dn_re.re_nsub );
+ if (regexec(&a->acl_dn_re, e->e_ndn, nmatch, matches, 0))
+ continue;
+
+ } else {
+ Debug( LDAP_DEBUG_ACL, "=> dn: [%d] %s\n",
+ *count, a->acl_dn_pat.bv_val, 0 );
+ patlen = a->acl_dn_pat.bv_len;
+ if ( dnlen < patlen )
+ continue;
+
+ if ( a->acl_dn_style == ACL_STYLE_BASE ) {
+ /* base dn -- entire object DN must match */
+ if ( dnlen != patlen )
+ continue;
+
+ } else if ( a->acl_dn_style == ACL_STYLE_ONE ) {
+ int rdnlen = -1, sep = 0;
+
+ if ( dnlen <= patlen )
+ continue;
+
+ if ( patlen > 0 ) {
+ if ( !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) )
+ continue;
+ sep = 1;
+ }
+
+ rdnlen = dn_rdnlen( NULL, &e->e_nname );
+ if ( rdnlen != dnlen - patlen - sep )
+ continue;
+
+ } else if ( a->acl_dn_style == ACL_STYLE_SUBTREE ) {
+ if ( dnlen > patlen && !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) )
+ continue;
+
+ } else if ( a->acl_dn_style == ACL_STYLE_CHILDREN ) {
+ if ( dnlen <= patlen )
+ continue;
+ if ( !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) )
+ continue;
+ }
+
+ if ( strcmp( a->acl_dn_pat.bv_val, e->e_ndn + dnlen - patlen ) != 0 )
+ continue;
+ }
+
+ Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] matched\n",
+ *count, 0, 0 );
+ }
+
+ if ( a->acl_attrs && !ad_inlist( desc, a->acl_attrs ) ) {
+ matches[0].rm_so = matches[0].rm_eo = -1;
+ continue;
+ }
+
+ /* Is this ACL only for a specific value? */
+ if ( a->acl_attrval.bv_len ) {
+ if ( val == NULL ) {
+ continue;
+ }
+
+ if( state && !( state->as_recorded & ACL_STATE_RECORDED_VD )) {
+ state->as_recorded |= ACL_STATE_RECORDED_VD;
+ state->as_vd_acl = a;
+ state->as_vd_acl_count = *count;
+ state->as_vd_access = a->acl_access;
+ state->as_vd_access_count = 1;
+ ACL_INVALIDATE( state->as_vd_acl_mask );
+ }
+
+ if ( a->acl_attrval_style == ACL_STYLE_REGEX ) {
+ Debug( LDAP_DEBUG_ACL,
+ "acl_get: valpat %s\n",
+ a->acl_attrval.bv_val, 0, 0 );
+ if ( regexec( &a->acl_attrval_re, val->bv_val, 0, NULL, 0 ) )
+ {
+ continue;
+ }
+
+ } else {
+ int match = 0;
+ const char *text;
+ Debug( LDAP_DEBUG_ACL,
+ "acl_get: val %s\n",
+ a->acl_attrval.bv_val, 0, 0 );
+
+ if ( a->acl_attrs[0].an_desc->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) {
+ if (value_match( &match, desc,
+ desc->ad_type->sat_equality, 0,
+ val, &a->acl_attrval, &text ) != LDAP_SUCCESS ||
+ match )
+ continue;
+
+ } else {
+ int patlen, vdnlen;
+
+ patlen = a->acl_attrval.bv_len;
+ vdnlen = val->bv_len;
+
+ if ( vdnlen < patlen )
+ continue;
+
+ if ( a->acl_attrval_style == ACL_STYLE_BASE ) {
+ if ( vdnlen > patlen )
+ continue;
+
+ } else if ( a->acl_attrval_style == ACL_STYLE_ONE ) {
+ int rdnlen = -1;
+
+ if ( !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) )
+ continue;
+
+ rdnlen = dn_rdnlen( NULL, val );
+ if ( rdnlen != vdnlen - patlen - 1 )
+ continue;
+
+ } else if ( a->acl_attrval_style == ACL_STYLE_SUBTREE ) {
+ if ( vdnlen > patlen && !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) )
+ continue;
+
+ } else if ( a->acl_attrval_style == ACL_STYLE_CHILDREN ) {
+ if ( vdnlen <= patlen )
+ continue;
+
+ if ( !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) )
+ continue;
+ }
+
+ if ( strcmp( a->acl_attrval.bv_val, val->bv_val + vdnlen - patlen ))
+ continue;
+ }
+ }
+ }
+
+ if ( a->acl_filter != NULL ) {
+ ber_int_t rc = test_filter( NULL, e, a->acl_filter );
+ if ( rc != LDAP_COMPARE_TRUE ) {
+ continue;
+ }
+ }
+
+ Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] attr %s\n",
+ *count, attr, 0);
+ return a;
+ }
+
+ Debug( LDAP_DEBUG_ACL, "<= acl_get: done.\n", 0, 0, 0 );