/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 1998-2005 The OpenLDAP Foundation.
+ * Copyright 1998-2006 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#define ACL_BUF_SIZE 1024 /* use most appropriate size */
-/*
- * speed up compares
- */
-const struct berval aci_bv[] = {
- BER_BVC("entry"),
- BER_BVC("children"),
- BER_BVC("onelevel"),
- BER_BVC("subtree"),
- BER_BVC("[entry]"),
- BER_BVC("[all]"),
- BER_BVC("access-id"),
-#if 0
- BER_BVC("anonymous"),
-#endif
- BER_BVC("public"),
- BER_BVC("users"),
- BER_BVC("self"),
- BER_BVC("dnattr"),
- BER_BVC("group"),
- BER_BVC("role"),
- BER_BVC("set"),
- BER_BVC("set-ref"),
- BER_BVC("grant"),
- BER_BVC("deny"),
-
- BER_BVC("IP="),
+static const struct berval acl_bv_ip_eq = BER_BVC( "IP=" );
#ifdef LDAP_PF_LOCAL
- BER_BVC("PATH="),
-#if 0
- BER_BVC(LDAP_DIRSEP),
-#endif
+static const struct berval acl_bv_path_eq = BER_BVC("PATH=");
#endif /* LDAP_PF_LOCAL */
-
- BER_BVC(SLAPD_GROUP_CLASS),
- BER_BVC(SLAPD_GROUP_ATTR),
- BER_BVC(SLAPD_ROLE_CLASS),
- BER_BVC(SLAPD_ROLE_ATTR),
-
- BER_BVC(SLAPD_ACI_SET_ATTR)
-};
static AccessControl * slap_acl_get(
AccessControl *ac, int *count,
*/
be_orig = op->o_bd;
- op->o_bd = select_backend( &op->o_req_ndn, 0, 0 );
if ( op->o_bd == NULL ) {
- op->o_bd = frontendDB;
+ op->o_bd = select_backend( &op->o_req_ndn, 0, 0 );
+ if ( op->o_bd == NULL )
+ op->o_bd = frontendDB;
}
rc = slap_access_allowed( op, e, desc, val, access, state, maskp );
op->o_bd = be_orig;
desc, val, access, state, &mask );
} else {
- BackendDB *be_orig = op->o_bd;
-
/* use default (but pass through frontend
* for global ACL overlays) */
- op->o_bd = frontendDB;
ret = frontendDB->bd_info->bi_access_allowed( op, e,
desc, val, access, state, &mask );
- op->o_bd = be_orig;
}
if ( !ret ) {
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 */ a->acl_attrval_mr, 0,
+ a->acl_attrval_mr, 0,
val, &a->acl_attrval, &text ) != LDAP_SUCCESS ||
match )
continue;
continue;
}
- if ( strcmp( a->acl_attrval.bv_val, val->bv_val + vdnlen - patlen ))
+ if ( strcmp( a->acl_attrval.bv_val, val->bv_val + vdnlen - patlen ) )
continue;
}
}
return( NULL );
}
+/*
+ * Record value-dependent access control state
+*/
+ #define ACL_RECORD_VALUE_STATE do { \
+ if( state && !( state->as_recorded & ACL_STATE_RECORDED_VD )) { \
+ state->as_recorded |= ACL_STATE_RECORDED_VD; \
+ state->as_vd_acl = a; \
+ AC_MEMCPY( state->as_vd_acl_matches, matches, \
+ sizeof( state->as_vd_acl_matches )) ; \
+ state->as_vd_acl_count = count; \
+ state->as_vd_access = b; \
+ state->as_vd_access_count = i; \
+ }\
+ } while( 0 )
+
static int
acl_mask_dn(
Operation *op,
Entry *e,
+ AttributeDescription *desc,
+ struct berval *val,
AccessControl *a,
int nmatch,
regmatch_t *matches,
- slap_dn_access *b,
+ slap_dn_access *bdn,
struct berval *opndn )
{
/*
* NOTE: styles "anonymous", "users" and "self"
* have been moved to enum slap_style_t, whose
* value is set in a_dn_style; however, the string
- * is maintaned in a_dn_pat.
+ * is maintained in a_dn_pat.
*/
- if ( b->a_style == ACL_STYLE_ANONYMOUS ) {
+
+ if ( bdn->a_style == ACL_STYLE_ANONYMOUS ) {
if ( !BER_BVISEMPTY( opndn ) ) {
return 1;
}
- } else if ( b->a_style == ACL_STYLE_USERS ) {
+ } else if ( bdn->a_style == ACL_STYLE_USERS ) {
if ( BER_BVISEMPTY( opndn ) ) {
return 1;
}
- } else if ( b->a_style == ACL_STYLE_SELF ) {
+ } else if ( bdn->a_style == ACL_STYLE_SELF ) {
struct berval ndn, selfndn;
int level;
return 1;
}
- level = b->a_self_level;
+ level = bdn->a_self_level;
if ( level < 0 ) {
selfndn = *opndn;
ndn = e->e_nname;
return 1;
}
- } else if ( b->a_style == ACL_STYLE_REGEX ) {
- if ( !ber_bvccmp( &b->a_pat, '*' ) ) {
+ } else if ( bdn->a_style == ACL_STYLE_REGEX ) {
+ if ( !ber_bvccmp( &bdn->a_pat, '*' ) ) {
int tmp_nmatch;
regmatch_t tmp_matches[2],
*tmp_matchesp = tmp_matches;
return 1;
}
- if ( !regex_matches( &b->a_pat, opndn->bv_val,
+ if ( !regex_matches( &bdn->a_pat, opndn->bv_val,
e->e_ndn, tmp_nmatch, tmp_matchesp ) )
{
return 1;
if ( e->e_dn == NULL )
return 1;
- if ( b->a_expand ) {
+ if ( bdn->a_expand ) {
struct berval bv;
char buf[ACL_BUF_SIZE];
return 1;
}
- if ( acl_string_expand( &bv, &b->a_pat,
+ if ( acl_string_expand( &bv, &bdn->a_pat,
e->e_nname.bv_val,
tmp_nmatch, tmp_matchesp ) )
{
}
} else {
- pat = b->a_pat;
+ pat = bdn->a_pat;
}
patlen = pat.bv_len;
}
- if ( b->a_style == ACL_STYLE_BASE ) {
+ if ( bdn->a_style == ACL_STYLE_BASE ) {
/* base dn -- entire object DN must match */
if ( odnlen != patlen ) {
goto dn_match_cleanup;
}
- } else if ( b->a_style == ACL_STYLE_ONE ) {
+ } else if ( bdn->a_style == ACL_STYLE_ONE ) {
ber_len_t rdnlen = 0;
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
- } else if ( b->a_style == ACL_STYLE_SUBTREE ) {
+ } else if ( bdn->a_style == ACL_STYLE_SUBTREE ) {
if ( odnlen > patlen && !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
- } else if ( b->a_style == ACL_STYLE_CHILDREN ) {
+ } else if ( bdn->a_style == ACL_STYLE_CHILDREN ) {
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
goto dn_match_cleanup;
}
- } else if ( b->a_style == ACL_STYLE_LEVEL ) {
- int level = b->a_level;
+ } else if ( bdn->a_style == ACL_STYLE_LEVEL ) {
+ int level = bdn->a_level;
struct berval ndn;
if ( odnlen <= patlen ) {
got_match = !strcmp( pat.bv_val, &opndn->bv_val[ odnlen - patlen ] );
dn_match_cleanup:;
- if ( pat.bv_val != b->a_pat.bv_val ) {
+ if ( pat.bv_val != bdn->a_pat.bv_val ) {
slap_sl_free( pat.bv_val, op->o_tmpmemctx );
}
return 0;
}
-/*
- * Record value-dependent access control state
- */
-#define ACL_RECORD_VALUE_STATE do { \
- if( state && !( state->as_recorded & ACL_STATE_RECORDED_VD )) { \
- state->as_recorded |= ACL_STATE_RECORDED_VD; \
- state->as_vd_acl = a; \
- AC_MEMCPY( state->as_vd_acl_matches, matches, \
- sizeof( state->as_vd_acl_matches )) ; \
- state->as_vd_acl_count = count; \
- state->as_vd_access = b; \
- state->as_vd_access_count = i; \
- } \
- } while( 0 )
-
static int
acl_mask_dnattr(
Operation *op,
Access *b;
#ifdef LDAP_DEBUG
char accessmaskbuf[ACCESSMASK_MAXLEN];
-#if !defined( SLAP_DYNACL ) && defined( SLAPD_ACI_ENABLED )
- char accessmaskbuf1[ACCESSMASK_MAXLEN];
-#endif /* !SLAP_DYNACL && SLAPD_ACI_ENABLED */
#endif /* DEBUG */
const char *attr;
slap_mask_t a2pmask = ACL_ACCESS2PRIV( *mask );
* NOTE: styles "anonymous", "users" and "self"
* have been moved to enum slap_style_t, whose
* value is set in a_dn_style; however, the string
- * is maintaned in a_dn_pat.
+ * is maintained in a_dn_pat.
*/
- if ( acl_mask_dn( op, e, a, nmatch, matches,
- &b->a_dn, &op->o_ndn ) )
+ if ( acl_mask_dn( op, e, desc, val, a, nmatch, matches,
+ &b->a_dn, &op->o_ndn ) )
{
continue;
}
* NOTE: styles "anonymous", "users" and "self"
* have been moved to enum slap_style_t, whose
* value is set in a_dn_style; however, the string
- * is maintaned in a_dn_pat.
+ * is maintained in a_dn_pat.
*/
if ( op->o_conn && !BER_BVISNULL( &op->o_conn->c_ndn ) )
ndn = op->o_ndn;
}
- if ( acl_mask_dn( op, e, a, nmatch, matches,
- &b->a_realdn, &ndn ) )
+ if ( acl_mask_dn( op, e, desc, val, a, nmatch, matches,
+ &b->a_realdn, &ndn ) )
{
continue;
}
int port_number = -1;
if ( strncasecmp( op->o_conn->c_peer_name.bv_val,
- aci_bv[ ACI_BV_IP_EQ ].bv_val,
- aci_bv[ ACI_BV_IP_EQ ].bv_len ) != 0 )
+ acl_bv_ip_eq.bv_val,
+ acl_bv_ip_eq.bv_len ) != 0 )
continue;
- ip.bv_val = op->o_conn->c_peer_name.bv_val + aci_bv[ ACI_BV_IP_EQ ].bv_len;
- ip.bv_len = op->o_conn->c_peer_name.bv_len - aci_bv[ ACI_BV_IP_EQ ].bv_len;
+ ip.bv_val = op->o_conn->c_peer_name.bv_val + acl_bv_ip_eq.bv_len;
+ ip.bv_len = op->o_conn->c_peer_name.bv_len - acl_bv_ip_eq.bv_len;
port = strrchr( ip.bv_val, ':' );
if ( port ) {
- char *next;
-
ip.bv_len = port - ip.bv_val;
++port;
- port_number = strtol( port, &next, 10 );
- if ( next[0] != '\0' )
+ if ( lutil_atoi( &port_number, port ) != 0 )
continue;
}
struct berval path;
if ( strncmp( op->o_conn->c_peer_name.bv_val,
- aci_bv[ ACI_BV_PATH_EQ ].bv_val,
- aci_bv[ ACI_BV_PATH_EQ ].bv_len ) != 0 )
+ acl_bv_path_eq.bv_val,
+ acl_bv_path_eq.bv_len ) != 0 )
continue;
path.bv_val = op->o_conn->c_peer_name.bv_val
- + aci_bv[ ACI_BV_PATH_EQ ].bv_len;
+ + acl_bv_path_eq.bv_len;
path.bv_len = op->o_conn->c_peer_name.bv_len
- - aci_bv[ ACI_BV_PATH_EQ ].bv_len;
+ - acl_bv_path_eq.bv_len;
if ( ber_bvcmp( &b->a_peername_pat, &path ) != 0 )
continue;
bv = b->a_set_pat;
}
- if ( acl_match_set( &bv, op, e, 0 ) == 0 ) {
+ if ( acl_match_set( &bv, op, e, NULL ) == 0 ) {
continue;
}
}
}
}
+ /* check for the "self" modifier in the <access> field */
+ if ( b->a_dn.a_self ) {
+ const char *dummy;
+ int rc, match = 0;
+
+ ACL_RECORD_VALUE_STATE;
+
+ /* must have DN syntax */
+ if ( desc->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName &&
+ !is_at_syntax( desc->ad_type, SLAPD_NAMEUID_SYNTAX )) continue;
+
+ /* check if the target is an attribute. */
+ if ( val == NULL ) continue;
+
+ /* a DN must be present */
+ if ( BER_BVISEMPTY( &op->o_ndn ) ) {
+ continue;
+ }
+
+ /* target is attribute, check if the attribute value
+ * is the op dn.
+ */
+ rc = value_match( &match, desc,
+ desc->ad_type->sat_equality, 0,
+ val, &op->o_ndn, &dummy );
+ /* on match error or no match, fail the ACL clause */
+ if ( rc != LDAP_SUCCESS || match != 0 )
+ continue;
+ }
#ifdef SLAP_DYNACL
if ( b->a_dynacl ) {
slap_dynacl_t *da;
0, 0, 0 );
/* this case works different from the others above.
- * since aci's themselves give permissions, we need
+ * since dynamic ACL's themselves give permissions, we need
* to first check b->a_access_mask, the ACL's access level.
*/
- if ( BER_BVISEMPTY( &e->e_nname ) ) {
- /* no ACIs in the root DSE */
- continue;
- }
-
/* first check if the right being requested
* is allowed by the ACL clause.
*/
}
/* start out with nothing granted, nothing denied */
- ACL_INIT(tgrant);
- ACL_INIT(tdeny);
+ ACL_INVALIDATE(tgrant);
+ ACL_INVALIDATE(tdeny);
for ( da = b->a_dynacl; da; da = da->da_next ) {
slap_access_t grant,
deny;
- ACL_INIT(grant);
- ACL_INIT(deny);
+ ACL_INVALIDATE(grant);
+ ACL_INVALIDATE(deny);
Debug( LDAP_DEBUG_ACL, " <= check a_dynacl: %s\n",
da->da_name, 0, 0 );
} else
#else /* !SLAP_DYNACL */
+ /* NOTE: this entire block can be eliminated when SLAP_DYNACL
+ * moves outside of LDAP_DEVEL */
#ifdef SLAPD_ACI_ENABLED
if ( b->a_aci_at != NULL ) {
Attribute *at;
struct berval parent_ndn;
BerVarray bvals = NULL;
int ret, stop;
+#ifdef LDAP_DEBUG
+ char accessmaskbuf1[ACCESSMASK_MAXLEN];
+#endif /* DEBUG */
Debug( LDAP_DEBUG_ACL, " <= check a_aci_at: %s\n",
b->a_aci_at->ad_cname.bv_val, 0, 0 );
switch ( mlist->sml_op ) {
case LDAP_MOD_REPLACE:
+ case LDAP_MOD_INCREMENT:
/*
* We must check both permission to delete the whole
* attribute and permission to add the specific attributes.
struct berval *subj,
Operation *op,
Entry *e,
- int setref )
+ struct berval *default_set_attribute )
{
struct berval set = BER_BVNULL;
int rc = 0;
AclSetCookie cookie;
- if ( setref == 0 ) {
+ if ( default_set_attribute == NULL ) {
ber_dupbv_x( &set, subj, op->o_tmpmemctx );
} else {
struct berval subjdn, ndn = BER_BVNULL;
struct berval setat;
- BerVarray bvals;
+ BerVarray bvals=NULL;
const char *text;
AttributeDescription *desc = NULL;
}
if ( acl_get_part( subj, 1, '/', &setat ) < 0 ) {
- setat = aci_bv[ ACI_BV_SET_ATTR ];
+ setat = *default_set_attribute;
}
/*
}
#endif /* SLAP_DYNACL */
-int
-acl_init( void )
-{
- int rc = 0;
-
+/*
+ * statically built-in dynamic ACL initialization
+ */
+static int (*acl_init_func[])( void ) = {
#ifdef SLAPD_ACI_ENABLED
#ifdef SLAP_DYNACL
- rc = dynacl_aci_init();
+ dynacl_aci_init,
#else /* !SLAP_DYNACL */
- rc = aci_init();
+ aci_init,
#endif /* !SLAP_DYNACL */
- if ( rc != 0 ) {
- return rc;
- }
#endif /* SLAPD_ACI_ENABLED */
- return rc;
+ NULL
+};
+
+int
+acl_init( void )
+{
+ int i, rc;
+
+ for ( i = 0; acl_init_func[ i ] != NULL; i++ ) {
+ rc = (*(acl_init_func[ i ]))();
+ if ( rc != 0 ) {
+ return rc;
+ }
+ }
+
+ return 0;
}
int