move compare to frontend (disabled by default, only invoked if backend doesn't provide hook); honor ITS#3472 (disclose access check); fix ITS#3521 as well (check access to hasSubordinates); fix a problem in backend_attribute() with operational attrs; add backend_access() helper

This commit is contained in:
Pierangelo Masarati 2005-01-26 23:19:48 +00:00
parent 1b268479c3
commit 362766b316
2 changed files with 244 additions and 19 deletions

View File

@ -555,11 +555,11 @@ backend_db_init(
/* assign a default depth limit for alias deref */ /* assign a default depth limit for alias deref */
be->be_max_deref_depth = SLAPD_DEFAULT_MAXDEREFDEPTH; be->be_max_deref_depth = SLAPD_DEFAULT_MAXDEREFDEPTH;
if(bi->bi_db_init) { if ( bi->bi_db_init ) {
rc = bi->bi_db_init( be ); rc = bi->bi_db_init( be );
} }
if(rc != 0) { if ( rc != 0 ) {
fprintf( stderr, "database init failed (%s)\n", type ); fprintf( stderr, "database init failed (%s)\n", type );
nbackends--; nbackends--;
return NULL; return NULL;
@ -583,6 +583,7 @@ be_db_close( void )
if ( frontendDB->bd_info->bi_db_close ) { if ( frontendDB->bd_info->bi_db_close ) {
(*frontendDB->bd_info->bi_db_close)( frontendDB ); (*frontendDB->bd_info->bi_db_close)( frontendDB );
} }
} }
Backend * Backend *
@ -1479,13 +1480,21 @@ backend_attribute(
BER_BVZERO( &anlist[ 1 ].an_name ); BER_BVZERO( &anlist[ 1 ].an_name );
rs.sr_attrs = anlist; 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 ); rc = backend_operational( op, &rs );
rs.sr_entry = NULL;
if ( rc == LDAP_SUCCESS && rs.sr_operational_attrs ) { if ( rc == LDAP_SUCCESS ) {
if ( rs.sr_operational_attrs ) {
freeattr = 1; freeattr = 1;
a = rs.sr_operational_attrs; a = rs.sr_operational_attrs;
} else {
rc = LDAP_NO_SUCH_ATTRIBUTE;
}
} }
} }
@ -1567,6 +1576,144 @@ freeit: if ( e != target ) {
return rc; return rc;
} }
#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;
}
int backend_operational( int backend_operational(
Operation *op, Operation *op,
SlapReply *rs ) SlapReply *rs )
@ -1583,15 +1730,15 @@ int backend_operational(
* and the backend supports specific operational attributes, * and the backend supports specific operational attributes,
* add them to the attribute list * add them to the attribute list
*/ */
if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( op->ors_attrs && if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs &&
ad_inlist( slap_schema.si_ad_entryDN, op->ors_attrs ))) ad_inlist( slap_schema.si_ad_entryDN, rs->sr_attrs )))
{ {
*ap = slap_operational_entryDN( rs->sr_entry ); *ap = slap_operational_entryDN( rs->sr_entry );
ap = &(*ap)->a_next; ap = &(*ap)->a_next;
} }
if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( op->ors_attrs && if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs &&
ad_inlist( slap_schema.si_ad_subschemaSubentry, op->ors_attrs ))) ad_inlist( slap_schema.si_ad_subschemaSubentry, rs->sr_attrs )))
{ {
*ap = slap_operational_subschemaSubentry( op->o_bd ); *ap = slap_operational_subschemaSubentry( op->o_bd );
ap = &(*ap)->a_next; ap = &(*ap)->a_next;
@ -1602,7 +1749,7 @@ int backend_operational(
if ( SLAP_ISOVERLAY( be_orig )) if ( SLAP_ISOVERLAY( be_orig ))
op->o_bd = select_backend( be_orig->be_nsuffix, 0, 0 ); op->o_bd = select_backend( be_orig->be_nsuffix, 0, 0 );
if (( SLAP_OPATTRS( rs->sr_attr_flags ) || op->ors_attrs ) && if (( SLAP_OPATTRS( rs->sr_attr_flags ) || rs->sr_attrs ) &&
op->o_bd && op->o_bd->be_operational != NULL ) op->o_bd && op->o_bd->be_operational != NULL )
{ {
Attribute *a; Attribute *a;

View File

@ -274,6 +274,7 @@ fe_op_compare( Operation *op, SlapReply *rs )
send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
"subschemaSubentry compare not supported" ); "subschemaSubentry compare not supported" );
#ifndef SLAP_COMPARE_IN_FRONTEND
} else if ( ava.aa_desc == slap_schema.si_ad_hasSubordinates } else if ( ava.aa_desc == slap_schema.si_ad_hasSubordinates
&& op->o_bd->be_has_subordinates ) && op->o_bd->be_has_subordinates )
{ {
@ -281,10 +282,17 @@ fe_op_compare( Operation *op, SlapReply *rs )
rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &entry ); rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &entry );
if ( rc == 0 && entry ) { if ( rc == 0 && entry ) {
rc = op->o_bd->be_has_subordinates( op, entry, if ( ! access_allowed( op, entry,
&hasSubordinates ); ava.aa_desc, &ava.aa_value, ACL_COMPARE, NULL ) )
{
rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
} else {
rc = rs->sr_err = op->o_bd->be_has_subordinates( op,
entry, &hasSubordinates );
be_entry_release_r( op, entry ); be_entry_release_r( op, entry );
} }
}
if ( rc == 0 ) { if ( rc == 0 ) {
int asserted; int asserted;
@ -293,20 +301,90 @@ fe_op_compare( Operation *op, SlapReply *rs )
? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE; ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE;
if ( hasSubordinates == asserted ) { if ( hasSubordinates == asserted ) {
rs->sr_err = LDAP_COMPARE_TRUE; rs->sr_err = LDAP_COMPARE_TRUE;
} else { } else {
rs->sr_err = LDAP_COMPARE_FALSE; rs->sr_err = LDAP_COMPARE_FALSE;
} }
} else {
#ifdef SLAP_ACL_HONOR_DISCLOSE
/* return error only if "disclose"
* is granted on the object */
if ( backend_access( op, NULL, &op->o_req_ndn,
slap_schema.si_ad_entry,
NULL, ACL_DISCLOSE, NULL ) == LDAP_INSUFFICIENT_ACCESS )
{
rs->sr_err = LDAP_NO_SUCH_OBJECT;
} }
#endif /* SLAP_ACL_HONOR_DISCLOSE */
}
send_ldap_result( op, rs ); send_ldap_result( op, rs );
if( rc == 0 ) rs->sr_err = LDAP_SUCCESS; if ( rc == 0 ) {
rs->sr_err = LDAP_SUCCESS;
}
} else if ( op->o_bd->be_compare ) { } else if ( op->o_bd->be_compare ) {
op->o_bd->be_compare( op, rs ); op->o_bd->be_compare( op, rs );
#endif /* ! SLAP_COMPARE_IN_FRONTEND */
} else { } else {
send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, /* do our best to compare that AVA
"operation not supported within namingContext" ); *
* NOTE: this code is used only
* if SLAP_COMPARE_IN_FRONTEND
* is #define'd (it's not by default)
* or if op->o_bd->be_compare is NULL.
*
* FIXME: one potential issue is that
* if SLAP_COMPARE_IN_FRONTEND overlays
* are not executed for compare. */
BerVarray vals = NULL;
int rc = LDAP_OTHER;
rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn,
ava.aa_desc, &vals, ACL_COMPARE );
switch ( rs->sr_err ) {
default:
#ifdef SLAP_ACL_HONOR_DISCLOSE
/* return error only if "disclose"
* is granted on the object */
if ( backend_access( op, NULL, &op->o_req_ndn,
slap_schema.si_ad_entry,
NULL, ACL_DISCLOSE, NULL )
== LDAP_INSUFFICIENT_ACCESS )
{
rs->sr_err = LDAP_NO_SUCH_OBJECT;
}
#endif /* SLAP_ACL_HONOR_DISCLOSE */
break;
case LDAP_SUCCESS:
if ( value_find_ex( op->oq_compare.rs_ava->aa_desc,
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
vals, &ava.aa_value, op->o_tmpmemctx ) == 0 )
{
rs->sr_err = LDAP_COMPARE_TRUE;
break;
} else {
rs->sr_err = LDAP_COMPARE_FALSE;
}
rc = LDAP_SUCCESS;
break;
}
send_ldap_result( op, rs );
if ( rc == 0 ) {
rs->sr_err = LDAP_SUCCESS;
}
if ( vals ) {
ber_bvarray_free_x( vals, op->o_tmpmemctx );
}
} }
#if defined( LDAP_SLAPI ) #if defined( LDAP_SLAPI )