X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Facl.c;h=c648d4ef6fb6dcabf90ac232bfe29f5b718c7231;hb=bd1543ce44c8478d8785cabbe449516167d72141;hp=f924da1a8e8bfd871fa7801604fc97960149db3c;hpb=dc41a6b37e8e7252ad9483c120bb0a101ed04d0f;p=openldap diff --git a/servers/slapd/acl.c b/servers/slapd/acl.c index f924da1a8e..c648d4ef6f 100644 --- a/servers/slapd/acl.c +++ b/servers/slapd/acl.c @@ -1,8 +1,27 @@ /* acl.c - routines to parse and check acl's */ /* $OpenLDAP$ */ -/* - * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved. - * COPYING RESTRICTIONS APPLY, see COPYRIGHT file +/* This work is part of OpenLDAP Software . + * + * Copyright 1998-2003 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* Portions Copyright (c) 1995 Regents of the University of Michigan. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of Michigan at Ann Arbor. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. */ #include "portable.h" @@ -24,6 +43,7 @@ */ static struct berval aci_bv_entry = BER_BVC("entry"), + aci_bv_children = BER_BVC("children"), aci_bv_br_entry = BER_BVC("[entry]"), aci_bv_br_all = BER_BVC("[all]"), aci_bv_access_id = BER_BVC("access-id"), @@ -49,6 +69,7 @@ static AccessControl * acl_get( AccessControl *ac, int *count, Operation *op, Entry *e, AttributeDescription *desc, + struct berval *val, int nmatches, regmatch_t *matches ); static slap_control_t acl_mask( @@ -68,7 +89,8 @@ static int aci_mask( struct berval *aci, regmatch_t *matches, slap_access_t *grant, - slap_access_t *deny ); + slap_access_t *deny, + struct berval *scope); #endif static int regex_matches( @@ -174,6 +196,14 @@ access_allowed( goto done; } +#ifdef LDAP_SLAPI + if ( op->o_pb && + !slapi_x_access_allowed( op, e, desc, val, access, state )) { + /* ACL plugin denied access */ + goto done; + } +#endif /* LDAP_SLAPI */ + be = op->o_bd; if ( be == NULL ) { be = &backends[0]; @@ -269,13 +299,14 @@ access_allowed( 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 = acl_get( a, &count, op, e, desc, + while((a = acl_get( a, &count, op, e, desc, val, MAXREMATCHES, matches )) != NULL) { int i; @@ -368,10 +399,11 @@ vd_access: done: if( state != NULL ) { /* If not value-dependent, save ACL in case of more attrs */ - if ( !(state->as_recorded & ACL_STATE_RECORDED_VD) ) + if ( !(state->as_recorded & ACL_STATE_RECORDED_VD) ) { state->as_vi_acl = a; + state->as_result = ret; + } state->as_recorded |= ACL_STATE_RECORDED; - state->as_result = ret; } if (be_null) op->o_bd = NULL; return ret; @@ -390,6 +422,7 @@ acl_get( Operation *op, Entry *e, AttributeDescription *desc, + struct berval *val, int nmatch, regmatch_t *matches ) { @@ -504,7 +537,7 @@ acl_get( Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] check attr %s\n", *count, attr, 0); #endif - if ( attr == NULL || a->acl_attrs == NULL || + if ( a->acl_attrs == NULL || ad_inlist( desc, a->acl_attrs ) ) { #ifdef NEW_LOGGING @@ -568,6 +601,7 @@ acl_mask( Access *b; #ifdef LDAP_DEBUG char accessmaskbuf[ACCESSMASK_MAXLEN]; + char accessmaskbuf1[ACCESSMASK_MAXLEN]; #endif const char *attr; @@ -600,6 +634,48 @@ acl_mask( accessmask2str( *mask, accessmaskbuf ) ); #endif + /* Is this ACL only for a specific value? */ + if ( a->acl_attrval.bv_len ) { + if ( state && !state->as_vd_acl ) { + state->as_vd_acl = a; + state->as_vd_access = a->acl_access; + state->as_vd_access_count = 1; + } + if ( val == NULL ) { + return ACL_BREAK; + } + if ( a->acl_attrval_style == ACL_STYLE_REGEX ) { +#ifdef NEW_LOGGING + LDAP_LOG( ACL, DETAIL1, + "acl_get: valpat %s\n", + a->acl_attrval.bv_val, 0, 0 ); +#else + Debug( LDAP_DEBUG_ACL, + "acl_get: valpat %s\n", + a->acl_attrval.bv_val, 0, 0 ); +#endif + if (regexec(&a->acl_attrval_re, val->bv_val, 0, NULL, 0)) + return ACL_BREAK; + } else { + int match = 0; + const char *text; +#ifdef NEW_LOGGING + LDAP_LOG( ACL, DETAIL1, + "acl_get: val %s\n", + a->acl_attrval.bv_val, 0, 0 ); +#else + Debug( LDAP_DEBUG_ACL, + "acl_get: val %s\n", + a->acl_attrval.bv_val, 0, 0 ); +#endif + if (value_match( &match, desc, + desc->ad_type->sat_equality, 0, + val, &a->acl_attrval, &text ) != LDAP_SUCCESS || + match ) + return ACL_BREAK; + } + } + if( state && ( state->as_recorded & ACL_STATE_RECORDED_VD ) && state->as_vd_acl == a ) { @@ -1084,6 +1160,9 @@ dn_match_cleanup:; if ( b->a_aci_at != NULL ) { Attribute *at; slap_access_t grant, deny, tgrant, tdeny; + struct berval parent_ndn, old_parent_ndn; + BerVarray bvals = NULL; + int ret,stop; /* this case works different from the others above. * since aci's themselves give permissions, we need @@ -1101,34 +1180,90 @@ dn_match_cleanup:; if ( ! ACL_GRANT( b->a_access_mask, *mask ) ) { continue; } - - /* get the aci attribute */ - at = attr_find( e->e_attrs, b->a_aci_at ); - if ( at == NULL ) { - continue; - } - - ACL_RECORD_VALUE_STATE; - /* start out with nothing granted, nothing denied */ ACL_INIT(tgrant); ACL_INIT(tdeny); - /* the aci is an multi-valued attribute. The - * rights are determined by OR'ing the individual - * rights given by the acis. + /* get the aci attribute */ + at = attr_find( e->e_attrs, b->a_aci_at ); + if ( at != NULL ) { + ACL_RECORD_VALUE_STATE; + /* the aci is an multi-valued attribute. The + * rights are determined by OR'ing the individual + * rights given by the acis. + */ + for ( i = 0; at->a_vals[i].bv_val != NULL; i++ ) { + if (aci_mask( op, + e, desc, val, + &at->a_nvals[i], + matches, &grant, &deny, &aci_bv_entry ) != 0) + { + tgrant |= grant; + tdeny |= deny; + } + } + Debug(LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n", + accessmask2str(tgrant,accessmaskbuf), + accessmask2str(tdeny, accessmaskbuf1), 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 */ - for ( i = 0; at->a_vals[i].bv_val != NULL; i++ ) { - if (aci_mask( op, - e, desc, val, - &at->a_nvals[i], - matches, &grant, &deny ) != 0) - { - tgrant |= grant; - tdeny |= deny; + if( (tgrant == ACL_PRIV_NONE) && (tdeny == ACL_PRIV_NONE) ){ + dnParent(&(e->e_nname), &parent_ndn); + while ( parent_ndn.bv_val != old_parent_ndn.bv_val ){ + old_parent_ndn = parent_ndn; + Debug(LDAP_DEBUG_ACL, "checking ACI of %s\n", parent_ndn.bv_val, 0, 0); + ret=backend_attribute(op, NULL, &parent_ndn, b->a_aci_at, &bvals); + switch(ret){ + case LDAP_SUCCESS : + if(bvals){ + for( i = 0; bvals[i].bv_val != NULL; i++){ + ACL_RECORD_VALUE_STATE; + if (aci_mask(op, e, desc, val, &bvals[i], matches, + &grant, &deny, &aci_bv_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), + accessmask2str(tdeny, accessmaskbuf1), 0); + } + } + stop=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); } } + /* remove anything that the ACL clause does not allow */ tgrant &= b->a_access_mask & ACL_PRIV_MASK; tdeny &= ACL_PRIV_MASK; @@ -1743,7 +1878,8 @@ aci_mask( struct berval *aci, regmatch_t *matches, slap_access_t *grant, - slap_access_t *deny + slap_access_t *deny, + struct berval *scope ) { struct berval bv, perms, sdn; @@ -1762,7 +1898,6 @@ aci_mask( For now, this routine only supports scope=entry. */ - /* check that the aci has all 5 components */ if (aci_get_part(aci, 4, '#', NULL) < 0) return(0); @@ -1771,9 +1906,9 @@ aci_mask( if (aci_get_part(aci, 0, '#', &bv) < 0) return(0); - /* check that the scope is "entry" */ + /* check that the scope matches */ if (aci_get_part(aci, 1, '#', &bv) < 0 - || ber_bvstrcasecmp( &aci_bv_entry, &bv ) != 0) + || ber_bvstrcasecmp( scope, &bv ) != 0) { return(0); }