1 /* aclparse.c - routines to parse and check acl's */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2024 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.
33 #include <ac/socket.h>
34 #include <ac/string.h>
35 #include <ac/unistd.h>
40 #include "slap-config.h"
42 static const char style_base
[] = "base";
43 const char *style_strings
[] = {
61 #define ACLBUF_CHUNKSIZE 8192
62 static struct berval aclbuf
;
64 static void split(char *line
, int splitchar
, char **left
, char **right
);
65 static void access_append(Access
**l
, Access
*a
);
66 static void access_free( Access
*a
);
67 static int acl_usage(void);
69 static void acl_regex_normalized_dn(const char *src
, struct berval
*pat
);
72 static void print_acl(Backend
*be
, AccessControl
*a
);
75 static int check_scope( BackendDB
*be
, AccessControl
*a
);
80 struct config_args_s
*c
,
87 slap_dynacl_t
*da
, *tmp
;
90 for ( da
= b
->a_dynacl
; da
; da
= da
->da_next
) {
91 if ( strcasecmp( da
->da_name
, name
) == 0 ) {
92 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
93 "dynacl \"%s\" already specified",
95 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
100 da
= slap_dynacl_get( name
);
105 tmp
= ch_malloc( sizeof( slap_dynacl_t
) );
108 if ( tmp
->da_parse
) {
109 rc
= ( *tmp
->da_parse
)( c
, opts
, sty
, right
, &tmp
->da_private
);
116 tmp
->da_next
= b
->a_dynacl
;
121 #endif /* SLAP_DYNACL */
124 regtest(struct config_args_s
*c
, char *pat
) {
128 char buf
[ SLAP_TEXT_BUFLEN
];
140 for (size
= 0, flag
= 0; (size
< sizeof(buf
)) && *sp
; sp
++) {
142 if (*sp
== '$'|| (*sp
>= '0' && *sp
<= '9')) {
159 if ( size
>= (sizeof(buf
) - 1) ) {
160 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
161 "regular expression too large \"%s\"", pat
);
162 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
167 if ( (e
= regcomp(&re
, buf
, REG_EXTENDED
|REG_ICASE
)) ) {
168 char error
[ SLAP_TEXT_BUFLEN
];
170 regerror(e
, &re
, error
, sizeof(error
));
172 snprintf( c
->cr_msg
, sizeof ( c
->cr_msg
),
173 "regular expression \"%s\" bad because of %s", pat
, error
);
174 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
186 * Check if the pattern of an ACL, if any, matches the scope
187 * of the backend it is defined within.
189 #define ACL_SCOPE_UNKNOWN (-2)
190 #define ACL_SCOPE_ERR (-1)
191 #define ACL_SCOPE_OK (0)
192 #define ACL_SCOPE_PARTIAL (1)
193 #define ACL_SCOPE_WARN (2)
196 check_scope( BackendDB
*be
, AccessControl
*a
)
201 dn
= be
->be_nsuffix
[0];
203 if ( BER_BVISEMPTY( &dn
) ) {
207 if ( !BER_BVISEMPTY( &a
->acl_dn_pat
) ||
208 a
->acl_dn_style
!= ACL_STYLE_REGEX
)
210 slap_style_t style
= a
->acl_dn_style
;
212 if ( style
== ACL_STYLE_REGEX
) {
213 char dnbuf
[SLAP_LDAPDN_MAXLEN
+ 2];
214 char rebuf
[SLAP_LDAPDN_MAXLEN
+ 1];
219 /* add trailing '$' to database suffix to form
220 * a simple trial regex pattern "<suffix>$" */
221 AC_MEMCPY( dnbuf
, be
->be_nsuffix
[0].bv_val
,
222 be
->be_nsuffix
[0].bv_len
);
223 dnbuf
[be
->be_nsuffix
[0].bv_len
] = '$';
224 dnbuf
[be
->be_nsuffix
[0].bv_len
+ 1] = '\0';
226 if ( regcomp( &re
, dnbuf
, REG_EXTENDED
|REG_ICASE
) ) {
227 return ACL_SCOPE_WARN
;
230 /* remove trailing ')$', if any, from original
232 rebuflen
= a
->acl_dn_pat
.bv_len
;
233 AC_MEMCPY( rebuf
, a
->acl_dn_pat
.bv_val
, rebuflen
+ 1 );
234 if ( rebuf
[rebuflen
- 1] == '$' ) {
235 rebuf
[--rebuflen
] = '\0';
237 while ( rebuflen
> be
->be_nsuffix
[0].bv_len
&& rebuf
[rebuflen
- 1] == ')' ) {
238 rebuf
[--rebuflen
] = '\0';
240 if ( rebuflen
== be
->be_nsuffix
[0].bv_len
) {
245 /* not a clear indication of scoping error, though */
246 rc
= regexec( &re
, rebuf
, 0, NULL
, 0 )
247 ? ACL_SCOPE_WARN
: ACL_SCOPE_OK
;
254 patlen
= a
->acl_dn_pat
.bv_len
;
255 /* If backend suffix is longer than pattern,
256 * it is a potential mismatch (in the sense
257 * that a superior naming context could
259 if ( dn
.bv_len
> patlen
) {
260 /* base is blatantly wrong */
261 if ( style
== ACL_STYLE_BASE
) return ACL_SCOPE_ERR
;
263 /* a style of one can be wrong if there is
264 * more than one level between the suffix
266 if ( style
== ACL_STYLE_ONE
) {
267 ber_len_t rdnlen
= 0;
271 if ( !DN_SEPARATOR( dn
.bv_val
[dn
.bv_len
- patlen
- 1] )) {
272 return ACL_SCOPE_ERR
;
277 rdnlen
= dn_rdnlen( NULL
, &dn
);
278 if ( rdnlen
!= dn
.bv_len
- patlen
- sep
)
279 return ACL_SCOPE_ERR
;
282 /* if the trailing part doesn't match,
283 * then it's an error */
284 if ( strcmp( a
->acl_dn_pat
.bv_val
,
285 &dn
.bv_val
[dn
.bv_len
- patlen
] ) != 0 )
287 return ACL_SCOPE_ERR
;
290 return ACL_SCOPE_PARTIAL
;
296 case ACL_STYLE_CHILDREN
:
297 case ACL_STYLE_SUBTREE
:
305 if ( dn
.bv_len
< patlen
&&
306 !DN_SEPARATOR( a
->acl_dn_pat
.bv_val
[patlen
- dn
.bv_len
- 1] ))
308 return ACL_SCOPE_ERR
;
311 if ( strcmp( &a
->acl_dn_pat
.bv_val
[patlen
- dn
.bv_len
], dn
.bv_val
)
314 return ACL_SCOPE_ERR
;
320 return ACL_SCOPE_UNKNOWN
;
325 struct config_args_s
*c
,
329 char *left
, *right
, *style
;
331 AccessControl
*a
= NULL
;
336 const char *fname
= c
->fname
;
337 int lineno
= c
->lineno
;
339 char **argv
= c
->argv
;
341 for ( i
= 1; i
< argc
; i
++ ) {
342 /* to clause - select which entries are protected */
343 if ( strcasecmp( argv
[i
], "to" ) == 0 ) {
345 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
346 "only one to clause allowed in access line" );
347 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
350 a
= (AccessControl
*) ch_calloc( 1, sizeof(AccessControl
) );
351 a
->acl_attrval_style
= ACL_STYLE_NONE
;
352 for ( ++i
; i
< argc
; i
++ ) {
353 if ( strcasecmp( argv
[i
], "by" ) == 0 ) {
358 if ( strcasecmp( argv
[i
], "*" ) == 0 ) {
359 if ( !BER_BVISEMPTY( &a
->acl_dn_pat
) ||
360 a
->acl_dn_style
!= ACL_STYLE_REGEX
)
362 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
363 "dn pattern already specified in to clause." );
364 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
368 ber_str2bv( "*", STRLENOF( "*" ), 1, &a
->acl_dn_pat
);
372 split( argv
[i
], '=', &left
, &right
);
373 split( left
, '.', &left
, &style
);
375 if ( right
== NULL
) {
376 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
377 "missing \"=\" in \"%s\" in to clause", left
);
378 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
382 if ( strcasecmp( left
, "dn" ) == 0 ) {
383 if ( !BER_BVISEMPTY( &a
->acl_dn_pat
) ||
384 a
->acl_dn_style
!= ACL_STYLE_REGEX
)
386 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
387 "dn pattern already specified in to clause" );
388 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
392 if ( style
== NULL
|| *style
== '\0' ||
393 strcasecmp( style
, "baseObject" ) == 0 ||
394 strcasecmp( style
, "base" ) == 0 ||
395 strcasecmp( style
, "exact" ) == 0 )
397 a
->acl_dn_style
= ACL_STYLE_BASE
;
398 ber_str2bv( right
, 0, 1, &a
->acl_dn_pat
);
400 } else if ( strcasecmp( style
, "oneLevel" ) == 0 ||
401 strcasecmp( style
, "one" ) == 0 )
403 a
->acl_dn_style
= ACL_STYLE_ONE
;
404 ber_str2bv( right
, 0, 1, &a
->acl_dn_pat
);
406 } else if ( strcasecmp( style
, "subtree" ) == 0 ||
407 strcasecmp( style
, "sub" ) == 0 )
409 if( *right
== '\0' ) {
410 ber_str2bv( "*", STRLENOF( "*" ), 1, &a
->acl_dn_pat
);
413 a
->acl_dn_style
= ACL_STYLE_SUBTREE
;
414 ber_str2bv( right
, 0, 1, &a
->acl_dn_pat
);
417 } else if ( strcasecmp( style
, "children" ) == 0 ) {
418 a
->acl_dn_style
= ACL_STYLE_CHILDREN
;
419 ber_str2bv( right
, 0, 1, &a
->acl_dn_pat
);
421 } else if ( strcasecmp( style
, "regex" ) == 0 ) {
422 a
->acl_dn_style
= ACL_STYLE_REGEX
;
424 if ( *right
== '\0' ) {
425 /* empty regex should match empty DN */
426 a
->acl_dn_style
= ACL_STYLE_BASE
;
427 ber_str2bv( right
, 0, 1, &a
->acl_dn_pat
);
429 } else if ( strcmp(right
, "*") == 0
430 || strcmp(right
, ".*") == 0
431 || strcmp(right
, ".*$") == 0
432 || strcmp(right
, "^.*") == 0
433 || strcmp(right
, "^.*$") == 0
434 || strcmp(right
, ".*$$") == 0
435 || strcmp(right
, "^.*$$") == 0 )
437 ber_str2bv( "*", STRLENOF("*"), 1, &a
->acl_dn_pat
);
440 acl_regex_normalized_dn( right
, &a
->acl_dn_pat
);
444 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
445 "unknown dn style \"%s\" in to clause", style
);
446 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
453 if ( strcasecmp( left
, "filter" ) == 0 ) {
454 if ( (a
->acl_filter
= str2filter( right
)) == NULL
) {
455 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
456 "bad filter \"%s\" in to clause", right
);
457 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
461 } else if ( strcasecmp( left
, "attr" ) == 0 /* TOLERATED */
462 || strcasecmp( left
, "attrs" ) == 0 ) /* DOCUMENTED */
464 if ( strcasecmp( left
, "attr" ) == 0 ) {
465 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
466 "\"attr\" is deprecated (and undocumented); "
467 "use \"attrs\" instead");
468 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
471 a
->acl_attrs
= str2anlist( a
->acl_attrs
,
473 if ( a
->acl_attrs
== NULL
) {
474 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
475 "unknown attr \"%s\" in to clause", right
);
476 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
480 } else if ( strncasecmp( left
, "val", 3 ) == 0 ) {
484 if ( !BER_BVISEMPTY( &a
->acl_attrval
) ) {
485 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
486 "attr val already specified in to clause" );
487 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
490 if ( a
->acl_attrs
== NULL
|| !BER_BVISEMPTY( &a
->acl_attrs
[1].an_name
) )
492 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
493 "attr val requires a single attribute");
494 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
498 ber_str2bv( right
, 0, 0, &bv
);
499 a
->acl_attrval_style
= ACL_STYLE_BASE
;
501 mr
= strchr( left
, '/' );
506 a
->acl_attrval_mr
= mr_find( mr
);
507 if ( a
->acl_attrval_mr
== NULL
) {
508 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
509 "invalid matching rule \"%s\"", mr
);
510 Debug( LDAP_DEBUG_ANY
, "%s: %s\n", c
->log
, c
->cr_msg
);
514 if( !mr_usable_with_at( a
->acl_attrval_mr
, a
->acl_attrs
[ 0 ].an_desc
->ad_type
) )
516 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
517 "matching rule \"%s\" use " "with attr \"%s\" not appropriate",
519 a
->acl_attrs
[0].an_name
.bv_val
);
520 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
-> log
, c
->cr_msg
);
525 if ( style
!= NULL
) {
526 if ( strcasecmp( style
, "regex" ) == 0 ) {
527 int e
= regcomp( &a
->acl_attrval_re
, bv
.bv_val
,
528 REG_EXTENDED
| REG_ICASE
);
530 char err
[SLAP_TEXT_BUFLEN
];
532 regerror( e
, &a
->acl_attrval_re
, err
, sizeof( err
) );
533 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
534 "regular expression \"%s\" bad because of %s",
536 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
539 a
->acl_attrval_style
= ACL_STYLE_REGEX
;
542 /* FIXME: if the attribute has DN syntax, we might
543 * allow one, subtree and children styles as well */
544 if ( !strcasecmp( style
, "base" ) ||
545 !strcasecmp( style
, "exact" ) ) {
546 a
->acl_attrval_style
= ACL_STYLE_BASE
;
548 } else if ( a
->acl_attrs
[0].an_desc
->ad_type
->
549 sat_syntax
== slap_schema
.si_syn_distinguishedName
)
551 if ( !strcasecmp( style
, "baseObject" ) ||
552 !strcasecmp( style
, "base" ) )
554 a
->acl_attrval_style
= ACL_STYLE_BASE
;
555 } else if ( !strcasecmp( style
, "onelevel" ) ||
556 !strcasecmp( style
, "one" ) )
558 a
->acl_attrval_style
= ACL_STYLE_ONE
;
559 } else if ( !strcasecmp( style
, "subtree" ) ||
560 !strcasecmp( style
, "sub" ) )
562 a
->acl_attrval_style
= ACL_STYLE_SUBTREE
;
563 } else if ( !strcasecmp( style
, "children" ) ) {
564 a
->acl_attrval_style
= ACL_STYLE_CHILDREN
;
566 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
567 "unknown val.<style> \"%s\" for attributeType \"%s\" " "with DN syntax",
569 a
->acl_attrs
[0].an_desc
->ad_cname
.bv_val
);
570 Debug( LDAP_DEBUG_CONFIG
| LDAP_DEBUG_ACL
, "%s: %s.\n", c
->log
, c
->cr_msg
);
574 rc
= dnNormalize( 0, NULL
, NULL
, &bv
, &a
->acl_attrval
, NULL
);
575 if ( rc
!= LDAP_SUCCESS
) {
576 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
577 "unable to normalize DN \"%s\" " "for attributeType \"%s\" (%d)",
579 a
->acl_attrs
[0].an_desc
->ad_cname
.bv_val
,
581 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
586 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
587 "unknown val.<style> \"%s\" for attributeType \"%s\"",
589 a
->acl_attrs
[0].an_desc
->ad_cname
.bv_val
);
590 Debug( LDAP_DEBUG_CONFIG
| LDAP_DEBUG_ACL
, "%s: %s.\n", c
->log
, c
->cr_msg
);
596 /* Check for appropriate matching rule */
597 if ( a
->acl_attrval_style
== ACL_STYLE_REGEX
) {
598 ber_dupbv( &a
->acl_attrval
, &bv
);
600 } else if ( BER_BVISNULL( &a
->acl_attrval
) ) {
604 if ( a
->acl_attrval_mr
== NULL
) {
605 a
->acl_attrval_mr
= a
->acl_attrs
[ 0 ].an_desc
->ad_type
->sat_equality
;
608 if ( a
->acl_attrval_mr
== NULL
) {
609 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
610 "attr \"%s\" does not have an EQUALITY matching rule",
611 a
->acl_attrs
[ 0 ].an_name
.bv_val
);
612 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
616 rc
= asserted_value_validate_normalize(
617 a
->acl_attrs
[ 0 ].an_desc
,
619 SLAP_MR_EQUALITY
|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
,
624 if ( rc
!= LDAP_SUCCESS
) {
625 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
626 "attr \"%s\" normalization failed (%d: %s).\n",
627 a
->acl_attrs
[0].an_name
.bv_val
,
629 Debug(LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
635 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
636 "expecting <what> got \"%s\"",
638 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
643 if ( !BER_BVISNULL( &a
->acl_dn_pat
) &&
644 ber_bvccmp( &a
->acl_dn_pat
, '*' ) )
646 free( a
->acl_dn_pat
.bv_val
);
647 BER_BVZERO( &a
->acl_dn_pat
);
648 a
->acl_dn_style
= ACL_STYLE_REGEX
;
651 if ( !BER_BVISEMPTY( &a
->acl_dn_pat
) ||
652 a
->acl_dn_style
!= ACL_STYLE_REGEX
)
654 if ( a
->acl_dn_style
!= ACL_STYLE_REGEX
) {
656 rc
= dnNormalize( 0, NULL
, NULL
, &a
->acl_dn_pat
, &bv
, NULL
);
657 if ( rc
!= LDAP_SUCCESS
) {
658 snprintf( c
->cr_msg
, sizeof(c
->cr_msg
),
659 "bad DN \"%s\" in to DN clause",
660 a
->acl_dn_pat
.bv_val
);
661 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
664 free( a
->acl_dn_pat
.bv_val
);
668 int e
= regcomp( &a
->acl_dn_re
, a
->acl_dn_pat
.bv_val
,
669 REG_EXTENDED
| REG_ICASE
);
671 char err
[ SLAP_TEXT_BUFLEN
];
673 regerror( e
, &a
->acl_dn_re
, err
, sizeof( err
) );
674 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
675 "regular expression \"%s\" bad because of %s",
677 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
683 /* by clause - select who has what access to entries */
684 } else if ( strcasecmp( argv
[i
], "by" ) == 0 ) {
686 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
687 "to clause required before by clause in access line");
688 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
693 * by clause consists of <who> and <access>
697 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
698 "premature EOL: expecting <who>");
699 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
703 b
= (Access
*) ch_calloc( 1, sizeof(Access
) );
705 ACL_INVALIDATE( b
->a_access_mask
);
708 for ( ; i
< argc
; i
++ ) {
709 slap_style_t sty
= ACL_STYLE_REGEX
;
710 char *style_modifier
= NULL
;
711 char *style_level
= NULL
;
714 slap_dn_access
*bdn
= &b
->a_dn
;
717 split( argv
[i
], '=', &left
, &right
);
718 split( left
, '.', &left
, &style
);
720 split( style
, ',', &style
, &style_modifier
);
722 if ( strncasecmp( style
, "level", STRLENOF( "level" ) ) == 0 ) {
723 split( style
, '{', &style
, &style_level
);
724 if ( style_level
!= NULL
) {
725 char *p
= strchr( style_level
, '}' );
727 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
728 "premature eol: expecting closing '}' in \"level{n}\"");
729 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
731 } else if ( p
== style_level
) {
732 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
733 "empty level in \"level{n}\"");
734 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
742 if ( style
== NULL
|| *style
== '\0' ||
743 strcasecmp( style
, "exact" ) == 0 ||
744 strcasecmp( style
, "baseObject" ) == 0 ||
745 strcasecmp( style
, "base" ) == 0 )
747 sty
= ACL_STYLE_BASE
;
749 } else if ( strcasecmp( style
, "onelevel" ) == 0 ||
750 strcasecmp( style
, "one" ) == 0 )
754 } else if ( strcasecmp( style
, "subtree" ) == 0 ||
755 strcasecmp( style
, "sub" ) == 0 )
757 sty
= ACL_STYLE_SUBTREE
;
759 } else if ( strcasecmp( style
, "children" ) == 0 ) {
760 sty
= ACL_STYLE_CHILDREN
;
762 } else if ( strcasecmp( style
, "level" ) == 0 )
764 if ( lutil_atoi( &level
, style_level
) != 0 ) {
765 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
766 "unable to parse level in \"level{n}\"");
767 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
771 sty
= ACL_STYLE_LEVEL
;
773 } else if ( strcasecmp( style
, "regex" ) == 0 ) {
774 sty
= ACL_STYLE_REGEX
;
776 } else if ( strcasecmp( style
, "expand" ) == 0 ) {
777 sty
= ACL_STYLE_EXPAND
;
779 } else if ( strcasecmp( style
, "ip" ) == 0 ) {
782 } else if ( strcasecmp( style
, "ipv6" ) == 0 ) {
783 #ifndef LDAP_PF_INET6
784 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
785 "IPv6 not supported");
786 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
787 #endif /* ! LDAP_PF_INET6 */
788 sty
= ACL_STYLE_IPV6
;
790 } else if ( strcasecmp( style
, "path" ) == 0 ) {
791 sty
= ACL_STYLE_PATH
;
792 #ifndef LDAP_PF_LOCAL
793 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
794 "\"path\" style modifier is useless without local");
795 Debug( LDAP_DEBUG_CONFIG
| LDAP_DEBUG_ACL
, "%s: %s.\n", c
->log
, c
->cr_msg
);
797 #endif /* LDAP_PF_LOCAL */
800 snprintf( c
->cr_msg
, sizeof ( c
->cr_msg
),
801 "unknown style \"%s\" in by clause", style
);
802 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
806 if ( style_modifier
&&
807 strcasecmp( style_modifier
, "expand" ) == 0 )
810 case ACL_STYLE_REGEX
:
811 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
812 "\"regex\" style implies \"expand\" modifier" );
813 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
817 case ACL_STYLE_EXPAND
:
821 /* we'll see later if it's pertinent */
827 if ( strncasecmp( left
, "real", STRLENOF( "real" ) ) == 0 ) {
830 left
+= STRLENOF( "real" );
833 if ( strcasecmp( left
, "*" ) == 0 ) {
838 ber_str2bv( "*", STRLENOF( "*" ), 1, &bv
);
839 sty
= ACL_STYLE_REGEX
;
841 } else if ( strcasecmp( left
, "anonymous" ) == 0 ) {
842 ber_str2bv("anonymous", STRLENOF( "anonymous" ), 1, &bv
);
843 sty
= ACL_STYLE_ANONYMOUS
;
845 } else if ( strcasecmp( left
, "users" ) == 0 ) {
846 ber_str2bv("users", STRLENOF( "users" ), 1, &bv
);
847 sty
= ACL_STYLE_USERS
;
849 } else if ( strcasecmp( left
, "self" ) == 0 ) {
850 ber_str2bv("self", STRLENOF( "self" ), 1, &bv
);
851 sty
= ACL_STYLE_SELF
;
853 } else if ( strcasecmp( left
, "dn" ) == 0 ) {
854 if ( sty
== ACL_STYLE_REGEX
) {
855 bdn
->a_style
= ACL_STYLE_REGEX
;
856 if ( right
== NULL
) {
861 bdn
->a_style
= ACL_STYLE_USERS
;
863 } else if (*right
== '\0' ) {
865 ber_str2bv("anonymous",
866 STRLENOF( "anonymous" ),
868 bdn
->a_style
= ACL_STYLE_ANONYMOUS
;
870 } else if ( strcmp( right
, "*" ) == 0 ) {
872 /* any or users? users for now */
876 bdn
->a_style
= ACL_STYLE_USERS
;
878 } else if ( strcmp( right
, ".+" ) == 0
879 || strcmp( right
, "^.+" ) == 0
880 || strcmp( right
, ".+$" ) == 0
881 || strcmp( right
, "^.+$" ) == 0
882 || strcmp( right
, ".+$$" ) == 0
883 || strcmp( right
, "^.+$$" ) == 0 )
888 bdn
->a_style
= ACL_STYLE_USERS
;
890 } else if ( strcmp( right
, ".*" ) == 0
891 || strcmp( right
, "^.*" ) == 0
892 || strcmp( right
, ".*$" ) == 0
893 || strcmp( right
, "^.*$" ) == 0
894 || strcmp( right
, ".*$$" ) == 0
895 || strcmp( right
, "^.*$$" ) == 0 )
902 acl_regex_normalized_dn( right
, &bv
);
903 if ( !ber_bvccmp( &bv
, '*' ) ) {
904 if ( regtest( c
, bv
.bv_val
) != 0)
909 } else if ( right
== NULL
|| *right
== '\0' ) {
910 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
911 "missing \"=\" in (or value after) \"%s\" in by clause", left
);
912 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
916 ber_str2bv( right
, 0, 1, &bv
);
923 if ( !BER_BVISNULL( &bv
) ) {
924 if ( !BER_BVISEMPTY( &bdn
->a_pat
) ) {
925 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
926 "dn pattern already specified" );
927 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
931 if ( sty
!= ACL_STYLE_REGEX
&&
932 sty
!= ACL_STYLE_ANONYMOUS
&&
933 sty
!= ACL_STYLE_USERS
&&
934 sty
!= ACL_STYLE_SELF
&&
937 rc
= dnNormalize(0, NULL
, NULL
,
938 &bv
, &bdn
->a_pat
, NULL
);
939 if ( rc
!= LDAP_SUCCESS
) {
940 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
941 "bad DN \"%s\" in by DN clause", bv
.bv_val
);
942 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
946 if ( sty
== ACL_STYLE_BASE
948 && !BER_BVISNULL( &be
->be_rootndn
)
949 && dn_match( &bdn
->a_pat
, &be
->be_rootndn
) )
951 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
952 "rootdn is always granted unlimited privileges" );
953 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
964 for ( exp
= strchr( bdn
->a_pat
.bv_val
, '$' );
965 exp
&& (ber_len_t
)(exp
- bdn
->a_pat
.bv_val
)
967 exp
= strchr( exp
, '$' ) )
969 if ( ( isdigit( (unsigned char) exp
[ 1 ] ) ||
970 exp
[ 1 ] == '{' ) ) {
977 bdn
->a_expand
= expand
;
980 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
981 "\"expand\" used with no expansions in \"pattern\"");
982 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
986 if ( sty
== ACL_STYLE_SELF
) {
987 bdn
->a_self_level
= level
;
991 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
992 "bad negative level \"%d\" in by DN clause", level
);
993 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
995 } else if ( level
== 1 ) {
996 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
997 "\"onelevel\" should be used instead of \"level{1}\" in by DN clause" );
998 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
999 } else if ( level
== 0 && sty
== ACL_STYLE_LEVEL
) {
1000 snprintf ( c
->cr_msg
, sizeof( c
->cr_msg
),
1001 "\"base\" should be used instead of \"level{0}\" in by DN clause" );
1002 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1005 bdn
->a_level
= level
;
1010 if ( strcasecmp( left
, "dnattr" ) == 0 ) {
1011 if ( right
== NULL
|| right
[0] == '\0' ) {
1012 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1013 "missing \"=\" in (or value after) \"%s\" in by clause", left
);
1014 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1018 if( bdn
->a_at
!= NULL
) {
1019 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1020 "dnattr already specified" );
1021 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1025 rc
= slap_str2ad( right
, &bdn
->a_at
, &text
);
1027 if( rc
!= LDAP_SUCCESS
) {
1028 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1029 "dnattr \"%s\": %s", right
, text
);
1030 Debug(LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1035 if( !is_at_syntax( bdn
->a_at
->ad_type
,
1036 SLAPD_DN_SYNTAX
) &&
1037 !is_at_syntax( bdn
->a_at
->ad_type
,
1038 SLAPD_NAMEUID_SYNTAX
))
1040 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1041 "dnattr \"%s\": " "inappropriate syntax: %s",
1042 right
, bdn
->a_at
->ad_type
->sat_syntax_oid
);
1043 Debug(LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1047 if( bdn
->a_at
->ad_type
->sat_equality
== NULL
) {
1048 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1049 "dnattr \"%s\": inappropriate matching (no EQUALITY)", right
);
1050 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1057 if ( strncasecmp( left
, "group", STRLENOF( "group" ) ) == 0 ) {
1060 char *attr_name
= SLAPD_GROUP_ATTR
;
1063 case ACL_STYLE_REGEX
:
1064 /* legacy, tolerated */
1065 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1066 "deprecated group style \"regex\"; use \"expand\" instead" );
1067 Debug( LDAP_DEBUG_CONFIG
| LDAP_DEBUG_ACL
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1068 sty
= ACL_STYLE_EXPAND
;
1071 case ACL_STYLE_BASE
:
1072 /* legal, traditional */
1073 case ACL_STYLE_EXPAND
:
1074 /* legal, substring expansion; supersedes regex */
1079 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1080 "inappropriate style \"%s\" in by clause", style
);
1081 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1085 if ( right
== NULL
|| right
[0] == '\0' ) {
1086 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1087 "missing \"=\" in (or value after) \"%s\" in by clause", left
);
1088 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1092 if ( !BER_BVISEMPTY( &b
->a_group_pat
) ) {
1093 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1094 "group pattern already specified" );
1095 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1099 /* format of string is
1100 "group/objectClassValue/groupAttrName" */
1101 if ( ( value
= strchr(left
, '/') ) != NULL
) {
1103 if ( *value
&& ( name
= strchr( value
, '/' ) ) != NULL
) {
1108 b
->a_group_style
= sty
;
1109 if ( sty
== ACL_STYLE_EXPAND
) {
1110 acl_regex_normalized_dn( right
, &bv
);
1111 if ( !ber_bvccmp( &bv
, '*' ) ) {
1112 if ( regtest( c
, bv
.bv_val
) != 0)
1115 b
->a_group_pat
= bv
;
1118 ber_str2bv( right
, 0, 0, &bv
);
1119 rc
= dnNormalize( 0, NULL
, NULL
, &bv
,
1120 &b
->a_group_pat
, NULL
);
1121 if ( rc
!= LDAP_SUCCESS
) {
1122 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1123 "bad DN \"%s\"", right
);
1124 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1129 if ( value
&& *value
) {
1130 b
->a_group_oc
= oc_find( value
);
1133 if ( b
->a_group_oc
== NULL
) {
1134 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1135 "group objectclass \"%s\" unknown", value
);
1136 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1141 b
->a_group_oc
= oc_find( SLAPD_GROUP_CLASS
);
1143 if( b
->a_group_oc
== NULL
) {
1144 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1145 "group default objectclass \"%s\" unknown", SLAPD_GROUP_CLASS
);
1146 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1151 if ( is_object_subclass( slap_schema
.si_oc_referral
,
1154 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1155 "group objectclass \"%s\" is subclass of referral", value
);
1156 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1160 if ( is_object_subclass( slap_schema
.si_oc_alias
,
1163 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1164 "group objectclass \"%s\" is subclass of alias", value
);
1165 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1169 if ( name
&& *name
) {
1175 rc
= slap_str2ad( attr_name
, &b
->a_group_at
, &text
);
1176 if ( rc
!= LDAP_SUCCESS
) {
1177 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1178 "group \"%s\": %s", right
, text
);
1179 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1183 if ( !is_at_syntax( b
->a_group_at
->ad_type
,
1184 SLAPD_DN_SYNTAX
) /* e.g. "member" */
1185 && !is_at_syntax( b
->a_group_at
->ad_type
,
1186 SLAPD_NAMEUID_SYNTAX
) /* e.g. memberUID */
1187 && !is_at_subtype( b
->a_group_at
->ad_type
,
1188 slap_schema
.si_ad_labeledURI
->ad_type
) /* e.g. memberURL */ )
1190 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1191 "group \"%s\" attr \"%s\": inappropriate syntax: %s; " "must be " SLAPD_DN_SYNTAX
" (DN), " SLAPD_NAMEUID_SYNTAX
" (NameUID) " "or a subtype of labeledURI",
1192 right
, attr_name
, at_syntax(b
->a_group_at
->ad_type
) );
1193 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1200 ObjectClass
*ocs
[2];
1202 ocs
[0] = b
->a_group_oc
;
1205 rc
= oc_check_allowed( b
->a_group_at
->ad_type
,
1209 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1210 "group: \"%s\" not allowed by \"%s\".\n",
1211 b
->a_group_at
->ad_cname
.bv_val
,
1212 b
->a_group_oc
->soc_oid
);
1213 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1220 if ( strcasecmp( left
, "peername" ) == 0 ) {
1222 case ACL_STYLE_REGEX
:
1223 case ACL_STYLE_BASE
:
1224 /* legal, traditional */
1225 case ACL_STYLE_EXPAND
:
1226 /* cheap replacement to regex for simple expansion */
1228 case ACL_STYLE_IPV6
:
1229 case ACL_STYLE_PATH
:
1230 /* legal, peername specific */
1234 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1235 "inappropriate style \"%s\" in by clause", style
);
1236 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1240 if ( right
== NULL
|| right
[0] == '\0' ) {
1241 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1242 "missing \"=\" in (or value after) \"%s\" in by clause", left
);
1243 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1247 if ( !BER_BVISEMPTY( &b
->a_peername_pat
) ) {
1248 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1249 "peername pattern already specified" );
1250 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1254 b
->a_peername_style
= sty
;
1255 if ( sty
== ACL_STYLE_REGEX
) {
1256 acl_regex_normalized_dn( right
, &bv
);
1257 if ( !ber_bvccmp( &bv
, '*' ) ) {
1258 if ( regtest( c
, bv
.bv_val
) != 0)
1261 b
->a_peername_pat
= bv
;
1264 ber_str2bv( right
, 0, 1, &b
->a_peername_pat
);
1266 if ( sty
== ACL_STYLE_IP
) {
1271 split( right
, '{', &addr
, &port
);
1272 split( addr
, '%', &addr
, &mask
);
1274 b
->a_peername_addr
= inet_addr( addr
);
1275 if ( b
->a_peername_addr
== (unsigned long)(-1) ) {
1276 /* illegal address */
1277 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1278 "illegal peername address \"%s\"", addr
);
1279 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1283 b
->a_peername_mask
= (unsigned long)(-1);
1284 if ( mask
!= NULL
) {
1285 b
->a_peername_mask
= inet_addr( mask
);
1286 if ( b
->a_peername_mask
==
1287 (unsigned long)(-1) )
1290 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1291 "illegal peername address mask \"%s\"", mask
);
1292 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1297 b
->a_peername_port
= -1;
1301 b
->a_peername_port
= strtol( port
, &end
, 10 );
1302 if ( end
== port
|| end
[0] != '}' ) {
1304 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1305 "illegal peername port specification \"{%s}\"", port
);
1306 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1311 #ifdef LDAP_PF_INET6
1312 } else if ( sty
== ACL_STYLE_IPV6
) {
1317 split( right
, '{', &addr
, &port
);
1318 split( addr
, '%', &addr
, &mask
);
1320 if ( inet_pton( AF_INET6
, addr
, &b
->a_peername_addr6
) != 1 ) {
1321 /* illegal address */
1322 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1323 "illegal peername address \"%s\"", addr
);
1324 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1328 if ( mask
== NULL
) {
1329 mask
= "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF";
1332 if ( inet_pton( AF_INET6
, mask
, &b
->a_peername_mask6
) != 1 ) {
1334 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1335 "illegal peername address mask \"%s\"", mask
);
1336 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1340 b
->a_peername_port
= -1;
1344 b
->a_peername_port
= strtol( port
, &end
, 10 );
1345 if ( end
== port
|| end
[0] != '}' ) {
1347 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1348 "illegal peername port specification \"{%s}\"", port
);
1349 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1353 #endif /* LDAP_PF_INET6 */
1359 if ( strcasecmp( left
, "sockname" ) == 0 ) {
1361 case ACL_STYLE_REGEX
:
1362 case ACL_STYLE_BASE
:
1363 /* legal, traditional */
1364 case ACL_STYLE_EXPAND
:
1365 /* cheap replacement to regex for simple expansion */
1370 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1371 "inappropriate style \"%s\" in by clause", style
);
1372 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1376 if ( right
== NULL
|| right
[0] == '\0' ) {
1377 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1378 "missing \"=\" in (or value after) \"%s\" in by clause", left
);
1379 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1383 if ( !BER_BVISNULL( &b
->a_sockname_pat
) ) {
1384 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1385 "sockname pattern already specified" );
1386 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1390 b
->a_sockname_style
= sty
;
1391 if ( sty
== ACL_STYLE_REGEX
) {
1392 acl_regex_normalized_dn( right
, &bv
);
1393 if ( !ber_bvccmp( &bv
, '*' ) ) {
1394 if ( regtest( c
, bv
.bv_val
) != 0)
1397 b
->a_sockname_pat
= bv
;
1400 ber_str2bv( right
, 0, 1, &b
->a_sockname_pat
);
1405 if ( strcasecmp( left
, "domain" ) == 0 ) {
1407 case ACL_STYLE_REGEX
:
1408 case ACL_STYLE_BASE
:
1409 case ACL_STYLE_SUBTREE
:
1410 /* legal, traditional */
1413 case ACL_STYLE_EXPAND
:
1414 /* tolerated: means exact,expand */
1416 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1417 "\"expand\" modifier with \"expand\" style" );
1418 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1420 sty
= ACL_STYLE_BASE
;
1426 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1427 "inappropriate style \"%s\" in by clause", style
);
1428 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1432 if ( right
== NULL
|| right
[0] == '\0' ) {
1433 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1434 "missing \"=\" in (or value after) \"%s\" in by clause", left
);
1435 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1439 if ( !BER_BVISEMPTY( &b
->a_domain_pat
) ) {
1440 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1441 "domain pattern already specified" );
1442 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1446 b
->a_domain_style
= sty
;
1447 b
->a_domain_expand
= expand
;
1448 if ( sty
== ACL_STYLE_REGEX
) {
1449 acl_regex_normalized_dn( right
, &bv
);
1450 if ( !ber_bvccmp( &bv
, '*' ) ) {
1451 if ( regtest( c
, bv
.bv_val
) != 0)
1454 b
->a_domain_pat
= bv
;
1457 ber_str2bv( right
, 0, 1, &b
->a_domain_pat
);
1462 if ( strcasecmp( left
, "sockurl" ) == 0 ) {
1464 case ACL_STYLE_REGEX
:
1465 case ACL_STYLE_BASE
:
1466 /* legal, traditional */
1467 case ACL_STYLE_EXPAND
:
1468 /* cheap replacement to regex for simple expansion */
1473 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1474 "inappropriate style \"%s\" in by clause", style
);
1475 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1479 if ( right
== NULL
|| right
[0] == '\0' ) {
1480 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1481 "missing \"=\" in (or value after) \"%s\" in by clause", left
);
1482 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1486 if ( !BER_BVISEMPTY( &b
->a_sockurl_pat
) ) {
1487 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1488 "sockurl pattern already specified" );
1489 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1493 b
->a_sockurl_style
= sty
;
1494 if ( sty
== ACL_STYLE_REGEX
) {
1495 acl_regex_normalized_dn( right
, &bv
);
1496 if ( !ber_bvccmp( &bv
, '*' ) ) {
1497 if ( regtest( c
, bv
.bv_val
) != 0)
1500 b
->a_sockurl_pat
= bv
;
1503 ber_str2bv( right
, 0, 1, &b
->a_sockurl_pat
);
1508 if ( strcasecmp( left
, "set" ) == 0 ) {
1511 case ACL_STYLE_REGEX
:
1512 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1513 "deprecated set style "
1514 "\"regex\" in <by> clause; "
1515 "use \"expand\" instead" );
1516 Debug( LDAP_DEBUG_CONFIG
| LDAP_DEBUG_ACL
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1517 sty
= ACL_STYLE_EXPAND
;
1520 case ACL_STYLE_BASE
:
1521 case ACL_STYLE_EXPAND
:
1525 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1526 "inappropriate style \"%s\" in by clause", style
);
1527 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1531 if ( !BER_BVISEMPTY( &b
->a_set_pat
) ) {
1532 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1533 "set attribute already specified" );
1534 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1538 if ( right
== NULL
|| *right
== '\0' ) {
1539 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1540 "no set is defined" );
1541 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1545 b
->a_set_style
= sty
;
1546 ber_str2bv( right
, 0, 1, &b
->a_set_pat
);
1556 #if 1 /* tolerate legacy "aci" <who> */
1557 if ( strcasecmp( left
, "aci" ) == 0 ) {
1558 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1559 "undocumented deprecated \"aci\" directive "
1560 "is superseded by \"dynacl/aci\"" );
1561 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1565 #endif /* tolerate legacy "aci" <who> */
1566 if ( strncasecmp( left
, "dynacl/", STRLENOF( "dynacl/" ) ) == 0 ) {
1567 name
= &left
[ STRLENOF( "dynacl/" ) ];
1568 opts
= strchr( name
, '/' );
1576 if ( slap_dynacl_config( c
, b
, name
, opts
, sty
, right
) ) {
1577 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1578 "unable to configure dynacl \"%s\"", name
);
1579 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1586 #endif /* SLAP_DYNACL */
1588 if ( strcasecmp( left
, "ssf" ) == 0 ) {
1589 if ( sty
!= ACL_STYLE_REGEX
&& sty
!= ACL_STYLE_BASE
) {
1590 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1591 "inappropriate style \"%s\" in by clause", style
);
1592 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1596 if ( b
->a_authz
.sai_ssf
) {
1597 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1598 "ssf attribute already specified" );
1599 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1603 if ( right
== NULL
|| *right
== '\0' ) {
1604 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1605 "no ssf is defined" );
1606 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1610 if ( lutil_atou( &b
->a_authz
.sai_ssf
, right
) != 0 ) {
1611 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1612 "unable to parse ssf value (%s)", right
);
1613 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1617 if ( !b
->a_authz
.sai_ssf
) {
1618 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1619 "invalid ssf value (%s)", right
);
1620 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1626 if ( strcasecmp( left
, "transport_ssf" ) == 0 ) {
1627 if ( sty
!= ACL_STYLE_REGEX
&& sty
!= ACL_STYLE_BASE
) {
1628 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1629 "inappropriate style \"%s\" in by clause", style
);
1630 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1634 if ( b
->a_authz
.sai_transport_ssf
) {
1635 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1636 "transport_ssf attribute already specified" );
1637 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1641 if ( right
== NULL
|| *right
== '\0' ) {
1642 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1643 "no transport_ssf is defined" );
1644 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1648 if ( lutil_atou( &b
->a_authz
.sai_transport_ssf
, right
) != 0 ) {
1649 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1650 "unable to parse transport_ssf value (%s)", right
);
1651 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1655 if ( !b
->a_authz
.sai_transport_ssf
) {
1656 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1657 "invalid transport_ssf value (%s)", right
);
1658 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1664 if ( strcasecmp( left
, "tls_ssf" ) == 0 ) {
1665 if ( sty
!= ACL_STYLE_REGEX
&& sty
!= ACL_STYLE_BASE
) {
1666 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1667 "inappropriate style \"%s\" in by clause", style
);
1668 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1672 if ( b
->a_authz
.sai_tls_ssf
) {
1673 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1674 "tls_ssf attribute already specified" );
1678 if ( right
== NULL
|| *right
== '\0' ) {
1679 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1680 "no tls_ssf is defined" );
1681 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1685 if ( lutil_atou( &b
->a_authz
.sai_tls_ssf
, right
) != 0 ) {
1686 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1687 "unable to parse tls_ssf value (%s)", right
);
1688 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1692 if ( !b
->a_authz
.sai_tls_ssf
) {
1693 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1694 "invalid tls_ssf value (%s)", right
);
1695 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1701 if ( strcasecmp( left
, "sasl_ssf" ) == 0 ) {
1702 if ( sty
!= ACL_STYLE_REGEX
&& sty
!= ACL_STYLE_BASE
) {
1703 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1704 "inappropriate style \"%s\" in by clause", style
);
1705 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1709 if ( b
->a_authz
.sai_sasl_ssf
) {
1710 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1711 "sasl_ssf attribute already specified" );
1712 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1716 if ( right
== NULL
|| *right
== '\0' ) {
1717 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1718 "no sasl_ssf is defined" );
1719 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1723 if ( lutil_atou( &b
->a_authz
.sai_sasl_ssf
, right
) != 0 ) {
1724 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1725 "unable to parse sasl_ssf value (%s)", right
);
1726 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1730 if ( !b
->a_authz
.sai_sasl_ssf
) {
1731 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1732 "invalid sasl_ssf value (%s)", right
);
1733 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1739 if ( right
!= NULL
) {
1746 if ( i
== argc
|| ( strcasecmp( left
, "stop" ) == 0 ) ) {
1747 /* out of arguments or plain stop */
1749 ACL_PRIV_ASSIGN( b
->a_access_mask
, ACL_PRIV_ADDITIVE
);
1750 ACL_PRIV_SET( b
->a_access_mask
, ACL_PRIV_NONE
);
1751 b
->a_type
= ACL_STOP
;
1753 access_append( &a
->acl_access
, b
);
1757 if ( strcasecmp( left
, "continue" ) == 0 ) {
1758 /* plain continue */
1760 ACL_PRIV_ASSIGN( b
->a_access_mask
, ACL_PRIV_ADDITIVE
);
1761 ACL_PRIV_SET( b
->a_access_mask
, ACL_PRIV_NONE
);
1762 b
->a_type
= ACL_CONTINUE
;
1764 access_append( &a
->acl_access
, b
);
1768 if ( strcasecmp( left
, "break" ) == 0 ) {
1769 /* plain continue */
1771 ACL_PRIV_ASSIGN(b
->a_access_mask
, ACL_PRIV_ADDITIVE
);
1772 ACL_PRIV_SET( b
->a_access_mask
, ACL_PRIV_NONE
);
1773 b
->a_type
= ACL_BREAK
;
1775 access_append( &a
->acl_access
, b
);
1779 if ( strcasecmp( left
, "by" ) == 0 ) {
1780 /* we've gone too far */
1782 ACL_PRIV_ASSIGN( b
->a_access_mask
, ACL_PRIV_ADDITIVE
);
1783 ACL_PRIV_SET( b
->a_access_mask
, ACL_PRIV_NONE
);
1784 b
->a_type
= ACL_STOP
;
1786 access_append( &a
->acl_access
, b
);
1794 if ( strncasecmp( left
, "self", STRLENOF( "self" ) ) == 0 ) {
1796 lleft
= &left
[ STRLENOF( "self" ) ];
1798 } else if ( strncasecmp( left
, "realself", STRLENOF( "realself" ) ) == 0 ) {
1799 b
->a_realdn_self
= 1;
1800 lleft
= &left
[ STRLENOF( "realself" ) ];
1803 ACL_PRIV_ASSIGN( b
->a_access_mask
, str2accessmask( lleft
) );
1806 if ( ACL_IS_INVALID( b
->a_access_mask
) ) {
1807 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1808 "expecting <access> got \"%s\"", left
);
1809 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1813 b
->a_type
= ACL_STOP
;
1815 if ( ++i
== argc
) {
1816 /* out of arguments or plain stop */
1817 access_append( &a
->acl_access
, b
);
1821 if ( strcasecmp( argv
[i
], "continue" ) == 0 ) {
1822 /* plain continue */
1823 b
->a_type
= ACL_CONTINUE
;
1825 } else if ( strcasecmp( argv
[i
], "break" ) == 0 ) {
1826 /* plain continue */
1827 b
->a_type
= ACL_BREAK
;
1829 } else if ( strcasecmp( argv
[i
], "stop" ) != 0 ) {
1834 access_append( &a
->acl_access
, b
);
1838 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1839 "expecting \"to\" or \"by\" got \"%s\"", argv
[i
] );
1840 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1845 /* if we have no real access clause, complain and do nothing */
1847 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1848 "warning: no access clause(s) specified in access line");
1849 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1854 if ( slap_debug
& LDAP_DEBUG_ACL
) {
1859 if ( a
->acl_access
== NULL
) {
1860 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1861 "warning: no by clause(s) specified in access line" );
1862 Debug( LDAP_DEBUG_ANY
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1867 if ( be
->be_nsuffix
== NULL
) {
1868 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1869 "warning: scope checking needs suffix before ACLs" );
1870 Debug( LDAP_DEBUG_ACL
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1871 /* go ahead, since checking is not authoritative */
1872 } else if ( !BER_BVISNULL( &be
->be_nsuffix
[ 1 ] ) ) {
1873 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1874 "warning: scope checking only applies to single-valued suffix databases" );
1875 Debug( LDAP_DEBUG_ACL
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1876 /* go ahead, since checking is not authoritative */
1878 switch ( check_scope( be
, a
) ) {
1879 case ACL_SCOPE_UNKNOWN
:
1880 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1881 "warning: cannot assess the validity of the ACL scope within backend naming context" );
1882 Debug( LDAP_DEBUG_ACL
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1885 case ACL_SCOPE_WARN
:
1886 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1887 "warning: ACL could be out of scope within backend naming context" );
1888 Debug( LDAP_DEBUG_ACL
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1891 case ACL_SCOPE_PARTIAL
:
1892 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1893 "warning: ACL appears to be partially out of scope within backend naming context" );
1894 Debug( LDAP_DEBUG_ACL
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1898 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
1899 "warning: ACL appears to be out of scope within backend naming context" );
1900 Debug( LDAP_DEBUG_ACL
, "%s: %s.\n", c
->log
, c
->cr_msg
);
1907 acl_append( &be
->be_acl
, a
, pos
);
1910 acl_append( &frontendDB
->be_acl
, a
, pos
);
1917 if ( b
) access_free( b
);
1918 if ( a
) acl_free( a
);
1923 accessmask2str( slap_mask_t mask
, char *buf
, int debug
)
1928 assert( buf
!= NULL
);
1930 if ( ACL_IS_INVALID( mask
) ) {
1936 if ( ACL_IS_LEVEL( mask
) ) {
1937 if ( ACL_LVL_IS_NONE(mask
) ) {
1938 ptr
= lutil_strcopy( ptr
, "none" );
1940 } else if ( ACL_LVL_IS_DISCLOSE(mask
) ) {
1941 ptr
= lutil_strcopy( ptr
, "disclose" );
1943 } else if ( ACL_LVL_IS_AUTH(mask
) ) {
1944 ptr
= lutil_strcopy( ptr
, "auth" );
1946 } else if ( ACL_LVL_IS_COMPARE(mask
) ) {
1947 ptr
= lutil_strcopy( ptr
, "compare" );
1949 } else if ( ACL_LVL_IS_SEARCH(mask
) ) {
1950 ptr
= lutil_strcopy( ptr
, "search" );
1952 } else if ( ACL_LVL_IS_READ(mask
) ) {
1953 ptr
= lutil_strcopy( ptr
, "read" );
1955 } else if ( ACL_LVL_IS_WRITE(mask
) ) {
1956 ptr
= lutil_strcopy( ptr
, "write" );
1958 } else if ( ACL_LVL_IS_WADD(mask
) ) {
1959 ptr
= lutil_strcopy( ptr
, "add" );
1961 } else if ( ACL_LVL_IS_WDEL(mask
) ) {
1962 ptr
= lutil_strcopy( ptr
, "delete" );
1964 } else if ( ACL_LVL_IS_MANAGE(mask
) ) {
1965 ptr
= lutil_strcopy( ptr
, "manage" );
1968 ptr
= lutil_strcopy( ptr
, "unknown" );
1978 if( ACL_IS_ADDITIVE( mask
) ) {
1981 } else if( ACL_IS_SUBTRACTIVE( mask
) ) {
1988 if ( ACL_PRIV_ISSET(mask
, ACL_PRIV_MANAGE
) ) {
1993 if ( ACL_PRIV_ISSET(mask
, ACL_PRIV_WRITE
) ) {
1997 } else if ( ACL_PRIV_ISSET(mask
, ACL_PRIV_WADD
) ) {
2001 } else if ( ACL_PRIV_ISSET(mask
, ACL_PRIV_WDEL
) ) {
2006 if ( ACL_PRIV_ISSET(mask
, ACL_PRIV_READ
) ) {
2011 if ( ACL_PRIV_ISSET(mask
, ACL_PRIV_SEARCH
) ) {
2016 if ( ACL_PRIV_ISSET(mask
, ACL_PRIV_COMPARE
) ) {
2021 if ( ACL_PRIV_ISSET(mask
, ACL_PRIV_AUTH
) ) {
2026 if ( ACL_PRIV_ISSET(mask
, ACL_PRIV_DISCLOSE
) ) {
2031 if ( none
&& ACL_PRIV_ISSET(mask
, ACL_PRIV_NONE
) ) {
2040 if ( ACL_IS_LEVEL( mask
) ) {
2050 str2accessmask( const char *str
)
2054 if( !ASCII_ALPHA(str
[0]) ) {
2057 if ( str
[0] == '=' ) {
2060 } else if( str
[0] == '+' ) {
2061 ACL_PRIV_ASSIGN(mask
, ACL_PRIV_ADDITIVE
);
2063 } else if( str
[0] == '-' ) {
2064 ACL_PRIV_ASSIGN(mask
, ACL_PRIV_SUBSTRACTIVE
);
2067 ACL_INVALIDATE(mask
);
2071 for( i
=1; str
[i
] != '\0'; i
++ ) {
2072 if( TOLOWER((unsigned char) str
[i
]) == 'm' ) {
2073 ACL_PRIV_SET(mask
, ACL_PRIV_MANAGE
);
2075 } else if( TOLOWER((unsigned char) str
[i
]) == 'w' ) {
2076 ACL_PRIV_SET(mask
, ACL_PRIV_WRITE
);
2078 } else if( TOLOWER((unsigned char) str
[i
]) == 'a' ) {
2079 ACL_PRIV_SET(mask
, ACL_PRIV_WADD
);
2081 } else if( TOLOWER((unsigned char) str
[i
]) == 'z' ) {
2082 ACL_PRIV_SET(mask
, ACL_PRIV_WDEL
);
2084 } else if( TOLOWER((unsigned char) str
[i
]) == 'r' ) {
2085 ACL_PRIV_SET(mask
, ACL_PRIV_READ
);
2087 } else if( TOLOWER((unsigned char) str
[i
]) == 's' ) {
2088 ACL_PRIV_SET(mask
, ACL_PRIV_SEARCH
);
2090 } else if( TOLOWER((unsigned char) str
[i
]) == 'c' ) {
2091 ACL_PRIV_SET(mask
, ACL_PRIV_COMPARE
);
2093 } else if( TOLOWER((unsigned char) str
[i
]) == 'x' ) {
2094 ACL_PRIV_SET(mask
, ACL_PRIV_AUTH
);
2096 } else if( TOLOWER((unsigned char) str
[i
]) == 'd' ) {
2097 ACL_PRIV_SET(mask
, ACL_PRIV_DISCLOSE
);
2099 } else if( str
[i
] == '0' ) {
2100 ACL_PRIV_SET(mask
, ACL_PRIV_NONE
);
2103 ACL_INVALIDATE(mask
);
2111 if ( strcasecmp( str
, "none" ) == 0 ) {
2112 ACL_LVL_ASSIGN_NONE(mask
);
2114 } else if ( strcasecmp( str
, "disclose" ) == 0 ) {
2115 ACL_LVL_ASSIGN_DISCLOSE(mask
);
2117 } else if ( strcasecmp( str
, "auth" ) == 0 ) {
2118 ACL_LVL_ASSIGN_AUTH(mask
);
2120 } else if ( strcasecmp( str
, "compare" ) == 0 ) {
2121 ACL_LVL_ASSIGN_COMPARE(mask
);
2123 } else if ( strcasecmp( str
, "search" ) == 0 ) {
2124 ACL_LVL_ASSIGN_SEARCH(mask
);
2126 } else if ( strcasecmp( str
, "read" ) == 0 ) {
2127 ACL_LVL_ASSIGN_READ(mask
);
2129 } else if ( strcasecmp( str
, "add" ) == 0 ) {
2130 ACL_LVL_ASSIGN_WADD(mask
);
2132 } else if ( strcasecmp( str
, "delete" ) == 0 ) {
2133 ACL_LVL_ASSIGN_WDEL(mask
);
2135 } else if ( strcasecmp( str
, "write" ) == 0 ) {
2136 ACL_LVL_ASSIGN_WRITE(mask
);
2138 } else if ( strcasecmp( str
, "manage" ) == 0 ) {
2139 ACL_LVL_ASSIGN_MANAGE(mask
);
2142 ACL_INVALIDATE( mask
);
2152 "<access clause> ::= access to <what> "
2153 "[ by <who> [ <access> ] [ <control> ] ]+ \n";
2155 "<what> ::= * | dn[.<dnstyle>=<DN>] [filter=<filter>] [attrs=<attrspec>]\n"
2156 "<attrspec> ::= <attrname> [val[/<matchingRule>][.<attrstyle>]=<value>] | <attrlist>\n"
2157 "<attrlist> ::= <attr> [ , <attrlist> ]\n"
2158 "<attr> ::= <attrname> | @<objectClass> | !<objectClass> | entry | children\n";
2161 "<who> ::= [ * | anonymous | users | self | dn[.<dnstyle>]=<DN> ]\n"
2162 "\t[ realanonymous | realusers | realself | realdn[.<dnstyle>]=<DN> ]\n"
2163 "\t[dnattr=<attrname>]\n"
2164 "\t[realdnattr=<attrname>]\n"
2165 "\t[group[/<objectclass>[/<attrname>]][.<style>]=<group>]\n"
2166 "\t[peername[.<peernamestyle>]=<peer>] [sockname[.<style>]=<name>]\n"
2167 "\t[domain[.<domainstyle>]=<domain>] [sockurl[.<style>]=<url>]\n"
2169 "\t[dynacl/<name>[/<options>][.<dynstyle>][=<pattern>]]\n"
2170 #endif /* SLAP_DYNACL */
2171 "\t[ssf=<n>] [transport_ssf=<n>] [tls_ssf=<n>] [sasl_ssf=<n>]\n"
2172 "<style> ::= exact | regex | base(Object)\n"
2173 "<dnstyle> ::= base(Object) | one(level) | sub(tree) | children | "
2175 "<attrstyle> ::= exact | regex | base(Object) | one(level) | "
2176 "sub(tree) | children\n"
2177 "<peernamestyle> ::= exact | regex | ip | ipv6 | path\n"
2178 "<domainstyle> ::= exact | regex | base(Object) | sub(tree)\n"
2179 "<access> ::= [[real]self]{<level>|<priv>}\n"
2180 "<level> ::= none|disclose|auth|compare|search|read|{write|add|delete}|manage\n"
2181 "<priv> ::= {=|+|-}{0|d|x|c|s|r|{w|a|z}|m}+\n"
2182 "<control> ::= [ stop | continue | break ]\n"
2184 #ifdef SLAPD_ACI_ENABLED
2186 "\t<name>=ACI\t<pattern>=<attrname>\n"
2187 #endif /* SLAPD_ACI_ENABLED */
2188 #endif /* ! SLAP_DYNACL */
2191 Debug( LDAP_DEBUG_ANY
, "%s%s%s\n", access
, what
, who
);
2197 * Set pattern to a "normalized" DN from src.
2198 * At present, it simply eats the (optional) space after
2199 * a RDN separator (,)
2200 * Eventually will evolve in a more complete normalization
2203 acl_regex_normalized_dn(
2205 struct berval
*pattern
)
2210 str
= ch_strdup( src
);
2211 len
= strlen( src
);
2213 for ( p
= str
; p
&& p
[0]; p
++ ) {
2215 if ( p
[0] == '\\' && p
[1] ) {
2217 * if escaping a hex pair we should
2218 * increment p twice; however, in that
2219 * case the second hex number does
2225 if ( p
[0] == ',' && p
[1] == ' ' ) {
2229 * too much space should be an error if we are pedantic
2231 for ( q
= &p
[2]; q
[0] == ' '; q
++ ) {
2234 AC_MEMCPY( p
+1, q
, len
-(q
-str
)+1);
2237 pattern
->bv_val
= str
;
2238 pattern
->bv_len
= p
- str
;
2251 if ( (*right
= strchr( line
, splitchar
)) != NULL
) {
2252 *((*right
)++) = '\0';
2257 access_append( Access
**l
, Access
*a
)
2259 for ( ; *l
!= NULL
; l
= &(*l
)->a_next
) {
2267 acl_append( AccessControl
**l
, AccessControl
*a
, int pos
)
2271 for (i
=0 ; i
!= pos
&& *l
!= NULL
; l
= &(*l
)->acl_next
, i
++ ) {
2280 access_free( Access
*a
)
2282 if ( !BER_BVISNULL( &a
->a_dn_pat
) ) {
2283 free( a
->a_dn_pat
.bv_val
);
2285 if ( !BER_BVISNULL( &a
->a_realdn_pat
) ) {
2286 free( a
->a_realdn_pat
.bv_val
);
2288 if ( !BER_BVISNULL( &a
->a_peername_pat
) ) {
2289 free( a
->a_peername_pat
.bv_val
);
2291 if ( !BER_BVISNULL( &a
->a_sockname_pat
) ) {
2292 free( a
->a_sockname_pat
.bv_val
);
2294 if ( !BER_BVISNULL( &a
->a_domain_pat
) ) {
2295 free( a
->a_domain_pat
.bv_val
);
2297 if ( !BER_BVISNULL( &a
->a_sockurl_pat
) ) {
2298 free( a
->a_sockurl_pat
.bv_val
);
2300 if ( !BER_BVISNULL( &a
->a_set_pat
) ) {
2301 free( a
->a_set_pat
.bv_val
);
2303 if ( !BER_BVISNULL( &a
->a_group_pat
) ) {
2304 free( a
->a_group_pat
.bv_val
);
2307 if ( a
->a_dynacl
!= NULL
) {
2309 for ( da
= a
->a_dynacl
; da
; ) {
2310 slap_dynacl_t
*tmp
= da
;
2314 if ( tmp
->da_destroy
) {
2315 tmp
->da_destroy( tmp
->da_private
);
2321 #endif /* SLAP_DYNACL */
2326 acl_free( AccessControl
*a
)
2331 if ( a
->acl_filter
) {
2332 filter_free( a
->acl_filter
);
2334 if ( !BER_BVISNULL( &a
->acl_dn_pat
) ) {
2335 if ( a
->acl_dn_style
== ACL_STYLE_REGEX
) {
2336 regfree( &a
->acl_dn_re
);
2338 free ( a
->acl_dn_pat
.bv_val
);
2340 if ( a
->acl_attrs
) {
2341 for ( an
= a
->acl_attrs
; !BER_BVISNULL( &an
->an_name
); an
++ ) {
2342 free( an
->an_name
.bv_val
);
2344 free( a
->acl_attrs
);
2346 if ( a
->acl_attrval_style
== ACL_STYLE_REGEX
) {
2347 regfree( &a
->acl_attrval_re
);
2350 if ( !BER_BVISNULL( &a
->acl_attrval
) ) {
2351 ber_memfree( a
->acl_attrval
.bv_val
);
2354 for ( ; a
->acl_access
; a
->acl_access
= n
) {
2355 n
= a
->acl_access
->a_next
;
2356 access_free( a
->acl_access
);
2362 acl_destroy( AccessControl
*a
)
2366 for ( ; a
; a
= n
) {
2371 if ( !BER_BVISNULL( &aclbuf
) ) {
2372 ch_free( aclbuf
.bv_val
);
2373 BER_BVZERO( &aclbuf
);
2378 access2str( slap_access_t access
)
2380 if ( access
== ACL_NONE
) {
2383 } else if ( access
== ACL_DISCLOSE
) {
2386 } else if ( access
== ACL_AUTH
) {
2389 } else if ( access
== ACL_COMPARE
) {
2392 } else if ( access
== ACL_SEARCH
) {
2395 } else if ( access
== ACL_READ
) {
2398 } else if ( access
== ACL_WRITE
) {
2401 } else if ( access
== ACL_WADD
) {
2404 } else if ( access
== ACL_WDEL
) {
2407 } else if ( access
== ACL_MANAGE
) {
2416 str2access( const char *str
)
2418 if ( strcasecmp( str
, "none" ) == 0 ) {
2421 } else if ( strcasecmp( str
, "disclose" ) == 0 ) {
2422 return ACL_DISCLOSE
;
2424 } else if ( strcasecmp( str
, "auth" ) == 0 ) {
2427 } else if ( strcasecmp( str
, "compare" ) == 0 ) {
2430 } else if ( strcasecmp( str
, "search" ) == 0 ) {
2433 } else if ( strcasecmp( str
, "read" ) == 0 ) {
2436 } else if ( strcasecmp( str
, "write" ) == 0 ) {
2439 } else if ( strcasecmp( str
, "add" ) == 0 ) {
2442 } else if ( strcasecmp( str
, "delete" ) == 0 ) {
2445 } else if ( strcasecmp( str
, "manage" ) == 0 ) {
2449 return( ACL_INVALID_ACCESS
);
2453 safe_strncopy( char *ptr
, const char *src
, size_t n
, struct berval
*buf
)
2455 while ( ptr
+ n
>= buf
->bv_val
+ buf
->bv_len
) {
2456 char *tmp
= ch_realloc( buf
->bv_val
, 2*buf
->bv_len
);
2457 if ( tmp
== NULL
) {
2460 ptr
= tmp
+ (ptr
- buf
->bv_val
);
2465 return lutil_strncopy( ptr
, src
, n
);
2469 safe_strcopy( char *ptr
, const char *s
, struct berval
*buf
)
2471 size_t n
= strlen( s
);
2473 return safe_strncopy( ptr
, s
, n
, buf
);
2477 safe_strbvcopy( char *ptr
, const struct berval
*bv
, struct berval
*buf
)
2479 return safe_strncopy( ptr
, bv
->bv_val
, bv
->bv_len
, buf
);
2482 #define acl_safe_strcopy( ptr, s ) safe_strcopy( (ptr), (s), &aclbuf )
2483 #define acl_safe_strncopy( ptr, s, n ) safe_strncopy( (ptr), (s), (n), &aclbuf )
2484 #define acl_safe_strbvcopy( ptr, bv ) safe_strbvcopy( (ptr), (bv), &aclbuf )
2487 dnaccess2text( slap_dn_access
*bdn
, char *ptr
, int is_realdn
)
2492 ptr
= acl_safe_strcopy( ptr
, "real" );
2495 if ( ber_bvccmp( &bdn
->a_pat
, '*' ) ||
2496 bdn
->a_style
== ACL_STYLE_ANONYMOUS
||
2497 bdn
->a_style
== ACL_STYLE_USERS
||
2498 bdn
->a_style
== ACL_STYLE_SELF
)
2501 assert( ! ber_bvccmp( &bdn
->a_pat
, '*' ) );
2504 ptr
= acl_safe_strbvcopy( ptr
, &bdn
->a_pat
);
2505 if ( bdn
->a_style
== ACL_STYLE_SELF
&& bdn
->a_self_level
!= 0 ) {
2506 char buf
[SLAP_TEXT_BUFLEN
];
2507 int n
= snprintf( buf
, sizeof(buf
), ".level{%d}", bdn
->a_self_level
);
2509 ptr
= acl_safe_strncopy( ptr
, buf
, n
);
2514 ptr
= acl_safe_strcopy( ptr
, "dn." );
2515 if ( bdn
->a_style
== ACL_STYLE_BASE
)
2516 ptr
= acl_safe_strcopy( ptr
, style_base
);
2518 ptr
= acl_safe_strcopy( ptr
, style_strings
[bdn
->a_style
] );
2519 if ( bdn
->a_style
== ACL_STYLE_LEVEL
) {
2520 char buf
[SLAP_TEXT_BUFLEN
];
2521 int n
= snprintf( buf
, sizeof(buf
), "{%d}", bdn
->a_level
);
2523 ptr
= acl_safe_strncopy( ptr
, buf
, n
);
2526 if ( bdn
->a_expand
) {
2527 ptr
= acl_safe_strcopy( ptr
, ",expand" );
2529 ptr
= acl_safe_strcopy( ptr
, "=\"" );
2530 ptr
= acl_safe_strbvcopy( ptr
, &bdn
->a_pat
);
2531 ptr
= acl_safe_strcopy( ptr
, "\"" );
2537 access2text( Access
*b
, char *ptr
)
2539 char maskbuf
[ACCESSMASK_MAXLEN
];
2541 ptr
= acl_safe_strcopy( ptr
, "\tby" );
2543 if ( !BER_BVISEMPTY( &b
->a_dn_pat
) ) {
2544 ptr
= dnaccess2text( &b
->a_dn
, ptr
, 0 );
2547 ptr
= acl_safe_strcopy( ptr
, " dnattr=" );
2548 ptr
= acl_safe_strbvcopy( ptr
, &b
->a_dn_at
->ad_cname
);
2551 if ( !BER_BVISEMPTY( &b
->a_realdn_pat
) ) {
2552 ptr
= dnaccess2text( &b
->a_realdn
, ptr
, 1 );
2554 if ( b
->a_realdn_at
) {
2555 ptr
= acl_safe_strcopy( ptr
, " realdnattr=" );
2556 ptr
= acl_safe_strbvcopy( ptr
, &b
->a_realdn_at
->ad_cname
);
2559 if ( !BER_BVISEMPTY( &b
->a_group_pat
) ) {
2560 ptr
= acl_safe_strcopy( ptr
, " group/" );
2561 ptr
= acl_safe_strcopy( ptr
, b
->a_group_oc
?
2562 b
->a_group_oc
->soc_cname
.bv_val
: SLAPD_GROUP_CLASS
);
2563 ptr
= acl_safe_strcopy( ptr
, "/" );
2564 ptr
= acl_safe_strcopy( ptr
, b
->a_group_at
?
2565 b
->a_group_at
->ad_cname
.bv_val
: SLAPD_GROUP_ATTR
);
2566 ptr
= acl_safe_strcopy( ptr
, "." );
2567 ptr
= acl_safe_strcopy( ptr
, style_strings
[b
->a_group_style
] );
2568 ptr
= acl_safe_strcopy( ptr
, "=\"" );
2569 ptr
= acl_safe_strbvcopy( ptr
, &b
->a_group_pat
);
2570 ptr
= acl_safe_strcopy( ptr
, "\"" );
2573 if ( !BER_BVISEMPTY( &b
->a_peername_pat
) ) {
2574 ptr
= acl_safe_strcopy( ptr
, " peername" );
2575 ptr
= acl_safe_strcopy( ptr
, "." );
2576 ptr
= acl_safe_strcopy( ptr
, style_strings
[b
->a_peername_style
] );
2577 ptr
= acl_safe_strcopy( ptr
, "=\"" );
2578 ptr
= acl_safe_strbvcopy( ptr
, &b
->a_peername_pat
);
2579 ptr
= acl_safe_strcopy( ptr
, "\"" );
2582 if ( !BER_BVISEMPTY( &b
->a_sockname_pat
) ) {
2583 ptr
= acl_safe_strcopy( ptr
, " sockname" );
2584 ptr
= acl_safe_strcopy( ptr
, "." );
2585 ptr
= acl_safe_strcopy( ptr
, style_strings
[b
->a_sockname_style
] );
2586 ptr
= acl_safe_strcopy( ptr
, "=\"" );
2587 ptr
= acl_safe_strbvcopy( ptr
, &b
->a_sockname_pat
);
2588 ptr
= acl_safe_strcopy( ptr
, "\"" );
2591 if ( !BER_BVISEMPTY( &b
->a_domain_pat
) ) {
2592 ptr
= acl_safe_strcopy( ptr
, " domain" );
2593 ptr
= acl_safe_strcopy( ptr
, "." );
2594 ptr
= acl_safe_strcopy( ptr
, style_strings
[b
->a_domain_style
] );
2595 if ( b
->a_domain_expand
) {
2596 ptr
= acl_safe_strcopy( ptr
, ",expand" );
2598 ptr
= acl_safe_strcopy( ptr
, "=" );
2599 ptr
= acl_safe_strbvcopy( ptr
, &b
->a_domain_pat
);
2602 if ( !BER_BVISEMPTY( &b
->a_sockurl_pat
) ) {
2603 ptr
= acl_safe_strcopy( ptr
, " sockurl" );
2604 ptr
= acl_safe_strcopy( ptr
, "." );
2605 ptr
= acl_safe_strcopy( ptr
, style_strings
[b
->a_sockurl_style
] );
2606 ptr
= acl_safe_strcopy( ptr
, "=\"" );
2607 ptr
= acl_safe_strbvcopy( ptr
, &b
->a_sockurl_pat
);
2608 ptr
= acl_safe_strcopy( ptr
, "\"" );
2611 if ( !BER_BVISEMPTY( &b
->a_set_pat
) ) {
2612 ptr
= acl_safe_strcopy( ptr
, " set" );
2613 ptr
= acl_safe_strcopy( ptr
, "." );
2614 ptr
= acl_safe_strcopy( ptr
, style_strings
[b
->a_set_style
] );
2615 ptr
= acl_safe_strcopy( ptr
, "=\"" );
2616 ptr
= acl_safe_strbvcopy( ptr
, &b
->a_set_pat
);
2617 ptr
= acl_safe_strcopy( ptr
, "\"" );
2621 if ( b
->a_dynacl
) {
2624 for ( da
= b
->a_dynacl
; da
; da
= da
->da_next
) {
2625 if ( da
->da_unparse
) {
2626 struct berval bv
= BER_BVNULL
;
2627 (void)( *da
->da_unparse
)( da
->da_private
, &bv
);
2628 assert( !BER_BVISNULL( &bv
) );
2629 ptr
= acl_safe_strbvcopy( ptr
, &bv
);
2630 ch_free( bv
.bv_val
);
2634 #endif /* SLAP_DYNACL */
2636 /* Security Strength Factors */
2637 if ( b
->a_authz
.sai_ssf
) {
2638 char buf
[SLAP_TEXT_BUFLEN
];
2639 int n
= snprintf( buf
, sizeof(buf
), " ssf=%u",
2640 b
->a_authz
.sai_ssf
);
2641 ptr
= acl_safe_strncopy( ptr
, buf
, n
);
2643 if ( b
->a_authz
.sai_transport_ssf
) {
2644 char buf
[SLAP_TEXT_BUFLEN
];
2645 int n
= snprintf( buf
, sizeof(buf
), " transport_ssf=%u",
2646 b
->a_authz
.sai_transport_ssf
);
2647 ptr
= acl_safe_strncopy( ptr
, buf
, n
);
2649 if ( b
->a_authz
.sai_tls_ssf
) {
2650 char buf
[SLAP_TEXT_BUFLEN
];
2651 int n
= snprintf( buf
, sizeof(buf
), " tls_ssf=%u",
2652 b
->a_authz
.sai_tls_ssf
);
2653 ptr
= acl_safe_strncopy( ptr
, buf
, n
);
2655 if ( b
->a_authz
.sai_sasl_ssf
) {
2656 char buf
[SLAP_TEXT_BUFLEN
];
2657 int n
= snprintf( buf
, sizeof(buf
), " sasl_ssf=%u",
2658 b
->a_authz
.sai_sasl_ssf
);
2659 ptr
= acl_safe_strncopy( ptr
, buf
, n
);
2662 ptr
= acl_safe_strcopy( ptr
, " " );
2663 if ( b
->a_dn_self
) {
2664 ptr
= acl_safe_strcopy( ptr
, "self" );
2665 } else if ( b
->a_realdn_self
) {
2666 ptr
= acl_safe_strcopy( ptr
, "realself" );
2668 ptr
= acl_safe_strcopy( ptr
, accessmask2str( b
->a_access_mask
, maskbuf
, 0 ));
2669 if ( !maskbuf
[0] ) ptr
--;
2671 if( b
->a_type
== ACL_BREAK
) {
2672 ptr
= acl_safe_strcopy( ptr
, " break" );
2674 } else if( b
->a_type
== ACL_CONTINUE
) {
2675 ptr
= acl_safe_strcopy( ptr
, " continue" );
2677 } else if( b
->a_type
!= ACL_STOP
) {
2678 ptr
= acl_safe_strcopy( ptr
, " unknown-control" );
2680 if ( !maskbuf
[0] ) ptr
= acl_safe_strcopy( ptr
, " stop" );
2682 ptr
= acl_safe_strcopy( ptr
, "\n" );
2688 acl_unparse( AccessControl
*a
, struct berval
*bv
)
2694 if ( BER_BVISNULL( &aclbuf
) ) {
2695 aclbuf
.bv_val
= ch_malloc( ACLBUF_CHUNKSIZE
);
2696 aclbuf
.bv_len
= ACLBUF_CHUNKSIZE
;
2701 ptr
= aclbuf
.bv_val
;
2703 ptr
= acl_safe_strcopy( ptr
, "to" );
2704 if ( !BER_BVISNULL( &a
->acl_dn_pat
) ) {
2706 ptr
= acl_safe_strcopy( ptr
, " dn." );
2707 if ( a
->acl_dn_style
== ACL_STYLE_BASE
)
2708 ptr
= acl_safe_strcopy( ptr
, style_base
);
2710 ptr
= acl_safe_strcopy( ptr
, style_strings
[a
->acl_dn_style
] );
2711 ptr
= acl_safe_strcopy( ptr
, "=\"" );
2712 ptr
= acl_safe_strbvcopy( ptr
, &a
->acl_dn_pat
);
2713 ptr
= acl_safe_strcopy( ptr
, "\"\n" );
2716 if ( a
->acl_filter
!= NULL
) {
2717 struct berval fbv
= BER_BVNULL
;
2720 filter2bv( a
->acl_filter
, &fbv
);
2721 ptr
= acl_safe_strcopy( ptr
, " filter=\"" );
2722 ptr
= acl_safe_strbvcopy( ptr
, &fbv
);
2723 ptr
= acl_safe_strcopy( ptr
, "\"\n" );
2724 ch_free( fbv
.bv_val
);
2727 if ( a
->acl_attrs
!= NULL
) {
2732 ptr
= acl_safe_strcopy( ptr
, " attrs=" );
2733 for ( an
= a
->acl_attrs
; an
&& !BER_BVISNULL( &an
->an_name
); an
++ ) {
2734 if ( ! first
) ptr
= acl_safe_strcopy( ptr
, ",");
2736 ptr
= acl_safe_strcopy( ptr
, ( an
->an_flags
& SLAP_AN_OCEXCLUDE
) ? "!" : "@" );
2737 ptr
= acl_safe_strbvcopy( ptr
, &an
->an_oc
->soc_cname
);
2740 ptr
= acl_safe_strbvcopy( ptr
, &an
->an_name
);
2744 ptr
= acl_safe_strcopy( ptr
, "\n" );
2747 if ( !BER_BVISNULL( &a
->acl_attrval
) ) {
2749 ptr
= acl_safe_strcopy( ptr
, " val." );
2750 if ( a
->acl_attrval_style
== ACL_STYLE_BASE
&&
2751 a
->acl_attrs
[0].an_desc
->ad_type
->sat_syntax
==
2752 slap_schema
.si_syn_distinguishedName
)
2753 ptr
= acl_safe_strcopy( ptr
, style_base
);
2755 ptr
= acl_safe_strcopy( ptr
, style_strings
[a
->acl_attrval_style
] );
2756 ptr
= acl_safe_strcopy( ptr
, "=\"" );
2757 ptr
= acl_safe_strbvcopy( ptr
, &a
->acl_attrval
);
2758 ptr
= acl_safe_strcopy( ptr
, "\"\n" );
2762 ptr
= acl_safe_strcopy( ptr
, " *\n" );
2765 for ( b
= a
->acl_access
; b
!= NULL
; b
= b
->a_next
) {
2766 ptr
= access2text( b
, ptr
);
2769 bv
->bv_val
= aclbuf
.bv_val
;
2770 bv
->bv_len
= ptr
- bv
->bv_val
;
2775 print_acl( Backend
*be
, AccessControl
*a
)
2779 acl_unparse( a
, &bv
);
2780 fprintf( stderr
, "%s ACL: access %s\n",
2781 be
== NULL
? "Global" : "Backend", bv
.bv_val
);
2783 #endif /* LDAP_DEBUG */