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