mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-21 03:10:25 +08:00
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:
parent
1b268479c3
commit
362766b316
@ -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;
|
||||||
|
@ -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 )
|
||||||
|
Loading…
Reference in New Issue
Block a user