]> git.sur5r.net Git - openldap/blob - servers/slapd/aclparse.c
remove a componentCertificate attribute from the organizationalPerson objectclass
[openldap] / servers / slapd / aclparse.c
1 /* aclparse.c - routines to parse and check acl's */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2004 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
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>.
15  */
16 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
17  * All rights reserved.
18  *
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.
25  */
26
27 #include "portable.h"
28
29 #include <stdio.h>
30
31 #include <ac/ctype.h>
32 #include <ac/regex.h>
33 #include <ac/socket.h>
34 #include <ac/string.h>
35 #include <ac/unistd.h>
36
37 #include "slap.h"
38 #include "lber_pvt.h"
39 #include "lutil.h"
40
41 static char *style_strings[] = {
42         "regex",
43         "expand",
44         "base",
45         "one",
46         "subtree",
47         "children",
48         "attrof",
49         "ip",
50         "path",
51         NULL
52 };
53
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));
57
58 static void             acl_regex_normalized_dn(const char *src, struct berval *pat);
59
60 #ifdef LDAP_DEBUG
61 static void             print_acl(Backend *be, AccessControl *a);
62 static void             print_access(Access *b);
63 #endif
64
65 #ifdef LDAP_DEVEL
66 static int
67 check_scope( BackendDB *be, AccessControl *a );
68 #endif /* LDAP_DEVEL */
69
70 static void
71 regtest(const char *fname, int lineno, char *pat) {
72         int e;
73         regex_t re;
74
75         char buf[512];
76         unsigned size;
77
78         char *sp;
79         char *dp;
80         int  flag;
81
82         sp = pat;
83         dp = buf;
84         size = 0;
85         buf[0] = '\0';
86
87         for (size = 0, flag = 0; (size < sizeof(buf)) && *sp; sp++) {
88                 if (flag) {
89                         if (*sp == '$'|| (*sp >= '0' && *sp <= '9')) {
90                                 *dp++ = *sp;
91                                 size++;
92                         }
93                         flag = 0;
94
95                 } else {
96                         if (*sp == '$') {
97                                 flag = 1;
98                         } else {
99                                 *dp++ = *sp;
100                                 size++;
101                         }
102                 }
103         }
104
105         *dp = '\0';
106         if ( size >= (sizeof(buf) - 1) ) {
107                 fprintf( stderr,
108                         "%s: line %d: regular expression \"%s\" too large\n",
109                         fname, lineno, pat );
110                 acl_usage();
111         }
112
113         if ((e = regcomp(&re, buf, REG_EXTENDED|REG_ICASE))) {
114                 char error[512];
115                 regerror(e, &re, error, sizeof(error));
116                 fprintf( stderr,
117                         "%s: line %d: regular expression \"%s\" bad because of %s\n",
118                         fname, lineno, pat, error );
119                 acl_usage();
120         }
121         regfree(&re);
122 }
123
124 #ifdef LDAP_DEVEL
125 /*
126  * Experimental
127  *
128  * Check if the pattern of an ACL, if any, matches the scope
129  * of the backend it is defined within.
130  */
131 #define ACL_SCOPE_UNKNOWN       (-2)
132 #define ACL_SCOPE_ERR           (-1)
133 #define ACL_SCOPE_OK            (0)
134 #define ACL_SCOPE_PARTIAL       (1)
135 #define ACL_SCOPE_WARN          (2)
136
137 static int
138 check_scope( BackendDB *be, AccessControl *a )
139 {
140         int             patlen;
141         struct berval   dn;
142
143         dn = be->be_nsuffix[0];
144
145         if ( a->acl_dn_pat.bv_len || a->acl_dn_style != ACL_STYLE_REGEX ) {
146                 slap_style_t    style = a->acl_dn_style;
147
148                 if ( style == ACL_STYLE_REGEX ) {
149                         char    dnbuf[SLAP_LDAPDN_MAXLEN + 2];
150                         char    rebuf[SLAP_LDAPDN_MAXLEN + 1];
151                         regex_t re;
152                         int     rc;
153                         
154                         /* add trailing '$' */
155                         AC_MEMCPY( dnbuf, be->be_nsuffix[0].bv_val,
156                                 be->be_nsuffix[0].bv_len );
157                         dnbuf[be->be_nsuffix[0].bv_len] = '$';
158                         dnbuf[be->be_nsuffix[0].bv_len + 1] = '\0';
159
160                         if ( regcomp( &re, dnbuf, REG_EXTENDED|REG_ICASE ) ) {
161                                 return ACL_SCOPE_WARN;
162                         }
163
164                         /* remove trailing '$' */
165                         AC_MEMCPY( rebuf, a->acl_dn_pat.bv_val,
166                                 a->acl_dn_pat.bv_len + 1 );
167                         if ( a->acl_dn_pat.bv_val[a->acl_dn_pat.bv_len - 1] == '$' ) {
168                                 rebuf[a->acl_dn_pat.bv_len - 1] = '\0';
169                         }
170
171                         /* not a clear indication of scoping error, though */
172                         rc = regexec( &re, rebuf, 0, NULL, 0 )
173                                 ? ACL_SCOPE_WARN : ACL_SCOPE_OK;
174
175                         regfree( &re );
176                         return rc;
177                 }
178
179                 patlen = a->acl_dn_pat.bv_len;
180                 /* If backend suffix is longer than pattern,
181                  * it is a potential mismatch (in the sense
182                  * that a superior naming context could
183                  * match */
184                 if ( dn.bv_len > patlen ) {
185                         /* base is blatantly wrong */
186                         if ( style == ACL_STYLE_BASE ) return ACL_SCOPE_ERR;
187
188                         /* one can be wrong if there is more
189                          * than one level between the suffix
190                          * and the pattern */
191                         if ( style == ACL_STYLE_ONE ) {
192                                 int     rdnlen = -1, sep = 0;
193
194                                 if ( patlen > 0 ) {
195                                         if ( !DN_SEPARATOR( dn.bv_val[dn.bv_len - patlen - 1] )) {
196                                                 return ACL_SCOPE_ERR;
197                                         }
198                                         sep = 1;
199                                 }
200
201                                 rdnlen = dn_rdnlen( NULL, &dn );
202                                 if ( rdnlen != dn.bv_len - patlen - sep )
203                                         return ACL_SCOPE_ERR;
204                         }
205
206                         /* if the trailing part doesn't match,
207                          * then it's an error */
208                         if ( strcmp( a->acl_dn_pat.bv_val,
209                                 &dn.bv_val[dn.bv_len - patlen] ) != 0 )
210                         {
211                                 return ACL_SCOPE_ERR;
212                         }
213
214                         return ACL_SCOPE_PARTIAL;
215                 }
216
217                 switch ( style ) {
218                 case ACL_STYLE_BASE:
219                 case ACL_STYLE_ONE:
220                 case ACL_STYLE_CHILDREN:
221                 case ACL_STYLE_SUBTREE:
222                         break;
223
224                 default:
225                         assert( 0 );
226                         break;
227                 }
228
229                 if ( dn.bv_len < patlen &&
230                         !DN_SEPARATOR( a->acl_dn_pat.bv_val[patlen -dn.bv_len - 1] )) {
231                         return ACL_SCOPE_ERR;
232                 }
233
234                 if ( strcmp( &a->acl_dn_pat.bv_val[patlen - dn.bv_len], dn.bv_val )
235                         != 0 )
236                 {
237                         return ACL_SCOPE_ERR;
238                 }
239
240                 return ACL_SCOPE_OK;
241         }
242
243         return ACL_SCOPE_UNKNOWN;
244 }
245 #endif /* LDAP_DEVEL */
246
247 void
248 parse_acl(
249     Backend     *be,
250     const char  *fname,
251     int         lineno,
252     int         argc,
253     char        **argv
254 )
255 {
256         int             i;
257         char            *left, *right, *style, *next;
258         struct berval   bv;
259         AccessControl   *a;
260         Access  *b;
261         int rc;
262         const char *text;
263
264         a = NULL;
265         for ( i = 1; i < argc; i++ ) {
266                 /* to clause - select which entries are protected */
267                 if ( strcasecmp( argv[i], "to" ) == 0 ) {
268                         if ( a != NULL ) {
269                                 fprintf( stderr, "%s: line %d: "
270                                         "only one to clause allowed in access line\n",
271                                     fname, lineno );
272                                 acl_usage();
273                         }
274                         a = (AccessControl *) ch_calloc( 1, sizeof(AccessControl) );
275                         for ( ++i; i < argc; i++ ) {
276                                 if ( strcasecmp( argv[i], "by" ) == 0 ) {
277                                         i--;
278                                         break;
279                                 }
280
281                                 if ( strcasecmp( argv[i], "*" ) == 0 ) {
282                                         if( a->acl_dn_pat.bv_len ||
283                                                 ( a->acl_dn_style != ACL_STYLE_REGEX ) )
284                                         {
285                                                 fprintf( stderr,
286                                                         "%s: line %d: dn pattern"
287                                                         " already specified in to clause.\n",
288                                                         fname, lineno );
289                                                 acl_usage();
290                                         }
291
292                                         a->acl_dn_pat.bv_val = ch_strdup( "*" );
293                                         a->acl_dn_pat.bv_len = 1;
294                                         continue;
295                                 }
296
297                                 split( argv[i], '=', &left, &right );
298                                 split( left, '.', &left, &style );
299
300                                 if ( right == NULL ) {
301                                         fprintf( stderr, "%s: line %d: "
302                                                 "missing \"=\" in \"%s\" in to clause\n",
303                                             fname, lineno, left );
304                                         acl_usage();
305                                 }
306
307                                 if ( strcasecmp( left, "dn" ) == 0 ) {
308                                         if( a->acl_dn_pat.bv_len != 0 ||
309                                                 ( a->acl_dn_style != ACL_STYLE_REGEX ) )
310                                         {
311                                                 fprintf( stderr,
312                                                         "%s: line %d: dn pattern"
313                                                         " already specified in to clause.\n",
314                                                         fname, lineno );
315                                                 acl_usage();
316                                         }
317
318                                         if ( style == NULL || *style == '\0' ||
319                                                 strcasecmp( style, "baseObject" ) == 0 ||
320                                                 strcasecmp( style, "base" ) == 0 ||
321                                                 strcasecmp( style, "exact" ) == 0 )
322                                         {
323                                                 a->acl_dn_style = ACL_STYLE_BASE;
324                                                 ber_str2bv( right, 0, 1, &a->acl_dn_pat );
325
326                                         } else if ( strcasecmp( style, "oneLevel" ) == 0 ||
327                                                 strcasecmp( style, "one" ) == 0 )
328                                         {
329                                                 a->acl_dn_style = ACL_STYLE_ONE;
330                                                 ber_str2bv( right, 0, 1, &a->acl_dn_pat );
331
332                                         } else if ( strcasecmp( style, "subtree" ) == 0 ||
333                                                 strcasecmp( style, "sub" ) == 0 )
334                                         {
335                                                 if( *right == '\0' ) {
336                                                         a->acl_dn_pat.bv_val = ch_strdup( "*" );
337                                                         a->acl_dn_pat.bv_len = 1;
338
339                                                 } else {
340                                                         a->acl_dn_style = ACL_STYLE_SUBTREE;
341                                                         ber_str2bv( right, 0, 1, &a->acl_dn_pat );
342                                                 }
343
344                                         } else if ( strcasecmp( style, "children" ) == 0 ) {
345                                                 a->acl_dn_style = ACL_STYLE_CHILDREN;
346                                                 ber_str2bv( right, 0, 1, &a->acl_dn_pat );
347
348                                         } else if ( strcasecmp( style, "regex" ) == 0 ) {
349                                                 a->acl_dn_style = ACL_STYLE_REGEX;
350
351                                                 if ( *right == '\0' ) {
352                                                         /* empty regex should match empty DN */
353                                                         a->acl_dn_style = ACL_STYLE_BASE;
354                                                         ber_str2bv( right, 0, 1, &a->acl_dn_pat );
355
356                                                 } else if ( strcmp(right, "*") == 0 
357                                                         || strcmp(right, ".*") == 0 
358                                                         || strcmp(right, ".*$") == 0 
359                                                         || strcmp(right, "^.*") == 0 
360                                                         || strcmp(right, "^.*$") == 0
361                                                         || strcmp(right, ".*$$") == 0 
362                                                         || strcmp(right, "^.*$$") == 0 )
363                                                 {
364                                                         a->acl_dn_pat.bv_val = ch_strdup( "*" );
365                                                         a->acl_dn_pat.bv_len = STRLENOF("*");
366
367                                                 } else {
368                                                         acl_regex_normalized_dn( right, &a->acl_dn_pat );
369                                                 }
370
371                                         } else {
372                                                 fprintf( stderr, "%s: line %d: "
373                                                         "unknown dn style \"%s\" in to clause\n",
374                                                     fname, lineno, style );
375                                                 acl_usage();
376                                         }
377
378                                         continue;
379                                 }
380
381                                 if ( strcasecmp( left, "filter" ) == 0 ) {
382                                         if ( (a->acl_filter = str2filter( right )) == NULL ) {
383                                                 fprintf( stderr,
384                                 "%s: line %d: bad filter \"%s\" in to clause\n",
385                                                     fname, lineno, right );
386                                                 acl_usage();
387                                         }
388
389                                 } else if ( strcasecmp( left, "attr" ) == 0
390                                                 || strcasecmp( left, "attrs" ) == 0 ) {
391                                         a->acl_attrs = str2anlist( a->acl_attrs,
392                                                 right, "," );
393                                         if ( a->acl_attrs == NULL ) {
394                                                 fprintf( stderr,
395                                 "%s: line %d: unknown attr \"%s\" in to clause\n",
396                                                     fname, lineno, right );
397                                                 acl_usage();
398                                         }
399
400                                 } else if ( strncasecmp( left, "val", 3 ) == 0 ) {
401                                         if ( a->acl_attrval.bv_len ) {
402                                                 fprintf( stderr,
403                                 "%s: line %d: attr val already specified in to clause.\n",
404                                                         fname, lineno );
405                                                 acl_usage();
406                                         }
407                                         if ( a->acl_attrs == NULL || a->acl_attrs[1].an_name.bv_val ) {
408                                                 fprintf( stderr,
409                                 "%s: line %d: attr val requires a single attribute.\n",
410                                                         fname, lineno );
411                                                 acl_usage();
412                                         }
413                                         ber_str2bv( right, 0, 1, &a->acl_attrval );
414                                         if ( style && strcasecmp( style, "regex" ) == 0 ) {
415                                                 int e = regcomp( &a->acl_attrval_re, a->acl_attrval.bv_val,
416                                                         REG_EXTENDED | REG_ICASE | REG_NOSUB );
417                                                 if ( e ) {
418                                                         char buf[512];
419                                                         regerror( e, &a->acl_attrval_re, buf, sizeof(buf) );
420                                                         fprintf( stderr, "%s: line %d: "
421                                                                 "regular expression \"%s\" bad because of %s\n",
422                                                                 fname, lineno, right, buf );
423                                                         acl_usage();
424                                                 }
425                                                 a->acl_attrval_style = ACL_STYLE_REGEX;
426                                         } else {
427                                                 /* FIXME: if the attribute has DN syntax, we might
428                                                  * allow one, subtree and children styles as well */
429                                                 if ( !strcasecmp( style, "exact" ) ) {
430                                                         a->acl_attrval_style = ACL_STYLE_BASE;
431
432                                                 } else if ( a->acl_attrs[0].an_desc->ad_type->
433                                                         sat_syntax == slap_schema.si_syn_distinguishedName )
434                                                 {
435                                                         if ( !strcasecmp( style, "baseObject" ) ||
436                                                                 !strcasecmp( style, "base" ) )
437                                                         {
438                                                                 a->acl_attrval_style = ACL_STYLE_BASE;
439                                                         } else if ( !strcasecmp( style, "onelevel" ) ||
440                                                                 !strcasecmp( style, "one" ) )
441                                                         {
442                                                                 a->acl_attrval_style = ACL_STYLE_ONE;
443                                                         } else if ( !strcasecmp( style, "subtree" ) ||
444                                                                 !strcasecmp( style, "sub" ) )
445                                                         {
446                                                                 a->acl_attrval_style = ACL_STYLE_SUBTREE;
447                                                         } else if ( !strcasecmp( style, "children" ) ) {
448                                                                 a->acl_attrval_style = ACL_STYLE_CHILDREN;
449                                                         } else {
450                                                                 fprintf( stderr, 
451                                                                         "%s: line %d: unknown val.<style> \"%s\" "
452                                                                         "for attributeType \"%s\" with DN syntax; "
453                                                                         "using \"base\"\n",
454                                                                         fname, lineno, style,
455                                                                         a->acl_attrs[0].an_desc->ad_cname.bv_val );
456                                                                 a->acl_attrval_style = ACL_STYLE_BASE;
457                                                         }
458                                                         
459                                                 } else {
460                                                         fprintf( stderr, 
461                                                                 "%s: line %d: unknown val.<style> \"%s\" "
462                                                                 "for attributeType \"%s\"; using \"exact\"\n",
463                                                                 fname, lineno, style,
464                                                                 a->acl_attrs[0].an_desc->ad_cname.bv_val );
465                                                         a->acl_attrval_style = ACL_STYLE_BASE;
466                                                 }
467                                         }
468                                         
469                                 } else {
470                                         fprintf( stderr,
471                                                 "%s: line %d: expecting <what> got \"%s\"\n",
472                                             fname, lineno, left );
473                                         acl_usage();
474                                 }
475                         }
476
477                         if ( !BER_BVISNULL( &a->acl_dn_pat ) && 
478                                         ber_bvccmp( &a->acl_dn_pat, '*' ) )
479                         {
480                                 free( a->acl_dn_pat.bv_val );
481                                 BER_BVZERO( &a->acl_dn_pat );
482                         }
483                         
484                         if( a->acl_dn_pat.bv_len != 0 ||
485                                 ( a->acl_dn_style != ACL_STYLE_REGEX ) )
486                         {
487                                 if ( a->acl_dn_style != ACL_STYLE_REGEX ) {
488                                         struct berval bv;
489                                         rc = dnNormalize( 0, NULL, NULL, &a->acl_dn_pat, &bv, NULL);
490                                         if ( rc != LDAP_SUCCESS ) {
491                                                 fprintf( stderr,
492                                                         "%s: line %d: bad DN \"%s\" in to DN clause\n",
493                                                         fname, lineno, a->acl_dn_pat.bv_val );
494                                                 acl_usage();
495                                         }
496                                         free( a->acl_dn_pat.bv_val );
497                                         a->acl_dn_pat = bv;
498                                 } else {
499                                         int e = regcomp( &a->acl_dn_re, a->acl_dn_pat.bv_val,
500                                                 REG_EXTENDED | REG_ICASE );
501                                         if ( e ) {
502                                                 char buf[512];
503                                                 regerror( e, &a->acl_dn_re, buf, sizeof(buf) );
504                                                 fprintf( stderr, "%s: line %d: "
505                                                         "regular expression \"%s\" bad because of %s\n",
506                                                         fname, lineno, right, buf );
507                                                 acl_usage();
508                                         }
509                                 }
510                         }
511
512                 /* by clause - select who has what access to entries */
513                 } else if ( strcasecmp( argv[i], "by" ) == 0 ) {
514                         if ( a == NULL ) {
515                                 fprintf( stderr, "%s: line %d: "
516                                         "to clause required before by clause in access line\n",
517                                     fname, lineno );
518                                 acl_usage();
519                         }
520
521                         /*
522                          * by clause consists of <who> and <access>
523                          */
524
525                         b = (Access *) ch_calloc( 1, sizeof(Access) );
526
527                         ACL_INVALIDATE( b->a_access_mask );
528
529                         if ( ++i == argc ) {
530                                 fprintf( stderr,
531                             "%s: line %d: premature eol: expecting <who>\n",
532                                     fname, lineno );
533                                 acl_usage();
534                         }
535
536                         /* get <who> */
537                         for ( ; i < argc; i++ ) {
538                                 slap_style_t sty = ACL_STYLE_REGEX;
539                                 char *style_modifier = NULL;
540                                 int expand = 0;
541
542                                 split( argv[i], '=', &left, &right );
543                                 split( left, '.', &left, &style );
544                                 if ( style ) {
545                                         split( style, ',', &style, &style_modifier);
546                                 }
547
548                                 if ( style == NULL || *style == '\0' ||
549                                         strcasecmp( style, "exact" ) == 0 ||
550                                         strcasecmp( style, "baseObject" ) == 0 ||
551                                         strcasecmp( style, "base" ) == 0 )
552                                 {
553                                         sty = ACL_STYLE_BASE;
554
555                                 } else if ( strcasecmp( style, "onelevel" ) == 0 ||
556                                         strcasecmp( style, "one" ) == 0 )
557                                 {
558                                         sty = ACL_STYLE_ONE;
559
560                                 } else if ( strcasecmp( style, "subtree" ) == 0 ||
561                                         strcasecmp( style, "sub" ) == 0 )
562                                 {
563                                         sty = ACL_STYLE_SUBTREE;
564
565                                 } else if ( strcasecmp( style, "children" ) == 0 ) {
566                                         sty = ACL_STYLE_CHILDREN;
567
568                                 } else if ( strcasecmp( style, "regex" ) == 0 ) {
569                                         sty = ACL_STYLE_REGEX;
570
571                                 } else if ( strcasecmp( style, "expand" ) == 0 ) {
572                                         sty = ACL_STYLE_EXPAND;
573
574                                 } else if ( strcasecmp( style, "ip" ) == 0 ) {
575                                         sty = ACL_STYLE_IP;
576
577                                 } else if ( strcasecmp( style, "path" ) == 0 ) {
578                                         sty = ACL_STYLE_PATH;
579 #ifndef LDAP_PF_LOCAL
580                                         fprintf( stderr, "%s: line %d: "
581                                                 "path style modifier is useless without local\n",
582                                                 fname, lineno );
583 #endif /* LDAP_PF_LOCAL */
584
585                                 } else {
586                                         fprintf( stderr,
587                                                 "%s: line %d: unknown style \"%s\" in by clause\n",
588                                             fname, lineno, style );
589                                         acl_usage();
590                                 }
591
592                                 if ( style_modifier &&
593                                         strcasecmp( style_modifier, "expand" ) == 0 )
594                                 {
595                                         switch ( sty ) {
596                                         case ACL_STYLE_REGEX:
597                                                 fprintf( stderr, "%s: line %d: "
598                                                         "\"regex\" style implies "
599                                                         "\"expand\" modifier (ignored)\n",
600                                                         fname, lineno );
601                                                 break;
602
603                                         case ACL_STYLE_EXPAND:
604 #if 0
605                                                 /* FIXME: now it's legal... */
606                                                 fprintf( stderr, "%s: line %d: "
607                                                         "\"expand\" style used "
608                                                         "in conjunction with "
609                                                         "\"expand\" modifier (ignored)\n",
610                                                         fname, lineno );
611 #endif
612                                                 break;
613
614                                         default:
615                                                 /* we'll see later if it's pertinent */
616                                                 expand = 1;
617                                                 break;
618                                         }
619                                 }
620
621                                 /* expand in <who> needs regex in <what> */
622                                 if ( ( sty == ACL_STYLE_EXPAND || expand )
623                                                 && a->acl_dn_style != ACL_STYLE_REGEX )
624                                 {
625                                         fprintf( stderr, "%s: line %d: "
626                                                 "\"expand\" style or modifier used "
627                                                 "in conjunction with "
628                                                 "a non-regex <what> clause\n",
629                                                 fname, lineno );
630                                 }
631
632                                 if ( strcasecmp( argv[i], "*" ) == 0 ) {
633                                         bv.bv_val = ch_strdup( "*" );
634                                         bv.bv_len = 1;
635                                         sty = ACL_STYLE_REGEX;
636
637                                 } else if ( strcasecmp( argv[i], "anonymous" ) == 0 ) {
638                                         ber_str2bv("anonymous", STRLENOF( "anonymous" ), 1, &bv);
639                                         sty = ACL_STYLE_REGEX;
640
641                                 } else if ( strcasecmp( argv[i], "self" ) == 0 ) {
642                                         ber_str2bv("self", STRLENOF( "self" ), 1, &bv);
643                                         sty = ACL_STYLE_REGEX;
644
645                                 } else if ( strcasecmp( argv[i], "users" ) == 0 ) {
646                                         ber_str2bv("users", STRLENOF( "users" ), 1, &bv);
647                                         sty = ACL_STYLE_REGEX;
648
649                                 } else if ( strcasecmp( left, "dn" ) == 0 ) {
650                                         if ( sty == ACL_STYLE_REGEX ) {
651                                                 b->a_dn_style = ACL_STYLE_REGEX;
652                                                 if( right == NULL ) {
653                                                         /* no '=' */
654                                                         ber_str2bv("users",
655                                                                 STRLENOF( "users" ),
656                                                                 1, &bv);
657                                                 } else if (*right == '\0' ) {
658                                                         /* dn="" */
659                                                         ber_str2bv("anonymous",
660                                                                 STRLENOF( "anonymous" ),
661                                                                 1, &bv);
662                                                 } else if ( strcmp( right, "*" ) == 0 ) {
663                                                         /* dn=* */
664                                                         /* any or users?  users for now */
665                                                         ber_str2bv("users",
666                                                                 STRLENOF( "users" ),
667                                                                 1, &bv);
668                                                 } else if ( strcmp( right, ".+" ) == 0
669                                                         || strcmp( right, "^.+" ) == 0
670                                                         || strcmp( right, ".+$" ) == 0
671                                                         || strcmp( right, "^.+$" ) == 0
672                                                         || strcmp( right, ".+$$" ) == 0
673                                                         || strcmp( right, "^.+$$" ) == 0 )
674                                                 {
675                                                         ber_str2bv("users",
676                                                                 STRLENOF( "users" ),
677                                                                 1, &bv);
678                                                 } else if ( strcmp( right, ".*" ) == 0
679                                                         || strcmp( right, "^.*" ) == 0
680                                                         || strcmp( right, ".*$" ) == 0
681                                                         || strcmp( right, "^.*$" ) == 0
682                                                         || strcmp( right, ".*$$" ) == 0
683                                                         || strcmp( right, "^.*$$" ) == 0 )
684                                                 {
685                                                         ber_str2bv("*",
686                                                                 STRLENOF( "*" ),
687                                                                 1, &bv);
688
689                                                 } else {
690                                                         acl_regex_normalized_dn( right, &bv );
691                                                         if ( !ber_bvccmp( &bv, '*' ) ) {
692                                                                 regtest(fname, lineno, bv.bv_val);
693                                                         }
694                                                 }
695                                         } else if ( right == NULL || *right == '\0' ) {
696                                                 fprintf( stderr, "%s: line %d: "
697                                                         "missing \"=\" in (or value after) \"%s\" "
698                                                         "in by clause\n",
699                                                     fname, lineno, left );
700                                                 acl_usage();
701
702                                         } else {
703                                                 ber_str2bv( right, 0, 1, &bv );
704                                         }
705
706                                 } else {
707                                         bv.bv_val = NULL;
708                                 }
709
710                                 if( bv.bv_val != NULL ) {
711                                         if( b->a_dn_pat.bv_len != 0 ) {
712                                                 fprintf( stderr,
713                                                     "%s: line %d: dn pattern already specified.\n",
714                                                     fname, lineno );
715                                                 acl_usage();
716                                         }
717
718                                         if ( sty != ACL_STYLE_REGEX && expand == 0 ) {
719                                                 rc = dnNormalize(0, NULL, NULL,
720                                                         &bv, &b->a_dn_pat, NULL);
721                                                 if ( rc != LDAP_SUCCESS ) {
722                                                         fprintf( stderr,
723                                                                 "%s: line %d: bad DN \"%s\" in by DN clause\n",
724                                                                 fname, lineno, bv.bv_val );
725                                                         acl_usage();
726                                                 }
727                                                 free(bv.bv_val);
728                                         } else {
729                                                 b->a_dn_pat = bv;
730                                         }
731                                         b->a_dn_style = sty;
732                                         b->a_dn_expand = expand;
733                                         continue;
734                                 }
735
736                                 if ( strcasecmp( left, "dnattr" ) == 0 ) {
737                                         if ( right == NULL || right[0] == '\0' ) {
738                                                 fprintf( stderr, "%s: line %d: "
739                                                         "missing \"=\" in (or value after) \"%s\" "
740                                                         "in by clause\n",
741                                                         fname, lineno, left );
742                                                 acl_usage();
743                                         }
744
745                                         if( b->a_dn_at != NULL ) {
746                                                 fprintf( stderr,
747                                                         "%s: line %d: dnattr already specified.\n",
748                                                         fname, lineno );
749                                                 acl_usage();
750                                         }
751
752                                         rc = slap_str2ad( right, &b->a_dn_at, &text );
753
754                                         if( rc != LDAP_SUCCESS ) {
755                                                 fprintf( stderr,
756                                                         "%s: line %d: dnattr \"%s\": %s\n",
757                                                         fname, lineno, right, text );
758                                                 acl_usage();
759                                         }
760
761
762                                         if( !is_at_syntax( b->a_dn_at->ad_type,
763                                                 SLAPD_DN_SYNTAX ) &&
764                                                 !is_at_syntax( b->a_dn_at->ad_type,
765                                                 SLAPD_NAMEUID_SYNTAX ))
766                                         {
767                                                 fprintf( stderr,
768                                                         "%s: line %d: dnattr \"%s\": "
769                                                         "inappropriate syntax: %s\n",
770                                                         fname, lineno, right,
771                                                         b->a_dn_at->ad_type->sat_syntax_oid );
772                                                 acl_usage();
773                                         }
774
775                                         if( b->a_dn_at->ad_type->sat_equality == NULL ) {
776                                                 fprintf( stderr,
777                                                         "%s: line %d: dnattr \"%s\": "
778                                                         "inappropriate matching (no EQUALITY)\n",
779                                                         fname, lineno, right );
780                                                 acl_usage();
781                                         }
782
783                                         continue;
784                                 }
785
786                                 if ( strncasecmp( left, "group", STRLENOF( "group" ) ) == 0 ) {
787                                         char *name = NULL;
788                                         char *value = NULL;
789
790                                         switch ( sty ) {
791                                         case ACL_STYLE_REGEX:
792                                                 /* legacy, tolerated */
793                                                 fprintf( stderr, "%s: line %d: "
794                                                         "deprecated group style \"regex\"; "
795                                                         "use \"expand\" instead\n",
796                                                         fname, lineno, style );
797                                                 sty = ACL_STYLE_EXPAND;
798                                                 break;
799
800                                         case ACL_STYLE_BASE:
801                                                 /* legal, traditional */
802                                         case ACL_STYLE_EXPAND:
803                                                 /* legal, substring expansion; supersedes regex */
804                                                 break;
805
806                                         default:
807                                                 /* unknown */
808                                                 fprintf( stderr, "%s: line %d: "
809                                                         "inappropriate style \"%s\" in by clause\n",
810                                                         fname, lineno, style );
811                                                 acl_usage();
812                                         }
813
814                                         if ( right == NULL || right[0] == '\0' ) {
815                                                 fprintf( stderr, "%s: line %d: "
816                                                         "missing \"=\" in (or value after) \"%s\" "
817                                                         "in by clause\n",
818                                                         fname, lineno, left );
819                                                 acl_usage();
820                                         }
821
822                                         if( b->a_group_pat.bv_len ) {
823                                                 fprintf( stderr,
824                                                         "%s: line %d: group pattern already specified.\n",
825                                                         fname, lineno );
826                                                 acl_usage();
827                                         }
828
829                                         /* format of string is
830                                                 "group/objectClassValue/groupAttrName" */
831                                         if ((value = strchr(left, '/')) != NULL) {
832                                                 *value++ = '\0';
833                                                 if (*value && (name = strchr(value, '/')) != NULL) {
834                                                         *name++ = '\0';
835                                                 }
836                                         }
837
838                                         b->a_group_style = sty;
839                                         if (sty == ACL_STYLE_EXPAND) {
840                                                 acl_regex_normalized_dn( right, &bv );
841                                                 if ( !ber_bvccmp( &bv, '*' ) ) {
842                                                         regtest(fname, lineno, bv.bv_val);
843                                                 }
844                                                 b->a_group_pat = bv;
845                                         } else {
846                                                 ber_str2bv( right, 0, 0, &bv );
847                                                 rc = dnNormalize( 0, NULL, NULL, &bv,
848                                                         &b->a_group_pat, NULL );
849                                                 if ( rc != LDAP_SUCCESS ) {
850                                                         fprintf( stderr,
851                                                                 "%s: line %d: bad DN \"%s\"\n",
852                                                                 fname, lineno, right );
853                                                         acl_usage();
854                                                 }
855                                         }
856
857                                         if (value && *value) {
858                                                 b->a_group_oc = oc_find( value );
859                                                 *--value = '/';
860
861                                                 if( b->a_group_oc == NULL ) {
862                                                         fprintf( stderr,
863                                                                 "%s: line %d: group objectclass "
864                                                                 "\"%s\" unknown\n",
865                                                                 fname, lineno, value );
866                                                         acl_usage();
867                                                 }
868                                         } else {
869                                                 b->a_group_oc = oc_find(SLAPD_GROUP_CLASS);
870
871                                                 if( b->a_group_oc == NULL ) {
872                                                         fprintf( stderr,
873                                                                 "%s: line %d: group default objectclass "
874                                                                 "\"%s\" unknown\n",
875                                                                 fname, lineno, SLAPD_GROUP_CLASS );
876                                                         acl_usage();
877                                                 }
878                                         }
879
880                                         if( is_object_subclass( slap_schema.si_oc_referral,
881                                                 b->a_group_oc ))
882                                         {
883                                                 fprintf( stderr,
884                                                         "%s: line %d: group objectclass \"%s\" "
885                                                         "is subclass of referral\n",
886                                                         fname, lineno, value );
887                                                 acl_usage();
888                                         }
889
890                                         if( is_object_subclass( slap_schema.si_oc_alias,
891                                                 b->a_group_oc ))
892                                         {
893                                                 fprintf( stderr,
894                                                         "%s: line %d: group objectclass \"%s\" "
895                                                         "is subclass of alias\n",
896                                                         fname, lineno, value );
897                                                 acl_usage();
898                                         }
899
900                                         if (name && *name) {
901                                                 rc = slap_str2ad( name, &b->a_group_at, &text );
902
903                                                 if( rc != LDAP_SUCCESS ) {
904                                                         fprintf( stderr,
905                                                                 "%s: line %d: group \"%s\": %s\n",
906                                                                 fname, lineno, right, text );
907                                                         acl_usage();
908                                                 }
909                                                 *--name = '/';
910                                         } else {
911                                                 rc = slap_str2ad( SLAPD_GROUP_ATTR, &b->a_group_at, &text );
912
913                                                 if( rc != LDAP_SUCCESS ) {
914                                                         fprintf( stderr,
915                                                                 "%s: line %d: group \"%s\": %s\n",
916                                                                 fname, lineno, SLAPD_GROUP_ATTR, text );
917                                                         acl_usage();
918                                                 }
919                                         }
920
921                                         if( !is_at_syntax( b->a_group_at->ad_type,
922                                                 SLAPD_DN_SYNTAX ) &&
923                                             !is_at_syntax( b->a_group_at->ad_type,
924                                                 SLAPD_NAMEUID_SYNTAX ) &&
925                                                 !is_at_subtype( b->a_group_at->ad_type, slap_schema.si_ad_labeledURI->ad_type ))
926                                         {
927                                                 fprintf( stderr,
928                                                         "%s: line %d: group \"%s\": inappropriate syntax: %s\n",
929                                                         fname, lineno, right,
930                                                         b->a_group_at->ad_type->sat_syntax_oid );
931                                                 acl_usage();
932                                         }
933
934
935                                         {
936                                                 int rc;
937                                                 struct berval vals[2];
938
939                                                 vals[0].bv_val = b->a_group_oc->soc_oid;
940                                                 vals[0].bv_len = strlen(vals[0].bv_val);
941                                                 vals[1].bv_val = NULL;
942
943
944                                                 rc = oc_check_allowed( b->a_group_at->ad_type,
945                                                         vals, NULL );
946
947                                                 if( rc != 0 ) {
948                                                         fprintf( stderr, "%s: line %d: "
949                                                                 "group: \"%s\" not allowed by \"%s\"\n",
950                                                                 fname, lineno,
951                                                                 b->a_group_at->ad_cname.bv_val,
952                                                                 b->a_group_oc->soc_oid );
953                                                         acl_usage();
954                                                 }
955                                         }
956                                         continue;
957                                 }
958
959                                 if ( strcasecmp( left, "peername" ) == 0 ) {
960                                         switch (sty) {
961                                         case ACL_STYLE_REGEX:
962                                         case ACL_STYLE_BASE:
963                                                 /* legal, traditional */
964                                         case ACL_STYLE_EXPAND:
965                                                 /* cheap replacement to regex for simple expansion */
966                                         case ACL_STYLE_IP:
967                                         case ACL_STYLE_PATH:
968                                                 /* legal, peername specific */
969                                                 break;
970
971                                         default:
972                                                 fprintf( stderr, "%s: line %d: "
973                                                         "inappropriate style \"%s\" in by clause\n",
974                                                     fname, lineno, style );
975                                                 acl_usage();
976                                         }
977
978                                         if ( right == NULL || right[0] == '\0' ) {
979                                                 fprintf( stderr, "%s: line %d: "
980                                                         "missing \"=\" in (or value after) \"%s\" "
981                                                         "in by clause\n",
982                                                         fname, lineno, left );
983                                                 acl_usage();
984                                         }
985
986                                         if( b->a_peername_pat.bv_len ) {
987                                                 fprintf( stderr, "%s: line %d: "
988                                                         "peername pattern already specified.\n",
989                                                         fname, lineno );
990                                                 acl_usage();
991                                         }
992
993                                         b->a_peername_style = sty;
994                                         if (sty == ACL_STYLE_REGEX) {
995                                                 acl_regex_normalized_dn( right, &bv );
996                                                 if ( !ber_bvccmp( &bv, '*' ) ) {
997                                                         regtest(fname, lineno, bv.bv_val);
998                                                 }
999                                                 b->a_peername_pat = bv;
1000
1001                                         } else {
1002                                                 ber_str2bv( right, 0, 1, &b->a_peername_pat );
1003
1004                                                 if ( sty == ACL_STYLE_IP ) {
1005                                                         char            *addr = NULL,
1006                                                                         *mask = NULL,
1007                                                                         *port = NULL;
1008
1009                                                         split( right, '{', &addr, &port );
1010                                                         split( addr, '%', &addr, &mask );
1011
1012                                                         b->a_peername_addr = inet_addr( addr );
1013                                                         if ( b->a_peername_addr == (unsigned long)(-1)) {
1014                                                                 /* illegal address */
1015                                                                 fprintf( stderr, "%s: line %d: "
1016                                                                         "illegal peername address \"%s\".\n",
1017                                                                         fname, lineno, addr );
1018                                                                 acl_usage();
1019                                                         }
1020
1021                                                         b->a_peername_mask = (unsigned long)(-1);
1022                                                         if ( mask != NULL ) {
1023                                                                 b->a_peername_mask = inet_addr( mask );
1024                                                                 if ( b->a_peername_mask ==
1025                                                                         (unsigned long)(-1))
1026                                                                 {
1027                                                                         /* illegal mask */
1028                                                                         fprintf( stderr, "%s: line %d: "
1029                                                                                 "illegal peername address mask "
1030                                                                                 "\"%s\".\n",
1031                                                                                 fname, lineno, mask );
1032                                                                         acl_usage();
1033                                                                 }
1034                                                         } 
1035
1036                                                         b->a_peername_port = -1;
1037                                                         if ( port ) {
1038                                                                 char    *end = NULL;
1039
1040                                                                 b->a_peername_port = strtol( port, &end, 10 );
1041                                                                 if ( end[0] != '}' ) {
1042                                                                         /* illegal port */
1043                                                                         fprintf( stderr, "%s: line %d: "
1044                                                                                 "illegal peername port specification "
1045                                                                                 "\"{%s}\".\n",
1046                                                                                 fname, lineno, port );
1047                                                                         acl_usage();
1048                                                                 }
1049                                                         }
1050                                                 }
1051                                         }
1052                                         continue;
1053                                 }
1054
1055                                 if ( strcasecmp( left, "sockname" ) == 0 ) {
1056                                         switch (sty) {
1057                                         case ACL_STYLE_REGEX:
1058                                         case ACL_STYLE_BASE:
1059                                                 /* legal, traditional */
1060                                         case ACL_STYLE_EXPAND:
1061                                                 /* cheap replacement to regex for simple expansion */
1062                                                 break;
1063
1064                                         default:
1065                                                 /* unknown */
1066                                                 fprintf( stderr, "%s: line %d: "
1067                                                         "inappropriate style \"%s\" in by clause\n",
1068                                                     fname, lineno, style );
1069                                                 acl_usage();
1070                                         }
1071
1072                                         if ( right == NULL || right[0] == '\0' ) {
1073                                                 fprintf( stderr, "%s: line %d: "
1074                                                         "missing \"=\" in (or value after) \"%s\" "
1075                                                         "in by clause\n",
1076                                                         fname, lineno, left );
1077                                                 acl_usage();
1078                                         }
1079
1080                                         if( b->a_sockname_pat.bv_len ) {
1081                                                 fprintf( stderr, "%s: line %d: "
1082                                                         "sockname pattern already specified.\n",
1083                                                         fname, lineno );
1084                                                 acl_usage();
1085                                         }
1086
1087                                         b->a_sockname_style = sty;
1088                                         if (sty == ACL_STYLE_REGEX) {
1089                                                 acl_regex_normalized_dn( right, &bv );
1090                                                 if ( !ber_bvccmp( &bv, '*' ) ) {
1091                                                         regtest(fname, lineno, bv.bv_val);
1092                                                 }
1093                                                 b->a_sockname_pat = bv;
1094                                         } else {
1095                                                 ber_str2bv( right, 0, 1, &b->a_sockname_pat );
1096                                         }
1097                                         continue;
1098                                 }
1099
1100                                 if ( strcasecmp( left, "domain" ) == 0 ) {
1101                                         switch ( sty ) {
1102                                         case ACL_STYLE_REGEX:
1103                                         case ACL_STYLE_BASE:
1104                                         case ACL_STYLE_SUBTREE:
1105                                                 /* legal, traditional */
1106                                                 break;
1107
1108                                         case ACL_STYLE_EXPAND:
1109                                                 /* tolerated: means exact,expand */
1110                                                 if ( expand ) {
1111                                                         fprintf( stderr,
1112                                                                 "%s: line %d: "
1113                                                                 "\"expand\" modifier "
1114                                                                 "with \"expand\" style\n",
1115                                                                 fname, lineno );
1116                                                 }
1117                                                 sty = ACL_STYLE_BASE;
1118                                                 expand = 1;
1119                                                 break;
1120
1121                                         default:
1122                                                 /* unknown */
1123                                                 fprintf( stderr, "%s: line %d: "
1124                                                         "inappropriate style \"%s\" in by clause\n",
1125                                                     fname, lineno, style );
1126                                                 acl_usage();
1127                                         }
1128
1129                                         if ( right == NULL || right[0] == '\0' ) {
1130                                                 fprintf( stderr, "%s: line %d: "
1131                                                         "missing \"=\" in (or value after) \"%s\" "
1132                                                         "in by clause\n",
1133                                                         fname, lineno, left );
1134                                                 acl_usage();
1135                                         }
1136
1137                                         if( b->a_domain_pat.bv_len ) {
1138                                                 fprintf( stderr,
1139                                                         "%s: line %d: domain pattern already specified.\n",
1140                                                         fname, lineno );
1141                                                 acl_usage();
1142                                         }
1143
1144                                         b->a_domain_style = sty;
1145                                         b->a_domain_expand = expand;
1146                                         if (sty == ACL_STYLE_REGEX) {
1147                                                 acl_regex_normalized_dn( right, &bv );
1148                                                 if ( !ber_bvccmp( &bv, '*' ) ) {
1149                                                         regtest(fname, lineno, bv.bv_val);
1150                                                 }
1151                                                 b->a_domain_pat = bv;
1152                                         } else {
1153                                                 ber_str2bv( right, 0, 1, &b->a_domain_pat );
1154                                         }
1155                                         continue;
1156                                 }
1157
1158                                 if ( strcasecmp( left, "sockurl" ) == 0 ) {
1159                                         switch (sty) {
1160                                         case ACL_STYLE_REGEX:
1161                                         case ACL_STYLE_BASE:
1162                                                 /* legal, traditional */
1163                                         case ACL_STYLE_EXPAND:
1164                                                 /* cheap replacement to regex for simple expansion */
1165                                                 break;
1166
1167                                         default:
1168                                                 /* unknown */
1169                                                 fprintf( stderr, "%s: line %d: "
1170                                                         "inappropriate style \"%s\" in by clause\n",
1171                                                     fname, lineno, style );
1172                                                 acl_usage();
1173                                         }
1174
1175                                         if ( right == NULL || right[0] == '\0' ) {
1176                                                 fprintf( stderr, "%s: line %d: "
1177                                                         "missing \"=\" in (or value after) \"%s\" "
1178                                                         "in by clause\n",
1179                                                         fname, lineno, left );
1180                                                 acl_usage();
1181                                         }
1182
1183                                         if( b->a_sockurl_pat.bv_len ) {
1184                                                 fprintf( stderr,
1185                                                         "%s: line %d: sockurl pattern already specified.\n",
1186                                                         fname, lineno );
1187                                                 acl_usage();
1188                                         }
1189
1190                                         b->a_sockurl_style = sty;
1191                                         if (sty == ACL_STYLE_REGEX) {
1192                                                 acl_regex_normalized_dn( right, &bv );
1193                                                 if ( !ber_bvccmp( &bv, '*' ) ) {
1194                                                         regtest(fname, lineno, bv.bv_val);
1195                                                 }
1196                                                 b->a_sockurl_pat = bv;
1197                                         } else {
1198                                                 ber_str2bv( right, 0, 1, &b->a_sockurl_pat );
1199                                         }
1200                                         continue;
1201                                 }
1202
1203                                 if ( strcasecmp( left, "set" ) == 0 ) {
1204                                         switch ( sty ) {
1205                                                 /* deprecated */
1206                                         case ACL_STYLE_REGEX:
1207                                                 fprintf( stderr, "%s: line %d: "
1208                                                         "deprecated set style "
1209                                                         "\"regex\" in <by> clause; "
1210                                                         "use \"expand\" instead\n",
1211                                                         fname, lineno );
1212                                                 sty = ACL_STYLE_EXPAND;
1213                                                 /* FALLTHRU */
1214                                                 
1215                                         case ACL_STYLE_BASE:
1216                                         case ACL_STYLE_EXPAND:
1217                                                 break;
1218
1219                                         default:
1220                                                 fprintf( stderr, "%s: line %d: "
1221                                                         "inappropriate style \"%s\" in by clause\n",
1222                                                         fname, lineno, style );
1223                                                 acl_usage();
1224                                         }
1225
1226                                         if( b->a_set_pat.bv_len != 0 ) {
1227                                                 fprintf( stderr,
1228                                                         "%s: line %d: set attribute already specified.\n",
1229                                                         fname, lineno );
1230                                                 acl_usage();
1231                                         }
1232
1233                                         if ( right == NULL || *right == '\0' ) {
1234                                                 fprintf( stderr,
1235                                                         "%s: line %d: no set is defined\n",
1236                                                         fname, lineno );
1237                                                 acl_usage();
1238                                         }
1239
1240                                         b->a_set_style = sty;
1241                                         ber_str2bv( right, 0, 1, &b->a_set_pat );
1242
1243                                         continue;
1244                                 }
1245
1246 #ifdef SLAPD_ACI_ENABLED
1247                                 if ( strcasecmp( left, "aci" ) == 0 ) {
1248                                         if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) {
1249                                                 fprintf( stderr, "%s: line %d: "
1250                                                         "inappropriate style \"%s\" in by clause\n",
1251                                                     fname, lineno, style );
1252                                                 acl_usage();
1253                                         }
1254
1255                                         if( b->a_aci_at != NULL ) {
1256                                                 fprintf( stderr,
1257                                                         "%s: line %d: aci attribute already specified.\n",
1258                                                         fname, lineno );
1259                                                 acl_usage();
1260                                         }
1261
1262                                         if ( right != NULL && *right != '\0' ) {
1263                                                 rc = slap_str2ad( right, &b->a_aci_at, &text );
1264
1265                                                 if( rc != LDAP_SUCCESS ) {
1266                                                         fprintf( stderr,
1267                                                                 "%s: line %d: aci \"%s\": %s\n",
1268                                                                 fname, lineno, right, text );
1269                                                         acl_usage();
1270                                                 }
1271
1272                                         } else {
1273                                                 b->a_aci_at = slap_schema.si_ad_aci;
1274                                         }
1275
1276                                         if( !is_at_syntax( b->a_aci_at->ad_type,
1277                                                 SLAPD_ACI_SYNTAX) )
1278                                         {
1279                                                 fprintf( stderr, "%s: line %d: "
1280                                                         "aci \"%s\": inappropriate syntax: %s\n",
1281                                                         fname, lineno, right,
1282                                                         b->a_aci_at->ad_type->sat_syntax_oid );
1283                                                 acl_usage();
1284                                         }
1285
1286                                         continue;
1287                                 }
1288 #endif /* SLAPD_ACI_ENABLED */
1289
1290                                 if ( strcasecmp( left, "ssf" ) == 0 ) {
1291                                         if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) {
1292                                                 fprintf( stderr, "%s: line %d: "
1293                                                         "inappropriate style \"%s\" in by clause\n",
1294                                                     fname, lineno, style );
1295                                                 acl_usage();
1296                                         }
1297
1298                                         if( b->a_authz.sai_ssf ) {
1299                                                 fprintf( stderr,
1300                                                         "%s: line %d: ssf attribute already specified.\n",
1301                                                         fname, lineno );
1302                                                 acl_usage();
1303                                         }
1304
1305                                         if ( right == NULL || *right == '\0' ) {
1306                                                 fprintf( stderr,
1307                                                         "%s: line %d: no ssf is defined\n",
1308                                                         fname, lineno );
1309                                                 acl_usage();
1310                                         }
1311
1312                                         b->a_authz.sai_ssf = strtol( right, &next, 10 );
1313                                         if ( next == NULL || next[0] != '\0' ) {
1314                                                 fprintf( stderr,
1315                                                         "%s: line %d: unable to parse ssf value (%s)\n",
1316                                                         fname, lineno, right );
1317                                                 acl_usage();
1318                                         }
1319
1320                                         if( !b->a_authz.sai_ssf ) {
1321                                                 fprintf( stderr,
1322                                                         "%s: line %d: invalid ssf value (%s)\n",
1323                                                         fname, lineno, right );
1324                                                 acl_usage();
1325                                         }
1326                                         continue;
1327                                 }
1328
1329                                 if ( strcasecmp( left, "transport_ssf" ) == 0 ) {
1330                                         if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) {
1331                                                 fprintf( stderr, "%s: line %d: "
1332                                                         "inappropriate style \"%s\" in by clause\n",
1333                                                     fname, lineno, style );
1334                                                 acl_usage();
1335                                         }
1336
1337                                         if( b->a_authz.sai_transport_ssf ) {
1338                                                 fprintf( stderr, "%s: line %d: "
1339                                                         "transport_ssf attribute already specified.\n",
1340                                                         fname, lineno );
1341                                                 acl_usage();
1342                                         }
1343
1344                                         if ( right == NULL || *right == '\0' ) {
1345                                                 fprintf( stderr,
1346                                                         "%s: line %d: no transport_ssf is defined\n",
1347                                                         fname, lineno );
1348                                                 acl_usage();
1349                                         }
1350
1351                                         b->a_authz.sai_transport_ssf = strtol( right, &next, 10 );
1352                                         if ( next == NULL || next[0] != '\0' ) {
1353                                                 fprintf( stderr, "%s: line %d: "
1354                                                         "unable to parse transport_ssf value (%s)\n",
1355                                                         fname, lineno, right );
1356                                                 acl_usage();
1357                                         }
1358
1359                                         if( !b->a_authz.sai_transport_ssf ) {
1360                                                 fprintf( stderr,
1361                                                         "%s: line %d: invalid transport_ssf value (%s)\n",
1362                                                         fname, lineno, right );
1363                                                 acl_usage();
1364                                         }
1365                                         continue;
1366                                 }
1367
1368                                 if ( strcasecmp( left, "tls_ssf" ) == 0 ) {
1369                                         if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) {
1370                                                 fprintf( stderr, "%s: line %d: "
1371                                                         "inappropriate style \"%s\" in by clause\n",
1372                                                     fname, lineno, style );
1373                                                 acl_usage();
1374                                         }
1375
1376                                         if( b->a_authz.sai_tls_ssf ) {
1377                                                 fprintf( stderr, "%s: line %d: "
1378                                                         "tls_ssf attribute already specified.\n",
1379                                                         fname, lineno );
1380                                                 acl_usage();
1381                                         }
1382
1383                                         if ( right == NULL || *right == '\0' ) {
1384                                                 fprintf( stderr,
1385                                                         "%s: line %d: no tls_ssf is defined\n",
1386                                                         fname, lineno );
1387                                                 acl_usage();
1388                                         }
1389
1390                                         b->a_authz.sai_tls_ssf = strtol( right, &next, 10 );
1391                                         if ( next == NULL || next[0] != '\0' ) {
1392                                                 fprintf( stderr, "%s: line %d: "
1393                                                         "unable to parse tls_ssf value (%s)\n",
1394                                                         fname, lineno, right );
1395                                                 acl_usage();
1396                                         }
1397
1398                                         if( !b->a_authz.sai_tls_ssf ) {
1399                                                 fprintf( stderr,
1400                                                         "%s: line %d: invalid tls_ssf value (%s)\n",
1401                                                         fname, lineno, right );
1402                                                 acl_usage();
1403                                         }
1404                                         continue;
1405                                 }
1406
1407                                 if ( strcasecmp( left, "sasl_ssf" ) == 0 ) {
1408                                         if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) {
1409                                                 fprintf( stderr, "%s: line %d: "
1410                                                         "inappropriate style \"%s\" in by clause\n",
1411                                                     fname, lineno, style );
1412                                                 acl_usage();
1413                                         }
1414
1415                                         if( b->a_authz.sai_sasl_ssf ) {
1416                                                 fprintf( stderr, "%s: line %d: "
1417                                                         "sasl_ssf attribute already specified.\n",
1418                                                         fname, lineno );
1419                                                 acl_usage();
1420                                         }
1421
1422                                         if ( right == NULL || *right == '\0' ) {
1423                                                 fprintf( stderr,
1424                                                         "%s: line %d: no sasl_ssf is defined\n",
1425                                                         fname, lineno );
1426                                                 acl_usage();
1427                                         }
1428
1429                                         b->a_authz.sai_sasl_ssf = strtol( right, &next, 10 );
1430                                         if ( next == NULL || next[0] != '\0' ) {
1431                                                 fprintf( stderr, "%s: line %d: "
1432                                                         "unable to parse sasl_ssf value (%s)\n",
1433                                                         fname, lineno, right );
1434                                                 acl_usage();
1435                                         }
1436
1437                                         if( !b->a_authz.sai_sasl_ssf ) {
1438                                                 fprintf( stderr,
1439                                                         "%s: line %d: invalid sasl_ssf value (%s)\n",
1440                                                         fname, lineno, right );
1441                                                 acl_usage();
1442                                         }
1443                                         continue;
1444                                 }
1445
1446                                 if( right != NULL ) {
1447                                         /* unsplit */
1448                                         right[-1] = '=';
1449                                 }
1450                                 break;
1451                         }
1452
1453                         if( i == argc || ( strcasecmp( left, "stop" ) == 0 )) { 
1454                                 /* out of arguments or plain stop */
1455
1456                                 ACL_PRIV_ASSIGN(b->a_access_mask, ACL_PRIV_ADDITIVE);
1457                                 b->a_type = ACL_STOP;
1458
1459                                 access_append( &a->acl_access, b );
1460                                 continue;
1461                         }
1462
1463                         if( strcasecmp( left, "continue" ) == 0 ) {
1464                                 /* plain continue */
1465
1466                                 ACL_PRIV_ASSIGN(b->a_access_mask, ACL_PRIV_ADDITIVE);
1467                                 b->a_type = ACL_CONTINUE;
1468
1469                                 access_append( &a->acl_access, b );
1470                                 continue;
1471                         }
1472
1473                         if( strcasecmp( left, "break" ) == 0 ) {
1474                                 /* plain continue */
1475
1476                                 ACL_PRIV_ASSIGN(b->a_access_mask, ACL_PRIV_ADDITIVE);
1477                                 b->a_type = ACL_BREAK;
1478
1479                                 access_append( &a->acl_access, b );
1480                                 continue;
1481                         }
1482
1483                         if ( strcasecmp( left, "by" ) == 0 ) {
1484                                 /* we've gone too far */
1485                                 --i;
1486                                 ACL_PRIV_ASSIGN(b->a_access_mask, ACL_PRIV_ADDITIVE);
1487                                 b->a_type = ACL_STOP;
1488
1489                                 access_append( &a->acl_access, b );
1490                                 continue;
1491                         }
1492
1493                         /* get <access> */
1494                         if( strncasecmp( left, "self", 4 ) == 0 ) {
1495                                 b->a_dn_self = 1;
1496                                 ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( &left[4] ) );
1497
1498                         } else {
1499                                 ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( left ) );
1500                         }
1501
1502                         if( ACL_IS_INVALID( b->a_access_mask ) ) {
1503                                 fprintf( stderr,
1504                                         "%s: line %d: expecting <access> got \"%s\"\n",
1505                                         fname, lineno, left );
1506                                 acl_usage();
1507                         }
1508
1509                         b->a_type = ACL_STOP;
1510
1511                         if( ++i == argc ) {
1512                                 /* out of arguments or plain stop */
1513                                 access_append( &a->acl_access, b );
1514                                 continue;
1515                         }
1516
1517                         if( strcasecmp( argv[i], "continue" ) == 0 ) {
1518                                 /* plain continue */
1519                                 b->a_type = ACL_CONTINUE;
1520
1521                         } else if( strcasecmp( argv[i], "break" ) == 0 ) {
1522                                 /* plain continue */
1523                                 b->a_type = ACL_BREAK;
1524
1525                         } else if ( strcasecmp( argv[i], "stop" ) != 0 ) {
1526                                 /* gone to far */
1527                                 i--;
1528                         }
1529
1530                         access_append( &a->acl_access, b );
1531
1532                 } else {
1533                         fprintf( stderr,
1534                     "%s: line %d: expecting \"to\" or \"by\" got \"%s\"\n",
1535                             fname, lineno, argv[i] );
1536                         acl_usage();
1537                 }
1538         }
1539
1540         /* if we have no real access clause, complain and do nothing */
1541         if ( a == NULL ) {
1542                 fprintf( stderr, "%s: line %d: "
1543                         "warning: no access clause(s) specified in access line\n",
1544                         fname, lineno );
1545
1546         } else {
1547 #ifdef LDAP_DEBUG
1548                 if (ldap_debug & LDAP_DEBUG_ACL) print_acl(be, a);
1549 #endif
1550         
1551                 if ( a->acl_access == NULL ) {
1552                         fprintf( stderr, "%s: line %d: "
1553                                 "warning: no by clause(s) specified in access line\n",
1554                             fname, lineno );
1555                 }
1556
1557                 if ( be != NULL ) {
1558 #ifdef LDAP_DEVEL
1559                         switch ( check_scope( be, a ) ) {
1560                         case ACL_SCOPE_UNKNOWN:
1561                                 fprintf( stderr, "%s: line %d: warning: "
1562                                         "cannot assess the validity of the ACL scope within "
1563                                         "backend naming context\n",
1564                                         fname, lineno );
1565                                 break;
1566
1567                         case ACL_SCOPE_WARN:
1568                                 fprintf( stderr, "%s: line %d: warning: "
1569                                         "ACL could be out of scope within backend naming context\n",
1570                                         fname, lineno );
1571                                 break;
1572
1573                         case ACL_SCOPE_PARTIAL:
1574                                 fprintf( stderr, "%s: line %d: warning: "
1575                                         "ACL appears to be partially out of scope within "
1576                                         "backend naming context\n",
1577                                         fname, lineno );
1578                                 break;
1579
1580                         case ACL_SCOPE_ERR:
1581                                 fprintf( stderr, "%s: line %d: warning: "
1582                                         "ACL appears to be out of scope within "
1583                                         "backend naming context\n",
1584                                         fname, lineno );
1585                                 break;
1586
1587                         default:
1588                                 break;
1589                         }
1590 #endif /* LDAP_DEVEL */
1591                         acl_append( &be->be_acl, a );
1592                 } else {
1593                         acl_append( &frontendDB->be_acl, a );
1594                 }
1595         }
1596 }
1597
1598 char *
1599 accessmask2str( slap_mask_t mask, char *buf )
1600 {
1601         int none=1;
1602         char *ptr = buf;
1603
1604         assert( buf != NULL );
1605
1606         if ( ACL_IS_INVALID( mask ) ) {
1607                 return "invalid";
1608         }
1609
1610         buf[0] = '\0';
1611
1612         if ( ACL_IS_LEVEL( mask ) ) {
1613                 if ( ACL_LVL_IS_NONE(mask) ) {
1614                         ptr = lutil_strcopy( ptr, "none" );
1615
1616                 } else if ( ACL_LVL_IS_AUTH(mask) ) {
1617                         ptr = lutil_strcopy( ptr, "auth" );
1618
1619                 } else if ( ACL_LVL_IS_COMPARE(mask) ) {
1620                         ptr = lutil_strcopy( ptr, "compare" );
1621
1622                 } else if ( ACL_LVL_IS_SEARCH(mask) ) {
1623                         ptr = lutil_strcopy( ptr, "search" );
1624
1625                 } else if ( ACL_LVL_IS_READ(mask) ) {
1626                         ptr = lutil_strcopy( ptr, "read" );
1627
1628                 } else if ( ACL_LVL_IS_WRITE(mask) ) {
1629                         ptr = lutil_strcopy( ptr, "write" );
1630                 } else {
1631                         ptr = lutil_strcopy( ptr, "unknown" );
1632                 }
1633                 
1634                 *ptr++ = '(';
1635         }
1636
1637         if( ACL_IS_ADDITIVE( mask ) ) {
1638                 *ptr++ = '+';
1639
1640         } else if( ACL_IS_SUBTRACTIVE( mask ) ) {
1641                 *ptr++ = '-';
1642
1643         } else {
1644                 *ptr++ = '=';
1645         }
1646
1647         if ( ACL_PRIV_ISSET(mask, ACL_PRIV_WRITE) ) {
1648                 none = 0;
1649                 *ptr++ = 'w';
1650         } 
1651
1652         if ( ACL_PRIV_ISSET(mask, ACL_PRIV_READ) ) {
1653                 none = 0;
1654                 *ptr++ = 'r';
1655         } 
1656
1657         if ( ACL_PRIV_ISSET(mask, ACL_PRIV_SEARCH) ) {
1658                 none = 0;
1659                 *ptr++ = 's';
1660         } 
1661
1662         if ( ACL_PRIV_ISSET(mask, ACL_PRIV_COMPARE) ) {
1663                 none = 0;
1664                 *ptr++ = 'c';
1665         } 
1666
1667         if ( ACL_PRIV_ISSET(mask, ACL_PRIV_AUTH) ) {
1668                 none = 0;
1669                 *ptr++ = 'x';
1670         } 
1671
1672         if ( none && ACL_PRIV_ISSET(mask, ACL_PRIV_NONE) ) {
1673                 none = 0;
1674                 *ptr++ = 'n';
1675         } 
1676
1677         if ( none ) {
1678                 *ptr++ = '0';
1679         }
1680
1681         if ( ACL_IS_LEVEL( mask ) ) {
1682                 *ptr++ = ')';
1683         }
1684
1685         *ptr = '\0';
1686
1687         return buf;
1688 }
1689
1690 slap_mask_t
1691 str2accessmask( const char *str )
1692 {
1693         slap_mask_t     mask;
1694
1695         if( !ASCII_ALPHA(str[0]) ) {
1696                 int i;
1697
1698                 if ( str[0] == '=' ) {
1699                         ACL_INIT(mask);
1700
1701                 } else if( str[0] == '+' ) {
1702                         ACL_PRIV_ASSIGN(mask, ACL_PRIV_ADDITIVE);
1703
1704                 } else if( str[0] == '-' ) {
1705                         ACL_PRIV_ASSIGN(mask, ACL_PRIV_SUBSTRACTIVE);
1706
1707                 } else {
1708                         ACL_INVALIDATE(mask);
1709                         return mask;
1710                 }
1711
1712                 for( i=1; str[i] != '\0'; i++ ) {
1713                         if( TOLOWER((unsigned char) str[i]) == 'w' ) {
1714                                 ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
1715
1716                         } else if( TOLOWER((unsigned char) str[i]) == 'r' ) {
1717                                 ACL_PRIV_SET(mask, ACL_PRIV_READ);
1718
1719                         } else if( TOLOWER((unsigned char) str[i]) == 's' ) {
1720                                 ACL_PRIV_SET(mask, ACL_PRIV_SEARCH);
1721
1722                         } else if( TOLOWER((unsigned char) str[i]) == 'c' ) {
1723                                 ACL_PRIV_SET(mask, ACL_PRIV_COMPARE);
1724
1725                         } else if( TOLOWER((unsigned char) str[i]) == 'x' ) {
1726                                 ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
1727
1728                         } else if( str[i] != '0' ) {
1729                                 ACL_INVALIDATE(mask);
1730                                 return mask;
1731                         }
1732                 }
1733
1734                 return mask;
1735         }
1736
1737         if ( strcasecmp( str, "none" ) == 0 ) {
1738                 ACL_LVL_ASSIGN_NONE(mask);
1739
1740         } else if ( strcasecmp( str, "auth" ) == 0 ) {
1741                 ACL_LVL_ASSIGN_AUTH(mask);
1742
1743         } else if ( strcasecmp( str, "compare" ) == 0 ) {
1744                 ACL_LVL_ASSIGN_COMPARE(mask);
1745
1746         } else if ( strcasecmp( str, "search" ) == 0 ) {
1747                 ACL_LVL_ASSIGN_SEARCH(mask);
1748
1749         } else if ( strcasecmp( str, "read" ) == 0 ) {
1750                 ACL_LVL_ASSIGN_READ(mask);
1751
1752         } else if ( strcasecmp( str, "write" ) == 0 ) {
1753                 ACL_LVL_ASSIGN_WRITE(mask);
1754
1755         } else {
1756                 ACL_INVALIDATE( mask );
1757         }
1758
1759         return mask;
1760 }
1761
1762 static void
1763 acl_usage( void )
1764 {
1765         fprintf( stderr, "%s%s%s\n",
1766                 "<access clause> ::= access to <what> "
1767                                 "[ by <who> <access> [ <control> ] ]+ \n"
1768                 "<what> ::= * | [dn[.<dnstyle>]=<DN>] [filter=<filter>] [attrs=<attrlist>]\n"
1769                 "<attrlist> ::= <attr> [val[.<style>]=<value>] | <attr> , <attrlist>\n"
1770                 "<attr> ::= <attrname> | entry | children\n",
1771                 "<who> ::= [ * | anonymous | users | self | dn[.<dnstyle>]=<DN> ]\n"
1772                         "\t[dnattr=<attrname>]\n"
1773                         "\t[group[/<objectclass>[/<attrname>]][.<style>]=<group>]\n"
1774                         "\t[peername[.<peernamestyle>]=<peer>] [sockname[.<style>]=<name>]\n"
1775                         "\t[domain[.<domainstyle>]=<domain>] [sockurl[.<style>]=<url>]\n"
1776 #ifdef SLAPD_ACI_ENABLED
1777                         "\t[aci=<attrname>]\n"
1778 #endif
1779                         "\t[ssf=<n>] [transport_ssf=<n>] [tls_ssf=<n>] [sasl_ssf=<n>]\n",
1780                 "<dnstyle> ::= base(Object) | one(level) | sub(tree) | children | "
1781                         "exact | regex\n"
1782                 "<style> ::= exact | regex | base(Object)\n"
1783                 "<peernamestyle> ::= exact | regex | ip | path\n"
1784                 "<domainstyle> ::= exact | regex | base(Object) | sub(tree)\n"
1785                 "<access> ::= [self]{<level>|<priv>}\n"
1786                 "<level> ::= none | auth | compare | search | read | write\n"
1787                 "<priv> ::= {=|+|-}{w|r|s|c|x|0}+\n"
1788                 "<control> ::= [ stop | continue | break ]\n"
1789         );
1790         exit( EXIT_FAILURE );
1791 }
1792
1793 /*
1794  * Set pattern to a "normalized" DN from src.
1795  * At present it simply eats the (optional) space after 
1796  * a RDN separator (,)
1797  * Eventually will evolve in a more complete normalization
1798  */
1799 static void
1800 acl_regex_normalized_dn(
1801         const char *src,
1802         struct berval *pattern )
1803 {
1804         char *str, *p;
1805         ber_len_t len;
1806
1807         str = ch_strdup( src );
1808         len = strlen( src );
1809
1810         for ( p = str; p && p[0]; p++ ) {
1811                 /* escape */
1812                 if ( p[0] == '\\' && p[1] ) {
1813                         /* 
1814                          * if escaping a hex pair we should
1815                          * increment p twice; however, in that 
1816                          * case the second hex number does 
1817                          * no harm
1818                          */
1819                         p++;
1820                 }
1821
1822                 if ( p[0] == ',' && p[1] == ' ' ) {
1823                         char *q;
1824                         
1825                         /*
1826                          * too much space should be an error if we are pedantic
1827                          */
1828                         for ( q = &p[2]; q[0] == ' '; q++ ) {
1829                                 /* DO NOTHING */ ;
1830                         }
1831                         AC_MEMCPY( p+1, q, len-(q-str)+1);
1832                 }
1833         }
1834         pattern->bv_val = str;
1835         pattern->bv_len = p-str;
1836
1837         return;
1838 }
1839
1840 static void
1841 split(
1842     char        *line,
1843     int         splitchar,
1844     char        **left,
1845     char        **right )
1846 {
1847         *left = line;
1848         if ( (*right = strchr( line, splitchar )) != NULL ) {
1849                 *((*right)++) = '\0';
1850         }
1851 }
1852
1853 static void
1854 access_append( Access **l, Access *a )
1855 {
1856         for ( ; *l != NULL; l = &(*l)->a_next ) {
1857                 ;       /* Empty */
1858         }
1859
1860         *l = a;
1861 }
1862
1863 void
1864 acl_append( AccessControl **l, AccessControl *a )
1865 {
1866         for ( ; *l != NULL; l = &(*l)->acl_next ) {
1867                 ;       /* Empty */
1868         }
1869
1870         *l = a;
1871 }
1872
1873 static void
1874 access_free( Access *a )
1875 {
1876         if ( a->a_dn_pat.bv_val ) free ( a->a_dn_pat.bv_val );
1877         if ( a->a_peername_pat.bv_val ) free ( a->a_peername_pat.bv_val );
1878         if ( a->a_sockname_pat.bv_val ) free ( a->a_sockname_pat.bv_val );
1879         if ( a->a_domain_pat.bv_val ) free ( a->a_domain_pat.bv_val );
1880         if ( a->a_sockurl_pat.bv_val ) free ( a->a_sockurl_pat.bv_val );
1881         if ( a->a_set_pat.bv_len ) free ( a->a_set_pat.bv_val );
1882         if ( a->a_group_pat.bv_len ) free ( a->a_group_pat.bv_val );
1883         free( a );
1884 }
1885
1886 void
1887 acl_free( AccessControl *a )
1888 {
1889         Access *n;
1890         AttributeName *an;
1891
1892         if ( a->acl_filter ) filter_free( a->acl_filter );
1893         if ( a->acl_dn_pat.bv_len ) free ( a->acl_dn_pat.bv_val );
1894         if ( a->acl_attrs ) {
1895                 for ( an = a->acl_attrs; an->an_name.bv_val; an++ ) {
1896                         free( an->an_name.bv_val );
1897                 }
1898                 free( a->acl_attrs );
1899         }
1900         for (; a->acl_access; a->acl_access = n) {
1901                 n = a->acl_access->a_next;
1902                 access_free( a->acl_access );
1903         }
1904         free( a );
1905 }
1906
1907 /* Because backend_startup uses acl_append to tack on the global_acl to
1908  * the end of each backend's acl, we cannot just take one argument and
1909  * merrily free our way to the end of the list. backend_destroy calls us
1910  * with the be_acl in arg1, and global_acl in arg2 to give us a stopping
1911  * point. config_destroy calls us with global_acl in arg1 and NULL in
1912  * arg2, so we then proceed to polish off the global_acl.
1913  */
1914 void
1915 acl_destroy( AccessControl *a, AccessControl *end )
1916 {
1917         AccessControl *n;
1918
1919         for (; a && a!= end; a=n) {
1920                 n = a->acl_next;
1921                 acl_free( a );
1922         }
1923 }
1924
1925 char *
1926 access2str( slap_access_t access )
1927 {
1928         if ( access == ACL_NONE ) {
1929                 return "none";
1930
1931         } else if ( access == ACL_AUTH ) {
1932                 return "auth";
1933
1934         } else if ( access == ACL_COMPARE ) {
1935                 return "compare";
1936
1937         } else if ( access == ACL_SEARCH ) {
1938                 return "search";
1939
1940         } else if ( access == ACL_READ ) {
1941                 return "read";
1942
1943         } else if ( access == ACL_WRITE ) {
1944                 return "write";
1945         }
1946
1947         return "unknown";
1948 }
1949
1950 slap_access_t
1951 str2access( const char *str )
1952 {
1953         if ( strcasecmp( str, "none" ) == 0 ) {
1954                 return ACL_NONE;
1955
1956         } else if ( strcasecmp( str, "auth" ) == 0 ) {
1957                 return ACL_AUTH;
1958
1959         } else if ( strcasecmp( str, "compare" ) == 0 ) {
1960                 return ACL_COMPARE;
1961
1962         } else if ( strcasecmp( str, "search" ) == 0 ) {
1963                 return ACL_SEARCH;
1964
1965         } else if ( strcasecmp( str, "read" ) == 0 ) {
1966                 return ACL_READ;
1967
1968         } else if ( strcasecmp( str, "write" ) == 0 ) {
1969                 return ACL_WRITE;
1970         }
1971
1972         return( ACL_INVALID_ACCESS );
1973 }
1974
1975 #ifdef LDAP_DEBUG
1976
1977 static void
1978 print_access( Access *b )
1979 {
1980         char maskbuf[ACCESSMASK_MAXLEN];
1981
1982         fprintf( stderr, "\tby" );
1983
1984         if ( b->a_dn_pat.bv_len != 0 ) {
1985                 if ( ber_bvccmp( &b->a_dn_pat, '*' ) ||
1986                         strcmp(b->a_dn_pat.bv_val, "users") == 0 ||
1987                         strcmp(b->a_dn_pat.bv_val, "anonymous") == 0 ||
1988                         strcmp(b->a_dn_pat.bv_val, "self") == 0 )
1989                 {
1990                         fprintf( stderr, " %s", b->a_dn_pat.bv_val );
1991
1992                 } else {
1993                         fprintf( stderr, " dn.%s=\"%s\"",
1994                                 style_strings[b->a_dn_style], b->a_dn_pat.bv_val );
1995                 }
1996         }
1997
1998         if ( b->a_dn_at != NULL ) {
1999                 fprintf( stderr, " dnattr=%s", b->a_dn_at->ad_cname.bv_val );
2000         }
2001
2002         if ( b->a_group_pat.bv_len ) {
2003                 fprintf( stderr, " group/%s/%s.%s=\"%s\"",
2004                         b->a_group_oc ? b->a_group_oc->soc_cname.bv_val : "groupOfNames",
2005                         b->a_group_at ? b->a_group_at->ad_cname.bv_val : "member",
2006                         style_strings[b->a_group_style],
2007                         b->a_group_pat.bv_val );
2008     }
2009
2010         if ( b->a_peername_pat.bv_len != 0 ) {
2011                 fprintf( stderr, " peername=\"%s\"", b->a_peername_pat.bv_val );
2012         }
2013
2014         if ( b->a_sockname_pat.bv_len != 0 ) {
2015                 fprintf( stderr, " sockname=\"%s\"", b->a_sockname_pat.bv_val );
2016         }
2017
2018         if ( b->a_domain_pat.bv_len != 0 ) {
2019                 fprintf( stderr, " domain=%s", b->a_domain_pat.bv_val );
2020         }
2021
2022         if ( b->a_sockurl_pat.bv_len != 0 ) {
2023                 fprintf( stderr, " sockurl=\"%s\"", b->a_sockurl_pat.bv_val );
2024         }
2025
2026         if ( b->a_set_pat.bv_len != 0 ) {
2027                 fprintf( stderr, " set=\"%s\"", b->a_set_pat.bv_val );
2028         }
2029
2030 #ifdef SLAPD_ACI_ENABLED
2031         if ( b->a_aci_at != NULL ) {
2032                 fprintf( stderr, " aci=%s", b->a_aci_at->ad_cname.bv_val );
2033         }
2034 #endif
2035
2036         /* Security Strength Factors */
2037         if ( b->a_authz.sai_ssf ) {
2038                 fprintf( stderr, " ssf=%u",
2039                         b->a_authz.sai_ssf );
2040         }
2041         if ( b->a_authz.sai_transport_ssf ) {
2042                 fprintf( stderr, " transport_ssf=%u",
2043                         b->a_authz.sai_transport_ssf );
2044         }
2045         if ( b->a_authz.sai_tls_ssf ) {
2046                 fprintf( stderr, " tls_ssf=%u",
2047                         b->a_authz.sai_tls_ssf );
2048         }
2049         if ( b->a_authz.sai_sasl_ssf ) {
2050                 fprintf( stderr, " sasl_ssf=%u",
2051                         b->a_authz.sai_sasl_ssf );
2052         }
2053
2054         fprintf( stderr, " %s%s",
2055                 b->a_dn_self ? "self" : "",
2056                 accessmask2str( b->a_access_mask, maskbuf ) );
2057
2058         if( b->a_type == ACL_BREAK ) {
2059                 fprintf( stderr, " break" );
2060
2061         } else if( b->a_type == ACL_CONTINUE ) {
2062                 fprintf( stderr, " continue" );
2063
2064         } else if( b->a_type != ACL_STOP ) {
2065                 fprintf( stderr, " unknown-control" );
2066         }
2067
2068         fprintf( stderr, "\n" );
2069 }
2070
2071
2072 static void
2073 print_acl( Backend *be, AccessControl *a )
2074 {
2075         int             to = 0;
2076         Access  *b;
2077
2078         fprintf( stderr, "%s ACL: access to",
2079                 be == NULL ? "Global" : "Backend" );
2080
2081         if ( a->acl_dn_pat.bv_len != 0 ) {
2082                 to++;
2083                 fprintf( stderr, " dn.%s=\"%s\"\n",
2084                         style_strings[a->acl_dn_style], a->acl_dn_pat.bv_val );
2085         }
2086
2087         if ( a->acl_filter != NULL ) {
2088                 struct berval bv = BER_BVNULL;
2089                 to++;
2090                 filter2bv( a->acl_filter, &bv );
2091                 fprintf( stderr, " filter=%s\n", bv.bv_val );
2092                 ch_free( bv.bv_val );
2093         }
2094
2095         if ( a->acl_attrs != NULL ) {
2096                 int     first = 1;
2097                 AttributeName *an;
2098                 to++;
2099
2100                 fprintf( stderr, " attrs=" );
2101                 for ( an = a->acl_attrs; an && an->an_name.bv_val; an++ ) {
2102                         if ( ! first ) fprintf( stderr, "," );
2103                         if (an->an_oc) {
2104                                 fputc( an->an_oc_exclude ? '!' : '@', stderr);
2105                         }
2106                         fputs( an->an_name.bv_val, stderr );
2107                         first = 0;
2108                 }
2109                 fprintf(  stderr, "\n" );
2110         }
2111
2112         if ( a->acl_attrval.bv_len != 0 ) {
2113                 to++;
2114                 fprintf( stderr, " val.%s=\"%s\"\n",
2115                         style_strings[a->acl_attrval_style], a->acl_attrval.bv_val );
2116
2117         }
2118
2119         if( !to ) fprintf( stderr, " *\n" );
2120
2121         for ( b = a->acl_access; b != NULL; b = b->a_next ) {
2122                 print_access( b );
2123         }
2124
2125         fprintf( stderr, "\n" );
2126 }
2127 #endif /* LDAP_DEBUG */