/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 1998-2005 The OpenLDAP Foundation.
+ * Copyright 1998-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#include "lber_pvt.h"
#include "lutil.h"
-#define ACI_BUF_SIZE 1024 /* use most appropriate size */
+/* use most appropriate size */
+#define ACI_BUF_SIZE 1024
+
+/* move to "stable" when no longer experimental */
+#define SLAPD_ACI_SYNTAX "1.3.6.1.4.1.4203.666.2.1"
+
+/* change this to "OpenLDAPset" */
+#define SLAPD_ACI_SET_ATTR "template"
+
+typedef enum slap_aci_scope_t {
+ SLAP_ACI_SCOPE_ENTRY = 0x1,
+ SLAP_ACI_SCOPE_CHILDREN = 0x2,
+ SLAP_ACI_SCOPE_SUBTREE = ( SLAP_ACI_SCOPE_ENTRY | SLAP_ACI_SCOPE_CHILDREN )
+} slap_aci_scope_t;
+
+enum {
+ ACI_BV_ENTRY,
+ ACI_BV_CHILDREN,
+ ACI_BV_ONELEVEL,
+ ACI_BV_SUBTREE,
+
+ ACI_BV_BR_ENTRY,
+ ACI_BV_BR_CHILDREN,
+ ACI_BV_BR_ALL,
+
+ ACI_BV_ACCESS_ID,
+ ACI_BV_PUBLIC,
+ ACI_BV_USERS,
+ ACI_BV_SELF,
+ ACI_BV_DNATTR,
+ ACI_BV_GROUP,
+ ACI_BV_ROLE,
+ ACI_BV_SET,
+ ACI_BV_SET_REF,
+
+ ACI_BV_GRANT,
+ ACI_BV_DENY,
+
+ ACI_BV_GROUP_CLASS,
+ ACI_BV_GROUP_ATTR,
+ ACI_BV_ROLE_CLASS,
+ ACI_BV_ROLE_ATTR,
+
+ ACI_BV_SET_ATTR,
+
+ ACI_BV_LAST
+};
+
+static const struct berval aci_bv[] = {
+ /* scope */
+ BER_BVC("entry"),
+ BER_BVC("children"),
+ BER_BVC("onelevel"),
+ BER_BVC("subtree"),
+
+ /* */
+ BER_BVC("[entry]"),
+ BER_BVC("[children]"),
+ BER_BVC("[all]"),
+
+ /* type */
+ BER_BVC("access-id"),
+ 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"),
+
+ /* actions */
+ BER_BVC("grant"),
+ BER_BVC("deny"),
+
+ /* schema */
+ 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),
+
+ BER_BVNULL
+};
+
+static 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(
}
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;
}
ACL_INIT(mask);
for ( i = 1; acl_get_part( list, i + 1, ';', &bv ) >= 0; i += 2 ) {
if ( aci_list_has_attr( &bv, attr, val ) == 0 ) {
+ Debug( LDAP_DEBUG_ACL,
+ " <= aci_list_get_attr_rights "
+ "test %s for %s -> failed\n",
+ bv.bv_val, attr->bv_val, 0 );
continue;
}
+ Debug( LDAP_DEBUG_ACL,
+ " <= aci_list_get_attr_rights "
+ "test %s for %s -> ok\n",
+ bv.bv_val, attr->bv_val, 0 );
+
if ( acl_get_part( list, i, ';', &bv ) < 0 ) {
+ Debug( LDAP_DEBUG_ACL,
+ " <= aci_list_get_attr_rights "
+ "test no rights\n",
+ 0, 0, 0 );
continue;
}
mask |= aci_list_map_rights( &bv );
+ Debug( LDAP_DEBUG_ACL,
+ " <= aci_list_get_attr_rights "
+ "rights %s to mask 0x%x\n",
+ bv.bv_val, mask, 0 );
}
return mask;
static int
aci_list_get_rights(
- struct berval *list,
- const struct berval *attr,
- struct berval *val,
- slap_access_t *grant,
- slap_access_t *deny )
+ struct berval *list,
+ struct berval *attr,
+ struct berval *val,
+ slap_access_t *grant,
+ slap_access_t *deny )
{
- struct berval perm, actn;
+ struct berval perm, actn, baseattr;
slap_access_t *mask;
int i, found;
- if ( attr == NULL || BER_BVISEMPTY( attr )
- || ber_bvstrcasecmp( attr, &aci_bv[ ACI_BV_ENTRY ] ) == 0 )
- {
- attr = &aci_bv[ ACI_BV_BR_ENTRY ];
- }
+ if ( attr == NULL || BER_BVISEMPTY( attr ) ) {
+ attr = (struct berval *)&aci_bv[ ACI_BV_ENTRY ];
+ } else if ( acl_get_part( attr, 0, ';', &baseattr ) > 0 ) {
+ attr = &baseattr;
+ }
found = 0;
ACL_INIT(*grant);
ACL_INIT(*deny);
continue;
}
- found = 1;
*mask |= aci_list_get_attr_rights( &perm, attr, val );
*mask |= aci_list_get_attr_rights( &perm, &aci_bv[ ACI_BV_BR_ALL ], NULL );
+
+ if ( *mask != ACL_PRIV_NONE ) {
+ found = 1;
+ }
}
return found;
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;
}
if ( grp_oc != NULL && grp_ad != NULL ) {
char buf[ ACI_BUF_SIZE ];
struct berval bv, ndn;
+ AclRegexMatches amatches = { 0 };
+
+ amatches.dn_count = nmatch;
+ AC_MEMCPY( amatches.dn_data, matches, sizeof( amatches.dn_data ) );
bv.bv_len = sizeof( buf ) - 1;
bv.bv_val = (char *)&buf;
if ( acl_string_expand( &bv, &subjdn,
- e->e_ndn, nmatch, matches ) )
+ &e->e_nname, NULL, &amatches ) )
{
rc = LDAP_OTHER;
goto done;
return rc;
}
-int
+static int
aci_mask(
Operation *op,
Entry *e,
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;
-
+
+ ACL_INIT( *grant );
+ ACL_INIT( *deny );
assert( !BER_BVISNULL( &desc->ad_cname ) );
This routine now supports scope={ENTRY,CHILDREN}
with the semantics:
- ENTRY applies to "entry" and "subtree";
- - CHILDREN aplies to "children" and "subtree"
+ - CHILDREN applies to "children" and "subtree"
*/
/* check that the aci has all 5 components */
sdn.bv_val = type.bv_val + type.bv_len + STRLENOF( "#" );
sdn.bv_len = aci->bv_len - ( sdn.bv_val - aci->bv_val );
+ /* 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;
+
+ } else {
+ BER_BVZERO( &opts );
+ }
+
if ( ber_bvcmp( &aci_bv[ ACI_BV_ACCESS_ID ], &type ) == 0 ) {
return dn_match( &op->o_ndn, &sdn );
at != NULL;
at = attrs_find( at->a_next, ad ) )
{
- if ( value_find_ex( ad,
+ if ( attr_valfind( at,
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
- at->a_nvals,
- &op->o_ndn, op->o_tmpmemctx ) == 0 )
+ &op->o_ndn, NULL, op->o_tmpmemctx ) == 0 )
{
rc = 1;
break;
return rc;
} else if ( ber_bvcmp( &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 ) )
+ 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;
}
} else if ( ber_bvcmp( &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 ) )
+ 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;
}
} else if ( ber_bvcmp( &aci_bv[ ACI_BV_SET ], &type ) == 0 ) {
- if ( acl_match_set( &sdn, op, e, 0 ) ) {
+ if ( acl_match_set( &sdn, op, e, NULL ) ) {
return 1;
}
} else if ( ber_bvcmp( &aci_bv[ ACI_BV_SET_REF ], &type ) == 0 ) {
- if ( acl_match_set( &sdn, op, e, 1 ) ) {
+ if ( acl_match_set( &sdn, op, e, (struct berval *)&aci_bv[ ACI_BV_SET_ATTR ] ) ) {
return 1;
}
+
+ } else {
+ /* it passed normalization! */
+ assert( 0 );
}
return 0;
}
-#ifdef SLAP_DYNACL
-/*
- * FIXME: there is a silly dependence that makes it difficult
- * to move ACIs in a run-time loadable module under the "dynacl"
- * 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 )
+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,
+ NULL,
+ 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
+ };
+
+ int rc;
+
+ /* 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 */
+ rc = register_at( aci_at.desc, aci_at.ad, 0 );
+ if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY,
+ "aci_init: at_register failed\n", 0, 0, 0 );
+ return rc;
+ }
+
+ /* install flags */
+ (*aci_at.ad)->ad_type->sat_flags |= aci_at.flags;
+
+ return rc;
+}
+
+static int
+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) ) {
char accessmaskbuf1[ACCESSMASK_MAXLEN];
#endif /* LDAP_DEBUG */
+ if ( BER_BVISEMPTY( &e->e_nname ) ) {
+ /* no ACIs in the root DSE */
+ return -1;
+ }
+
/* start out with nothing granted, nothing denied */
ACL_INIT(tgrant);
ACL_INIT(tdeny);
}
}
- Debug( LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
+ Debug( LDAP_DEBUG_ACL, " <= aci_mask grant %s deny %s\n",
accessmask2str( tgrant, accessmaskbuf, 1 ),
accessmask2str( tdeny, accessmaskbuf1, 1 ), 0 );
}
if ( tgrant == ACL_PRIV_NONE && tdeny == ACL_PRIV_NONE ) {
struct berval parent_ndn;
-#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 ( !BER_BVISEMPTY( &parent_ndn ) ){
int i;
BerVarray bvals = NULL;
int ret, stop;
- Debug( LDAP_DEBUG_ACL, "checking ACI of \"%s\"\n", parent_ndn.bv_val, 0, 0 );
- ret = backend_attribute( &op2, NULL, &parent_ndn, ad, &bvals, ACL_AUTH );
+ /* 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. */
+ struct berval save_o_dn, save_o_ndn;
+
+ if ( !BER_BVISNULL( &op->o_bd->be_rootndn ) ) {
+ save_o_dn = op->o_dn;
+ save_o_ndn = op->o_ndn;
+
+ op->o_dn = op->o_bd->be_rootdn;
+ op->o_ndn = op->o_bd->be_rootndn;
+ }
+
+ 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 );
+
+ if ( !BER_BVISNULL( &op->o_bd->be_rootndn ) ) {
+ op->o_dn = save_o_dn;
+ op->o_ndn = save_o_ndn;
+ }
switch ( ret ) {
case LDAP_SUCCESS :
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 */
/* ACI syntax validation */
* aci is accepted in following form:
* oid#scope#rights#type#subject
* Where:
- * oid := numeric OID
- * scope := entry|children
+ * oid := numeric OID (currently ignored)
+ * scope := entry|children|subtree
* rights := right[[$right]...]
* right := (grant|deny);action
- * action := perms;attr[[;perms;attr]...]
+ * action := perms;attrs[[;perms;attrs]...]
* perms := perm[[,perm]...]
* perm := c|s|r|w|x
- * attr := attributeType|[all]
- * type := public|users|self|dnattr|group|role|set|set-ref|
- * access_id|subtree|onelevel|children
+ * attrs := attribute[[,attribute]..]|"[all]"
+ * attribute := attributeType|attributeType=attributeValue|attributeType=attributeValuePrefix*
+ * type := public|users|self|dnattr|group|role|set|set-ref|
+ * access_id|subtree|onelevel|children
*/
static int
OpenLDAPaciValidatePerms(
struct berval *perms )
{
- int i;
+ ber_len_t i;
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:
+ Debug( LDAP_DEBUG_ACL, "aciValidatePerms: perms needs to be one of x,d,c,s,r,w in '%s'\n", perms->bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
assert( i != perms->bv_len );
if ( perms->bv_val[ i ] != ',' ) {
+ Debug( LDAP_DEBUG_ACL, "aciValidatePerms: missing comma in '%s'\n", perms->bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
if ( acl_get_part( action, 0, ';', &bv ) < 0 ||
bv_getcaseidx( &bv, ACIgrantdeny ) == -1 )
{
+ Debug( LDAP_DEBUG_ACL, "aciValidateRight: '%s' must be either 'grant' or 'deny'\n", bv.bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
} else {
/* attr */
- AttributeDescription *ad = NULL;
- const char *text = NULL;
+ AttributeDescription *ad;
+ const char *text;
+ struct berval attr, left, right;
+ int j;
/* could be "[all]" or an attribute description */
if ( ber_bvstrcasecmp( &bv, &aci_bv[ ACI_BV_BR_ALL ] ) == 0 ) {
continue;
}
- if ( slap_bv2ad( &bv, &ad, &text ) != LDAP_SUCCESS ) {
- return LDAP_INVALID_SYNTAX;
+
+ for ( j = 0; acl_get_part( &bv, j, ',', &attr ) >= 0; j++ )
+ {
+ ad = NULL;
+ text = NULL;
+ if ( acl_get_part( &attr, 0, '=', &left ) < 0
+ || acl_get_part( &attr, 1, '=', &right ) < 0 )
+ {
+ if ( slap_bv2ad( &attr, &ad, &text ) != LDAP_SUCCESS )
+ {
+ Debug( LDAP_DEBUG_ACL, "aciValidateRight: unknown attribute: '%s'\n", attr.bv_val, 0, 0 );
+ return LDAP_INVALID_SYNTAX;
+ }
+ } else {
+ if ( slap_bv2ad( &left, &ad, &text ) != LDAP_SUCCESS )
+ {
+ Debug( LDAP_DEBUG_ACL, "aciValidateRight: unknown attribute: '%s'\n", left.bv_val, 0, 0 );
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
}
}
}
return LDAP_SUCCESS;
} else {
+ Debug( LDAP_DEBUG_ACL, "aciValidateRight: perms:attr need to be pairs in '%s'\n", action->bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
/* grant|deny */
if ( acl_get_part( action, 0, ';', &grantdeny ) < 0 ) {
+ Debug( LDAP_DEBUG_ACL, "aciNormalizeRight: missing ';' in '%s'\n", action->bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
idx = bv_getcaseidx( &grantdeny, ACIgrantdeny );
if ( idx == -1 ) {
+ Debug( LDAP_DEBUG_ACL, "aciNormalizeRight: '%s' must be grant or deny\n", grantdeny.bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
ber_dupbv_x( naction, (struct berval *)ACIgrantdeny[ idx ], ctx );
for ( i = 1; acl_get_part( action, i, ';', &bv ) >= 0; i++ ) {
+ struct berval nattrs = BER_BVNULL;
+ int freenattrs = 1;
if ( i & 1 ) {
/* perms */
if ( OpenLDAPaciValidatePerms( &bv ) != LDAP_SUCCESS )
/* could be "[all]" or an attribute description */
if ( ber_bvstrcasecmp( &bv, &aci_bv[ ACI_BV_BR_ALL ] ) == 0 ) {
- bv = aci_bv[ ACI_BV_BR_ALL ];
+ nattrs = aci_bv[ ACI_BV_BR_ALL ];
+ freenattrs = 0;
} else {
AttributeDescription *ad = NULL;
+ AttributeDescription adstatic= { 0 };
const char *text = NULL;
- int rc;
+ struct berval attr, left, right;
+ int j;
+ int len;
- rc = slap_bv2ad( &bv, &ad, &text );
- if ( rc != LDAP_SUCCESS ) {
- return LDAP_INVALID_SYNTAX;
+ for ( j = 0; acl_get_part( &bv, j, ',', &attr ) >= 0; j++ )
+ {
+ ad = NULL;
+ text = NULL;
+ /* openldap 2.1 aci compabitibility [entry] -> entry */
+ if ( ber_bvstrcasecmp( &attr, &aci_bv[ ACI_BV_BR_ENTRY ] ) == 0 ) {
+ ad = &adstatic;
+ adstatic.ad_cname = aci_bv[ ACI_BV_ENTRY ];
+
+ /* openldap 2.1 aci compabitibility [children] -> children */
+ } else if ( ber_bvstrcasecmp( &attr, &aci_bv[ ACI_BV_BR_CHILDREN ] ) == 0 ) {
+ ad = &adstatic;
+ adstatic.ad_cname = aci_bv[ ACI_BV_CHILDREN ];
+
+ /* openldap 2.1 aci compabitibility [all] -> only [all] */
+ } else if ( ber_bvstrcasecmp( &attr, &aci_bv[ ACI_BV_BR_ALL ] ) == 0 ) {
+ ber_memfree_x( nattrs.bv_val, ctx );
+ nattrs = aci_bv[ ACI_BV_BR_ALL ];
+ freenattrs = 0;
+ break;
+
+ } else if ( acl_get_part( &attr, 0, '=', &left ) < 0
+ || acl_get_part( &attr, 1, '=', &right ) < 0 )
+ {
+ if ( slap_bv2ad( &attr, &ad, &text ) != LDAP_SUCCESS )
+ {
+ ber_memfree_x( nattrs.bv_val, ctx );
+ Debug( LDAP_DEBUG_ACL, "aciNormalizeRight: unknown attribute: '%s'\n", attr.bv_val, 0, 0 );
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ } else {
+ if ( slap_bv2ad( &left, &ad, &text ) != LDAP_SUCCESS )
+ {
+ ber_memfree_x( nattrs.bv_val, ctx );
+ Debug( LDAP_DEBUG_ACL, "aciNormalizeRight: unknown attribute: '%s'\n", left.bv_val, 0, 0 );
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+
+ len = nattrs.bv_len + ( !BER_BVISEMPTY( &nattrs ) ? STRLENOF( "," ) : 0 )
+ + ad->ad_cname.bv_len;
+ nattrs.bv_val = ber_memrealloc_x( nattrs.bv_val, len + 1, ctx );
+ ptr = &nattrs.bv_val[ nattrs.bv_len ];
+ if ( !BER_BVISEMPTY( &nattrs ) ) {
+ *ptr++ = ',';
+ }
+ ptr = lutil_strncopy( ptr, ad->ad_cname.bv_val, ad->ad_cname.bv_len );
+ ptr[ 0 ] = '\0';
+ nattrs.bv_len = len;
}
- bv = ad->ad_cname;
}
naction->bv_val = ber_memrealloc_x( naction->bv_val,
naction->bv_len + STRLENOF( ";" )
+ perms.bv_len + STRLENOF( ";" )
- + bv.bv_len + 1,
+ + nattrs.bv_len + 1,
ctx );
ptr = &naction->bv_val[ naction->bv_len ];
ptr = lutil_strncopy( ptr, perms.bv_val, perms.bv_len );
ptr[ 0 ] = ';';
ptr++;
- ptr = lutil_strncopy( ptr, bv.bv_val, bv.bv_len );
+ ptr = lutil_strncopy( ptr, nattrs.bv_val, nattrs.bv_len );
ptr[ 0 ] = '\0';
naction->bv_len += STRLENOF( ";" ) + perms.bv_len
- + STRLENOF( ";" ) + bv.bv_len;
+ + STRLENOF( ";" ) + nattrs.bv_len;
+ if ( freenattrs ) {
+ ber_memfree_x( nattrs.bv_val, ctx );
+ }
}
}
return LDAP_SUCCESS;
} else {
+ Debug( LDAP_DEBUG_ACL, "aciNormalizeRight: perms:attr need to be pairs in '%s'\n", action->bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
}
NULL
};
-int
+static int
OpenLDAPaciValidate(
Syntax *syntax,
struct berval *val )
type = BER_BVNULL,
subject = BER_BVNULL;
int idx;
-
+ int rc;
+
if ( BER_BVISEMPTY( val ) ) {
+ Debug( LDAP_DEBUG_ACL, "aciValidatet: value is empty\n", 0, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
* I'd replace it with X-ORDERED VALUES so that
* it's guaranteed values are maintained and used
* in the desired order */
+ Debug( LDAP_DEBUG_ACL, "aciValidate: invalid oid '%s'\n", oid.bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
if ( acl_get_part( val, 1, '#', &scope ) < 0 ||
bv_getcaseidx( &scope, OpenLDAPaciscopes ) == -1 )
{
+ Debug( LDAP_DEBUG_ACL, "aciValidate: invalid scope '%s'\n", scope.bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
/* type */
if ( acl_get_part( val, 3, '#', &type ) < 0 ) {
+ Debug( LDAP_DEBUG_ACL, "aciValidate: missing type in '%s'\n", val->bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
idx = bv_getcaseidx( &type, OpenLDAPacitypes );
struct berval isgr;
if ( acl_get_part( &type, 0, '/', &isgr ) < 0 ) {
+ Debug( LDAP_DEBUG_ACL, "aciValidate: invalid type '%s'\n", type.bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
idx = bv_getcaseidx( &isgr, OpenLDAPacitypes );
if ( idx == -1 || idx >= LAST_OPTIONAL ) {
+ Debug( LDAP_DEBUG_ACL, "aciValidate: invalid type '%s'\n", isgr.bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
}
/* subject */
bv_get_tail( val, &type, &subject );
if ( subject.bv_val[ 0 ] != '#' ) {
+ Debug( LDAP_DEBUG_ACL, "aciValidate: missing subject in '%s'\n", val->bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
if ( OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_DNATTR ] ) {
AttributeDescription *ad = NULL;
const char *text = NULL;
- int rc;
rc = slap_bv2ad( &subject, &ad, &text );
if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ACL, "aciValidate: unknown dn attribute '%s'\n", subject.bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
if ( ad->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) {
/* FIXME: allow nameAndOptionalUID? */
+ Debug( LDAP_DEBUG_ACL, "aciValidate: wrong syntax for dn attribute '%s'\n", subject.bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
}
struct berval ocbv = BER_BVNULL,
atbv = BER_BVNULL;
- ocbv.bv_val = strchr( type.bv_val, '/' );
+ ocbv.bv_val = ber_bvchr( &type, '/' );
if ( ocbv.bv_val != NULL ) {
ocbv.bv_val++;
+ ocbv.bv_len = type.bv_len
+ - ( ocbv.bv_val - type.bv_val );
- atbv.bv_val = strchr( ocbv.bv_val, '/' );
+ atbv.bv_val = ber_bvchr( &ocbv, '/' );
if ( atbv.bv_val != NULL ) {
AttributeDescription *ad = NULL;
const char *text = NULL;
rc = slap_bv2ad( &atbv, &ad, &text );
if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ACL, "aciValidate: unknown group attribute '%s'\n", atbv.bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
-
- } else {
- ocbv.bv_len = type.bv_len
- - ( ocbv.bv_val - type.bv_val );
}
if ( oc_bvfind( &ocbv ) == NULL ) {
+ Debug( LDAP_DEBUG_ACL, "aciValidate: unknown group '%s'\n", ocbv.bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
}
if ( BER_BVISEMPTY( &subject ) ) {
/* empty DN invalid */
+ Debug( LDAP_DEBUG_ACL, "aciValidate: missing dn in '%s'\n", val->bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
subject.bv_len--;
/* FIXME: pass DN syntax? */
- return dnValidate( NULL, &subject );
+ rc = dnValidate( NULL, &subject );
+ if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ACL, "aciValidate: invalid dn '%s'\n", subject.bv_val, 0, 0 );
+ }
+ return rc;
}
static int
subject = BER_BVNULL,
nsubject = BER_BVNULL;
int idx,
- rc,
+ rc = LDAP_SUCCESS,
freesubject = 0,
freetype = 0;
char *ptr;
+ BER_BVZERO( out );
+
if ( BER_BVISEMPTY( val ) ) {
+ Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: value is empty\n", 0, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
if ( acl_get_part( val, 0, '#', &oid ) < 0 ||
numericoidValidate( NULL, &oid ) != LDAP_SUCCESS )
{
+ Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid oid '%s'\n", oid.bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
/* scope: normalize by replacing with OpenLDAPaciscopes */
if ( acl_get_part( val, 1, '#', &scope ) < 0 ) {
+ Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: missing scope in '%s'\n", val->bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
idx = bv_getcaseidx( &scope, OpenLDAPaciscopes );
if ( idx == -1 ) {
+ Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid scope '%s'\n", scope.bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
scope = *OpenLDAPaciscopes[ idx ];
/* rights */
if ( acl_get_part( val, 2, '#', &rights ) < 0 ) {
+ Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: missing rights in '%s'\n", val->bv_val, 0, 0 );
return LDAP_INVALID_SYNTAX;
}
if ( OpenLDAPaciNormalizeRights( &rights, &nrights, ctx )
/* type */
if ( acl_get_part( val, 3, '#', &type ) < 0 ) {
+ Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: missing type in '%s'\n", val->bv_val, 0, 0 );
rc = LDAP_INVALID_SYNTAX;
goto cleanup;
}
struct berval isgr;
if ( acl_get_part( &type, 0, '/', &isgr ) < 0 ) {
+ Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid type '%s'\n", type.bv_val, 0, 0 );
rc = LDAP_INVALID_SYNTAX;
goto cleanup;
}
idx = bv_getcaseidx( &isgr, OpenLDAPacitypes );
if ( idx == -1 || idx >= LAST_OPTIONAL ) {
+ Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid type '%s'\n", isgr.bv_val, 0, 0 );
rc = LDAP_INVALID_SYNTAX;
goto cleanup;
}
bv_get_tail( val, &type, &subject );
if ( BER_BVISEMPTY( &subject ) || subject.bv_val[ 0 ] != '#' ) {
+ Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: missing subject in '%s'\n", val->bv_val, 0, 0 );
rc = LDAP_INVALID_SYNTAX;
goto cleanup;
}
freesubject = 1;
} else {
+ Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid subject dn '%s'\n", subject.bv_val, 0, 0 );
goto cleanup;
}
struct berval ocbv = BER_BVNULL,
atbv = BER_BVNULL;
- ocbv.bv_val = strchr( type.bv_val, '/' );
+ ocbv.bv_val = ber_bvchr( &type, '/' );
if ( ocbv.bv_val != NULL ) {
ObjectClass *oc = NULL;
AttributeDescription *ad = NULL;
bv.bv_len = ntype.bv_len;
ocbv.bv_val++;
+ ocbv.bv_len = type.bv_len - ( ocbv.bv_val - type.bv_val );
- atbv.bv_val = strchr( ocbv.bv_val, '/' );
+ atbv.bv_val = ber_bvchr( &ocbv, '/' );
if ( atbv.bv_val != NULL ) {
atbv.bv_val++;
atbv.bv_len = type.bv_len
rc = slap_bv2ad( &atbv, &ad, &text );
if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: unknown group attribute '%s'\n", atbv.bv_val, 0, 0 );
rc = LDAP_INVALID_SYNTAX;
goto cleanup;
}
bv.bv_len += STRLENOF( "/" ) + ad->ad_cname.bv_len;
-
- } else {
- ocbv.bv_len = type.bv_len
- - ( ocbv.bv_val - type.bv_val );
}
- if ( oc_bvfind( &ocbv ) == NULL ) {
+ oc = oc_bvfind( &ocbv );
+ if ( oc == NULL ) {
+ Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid group '%s'\n", ocbv.bv_val, 0, 0 );
rc = LDAP_INVALID_SYNTAX;
goto cleanup;
}
rc = slap_bv2ad( &subject, &ad, &text );
if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: unknown dn attribute '%s'\n", subject.bv_val, 0, 0 );
rc = LDAP_INVALID_SYNTAX;
goto cleanup;
}
if ( ad->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) {
/* FIXME: allow nameAndOptionalUID? */
+ Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: wrong syntax for dn attribute '%s'\n", subject.bv_val, 0, 0 );
rc = LDAP_INVALID_SYNTAX;
goto cleanup;
}
nsubject = ad->ad_cname;
+
+ } else if ( OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_SET ]
+ || OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_SET_REF ] )
+ {
+ /* NOTE: dunno how to normalize it... */
+ nsubject = subject;
}
out->bv_len =
oid.bv_len + STRLENOF( "#" )
+ scope.bv_len + STRLENOF( "#" )
- + rights.bv_len + STRLENOF( "#" )
+ + nrights.bv_len + STRLENOF( "#" )
+ ntype.bv_len + STRLENOF( "#" )
+ nsubject.bv_len;
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,
return OpenLDAPaciPrettyNormal( val, out, ctx, 1 );
}
+#if SLAPD_ACI_ENABLED == SLAPD_MOD_DYNAMIC
+/*
+ * FIXME: need config and Makefile.am code to ease building
+ * as dynamic module
+ */
+int
+init_module( int argc, char *argv[] )
+{
+ return dynacl_aci_init();
+}
+#endif /* SLAPD_ACI_ENABLED == SLAPD_MOD_DYNAMIC */
+
#endif /* SLAPD_ACI_ENABLED */