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