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-2005 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>
41 static char *style_strings[] = {
54 static void split(char *line, int splitchar, char **left, char **right);
55 static void access_append(Access **l, Access *a);
56 static void acl_usage(void) LDAP_GCCATTR((noreturn));
58 static void acl_regex_normalized_dn(const char *src, struct berval *pat);
61 static void print_acl(Backend *be, AccessControl *a);
62 static void print_access(Access *b);
67 check_scope( BackendDB *be, AccessControl *a );
68 #endif /* LDAP_DEVEL */
72 slap_dynacl_config( const char *fname, int lineno, Access *b, const char *name, slap_style_t sty, const char *right )
74 slap_dynacl_t *da, *tmp;
77 for ( da = b->a_dynacl; da; da = da->da_next ) {
78 if ( strcasecmp( da->da_name, name ) == 0 ) {
80 "%s: line %d: dynacl \"%s\" already specified.\n",
81 fname, lineno, name );
86 da = slap_dynacl_get( name );
91 tmp = ch_malloc( sizeof( slap_dynacl_t ) );
94 if ( tmp->da_parse ) {
95 rc = ( *tmp->da_parse )( fname, lineno, sty, right, &tmp->da_private );
102 tmp->da_next = b->a_dynacl;
107 #endif /* SLAP_DYNACL */
110 regtest(const char *fname, int lineno, char *pat) {
126 for (size = 0, flag = 0; (size < sizeof(buf)) && *sp; sp++) {
128 if (*sp == '$'|| (*sp >= '0' && *sp <= '9')) {
145 if ( size >= (sizeof(buf) - 1) ) {
147 "%s: line %d: regular expression \"%s\" too large\n",
148 fname, lineno, pat );
152 if ((e = regcomp(&re, buf, REG_EXTENDED|REG_ICASE))) {
154 regerror(e, &re, error, sizeof(error));
156 "%s: line %d: regular expression \"%s\" bad because of %s\n",
157 fname, lineno, pat, error );
167 * Check if the pattern of an ACL, if any, matches the scope
168 * of the backend it is defined within.
170 #define ACL_SCOPE_UNKNOWN (-2)
171 #define ACL_SCOPE_ERR (-1)
172 #define ACL_SCOPE_OK (0)
173 #define ACL_SCOPE_PARTIAL (1)
174 #define ACL_SCOPE_WARN (2)
177 check_scope( BackendDB *be, AccessControl *a )
182 dn = be->be_nsuffix[0];
184 if ( !BER_BVISEMPTY( &a->acl_dn_pat ) ||
185 a->acl_dn_style != ACL_STYLE_REGEX )
187 slap_style_t style = a->acl_dn_style;
189 if ( style == ACL_STYLE_REGEX ) {
190 char dnbuf[SLAP_LDAPDN_MAXLEN + 2];
191 char rebuf[SLAP_LDAPDN_MAXLEN + 1];
196 /* add trailing '$' to database suffix to form
197 * a simple trial regex pattern "<suffix>$" */
198 AC_MEMCPY( dnbuf, be->be_nsuffix[0].bv_val,
199 be->be_nsuffix[0].bv_len );
200 dnbuf[be->be_nsuffix[0].bv_len] = '$';
201 dnbuf[be->be_nsuffix[0].bv_len + 1] = '\0';
203 if ( regcomp( &re, dnbuf, REG_EXTENDED|REG_ICASE ) ) {
204 return ACL_SCOPE_WARN;
207 /* remove trailing ')$', if any, from original
209 rebuflen = a->acl_dn_pat.bv_len;
210 AC_MEMCPY( rebuf, a->acl_dn_pat.bv_val, rebuflen + 1 );
211 if ( rebuf[rebuflen - 1] == '$' ) {
212 rebuf[--rebuflen] = '\0';
214 while ( rebuflen > be->be_nsuffix[0].bv_len && rebuf[rebuflen - 1] == ')' ) {
215 rebuf[--rebuflen] = '\0';
217 if ( rebuflen == be->be_nsuffix[0].bv_len ) {
222 /* not a clear indication of scoping error, though */
223 rc = regexec( &re, rebuf, 0, NULL, 0 )
224 ? ACL_SCOPE_WARN : ACL_SCOPE_OK;
231 patlen = a->acl_dn_pat.bv_len;
232 /* If backend suffix is longer than pattern,
233 * it is a potential mismatch (in the sense
234 * that a superior naming context could
236 if ( dn.bv_len > patlen ) {
237 /* base is blatantly wrong */
238 if ( style == ACL_STYLE_BASE ) return ACL_SCOPE_ERR;
240 /* a style of one can be wrong if there is
241 * more than one level between the suffix
243 if ( style == ACL_STYLE_ONE ) {
244 int rdnlen = -1, sep = 0;
247 if ( !DN_SEPARATOR( dn.bv_val[dn.bv_len - patlen - 1] )) {
248 return ACL_SCOPE_ERR;
253 rdnlen = dn_rdnlen( NULL, &dn );
254 if ( rdnlen != dn.bv_len - patlen - sep )
255 return ACL_SCOPE_ERR;
258 /* if the trailing part doesn't match,
259 * then it's an error */
260 if ( strcmp( a->acl_dn_pat.bv_val,
261 &dn.bv_val[dn.bv_len - patlen] ) != 0 )
263 return ACL_SCOPE_ERR;
266 return ACL_SCOPE_PARTIAL;
272 case ACL_STYLE_CHILDREN:
273 case ACL_STYLE_SUBTREE:
281 if ( dn.bv_len < patlen &&
282 !DN_SEPARATOR( a->acl_dn_pat.bv_val[patlen - dn.bv_len - 1] ))
284 return ACL_SCOPE_ERR;
287 if ( strcmp( &a->acl_dn_pat.bv_val[patlen - dn.bv_len], dn.bv_val )
290 return ACL_SCOPE_ERR;
296 return ACL_SCOPE_UNKNOWN;
298 #endif /* LDAP_DEVEL */
310 char *left, *right, *style, *next;
318 for ( i = 1; i < argc; i++ ) {
319 /* to clause - select which entries are protected */
320 if ( strcasecmp( argv[i], "to" ) == 0 ) {
322 fprintf( stderr, "%s: line %d: "
323 "only one to clause allowed in access line\n",
327 a = (AccessControl *) ch_calloc( 1, sizeof(AccessControl) );
328 for ( ++i; i < argc; i++ ) {
329 if ( strcasecmp( argv[i], "by" ) == 0 ) {
334 if ( strcasecmp( argv[i], "*" ) == 0 ) {
335 if ( !BER_BVISEMPTY( &a->acl_dn_pat ) ||
336 a->acl_dn_style != ACL_STYLE_REGEX )
339 "%s: line %d: dn pattern"
340 " already specified in to clause.\n",
345 ber_str2bv( "*", STRLENOF( "*" ), 1, &a->acl_dn_pat );
349 split( argv[i], '=', &left, &right );
350 split( left, '.', &left, &style );
352 if ( right == NULL ) {
353 fprintf( stderr, "%s: line %d: "
354 "missing \"=\" in \"%s\" in to clause\n",
355 fname, lineno, left );
359 if ( strcasecmp( left, "dn" ) == 0 ) {
360 if ( !BER_BVISEMPTY( &a->acl_dn_pat ) ||
361 a->acl_dn_style != ACL_STYLE_REGEX )
364 "%s: line %d: dn pattern"
365 " already specified in to clause.\n",
370 if ( style == NULL || *style == '\0' ||
371 strcasecmp( style, "baseObject" ) == 0 ||
372 strcasecmp( style, "base" ) == 0 ||
373 strcasecmp( style, "exact" ) == 0 )
375 a->acl_dn_style = ACL_STYLE_BASE;
376 ber_str2bv( right, 0, 1, &a->acl_dn_pat );
378 } else if ( strcasecmp( style, "oneLevel" ) == 0 ||
379 strcasecmp( style, "one" ) == 0 )
381 a->acl_dn_style = ACL_STYLE_ONE;
382 ber_str2bv( right, 0, 1, &a->acl_dn_pat );
384 } else if ( strcasecmp( style, "subtree" ) == 0 ||
385 strcasecmp( style, "sub" ) == 0 )
387 if( *right == '\0' ) {
388 ber_str2bv( "*", STRLENOF( "*" ), 1, &a->acl_dn_pat );
391 a->acl_dn_style = ACL_STYLE_SUBTREE;
392 ber_str2bv( right, 0, 1, &a->acl_dn_pat );
395 } else if ( strcasecmp( style, "children" ) == 0 ) {
396 a->acl_dn_style = ACL_STYLE_CHILDREN;
397 ber_str2bv( right, 0, 1, &a->acl_dn_pat );
399 } else if ( strcasecmp( style, "regex" ) == 0 ) {
400 a->acl_dn_style = ACL_STYLE_REGEX;
402 if ( *right == '\0' ) {
403 /* empty regex should match empty DN */
404 a->acl_dn_style = ACL_STYLE_BASE;
405 ber_str2bv( right, 0, 1, &a->acl_dn_pat );
407 } else if ( strcmp(right, "*") == 0
408 || strcmp(right, ".*") == 0
409 || strcmp(right, ".*$") == 0
410 || strcmp(right, "^.*") == 0
411 || strcmp(right, "^.*$") == 0
412 || strcmp(right, ".*$$") == 0
413 || strcmp(right, "^.*$$") == 0 )
415 ber_str2bv( "*", STRLENOF("*"), 1, &a->acl_dn_pat );
418 acl_regex_normalized_dn( right, &a->acl_dn_pat );
422 fprintf( stderr, "%s: line %d: "
423 "unknown dn style \"%s\" in to clause\n",
424 fname, lineno, style );
431 if ( strcasecmp( left, "filter" ) == 0 ) {
432 if ( (a->acl_filter = str2filter( right )) == NULL ) {
434 "%s: line %d: bad filter \"%s\" in to clause\n",
435 fname, lineno, right );
439 } else if ( strcasecmp( left, "attr" ) == 0
440 || strcasecmp( left, "attrs" ) == 0 ) {
441 a->acl_attrs = str2anlist( a->acl_attrs,
443 if ( a->acl_attrs == NULL ) {
445 "%s: line %d: unknown attr \"%s\" in to clause\n",
446 fname, lineno, right );
450 } else if ( strncasecmp( left, "val", 3 ) == 0 ) {
451 if ( !BER_BVISEMPTY( &a->acl_attrval ) ) {
453 "%s: line %d: attr val already specified in to clause.\n",
457 if ( a->acl_attrs == NULL || !BER_BVISEMPTY( &a->acl_attrs[1].an_name ) )
460 "%s: line %d: attr val requires a single attribute.\n",
464 ber_str2bv( right, 0, 1, &a->acl_attrval );
465 if ( style && strcasecmp( style, "regex" ) == 0 ) {
466 int e = regcomp( &a->acl_attrval_re, a->acl_attrval.bv_val,
467 REG_EXTENDED | REG_ICASE | REG_NOSUB );
470 regerror( e, &a->acl_attrval_re, buf, sizeof(buf) );
471 fprintf( stderr, "%s: line %d: "
472 "regular expression \"%s\" bad because of %s\n",
473 fname, lineno, right, buf );
476 a->acl_attrval_style = ACL_STYLE_REGEX;
478 /* FIXME: if the attribute has DN syntax, we might
479 * allow one, subtree and children styles as well */
480 if ( !strcasecmp( style, "exact" ) ) {
481 a->acl_attrval_style = ACL_STYLE_BASE;
483 } else if ( a->acl_attrs[0].an_desc->ad_type->
484 sat_syntax == slap_schema.si_syn_distinguishedName )
486 if ( !strcasecmp( style, "baseObject" ) ||
487 !strcasecmp( style, "base" ) )
489 a->acl_attrval_style = ACL_STYLE_BASE;
490 } else if ( !strcasecmp( style, "onelevel" ) ||
491 !strcasecmp( style, "one" ) )
493 a->acl_attrval_style = ACL_STYLE_ONE;
494 } else if ( !strcasecmp( style, "subtree" ) ||
495 !strcasecmp( style, "sub" ) )
497 a->acl_attrval_style = ACL_STYLE_SUBTREE;
498 } else if ( !strcasecmp( style, "children" ) ) {
499 a->acl_attrval_style = ACL_STYLE_CHILDREN;
502 "%s: line %d: unknown val.<style> \"%s\" "
503 "for attributeType \"%s\" with DN syntax; "
505 fname, lineno, style,
506 a->acl_attrs[0].an_desc->ad_cname.bv_val );
507 a->acl_attrval_style = ACL_STYLE_BASE;
512 "%s: line %d: unknown val.<style> \"%s\" "
513 "for attributeType \"%s\"; using \"exact\"\n",
514 fname, lineno, style,
515 a->acl_attrs[0].an_desc->ad_cname.bv_val );
516 a->acl_attrval_style = ACL_STYLE_BASE;
522 "%s: line %d: expecting <what> got \"%s\"\n",
523 fname, lineno, left );
528 if ( !BER_BVISNULL( &a->acl_dn_pat ) &&
529 ber_bvccmp( &a->acl_dn_pat, '*' ) )
531 free( a->acl_dn_pat.bv_val );
532 BER_BVZERO( &a->acl_dn_pat );
535 if ( !BER_BVISEMPTY( &a->acl_dn_pat ) ||
536 a->acl_dn_style != ACL_STYLE_REGEX )
538 if ( a->acl_dn_style != ACL_STYLE_REGEX ) {
540 rc = dnNormalize( 0, NULL, NULL, &a->acl_dn_pat, &bv, NULL);
541 if ( rc != LDAP_SUCCESS ) {
543 "%s: line %d: bad DN \"%s\" in to DN clause\n",
544 fname, lineno, a->acl_dn_pat.bv_val );
547 free( a->acl_dn_pat.bv_val );
551 int e = regcomp( &a->acl_dn_re, a->acl_dn_pat.bv_val,
552 REG_EXTENDED | REG_ICASE );
555 regerror( e, &a->acl_dn_re, buf, sizeof(buf) );
556 fprintf( stderr, "%s: line %d: "
557 "regular expression \"%s\" bad because of %s\n",
558 fname, lineno, right, buf );
564 /* by clause - select who has what access to entries */
565 } else if ( strcasecmp( argv[i], "by" ) == 0 ) {
567 fprintf( stderr, "%s: line %d: "
568 "to clause required before by clause in access line\n",
574 * by clause consists of <who> and <access>
577 b = (Access *) ch_calloc( 1, sizeof(Access) );
579 ACL_INVALIDATE( b->a_access_mask );
583 "%s: line %d: premature eol: expecting <who>\n",
589 for ( ; i < argc; i++ ) {
590 slap_style_t sty = ACL_STYLE_REGEX;
591 char *style_modifier = NULL;
594 split( argv[i], '=', &left, &right );
595 split( left, '.', &left, &style );
597 split( style, ',', &style, &style_modifier);
600 if ( style == NULL || *style == '\0' ||
601 strcasecmp( style, "exact" ) == 0 ||
602 strcasecmp( style, "baseObject" ) == 0 ||
603 strcasecmp( style, "base" ) == 0 )
605 sty = ACL_STYLE_BASE;
607 } else if ( strcasecmp( style, "onelevel" ) == 0 ||
608 strcasecmp( style, "one" ) == 0 )
612 } else if ( strcasecmp( style, "subtree" ) == 0 ||
613 strcasecmp( style, "sub" ) == 0 )
615 sty = ACL_STYLE_SUBTREE;
617 } else if ( strcasecmp( style, "children" ) == 0 ) {
618 sty = ACL_STYLE_CHILDREN;
620 } else if ( strcasecmp( style, "regex" ) == 0 ) {
621 sty = ACL_STYLE_REGEX;
623 } else if ( strcasecmp( style, "expand" ) == 0 ) {
624 sty = ACL_STYLE_EXPAND;
626 } else if ( strcasecmp( style, "ip" ) == 0 ) {
629 } else if ( strcasecmp( style, "path" ) == 0 ) {
630 sty = ACL_STYLE_PATH;
631 #ifndef LDAP_PF_LOCAL
632 fprintf( stderr, "%s: line %d: "
633 "path style modifier is useless without local\n",
635 #endif /* LDAP_PF_LOCAL */
639 "%s: line %d: unknown style \"%s\" in by clause\n",
640 fname, lineno, style );
644 if ( style_modifier &&
645 strcasecmp( style_modifier, "expand" ) == 0 )
648 case ACL_STYLE_REGEX:
649 fprintf( stderr, "%s: line %d: "
650 "\"regex\" style implies "
651 "\"expand\" modifier (ignored)\n",
655 case ACL_STYLE_EXPAND:
657 /* FIXME: now it's legal... */
658 fprintf( stderr, "%s: line %d: "
659 "\"expand\" style used "
660 "in conjunction with "
661 "\"expand\" modifier (ignored)\n",
667 /* we'll see later if it's pertinent */
673 /* expand in <who> needs regex in <what> */
674 if ( ( sty == ACL_STYLE_EXPAND || expand )
675 && a->acl_dn_style != ACL_STYLE_REGEX )
677 fprintf( stderr, "%s: line %d: "
678 "\"expand\" style or modifier used "
679 "in conjunction with "
680 "a non-regex <what> clause\n",
684 if ( strcasecmp( argv[i], "*" ) == 0 ) {
685 ber_str2bv( "*", STRLENOF( "*" ), 1, &bv );
686 sty = ACL_STYLE_REGEX;
688 } else if ( strcasecmp( argv[i], "anonymous" ) == 0 ) {
689 ber_str2bv("anonymous", STRLENOF( "anonymous" ), 1, &bv);
690 sty = ACL_STYLE_ANONYMOUS;
692 } else if ( strcasecmp( argv[i], "users" ) == 0 ) {
693 ber_str2bv("users", STRLENOF( "users" ), 1, &bv);
694 sty = ACL_STYLE_USERS;
696 } else if ( strcasecmp( argv[i], "self" ) == 0 ) {
697 ber_str2bv("self", STRLENOF( "self" ), 1, &bv);
698 sty = ACL_STYLE_SELF;
700 } else if ( strcasecmp( left, "dn" ) == 0 ) {
701 if ( sty == ACL_STYLE_REGEX ) {
702 b->a_dn_style = ACL_STYLE_REGEX;
703 if ( right == NULL ) {
708 b->a_dn_style = ACL_STYLE_USERS;
710 } else if (*right == '\0' ) {
712 ber_str2bv("anonymous",
713 STRLENOF( "anonymous" ),
715 b->a_dn_style = ACL_STYLE_ANONYMOUS;
717 } else if ( strcmp( right, "*" ) == 0 ) {
719 /* any or users? users for now */
723 b->a_dn_style = ACL_STYLE_USERS;
725 } else if ( strcmp( right, ".+" ) == 0
726 || strcmp( right, "^.+" ) == 0
727 || strcmp( right, ".+$" ) == 0
728 || strcmp( right, "^.+$" ) == 0
729 || strcmp( right, ".+$$" ) == 0
730 || strcmp( right, "^.+$$" ) == 0 )
735 b->a_dn_style = ACL_STYLE_USERS;
737 } else if ( strcmp( right, ".*" ) == 0
738 || strcmp( right, "^.*" ) == 0
739 || strcmp( right, ".*$" ) == 0
740 || strcmp( right, "^.*$" ) == 0
741 || strcmp( right, ".*$$" ) == 0
742 || strcmp( right, "^.*$$" ) == 0 )
749 acl_regex_normalized_dn( right, &bv );
750 if ( !ber_bvccmp( &bv, '*' ) ) {
751 regtest( fname, lineno, bv.bv_val );
755 } else if ( right == NULL || *right == '\0' ) {
756 fprintf( stderr, "%s: line %d: "
757 "missing \"=\" in (or value after) \"%s\" "
759 fname, lineno, left );
763 ber_str2bv( right, 0, 1, &bv );
770 if ( !BER_BVISNULL( &bv ) ) {
771 if ( !BER_BVISEMPTY( &b->a_dn_pat ) ) {
773 "%s: line %d: dn pattern already specified.\n",
778 if ( sty != ACL_STYLE_REGEX &&
779 sty != ACL_STYLE_ANONYMOUS &&
780 sty != ACL_STYLE_USERS &&
781 sty != ACL_STYLE_SELF &&
784 rc = dnNormalize(0, NULL, NULL,
785 &bv, &b->a_dn_pat, NULL);
786 if ( rc != LDAP_SUCCESS ) {
788 "%s: line %d: bad DN \"%s\" in by DN clause\n",
789 fname, lineno, bv.bv_val );
798 b->a_dn_expand = expand;
802 if ( strcasecmp( left, "dnattr" ) == 0 ) {
803 if ( right == NULL || right[0] == '\0' ) {
804 fprintf( stderr, "%s: line %d: "
805 "missing \"=\" in (or value after) \"%s\" "
807 fname, lineno, left );
811 if( b->a_dn_at != NULL ) {
813 "%s: line %d: dnattr already specified.\n",
818 rc = slap_str2ad( right, &b->a_dn_at, &text );
820 if( rc != LDAP_SUCCESS ) {
822 "%s: line %d: dnattr \"%s\": %s\n",
823 fname, lineno, right, text );
828 if( !is_at_syntax( b->a_dn_at->ad_type,
830 !is_at_syntax( b->a_dn_at->ad_type,
831 SLAPD_NAMEUID_SYNTAX ))
834 "%s: line %d: dnattr \"%s\": "
835 "inappropriate syntax: %s\n",
836 fname, lineno, right,
837 b->a_dn_at->ad_type->sat_syntax_oid );
841 if( b->a_dn_at->ad_type->sat_equality == NULL ) {
843 "%s: line %d: dnattr \"%s\": "
844 "inappropriate matching (no EQUALITY)\n",
845 fname, lineno, right );
852 if ( strncasecmp( left, "group", STRLENOF( "group" ) ) == 0 ) {
857 case ACL_STYLE_REGEX:
858 /* legacy, tolerated */
859 fprintf( stderr, "%s: line %d: "
860 "deprecated group style \"regex\"; "
861 "use \"expand\" instead\n",
862 fname, lineno, style );
863 sty = ACL_STYLE_EXPAND;
867 /* legal, traditional */
868 case ACL_STYLE_EXPAND:
869 /* legal, substring expansion; supersedes regex */
874 fprintf( stderr, "%s: line %d: "
875 "inappropriate style \"%s\" in by clause\n",
876 fname, lineno, style );
880 if ( right == NULL || right[0] == '\0' ) {
881 fprintf( stderr, "%s: line %d: "
882 "missing \"=\" in (or value after) \"%s\" "
884 fname, lineno, left );
888 if ( !BER_BVISEMPTY( &b->a_group_pat ) ) {
890 "%s: line %d: group pattern already specified.\n",
895 /* format of string is
896 "group/objectClassValue/groupAttrName" */
897 if ( ( value = strchr(left, '/') ) != NULL ) {
899 if ( *value && ( name = strchr( value, '/' ) ) != NULL ) {
904 b->a_group_style = sty;
905 if ( sty == ACL_STYLE_EXPAND ) {
906 acl_regex_normalized_dn( right, &bv );
907 if ( !ber_bvccmp( &bv, '*' ) ) {
908 regtest( fname, lineno, bv.bv_val );
913 ber_str2bv( right, 0, 0, &bv );
914 rc = dnNormalize( 0, NULL, NULL, &bv,
915 &b->a_group_pat, NULL );
916 if ( rc != LDAP_SUCCESS ) {
918 "%s: line %d: bad DN \"%s\"\n",
919 fname, lineno, right );
924 if ( value && *value ) {
925 b->a_group_oc = oc_find( value );
928 if ( b->a_group_oc == NULL ) {
930 "%s: line %d: group objectclass "
932 fname, lineno, value );
937 b->a_group_oc = oc_find(SLAPD_GROUP_CLASS);
939 if( b->a_group_oc == NULL ) {
941 "%s: line %d: group default objectclass "
943 fname, lineno, SLAPD_GROUP_CLASS );
948 if ( is_object_subclass( slap_schema.si_oc_referral,
952 "%s: line %d: group objectclass \"%s\" "
953 "is subclass of referral\n",
954 fname, lineno, value );
958 if ( is_object_subclass( slap_schema.si_oc_alias,
962 "%s: line %d: group objectclass \"%s\" "
963 "is subclass of alias\n",
964 fname, lineno, value );
968 if ( name && *name ) {
969 rc = slap_str2ad( name, &b->a_group_at, &text );
971 if( rc != LDAP_SUCCESS ) {
973 "%s: line %d: group \"%s\": %s\n",
974 fname, lineno, right, text );
980 rc = slap_str2ad( SLAPD_GROUP_ATTR, &b->a_group_at, &text );
982 if ( rc != LDAP_SUCCESS ) {
984 "%s: line %d: group \"%s\": %s\n",
985 fname, lineno, SLAPD_GROUP_ATTR, text );
990 if ( !is_at_syntax( b->a_group_at->ad_type,
992 !is_at_syntax( b->a_group_at->ad_type,
993 SLAPD_NAMEUID_SYNTAX ) &&
994 !is_at_subtype( b->a_group_at->ad_type, slap_schema.si_ad_labeledURI->ad_type ) )
997 "%s: line %d: group \"%s\": inappropriate syntax: %s\n",
998 fname, lineno, right,
999 b->a_group_at->ad_type->sat_syntax_oid );
1006 struct berval vals[2];
1008 ber_str2bv( b->a_group_oc->soc_oid, 0, 0, &vals[0] );
1009 BER_BVZERO( &vals[1] );
1011 rc = oc_check_allowed( b->a_group_at->ad_type,
1015 fprintf( stderr, "%s: line %d: "
1016 "group: \"%s\" not allowed by \"%s\"\n",
1018 b->a_group_at->ad_cname.bv_val,
1019 b->a_group_oc->soc_oid );
1026 if ( strcasecmp( left, "peername" ) == 0 ) {
1028 case ACL_STYLE_REGEX:
1029 case ACL_STYLE_BASE:
1030 /* legal, traditional */
1031 case ACL_STYLE_EXPAND:
1032 /* cheap replacement to regex for simple expansion */
1034 case ACL_STYLE_PATH:
1035 /* legal, peername specific */
1039 fprintf( stderr, "%s: line %d: "
1040 "inappropriate style \"%s\" in by clause\n",
1041 fname, lineno, style );
1045 if ( right == NULL || right[0] == '\0' ) {
1046 fprintf( stderr, "%s: line %d: "
1047 "missing \"=\" in (or value after) \"%s\" "
1049 fname, lineno, left );
1053 if ( !BER_BVISEMPTY( &b->a_peername_pat ) ) {
1054 fprintf( stderr, "%s: line %d: "
1055 "peername pattern already specified.\n",
1060 b->a_peername_style = sty;
1061 if ( sty == ACL_STYLE_REGEX ) {
1062 acl_regex_normalized_dn( right, &bv );
1063 if ( !ber_bvccmp( &bv, '*' ) ) {
1064 regtest( fname, lineno, bv.bv_val );
1066 b->a_peername_pat = bv;
1069 ber_str2bv( right, 0, 1, &b->a_peername_pat );
1071 if ( sty == ACL_STYLE_IP ) {
1076 split( right, '{', &addr, &port );
1077 split( addr, '%', &addr, &mask );
1079 b->a_peername_addr = inet_addr( addr );
1080 if ( b->a_peername_addr == (unsigned long)(-1) ) {
1081 /* illegal address */
1082 fprintf( stderr, "%s: line %d: "
1083 "illegal peername address \"%s\".\n",
1084 fname, lineno, addr );
1088 b->a_peername_mask = (unsigned long)(-1);
1089 if ( mask != NULL ) {
1090 b->a_peername_mask = inet_addr( mask );
1091 if ( b->a_peername_mask ==
1092 (unsigned long)(-1) )
1095 fprintf( stderr, "%s: line %d: "
1096 "illegal peername address mask "
1098 fname, lineno, mask );
1103 b->a_peername_port = -1;
1107 b->a_peername_port = strtol( port, &end, 10 );
1108 if ( end[0] != '}' ) {
1110 fprintf( stderr, "%s: line %d: "
1111 "illegal peername port specification "
1113 fname, lineno, port );
1122 if ( strcasecmp( left, "sockname" ) == 0 ) {
1124 case ACL_STYLE_REGEX:
1125 case ACL_STYLE_BASE:
1126 /* legal, traditional */
1127 case ACL_STYLE_EXPAND:
1128 /* cheap replacement to regex for simple expansion */
1133 fprintf( stderr, "%s: line %d: "
1134 "inappropriate style \"%s\" in by clause\n",
1135 fname, lineno, style );
1139 if ( right == NULL || right[0] == '\0' ) {
1140 fprintf( stderr, "%s: line %d: "
1141 "missing \"=\" in (or value after) \"%s\" "
1143 fname, lineno, left );
1147 if ( !BER_BVISNULL( &b->a_sockname_pat ) ) {
1148 fprintf( stderr, "%s: line %d: "
1149 "sockname pattern already specified.\n",
1154 b->a_sockname_style = sty;
1155 if ( sty == ACL_STYLE_REGEX ) {
1156 acl_regex_normalized_dn( right, &bv );
1157 if ( !ber_bvccmp( &bv, '*' ) ) {
1158 regtest( fname, lineno, bv.bv_val );
1160 b->a_sockname_pat = bv;
1163 ber_str2bv( right, 0, 1, &b->a_sockname_pat );
1168 if ( strcasecmp( left, "domain" ) == 0 ) {
1170 case ACL_STYLE_REGEX:
1171 case ACL_STYLE_BASE:
1172 case ACL_STYLE_SUBTREE:
1173 /* legal, traditional */
1176 case ACL_STYLE_EXPAND:
1177 /* tolerated: means exact,expand */
1181 "\"expand\" modifier "
1182 "with \"expand\" style\n",
1185 sty = ACL_STYLE_BASE;
1191 fprintf( stderr, "%s: line %d: "
1192 "inappropriate style \"%s\" in by clause\n",
1193 fname, lineno, style );
1197 if ( right == NULL || right[0] == '\0' ) {
1198 fprintf( stderr, "%s: line %d: "
1199 "missing \"=\" in (or value after) \"%s\" "
1201 fname, lineno, left );
1205 if ( !BER_BVISEMPTY( &b->a_domain_pat ) ) {
1207 "%s: line %d: domain pattern already specified.\n",
1212 b->a_domain_style = sty;
1213 b->a_domain_expand = expand;
1214 if ( sty == ACL_STYLE_REGEX ) {
1215 acl_regex_normalized_dn( right, &bv );
1216 if ( !ber_bvccmp( &bv, '*' ) ) {
1217 regtest( fname, lineno, bv.bv_val );
1219 b->a_domain_pat = bv;
1222 ber_str2bv( right, 0, 1, &b->a_domain_pat );
1227 if ( strcasecmp( left, "sockurl" ) == 0 ) {
1229 case ACL_STYLE_REGEX:
1230 case ACL_STYLE_BASE:
1231 /* legal, traditional */
1232 case ACL_STYLE_EXPAND:
1233 /* cheap replacement to regex for simple expansion */
1238 fprintf( stderr, "%s: line %d: "
1239 "inappropriate style \"%s\" in by clause\n",
1240 fname, lineno, style );
1244 if ( right == NULL || right[0] == '\0' ) {
1245 fprintf( stderr, "%s: line %d: "
1246 "missing \"=\" in (or value after) \"%s\" "
1248 fname, lineno, left );
1252 if ( !BER_BVISEMPTY( &b->a_sockurl_pat ) ) {
1254 "%s: line %d: sockurl pattern already specified.\n",
1259 b->a_sockurl_style = sty;
1260 if ( sty == ACL_STYLE_REGEX ) {
1261 acl_regex_normalized_dn( right, &bv );
1262 if ( !ber_bvccmp( &bv, '*' ) ) {
1263 regtest( fname, lineno, bv.bv_val );
1265 b->a_sockurl_pat = bv;
1268 ber_str2bv( right, 0, 1, &b->a_sockurl_pat );
1273 if ( strcasecmp( left, "set" ) == 0 ) {
1276 case ACL_STYLE_REGEX:
1277 fprintf( stderr, "%s: line %d: "
1278 "deprecated set style "
1279 "\"regex\" in <by> clause; "
1280 "use \"expand\" instead\n",
1282 sty = ACL_STYLE_EXPAND;
1285 case ACL_STYLE_BASE:
1286 case ACL_STYLE_EXPAND:
1290 fprintf( stderr, "%s: line %d: "
1291 "inappropriate style \"%s\" in by clause\n",
1292 fname, lineno, style );
1296 if ( !BER_BVISEMPTY( &b->a_set_pat ) ) {
1298 "%s: line %d: set attribute already specified.\n",
1303 if ( right == NULL || *right == '\0' ) {
1305 "%s: line %d: no set is defined\n",
1310 b->a_set_style = sty;
1311 ber_str2bv( right, 0, 1, &b->a_set_pat );
1320 if ( strcasecmp( left, "aci" ) == 0 ) {
1323 } else if ( strncasecmp( left, "dynacl/", STRLENOF( "dynacl/" ) ) == 0 ) {
1324 name = &left[ STRLENOF( "dynacl/" ) ];
1328 if ( slap_dynacl_config( fname, lineno, b, name, sty, right ) ) {
1329 fprintf( stderr, "%s: line %d: "
1330 "unable to configure dynacl \"%s\"\n",
1331 fname, lineno, name );
1338 #else /* ! SLAP_DYNACL */
1340 #ifdef SLAPD_ACI_ENABLED
1341 if ( strcasecmp( left, "aci" ) == 0 ) {
1342 if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) {
1343 fprintf( stderr, "%s: line %d: "
1344 "inappropriate style \"%s\" in by clause\n",
1345 fname, lineno, style );
1349 if( b->a_aci_at != NULL ) {
1351 "%s: line %d: aci attribute already specified.\n",
1356 if ( right != NULL && *right != '\0' ) {
1357 rc = slap_str2ad( right, &b->a_aci_at, &text );
1359 if( rc != LDAP_SUCCESS ) {
1361 "%s: line %d: aci \"%s\": %s\n",
1362 fname, lineno, right, text );
1367 b->a_aci_at = slap_schema.si_ad_aci;
1370 if( !is_at_syntax( b->a_aci_at->ad_type,
1373 fprintf( stderr, "%s: line %d: "
1374 "aci \"%s\": inappropriate syntax: %s\n",
1375 fname, lineno, right,
1376 b->a_aci_at->ad_type->sat_syntax_oid );
1382 #endif /* SLAPD_ACI_ENABLED */
1383 #endif /* ! SLAP_DYNACL */
1385 if ( strcasecmp( left, "ssf" ) == 0 ) {
1386 if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
1387 fprintf( stderr, "%s: line %d: "
1388 "inappropriate style \"%s\" in by clause\n",
1389 fname, lineno, style );
1393 if ( b->a_authz.sai_ssf ) {
1395 "%s: line %d: ssf attribute already specified.\n",
1400 if ( right == NULL || *right == '\0' ) {
1402 "%s: line %d: no ssf is defined\n",
1407 b->a_authz.sai_ssf = strtol( right, &next, 10 );
1408 if ( next == NULL || next[0] != '\0' ) {
1410 "%s: line %d: unable to parse ssf value (%s)\n",
1411 fname, lineno, right );
1415 if ( !b->a_authz.sai_ssf ) {
1417 "%s: line %d: invalid ssf value (%s)\n",
1418 fname, lineno, right );
1424 if ( strcasecmp( left, "transport_ssf" ) == 0 ) {
1425 if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
1426 fprintf( stderr, "%s: line %d: "
1427 "inappropriate style \"%s\" in by clause\n",
1428 fname, lineno, style );
1432 if ( b->a_authz.sai_transport_ssf ) {
1433 fprintf( stderr, "%s: line %d: "
1434 "transport_ssf attribute already specified.\n",
1439 if ( right == NULL || *right == '\0' ) {
1441 "%s: line %d: no transport_ssf is defined\n",
1446 b->a_authz.sai_transport_ssf = strtol( right, &next, 10 );
1447 if ( next == NULL || next[0] != '\0' ) {
1448 fprintf( stderr, "%s: line %d: "
1449 "unable to parse transport_ssf value (%s)\n",
1450 fname, lineno, right );
1454 if ( !b->a_authz.sai_transport_ssf ) {
1456 "%s: line %d: invalid transport_ssf value (%s)\n",
1457 fname, lineno, right );
1463 if ( strcasecmp( left, "tls_ssf" ) == 0 ) {
1464 if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
1465 fprintf( stderr, "%s: line %d: "
1466 "inappropriate style \"%s\" in by clause\n",
1467 fname, lineno, style );
1471 if ( b->a_authz.sai_tls_ssf ) {
1472 fprintf( stderr, "%s: line %d: "
1473 "tls_ssf attribute already specified.\n",
1478 if ( right == NULL || *right == '\0' ) {
1480 "%s: line %d: no tls_ssf is defined\n",
1485 b->a_authz.sai_tls_ssf = strtol( right, &next, 10 );
1486 if ( next == NULL || next[0] != '\0' ) {
1487 fprintf( stderr, "%s: line %d: "
1488 "unable to parse tls_ssf value (%s)\n",
1489 fname, lineno, right );
1493 if ( !b->a_authz.sai_tls_ssf ) {
1495 "%s: line %d: invalid tls_ssf value (%s)\n",
1496 fname, lineno, right );
1502 if ( strcasecmp( left, "sasl_ssf" ) == 0 ) {
1503 if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
1504 fprintf( stderr, "%s: line %d: "
1505 "inappropriate style \"%s\" in by clause\n",
1506 fname, lineno, style );
1510 if ( b->a_authz.sai_sasl_ssf ) {
1511 fprintf( stderr, "%s: line %d: "
1512 "sasl_ssf attribute already specified.\n",
1517 if ( right == NULL || *right == '\0' ) {
1519 "%s: line %d: no sasl_ssf is defined\n",
1524 b->a_authz.sai_sasl_ssf = strtol( right, &next, 10 );
1525 if ( next == NULL || next[0] != '\0' ) {
1526 fprintf( stderr, "%s: line %d: "
1527 "unable to parse sasl_ssf value (%s)\n",
1528 fname, lineno, right );
1532 if ( !b->a_authz.sai_sasl_ssf ) {
1534 "%s: line %d: invalid sasl_ssf value (%s)\n",
1535 fname, lineno, right );
1541 if ( right != NULL ) {
1548 if ( i == argc || ( strcasecmp( left, "stop" ) == 0 ) ) {
1549 /* out of arguments or plain stop */
1551 ACL_PRIV_ASSIGN( b->a_access_mask, ACL_PRIV_ADDITIVE );
1552 b->a_type = ACL_STOP;
1554 access_append( &a->acl_access, b );
1558 if ( strcasecmp( left, "continue" ) == 0 ) {
1559 /* plain continue */
1561 ACL_PRIV_ASSIGN( b->a_access_mask, ACL_PRIV_ADDITIVE );
1562 b->a_type = ACL_CONTINUE;
1564 access_append( &a->acl_access, b );
1568 if ( strcasecmp( left, "break" ) == 0 ) {
1569 /* plain continue */
1571 ACL_PRIV_ASSIGN(b->a_access_mask, ACL_PRIV_ADDITIVE);
1572 b->a_type = ACL_BREAK;
1574 access_append( &a->acl_access, b );
1578 if ( strcasecmp( left, "by" ) == 0 ) {
1579 /* we've gone too far */
1581 ACL_PRIV_ASSIGN( b->a_access_mask, ACL_PRIV_ADDITIVE );
1582 b->a_type = ACL_STOP;
1584 access_append( &a->acl_access, b );
1589 if ( strncasecmp( left, "self", 4 ) == 0 ) {
1591 ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( &left[4] ) );
1594 ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( left ) );
1597 if ( ACL_IS_INVALID( b->a_access_mask ) ) {
1599 "%s: line %d: expecting <access> got \"%s\"\n",
1600 fname, lineno, left );
1604 b->a_type = ACL_STOP;
1606 if ( ++i == argc ) {
1607 /* out of arguments or plain stop */
1608 access_append( &a->acl_access, b );
1612 if ( strcasecmp( argv[i], "continue" ) == 0 ) {
1613 /* plain continue */
1614 b->a_type = ACL_CONTINUE;
1616 } else if ( strcasecmp( argv[i], "break" ) == 0 ) {
1617 /* plain continue */
1618 b->a_type = ACL_BREAK;
1620 } else if ( strcasecmp( argv[i], "stop" ) != 0 ) {
1625 access_append( &a->acl_access, b );
1629 "%s: line %d: expecting \"to\" "
1630 "or \"by\" got \"%s\"\n",
1631 fname, lineno, argv[i] );
1636 /* if we have no real access clause, complain and do nothing */
1638 fprintf( stderr, "%s: line %d: "
1639 "warning: no access clause(s) specified in access line\n",
1644 if ( ldap_debug & LDAP_DEBUG_ACL ) {
1649 if ( a->acl_access == NULL ) {
1650 fprintf( stderr, "%s: line %d: "
1651 "warning: no by clause(s) specified in access line\n",
1657 if ( !BER_BVISNULL( &be->be_nsuffix[ 1 ] ) ) {
1658 fprintf( stderr, "%s: line %d: warning: "
1659 "scope checking only applies to single-valued "
1660 "suffix databases\n",
1662 /* go ahead, since checking is not authoritative */
1665 switch ( check_scope( be, a ) ) {
1666 case ACL_SCOPE_UNKNOWN:
1667 fprintf( stderr, "%s: line %d: warning: "
1668 "cannot assess the validity of the ACL scope within "
1669 "backend naming context\n",
1673 case ACL_SCOPE_WARN:
1674 fprintf( stderr, "%s: line %d: warning: "
1675 "ACL could be out of scope within backend naming context\n",
1679 case ACL_SCOPE_PARTIAL:
1680 fprintf( stderr, "%s: line %d: warning: "
1681 "ACL appears to be partially out of scope within "
1682 "backend naming context\n",
1687 fprintf( stderr, "%s: line %d: warning: "
1688 "ACL appears to be out of scope within "
1689 "backend naming context\n",
1696 #endif /* LDAP_DEVEL */
1697 acl_append( &be->be_acl, a );
1700 acl_append( &frontendDB->be_acl, a );
1706 accessmask2str( slap_mask_t mask, char *buf )
1711 assert( buf != NULL );
1713 if ( ACL_IS_INVALID( mask ) ) {
1719 if ( ACL_IS_LEVEL( mask ) ) {
1720 if ( ACL_LVL_IS_NONE(mask) ) {
1721 ptr = lutil_strcopy( ptr, "none" );
1723 } else if ( ACL_LVL_IS_AUTH(mask) ) {
1724 ptr = lutil_strcopy( ptr, "auth" );
1726 } else if ( ACL_LVL_IS_COMPARE(mask) ) {
1727 ptr = lutil_strcopy( ptr, "compare" );
1729 } else if ( ACL_LVL_IS_SEARCH(mask) ) {
1730 ptr = lutil_strcopy( ptr, "search" );
1732 } else if ( ACL_LVL_IS_READ(mask) ) {
1733 ptr = lutil_strcopy( ptr, "read" );
1735 } else if ( ACL_LVL_IS_WRITE(mask) ) {
1736 ptr = lutil_strcopy( ptr, "write" );
1738 ptr = lutil_strcopy( ptr, "unknown" );
1744 if( ACL_IS_ADDITIVE( mask ) ) {
1747 } else if( ACL_IS_SUBTRACTIVE( mask ) ) {
1754 if ( ACL_PRIV_ISSET(mask, ACL_PRIV_WRITE) ) {
1759 if ( ACL_PRIV_ISSET(mask, ACL_PRIV_READ) ) {
1764 if ( ACL_PRIV_ISSET(mask, ACL_PRIV_SEARCH) ) {
1769 if ( ACL_PRIV_ISSET(mask, ACL_PRIV_COMPARE) ) {
1774 if ( ACL_PRIV_ISSET(mask, ACL_PRIV_AUTH) ) {
1779 if ( none && ACL_PRIV_ISSET(mask, ACL_PRIV_NONE) ) {
1788 if ( ACL_IS_LEVEL( mask ) ) {
1798 str2accessmask( const char *str )
1802 if( !ASCII_ALPHA(str[0]) ) {
1805 if ( str[0] == '=' ) {
1808 } else if( str[0] == '+' ) {
1809 ACL_PRIV_ASSIGN(mask, ACL_PRIV_ADDITIVE);
1811 } else if( str[0] == '-' ) {
1812 ACL_PRIV_ASSIGN(mask, ACL_PRIV_SUBSTRACTIVE);
1815 ACL_INVALIDATE(mask);
1819 for( i=1; str[i] != '\0'; i++ ) {
1820 if( TOLOWER((unsigned char) str[i]) == 'w' ) {
1821 ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
1823 } else if( TOLOWER((unsigned char) str[i]) == 'r' ) {
1824 ACL_PRIV_SET(mask, ACL_PRIV_READ);
1826 } else if( TOLOWER((unsigned char) str[i]) == 's' ) {
1827 ACL_PRIV_SET(mask, ACL_PRIV_SEARCH);
1829 } else if( TOLOWER((unsigned char) str[i]) == 'c' ) {
1830 ACL_PRIV_SET(mask, ACL_PRIV_COMPARE);
1832 } else if( TOLOWER((unsigned char) str[i]) == 'x' ) {
1833 ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
1835 } else if( str[i] != '0' ) {
1836 ACL_INVALIDATE(mask);
1844 if ( strcasecmp( str, "none" ) == 0 ) {
1845 ACL_LVL_ASSIGN_NONE(mask);
1847 } else if ( strcasecmp( str, "auth" ) == 0 ) {
1848 ACL_LVL_ASSIGN_AUTH(mask);
1850 } else if ( strcasecmp( str, "compare" ) == 0 ) {
1851 ACL_LVL_ASSIGN_COMPARE(mask);
1853 } else if ( strcasecmp( str, "search" ) == 0 ) {
1854 ACL_LVL_ASSIGN_SEARCH(mask);
1856 } else if ( strcasecmp( str, "read" ) == 0 ) {
1857 ACL_LVL_ASSIGN_READ(mask);
1859 } else if ( strcasecmp( str, "write" ) == 0 ) {
1860 ACL_LVL_ASSIGN_WRITE(mask);
1863 ACL_INVALIDATE( mask );
1872 fprintf( stderr, "%s%s%s\n",
1873 "<access clause> ::= access to <what> "
1874 "[ by <who> <access> [ <control> ] ]+ \n"
1875 "<what> ::= * | [dn[.<dnstyle>]=<DN>] [filter=<filter>] [attrs=<attrlist>]\n"
1876 "<attrlist> ::= <attr> [val[.<style>]=<value>] | <attr> , <attrlist>\n"
1877 "<attr> ::= <attrname> | entry | children\n",
1878 "<who> ::= [ * | anonymous | users | self | dn[.<dnstyle>]=<DN> ]\n"
1879 "\t[dnattr=<attrname>]\n"
1880 "\t[group[/<objectclass>[/<attrname>]][.<style>]=<group>]\n"
1881 "\t[peername[.<peernamestyle>]=<peer>] [sockname[.<style>]=<name>]\n"
1882 "\t[domain[.<domainstyle>]=<domain>] [sockurl[.<style>]=<url>]\n"
1883 #ifdef SLAPD_ACI_ENABLED
1884 "\t[aci=<attrname>]\n"
1886 "\t[ssf=<n>] [transport_ssf=<n>] [tls_ssf=<n>] [sasl_ssf=<n>]\n",
1887 "<dnstyle> ::= base(Object) | one(level) | sub(tree) | children | "
1889 "<style> ::= exact | regex | base(Object)\n"
1890 "<peernamestyle> ::= exact | regex | ip | path\n"
1891 "<domainstyle> ::= exact | regex | base(Object) | sub(tree)\n"
1892 "<access> ::= [self]{<level>|<priv>}\n"
1893 "<level> ::= none | auth | compare | search | read | write\n"
1894 "<priv> ::= {=|+|-}{w|r|s|c|x|0}+\n"
1895 "<control> ::= [ stop | continue | break ]\n"
1897 exit( EXIT_FAILURE );
1901 * Set pattern to a "normalized" DN from src.
1902 * At present it simply eats the (optional) space after
1903 * a RDN separator (,)
1904 * Eventually will evolve in a more complete normalization
1907 acl_regex_normalized_dn(
1909 struct berval *pattern )
1914 str = ch_strdup( src );
1915 len = strlen( src );
1917 for ( p = str; p && p[0]; p++ ) {
1919 if ( p[0] == '\\' && p[1] ) {
1921 * if escaping a hex pair we should
1922 * increment p twice; however, in that
1923 * case the second hex number does
1929 if ( p[0] == ',' && p[1] == ' ' ) {
1933 * too much space should be an error if we are pedantic
1935 for ( q = &p[2]; q[0] == ' '; q++ ) {
1938 AC_MEMCPY( p+1, q, len-(q-str)+1);
1941 pattern->bv_val = str;
1942 pattern->bv_len = p - str;
1955 if ( (*right = strchr( line, splitchar )) != NULL ) {
1956 *((*right)++) = '\0';
1961 access_append( Access **l, Access *a )
1963 for ( ; *l != NULL; l = &(*l)->a_next ) {
1971 acl_append( AccessControl **l, AccessControl *a )
1973 for ( ; *l != NULL; l = &(*l)->acl_next ) {
1981 access_free( Access *a )
1983 if ( !BER_BVISNULL( &a->a_dn_pat ) ) {
1984 free( a->a_dn_pat.bv_val );
1986 if ( !BER_BVISNULL( &a->a_peername_pat ) ) {
1987 free( a->a_peername_pat.bv_val );
1989 if ( !BER_BVISNULL( &a->a_sockname_pat ) ) {
1990 free( a->a_sockname_pat.bv_val );
1992 if ( !BER_BVISNULL( &a->a_domain_pat ) ) {
1993 free( a->a_domain_pat.bv_val );
1995 if ( !BER_BVISNULL( &a->a_sockurl_pat ) ) {
1996 free( a->a_sockurl_pat.bv_val );
1998 if ( !BER_BVISNULL( &a->a_set_pat ) ) {
1999 free( a->a_set_pat.bv_val );
2001 if ( !BER_BVISNULL( &a->a_group_pat ) ) {
2002 free( a->a_group_pat.bv_val );
2008 acl_free( AccessControl *a )
2013 if ( a->acl_filter ) {
2014 filter_free( a->acl_filter );
2016 if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
2017 free ( a->acl_dn_pat.bv_val );
2019 if ( a->acl_attrs ) {
2020 for ( an = a->acl_attrs; !BER_BVISNULL( &an->an_name ); an++ ) {
2021 free( an->an_name.bv_val );
2023 free( a->acl_attrs );
2025 for ( ; a->acl_access; a->acl_access = n ) {
2026 n = a->acl_access->a_next;
2027 access_free( a->acl_access );
2032 /* Because backend_startup uses acl_append to tack on the global_acl to
2033 * the end of each backend's acl, we cannot just take one argument and
2034 * merrily free our way to the end of the list. backend_destroy calls us
2035 * with the be_acl in arg1, and global_acl in arg2 to give us a stopping
2036 * point. config_destroy calls us with global_acl in arg1 and NULL in
2037 * arg2, so we then proceed to polish off the global_acl.
2040 acl_destroy( AccessControl *a, AccessControl *end )
2044 for (; a && a!= end; a=n) {
2051 access2str( slap_access_t access )
2053 if ( access == ACL_NONE ) {
2056 } else if ( access == ACL_AUTH ) {
2059 } else if ( access == ACL_COMPARE ) {
2062 } else if ( access == ACL_SEARCH ) {
2065 } else if ( access == ACL_READ ) {
2068 } else if ( access == ACL_WRITE ) {
2076 str2access( const char *str )
2078 if ( strcasecmp( str, "none" ) == 0 ) {
2081 } else if ( strcasecmp( str, "auth" ) == 0 ) {
2084 } else if ( strcasecmp( str, "compare" ) == 0 ) {
2087 } else if ( strcasecmp( str, "search" ) == 0 ) {
2090 } else if ( strcasecmp( str, "read" ) == 0 ) {
2093 } else if ( strcasecmp( str, "write" ) == 0 ) {
2097 return( ACL_INVALID_ACCESS );
2103 print_access( Access *b )
2105 char maskbuf[ACCESSMASK_MAXLEN];
2107 fprintf( stderr, "\tby" );
2109 if ( !BER_BVISEMPTY( &b->a_dn_pat ) ) {
2110 if ( ber_bvccmp( &b->a_dn_pat, '*' ) ||
2111 b->a_dn_style == ACL_STYLE_ANONYMOUS /* strcmp( b->a_dn_pat.bv_val, "anonymous" ) == 0 */ ||
2112 b->a_dn_style == ACL_STYLE_USERS /* strcmp( b->a_dn_pat.bv_val, "users" ) == 0 */ ||
2113 b->a_dn_style == ACL_STYLE_SELF /* strcmp( b->a_dn_pat.bv_val, "self" ) == 0 */ )
2115 fprintf( stderr, " %s", b->a_dn_pat.bv_val );
2118 fprintf( stderr, " dn.%s=\"%s\"",
2119 style_strings[b->a_dn_style], b->a_dn_pat.bv_val );
2123 if ( b->a_dn_at != NULL ) {
2124 fprintf( stderr, " dnattr=%s", b->a_dn_at->ad_cname.bv_val );
2127 if ( !BER_BVISEMPTY( &b->a_group_pat ) ) {
2128 fprintf( stderr, " group/%s/%s.%s=\"%s\"",
2129 b->a_group_oc ? b->a_group_oc->soc_cname.bv_val : "groupOfNames",
2130 b->a_group_at ? b->a_group_at->ad_cname.bv_val : "member",
2131 style_strings[b->a_group_style],
2132 b->a_group_pat.bv_val );
2135 if ( !BER_BVISEMPTY( &b->a_peername_pat ) ) {
2136 fprintf( stderr, " peername=\"%s\"", b->a_peername_pat.bv_val );
2139 if ( !BER_BVISEMPTY( &b->a_sockname_pat ) ) {
2140 fprintf( stderr, " sockname=\"%s\"", b->a_sockname_pat.bv_val );
2143 if ( !BER_BVISEMPTY( &b->a_domain_pat ) ) {
2144 fprintf( stderr, " domain=%s", b->a_domain_pat.bv_val );
2147 if ( !BER_BVISEMPTY( &b->a_sockurl_pat ) ) {
2148 fprintf( stderr, " sockurl=\"%s\"", b->a_sockurl_pat.bv_val );
2151 if ( !BER_BVISEMPTY( &b->a_set_pat ) ) {
2152 fprintf( stderr, " set=\"%s\"", b->a_set_pat.bv_val );
2156 if ( b->a_dynacl ) {
2159 for ( da = b->a_dynacl; da; da = da->da_next ) {
2160 if ( da->da_print ) {
2161 (void)( *da->da_print )( da->da_private );
2165 #else /* ! SLAP_DYNACL */
2166 #ifdef SLAPD_ACI_ENABLED
2167 if ( b->a_aci_at != NULL ) {
2168 fprintf( stderr, " aci=%s", b->a_aci_at->ad_cname.bv_val );
2171 #endif /* SLAP_DYNACL */
2173 /* Security Strength Factors */
2174 if ( b->a_authz.sai_ssf ) {
2175 fprintf( stderr, " ssf=%u",
2176 b->a_authz.sai_ssf );
2178 if ( b->a_authz.sai_transport_ssf ) {
2179 fprintf( stderr, " transport_ssf=%u",
2180 b->a_authz.sai_transport_ssf );
2182 if ( b->a_authz.sai_tls_ssf ) {
2183 fprintf( stderr, " tls_ssf=%u",
2184 b->a_authz.sai_tls_ssf );
2186 if ( b->a_authz.sai_sasl_ssf ) {
2187 fprintf( stderr, " sasl_ssf=%u",
2188 b->a_authz.sai_sasl_ssf );
2191 fprintf( stderr, " %s%s",
2192 b->a_dn_self ? "self" : "",
2193 accessmask2str( b->a_access_mask, maskbuf ) );
2195 if( b->a_type == ACL_BREAK ) {
2196 fprintf( stderr, " break" );
2198 } else if( b->a_type == ACL_CONTINUE ) {
2199 fprintf( stderr, " continue" );
2201 } else if( b->a_type != ACL_STOP ) {
2202 fprintf( stderr, " unknown-control" );
2205 fprintf( stderr, "\n" );
2210 print_acl( Backend *be, AccessControl *a )
2215 fprintf( stderr, "%s ACL: access to",
2216 be == NULL ? "Global" : "Backend" );
2218 if ( !BER_BVISEMPTY( &a->acl_dn_pat ) ) {
2220 fprintf( stderr, " dn.%s=\"%s\"\n",
2221 style_strings[a->acl_dn_style], a->acl_dn_pat.bv_val );
2224 if ( a->acl_filter != NULL ) {
2225 struct berval bv = BER_BVNULL;
2228 filter2bv( a->acl_filter, &bv );
2229 fprintf( stderr, " filter=%s\n", bv.bv_val );
2230 ch_free( bv.bv_val );
2233 if ( a->acl_attrs != NULL ) {
2238 fprintf( stderr, " attrs=" );
2239 for ( an = a->acl_attrs; an && !BER_BVISNULL( &an->an_name ); an++ ) {
2240 if ( ! first ) fprintf( stderr, "," );
2242 fputc( an->an_oc_exclude ? '!' : '@', stderr);
2243 fputs( an->an_oc->soc_cname.bv_val, stderr );
2246 fputs( an->an_name.bv_val, stderr );
2250 fprintf( stderr, "\n" );
2253 if ( !BER_BVISEMPTY( &a->acl_attrval ) ) {
2255 fprintf( stderr, " val.%s=\"%s\"\n",
2256 style_strings[a->acl_attrval_style], a->acl_attrval.bv_val );
2260 if( !to ) fprintf( stderr, " *\n" );
2262 for ( b = a->acl_access; b != NULL; b = b->a_next ) {
2266 fprintf( stderr, "\n" );
2268 #endif /* LDAP_DEBUG */