1 /* aci.c - routines to parse and check acl's */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/aci.c,v 1.14.2.6 2008/02/11 23:26:43 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2008 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 ) {
349 *mask
|= aci_list_get_attr_rights( &perm
, attr
, val
);
350 *mask
|= aci_list_get_attr_rights( &perm
, &aci_bv
[ ACI_BV_BR_ALL
], NULL
);
359 const struct berval
*defgrpoc
,
360 const struct berval
*defgrpat
,
367 struct berval subjdn
;
370 ObjectClass
*grp_oc
= NULL
;
371 AttributeDescription
*grp_ad
= NULL
;
375 /* format of string is "{group|role}/objectClassValue/groupAttrName" */
376 if ( acl_get_part( subj
, 0, '/', &subjdn
) < 0 ) {
380 if ( acl_get_part( subj
, 1, '/', &grpoc
) < 0 ) {
384 if ( acl_get_part( subj
, 2, '/', &grpat
) < 0 ) {
388 rc
= slap_bv2ad( &grpat
, &grp_ad
, &text
);
389 if ( rc
!= LDAP_SUCCESS
) {
395 grp_oc
= oc_bvfind( &grpoc
);
397 if ( grp_oc
!= NULL
&& grp_ad
!= NULL
) {
398 char buf
[ ACI_BUF_SIZE
];
399 struct berval bv
, ndn
;
401 bv
.bv_len
= sizeof( buf
) - 1;
402 bv
.bv_val
= (char *)&buf
;
403 if ( acl_string_expand( &bv
, &subjdn
,
404 e
->e_ndn
, nmatch
, matches
) )
410 if ( dnNormalize( 0, NULL
, NULL
, &bv
, &ndn
, op
->o_tmpmemctx
) == LDAP_SUCCESS
)
412 rc
= ( backend_group( op
, e
, &ndn
, &op
->o_ndn
,
413 grp_oc
, grp_ad
) == 0 );
414 slap_sl_free( ndn
.bv_val
, op
->o_tmpmemctx
);
426 AttributeDescription
*desc
,
431 slap_access_t
*grant
,
433 slap_aci_scope_t asserted_scope
)
444 assert( !BER_BVISNULL( &desc
->ad_cname
) );
446 /* parse an aci of the form:
447 oid # scope # action;rights;attr;rights;attr
448 $ action;rights;attr;rights;attr # type # subject
450 [NOTE: the following comment is very outdated,
451 as the draft version it refers to (Ando, 2004-11-20)].
453 See draft-ietf-ldapext-aci-model-04.txt section 9.1 for
454 a full description of the format for this attribute.
455 Differences: "this" in the draft is "self" here, and
456 "self" and "public" is in the position of type.
458 <scope> = {entry|children|subtree}
459 <type> = {public|users|access-id|subtree|onelevel|children|
460 self|dnattr|group|role|set|set-ref}
462 This routine now supports scope={ENTRY,CHILDREN}
464 - ENTRY applies to "entry" and "subtree";
465 - CHILDREN applies to "children" and "subtree"
468 /* check that the aci has all 5 components */
469 if ( acl_get_part( aci
, 4, '#', NULL
) < 0 ) {
473 /* check that the aci family is supported */
474 /* FIXME: the OID is ignored? */
475 if ( acl_get_part( aci
, 0, '#', &bv
) < 0 ) {
479 /* check that the scope matches */
480 if ( acl_get_part( aci
, 1, '#', &scope
) < 0 ) {
484 /* note: scope can be either ENTRY or CHILDREN;
485 * they respectively match "entry" and "children" in bv
486 * both match "subtree" */
487 switch ( asserted_scope
) {
488 case SLAP_ACI_SCOPE_ENTRY
:
489 if ( ber_bvcmp( &scope
, &aci_bv
[ ACI_BV_ENTRY
] ) != 0
490 && ber_bvstrcasecmp( &scope
, &aci_bv
[ ACI_BV_SUBTREE
] ) != 0 )
496 case SLAP_ACI_SCOPE_CHILDREN
:
497 if ( ber_bvcmp( &scope
, &aci_bv
[ ACI_BV_CHILDREN
] ) != 0
498 && ber_bvstrcasecmp( &scope
, &aci_bv
[ ACI_BV_SUBTREE
] ) != 0 )
504 case SLAP_ACI_SCOPE_SUBTREE
:
505 /* TODO: add assertion? */
509 /* get the list of permissions clauses, bail if empty */
510 if ( acl_get_part( aci
, 2, '#', &perms
) <= 0 ) {
515 /* check if any permissions allow desired access */
516 if ( aci_list_get_rights( &perms
, &desc
->ad_cname
, val
, grant
, deny
) == 0 ) {
520 /* see if we have a DN match */
521 if ( acl_get_part( aci
, 3, '#', &type
) < 0 ) {
526 /* see if we have a public (i.e. anonymous) access */
527 if ( ber_bvcmp( &aci_bv
[ ACI_BV_PUBLIC
], &type
) == 0 ) {
531 /* otherwise require an identity */
532 if ( BER_BVISNULL( &op
->o_ndn
) || BER_BVISEMPTY( &op
->o_ndn
) ) {
536 /* see if we have a users access */
537 if ( ber_bvcmp( &aci_bv
[ ACI_BV_USERS
], &type
) == 0 ) {
541 /* NOTE: this may fail if a DN contains a valid '#' (unescaped);
542 * just grab all the berval up to its end (ITS#3303).
543 * NOTE: the problem could be solved by providing the DN with
544 * the embedded '#' encoded as hexpairs: "cn=Foo#Bar" would
545 * become "cn=Foo\23Bar" and be safely used by aci_mask(). */
547 if ( acl_get_part( aci
, 4, '#', &sdn
) < 0 ) {
551 sdn
.bv_val
= type
.bv_val
+ type
.bv_len
+ STRLENOF( "#" );
552 sdn
.bv_len
= aci
->bv_len
- ( sdn
.bv_val
- aci
->bv_val
);
554 /* get the type options, if any */
555 if ( acl_get_part( &type
, 1, '/', &opts
) > 0 ) {
556 opts
.bv_len
= type
.bv_len
- ( opts
.bv_val
- type
.bv_val
);
557 type
.bv_len
= opts
.bv_val
- type
.bv_val
- 1;
563 if ( ber_bvcmp( &aci_bv
[ ACI_BV_ACCESS_ID
], &type
) == 0 ) {
564 return dn_match( &op
->o_ndn
, &sdn
);
566 } else if ( ber_bvcmp( &aci_bv
[ ACI_BV_SUBTREE
], &type
) == 0 ) {
567 return dnIsSuffix( &op
->o_ndn
, &sdn
);
569 } else if ( ber_bvcmp( &aci_bv
[ ACI_BV_ONELEVEL
], &type
) == 0 ) {
572 dnParent( &sdn
, &pdn
);
574 return dn_match( &op
->o_ndn
, &pdn
);
576 } else if ( ber_bvcmp( &aci_bv
[ ACI_BV_CHILDREN
], &type
) == 0 ) {
577 return ( !dn_match( &op
->o_ndn
, &sdn
) && dnIsSuffix( &op
->o_ndn
, &sdn
) );
579 } else if ( ber_bvcmp( &aci_bv
[ ACI_BV_SELF
], &type
) == 0 ) {
580 return dn_match( &op
->o_ndn
, &e
->e_nname
);
582 } else if ( ber_bvcmp( &aci_bv
[ ACI_BV_DNATTR
], &type
) == 0 ) {
584 AttributeDescription
*ad
= NULL
;
587 rc
= slap_bv2ad( &sdn
, &ad
, &text
);
588 assert( rc
== LDAP_SUCCESS
);
591 for ( at
= attrs_find( e
->e_attrs
, ad
);
593 at
= attrs_find( at
->a_next
, ad
) )
595 if ( attr_valfind( at
,
596 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH
|
597 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
,
598 &op
->o_ndn
, NULL
, op
->o_tmpmemctx
) == 0 )
607 } else if ( ber_bvcmp( &aci_bv
[ ACI_BV_GROUP
], &type
) == 0 ) {
611 if ( BER_BVISNULL( &opts
) ) {
612 oc
= aci_bv
[ ACI_BV_GROUP_CLASS
];
613 at
= aci_bv
[ ACI_BV_GROUP_ATTR
];
616 if ( acl_get_part( &opts
, 0, '/', &oc
) < 0 ) {
620 if ( acl_get_part( &opts
, 1, '/', &at
) < 0 ) {
621 at
= aci_bv
[ ACI_BV_GROUP_ATTR
];
625 if ( aci_group_member( &sdn
, &oc
, &at
, op
, e
, nmatch
, matches
) )
630 } else if ( ber_bvcmp( &aci_bv
[ ACI_BV_ROLE
], &type
) == 0 ) {
634 if ( BER_BVISNULL( &opts
) ) {
635 oc
= aci_bv
[ ACI_BV_ROLE_CLASS
];
636 at
= aci_bv
[ ACI_BV_ROLE_ATTR
];
639 if ( acl_get_part( &opts
, 0, '/', &oc
) < 0 ) {
643 if ( acl_get_part( &opts
, 1, '/', &at
) < 0 ) {
644 at
= aci_bv
[ ACI_BV_ROLE_ATTR
];
648 if ( aci_group_member( &sdn
, &oc
, &at
, op
, e
, nmatch
, matches
) )
653 } else if ( ber_bvcmp( &aci_bv
[ ACI_BV_SET
], &type
) == 0 ) {
654 if ( acl_match_set( &sdn
, op
, e
, NULL
) ) {
658 } else if ( ber_bvcmp( &aci_bv
[ ACI_BV_SET_REF
], &type
) == 0 ) {
659 if ( acl_match_set( &sdn
, op
, e
, (struct berval
*)&aci_bv
[ ACI_BV_SET_ATTR
] ) ) {
664 /* it passed normalization! */
674 /* OpenLDAP eXperimental Syntax */
675 static slap_syntax_defs_rec aci_syntax_def
= {
676 "( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
682 static slap_mrule_defs_rec aci_mr_def
= {
683 "( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
684 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
685 SLAP_MR_HIDE
| SLAP_MR_EQUALITY
, NULL
,
686 NULL
, OpenLDAPaciNormalize
, OpenLDAPaciMatch
,
694 AttributeDescription
**ad
;
696 "OpenLDAPaci", "( 1.3.6.1.4.1.4203.666.1.5 "
697 "NAME 'OpenLDAPaci' "
698 "DESC 'OpenLDAP access control information (experimental)' "
699 "EQUALITY OpenLDAPaciMatch "
700 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 "
701 "USAGE directoryOperation )",
709 rc
= register_syntax( &aci_syntax_def
);
714 /* ACI equality rule */
715 rc
= register_matching_rule( &aci_mr_def
);
721 rc
= register_at( aci_at
.desc
, aci_at
.ad
, 0 );
722 if ( rc
!= LDAP_SUCCESS
) {
723 Debug( LDAP_DEBUG_ANY
,
724 "aci_init: at_register failed\n", 0, 0, 0 );
729 (*aci_at
.ad
)->ad_type
->sat_flags
|= aci_at
.flags
;
743 AttributeDescription
*ad
= NULL
;
744 const char *text
= NULL
;
746 if ( sty
!= ACL_STYLE_REGEX
&& sty
!= ACL_STYLE_BASE
) {
747 fprintf( stderr
, "%s: line %d: "
748 "inappropriate style \"%s\" in \"aci\" by clause\n",
749 fname
, lineno
, style_strings
[sty
] );
753 if ( right
!= NULL
&& *right
!= '\0' ) {
754 if ( slap_str2ad( right
, &ad
, &text
) != LDAP_SUCCESS
) {
756 "%s: line %d: aci \"%s\": %s\n",
757 fname
, lineno
, right
, text
);
765 if ( !is_at_syntax( ad
->ad_type
, SLAPD_ACI_SYNTAX
) ) {
766 fprintf( stderr
, "%s: line %d: "
767 "aci \"%s\": inappropriate syntax: %s\n",
768 fname
, lineno
, right
,
769 ad
->ad_type
->sat_syntax_oid
);
779 dynacl_aci_unparse( void *priv
, struct berval
*bv
)
781 AttributeDescription
*ad
= ( AttributeDescription
* )priv
;
784 assert( ad
!= NULL
);
786 bv
->bv_val
= ch_malloc( STRLENOF(" aci=") + ad
->ad_cname
.bv_len
+ 1 );
787 ptr
= lutil_strcopy( bv
->bv_val
, " aci=" );
788 ptr
= lutil_strcopy( ptr
, ad
->ad_cname
.bv_val
);
789 bv
->bv_len
= ptr
- bv
->bv_val
;
799 AttributeDescription
*desc
,
803 slap_access_t
*grantp
,
804 slap_access_t
*denyp
)
806 AttributeDescription
*ad
= ( AttributeDescription
* )priv
;
808 slap_access_t tgrant
, tdeny
, grant
, deny
;
810 char accessmaskbuf
[ACCESSMASK_MAXLEN
];
811 char accessmaskbuf1
[ACCESSMASK_MAXLEN
];
812 #endif /* LDAP_DEBUG */
814 if ( BER_BVISEMPTY( &e
->e_nname
) ) {
815 /* no ACIs in the root DSE */
819 /* start out with nothing granted, nothing denied */
823 /* get the aci attribute */
824 at
= attr_find( e
->e_attrs
, ad
);
828 /* the aci is an multi-valued attribute. The
829 * rights are determined by OR'ing the individual
830 * rights given by the acis.
832 for ( i
= 0; !BER_BVISNULL( &at
->a_nvals
[i
] ); i
++ ) {
833 if ( aci_mask( op
, e
, desc
, val
, &at
->a_nvals
[i
],
834 nmatch
, matches
, &grant
, &deny
,
835 SLAP_ACI_SCOPE_ENTRY
) != 0 )
842 Debug( LDAP_DEBUG_ACL
, " <= aci_mask grant %s deny %s\n",
843 accessmask2str( tgrant
, accessmaskbuf
, 1 ),
844 accessmask2str( tdeny
, accessmaskbuf1
, 1 ), 0 );
847 /* If the entry level aci didn't contain anything valid for the
848 * current operation, climb up the tree and evaluate the
849 * acis with scope set to subtree
851 if ( tgrant
== ACL_PRIV_NONE
&& tdeny
== ACL_PRIV_NONE
) {
852 struct berval parent_ndn
;
854 dnParent( &e
->e_nname
, &parent_ndn
);
855 while ( !BER_BVISEMPTY( &parent_ndn
) ){
857 BerVarray bvals
= NULL
;
860 /* to solve the chicken'n'egg problem of accessing
861 * the OpenLDAPaci attribute, the direct access
862 * to the entry's attribute is unchecked; however,
863 * further accesses to OpenLDAPaci values in the
864 * ancestors occur through backend_attribute(), i.e.
865 * with the identity of the operation, requiring
866 * further access checking. For uniformity, this
867 * makes further requests occur as the rootdn, if
868 * any, i.e. searching for the OpenLDAPaci attribute
869 * is considered an internal search. If this is not
870 * acceptable, then the same check needs be performed
871 * when accessing the entry's attribute. */
872 struct berval save_o_dn
, save_o_ndn
;
874 if ( !BER_BVISNULL( &op
->o_bd
->be_rootndn
) ) {
875 save_o_dn
= op
->o_dn
;
876 save_o_ndn
= op
->o_ndn
;
878 op
->o_dn
= op
->o_bd
->be_rootdn
;
879 op
->o_ndn
= op
->o_bd
->be_rootndn
;
882 Debug( LDAP_DEBUG_ACL
, " checking ACI of \"%s\"\n", parent_ndn
.bv_val
, 0, 0 );
883 ret
= backend_attribute( op
, NULL
, &parent_ndn
, ad
, &bvals
, ACL_AUTH
);
885 if ( !BER_BVISNULL( &op
->o_bd
->be_rootndn
) ) {
886 op
->o_dn
= save_o_dn
;
887 op
->o_ndn
= save_o_ndn
;
897 for ( i
= 0; !BER_BVISNULL( &bvals
[i
] ); i
++ ) {
898 if ( aci_mask( op
, e
, desc
, val
,
902 SLAP_ACI_SCOPE_CHILDREN
) != 0 )
906 /* evaluation stops as soon as either a "deny" or a
907 * "grant" directive matches.
909 if ( tgrant
!= ACL_PRIV_NONE
|| tdeny
!= ACL_PRIV_NONE
) {
913 Debug( LDAP_DEBUG_ACL
, "<= aci_mask grant %s deny %s\n",
914 accessmask2str( tgrant
, accessmaskbuf
, 1 ),
915 accessmask2str( tdeny
, accessmaskbuf1
, 1 ), 0 );
919 case LDAP_NO_SUCH_ATTRIBUTE
:
920 /* just go on if the aci-Attribute is not present in
923 Debug( LDAP_DEBUG_ACL
, "no such attribute\n", 0, 0, 0 );
927 case LDAP_NO_SUCH_OBJECT
:
928 /* We have reached the base object */
929 Debug( LDAP_DEBUG_ACL
, "no such object\n", 0, 0, 0 );
941 dnParent( &parent_ndn
, &parent_ndn
);
951 /* need to register this at some point */
952 static slap_dynacl_t dynacl_aci
= {
963 dynacl_aci_init( void )
970 rc
= slap_dynacl_register( &dynacl_aci
);
977 /* ACI syntax validation */
980 * Matches given berval to array of bervals
982 * >=0 if one if the array elements equals to this berval
983 * -1 if string was not found in array
988 const struct berval
*arr
[] )
992 if ( BER_BVISEMPTY( bv
) ) {
996 for ( i
= 0; arr
[ i
] != NULL
; i
++ ) {
997 if ( ber_bvstrcasecmp( bv
, arr
[ i
] ) == 0 ) {
1006 /* Returns what have left in input berval after current sub */
1011 struct berval
*tail
)
1015 tail
->bv_val
= sub
->bv_val
+ sub
->bv_len
;
1016 head_len
= (unsigned long) tail
->bv_val
- (unsigned long) val
->bv_val
;
1017 tail
->bv_len
= val
->bv_len
- head_len
;
1022 * aci is accepted in following form:
1023 * oid#scope#rights#type#subject
1025 * oid := numeric OID (currently ignored)
1026 * scope := entry|children|subtree
1027 * rights := right[[$right]...]
1028 * right := (grant|deny);action
1029 * action := perms;attrs[[;perms;attrs]...]
1030 * perms := perm[[,perm]...]
1032 * attrs := attribute[[,attribute]..]|"[all]"
1033 * attribute := attributeType|attributeType=attributeValue|attributeType=attributeValuePrefix*
1034 * type := public|users|self|dnattr|group|role|set|set-ref|
1035 * access_id|subtree|onelevel|children
1038 OpenLDAPaciValidatePerms(
1039 struct berval
*perms
)
1043 for ( i
= 0; i
< perms
->bv_len
; ) {
1044 switch ( perms
->bv_val
[ i
] ) {
1054 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 );
1055 return LDAP_INVALID_SYNTAX
;
1058 if ( ++i
== perms
->bv_len
) {
1059 return LDAP_SUCCESS
;
1062 while ( i
< perms
->bv_len
&& perms
->bv_val
[ i
] == ' ' )
1065 assert( i
!= perms
->bv_len
);
1067 if ( perms
->bv_val
[ i
] != ',' ) {
1068 Debug( LDAP_DEBUG_ACL
, "aciValidatePerms: missing comma in '%s'\n", perms
->bv_val
, 0, 0 );
1069 return LDAP_INVALID_SYNTAX
;
1074 } while ( perms
->bv_val
[ i
] == ' ' );
1077 return LDAP_SUCCESS
;
1080 static const struct berval
*ACIgrantdeny
[] = {
1081 &aci_bv
[ ACI_BV_GRANT
],
1082 &aci_bv
[ ACI_BV_DENY
],
1087 OpenLDAPaciValidateRight(
1088 struct berval
*action
)
1090 struct berval bv
= BER_BVNULL
;
1094 if ( acl_get_part( action
, 0, ';', &bv
) < 0 ||
1095 bv_getcaseidx( &bv
, ACIgrantdeny
) == -1 )
1097 Debug( LDAP_DEBUG_ACL
, "aciValidateRight: '%s' must be either 'grant' or 'deny'\n", bv
.bv_val
, 0, 0 );
1098 return LDAP_INVALID_SYNTAX
;
1101 for ( i
= 0; acl_get_part( action
, i
+ 1, ';', &bv
) >= 0; i
++ ) {
1104 if ( OpenLDAPaciValidatePerms( &bv
) != LDAP_SUCCESS
)
1106 return LDAP_INVALID_SYNTAX
;
1111 AttributeDescription
*ad
;
1113 struct berval attr
, left
, right
;
1116 /* could be "[all]" or an attribute description */
1117 if ( ber_bvstrcasecmp( &bv
, &aci_bv
[ ACI_BV_BR_ALL
] ) == 0 ) {
1122 for ( j
= 0; acl_get_part( &bv
, j
, ',', &attr
) >= 0; j
++ )
1126 if ( acl_get_part( &attr
, 0, '=', &left
) < 0
1127 || acl_get_part( &attr
, 1, '=', &right
) < 0 )
1129 if ( slap_bv2ad( &attr
, &ad
, &text
) != LDAP_SUCCESS
)
1131 Debug( LDAP_DEBUG_ACL
, "aciValidateRight: unknown attribute: '%s'\n", attr
.bv_val
, 0, 0 );
1132 return LDAP_INVALID_SYNTAX
;
1135 if ( slap_bv2ad( &left
, &ad
, &text
) != LDAP_SUCCESS
)
1137 Debug( LDAP_DEBUG_ACL
, "aciValidateRight: unknown attribute: '%s'\n", left
.bv_val
, 0, 0 );
1138 return LDAP_INVALID_SYNTAX
;
1145 /* "perms;attr" go in pairs */
1146 if ( i
> 0 && ( i
& 1 ) == 0 ) {
1147 return LDAP_SUCCESS
;
1150 Debug( LDAP_DEBUG_ACL
, "aciValidateRight: perms:attr need to be pairs in '%s'\n", action
->bv_val
, 0, 0 );
1151 return LDAP_INVALID_SYNTAX
;
1154 return LDAP_SUCCESS
;
1158 OpenLDAPaciNormalizeRight(
1159 struct berval
*action
,
1160 struct berval
*naction
,
1163 struct berval grantdeny
,
1170 if ( acl_get_part( action
, 0, ';', &grantdeny
) < 0 ) {
1171 Debug( LDAP_DEBUG_ACL
, "aciNormalizeRight: missing ';' in '%s'\n", action
->bv_val
, 0, 0 );
1172 return LDAP_INVALID_SYNTAX
;
1174 idx
= bv_getcaseidx( &grantdeny
, ACIgrantdeny
);
1176 Debug( LDAP_DEBUG_ACL
, "aciNormalizeRight: '%s' must be grant or deny\n", grantdeny
.bv_val
, 0, 0 );
1177 return LDAP_INVALID_SYNTAX
;
1180 ber_dupbv_x( naction
, (struct berval
*)ACIgrantdeny
[ idx
], ctx
);
1182 for ( i
= 1; acl_get_part( action
, i
, ';', &bv
) >= 0; i
++ ) {
1183 struct berval nattrs
= BER_BVNULL
;
1187 if ( OpenLDAPaciValidatePerms( &bv
) != LDAP_SUCCESS
)
1189 return LDAP_INVALID_SYNTAX
;
1197 /* could be "[all]" or an attribute description */
1198 if ( ber_bvstrcasecmp( &bv
, &aci_bv
[ ACI_BV_BR_ALL
] ) == 0 ) {
1199 nattrs
= aci_bv
[ ACI_BV_BR_ALL
];
1203 AttributeDescription
*ad
= NULL
;
1204 AttributeDescription adstatic
= { 0 };
1205 const char *text
= NULL
;
1206 struct berval attr
, left
, right
;
1210 for ( j
= 0; acl_get_part( &bv
, j
, ',', &attr
) >= 0; j
++ )
1214 /* openldap 2.1 aci compabitibility [entry] -> entry */
1215 if ( ber_bvstrcasecmp( &attr
, &aci_bv
[ ACI_BV_BR_ENTRY
] ) == 0 ) {
1217 adstatic
.ad_cname
= aci_bv
[ ACI_BV_ENTRY
];
1219 /* openldap 2.1 aci compabitibility [children] -> children */
1220 } else if ( ber_bvstrcasecmp( &attr
, &aci_bv
[ ACI_BV_BR_CHILDREN
] ) == 0 ) {
1222 adstatic
.ad_cname
= aci_bv
[ ACI_BV_CHILDREN
];
1224 /* openldap 2.1 aci compabitibility [all] -> only [all] */
1225 } else if ( ber_bvstrcasecmp( &attr
, &aci_bv
[ ACI_BV_BR_ALL
] ) == 0 ) {
1226 ber_memfree_x( nattrs
.bv_val
, ctx
);
1227 nattrs
= aci_bv
[ ACI_BV_BR_ALL
];
1231 } else if ( acl_get_part( &attr
, 0, '=', &left
) < 0
1232 || acl_get_part( &attr
, 1, '=', &right
) < 0 )
1234 if ( slap_bv2ad( &attr
, &ad
, &text
) != LDAP_SUCCESS
)
1236 ber_memfree_x( nattrs
.bv_val
, ctx
);
1237 Debug( LDAP_DEBUG_ACL
, "aciNormalizeRight: unknown attribute: '%s'\n", attr
.bv_val
, 0, 0 );
1238 return LDAP_INVALID_SYNTAX
;
1242 if ( slap_bv2ad( &left
, &ad
, &text
) != LDAP_SUCCESS
)
1244 ber_memfree_x( nattrs
.bv_val
, ctx
);
1245 Debug( LDAP_DEBUG_ACL
, "aciNormalizeRight: unknown attribute: '%s'\n", left
.bv_val
, 0, 0 );
1246 return LDAP_INVALID_SYNTAX
;
1251 len
= nattrs
.bv_len
+ ( !BER_BVISEMPTY( &nattrs
) ? STRLENOF( "," ) : 0 )
1252 + ad
->ad_cname
.bv_len
;
1253 nattrs
.bv_val
= ber_memrealloc_x( nattrs
.bv_val
, len
+ 1, ctx
);
1254 ptr
= &nattrs
.bv_val
[ nattrs
.bv_len
];
1255 if ( !BER_BVISEMPTY( &nattrs
) ) {
1258 ptr
= lutil_strncopy( ptr
, ad
->ad_cname
.bv_val
, ad
->ad_cname
.bv_len
);
1260 nattrs
.bv_len
= len
;
1265 naction
->bv_val
= ber_memrealloc_x( naction
->bv_val
,
1266 naction
->bv_len
+ STRLENOF( ";" )
1267 + perms
.bv_len
+ STRLENOF( ";" )
1268 + nattrs
.bv_len
+ 1,
1271 ptr
= &naction
->bv_val
[ naction
->bv_len
];
1274 ptr
= lutil_strncopy( ptr
, perms
.bv_val
, perms
.bv_len
);
1277 ptr
= lutil_strncopy( ptr
, nattrs
.bv_val
, nattrs
.bv_len
);
1279 naction
->bv_len
+= STRLENOF( ";" ) + perms
.bv_len
1280 + STRLENOF( ";" ) + nattrs
.bv_len
;
1282 ber_memfree_x( nattrs
.bv_val
, ctx
);
1287 /* perms;attr go in pairs */
1288 if ( i
> 1 && ( i
& 1 ) ) {
1289 return LDAP_SUCCESS
;
1292 Debug( LDAP_DEBUG_ACL
, "aciNormalizeRight: perms:attr need to be pairs in '%s'\n", action
->bv_val
, 0, 0 );
1293 return LDAP_INVALID_SYNTAX
;
1298 OpenLDAPaciValidateRights(
1299 struct berval
*actions
)
1302 struct berval bv
= BER_BVNULL
;
1305 for ( i
= 0; acl_get_part( actions
, i
, '$', &bv
) >= 0; i
++ ) {
1306 if ( OpenLDAPaciValidateRight( &bv
) != LDAP_SUCCESS
) {
1307 return LDAP_INVALID_SYNTAX
;
1311 return LDAP_SUCCESS
;
1315 OpenLDAPaciNormalizeRights(
1316 struct berval
*actions
,
1317 struct berval
*nactions
,
1321 struct berval bv
= BER_BVNULL
;
1324 BER_BVZERO( nactions
);
1325 for ( i
= 0; acl_get_part( actions
, i
, '$', &bv
) >= 0; i
++ ) {
1329 rc
= OpenLDAPaciNormalizeRight( &bv
, &nbv
, ctx
);
1330 if ( rc
!= LDAP_SUCCESS
) {
1331 ber_memfree_x( nactions
->bv_val
, ctx
);
1332 BER_BVZERO( nactions
);
1333 return LDAP_INVALID_SYNTAX
;
1340 nactions
->bv_val
= ber_memrealloc_x( nactions
->bv_val
,
1341 nactions
->bv_len
+ STRLENOF( "$" )
1344 nactions
->bv_val
[ nactions
->bv_len
] = '$';
1345 AC_MEMCPY( &nactions
->bv_val
[ nactions
->bv_len
+ 1 ],
1346 nbv
.bv_val
, nbv
.bv_len
+ 1 );
1347 ber_memfree_x( nbv
.bv_val
, ctx
);
1348 nactions
->bv_len
+= STRLENOF( "$" ) + nbv
.bv_len
;
1353 return LDAP_SUCCESS
;
1356 static const struct berval
*OpenLDAPaciscopes
[] = {
1357 &aci_bv
[ ACI_BV_ENTRY
],
1358 &aci_bv
[ ACI_BV_CHILDREN
],
1359 &aci_bv
[ ACI_BV_SUBTREE
],
1364 static const struct berval
*OpenLDAPacitypes
[] = {
1366 &aci_bv
[ ACI_BV_GROUP
],
1367 &aci_bv
[ ACI_BV_ROLE
],
1369 /* set to one past the last DN-valued type with options (/) */
1370 #define LAST_OPTIONAL 2
1372 &aci_bv
[ ACI_BV_ACCESS_ID
],
1373 &aci_bv
[ ACI_BV_SUBTREE
],
1374 &aci_bv
[ ACI_BV_ONELEVEL
],
1375 &aci_bv
[ ACI_BV_CHILDREN
],
1377 /* set to one past the last DN-valued type */
1378 #define LAST_DNVALUED 6
1381 &aci_bv
[ ACI_BV_DNATTR
],
1382 &aci_bv
[ ACI_BV_PUBLIC
],
1383 &aci_bv
[ ACI_BV_USERS
],
1384 &aci_bv
[ ACI_BV_SELF
],
1385 &aci_bv
[ ACI_BV_SET
],
1386 &aci_bv
[ ACI_BV_SET_REF
],
1392 OpenLDAPaciValidate(
1394 struct berval
*val
)
1396 struct berval oid
= BER_BVNULL
,
1398 rights
= BER_BVNULL
,
1400 subject
= BER_BVNULL
;
1404 if ( BER_BVISEMPTY( val
) ) {
1405 Debug( LDAP_DEBUG_ACL
, "aciValidatet: value is empty\n", 0, 0, 0 );
1406 return LDAP_INVALID_SYNTAX
;
1410 if ( acl_get_part( val
, 0, '#', &oid
) < 0 ||
1411 numericoidValidate( NULL
, &oid
) != LDAP_SUCCESS
)
1413 /* NOTE: the numericoidValidate() is rather pedantic;
1414 * I'd replace it with X-ORDERED VALUES so that
1415 * it's guaranteed values are maintained and used
1416 * in the desired order */
1417 Debug( LDAP_DEBUG_ACL
, "aciValidate: invalid oid '%s'\n", oid
.bv_val
, 0, 0 );
1418 return LDAP_INVALID_SYNTAX
;
1422 if ( acl_get_part( val
, 1, '#', &scope
) < 0 ||
1423 bv_getcaseidx( &scope
, OpenLDAPaciscopes
) == -1 )
1425 Debug( LDAP_DEBUG_ACL
, "aciValidate: invalid scope '%s'\n", scope
.bv_val
, 0, 0 );
1426 return LDAP_INVALID_SYNTAX
;
1430 if ( acl_get_part( val
, 2, '#', &rights
) < 0 ||
1431 OpenLDAPaciValidateRights( &rights
) != LDAP_SUCCESS
)
1433 return LDAP_INVALID_SYNTAX
;
1437 if ( acl_get_part( val
, 3, '#', &type
) < 0 ) {
1438 Debug( LDAP_DEBUG_ACL
, "aciValidate: missing type in '%s'\n", val
->bv_val
, 0, 0 );
1439 return LDAP_INVALID_SYNTAX
;
1441 idx
= bv_getcaseidx( &type
, OpenLDAPacitypes
);
1445 if ( acl_get_part( &type
, 0, '/', &isgr
) < 0 ) {
1446 Debug( LDAP_DEBUG_ACL
, "aciValidate: invalid type '%s'\n", type
.bv_val
, 0, 0 );
1447 return LDAP_INVALID_SYNTAX
;
1450 idx
= bv_getcaseidx( &isgr
, OpenLDAPacitypes
);
1451 if ( idx
== -1 || idx
>= LAST_OPTIONAL
) {
1452 Debug( LDAP_DEBUG_ACL
, "aciValidate: invalid type '%s'\n", isgr
.bv_val
, 0, 0 );
1453 return LDAP_INVALID_SYNTAX
;
1458 bv_get_tail( val
, &type
, &subject
);
1459 if ( subject
.bv_val
[ 0 ] != '#' ) {
1460 Debug( LDAP_DEBUG_ACL
, "aciValidate: missing subject in '%s'\n", val
->bv_val
, 0, 0 );
1461 return LDAP_INVALID_SYNTAX
;
1464 if ( idx
>= LAST_DNVALUED
) {
1465 if ( OpenLDAPacitypes
[ idx
] == &aci_bv
[ ACI_BV_DNATTR
] ) {
1466 AttributeDescription
*ad
= NULL
;
1467 const char *text
= NULL
;
1469 rc
= slap_bv2ad( &subject
, &ad
, &text
);
1470 if ( rc
!= LDAP_SUCCESS
) {
1471 Debug( LDAP_DEBUG_ACL
, "aciValidate: unknown dn attribute '%s'\n", subject
.bv_val
, 0, 0 );
1472 return LDAP_INVALID_SYNTAX
;
1475 if ( ad
->ad_type
->sat_syntax
!= slap_schema
.si_syn_distinguishedName
) {
1476 /* FIXME: allow nameAndOptionalUID? */
1477 Debug( LDAP_DEBUG_ACL
, "aciValidate: wrong syntax for dn attribute '%s'\n", subject
.bv_val
, 0, 0 );
1478 return LDAP_INVALID_SYNTAX
;
1483 return LDAP_SUCCESS
;
1485 } else if ( OpenLDAPacitypes
[ idx
] == &aci_bv
[ ACI_BV_GROUP
]
1486 || OpenLDAPacitypes
[ idx
] == &aci_bv
[ ACI_BV_ROLE
] )
1488 /* do {group|role}/oc/at check */
1489 struct berval ocbv
= BER_BVNULL
,
1492 ocbv
.bv_val
= ber_bvchr( &type
, '/' );
1493 if ( ocbv
.bv_val
!= NULL
) {
1495 ocbv
.bv_len
= type
.bv_len
1496 - ( ocbv
.bv_val
- type
.bv_val
);
1498 atbv
.bv_val
= ber_bvchr( &ocbv
, '/' );
1499 if ( atbv
.bv_val
!= NULL
) {
1500 AttributeDescription
*ad
= NULL
;
1501 const char *text
= NULL
;
1505 atbv
.bv_len
= type
.bv_len
1506 - ( atbv
.bv_val
- type
.bv_val
);
1507 ocbv
.bv_len
= atbv
.bv_val
- ocbv
.bv_val
- 1;
1509 rc
= slap_bv2ad( &atbv
, &ad
, &text
);
1510 if ( rc
!= LDAP_SUCCESS
) {
1511 Debug( LDAP_DEBUG_ACL
, "aciValidate: unknown group attribute '%s'\n", atbv
.bv_val
, 0, 0 );
1512 return LDAP_INVALID_SYNTAX
;
1516 if ( oc_bvfind( &ocbv
) == NULL
) {
1517 Debug( LDAP_DEBUG_ACL
, "aciValidate: unknown group '%s'\n", ocbv
.bv_val
, 0, 0 );
1518 return LDAP_INVALID_SYNTAX
;
1523 if ( BER_BVISEMPTY( &subject
) ) {
1524 /* empty DN invalid */
1525 Debug( LDAP_DEBUG_ACL
, "aciValidate: missing dn in '%s'\n", val
->bv_val
, 0, 0 );
1526 return LDAP_INVALID_SYNTAX
;
1532 /* FIXME: pass DN syntax? */
1533 rc
= dnValidate( NULL
, &subject
);
1534 if ( rc
!= LDAP_SUCCESS
) {
1535 Debug( LDAP_DEBUG_ACL
, "aciValidate: invalid dn '%s'\n", subject
.bv_val
, 0, 0 );
1541 OpenLDAPaciPrettyNormal(
1547 struct berval oid
= BER_BVNULL
,
1549 rights
= BER_BVNULL
,
1550 nrights
= BER_BVNULL
,
1553 subject
= BER_BVNULL
,
1554 nsubject
= BER_BVNULL
;
1563 if ( BER_BVISEMPTY( val
) ) {
1564 Debug( LDAP_DEBUG_ACL
, "aciPrettyNormal: value is empty\n", 0, 0, 0 );
1565 return LDAP_INVALID_SYNTAX
;
1568 /* oid: if valid, it's already normalized */
1569 if ( acl_get_part( val
, 0, '#', &oid
) < 0 ||
1570 numericoidValidate( NULL
, &oid
) != LDAP_SUCCESS
)
1572 Debug( LDAP_DEBUG_ACL
, "aciPrettyNormal: invalid oid '%s'\n", oid
.bv_val
, 0, 0 );
1573 return LDAP_INVALID_SYNTAX
;
1576 /* scope: normalize by replacing with OpenLDAPaciscopes */
1577 if ( acl_get_part( val
, 1, '#', &scope
) < 0 ) {
1578 Debug( LDAP_DEBUG_ACL
, "aciPrettyNormal: missing scope in '%s'\n", val
->bv_val
, 0, 0 );
1579 return LDAP_INVALID_SYNTAX
;
1581 idx
= bv_getcaseidx( &scope
, OpenLDAPaciscopes
);
1583 Debug( LDAP_DEBUG_ACL
, "aciPrettyNormal: invalid scope '%s'\n", scope
.bv_val
, 0, 0 );
1584 return LDAP_INVALID_SYNTAX
;
1586 scope
= *OpenLDAPaciscopes
[ idx
];
1589 if ( acl_get_part( val
, 2, '#', &rights
) < 0 ) {
1590 Debug( LDAP_DEBUG_ACL
, "aciPrettyNormal: missing rights in '%s'\n", val
->bv_val
, 0, 0 );
1591 return LDAP_INVALID_SYNTAX
;
1593 if ( OpenLDAPaciNormalizeRights( &rights
, &nrights
, ctx
)
1596 return LDAP_INVALID_SYNTAX
;
1600 if ( acl_get_part( val
, 3, '#', &type
) < 0 ) {
1601 Debug( LDAP_DEBUG_ACL
, "aciPrettyNormal: missing type in '%s'\n", val
->bv_val
, 0, 0 );
1602 rc
= LDAP_INVALID_SYNTAX
;
1605 idx
= bv_getcaseidx( &type
, OpenLDAPacitypes
);
1609 if ( acl_get_part( &type
, 0, '/', &isgr
) < 0 ) {
1610 Debug( LDAP_DEBUG_ACL
, "aciPrettyNormal: invalid type '%s'\n", type
.bv_val
, 0, 0 );
1611 rc
= LDAP_INVALID_SYNTAX
;
1615 idx
= bv_getcaseidx( &isgr
, OpenLDAPacitypes
);
1616 if ( idx
== -1 || idx
>= LAST_OPTIONAL
) {
1617 Debug( LDAP_DEBUG_ACL
, "aciPrettyNormal: invalid type '%s'\n", isgr
.bv_val
, 0, 0 );
1618 rc
= LDAP_INVALID_SYNTAX
;
1622 ntype
= *OpenLDAPacitypes
[ idx
];
1625 bv_get_tail( val
, &type
, &subject
);
1627 if ( BER_BVISEMPTY( &subject
) || subject
.bv_val
[ 0 ] != '#' ) {
1628 Debug( LDAP_DEBUG_ACL
, "aciPrettyNormal: missing subject in '%s'\n", val
->bv_val
, 0, 0 );
1629 rc
= LDAP_INVALID_SYNTAX
;
1636 if ( idx
< LAST_DNVALUED
) {
1637 /* FIXME: pass DN syntax? */
1639 rc
= dnNormalize( 0, NULL
, NULL
,
1640 &subject
, &nsubject
, ctx
);
1642 rc
= dnPretty( NULL
, &subject
, &nsubject
, ctx
);
1645 if ( rc
== LDAP_SUCCESS
) {
1649 Debug( LDAP_DEBUG_ACL
, "aciPrettyNormal: invalid subject dn '%s'\n", subject
.bv_val
, 0, 0 );
1653 if ( OpenLDAPacitypes
[ idx
] == &aci_bv
[ ACI_BV_GROUP
]
1654 || OpenLDAPacitypes
[ idx
] == &aci_bv
[ ACI_BV_ROLE
] )
1656 /* do {group|role}/oc/at check */
1657 struct berval ocbv
= BER_BVNULL
,
1660 ocbv
.bv_val
= ber_bvchr( &type
, '/' );
1661 if ( ocbv
.bv_val
!= NULL
) {
1662 ObjectClass
*oc
= NULL
;
1663 AttributeDescription
*ad
= NULL
;
1664 const char *text
= NULL
;
1668 bv
.bv_len
= ntype
.bv_len
;
1671 ocbv
.bv_len
= type
.bv_len
- ( ocbv
.bv_val
- type
.bv_val
);
1673 atbv
.bv_val
= ber_bvchr( &ocbv
, '/' );
1674 if ( atbv
.bv_val
!= NULL
) {
1676 atbv
.bv_len
= type
.bv_len
1677 - ( atbv
.bv_val
- type
.bv_val
);
1678 ocbv
.bv_len
= atbv
.bv_val
- ocbv
.bv_val
- 1;
1680 rc
= slap_bv2ad( &atbv
, &ad
, &text
);
1681 if ( rc
!= LDAP_SUCCESS
) {
1682 Debug( LDAP_DEBUG_ACL
, "aciPrettyNormal: unknown group attribute '%s'\n", atbv
.bv_val
, 0, 0 );
1683 rc
= LDAP_INVALID_SYNTAX
;
1687 bv
.bv_len
+= STRLENOF( "/" ) + ad
->ad_cname
.bv_len
;
1690 oc
= oc_bvfind( &ocbv
);
1692 Debug( LDAP_DEBUG_ACL
, "aciPrettyNormal: invalid group '%s'\n", ocbv
.bv_val
, 0, 0 );
1693 rc
= LDAP_INVALID_SYNTAX
;
1697 bv
.bv_len
+= STRLENOF( "/" ) + oc
->soc_cname
.bv_len
;
1698 bv
.bv_val
= ber_memalloc_x( bv
.bv_len
+ 1, ctx
);
1701 ptr
= lutil_strncopy( ptr
, ntype
.bv_val
, ntype
.bv_len
);
1704 ptr
= lutil_strncopy( ptr
,
1705 oc
->soc_cname
.bv_val
,
1706 oc
->soc_cname
.bv_len
);
1710 ptr
= lutil_strncopy( ptr
,
1711 ad
->ad_cname
.bv_val
,
1712 ad
->ad_cname
.bv_len
);
1721 } else if ( OpenLDAPacitypes
[ idx
] == &aci_bv
[ ACI_BV_DNATTR
] ) {
1722 AttributeDescription
*ad
= NULL
;
1723 const char *text
= NULL
;
1726 rc
= slap_bv2ad( &subject
, &ad
, &text
);
1727 if ( rc
!= LDAP_SUCCESS
) {
1728 Debug( LDAP_DEBUG_ACL
, "aciPrettyNormal: unknown dn attribute '%s'\n", subject
.bv_val
, 0, 0 );
1729 rc
= LDAP_INVALID_SYNTAX
;
1733 if ( ad
->ad_type
->sat_syntax
!= slap_schema
.si_syn_distinguishedName
) {
1734 /* FIXME: allow nameAndOptionalUID? */
1735 Debug( LDAP_DEBUG_ACL
, "aciPrettyNormal: wrong syntax for dn attribute '%s'\n", subject
.bv_val
, 0, 0 );
1736 rc
= LDAP_INVALID_SYNTAX
;
1740 nsubject
= ad
->ad_cname
;
1745 oid
.bv_len
+ STRLENOF( "#" )
1746 + scope
.bv_len
+ STRLENOF( "#" )
1747 + nrights
.bv_len
+ STRLENOF( "#" )
1748 + ntype
.bv_len
+ STRLENOF( "#" )
1751 out
->bv_val
= ber_memalloc_x( out
->bv_len
+ 1, ctx
);
1752 ptr
= lutil_strncopy( out
->bv_val
, oid
.bv_val
, oid
.bv_len
);
1755 ptr
= lutil_strncopy( ptr
, scope
.bv_val
, scope
.bv_len
);
1758 ptr
= lutil_strncopy( ptr
, nrights
.bv_val
, nrights
.bv_len
);
1761 ptr
= lutil_strncopy( ptr
, ntype
.bv_val
, ntype
.bv_len
);
1764 if ( !BER_BVISNULL( &nsubject
) ) {
1765 ptr
= lutil_strncopy( ptr
, nsubject
.bv_val
, nsubject
.bv_len
);
1770 if ( freesubject
) {
1771 ber_memfree_x( nsubject
.bv_val
, ctx
);
1775 ber_memfree_x( ntype
.bv_val
, ctx
);
1778 if ( !BER_BVISNULL( &nrights
) ) {
1779 ber_memfree_x( nrights
.bv_val
, ctx
);
1792 return OpenLDAPaciPrettyNormal( val
, out
, ctx
, 0 );
1796 OpenLDAPaciNormalize(
1804 return OpenLDAPaciPrettyNormal( val
, out
, ctx
, 1 );
1807 #if SLAPD_ACI_ENABLED == SLAPD_MOD_DYNAMIC
1809 * FIXME: need config and Makefile.am code to ease building
1813 init_module( int argc
, char *argv
[] )
1815 return dynacl_aci_init();
1817 #endif /* SLAPD_ACI_ENABLED == SLAPD_MOD_DYNAMIC */
1819 #endif /* SLAPD_ACI_ENABLED */