1 /* aci.c - routines to parse and check acl's */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2009 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
16 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
17 * All rights reserved.
19 * Redistribution and use in source and binary forms are permitted
20 * provided that this notice is preserved and that due credit is given
21 * to the University of Michigan at Ann Arbor. The name of the University
22 * may not be used to endorse or promote products derived from this
23 * software without specific prior written permission. This software
24 * is provided ``as is'' without express or implied warranty.
29 #ifdef SLAPD_ACI_ENABLED
35 #include <ac/socket.h>
36 #include <ac/string.h>
37 #include <ac/unistd.h>
43 /* use most appropriate size */
44 #define ACI_BUF_SIZE 1024
46 /* move to "stable" when no longer experimental */
47 #define SLAPD_ACI_SYNTAX "1.3.6.1.4.1.4203.666.2.1"
49 /* change this to "OpenLDAPset" */
50 #define SLAPD_ACI_SET_ATTR "template"
52 typedef enum slap_aci_scope_t {
53 SLAP_ACI_SCOPE_ENTRY = 0x1,
54 SLAP_ACI_SCOPE_CHILDREN = 0x2,
55 SLAP_ACI_SCOPE_SUBTREE = ( SLAP_ACI_SCOPE_ENTRY | SLAP_ACI_SCOPE_CHILDREN )
91 static const struct berval aci_bv[] = {
100 BER_BVC("[children]"),
104 BER_BVC("access-id"),
119 BER_BVC(SLAPD_GROUP_CLASS),
120 BER_BVC(SLAPD_GROUP_ATTR),
121 BER_BVC(SLAPD_ROLE_CLASS),
122 BER_BVC(SLAPD_ROLE_ATTR),
124 BER_BVC(SLAPD_ACI_SET_ATTR),
129 static AttributeDescription *slap_ad_aci;
134 struct berval *val );
144 OpenLDAPaciNormalize(
152 #define OpenLDAPaciMatch octetStringMatch
156 struct berval *list )
163 for ( i = 0; acl_get_part( list, i, ',', &bv ) >= 0; i++ ) {
164 if ( bv.bv_len <= 0 ) {
168 switch ( *bv.bv_val ) {
170 /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt does not
171 * define any equivalent to the AUTH right, so I've just used
174 ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
177 /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt defines
178 * the right 'd' to mean "delete"; we hijack it to mean
179 * "disclose" for consistency wuith the rest of slapd.
181 ACL_PRIV_SET(mask, ACL_PRIV_DISCLOSE);
184 ACL_PRIV_SET(mask, ACL_PRIV_COMPARE);
187 /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt defines
188 * the right 's' to mean "set", but in the examples states
189 * that the right 's' means "search". The latter definition
192 ACL_PRIV_SET(mask, ACL_PRIV_SEARCH);
195 ACL_PRIV_SET(mask, ACL_PRIV_READ);
198 ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
212 const struct berval *attr,
215 struct berval bv, left, right;
218 for ( i = 0; acl_get_part( list, i, ',', &bv ) >= 0; i++ ) {
219 if ( acl_get_part(&bv, 0, '=', &left ) < 0
220 || acl_get_part( &bv, 1, '=', &right ) < 0 )
222 if ( ber_bvstrcasecmp( attr, &bv ) == 0 ) {
226 } else if ( val == NULL ) {
227 if ( ber_bvstrcasecmp( attr, &left ) == 0 ) {
232 if ( ber_bvstrcasecmp( attr, &left ) == 0 ) {
233 /* FIXME: this is also totally undocumented! */
234 /* this is experimental code that implements a
235 * simple (prefix) match of the attribute value.
236 * the ACI draft does not provide for aci's that
237 * apply to specific values, but it would be
238 * nice to have. If the <attr> part of an aci's
239 * rights list is of the form <attr>=<value>,
240 * that means the aci applies only to attrs with
241 * the given value. Furthermore, if the attr is
242 * of the form <attr>=<value>*, then <value> is
243 * treated as a prefix, and the aci applies to
244 * any value with that prefix.
246 * Ideally, this would allow r.e. matches.
248 if ( acl_get_part( &right, 0, '*', &left ) < 0
249 || right.bv_len <= left.bv_len )
251 if ( ber_bvstrcasecmp( val, &right ) == 0 ) {
255 } else if ( val->bv_len >= left.bv_len ) {
256 if ( strncasecmp( val->bv_val, left.bv_val, left.bv_len ) == 0 ) {
268 aci_list_get_attr_rights(
270 const struct berval *attr,
277 /* loop through each rights/attr pair, skip first part (action) */
279 for ( i = 1; acl_get_part( list, i + 1, ';', &bv ) >= 0; i += 2 ) {
280 if ( aci_list_has_attr( &bv, attr, val ) == 0 ) {
281 Debug( LDAP_DEBUG_ACL,
282 " <= aci_list_get_attr_rights "
283 "test %s for %s -> failed\n",
284 bv.bv_val, attr->bv_val, 0 );
288 Debug( LDAP_DEBUG_ACL,
289 " <= aci_list_get_attr_rights "
290 "test %s for %s -> ok\n",
291 bv.bv_val, attr->bv_val, 0 );
293 if ( acl_get_part( list, i, ';', &bv ) < 0 ) {
294 Debug( LDAP_DEBUG_ACL,
295 " <= aci_list_get_attr_rights "
301 mask |= aci_list_map_rights( &bv );
302 Debug( LDAP_DEBUG_ACL,
303 " <= aci_list_get_attr_rights "
304 "rights %s to mask 0x%x\n",
305 bv.bv_val, mask, 0 );
316 slap_access_t *grant,
317 slap_access_t *deny )
319 struct berval perm, actn, baseattr;
323 if ( attr == NULL || BER_BVISEMPTY( attr ) ) {
324 attr = (struct berval *)&aci_bv[ ACI_BV_ENTRY ];
326 } else if ( acl_get_part( attr, 0, ';', &baseattr ) > 0 ) {
332 /* loop through each permissions clause */
333 for ( i = 0; acl_get_part( list, i, '$', &perm ) >= 0; i++ ) {
334 if ( acl_get_part( &perm, 0, ';', &actn ) < 0 ) {
338 if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_GRANT ], &actn ) == 0 ) {
341 } else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_DENY ], &actn ) == 0 ) {
348 *mask |= aci_list_get_attr_rights( &perm, attr, val );
349 *mask |= aci_list_get_attr_rights( &perm, &aci_bv[ ACI_BV_BR_ALL ], NULL );
351 if ( *mask != ACL_PRIV_NONE ) {
362 const struct berval *defgrpoc,
363 const struct berval *defgrpat,
370 struct berval subjdn;
373 ObjectClass *grp_oc = NULL;
374 AttributeDescription *grp_ad = NULL;
378 /* format of string is "{group|role}/objectClassValue/groupAttrName" */
379 if ( acl_get_part( subj, 0, '/', &subjdn ) < 0 ) {
383 if ( acl_get_part( subj, 1, '/', &grpoc ) < 0 ) {
387 if ( acl_get_part( subj, 2, '/', &grpat ) < 0 ) {
391 rc = slap_bv2ad( &grpat, &grp_ad, &text );
392 if ( rc != LDAP_SUCCESS ) {
398 grp_oc = oc_bvfind( &grpoc );
400 if ( grp_oc != NULL && grp_ad != NULL ) {
401 char buf[ ACI_BUF_SIZE ];
402 struct berval bv, ndn;
403 AclRegexMatches amatches = { 0 };
405 amatches.dn_count = nmatch;
406 AC_MEMCPY( amatches.dn_data, matches, sizeof( amatches.dn_data ) );
408 bv.bv_len = sizeof( buf ) - 1;
409 bv.bv_val = (char *)&buf;
410 if ( acl_string_expand( &bv, &subjdn,
411 &e->e_nname, NULL, &amatches ) )
417 if ( dnNormalize( 0, NULL, NULL, &bv, &ndn, op->o_tmpmemctx ) == LDAP_SUCCESS )
419 rc = ( backend_group( op, e, &ndn, &op->o_ndn,
420 grp_oc, grp_ad ) == 0 );
421 slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
433 AttributeDescription *desc,
438 slap_access_t *grant,
440 slap_aci_scope_t asserted_scope )
453 assert( !BER_BVISNULL( &desc->ad_cname ) );
455 /* parse an aci of the form:
456 oid # scope # action;rights;attr;rights;attr
457 $ action;rights;attr;rights;attr # type # subject
459 [NOTE: the following comment is very outdated,
460 as the draft version it refers to (Ando, 2004-11-20)].
462 See draft-ietf-ldapext-aci-model-04.txt section 9.1 for
463 a full description of the format for this attribute.
464 Differences: "this" in the draft is "self" here, and
465 "self" and "public" is in the position of type.
467 <scope> = {entry|children|subtree}
468 <type> = {public|users|access-id|subtree|onelevel|children|
469 self|dnattr|group|role|set|set-ref}
471 This routine now supports scope={ENTRY,CHILDREN}
473 - ENTRY applies to "entry" and "subtree";
474 - CHILDREN applies to "children" and "subtree"
477 /* check that the aci has all 5 components */
478 if ( acl_get_part( aci, 4, '#', NULL ) < 0 ) {
482 /* check that the aci family is supported */
483 /* FIXME: the OID is ignored? */
484 if ( acl_get_part( aci, 0, '#', &bv ) < 0 ) {
488 /* check that the scope matches */
489 if ( acl_get_part( aci, 1, '#', &scope ) < 0 ) {
493 /* note: scope can be either ENTRY or CHILDREN;
494 * they respectively match "entry" and "children" in bv
495 * both match "subtree" */
496 switch ( asserted_scope ) {
497 case SLAP_ACI_SCOPE_ENTRY:
498 if ( ber_bvcmp( &scope, &aci_bv[ ACI_BV_ENTRY ] ) != 0
499 && ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_SUBTREE ] ) != 0 )
505 case SLAP_ACI_SCOPE_CHILDREN:
506 if ( ber_bvcmp( &scope, &aci_bv[ ACI_BV_CHILDREN ] ) != 0
507 && ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_SUBTREE ] ) != 0 )
513 case SLAP_ACI_SCOPE_SUBTREE:
514 /* TODO: add assertion? */
518 /* get the list of permissions clauses, bail if empty */
519 if ( acl_get_part( aci, 2, '#', &perms ) <= 0 ) {
524 /* check if any permissions allow desired access */
525 if ( aci_list_get_rights( &perms, &desc->ad_cname, val, grant, deny ) == 0 ) {
529 /* see if we have a DN match */
530 if ( acl_get_part( aci, 3, '#', &type ) < 0 ) {
535 /* see if we have a public (i.e. anonymous) access */
536 if ( ber_bvcmp( &aci_bv[ ACI_BV_PUBLIC ], &type ) == 0 ) {
540 /* otherwise require an identity */
541 if ( BER_BVISNULL( &op->o_ndn ) || BER_BVISEMPTY( &op->o_ndn ) ) {
545 /* see if we have a users access */
546 if ( ber_bvcmp( &aci_bv[ ACI_BV_USERS ], &type ) == 0 ) {
550 /* NOTE: this may fail if a DN contains a valid '#' (unescaped);
551 * just grab all the berval up to its end (ITS#3303).
552 * NOTE: the problem could be solved by providing the DN with
553 * the embedded '#' encoded as hexpairs: "cn=Foo#Bar" would
554 * become "cn=Foo\23Bar" and be safely used by aci_mask(). */
556 if ( acl_get_part( aci, 4, '#', &sdn ) < 0 ) {
560 sdn.bv_val = type.bv_val + type.bv_len + STRLENOF( "#" );
561 sdn.bv_len = aci->bv_len - ( sdn.bv_val - aci->bv_val );
563 /* get the type options, if any */
564 if ( acl_get_part( &type, 1, '/', &opts ) > 0 ) {
565 opts.bv_len = type.bv_len - ( opts.bv_val - type.bv_val );
566 type.bv_len = opts.bv_val - type.bv_val - 1;
572 if ( ber_bvcmp( &aci_bv[ ACI_BV_ACCESS_ID ], &type ) == 0 ) {
573 return dn_match( &op->o_ndn, &sdn );
575 } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SUBTREE ], &type ) == 0 ) {
576 return dnIsSuffix( &op->o_ndn, &sdn );
578 } else if ( ber_bvcmp( &aci_bv[ ACI_BV_ONELEVEL ], &type ) == 0 ) {
581 dnParent( &sdn, &pdn );
583 return dn_match( &op->o_ndn, &pdn );
585 } else if ( ber_bvcmp( &aci_bv[ ACI_BV_CHILDREN ], &type ) == 0 ) {
586 return ( !dn_match( &op->o_ndn, &sdn ) && dnIsSuffix( &op->o_ndn, &sdn ) );
588 } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SELF ], &type ) == 0 ) {
589 return dn_match( &op->o_ndn, &e->e_nname );
591 } else if ( ber_bvcmp( &aci_bv[ ACI_BV_DNATTR ], &type ) == 0 ) {
593 AttributeDescription *ad = NULL;
596 rc = slap_bv2ad( &sdn, &ad, &text );
597 assert( rc == LDAP_SUCCESS );
600 for ( at = attrs_find( e->e_attrs, ad );
602 at = attrs_find( at->a_next, ad ) )
604 if ( attr_valfind( at,
605 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
606 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
607 &op->o_ndn, NULL, op->o_tmpmemctx ) == 0 )
616 } else if ( ber_bvcmp( &aci_bv[ ACI_BV_GROUP ], &type ) == 0 ) {
620 if ( BER_BVISNULL( &opts ) ) {
621 oc = aci_bv[ ACI_BV_GROUP_CLASS ];
622 at = aci_bv[ ACI_BV_GROUP_ATTR ];
625 if ( acl_get_part( &opts, 0, '/', &oc ) < 0 ) {
629 if ( acl_get_part( &opts, 1, '/', &at ) < 0 ) {
630 at = aci_bv[ ACI_BV_GROUP_ATTR ];
634 if ( aci_group_member( &sdn, &oc, &at, op, e, nmatch, matches ) )
639 } else if ( ber_bvcmp( &aci_bv[ ACI_BV_ROLE ], &type ) == 0 ) {
643 if ( BER_BVISNULL( &opts ) ) {
644 oc = aci_bv[ ACI_BV_ROLE_CLASS ];
645 at = aci_bv[ ACI_BV_ROLE_ATTR ];
648 if ( acl_get_part( &opts, 0, '/', &oc ) < 0 ) {
652 if ( acl_get_part( &opts, 1, '/', &at ) < 0 ) {
653 at = aci_bv[ ACI_BV_ROLE_ATTR ];
657 if ( aci_group_member( &sdn, &oc, &at, op, e, nmatch, matches ) )
662 } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SET ], &type ) == 0 ) {
663 if ( acl_match_set( &sdn, op, e, NULL ) ) {
667 } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SET_REF ], &type ) == 0 ) {
668 if ( acl_match_set( &sdn, op, e, (struct berval *)&aci_bv[ ACI_BV_SET_ATTR ] ) ) {
673 /* it passed normalization! */
683 /* OpenLDAP eXperimental Syntax */
684 static slap_syntax_defs_rec aci_syntax_def = {
685 "( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
691 static slap_mrule_defs_rec aci_mr_def = {
692 "( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
693 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
694 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
695 NULL, OpenLDAPaciNormalize, OpenLDAPaciMatch,
703 AttributeDescription **ad;
705 "OpenLDAPaci", "( 1.3.6.1.4.1.4203.666.1.5 "
706 "NAME 'OpenLDAPaci' "
707 "DESC 'OpenLDAP access control information (experimental)' "
708 "EQUALITY OpenLDAPaciMatch "
709 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 "
710 "USAGE directoryOperation )",
718 rc = register_syntax( &aci_syntax_def );
723 /* ACI equality rule */
724 rc = register_matching_rule( &aci_mr_def );
730 rc = register_at( aci_at.desc, aci_at.ad, 0 );
731 if ( rc != LDAP_SUCCESS ) {
732 Debug( LDAP_DEBUG_ANY,
733 "aci_init: at_register failed\n", 0, 0, 0 );
738 (*aci_at.ad)->ad_type->sat_flags |= aci_at.flags;
752 AttributeDescription *ad = NULL;
753 const char *text = NULL;
755 if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
756 fprintf( stderr, "%s: line %d: "
757 "inappropriate style \"%s\" in \"aci\" by clause\n",
758 fname, lineno, style_strings[sty] );
762 if ( right != NULL && *right != '\0' ) {
763 if ( slap_str2ad( right, &ad, &text ) != LDAP_SUCCESS ) {
765 "%s: line %d: aci \"%s\": %s\n",
766 fname, lineno, right, text );
774 if ( !is_at_syntax( ad->ad_type, SLAPD_ACI_SYNTAX) ) {
775 fprintf( stderr, "%s: line %d: "
776 "aci \"%s\": inappropriate syntax: %s\n",
777 fname, lineno, right,
778 ad->ad_type->sat_syntax_oid );
788 dynacl_aci_unparse( void *priv, struct berval *bv )
790 AttributeDescription *ad = ( AttributeDescription * )priv;
793 assert( ad != NULL );
795 bv->bv_val = ch_malloc( STRLENOF(" aci=") + ad->ad_cname.bv_len + 1 );
796 ptr = lutil_strcopy( bv->bv_val, " aci=" );
797 ptr = lutil_strcopy( ptr, ad->ad_cname.bv_val );
798 bv->bv_len = ptr - bv->bv_val;
808 AttributeDescription *desc,
812 slap_access_t *grantp,
813 slap_access_t *denyp )
815 AttributeDescription *ad = ( AttributeDescription * )priv;
817 slap_access_t tgrant, tdeny, grant, deny;
819 char accessmaskbuf[ACCESSMASK_MAXLEN];
820 char accessmaskbuf1[ACCESSMASK_MAXLEN];
821 #endif /* LDAP_DEBUG */
823 if ( BER_BVISEMPTY( &e->e_nname ) ) {
824 /* no ACIs in the root DSE */
828 /* start out with nothing granted, nothing denied */
832 /* get the aci attribute */
833 at = attr_find( e->e_attrs, ad );
837 /* the aci is an multi-valued attribute. The
838 * rights are determined by OR'ing the individual
839 * rights given by the acis.
841 for ( i = 0; !BER_BVISNULL( &at->a_nvals[i] ); i++ ) {
842 if ( aci_mask( op, e, desc, val, &at->a_nvals[i],
843 nmatch, matches, &grant, &deny,
844 SLAP_ACI_SCOPE_ENTRY ) != 0 )
851 Debug( LDAP_DEBUG_ACL, " <= aci_mask grant %s deny %s\n",
852 accessmask2str( tgrant, accessmaskbuf, 1 ),
853 accessmask2str( tdeny, accessmaskbuf1, 1 ), 0 );
856 /* If the entry level aci didn't contain anything valid for the
857 * current operation, climb up the tree and evaluate the
858 * acis with scope set to subtree
860 if ( tgrant == ACL_PRIV_NONE && tdeny == ACL_PRIV_NONE ) {
861 struct berval parent_ndn;
863 dnParent( &e->e_nname, &parent_ndn );
864 while ( !BER_BVISEMPTY( &parent_ndn ) ){
866 BerVarray bvals = NULL;
869 /* to solve the chicken'n'egg problem of accessing
870 * the OpenLDAPaci attribute, the direct access
871 * to the entry's attribute is unchecked; however,
872 * further accesses to OpenLDAPaci values in the
873 * ancestors occur through backend_attribute(), i.e.
874 * with the identity of the operation, requiring
875 * further access checking. For uniformity, this
876 * makes further requests occur as the rootdn, if
877 * any, i.e. searching for the OpenLDAPaci attribute
878 * is considered an internal search. If this is not
879 * acceptable, then the same check needs be performed
880 * when accessing the entry's attribute. */
881 struct berval save_o_dn, save_o_ndn;
883 if ( !BER_BVISNULL( &op->o_bd->be_rootndn ) ) {
884 save_o_dn = op->o_dn;
885 save_o_ndn = op->o_ndn;
887 op->o_dn = op->o_bd->be_rootdn;
888 op->o_ndn = op->o_bd->be_rootndn;
891 Debug( LDAP_DEBUG_ACL, " checking ACI of \"%s\"\n", parent_ndn.bv_val, 0, 0 );
892 ret = backend_attribute( op, NULL, &parent_ndn, ad, &bvals, ACL_AUTH );
894 if ( !BER_BVISNULL( &op->o_bd->be_rootndn ) ) {
895 op->o_dn = save_o_dn;
896 op->o_ndn = save_o_ndn;
906 for ( i = 0; !BER_BVISNULL( &bvals[i] ); i++ ) {
907 if ( aci_mask( op, e, desc, val,
911 SLAP_ACI_SCOPE_CHILDREN ) != 0 )
915 /* evaluation stops as soon as either a "deny" or a
916 * "grant" directive matches.
918 if ( tgrant != ACL_PRIV_NONE || tdeny != ACL_PRIV_NONE ) {
922 Debug( LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
923 accessmask2str( tgrant, accessmaskbuf, 1 ),
924 accessmask2str( tdeny, accessmaskbuf1, 1 ), 0 );
928 case LDAP_NO_SUCH_ATTRIBUTE:
929 /* just go on if the aci-Attribute is not present in
932 Debug( LDAP_DEBUG_ACL, "no such attribute\n", 0, 0, 0 );
936 case LDAP_NO_SUCH_OBJECT:
937 /* We have reached the base object */
938 Debug( LDAP_DEBUG_ACL, "no such object\n", 0, 0, 0 );
950 dnParent( &parent_ndn, &parent_ndn );
960 /* need to register this at some point */
961 static slap_dynacl_t dynacl_aci = {
972 dynacl_aci_init( void )
979 rc = slap_dynacl_register( &dynacl_aci );
986 /* ACI syntax validation */
989 * Matches given berval to array of bervals
991 * >=0 if one if the array elements equals to this berval
992 * -1 if string was not found in array
997 const struct berval *arr[] )
1001 if ( BER_BVISEMPTY( bv ) ) {
1005 for ( i = 0; arr[ i ] != NULL ; i++ ) {
1006 if ( ber_bvstrcasecmp( bv, arr[ i ] ) == 0 ) {
1015 /* Returns what have left in input berval after current sub */
1020 struct berval *tail )
1024 tail->bv_val = sub->bv_val + sub->bv_len;
1025 head_len = (unsigned long) tail->bv_val - (unsigned long) val->bv_val;
1026 tail->bv_len = val->bv_len - head_len;
1031 * aci is accepted in following form:
1032 * oid#scope#rights#type#subject
1034 * oid := numeric OID (currently ignored)
1035 * scope := entry|children|subtree
1036 * rights := right[[$right]...]
1037 * right := (grant|deny);action
1038 * action := perms;attrs[[;perms;attrs]...]
1039 * perms := perm[[,perm]...]
1041 * attrs := attribute[[,attribute]..]|"[all]"
1042 * attribute := attributeType|attributeType=attributeValue|attributeType=attributeValuePrefix*
1043 * type := public|users|self|dnattr|group|role|set|set-ref|
1044 * access_id|subtree|onelevel|children
1047 OpenLDAPaciValidatePerms(
1048 struct berval *perms )
1052 for ( i = 0; i < perms->bv_len; ) {
1053 switch ( perms->bv_val[ i ] ) {
1063 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 );
1064 return LDAP_INVALID_SYNTAX;
1067 if ( ++i == perms->bv_len ) {
1068 return LDAP_SUCCESS;
1071 while ( i < perms->bv_len && perms->bv_val[ i ] == ' ' )
1074 assert( i != perms->bv_len );
1076 if ( perms->bv_val[ i ] != ',' ) {
1077 Debug( LDAP_DEBUG_ACL, "aciValidatePerms: missing comma in '%s'\n", perms->bv_val, 0, 0 );
1078 return LDAP_INVALID_SYNTAX;
1083 } while ( perms->bv_val[ i ] == ' ' );
1086 return LDAP_SUCCESS;
1089 static const struct berval *ACIgrantdeny[] = {
1090 &aci_bv[ ACI_BV_GRANT ],
1091 &aci_bv[ ACI_BV_DENY ],
1096 OpenLDAPaciValidateRight(
1097 struct berval *action )
1099 struct berval bv = BER_BVNULL;
1103 if ( acl_get_part( action, 0, ';', &bv ) < 0 ||
1104 bv_getcaseidx( &bv, ACIgrantdeny ) == -1 )
1106 Debug( LDAP_DEBUG_ACL, "aciValidateRight: '%s' must be either 'grant' or 'deny'\n", bv.bv_val, 0, 0 );
1107 return LDAP_INVALID_SYNTAX;
1110 for ( i = 0; acl_get_part( action, i + 1, ';', &bv ) >= 0; i++ ) {
1113 if ( OpenLDAPaciValidatePerms( &bv ) != LDAP_SUCCESS )
1115 return LDAP_INVALID_SYNTAX;
1120 AttributeDescription *ad;
1122 struct berval attr, left, right;
1125 /* could be "[all]" or an attribute description */
1126 if ( ber_bvstrcasecmp( &bv, &aci_bv[ ACI_BV_BR_ALL ] ) == 0 ) {
1131 for ( j = 0; acl_get_part( &bv, j, ',', &attr ) >= 0; j++ )
1135 if ( acl_get_part( &attr, 0, '=', &left ) < 0
1136 || acl_get_part( &attr, 1, '=', &right ) < 0 )
1138 if ( slap_bv2ad( &attr, &ad, &text ) != LDAP_SUCCESS )
1140 Debug( LDAP_DEBUG_ACL, "aciValidateRight: unknown attribute: '%s'\n", attr.bv_val, 0, 0 );
1141 return LDAP_INVALID_SYNTAX;
1144 if ( slap_bv2ad( &left, &ad, &text ) != LDAP_SUCCESS )
1146 Debug( LDAP_DEBUG_ACL, "aciValidateRight: unknown attribute: '%s'\n", left.bv_val, 0, 0 );
1147 return LDAP_INVALID_SYNTAX;
1154 /* "perms;attr" go in pairs */
1155 if ( i > 0 && ( i & 1 ) == 0 ) {
1156 return LDAP_SUCCESS;
1159 Debug( LDAP_DEBUG_ACL, "aciValidateRight: perms:attr need to be pairs in '%s'\n", action->bv_val, 0, 0 );
1160 return LDAP_INVALID_SYNTAX;
1163 return LDAP_SUCCESS;
1167 OpenLDAPaciNormalizeRight(
1168 struct berval *action,
1169 struct berval *naction,
1172 struct berval grantdeny,
1179 if ( acl_get_part( action, 0, ';', &grantdeny ) < 0 ) {
1180 Debug( LDAP_DEBUG_ACL, "aciNormalizeRight: missing ';' in '%s'\n", action->bv_val, 0, 0 );
1181 return LDAP_INVALID_SYNTAX;
1183 idx = bv_getcaseidx( &grantdeny, ACIgrantdeny );
1185 Debug( LDAP_DEBUG_ACL, "aciNormalizeRight: '%s' must be grant or deny\n", grantdeny.bv_val, 0, 0 );
1186 return LDAP_INVALID_SYNTAX;
1189 ber_dupbv_x( naction, (struct berval *)ACIgrantdeny[ idx ], ctx );
1191 for ( i = 1; acl_get_part( action, i, ';', &bv ) >= 0; i++ ) {
1192 struct berval nattrs = BER_BVNULL;
1196 if ( OpenLDAPaciValidatePerms( &bv ) != LDAP_SUCCESS )
1198 return LDAP_INVALID_SYNTAX;
1206 /* could be "[all]" or an attribute description */
1207 if ( ber_bvstrcasecmp( &bv, &aci_bv[ ACI_BV_BR_ALL ] ) == 0 ) {
1208 nattrs = aci_bv[ ACI_BV_BR_ALL ];
1212 AttributeDescription *ad = NULL;
1213 AttributeDescription adstatic= { 0 };
1214 const char *text = NULL;
1215 struct berval attr, left, right;
1219 for ( j = 0; acl_get_part( &bv, j, ',', &attr ) >= 0; j++ )
1223 /* openldap 2.1 aci compabitibility [entry] -> entry */
1224 if ( ber_bvstrcasecmp( &attr, &aci_bv[ ACI_BV_BR_ENTRY ] ) == 0 ) {
1226 adstatic.ad_cname = aci_bv[ ACI_BV_ENTRY ];
1228 /* openldap 2.1 aci compabitibility [children] -> children */
1229 } else if ( ber_bvstrcasecmp( &attr, &aci_bv[ ACI_BV_BR_CHILDREN ] ) == 0 ) {
1231 adstatic.ad_cname = aci_bv[ ACI_BV_CHILDREN ];
1233 /* openldap 2.1 aci compabitibility [all] -> only [all] */
1234 } else if ( ber_bvstrcasecmp( &attr, &aci_bv[ ACI_BV_BR_ALL ] ) == 0 ) {
1235 ber_memfree_x( nattrs.bv_val, ctx );
1236 nattrs = aci_bv[ ACI_BV_BR_ALL ];
1240 } else if ( acl_get_part( &attr, 0, '=', &left ) < 0
1241 || acl_get_part( &attr, 1, '=', &right ) < 0 )
1243 if ( slap_bv2ad( &attr, &ad, &text ) != LDAP_SUCCESS )
1245 ber_memfree_x( nattrs.bv_val, ctx );
1246 Debug( LDAP_DEBUG_ACL, "aciNormalizeRight: unknown attribute: '%s'\n", attr.bv_val, 0, 0 );
1247 return LDAP_INVALID_SYNTAX;
1251 if ( slap_bv2ad( &left, &ad, &text ) != LDAP_SUCCESS )
1253 ber_memfree_x( nattrs.bv_val, ctx );
1254 Debug( LDAP_DEBUG_ACL, "aciNormalizeRight: unknown attribute: '%s'\n", left.bv_val, 0, 0 );
1255 return LDAP_INVALID_SYNTAX;
1260 len = nattrs.bv_len + ( !BER_BVISEMPTY( &nattrs ) ? STRLENOF( "," ) : 0 )
1261 + ad->ad_cname.bv_len;
1262 nattrs.bv_val = ber_memrealloc_x( nattrs.bv_val, len + 1, ctx );
1263 ptr = &nattrs.bv_val[ nattrs.bv_len ];
1264 if ( !BER_BVISEMPTY( &nattrs ) ) {
1267 ptr = lutil_strncopy( ptr, ad->ad_cname.bv_val, ad->ad_cname.bv_len );
1269 nattrs.bv_len = len;
1274 naction->bv_val = ber_memrealloc_x( naction->bv_val,
1275 naction->bv_len + STRLENOF( ";" )
1276 + perms.bv_len + STRLENOF( ";" )
1277 + nattrs.bv_len + 1,
1280 ptr = &naction->bv_val[ naction->bv_len ];
1283 ptr = lutil_strncopy( ptr, perms.bv_val, perms.bv_len );
1286 ptr = lutil_strncopy( ptr, nattrs.bv_val, nattrs.bv_len );
1288 naction->bv_len += STRLENOF( ";" ) + perms.bv_len
1289 + STRLENOF( ";" ) + nattrs.bv_len;
1291 ber_memfree_x( nattrs.bv_val, ctx );
1296 /* perms;attr go in pairs */
1297 if ( i > 1 && ( i & 1 ) ) {
1298 return LDAP_SUCCESS;
1301 Debug( LDAP_DEBUG_ACL, "aciNormalizeRight: perms:attr need to be pairs in '%s'\n", action->bv_val, 0, 0 );
1302 return LDAP_INVALID_SYNTAX;
1307 OpenLDAPaciValidateRights(
1308 struct berval *actions )
1311 struct berval bv = BER_BVNULL;
1314 for ( i = 0; acl_get_part( actions, i, '$', &bv ) >= 0; i++ ) {
1315 if ( OpenLDAPaciValidateRight( &bv ) != LDAP_SUCCESS ) {
1316 return LDAP_INVALID_SYNTAX;
1320 return LDAP_SUCCESS;
1324 OpenLDAPaciNormalizeRights(
1325 struct berval *actions,
1326 struct berval *nactions,
1330 struct berval bv = BER_BVNULL;
1333 BER_BVZERO( nactions );
1334 for ( i = 0; acl_get_part( actions, i, '$', &bv ) >= 0; i++ ) {
1338 rc = OpenLDAPaciNormalizeRight( &bv, &nbv, ctx );
1339 if ( rc != LDAP_SUCCESS ) {
1340 ber_memfree_x( nactions->bv_val, ctx );
1341 BER_BVZERO( nactions );
1342 return LDAP_INVALID_SYNTAX;
1349 nactions->bv_val = ber_memrealloc_x( nactions->bv_val,
1350 nactions->bv_len + STRLENOF( "$" )
1353 nactions->bv_val[ nactions->bv_len ] = '$';
1354 AC_MEMCPY( &nactions->bv_val[ nactions->bv_len + 1 ],
1355 nbv.bv_val, nbv.bv_len + 1 );
1356 ber_memfree_x( nbv.bv_val, ctx );
1357 nactions->bv_len += STRLENOF( "$" ) + nbv.bv_len;
1362 return LDAP_SUCCESS;
1365 static const struct berval *OpenLDAPaciscopes[] = {
1366 &aci_bv[ ACI_BV_ENTRY ],
1367 &aci_bv[ ACI_BV_CHILDREN ],
1368 &aci_bv[ ACI_BV_SUBTREE ],
1373 static const struct berval *OpenLDAPacitypes[] = {
1375 &aci_bv[ ACI_BV_GROUP ],
1376 &aci_bv[ ACI_BV_ROLE ],
1378 /* set to one past the last DN-valued type with options (/) */
1379 #define LAST_OPTIONAL 2
1381 &aci_bv[ ACI_BV_ACCESS_ID ],
1382 &aci_bv[ ACI_BV_SUBTREE ],
1383 &aci_bv[ ACI_BV_ONELEVEL ],
1384 &aci_bv[ ACI_BV_CHILDREN ],
1386 /* set to one past the last DN-valued type */
1387 #define LAST_DNVALUED 6
1390 &aci_bv[ ACI_BV_DNATTR ],
1391 &aci_bv[ ACI_BV_PUBLIC ],
1392 &aci_bv[ ACI_BV_USERS ],
1393 &aci_bv[ ACI_BV_SELF ],
1394 &aci_bv[ ACI_BV_SET ],
1395 &aci_bv[ ACI_BV_SET_REF ],
1401 OpenLDAPaciValidate(
1403 struct berval *val )
1405 struct berval oid = BER_BVNULL,
1407 rights = BER_BVNULL,
1409 subject = BER_BVNULL;
1413 if ( BER_BVISEMPTY( val ) ) {
1414 Debug( LDAP_DEBUG_ACL, "aciValidatet: value is empty\n", 0, 0, 0 );
1415 return LDAP_INVALID_SYNTAX;
1419 if ( acl_get_part( val, 0, '#', &oid ) < 0 ||
1420 numericoidValidate( NULL, &oid ) != LDAP_SUCCESS )
1422 /* NOTE: the numericoidValidate() is rather pedantic;
1423 * I'd replace it with X-ORDERED VALUES so that
1424 * it's guaranteed values are maintained and used
1425 * in the desired order */
1426 Debug( LDAP_DEBUG_ACL, "aciValidate: invalid oid '%s'\n", oid.bv_val, 0, 0 );
1427 return LDAP_INVALID_SYNTAX;
1431 if ( acl_get_part( val, 1, '#', &scope ) < 0 ||
1432 bv_getcaseidx( &scope, OpenLDAPaciscopes ) == -1 )
1434 Debug( LDAP_DEBUG_ACL, "aciValidate: invalid scope '%s'\n", scope.bv_val, 0, 0 );
1435 return LDAP_INVALID_SYNTAX;
1439 if ( acl_get_part( val, 2, '#', &rights ) < 0 ||
1440 OpenLDAPaciValidateRights( &rights ) != LDAP_SUCCESS )
1442 return LDAP_INVALID_SYNTAX;
1446 if ( acl_get_part( val, 3, '#', &type ) < 0 ) {
1447 Debug( LDAP_DEBUG_ACL, "aciValidate: missing type in '%s'\n", val->bv_val, 0, 0 );
1448 return LDAP_INVALID_SYNTAX;
1450 idx = bv_getcaseidx( &type, OpenLDAPacitypes );
1454 if ( acl_get_part( &type, 0, '/', &isgr ) < 0 ) {
1455 Debug( LDAP_DEBUG_ACL, "aciValidate: invalid type '%s'\n", type.bv_val, 0, 0 );
1456 return LDAP_INVALID_SYNTAX;
1459 idx = bv_getcaseidx( &isgr, OpenLDAPacitypes );
1460 if ( idx == -1 || idx >= LAST_OPTIONAL ) {
1461 Debug( LDAP_DEBUG_ACL, "aciValidate: invalid type '%s'\n", isgr.bv_val, 0, 0 );
1462 return LDAP_INVALID_SYNTAX;
1467 bv_get_tail( val, &type, &subject );
1468 if ( subject.bv_val[ 0 ] != '#' ) {
1469 Debug( LDAP_DEBUG_ACL, "aciValidate: missing subject in '%s'\n", val->bv_val, 0, 0 );
1470 return LDAP_INVALID_SYNTAX;
1473 if ( idx >= LAST_DNVALUED ) {
1474 if ( OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_DNATTR ] ) {
1475 AttributeDescription *ad = NULL;
1476 const char *text = NULL;
1478 rc = slap_bv2ad( &subject, &ad, &text );
1479 if ( rc != LDAP_SUCCESS ) {
1480 Debug( LDAP_DEBUG_ACL, "aciValidate: unknown dn attribute '%s'\n", subject.bv_val, 0, 0 );
1481 return LDAP_INVALID_SYNTAX;
1484 if ( ad->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) {
1485 /* FIXME: allow nameAndOptionalUID? */
1486 Debug( LDAP_DEBUG_ACL, "aciValidate: wrong syntax for dn attribute '%s'\n", subject.bv_val, 0, 0 );
1487 return LDAP_INVALID_SYNTAX;
1492 return LDAP_SUCCESS;
1494 } else if ( OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_GROUP ]
1495 || OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_ROLE ] )
1497 /* do {group|role}/oc/at check */
1498 struct berval ocbv = BER_BVNULL,
1501 ocbv.bv_val = ber_bvchr( &type, '/' );
1502 if ( ocbv.bv_val != NULL ) {
1504 ocbv.bv_len = type.bv_len
1505 - ( ocbv.bv_val - type.bv_val );
1507 atbv.bv_val = ber_bvchr( &ocbv, '/' );
1508 if ( atbv.bv_val != NULL ) {
1509 AttributeDescription *ad = NULL;
1510 const char *text = NULL;
1514 atbv.bv_len = type.bv_len
1515 - ( atbv.bv_val - type.bv_val );
1516 ocbv.bv_len = atbv.bv_val - ocbv.bv_val - 1;
1518 rc = slap_bv2ad( &atbv, &ad, &text );
1519 if ( rc != LDAP_SUCCESS ) {
1520 Debug( LDAP_DEBUG_ACL, "aciValidate: unknown group attribute '%s'\n", atbv.bv_val, 0, 0 );
1521 return LDAP_INVALID_SYNTAX;
1525 if ( oc_bvfind( &ocbv ) == NULL ) {
1526 Debug( LDAP_DEBUG_ACL, "aciValidate: unknown group '%s'\n", ocbv.bv_val, 0, 0 );
1527 return LDAP_INVALID_SYNTAX;
1532 if ( BER_BVISEMPTY( &subject ) ) {
1533 /* empty DN invalid */
1534 Debug( LDAP_DEBUG_ACL, "aciValidate: missing dn in '%s'\n", val->bv_val, 0, 0 );
1535 return LDAP_INVALID_SYNTAX;
1541 /* FIXME: pass DN syntax? */
1542 rc = dnValidate( NULL, &subject );
1543 if ( rc != LDAP_SUCCESS ) {
1544 Debug( LDAP_DEBUG_ACL, "aciValidate: invalid dn '%s'\n", subject.bv_val, 0, 0 );
1550 OpenLDAPaciPrettyNormal(
1556 struct berval oid = BER_BVNULL,
1558 rights = BER_BVNULL,
1559 nrights = BER_BVNULL,
1562 subject = BER_BVNULL,
1563 nsubject = BER_BVNULL;
1572 if ( BER_BVISEMPTY( val ) ) {
1573 Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: value is empty\n", 0, 0, 0 );
1574 return LDAP_INVALID_SYNTAX;
1577 /* oid: if valid, it's already normalized */
1578 if ( acl_get_part( val, 0, '#', &oid ) < 0 ||
1579 numericoidValidate( NULL, &oid ) != LDAP_SUCCESS )
1581 Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid oid '%s'\n", oid.bv_val, 0, 0 );
1582 return LDAP_INVALID_SYNTAX;
1585 /* scope: normalize by replacing with OpenLDAPaciscopes */
1586 if ( acl_get_part( val, 1, '#', &scope ) < 0 ) {
1587 Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: missing scope in '%s'\n", val->bv_val, 0, 0 );
1588 return LDAP_INVALID_SYNTAX;
1590 idx = bv_getcaseidx( &scope, OpenLDAPaciscopes );
1592 Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid scope '%s'\n", scope.bv_val, 0, 0 );
1593 return LDAP_INVALID_SYNTAX;
1595 scope = *OpenLDAPaciscopes[ idx ];
1598 if ( acl_get_part( val, 2, '#', &rights ) < 0 ) {
1599 Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: missing rights in '%s'\n", val->bv_val, 0, 0 );
1600 return LDAP_INVALID_SYNTAX;
1602 if ( OpenLDAPaciNormalizeRights( &rights, &nrights, ctx )
1605 return LDAP_INVALID_SYNTAX;
1609 if ( acl_get_part( val, 3, '#', &type ) < 0 ) {
1610 Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: missing type in '%s'\n", val->bv_val, 0, 0 );
1611 rc = LDAP_INVALID_SYNTAX;
1614 idx = bv_getcaseidx( &type, OpenLDAPacitypes );
1618 if ( acl_get_part( &type, 0, '/', &isgr ) < 0 ) {
1619 Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid type '%s'\n", type.bv_val, 0, 0 );
1620 rc = LDAP_INVALID_SYNTAX;
1624 idx = bv_getcaseidx( &isgr, OpenLDAPacitypes );
1625 if ( idx == -1 || idx >= LAST_OPTIONAL ) {
1626 Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid type '%s'\n", isgr.bv_val, 0, 0 );
1627 rc = LDAP_INVALID_SYNTAX;
1631 ntype = *OpenLDAPacitypes[ idx ];
1634 bv_get_tail( val, &type, &subject );
1636 if ( BER_BVISEMPTY( &subject ) || subject.bv_val[ 0 ] != '#' ) {
1637 Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: missing subject in '%s'\n", val->bv_val, 0, 0 );
1638 rc = LDAP_INVALID_SYNTAX;
1645 if ( idx < LAST_DNVALUED ) {
1646 /* FIXME: pass DN syntax? */
1648 rc = dnNormalize( 0, NULL, NULL,
1649 &subject, &nsubject, ctx );
1651 rc = dnPretty( NULL, &subject, &nsubject, ctx );
1654 if ( rc == LDAP_SUCCESS ) {
1658 Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid subject dn '%s'\n", subject.bv_val, 0, 0 );
1662 if ( OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_GROUP ]
1663 || OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_ROLE ] )
1665 /* do {group|role}/oc/at check */
1666 struct berval ocbv = BER_BVNULL,
1669 ocbv.bv_val = ber_bvchr( &type, '/' );
1670 if ( ocbv.bv_val != NULL ) {
1671 ObjectClass *oc = NULL;
1672 AttributeDescription *ad = NULL;
1673 const char *text = NULL;
1677 bv.bv_len = ntype.bv_len;
1680 ocbv.bv_len = type.bv_len - ( ocbv.bv_val - type.bv_val );
1682 atbv.bv_val = ber_bvchr( &ocbv, '/' );
1683 if ( atbv.bv_val != NULL ) {
1685 atbv.bv_len = type.bv_len
1686 - ( atbv.bv_val - type.bv_val );
1687 ocbv.bv_len = atbv.bv_val - ocbv.bv_val - 1;
1689 rc = slap_bv2ad( &atbv, &ad, &text );
1690 if ( rc != LDAP_SUCCESS ) {
1691 Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: unknown group attribute '%s'\n", atbv.bv_val, 0, 0 );
1692 rc = LDAP_INVALID_SYNTAX;
1696 bv.bv_len += STRLENOF( "/" ) + ad->ad_cname.bv_len;
1699 oc = oc_bvfind( &ocbv );
1701 Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid group '%s'\n", ocbv.bv_val, 0, 0 );
1702 rc = LDAP_INVALID_SYNTAX;
1706 bv.bv_len += STRLENOF( "/" ) + oc->soc_cname.bv_len;
1707 bv.bv_val = ber_memalloc_x( bv.bv_len + 1, ctx );
1710 ptr = lutil_strncopy( ptr, ntype.bv_val, ntype.bv_len );
1713 ptr = lutil_strncopy( ptr,
1714 oc->soc_cname.bv_val,
1715 oc->soc_cname.bv_len );
1719 ptr = lutil_strncopy( ptr,
1720 ad->ad_cname.bv_val,
1721 ad->ad_cname.bv_len );
1730 } else if ( OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_DNATTR ] ) {
1731 AttributeDescription *ad = NULL;
1732 const char *text = NULL;
1735 rc = slap_bv2ad( &subject, &ad, &text );
1736 if ( rc != LDAP_SUCCESS ) {
1737 Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: unknown dn attribute '%s'\n", subject.bv_val, 0, 0 );
1738 rc = LDAP_INVALID_SYNTAX;
1742 if ( ad->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) {
1743 /* FIXME: allow nameAndOptionalUID? */
1744 Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: wrong syntax for dn attribute '%s'\n", subject.bv_val, 0, 0 );
1745 rc = LDAP_INVALID_SYNTAX;
1749 nsubject = ad->ad_cname;
1751 } else if ( OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_SET ]
1752 || OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_SET_REF ] )
1754 /* NOTE: dunno how to normalize it... */
1760 oid.bv_len + STRLENOF( "#" )
1761 + scope.bv_len + STRLENOF( "#" )
1762 + nrights.bv_len + STRLENOF( "#" )
1763 + ntype.bv_len + STRLENOF( "#" )
1766 out->bv_val = ber_memalloc_x( out->bv_len + 1, ctx );
1767 ptr = lutil_strncopy( out->bv_val, oid.bv_val, oid.bv_len );
1770 ptr = lutil_strncopy( ptr, scope.bv_val, scope.bv_len );
1773 ptr = lutil_strncopy( ptr, nrights.bv_val, nrights.bv_len );
1776 ptr = lutil_strncopy( ptr, ntype.bv_val, ntype.bv_len );
1779 if ( !BER_BVISNULL( &nsubject ) ) {
1780 ptr = lutil_strncopy( ptr, nsubject.bv_val, nsubject.bv_len );
1785 if ( freesubject ) {
1786 ber_memfree_x( nsubject.bv_val, ctx );
1790 ber_memfree_x( ntype.bv_val, ctx );
1793 if ( !BER_BVISNULL( &nrights ) ) {
1794 ber_memfree_x( nrights.bv_val, ctx );
1807 return OpenLDAPaciPrettyNormal( val, out, ctx, 0 );
1811 OpenLDAPaciNormalize(
1819 return OpenLDAPaciPrettyNormal( val, out, ctx, 1 );
1822 #if SLAPD_ACI_ENABLED == SLAPD_MOD_DYNAMIC
1824 * FIXME: need config and Makefile.am code to ease building
1828 init_module( int argc, char *argv[] )
1830 return dynacl_aci_init();
1832 #endif /* SLAPD_ACI_ENABLED == SLAPD_MOD_DYNAMIC */
1834 #endif /* SLAPD_ACI_ENABLED */