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