]> git.sur5r.net Git - openldap/blob - servers/slapd/aclparse.c
Fix bug in group spec parsing, was failing to set attributeType if a
[openldap] / servers / slapd / aclparse.c
1 /* acl.c - routines to parse and check acl's */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/ctype.h>
13 #include <ac/regex.h>
14 #include <ac/socket.h>
15 #include <ac/string.h>
16 #include <ac/unistd.h>
17
18 #include "slap.h"
19
20 static void             split(char *line, int splitchar, char **left, char **right);
21 static void             access_append(Access **l, Access *a);
22 static void             acl_usage(void) LDAP_GCCATTR((noreturn));
23
24 #ifdef LDAP_DEBUG
25 static void             print_acl(Backend *be, AccessControl *a);
26 static void             print_access(Access *b);
27 #endif
28
29 static int
30 regtest(const char *fname, int lineno, char *pat) {
31         int e;
32         regex_t re;
33
34         char buf[512];
35         unsigned size;
36
37         char *sp;
38         char *dp;
39         int  flag;
40
41         sp = pat;
42         dp = buf;
43         size = 0;
44         buf[0] = '\0';
45
46         for (size = 0, flag = 0; (size < sizeof(buf)) && *sp; sp++) {
47                 if (flag) {
48                         if (*sp == '$'|| (*sp >= '0' && *sp <= '9')) {
49                                 *dp++ = *sp;
50                                 size++;
51                         }
52                         flag = 0;
53
54                 } else {
55                         if (*sp == '$') {
56                                 flag = 1;
57                         } else {
58                                 *dp++ = *sp;
59                                 size++;
60                         }
61                 }
62         }
63
64         *dp = '\0';
65         if ( size >= (sizeof(buf)-1) ) {
66                 fprintf( stderr,
67                         "%s: line %d: regular expression \"%s\" too large\n",
68                         fname, lineno, pat );
69                 acl_usage();
70         }
71
72         if ((e = regcomp(&re, buf, REG_EXTENDED|REG_ICASE))) {
73                 char error[512];
74                 regerror(e, &re, error, sizeof(error));
75                 fprintf( stderr,
76                         "%s: line %d: regular expression \"%s\" bad because of %s\n",
77                         fname, lineno, pat, error );
78                 acl_usage();
79                 return(0);
80         }
81         regfree(&re);
82         return(1);
83 }
84
85 void
86 parse_acl(
87     Backend     *be,
88     const char  *fname,
89     int         lineno,
90     int         argc,
91     char        **argv
92 )
93 {
94         int             i;
95         char            *left, *right;
96         AccessControl   *a;
97         Access  *b;
98
99         a = NULL;
100         for ( i = 1; i < argc; i++ ) {
101                 /* to clause - select which entries are protected */
102                 if ( strcasecmp( argv[i], "to" ) == 0 ) {
103                         if ( a != NULL ) {
104                                 fprintf( stderr,
105                 "%s: line %d: only one to clause allowed in access line\n",
106                                     fname, lineno );
107                                 acl_usage();
108                         }
109                         a = (AccessControl *) ch_calloc( 1, sizeof(AccessControl) );
110                         a->acl_filter = NULL;
111                         a->acl_dn_pat = NULL;
112                         a->acl_attrs  = NULL;
113                         a->acl_access = NULL;
114                         a->acl_next   = NULL;
115                         for ( ++i; i < argc; i++ ) {
116                                 if ( strcasecmp( argv[i], "by" ) == 0 ) {
117                                         i--;
118                                         break;
119                                 }
120
121                                 if ( strcasecmp( argv[i], "*" ) == 0 ) {
122                                         if( a->acl_dn_pat != NULL ) {
123                                                 fprintf( stderr,
124                                                         "%s: line %d: dn pattern"
125                                                         " already specified in to clause.\n",
126                                                         fname, lineno );
127                                                 acl_usage();
128                                         }
129
130                                         a->acl_dn_pat = ch_strdup( "*" );
131                                         continue;
132                                 }
133
134                                 split( argv[i], '=', &left, &right );
135
136                                 if ( strcasecmp( left, "dn" ) == 0 ) {
137                                         if( a->acl_dn_pat != NULL ) {
138                                                 fprintf( stderr,
139                                                         "%s: line %d: dn pattern"
140                                                         " already specified in to clause.\n",
141                                                         fname, lineno );
142                                                 acl_usage();
143                                         }
144
145                                         if ( right == NULL ) {
146                                                 fprintf( stderr,
147         "%s: line %d: missing \"=\" in \"%s\" in to clause\n",
148                                                     fname, lineno, left );
149                                                 acl_usage();
150                                         }
151
152                                         if( *right == '\0' ) {
153                                                 a->acl_dn_pat = ch_strdup("^$");
154
155                                         } else if ( strcmp(right, "*") == 0 
156                                                 || strcmp(right, ".*") == 0 
157                                                 || strcmp(right, ".*$") == 0 
158                                                 || strcmp(right, "^.*") == 0 
159                                                 || strcmp(right, "^.*$$") == 0
160                                                 || strcmp(right, ".*$$") == 0 
161                                                 || strcmp(right, "^.*$$") == 0 )
162                                         {
163                                                 a->acl_dn_pat = ch_strdup( "*" );
164
165                                         } else {
166                                                 a->acl_dn_pat = ch_strdup( right );
167                                         }
168
169                                         continue;
170                                 }
171
172                                 if ( right == NULL || *right == '\0' ) {
173                                         fprintf( stderr,
174         "%s: line %d: missing \"=\" in (or value after) \"%s\" in to clause\n",
175                                             fname, lineno, left );
176                                         acl_usage();
177                                 }
178
179                                 if ( strcasecmp( left, "filter" ) == 0 ) {
180                                         if ( (a->acl_filter = str2filter(
181                                             right )) == NULL ) {
182                                                 fprintf( stderr,
183                                 "%s: line %d: bad filter \"%s\" in to clause\n",
184                                                     fname, lineno, right );
185                                                 acl_usage();
186                                         }
187
188                                 } else if ( strncasecmp( left, "attr", 4 ) == 0 ) {
189                                         char    **alist;
190
191                                         alist = str2charray( right, "," );
192                                         charray_merge( &a->acl_attrs, alist );
193                                         charray_free( alist );
194
195                                 } else {
196                                         fprintf( stderr,
197                                                 "%s: line %d: expecting <what> got \"%s\"\n",
198                                             fname, lineno, left );
199                                         acl_usage();
200                                 }
201                         }
202
203                         if ( a->acl_dn_pat != NULL && strcmp(a->acl_dn_pat, "*") == 0) {
204                                 free( a->acl_dn_pat );
205                                 a->acl_dn_pat = NULL;
206                         }
207                         
208                         if( a->acl_dn_pat != NULL ) {
209                                 int e = regcomp( &a->acl_dn_re, a->acl_dn_pat,
210                                                  REG_EXTENDED | REG_ICASE );
211                                 if ( e ) {
212                                         char buf[512];
213                                         regerror( e, &a->acl_dn_re, buf, sizeof(buf) );
214                                         fprintf( stderr,
215                                 "%s: line %d: regular expression \"%s\" bad because of %s\n",
216                                                  fname, lineno, right, buf );
217                                         acl_usage();
218                                 }
219                         }
220
221                 /* by clause - select who has what access to entries */
222                 } else if ( strcasecmp( argv[i], "by" ) == 0 ) {
223                         if ( a == NULL ) {
224                                 fprintf( stderr,
225                                         "%s: line %d: to clause required before by clause in access line\n",
226                                     fname, lineno );
227                                 acl_usage();
228                         }
229
230                         /*
231                          * by clause consists of <who> and <access>
232                          */
233
234                         b = (Access *) ch_calloc( 1, sizeof(Access) );
235
236                         ACL_INVALIDATE( b->a_mask );
237
238                         if ( ++i == argc ) {
239                                 fprintf( stderr,
240                             "%s: line %d: premature eol: expecting <who>\n",
241                                     fname, lineno );
242                                 acl_usage();
243                         }
244
245                         /* get <who> */
246                         for ( ; i < argc; i++ ) {
247                                 char *pat;
248                                 split( argv[i], '=', &left, &right );
249
250                                 if ( strcasecmp( argv[i], "*" ) == 0 ) {
251                                         pat = ch_strdup( "*" );
252
253                                 } else if ( strcasecmp( argv[i], "anonymous" ) == 0 ) {
254                                         pat = ch_strdup( "anonymous" );
255
256                                 } else if ( strcasecmp( argv[i], "self" ) == 0 ) {
257                                         pat = ch_strdup( "self" );
258
259                                 } else if ( strcasecmp( argv[i], "users" ) == 0 ) {
260                                         pat = ch_strdup( "users" );
261
262                                 } else if ( strcasecmp( left, "dn" ) == 0 ) {
263                                         if( right == NULL ) {
264                                                 /* no '=' */
265                                                 pat = ch_strdup( "users" );
266
267                                         } else if (*right == '\0' ) {
268                                                 /* dn="" */
269                                                 pat = ch_strdup( "anonymous" );
270
271                                         } else if ( strcmp( right, "*" ) == 0 ) {
272                                                 /* dn=* /
273                                                 /* any or users?  any for now */
274                                                 pat = ch_strdup( "users" );
275
276                                         } else if ( strcmp( right, ".+" ) == 0
277                                                 || strcmp( right, "^.+" ) == 0
278                                                 || strcmp( right, ".+$" ) == 0
279                                                 || strcmp( right, "^.+$" ) == 0
280                                                 || strcmp( right, ".+$$" ) == 0
281                                                 || strcmp( right, "^.+$$" ) == 0 )
282                                         {
283                                                 pat = ch_strdup( "users" );
284
285                                         } else if ( strcmp( right, ".*" ) == 0
286                                                 || strcmp( right, "^.*" ) == 0
287                                                 || strcmp( right, ".*$" ) == 0
288                                                 || strcmp( right, "^.*$" ) == 0
289                                                 || strcmp( right, ".*$$" ) == 0
290                                                 || strcmp( right, "^.*$$" ) == 0 )
291                                         {
292                                                 pat = ch_strdup( "*" );
293
294                                         } else {
295                                                 regtest(fname, lineno, right);
296                                                 pat = ch_strdup( right );
297                                         }
298
299                                 } else {
300                                         pat = NULL;
301                                 }
302
303                                 if( pat != NULL ) {
304                                         if( b->a_dn_pat != NULL ) {
305                                                 fprintf( stderr,
306                                                     "%s: line %d: dn pattern already specified.\n",
307                                                     fname, lineno );
308                                                 acl_usage();
309                                         }
310
311                                         b->a_dn_pat = pat;
312                                         continue;
313                                 }
314
315                                 if ( strcasecmp( left, "dnattr" ) == 0 ) {
316                                         if( b->a_dn_pat != NULL ) {
317                                                 fprintf( stderr,
318                                                         "%s: line %d: dnaddr already specified.\n",
319                                                         fname, lineno );
320                                                 acl_usage();
321                                         }
322
323                                         b->a_dn_at = ch_strdup( right );
324                                         continue;
325                                 }
326
327                                 if ( strncasecmp( left, "group", sizeof("group")-1 ) == 0 ) {
328                                         char *name = NULL;
329                                         char *value = NULL;
330
331                                         if( b->a_group_pat != NULL ) {
332                                                 fprintf( stderr,
333                                                         "%s: line %d: group pattern already specified.\n",
334                                                         fname, lineno );
335                                                 acl_usage();
336                                         }
337
338                                         /* format of string is "group/objectClassValue/groupAttrName" */
339                                         if ((value = strchr(left, '/')) != NULL) {
340                                                 *value++ = '\0';
341                                                 if (*value
342                                                         && (name = strchr(value, '/')) != NULL)
343                                                 {
344                                                         *name++ = '\0';
345                                                 }
346                                         }
347
348                                         regtest(fname, lineno, right);
349                                         b->a_group_pat = ch_strdup( right );
350
351                                         if (value && *value) {
352                                                 b->a_group_oc = ch_strdup(value);
353                                                 *--value = '/';
354                                         } else {
355                                                 b->a_group_oc = ch_strdup("groupOfNames");
356                                         }
357
358                                         if (name && *name) {
359                                                 b->a_group_at = ch_strdup(name);
360                                                 *--name = '/';
361
362                                         } else {
363                                                 b->a_group_at = ch_strdup("member");
364                                         }
365                                         continue;
366                                 }
367
368                                 if ( strcasecmp( left, "peername" ) == 0 ) {
369                                         if( b->a_peername_pat != NULL ) {
370                                                 fprintf( stderr,
371                                                         "%s: line %d: peername pattern already specified.\n",
372                                                         fname, lineno );
373                                                 acl_usage();
374                                         }
375
376                                         regtest(fname, lineno, right);
377                                         b->a_peername_pat = ch_strdup( right );
378                                         continue;
379                                 }
380
381                                 if ( strcasecmp( left, "sockname" ) == 0 ) {
382                                         if( b->a_sockname_pat != NULL ) {
383                                                 fprintf( stderr,
384                                                         "%s: line %d: sockname pattern already specified.\n",
385                                                         fname, lineno );
386                                                 acl_usage();
387                                         }
388
389                                         regtest(fname, lineno, right);
390                                         b->a_sockname_pat = ch_strdup( right );
391                                         continue;
392                                 }
393
394                                 if ( strcasecmp( left, "domain" ) == 0 ) {
395                                         if( b->a_domain_pat != NULL ) {
396                                                 fprintf( stderr,
397                                                         "%s: line %d: domain pattern already specified.\n",
398                                                         fname, lineno );
399                                                 acl_usage();
400                                         }
401
402                                         regtest(fname, lineno, right);
403                                         b->a_domain_pat = ch_strdup( right );
404                                         continue;
405                                 }
406
407                                 if ( strcasecmp( left, "sockurl" ) == 0 ) {
408                                         if( b->a_sockurl_pat != NULL ) {
409                                                 fprintf( stderr,
410                                                         "%s: line %d: sockurl pattern already specified.\n",
411                                                         fname, lineno );
412                                                 acl_usage();
413                                         }
414
415                                         regtest(fname, lineno, right);
416                                         b->a_sockurl_pat = ch_strdup( right );
417                                         continue;
418                                 }
419
420 #ifdef SLAPD_ACI_ENABLED
421                                 if ( strcasecmp( left, "aci" ) == 0 ) {
422                                         if( b->a_aci_at != NULL ) {
423                                                 fprintf( stderr,
424                                                         "%s: line %d: aci attribute already specified.\n",
425                                                         fname, lineno );
426                                                 acl_usage();
427                                         }
428
429                                         if ( right != NULL && *right != '\0' )
430                                                 b->a_aci_at = ch_strdup( right );
431                                         else
432                                                 b->a_aci_at = ch_strdup( SLAPD_ACI_DEFAULT_ATTR );
433                                         continue;
434                                 }
435 #endif
436
437                                 if( right != NULL ) {
438                                         /* unsplit */
439                                         right[-1] = '=';
440                                 }
441                                 break;
442                         }
443
444                         if( i == argc || ( strcasecmp( left, "stop" ) == 0 )) { 
445                                 /* out of arguments or plain stop */
446
447                                 ACL_PRIV_ASSIGN(b->a_mask, ACL_PRIV_ADDITIVE);
448                                 b->a_type = ACL_STOP;
449
450                                 access_append( &a->acl_access, b );
451                                 continue;
452                         }
453
454                         if( strcasecmp( left, "continue" ) == 0 ) {
455                                 /* plain continue */
456
457                                 ACL_PRIV_ASSIGN(b->a_mask, ACL_PRIV_ADDITIVE);
458                                 b->a_type = ACL_CONTINUE;
459
460                                 access_append( &a->acl_access, b );
461                                 continue;
462                         }
463
464                         if( strcasecmp( left, "break" ) == 0 ) {
465                                 /* plain continue */
466
467                                 ACL_PRIV_ASSIGN(b->a_mask, ACL_PRIV_ADDITIVE);
468                                 b->a_type = ACL_BREAK;
469
470                                 access_append( &a->acl_access, b );
471                                 continue;
472                         }
473
474                         if ( strcasecmp( left, "by" ) == 0 ) {
475                                 /* we've gone too far */
476                                 --i;
477                                 ACL_PRIV_ASSIGN(b->a_mask, ACL_PRIV_ADDITIVE);
478                                 b->a_type = ACL_STOP;
479
480                                 access_append( &a->acl_access, b );
481                                 continue;
482                         }
483
484                         /* get <access> */
485                         if( strncasecmp( left, "self", 4 ) == 0 ) {
486                                 b->a_dn_self = 1;
487                                 ACL_PRIV_ASSIGN( b->a_mask, str2accessmask( &left[4] ) );
488
489                         } else {
490                                 ACL_PRIV_ASSIGN( b->a_mask, str2accessmask( left ) );
491                         }
492
493                         if( ACL_IS_INVALID( b->a_mask ) ) {
494                                 fprintf( stderr,
495                                         "%s: line %d: expecting <access> got \"%s\"\n",
496                                         fname, lineno, left );
497                                 acl_usage();
498                         }
499
500                         b->a_type = ACL_STOP;
501
502                         if( ++i == argc ) {
503                                 /* out of arguments or plain stop */
504                                 access_append( &a->acl_access, b );
505                                 continue;
506                         }
507
508                         if( strcasecmp( argv[i], "continue" ) == 0 ) {
509                                 /* plain continue */
510                                 b->a_type = ACL_CONTINUE;
511
512                         } else if( strcasecmp( argv[i], "break" ) == 0 ) {
513                                 /* plain continue */
514                                 b->a_type = ACL_BREAK;
515
516                         } else if ( strcasecmp( argv[i], "stop" ) != 0 ) {
517                                 /* gone to far */
518                                 i--;
519                         }
520
521                         access_append( &a->acl_access, b );
522
523                 } else {
524                         fprintf( stderr,
525                     "%s: line %d: expecting \"to\" or \"by\" got \"%s\"\n",
526                             fname, lineno, argv[i] );
527                         acl_usage();
528                 }
529         }
530
531         /* if we have no real access clause, complain and do nothing */
532         if ( a == NULL ) {
533                         fprintf( stderr,
534                                 "%s: line %d: warning: no access clause(s) specified in access line\n",
535                             fname, lineno );
536
537         } else {
538 #ifdef LDAP_DEBUG
539                 if (ldap_debug & LDAP_DEBUG_ACL)
540                         print_acl(be, a);
541 #endif
542         
543                 if ( a->acl_access == NULL ) {
544                         fprintf( stderr,
545                         "%s: line %d: warning: no by clause(s) specified in access line\n",
546                             fname, lineno );
547                 }
548
549                 if ( be != NULL ) {
550                         acl_append( &be->be_acl, a );
551                 } else {
552                         acl_append( &global_acl, a );
553                 }
554         }
555 }
556
557 char *
558 accessmask2str( slap_access_mask_t mask, char *buf )
559 {
560         int none=1;
561
562         assert( buf != NULL );
563
564         if ( ACL_IS_INVALID( mask ) ) {
565                 return "invalid";
566         }
567
568         buf[0] = '\0';
569
570         if ( ACL_IS_LEVEL( mask ) ) {
571                 if ( ACL_LVL_IS_NONE(mask) ) {
572                         strcat( buf, "none" );
573
574                 } else if ( ACL_LVL_IS_AUTH(mask) ) {
575                         strcat( buf, "auth" );
576
577                 } else if ( ACL_LVL_IS_COMPARE(mask) ) {
578                         strcat( buf, "compare" );
579
580                 } else if ( ACL_LVL_IS_SEARCH(mask) ) {
581                         strcat( buf, "search" );
582
583                 } else if ( ACL_LVL_IS_READ(mask) ) {
584                         strcat( buf, "read" );
585
586                 } else if ( ACL_LVL_IS_WRITE(mask) ) {
587                         strcat( buf, "write" );
588                 } else {
589                         strcat( buf, "unknown" );
590                 }
591                 
592                 strcat(buf, " (");
593         }
594
595         if( ACL_IS_ADDITIVE( mask ) ) {
596                 strcat( buf, "+" );
597
598         } else if( ACL_IS_SUBTRACTIVE( mask ) ) {
599                 strcat( buf, "-" );
600
601         } else {
602                 strcat( buf, "=" );
603         }
604
605         if ( ACL_PRIV_ISSET(mask, ACL_PRIV_WRITE) ) {
606                 none = 0;
607                 strcat( buf, "w" );
608         } 
609
610         if ( ACL_PRIV_ISSET(mask, ACL_PRIV_READ) ) {
611                 none = 0;
612                 strcat( buf, "r" );
613         } 
614
615         if ( ACL_PRIV_ISSET(mask, ACL_PRIV_SEARCH) ) {
616                 none = 0;
617                 strcat( buf, "s" );
618         } 
619
620         if ( ACL_PRIV_ISSET(mask, ACL_PRIV_COMPARE) ) {
621                 none = 0;
622                 strcat( buf, "c" );
623         } 
624
625         if ( ACL_PRIV_ISSET(mask, ACL_PRIV_AUTH) ) {
626                 none = 0;
627                 strcat( buf, "x" );
628         } 
629
630         if ( none && ACL_PRIV_ISSET(mask, ACL_PRIV_NONE) ) {
631                 none = 0;
632                 strcat( buf, "n" );
633         } 
634
635         if ( none ) {
636                 strcat( buf, "0" );
637         }
638
639         if ( ACL_IS_LEVEL( mask ) ) {
640                 strcat(buf, ")");
641         } 
642         return buf;
643 }
644
645 slap_access_mask_t
646 str2accessmask( const char *str )
647 {
648         slap_access_mask_t      mask;
649
650         if( !isalpha(str[0]) ) {
651                 int i;
652
653                 if ( str[0] == '=' ) {
654                         ACL_INIT(mask);
655
656                 } else if( str[0] == '+' ) {
657                         ACL_PRIV_ASSIGN(mask, ACL_PRIV_ADDITIVE);
658
659                 } else if( str[0] == '-' ) {
660                         ACL_PRIV_ASSIGN(mask, ACL_PRIV_SUBSTRACTIVE);
661
662                 } else {
663                         ACL_INVALIDATE(mask);
664                         return mask;
665                 }
666
667                 for( i=1; str[i] != '\0'; i++ ) {
668                         if( TOLOWER(str[i]) == 'w' ) {
669                                 ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
670
671                         } else if( TOLOWER(str[i]) == 'r' ) {
672                                 ACL_PRIV_SET(mask, ACL_PRIV_READ);
673
674                         } else if( TOLOWER(str[i]) == 's' ) {
675                                 ACL_PRIV_SET(mask, ACL_PRIV_SEARCH);
676
677                         } else if( TOLOWER(str[i]) == 'c' ) {
678                                 ACL_PRIV_SET(mask, ACL_PRIV_COMPARE);
679
680                         } else if( TOLOWER(str[i]) == 'x' ) {
681                                 ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
682
683                         } else if( str[i] != '0' ) {
684                                 ACL_INVALIDATE(mask);
685                                 return mask;
686                         }
687                 }
688
689                 return mask;
690         }
691
692         if ( strcasecmp( str, "none" ) == 0 ) {
693                 ACL_LVL_ASSIGN_NONE(mask);
694
695         } else if ( strcasecmp( str, "auth" ) == 0 ) {
696                 ACL_LVL_ASSIGN_AUTH(mask);
697
698         } else if ( strcasecmp( str, "compare" ) == 0 ) {
699                 ACL_LVL_ASSIGN_COMPARE(mask);
700
701         } else if ( strcasecmp( str, "search" ) == 0 ) {
702                 ACL_LVL_ASSIGN_SEARCH(mask);
703
704         } else if ( strcasecmp( str, "read" ) == 0 ) {
705                 ACL_LVL_ASSIGN_READ(mask);
706
707         } else if ( strcasecmp( str, "write" ) == 0 ) {
708                 ACL_LVL_ASSIGN_WRITE(mask);
709
710         } else {
711                 ACL_INVALIDATE( mask );
712         }
713
714         return mask;
715 }
716
717 static void
718 acl_usage( void )
719 {
720         fprintf( stderr, "\n"
721                 "<access clause> ::= access to <what> "
722                                 "[ by <who> <access> <control> ]+ \n"
723                 "<what> ::= * | [dn=<regex>] [filter=<ldapfilter>] [attrs=<attrlist>]\n"
724                 "<attrlist> ::= <attr> | <attr> , <attrlist>\n"
725                 "<attr> ::= <attrname> | entry | children\n"
726                 "<who> ::= [ * | anonymous | users | self | dn=<regex> ]\n"
727                         "\t[dnattr=<attrname>]\n"
728                         "\t[group[/<objectclass>[/<attrname>]]=<regex>]\n"
729                         "\t[peername=<regex>] [sockname=<regex>]\n"
730                         "\t[domain=<regex>] [sockurl=<regex>]\n"
731 #ifdef SLAPD_ACI_ENABLED
732                         "\t[aci=<attrname>]\n"
733 #endif
734                 "<access> ::= [self]{<level>|<priv>}\n"
735                 "<level> ::= none | auth | compare | search | read | write\n"
736                 "<priv> ::= {=|+|-}{w|r|s|c|x}+\n"
737                 "<control> ::= [ stop | continue | break ]\n"
738                 );
739         exit( EXIT_FAILURE );
740 }
741
742 static void
743 split(
744     char        *line,
745     int         splitchar,
746     char        **left,
747     char        **right
748 )
749 {
750         *left = line;
751         if ( (*right = strchr( line, splitchar )) != NULL ) {
752                 *((*right)++) = '\0';
753         }
754 }
755
756 static void
757 access_append( Access **l, Access *a )
758 {
759         for ( ; *l != NULL; l = &(*l)->a_next )
760                 ;       /* NULL */
761
762         *l = a;
763 }
764
765 void
766 acl_append( AccessControl **l, AccessControl *a )
767 {
768         for ( ; *l != NULL; l = &(*l)->acl_next )
769                 ;       /* NULL */
770
771         *l = a;
772 }
773
774 char *
775 access2str( slap_access_t access )
776 {
777         if ( access == ACL_NONE ) {
778                 return "none";
779
780         } else if ( access == ACL_AUTH ) {
781                 return "auth";
782
783         } else if ( access == ACL_COMPARE ) {
784                 return "compare";
785
786         } else if ( access == ACL_SEARCH ) {
787                 return "search";
788
789         } else if ( access == ACL_READ ) {
790                 return "read";
791
792         } else if ( access == ACL_WRITE ) {
793                 return "write";
794         }
795
796         return "unknown";
797 }
798
799 slap_access_t
800 str2access( const char *str )
801 {
802         if ( strcasecmp( str, "none" ) == 0 ) {
803                 return ACL_NONE;
804
805         } else if ( strcasecmp( str, "auth" ) == 0 ) {
806                 return ACL_AUTH;
807
808         } else if ( strcasecmp( str, "compare" ) == 0 ) {
809                 return ACL_COMPARE;
810
811         } else if ( strcasecmp( str, "search" ) == 0 ) {
812                 return ACL_SEARCH;
813
814         } else if ( strcasecmp( str, "read" ) == 0 ) {
815                 return ACL_READ;
816
817         } else if ( strcasecmp( str, "write" ) == 0 ) {
818                 return ACL_WRITE;
819         }
820
821         return( ACL_INVALID_ACCESS );
822 }
823
824 #ifdef LDAP_DEBUG
825
826 static void
827 print_access( Access *b )
828 {
829         char maskbuf[ACCESSMASK_MAXLEN];
830
831         fprintf( stderr, "\tby" );
832
833         if ( b->a_dn_pat != NULL ) {
834                 if( strcmp(b->a_dn_pat, "*") == 0
835                         || strcmp(b->a_dn_pat, "users") == 0 
836                         || strcmp(b->a_dn_pat, "anonymous") == 0 
837                         || strcmp(b->a_dn_pat, "self") == 0 )
838                 {
839                         fprintf( stderr, " %s", b->a_dn_pat );
840
841                 } else {
842                         fprintf( stderr, " dn=%s", b->a_dn_pat );
843                 }
844         }
845
846         if ( b->a_dn_at != NULL ) {
847                 fprintf( stderr, " dnattr=%s", b->a_dn_at );
848         }
849
850         if ( b->a_group_pat != NULL ) {
851                 fprintf( stderr, " group: %s", b->a_group_pat );
852
853                 if ( b->a_group_oc ) {
854                         fprintf( stderr, " objectClass: %s", b->a_group_oc );
855
856                         if ( b->a_group_at ) {
857                                 fprintf( stderr, " attributeType: %s", b->a_group_at );
858                         }
859                 }
860     }
861
862         if ( b->a_peername_pat != NULL ) {
863                 fprintf( stderr, " peername=%s", b->a_peername_pat );
864         }
865
866         if ( b->a_sockname_pat != NULL ) {
867                 fprintf( stderr, " sockname=%s", b->a_sockname_pat );
868         }
869
870         if ( b->a_domain_pat != NULL ) {
871                 fprintf( stderr, " domain=%s", b->a_domain_pat );
872         }
873
874         if ( b->a_sockurl_pat != NULL ) {
875                 fprintf( stderr, " sockurl=%s", b->a_sockurl_pat );
876         }
877
878 #ifdef SLAPD_ACI_ENABLED
879         if ( b->a_aci_at != NULL ) {
880                 fprintf( stderr, " aci=%s", b->a_aci_at );
881         }
882 #endif
883
884         fprintf( stderr, " %s%s",
885                 b->a_dn_self ? "self" : "",
886                 accessmask2str( b->a_mask, maskbuf ) );
887
888         if( b->a_type == ACL_BREAK ) {
889                 fprintf( stderr, " break" );
890
891         } else if( b->a_type == ACL_CONTINUE ) {
892                 fprintf( stderr, " continue" );
893
894         } else if( b->a_type != ACL_STOP ) {
895                 fprintf( stderr, " unknown-control" );
896         }
897
898         fprintf( stderr, "\n" );
899 }
900
901
902 static void
903 print_acl( Backend *be, AccessControl *a )
904 {
905         int             to = 0;
906         Access  *b;
907
908         fprintf( stderr, "%s ACL: access to",
909                 be == NULL ? "Global" : "Backend" );
910
911         if ( a->acl_dn_pat != NULL ) {
912                 to++;
913                 fprintf( stderr, " dn=%s\n",
914                         a->acl_dn_pat );
915         }
916
917         if ( a->acl_filter != NULL ) {
918                 to++;
919                 fprintf( stderr, " filter=" );
920                 filter_print( a->acl_filter );
921                 fprintf( stderr, "\n" );
922         }
923
924         if ( a->acl_attrs != NULL ) {
925                 int     i, first = 1;
926                 to++;
927
928                 fprintf( stderr, " attrs=" );
929                 for ( i = 0; a->acl_attrs[i] != NULL; i++ ) {
930                         if ( ! first ) {
931                                 fprintf( stderr, "," );
932                         }
933                         fprintf( stderr, a->acl_attrs[i] );
934                         first = 0;
935                 }
936                 fprintf(  stderr, "\n" );
937         }
938
939         if( !to ) {
940                 fprintf( stderr, " *\n" );
941         }
942
943         for ( b = a->acl_access; b != NULL; b = b->a_next ) {
944                 print_access( b );
945         }
946
947         fprintf( stderr, "\n" );
948 }
949
950 #endif /* LDAP_DEBUG */