-#ifdef SLAPD_ACI_ENABLED
-static int
-aci_list_map_rights(
- struct berval *list )
-{
- struct berval bv;
- slap_access_t mask;
- int i;
-
- ACL_INIT(mask);
- for (i = 0; aci_get_part(list, i, ',', &bv) >= 0; i++) {
- if (bv.bv_len <= 0)
- continue;
- switch (*bv.bv_val) {
- case 'c':
- ACL_PRIV_SET(mask, ACL_PRIV_COMPARE);
- break;
- case 's':
- /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt defines
- * the right 's' to mean "set", but in the examples states
- * that the right 's' means "search". The latter definition
- * is used here.
- */
- ACL_PRIV_SET(mask, ACL_PRIV_SEARCH);
- break;
- case 'r':
- ACL_PRIV_SET(mask, ACL_PRIV_READ);
- 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;
- }
-
- }
- return(mask);
-}
-
-static int
-aci_list_has_attr(
- struct berval *list,
- const struct berval *attr,
- struct berval *val )
-{
- struct berval bv, left, right;
- int i;
-
- for (i = 0; aci_get_part(list, i, ',', &bv) >= 0; i++) {
- if (aci_get_part(&bv, 0, '=', &left) < 0
- || aci_get_part(&bv, 1, '=', &right) < 0)
- {
- if (ber_bvstrcasecmp(attr, &bv) == 0)
- return(1);
- } else if (val == NULL) {
- if (ber_bvstrcasecmp(attr, &left) == 0)
- return(1);
- } else {
- if (ber_bvstrcasecmp(attr, &left) == 0) {
- /* this is experimental code that implements a
- * simple (prefix) match of the attribute value.
- * the ACI draft does not provide for aci's that
- * apply to specific values, but it would be
- * nice to have. If the <attr> part of an aci's
- * rights list is of the form <attr>=<value>,
- * that means the aci applies only to attrs with
- * the given value. Furthermore, if the attr is
- * of the form <attr>=<value>*, then <value> is
- * treated as a prefix, and the aci applies to
- * any value with that prefix.
- *
- * Ideally, this would allow r.e. matches.
- */
- if (aci_get_part(&right, 0, '*', &left) < 0
- || right.bv_len <= left.bv_len)
- {
- if (ber_bvstrcasecmp(val, &right) == 0)
- return(1);
- } else if (val->bv_len >= left.bv_len) {
- if (strncasecmp( val->bv_val, left.bv_val, left.bv_len ) == 0)
- return(1);
- }
- }
- }
- }
- return(0);
-}
-
-static slap_access_t
-aci_list_get_attr_rights(
- struct berval *list,
- const struct berval *attr,
- struct berval *val )
-{
- struct berval bv;
- slap_access_t mask;
- int i;
-
- /* loop through each rights/attr pair, skip first part (action) */
- ACL_INIT(mask);
- for (i = 1; aci_get_part(list, i + 1, ';', &bv) >= 0; i += 2) {
- if (aci_list_has_attr(&bv, attr, val) == 0)
- continue;
- if (aci_get_part(list, i, ';', &bv) < 0)
- continue;
- mask |= aci_list_map_rights(&bv);
- }
- 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 perm, actn;
- slap_access_t *mask;
- int i, found;
-
- if (attr == NULL || attr->bv_len == 0
- || ber_bvstrcasecmp( attr, &aci_bv_entry ) == 0) {
- attr = &aci_bv_br_entry;
- }
-
- found = 0;
- ACL_INIT(*grant);
- ACL_INIT(*deny);
- /* loop through each permissions clause */
- for (i = 0; aci_get_part(list, i, '$', &perm) >= 0; i++) {
- if (aci_get_part(&perm, 0, ';', &actn) < 0)
- continue;
- if (ber_bvstrcasecmp( &aci_bv_grant, &actn ) == 0) {
- mask = grant;
- } else if (ber_bvstrcasecmp( &aci_bv_deny, &actn ) == 0) {
- mask = deny;
- } else {
- continue;
- }
-
- found = 1;
- *mask |= aci_list_get_attr_rights(&perm, attr, val);
- *mask |= aci_list_get_attr_rights(&perm, &aci_bv_br_all, NULL);
- }
- return(found);
-}
-
-static int
-aci_group_member (
- struct berval *subj,
- struct berval *defgrpoc,
- struct berval *defgrpat,
- Operation *op,
- Entry *e,
- int nmatch,
- regmatch_t *matches
-)
-{
- struct berval subjdn;
- struct berval grpoc;
- struct berval grpat;
- ObjectClass *grp_oc = NULL;
- AttributeDescription *grp_ad = NULL;
- const char *text;
- int rc;
-
- /* format of string is "group/objectClassValue/groupAttrName" */
- if (aci_get_part(subj, 0, '/', &subjdn) < 0) {
- return(0);
- }
-
- if (aci_get_part(subj, 1, '/', &grpoc) < 0) {
- grpoc = *defgrpoc;
- }
-
- if (aci_get_part(subj, 2, '/', &grpat) < 0) {
- grpat = *defgrpat;
- }
-
- rc = slap_bv2ad( &grpat, &grp_ad, &text );
- if( rc != LDAP_SUCCESS ) {
- rc = 0;
- goto done;
- }
- rc = 0;
-
- grp_oc = oc_bvfind( &grpoc );
-
- if (grp_oc != NULL && grp_ad != NULL ) {
- char buf[ACL_BUF_SIZE];
- struct berval bv, ndn;
- bv.bv_len = sizeof( buf ) - 1;
- bv.bv_val = (char *)&buf;
- if ( string_expand(&bv, &subjdn,
- e->e_ndn, nmatch, matches) )
- {
- rc = LDAP_OTHER;
- goto done;
- }
- if ( dnNormalize( 0, NULL, NULL, &bv, &ndn, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
- rc = ( backend_group( op, e, &ndn, &op->o_ndn,
- grp_oc, grp_ad ) == 0 );
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
- }
- }
-
-done:
- return(rc);
-}
-
-static int
-aci_mask(
- Operation *op,
- Entry *e,
- AttributeDescription *desc,
- struct berval *val,
- struct berval *aci,
- int nmatch,
- regmatch_t *matches,
- slap_access_t *grant,
- slap_access_t *deny,
- slap_aci_scope_t asserted_scope
-)
-{
- struct berval bv, scope, perms, type, sdn;
- int rc;
-
-
- assert( !BER_BVISNULL( &desc->ad_cname ) );
-
- /* parse an aci of the form:
- oid # scope # action;rights;attr;rights;attr
- $ action;rights;attr;rights;attr # type # subject
-
- 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 type.
-
- 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;
- }
-
- /* check that the aci family is supported */
- if ( aci_get_part( aci, 0, '#', &bv ) < 0 ) {
- return 0;
- }
-
- /* check that the scope matches */
- if ( aci_get_part( aci, 1, '#', &scope ) < 0 ) {
- return 0;
- }
-
- /* note: scope can be either ENTRY or CHILDREN;
- * they respectively match "entry" and "children" in bv
- * both match "subtree" */
- switch ( asserted_scope ) {
- case SLAP_ACI_SCOPE_ENTRY:
- if ( ber_bvstrcasecmp( &scope, &aci_bv_entry ) != 0
- && ber_bvstrcasecmp( &scope, &aci_bv_subtree ) != 0 )
- {
- return 0;
- }
- break;
-
- case SLAP_ACI_SCOPE_CHILDREN:
- if ( ber_bvstrcasecmp( &scope, &aci_bv_children ) != 0
- && ber_bvstrcasecmp( &scope, &aci_bv_subtree ) != 0 )
- {
- return 0;
- }
- break;
-
- default:
- return 0;
- }
-
- /* get the list of permissions clauses, bail if empty */
- if ( aci_get_part( aci, 2, '#', &perms ) <= 0 ) {
- return 0;
- }
-
- /* check if any permissions allow desired access */
- if ( aci_list_get_rights( &perms, &desc->ad_cname, val, grant, deny ) == 0 ) {
- return 0;
- }
-
- /* see if we have a DN match */
- if ( aci_get_part( aci, 3, '#', &type ) < 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;
- }
-
- /* 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 = 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_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 ) ) {
- return 1;
- }
-
- } else if ( ber_bvstrcasecmp( &aci_bv_dnattr, &type ) == 0 ) {
- Attribute *at;
- AttributeDescription *ad = NULL;
- const char *text;
-
- rc = slap_bv2ad( &sdn, &ad, &text );
-
- if( rc != LDAP_SUCCESS ) {
- return 0;
- }
-
- rc = 0;
-
- for ( at = attrs_find( e->e_attrs, ad );
- at != NULL;
- at = attrs_find( at->a_next, ad ) )
- {
- if ( value_find_ex( ad,
- SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
- SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
- at->a_nvals,
- &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 1;
- }
-
- } else if ( ber_bvstrcasecmp( &aci_bv_role, &type ) == 0 ) {
- if ( aci_group_member( &sdn, &aci_bv_role_class,
- &aci_bv_role_attr, op, e, nmatch, matches ) )
- {
- return 1;
- }
-
- } else if ( ber_bvstrcasecmp( &aci_bv_set, &type ) == 0 ) {
- if ( aci_match_set( &sdn, op, e, 0 ) ) {
- return 1;
- }
-
- } else if ( ber_bvstrcasecmp( &aci_bv_set_ref, &type ) == 0 ) {
- if ( aci_match_set( &sdn, op, e, 1 ) ) {
- return 1;
- }
- }
-
- return 0;
-}
-
-#endif /* SLAPD_ACI_ENABLED */
-