#define ACI_BUF_SIZE 1024 /* use most appropriate size */
+#ifdef SLAP_DYNACL
+static
+#endif /* SLAP_DYNACL */
+AttributeDescription *slap_ad_aci;
+
+static int
+OpenLDAPaciValidate(
+ Syntax *syntax,
+ struct berval *val );
+
+static int
+OpenLDAPaciPretty(
+ Syntax *syntax,
+ struct berval *val,
+ struct berval *out,
+ void *ctx );
+
+static int
+OpenLDAPaciNormalize(
+ slap_mask_t use,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *val,
+ struct berval *out,
+ void *ctx );
+
+#define OpenLDAPaciMatch octetStringMatch
+
static int
aci_list_map_rights(
struct berval *list )
}
switch ( *bv.bv_val ) {
+ case 'x':
+ /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt does not
+ * define any equivalent to the AUTH right, so I've just used
+ * 'x' for now.
+ */
+ ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
+ break;
+ case 'd':
+ /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt defines
+ * the right 'd' to mean "delete"; we hijack it to mean
+ * "disclose" for consistency wuith the rest of slapd.
+ */
+ ACL_PRIV_SET(mask, ACL_PRIV_DISCLOSE);
+ break;
case 'c':
ACL_PRIV_SET(mask, ACL_PRIV_COMPARE);
break;
case 'w':
ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
break;
- case 'x':
- /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt does not
- * define any equivalent to the AUTH right, so I've just used
- * 'x' for now.
- */
- ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
- break;
default:
break;
}
const char *text;
int rc;
- /* format of string is "group/objectClassValue/groupAttrName" */
+ /* format of string is "{group|role}/objectClassValue/groupAttrName" */
if ( acl_get_part( subj, 0, '/', &subjdn ) < 0 ) {
return 0;
}
slap_access_t *deny,
slap_aci_scope_t asserted_scope )
{
- struct berval bv, scope, perms, type, sdn;
+ struct berval bv,
+ scope,
+ perms,
+ type,
+ opts,
+ sdn;
int rc;
* both match "subtree" */
switch ( asserted_scope ) {
case SLAP_ACI_SCOPE_ENTRY:
- /* TODO: use ber_bvcmp */
- if ( ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_ENTRY ] ) != 0
+ if ( ber_bvcmp( &scope, &aci_bv[ ACI_BV_ENTRY ] ) != 0
&& ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_SUBTREE ] ) != 0 )
{
return 0;
break;
case SLAP_ACI_SCOPE_CHILDREN:
- /* TODO: use ber_bvcmp */
- if ( ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_CHILDREN ] ) != 0
+ if ( ber_bvcmp( &scope, &aci_bv[ ACI_BV_CHILDREN ] ) != 0
&& ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_SUBTREE ] ) != 0 )
{
return 0;
}
break;
- default:
- /* TODO: add assertion */
+ case SLAP_ACI_SCOPE_SUBTREE:
+ /* TODO: add assertion? */
return 0;
}
/* get the list of permissions clauses, bail if empty */
if ( acl_get_part( aci, 2, '#', &perms ) <= 0 ) {
- /* TODO: add assertion */
+ assert( 0 );
return 0;
}
/* see if we have a DN match */
if ( acl_get_part( aci, 3, '#', &type ) < 0 ) {
- /* TODO: add assertion */
+ assert( 0 );
return 0;
}
/* see if we have a public (i.e. anonymous) access */
- /* TODO: use ber_bvcmp */
- if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_PUBLIC ], &type ) == 0 ) {
+ if ( ber_bvcmp( &aci_bv[ ACI_BV_PUBLIC ], &type ) == 0 ) {
return 1;
}
}
/* see if we have a users access */
- /* TODO: use ber_bvcmp */
- if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_USERS ], &type ) == 0 ) {
+ if ( ber_bvcmp( &aci_bv[ ACI_BV_USERS ], &type ) == 0 ) {
return 1;
}
sdn.bv_val = type.bv_val + type.bv_len + STRLENOF( "#" );
sdn.bv_len = aci->bv_len - ( sdn.bv_val - aci->bv_val );
- /* TODO: use ber_bvcmp */
- if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_ACCESS_ID ], &type ) == 0 ) {
- struct berval ndn;
-
- /* TODO: don't normalize */
- rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
- if ( rc != LDAP_SUCCESS ) {
- return 0;
- }
+ /* get the type options, if any */
+ if ( acl_get_part( &type, 1, '/', &opts ) > 0 ) {
+ opts.bv_len = type.bv_len - ( opts.bv_val - type.bv_val );
+ type.bv_len = opts.bv_val - type.bv_val - 1;
- if ( dn_match( &op->o_ndn, &ndn ) ) {
- rc = 1;
- }
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
-
- return rc;
-
- /* TODO: use ber_bvcmp */
- } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_SUBTREE ], &type ) == 0 ) {
- struct berval ndn;
-
- /* TODO: don't normalize */
- 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;
-
- /* TODO: use ber_bvcmp */
- } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_ONELEVEL ], &type ) == 0 ) {
- struct berval ndn, pndn;
-
- /* TODO: don't normalize */
- rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
- if ( rc != LDAP_SUCCESS ) {
- return 0;
- }
-
- dnParent( &ndn, &pndn );
+ } else {
+ BER_BVZERO( &opts );
+ }
- if ( dn_match( &op->o_ndn, &pndn ) ) {
- rc = 1;
- }
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
+ if ( ber_bvcmp( &aci_bv[ ACI_BV_ACCESS_ID ], &type ) == 0 ) {
+ return dn_match( &op->o_ndn, &sdn );
- return rc;
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SUBTREE ], &type ) == 0 ) {
+ return dnIsSuffix( &op->o_ndn, &sdn );
- /* TODO: use ber_bvcmp */
- } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_CHILDREN ], &type ) == 0 ) {
- struct berval ndn;
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_ONELEVEL ], &type ) == 0 ) {
+ struct berval pdn;
- /* TODO: don't normalize */
- rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
- if ( rc != LDAP_SUCCESS ) {
- return 0;
- }
+ dnParent( &sdn, &pdn );
- if ( !dn_match( &op->o_ndn, &ndn )
- && dnIsSuffix( &op->o_ndn, &ndn ) )
- {
- rc = 1;
- }
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
+ return dn_match( &op->o_ndn, &pdn );
- return rc;
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_CHILDREN ], &type ) == 0 ) {
+ return ( !dn_match( &op->o_ndn, &sdn ) && dnIsSuffix( &op->o_ndn, &sdn ) );
- /* TODO: use ber_bvcmp */
- } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_SELF ], &type ) == 0 ) {
- if ( dn_match( &op->o_ndn, &e->e_nname ) ) {
- return 1;
- }
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SELF ], &type ) == 0 ) {
+ return dn_match( &op->o_ndn, &e->e_nname );
- /* TODO: use ber_bvcmp */
- } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_DNATTR ], &type ) == 0 ) {
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_DNATTR ], &type ) == 0 ) {
Attribute *at;
AttributeDescription *ad = NULL;
const char *text;
rc = slap_bv2ad( &sdn, &ad, &text );
- if ( rc != LDAP_SUCCESS ) {
- /* TODO: add assertion */
- return 0;
- }
+ assert( rc == LDAP_SUCCESS );
rc = 0;
for ( at = attrs_find( e->e_attrs, ad );
return rc;
- /* TODO: use ber_bvcmp */
- } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_GROUP ], &type ) == 0 ) {
- if ( aci_group_member( &sdn, &aci_bv[ ACI_BV_GROUP_CLASS ],
- &aci_bv[ ACI_BV_GROUP_ATTR ], op, e, nmatch, matches ) )
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_GROUP ], &type ) == 0 ) {
+ struct berval oc,
+ at;
+
+ if ( BER_BVISNULL( &opts ) ) {
+ oc = aci_bv[ ACI_BV_GROUP_CLASS ];
+ at = aci_bv[ ACI_BV_GROUP_ATTR ];
+
+ } else {
+ if ( acl_get_part( &opts, 0, '/', &oc ) < 0 ) {
+ assert( 0 );
+ }
+
+ if ( acl_get_part( &opts, 1, '/', &at ) < 0 ) {
+ at = aci_bv[ ACI_BV_GROUP_ATTR ];
+ }
+ }
+
+ if ( aci_group_member( &sdn, &oc, &at, op, e, nmatch, matches ) )
{
return 1;
}
- /* TODO: use ber_bvcmp */
- } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_ROLE ], &type ) == 0 ) {
- if ( aci_group_member( &sdn, &aci_bv[ ACI_BV_ROLE_CLASS ],
- &aci_bv[ ACI_BV_ROLE_ATTR ], op, e, nmatch, matches ) )
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_ROLE ], &type ) == 0 ) {
+ struct berval oc,
+ at;
+
+ if ( BER_BVISNULL( &opts ) ) {
+ oc = aci_bv[ ACI_BV_ROLE_CLASS ];
+ at = aci_bv[ ACI_BV_ROLE_ATTR ];
+
+ } else {
+ if ( acl_get_part( &opts, 0, '/', &oc ) < 0 ) {
+ assert( 0 );
+ }
+
+ if ( acl_get_part( &opts, 1, '/', &at ) < 0 ) {
+ at = aci_bv[ ACI_BV_ROLE_ATTR ];
+ }
+ }
+
+ if ( aci_group_member( &sdn, &oc, &at, op, e, nmatch, matches ) )
{
return 1;
}
- /* TODO: use ber_bvcmp */
- } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_SET ], &type ) == 0 ) {
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SET ], &type ) == 0 ) {
if ( acl_match_set( &sdn, op, e, 0 ) ) {
return 1;
}
- /* TODO: use ber_bvcmp */
- } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_SET_REF ], &type ) == 0 ) {
+ } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SET_REF ], &type ) == 0 ) {
if ( acl_match_set( &sdn, op, e, 1 ) ) {
return 1;
}
+
+ } else {
+ /* it passed normalization! */
+ assert( 0 );
}
return 0;
}
+int
+aci_init( void )
+{
+ /* OpenLDAP Experimental Syntax */
+ static slap_syntax_defs_rec aci_syntax_def = {
+ "( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
+ SLAP_SYNTAX_HIDE,
+ OpenLDAPaciValidate,
+ OpenLDAPaciPretty
+ };
+ static slap_mrule_defs_rec aci_mr_def = {
+ "( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
+ "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
+ SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
+ NULL, OpenLDAPaciNormalize, OpenLDAPaciMatch,
+ NULL, NULL,
+ NULL
+ };
+ static struct {
+ char *name;
+ char *desc;
+ slap_mask_t flags;
+ AttributeDescription **ad;
+ } aci_at = {
+ "OpenLDAPaci", "( 1.3.6.1.4.1.4203.666.1.5 "
+ "NAME 'OpenLDAPaci' "
+ "DESC 'OpenLDAP access control information (experimental)' "
+ "EQUALITY OpenLDAPaciMatch "
+ "SYNTAX 1.3.6.1.4.1.4203.666.2.1 "
+ "USAGE directoryOperation )",
+ SLAP_AT_HIDE,
+ &slap_ad_aci
+ };
+
+ LDAPAttributeType *at;
+ AttributeType *sat;
+ int rc;
+ const char *text;
+
+ /* ACI syntax */
+ rc = register_syntax( &aci_syntax_def );
+ if ( rc != 0 ) {
+ return rc;
+ }
+
+ /* ACI equality rule */
+ rc = register_matching_rule( &aci_mr_def );
+ if ( rc != 0 ) {
+ return rc;
+ }
+
+ /* ACI attribute */
+ at = ldap_str2attributetype( aci_at.desc,
+ &rc, &text, LDAP_SCHEMA_ALLOW_ALL );
+ if ( !at ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s AttributeType load failed: %s %s\n",
+ aci_at.name, ldap_scherr2str( rc ), text );
+ return rc;
+ }
+
+ rc = at_add( at, 0, &sat, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ ldap_attributetype_free( at );
+ fprintf( stderr, "iMUX_monitor_schema_init: "
+ "AttributeType load failed: %s %s\n",
+ scherr2str( rc ), text );
+ return rc;
+ }
+ ldap_memfree( at );
+
+ rc = slap_str2ad( aci_at.name,
+ aci_at.ad, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY,
+ "unable to find AttributeDescription "
+ "\"%s\": %d (%s)\n",
+ aci_at.name, rc, text );
+ return 1;
+ }
+
+ /* install flags */
+ sat->sat_flags |= aci_at.flags;
+
+ return rc;
+}
+
#ifdef SLAP_DYNACL
/*
* FIXME: there is a silly dependence that makes it difficult
* umbrella, because sets share some helpers with ACIs.
*/
static int
-dynacl_aci_parse( const char *fname, int lineno, slap_style_t sty, const char *right, void **privp )
+dynacl_aci_parse(
+ const char *fname,
+ int lineno,
+ const char *opts,
+ slap_style_t sty,
+ const char *right,
+ void **privp )
{
AttributeDescription *ad = NULL;
const char *text = NULL;
}
} else {
- ad = slap_schema.si_ad_aci;
+ ad = slap_ad_aci;
}
if ( !is_at_syntax( ad->ad_type, SLAPD_ACI_SYNTAX) ) {
int
dynacl_aci_init( void )
{
- return slap_dynacl_register( &dynacl_aci );
+ int rc;
+
+ rc = aci_init();
+
+ if ( rc == 0 ) {
+ rc = slap_dynacl_register( &dynacl_aci );
+ }
+
+ return rc;
}
#endif /* SLAP_DYNACL */
for ( i = 0; i < perms->bv_len; ) {
switch ( perms->bv_val[ i ] ) {
+ case 'x':
+ case 'd':
case 'c':
case 's':
case 'r':
case 'w':
- case 'x':
break;
default:
static const struct berval *OpenLDAPaciscopes[] = {
&aci_bv[ ACI_BV_ENTRY ],
&aci_bv[ ACI_BV_CHILDREN ],
+ &aci_bv[ ACI_BV_SUBTREE ],
NULL
};
NULL
};
-int
+static int
OpenLDAPaciValidate(
Syntax *syntax,
struct berval *val )
subject = BER_BVNULL,
nsubject = BER_BVNULL;
int idx,
- rc,
+ rc = LDAP_SUCCESS,
freesubject = 0,
freetype = 0;
char *ptr;
- ( ocbv.bv_val - type.bv_val );
}
- if ( oc_bvfind( &ocbv ) == NULL ) {
+ oc = oc_bvfind( &ocbv );
+ if ( oc == NULL ) {
rc = LDAP_INVALID_SYNTAX;
goto cleanup;
}
return rc;
}
-int
+static int
OpenLDAPaciPretty(
Syntax *syntax,
struct berval *val,
return OpenLDAPaciPrettyNormal( val, out, ctx, 0 );
}
-int
+static int
OpenLDAPaciNormalize(
slap_mask_t use,
Syntax *syntax,