/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 1998-2004 The OpenLDAP Foundation.
+ * Copyright 1998-2005 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
static struct berval
aci_bv_entry = BER_BVC("entry"),
aci_bv_children = BER_BVC("children"),
+ aci_bv_onelevel = BER_BVC("onelevel"),
aci_bv_subtree = BER_BVC("subtree"),
aci_bv_br_entry = BER_BVC("[entry]"),
aci_bv_br_all = BER_BVC("[all]"),
"<= root access granted\n",
0, 0, 0 );
if ( maskp ) {
- mask = ACL_LVL_WRITE;
+ mask = ACL_LVL_MANAGE;
}
goto done;
"=> access_allowed: %s access %s by %s\n",
access2str( access ),
ACL_GRANT(mask, access) ? "granted" : "denied",
- accessmask2str( mask, accessmaskbuf ) );
+ accessmask2str( mask, accessmaskbuf, 1 ) );
ret = ACL_GRANT(mask, access);
Debug( LDAP_DEBUG_ACL,
"acl_get: valpat %s\n",
a->acl_attrval.bv_val, 0, 0 );
- if (regexec(&a->acl_attrval_re, val->bv_val, 0, NULL, 0))
+ if ( regexec( &a->acl_attrval_re, val->bv_val, 0, NULL, 0 ) )
+ {
continue;
+ }
+
} else {
int match = 0;
const char *text;
"=> acl_mask: to %s by \"%s\", (%s) \n",
val ? "value" : "all values",
op->o_ndn.bv_val ? op->o_ndn.bv_val : "",
- accessmask2str( *mask, accessmaskbuf ) );
+ accessmask2str( *mask, accessmaskbuf, 1) );
if( state && ( state->as_recorded & ACL_STATE_RECORDED_VD )
*/
/*
* NOTE: styles "anonymous", "users" and "self"
- * have been moved to an enumeration, * whose value
- * is set in a_dn_style; however, the string
+ * 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.
*/
- if ( b->a_dn_style == ACL_STYLE_ANONYMOUS /* bvmatch( &b->a_dn_pat, &aci_bv_anonymous ) */ ) {
+ if ( b->a_dn_style == ACL_STYLE_ANONYMOUS ) {
if ( op->o_ndn.bv_len != 0 ) {
continue;
}
- } else if ( b->a_dn_style == ACL_STYLE_USERS /* bvmatch( &b->a_dn_pat, &aci_bv_users ) */ ) {
+ } else if ( b->a_dn_style == ACL_STYLE_USERS ) {
if ( op->o_ndn.bv_len == 0 ) {
continue;
}
- } else if ( b->a_dn_style == ACL_STYLE_SELF /* bvmatch( &b->a_dn_pat, &aci_bv_self ) */ ) {
+ } else if ( b->a_dn_style == ACL_STYLE_SELF ) {
if ( op->o_ndn.bv_len == 0 ) {
continue;
}
}
}
Debug(LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
- accessmask2str(tgrant,accessmaskbuf),
- accessmask2str(tdeny, accessmaskbuf1), 0);
+ accessmask2str(tgrant,accessmaskbuf, 1),
+ accessmask2str(tdeny, accessmaskbuf1, 1), 0);
}
/* If the entry level aci didn't contain anything valid for the
}
}
Debug(LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
- accessmask2str(tgrant,accessmaskbuf),
- accessmask2str(tdeny, accessmaskbuf1), 0);
+ accessmask2str(tgrant,accessmaskbuf, 1),
+ accessmask2str(tdeny, accessmaskbuf1, 1), 0);
}
break;
Debug( LDAP_DEBUG_ACL,
"<= acl_mask: [%d] applying %s (%s)\n",
- i, accessmask2str( modmask, accessmaskbuf ),
+ i, accessmask2str( modmask, accessmaskbuf, 1 ),
b->a_type == ACL_CONTINUE
? "continue"
: b->a_type == ACL_BREAK
Debug( LDAP_DEBUG_ACL,
"<= acl_mask: [%d] mask: %s\n",
- i, accessmask2str(*mask, accessmaskbuf), 0 );
+ i, accessmask2str(*mask, accessmaskbuf, 1), 0 );
if( b->a_type == ACL_CONTINUE ) {
continue;
Debug( LDAP_DEBUG_ACL,
"<= acl_mask: no more <who> clauses, returning %s (stop)\n",
- accessmask2str(*mask, accessmaskbuf), 0, 0 );
+ accessmask2str(*mask, accessmaskbuf, 1), 0, 0 );
return ACL_STOP;
}
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: backend default %s access %s to \"%s\"\n",
access2str( ACL_WRITE ),
- op->o_bd->be_dfltaccess >= ACL_WRITE ? "granted" : "denied", op->o_dn.bv_val );
+ op->o_bd->be_dfltaccess >= ACL_WRITE
+ ? "granted" : "denied",
+ op->o_dn.bv_val );
ret = (op->o_bd->be_dfltaccess >= ACL_WRITE);
goto done;
}
p.cookie = cookie;
+ op2.o_hdr = cp->op->o_hdr;
op2.o_tag = LDAP_REQ_SEARCH;
- op2.o_protocol = LDAP_VERSION3;
op2.o_ndn = op2.o_bd->be_rootndn;
op2.o_callback = &cb;
op2.o_time = slap_get_time();
op2.o_do_not_cache = 1;
op2.o_is_auth_check = 0;
- op2.o_threadctx = cp->op->o_threadctx;
- op2.o_tmpmemctx = cp->op->o_tmpmemctx;
- op2.o_tmpmfuncs = cp->op->o_tmpmfuncs;
-#ifdef LDAP_SLAPI
- op2.o_pb = cp->op->o_pb;
-#endif
- op2.o_conn = cp->op->o_conn;
- op2.o_connid = cp->op->o_connid;
ber_dupbv_x( &op2.o_req_dn, &op2.o_req_ndn, cp->op->o_tmpmemctx );
op2.ors_slimit = SLAP_NO_LIMIT;
op2.ors_tlimit = SLAP_NO_LIMIT;
op2.ors_attrs = anlistp;
op2.ors_attrsonly = 0;
- op2.o_sync_slog_size = -1;
cb.sc_private = &p;
int rc = 0;
AciSetCookie cookie;
- if (setref == 0) {
+ if ( setref == 0 ) {
ber_dupbv_x( &set, subj, op->o_tmpmemctx );
+
} else {
struct berval subjdn, ndn = BER_BVNULL;
struct berval setat;
/* format of string is "entry/setAttrName" */
if ( aci_get_part( subj, 0, '/', &subjdn ) < 0 ) {
- return(0);
+ return 0;
}
if ( aci_get_part( subj, 1, '/', &setat ) < 0 ) {
assert( !BER_BVISNULL( &desc->ad_cname ) );
/* parse an aci of the form:
- oid#scope#action;rights;attr;rights;attr$action;rights;attr;rights;attr#dnType#subjectDN
+ oid # scope # action;rights;attr;rights;attr
+ $ action;rights;attr;rights;attr # type # subject
+
+ [NOTE: the following comment is very outdated,
+ as the draft version it refers to (Ando, 2004-11-20)].
See draft-ietf-ldapext-aci-model-04.txt section 9.1 for
a full description of the format for this attribute.
Differences: "this" in the draft is "self" here, and
- "self" and "public" is in the position of dnType.
+ "self" and "public" is in the position of type.
+
+ <scope> = {entry|children|subtree}
+ <type> = {public|users|access-id|subtree|onelevel|children|
+ self|dnattr|group|role|set|set-ref}
- For now, this routine only supports scope=entry.
+ This routine now supports scope={ENTRY,CHILDREN}
+ with the semantics:
+ - ENTRY applies to "entry" and "subtree";
+ - CHILDREN aplies to "children" and "subtree"
*/
+
/* check that the aci has all 5 components */
if ( aci_get_part( aci, 4, '#', NULL ) < 0 ) {
return 0;
return 0;
}
+ /* see if we have a public (i.e. anonymous) access */
+ if ( ber_bvstrcasecmp( &aci_bv_public, &type ) == 0 ) {
+ return 1;
+ }
+
+ /* otherwise require an identity */
+ if ( BER_BVISNULL( &op->o_ndn ) || BER_BVISEMPTY( &op->o_ndn ) ) {
+ return 0;
+ }
+
+ /* see if we have a users access */
+ if ( ber_bvstrcasecmp( &aci_bv_users, &type ) == 0 ) {
+ return 1;
+ }
+
+ /* NOTE: this may fail if a DN contains a valid '#' (unescaped);
+ * just grab all the berval up to its end (ITS#3303).
+ * NOTE: the problem could be solved by providing the DN with
+ * the embedded '#' encoded as hexpairs: "cn=Foo#Bar" would
+ * become "cn=Foo\23Bar" and be safely used by aci_mask(). */
+#if 0
if ( aci_get_part( aci, 4, '#', &sdn ) < 0 ) {
return 0;
}
+#endif
+ sdn.bv_val = type.bv_val + type.bv_len + STRLENOF( "#" );
+ sdn.bv_len = aci->bv_len - ( sdn.bv_val - aci->bv_val );
if ( ber_bvstrcasecmp( &aci_bv_access_id, &type ) == 0 ) {
struct berval ndn;
- rc = 0;
- if ( dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx ) == LDAP_SUCCESS )
- {
- if ( dn_match( &op->o_ndn, &ndn ) ) {
- rc = 1;
- }
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
+ rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
+ if ( rc != LDAP_SUCCESS ) {
+ return 0;
+ }
+
+ if ( dn_match( &op->o_ndn, &ndn ) ) {
+ rc = 1;
}
+ slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
+
return rc;
- } else if ( ber_bvstrcasecmp( &aci_bv_public, &type ) == 0 ) {
- return 1;
+ } else if ( ber_bvstrcasecmp( &aci_bv_subtree, &type ) == 0 ) {
+ struct berval ndn;
+
+ rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
+ if ( rc != LDAP_SUCCESS ) {
+ return 0;
+ }
+
+ if ( dnIsSuffix( &op->o_ndn, &ndn ) ) {
+ rc = 1;
+ }
+ slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
+
+ return rc;
+
+ } else if ( ber_bvstrcasecmp( &aci_bv_onelevel, &type ) == 0 ) {
+ struct berval ndn, pndn;
+
+ rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
+ if ( rc != LDAP_SUCCESS ) {
+ return 0;
+ }
+
+ dnParent( &ndn, &pndn );
+
+ if ( dn_match( &op->o_ndn, &pndn ) ) {
+ rc = 1;
+ }
+ slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
+
+ return rc;
+
+ } else if ( ber_bvstrcasecmp( &aci_bv_children, &type ) == 0 ) {
+ struct berval ndn;
+
+ rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
+ if ( rc != LDAP_SUCCESS ) {
+ return 0;
+ }
+
+ if ( !dn_match( &op->o_ndn, &ndn )
+ && dnIsSuffix( &op->o_ndn, &ndn ) )
+ {
+ rc = 1;
+ }
+ slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
+
+ return rc;
} else if ( ber_bvstrcasecmp( &aci_bv_self, &type ) == 0 ) {
if ( dn_match( &op->o_ndn, &e->e_nname ) ) {
rc = 0;
- bv = op->o_ndn;
-
for ( at = attrs_find( e->e_attrs, ad );
at != NULL;
at = attrs_find( at->a_next, ad ) )
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
at->a_nvals,
- &bv, op->o_tmpmemctx ) == 0 )
+ &op->o_ndn, op->o_tmpmemctx ) == 0 )
{
rc = 1;
break;
return rc;
-
} else if ( ber_bvstrcasecmp( &aci_bv_group, &type ) == 0 ) {
if ( aci_group_member( &sdn, &aci_bv_group_class,
&aci_bv_group_attr, op, e, nmatch, matches ) )
return 0;
}
-#endif /* SLAPD_ACI_ENABLED */
-
#ifdef SLAP_DYNACL
static int
dynacl_aci_parse( const char *fname, int lineno, slap_style_t sty, const char *right, void **privp )
}
static int
-dynacl_aci_print( void *priv )
+dynacl_aci_unparse( void *priv, struct berval *bv )
{
AttributeDescription *ad = ( AttributeDescription * )priv;
+ char *ptr;
assert( ad );
- fprintf( stderr, " aci=%s", ad->ad_cname.bv_val );
+ bv->bv_val = ch_malloc( STRLENOF(" aci=") + ad->ad_cname.bv_len + 1 );
+ ptr = lutil_strcopy( bv->bv_val, " aci=" );
+ ptr = lutil_strcopy( ptr, ad->ad_cname.bv_val );
+ bv->bv_len = ptr - bv->bv_val;
return 0;
}
}
Debug( LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
- accessmask2str( tgrant, accessmaskbuf ),
- accessmask2str( tdeny, accessmaskbuf1 ), 0 );
+ accessmask2str( tgrant, accessmaskbuf, 1 ),
+ accessmask2str( tdeny, accessmaskbuf1, 1 ), 0 );
}
/* If the entry level aci didn't contain anything valid for the
struct berval parent_ndn;
struct berval old_parent_ndn = BER_BVNULL;
+#if 1
+ /* to solve the chicken'n'egg problem of accessing
+ * the OpenLDAPaci attribute, the direct access
+ * to the entry's attribute is unchecked; however,
+ * further accesses to OpenLDAPaci values in the
+ * ancestors occur through backend_attribute(), i.e.
+ * with the identity of the operation, requiring
+ * further access checking. For uniformity, this
+ * makes further requests occur as the rootdn, if
+ * any, i.e. searching for the OpenLDAPaci attribute
+ * is considered an internal search. If this is not
+ * acceptable, then the same check needs be performed
+ * when accessing the entry's attribute. */
+ Operation op2 = *op;
+
+ if ( !BER_BVISNULL( &op->o_bd->be_rootndn ) ) {
+ op2.o_dn = op->o_bd->be_rootdn;
+ op2.o_ndn = op->o_bd->be_rootndn;
+ }
+#endif
+
dnParent( &e->e_nname, &parent_ndn );
while ( parent_ndn.bv_val != old_parent_ndn.bv_val ){
int i;
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, ad, &bvals, ACL_AUTH );
+ ret = backend_attribute( &op2, NULL, &parent_ndn, ad, &bvals, ACL_AUTH );
switch ( ret ) {
case LDAP_SUCCESS :
}
}
Debug( LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
- accessmask2str( tgrant, accessmaskbuf ),
- accessmask2str( tdeny, accessmaskbuf1 ), 0 );
+ accessmask2str( tgrant, accessmaskbuf, 1 ),
+ accessmask2str( tdeny, accessmaskbuf1, 1 ), 0 );
}
break;
static slap_dynacl_t dynacl_aci = {
"aci",
dynacl_aci_parse,
- dynacl_aci_print,
+ dynacl_aci_unparse,
dynacl_aci_mask,
NULL,
NULL,
NULL
};
-int
-aci_init( void )
-{
- return slap_dynacl_register( &dynacl_aci );
-}
+#endif /* SLAP_DYNACL */
+
+#endif /* SLAPD_ACI_ENABLED */
+
+#ifdef SLAP_DYNACL
/*
* dynamic ACL infrastructure
int
acl_init( void )
{
+ int i, rc;
#ifdef SLAP_DYNACL
- int rc;
-
- da_list = NULL;
-
+ slap_dynacl_t *known_dynacl[] = {
#ifdef SLAPD_ACI_ENABLED
- rc = aci_init();
- if ( rc ) {
- return rc;
+ &dynacl_aci,
+#endif /* SLAPD_ACI_ENABLED */
+ NULL
+ };
+
+ for ( i = 0; known_dynacl[ i ]; i++ ) {
+ rc = slap_dynacl_register( known_dynacl[ i ] );
+ if ( rc ) {
+ return rc;
+ }
}
-#endif /* SLAPD_ACI_ENABLED */
#endif /* SLAP_DYNACL */
return 0;
}
-
static int
string_expand(
struct berval *bv,