+#ifdef LDAP_SLAPI
+static int backend_compute_output_attr_access(computed_attr_context *c, Slapi_Attr *a, Slapi_Entry *e)
+{
+ struct berval *nval = (struct berval *)c->cac_private;
+ Operation *op = NULL;
+
+ slapi_pblock_get( c->cac_pb, SLAPI_OPERATION, &op );
+ if ( op == NULL ) {
+ return 1;
+ }
+
+ return access_allowed( op, e, a->a_desc, nval, ACL_AUTH, NULL ) == 0;
+}
+#endif /* LDAP_SLAPI */
+
+int
+backend_access(
+ Operation *op,
+ Entry *target,
+ struct berval *edn,
+ AttributeDescription *entry_at,
+ struct berval *nval,
+ slap_access_t access,
+ slap_mask_t *mask )
+{
+ Entry *e = NULL;
+ int rc = LDAP_INSUFFICIENT_ACCESS;
+ Backend *be = op->o_bd;
+
+ /* pedantic */
+ assert( op );
+ assert( op->o_conn );
+ assert( edn );
+ assert( access > ACL_NONE );
+
+ op->o_bd = select_backend( edn, 0, 0 );
+
+ if ( target && dn_match( &target->e_nname, edn ) ) {
+ e = target;
+
+ } else {
+ rc = be_entry_get_rw( op, edn, NULL, entry_at, 0, &e );
+ }
+
+ if ( e ) {
+ Attribute *a = NULL;
+ int freeattr = 0;
+
+ if ( entry_at == NULL ) {
+ entry_at = slap_schema.si_ad_entry;
+ }
+
+ if ( entry_at == slap_schema.si_ad_entry || entry_at == slap_schema.si_ad_children )
+ {
+ if ( access_allowed_mask( op, e, entry_at,
+ NULL, access, NULL, mask ) == 0 )
+ {
+ rc = LDAP_INSUFFICIENT_ACCESS;
+
+ } else {
+ rc = LDAP_SUCCESS;
+ }
+
+ } else {
+ a = attr_find( e->e_attrs, entry_at );
+ if ( a == NULL ) {
+ SlapReply rs = { 0 };
+ AttributeName anlist[ 2 ];
+
+ anlist[ 0 ].an_name = entry_at->ad_cname;
+ anlist[ 0 ].an_desc = entry_at;
+ BER_BVZERO( &anlist[ 1 ].an_name );
+ rs.sr_attrs = anlist;
+
+ rs.sr_attr_flags = slap_attr_flags( rs.sr_attrs );
+
+ /* NOTE: backend_operational() is also called
+ * when returning results, so it's supposed
+ * to do no harm to entries */
+ rs.sr_entry = e;
+ rc = backend_operational( op, &rs );
+ rs.sr_entry = NULL;
+
+ if ( rc == LDAP_SUCCESS ) {
+ if ( rs.sr_operational_attrs ) {
+ freeattr = 1;
+ a = rs.sr_operational_attrs;
+
+ } else {
+ rc = LDAP_NO_SUCH_OBJECT;
+ }
+ }
+ }
+
+ if ( a ) {
+ if ( access_allowed_mask( op, e, entry_at,
+ nval, access, NULL, mask ) == 0 )
+ {
+ rc = LDAP_INSUFFICIENT_ACCESS;
+ goto freeit;
+ }
+ rc = LDAP_SUCCESS;
+ }
+#ifdef LDAP_SLAPI
+ else if ( op->o_pb ) {
+ /* try any computed attributes */
+ computed_attr_context ctx;
+
+ slapi_int_pblock_set_operation( op->o_pb, op );
+
+ ctx.cac_pb = op->o_pb;
+ ctx.cac_attrs = NULL;
+ ctx.cac_userattrs = 0;
+ ctx.cac_opattrs = 0;
+ ctx.cac_private = (void *)nval;
+
+ rc = compute_evaluator( &ctx, entry_at->ad_cname.bv_val, e, backend_compute_output_attr_access );
+ if ( rc == 1 ) {
+ rc = LDAP_INSUFFICIENT_ACCESS;
+
+ } else {
+ rc = LDAP_SUCCESS;
+ }
+ }
+#endif /* LDAP_SLAPI */
+ }
+freeit: if ( e != target ) {
+ be_entry_release_r( op, e );
+ }
+ if ( freeattr ) {
+ attr_free( a );
+ }
+ }
+
+ op->o_bd = be;
+ return rc;
+}
+