X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Faci.c;h=97276cfc0b625b26c83aa1e33c093b1ada4a2482;hb=5747896ba081ff998fd97863de26d2f4af59bbd2;hp=012d829fcff25b82a75b8ac329f8a81ce62f10ff;hpb=849ecbcf1fa25b73bcc019150d332f8c1a1d37d4;p=openldap diff --git a/servers/slapd/aci.c b/servers/slapd/aci.c index 012d829fcf..97276cfc0b 100644 --- a/servers/slapd/aci.c +++ b/servers/slapd/aci.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * 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 @@ -40,12 +40,93 @@ #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 -#ifdef SLAP_DYNACL -static -#endif /* SLAP_DYNACL */ -AttributeDescription *slap_ad_aci; +/* 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( @@ -85,6 +166,20 @@ 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; @@ -102,13 +197,6 @@ aci_list_map_rights( 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; } @@ -190,14 +278,18 @@ aci_list_get_attr_rights( 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 rightsk\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; @@ -205,22 +297,22 @@ aci_list_get_attr_rights( 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); @@ -267,7 +359,7 @@ aci_group_member ( 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; } @@ -314,7 +406,7 @@ done: return rc; } -int +static int aci_mask( Operation *op, Entry *e, @@ -327,7 +419,12 @@ aci_mask( 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; @@ -441,6 +538,15 @@ aci_mask( 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 ); @@ -487,37 +593,73 @@ aci_mask( 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; } -int +static int aci_init( void ) { - /* OpenLDAP Experimental Syntax */ + /* 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, @@ -548,10 +690,7 @@ aci_init( void ) &slap_ad_aci }; - LDAPAttributeType *at; - AttributeType *sat; int rc; - const char *text; /* ACI syntax */ rc = register_syntax( &aci_syntax_def ); @@ -566,47 +705,19 @@ aci_init( void ) } /* 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 ); + rc = register_at( aci_at.desc, aci_at.ad, 0 ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, - "unable to find AttributeDescription " - "\"%s\": %d (%s)\n", - aci_at.name, rc, text ); - return 1; + "aci_init: at_register failed\n", 0, 0, 0 ); + return rc; } /* install flags */ - sat->sat_flags |= aci_at.flags; + (*aci_at.ad)->ad_type->sat_flags |= aci_at.flags; return rc; } -#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, @@ -687,6 +798,11 @@ dynacl_aci_mask( 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); @@ -710,7 +826,7 @@ dynacl_aci_mask( } } - 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 ); } @@ -722,35 +838,41 @@ dynacl_aci_mask( 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 : @@ -838,7 +960,6 @@ dynacl_aci_init( void ) return rc; } -#endif /* SLAP_DYNACL */ /* ACI syntax validation */ @@ -888,16 +1009,17 @@ bv_get_tail( * 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( @@ -907,14 +1029,16 @@ OpenLDAPaciValidatePerms( 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; } @@ -928,6 +1052,7 @@ OpenLDAPaciValidatePerms( 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; } @@ -956,6 +1081,7 @@ OpenLDAPaciValidateRight( 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; } @@ -969,16 +1095,36 @@ OpenLDAPaciValidateRight( } 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; + } + } } } } @@ -988,6 +1134,7 @@ OpenLDAPaciValidateRight( 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; } @@ -1008,16 +1155,20 @@ OpenLDAPaciNormalizeRight( /* 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 ) @@ -1032,25 +1183,76 @@ OpenLDAPaciNormalizeRight( /* 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 ]; @@ -1059,10 +1261,13 @@ OpenLDAPaciNormalizeRight( 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 ); + } } } @@ -1071,6 +1276,7 @@ OpenLDAPaciNormalizeRight( 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; } } @@ -1180,8 +1386,10 @@ OpenLDAPaciValidate( 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; } @@ -1193,6 +1401,7 @@ OpenLDAPaciValidate( * 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; } @@ -1200,6 +1409,7 @@ OpenLDAPaciValidate( 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; } @@ -1212,6 +1422,7 @@ OpenLDAPaciValidate( /* 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 ); @@ -1219,11 +1430,13 @@ OpenLDAPaciValidate( 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; } } @@ -1231,6 +1444,7 @@ OpenLDAPaciValidate( /* 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; } @@ -1238,15 +1452,16 @@ OpenLDAPaciValidate( 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; } } @@ -1261,11 +1476,13 @@ OpenLDAPaciValidate( 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; @@ -1278,15 +1495,13 @@ OpenLDAPaciValidate( 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; } } @@ -1294,6 +1509,7 @@ OpenLDAPaciValidate( 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; } @@ -1301,7 +1517,11 @@ OpenLDAPaciValidate( 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 @@ -1320,12 +1540,13 @@ OpenLDAPaciPrettyNormal( subject = BER_BVNULL, nsubject = BER_BVNULL; int idx, - rc, + rc = LDAP_SUCCESS, freesubject = 0, freetype = 0; char *ptr; if ( BER_BVISEMPTY( val ) ) { + Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: value is empty\n", 0, 0, 0 ); return LDAP_INVALID_SYNTAX; } @@ -1333,21 +1554,25 @@ OpenLDAPaciPrettyNormal( 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 ) @@ -1358,6 +1583,7 @@ OpenLDAPaciPrettyNormal( /* 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; } @@ -1366,12 +1592,14 @@ OpenLDAPaciPrettyNormal( 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; } @@ -1382,6 +1610,7 @@ OpenLDAPaciPrettyNormal( 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; } @@ -1402,6 +1631,7 @@ OpenLDAPaciPrettyNormal( freesubject = 1; } else { + Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid subject dn '%s'\n", subject.bv_val, 0, 0 ); goto cleanup; } @@ -1412,7 +1642,7 @@ OpenLDAPaciPrettyNormal( 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; @@ -1423,8 +1653,9 @@ OpenLDAPaciPrettyNormal( 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 @@ -1433,18 +1664,17 @@ OpenLDAPaciPrettyNormal( 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; } @@ -1480,12 +1710,14 @@ OpenLDAPaciPrettyNormal( 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; } @@ -1497,7 +1729,7 @@ OpenLDAPaciPrettyNormal( 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; @@ -1557,5 +1789,17 @@ OpenLDAPaciNormalize( 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 */