]> git.sur5r.net Git - openldap/blob - servers/slapd/aclparse.c
Fix anonymous mapping
[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("anonymous");
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?  users 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( !is_at_syntax( b->a_dn_at->ad_type,
339                                                 SLAPD_DN_SYNTAX ) )
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(SLAPD_GROUP_CLASS);
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, SLAPD_GROUP_CLASS );
403                                                         acl_usage();
404                                                 }
405 #else
406                                                 b->a_group_oc = ch_strdup(SLAPD_GROUP_CLASS);
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( SLAPD_GROUP_ATTR, &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, SLAPD_GROUP_ATTR, text );
456                                                         acl_usage();
457                                                 }
458 #else
459                                                 b->a_group_at = ch_strdup( SLAPD_GROUP_ATTR );
460 #endif
461                                         }
462
463 #ifdef SLAPD_SCHEMA_NOT_COMPAT
464                                         if( !is_at_syntax( b->a_group_at->ad_type,
465                                                 SLAPD_DN_SYNTAX ) )
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                                         } else {
574                                                 rc = slap_str2ad( SLAPD_ACI_ATTR, &b->a_aci_at, &text );
575
576                                                 if( rc != LDAP_SUCCESS ) {
577                                                         fprintf( stderr,
578                                                                 "%s: line %d: aci \"%s\": %s\n",
579                                                                 fname, lineno, SLAPD_ACI_ATTR, text );
580                                                         acl_usage();
581                                                 }
582                                         }
583
584                                         if( !is_at_syntax( b->a_aci_at->ad_type,
585                                                 SLAPD_ACI_SYNTAX) )
586                                         {
587                                                 fprintf( stderr,
588                                                         "%s: line %d: aci \"%s\": inappropriate syntax: %s\n",
589                                                         fname, lineno, right,
590                                                         b->a_aci_at->ad_type->sat_syntax_oid );
591                                                 acl_usage();
592                                         }
593
594 #else
595                                         if ( right != NULL && *right != '\0' ) {
596                                                 b->a_aci_at = ch_strdup( right );
597                                         } else {
598                                                 b->a_aci_at = ch_strdup( SLAPD_ACI_ATTR );
599                                         }
600 #endif
601                                         continue;
602                                 }
603 #endif /* SLAPD_ACI_ENABLED */
604
605                                 if( right != NULL ) {
606                                         /* unsplit */
607                                         right[-1] = '=';
608                                 }
609                                 break;
610                         }
611
612                         if( i == argc || ( strcasecmp( left, "stop" ) == 0 )) { 
613                                 /* out of arguments or plain stop */
614
615                                 ACL_PRIV_ASSIGN(b->a_mask, ACL_PRIV_ADDITIVE);
616                                 b->a_type = ACL_STOP;
617
618                                 access_append( &a->acl_access, b );
619                                 continue;
620                         }
621
622                         if( strcasecmp( left, "continue" ) == 0 ) {
623                                 /* plain continue */
624
625                                 ACL_PRIV_ASSIGN(b->a_mask, ACL_PRIV_ADDITIVE);
626                                 b->a_type = ACL_CONTINUE;
627
628                                 access_append( &a->acl_access, b );
629                                 continue;
630                         }
631
632                         if( strcasecmp( left, "break" ) == 0 ) {
633                                 /* plain continue */
634
635                                 ACL_PRIV_ASSIGN(b->a_mask, ACL_PRIV_ADDITIVE);
636                                 b->a_type = ACL_BREAK;
637
638                                 access_append( &a->acl_access, b );
639                                 continue;
640                         }
641
642                         if ( strcasecmp( left, "by" ) == 0 ) {
643                                 /* we've gone too far */
644                                 --i;
645                                 ACL_PRIV_ASSIGN(b->a_mask, ACL_PRIV_ADDITIVE);
646                                 b->a_type = ACL_STOP;
647
648                                 access_append( &a->acl_access, b );
649                                 continue;
650                         }
651
652                         /* get <access> */
653                         if( strncasecmp( left, "self", 4 ) == 0 ) {
654                                 b->a_dn_self = 1;
655                                 ACL_PRIV_ASSIGN( b->a_mask, str2accessmask( &left[4] ) );
656
657                         } else {
658                                 ACL_PRIV_ASSIGN( b->a_mask, str2accessmask( left ) );
659                         }
660
661                         if( ACL_IS_INVALID( b->a_mask ) ) {
662                                 fprintf( stderr,
663                                         "%s: line %d: expecting <access> got \"%s\"\n",
664                                         fname, lineno, left );
665                                 acl_usage();
666                         }
667
668                         b->a_type = ACL_STOP;
669
670                         if( ++i == argc ) {
671                                 /* out of arguments or plain stop */
672                                 access_append( &a->acl_access, b );
673                                 continue;
674                         }
675
676                         if( strcasecmp( argv[i], "continue" ) == 0 ) {
677                                 /* plain continue */
678                                 b->a_type = ACL_CONTINUE;
679
680                         } else if( strcasecmp( argv[i], "break" ) == 0 ) {
681                                 /* plain continue */
682                                 b->a_type = ACL_BREAK;
683
684                         } else if ( strcasecmp( argv[i], "stop" ) != 0 ) {
685                                 /* gone to far */
686                                 i--;
687                         }
688
689                         access_append( &a->acl_access, b );
690
691                 } else {
692                         fprintf( stderr,
693                     "%s: line %d: expecting \"to\" or \"by\" got \"%s\"\n",
694                             fname, lineno, argv[i] );
695                         acl_usage();
696                 }
697         }
698
699         /* if we have no real access clause, complain and do nothing */
700         if ( a == NULL ) {
701                         fprintf( stderr,
702                                 "%s: line %d: warning: no access clause(s) specified in access line\n",
703                             fname, lineno );
704
705         } else {
706 #ifdef LDAP_DEBUG
707                 if (ldap_debug & LDAP_DEBUG_ACL)
708                         print_acl(be, a);
709 #endif
710         
711                 if ( a->acl_access == NULL ) {
712                         fprintf( stderr,
713                         "%s: line %d: warning: no by clause(s) specified in access line\n",
714                             fname, lineno );
715                 }
716
717                 if ( be != NULL ) {
718                         acl_append( &be->be_acl, a );
719                 } else {
720                         acl_append( &global_acl, a );
721                 }
722         }
723 }
724
725 char *
726 accessmask2str( slap_access_mask_t mask, char *buf )
727 {
728         int none=1;
729
730         assert( buf != NULL );
731
732         if ( ACL_IS_INVALID( mask ) ) {
733                 return "invalid";
734         }
735
736         buf[0] = '\0';
737
738         if ( ACL_IS_LEVEL( mask ) ) {
739                 if ( ACL_LVL_IS_NONE(mask) ) {
740                         strcat( buf, "none" );
741
742                 } else if ( ACL_LVL_IS_AUTH(mask) ) {
743                         strcat( buf, "auth" );
744
745                 } else if ( ACL_LVL_IS_COMPARE(mask) ) {
746                         strcat( buf, "compare" );
747
748                 } else if ( ACL_LVL_IS_SEARCH(mask) ) {
749                         strcat( buf, "search" );
750
751                 } else if ( ACL_LVL_IS_READ(mask) ) {
752                         strcat( buf, "read" );
753
754                 } else if ( ACL_LVL_IS_WRITE(mask) ) {
755                         strcat( buf, "write" );
756                 } else {
757                         strcat( buf, "unknown" );
758                 }
759                 
760                 strcat(buf, " (");
761         }
762
763         if( ACL_IS_ADDITIVE( mask ) ) {
764                 strcat( buf, "+" );
765
766         } else if( ACL_IS_SUBTRACTIVE( mask ) ) {
767                 strcat( buf, "-" );
768
769         } else {
770                 strcat( buf, "=" );
771         }
772
773         if ( ACL_PRIV_ISSET(mask, ACL_PRIV_WRITE) ) {
774                 none = 0;
775                 strcat( buf, "w" );
776         } 
777
778         if ( ACL_PRIV_ISSET(mask, ACL_PRIV_READ) ) {
779                 none = 0;
780                 strcat( buf, "r" );
781         } 
782
783         if ( ACL_PRIV_ISSET(mask, ACL_PRIV_SEARCH) ) {
784                 none = 0;
785                 strcat( buf, "s" );
786         } 
787
788         if ( ACL_PRIV_ISSET(mask, ACL_PRIV_COMPARE) ) {
789                 none = 0;
790                 strcat( buf, "c" );
791         } 
792
793         if ( ACL_PRIV_ISSET(mask, ACL_PRIV_AUTH) ) {
794                 none = 0;
795                 strcat( buf, "x" );
796         } 
797
798         if ( none && ACL_PRIV_ISSET(mask, ACL_PRIV_NONE) ) {
799                 none = 0;
800                 strcat( buf, "n" );
801         } 
802
803         if ( none ) {
804                 strcat( buf, "0" );
805         }
806
807         if ( ACL_IS_LEVEL( mask ) ) {
808                 strcat(buf, ")");
809         } 
810         return buf;
811 }
812
813 slap_access_mask_t
814 str2accessmask( const char *str )
815 {
816         slap_access_mask_t      mask;
817
818         if( !isalpha(str[0]) ) {
819                 int i;
820
821                 if ( str[0] == '=' ) {
822                         ACL_INIT(mask);
823
824                 } else if( str[0] == '+' ) {
825                         ACL_PRIV_ASSIGN(mask, ACL_PRIV_ADDITIVE);
826
827                 } else if( str[0] == '-' ) {
828                         ACL_PRIV_ASSIGN(mask, ACL_PRIV_SUBSTRACTIVE);
829
830                 } else {
831                         ACL_INVALIDATE(mask);
832                         return mask;
833                 }
834
835                 for( i=1; str[i] != '\0'; i++ ) {
836                         if( TOLOWER(str[i]) == 'w' ) {
837                                 ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
838
839                         } else if( TOLOWER(str[i]) == 'r' ) {
840                                 ACL_PRIV_SET(mask, ACL_PRIV_READ);
841
842                         } else if( TOLOWER(str[i]) == 's' ) {
843                                 ACL_PRIV_SET(mask, ACL_PRIV_SEARCH);
844
845                         } else if( TOLOWER(str[i]) == 'c' ) {
846                                 ACL_PRIV_SET(mask, ACL_PRIV_COMPARE);
847
848                         } else if( TOLOWER(str[i]) == 'x' ) {
849                                 ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
850
851                         } else if( str[i] != '0' ) {
852                                 ACL_INVALIDATE(mask);
853                                 return mask;
854                         }
855                 }
856
857                 return mask;
858         }
859
860         if ( strcasecmp( str, "none" ) == 0 ) {
861                 ACL_LVL_ASSIGN_NONE(mask);
862
863         } else if ( strcasecmp( str, "auth" ) == 0 ) {
864                 ACL_LVL_ASSIGN_AUTH(mask);
865
866         } else if ( strcasecmp( str, "compare" ) == 0 ) {
867                 ACL_LVL_ASSIGN_COMPARE(mask);
868
869         } else if ( strcasecmp( str, "search" ) == 0 ) {
870                 ACL_LVL_ASSIGN_SEARCH(mask);
871
872         } else if ( strcasecmp( str, "read" ) == 0 ) {
873                 ACL_LVL_ASSIGN_READ(mask);
874
875         } else if ( strcasecmp( str, "write" ) == 0 ) {
876                 ACL_LVL_ASSIGN_WRITE(mask);
877
878         } else {
879                 ACL_INVALIDATE( mask );
880         }
881
882         return mask;
883 }
884
885 static void
886 acl_usage( void )
887 {
888         fprintf( stderr, "\n"
889                 "<access clause> ::= access to <what> "
890                                 "[ by <who> <access> <control> ]+ \n"
891                 "<what> ::= * | [dn=<regex>] [filter=<ldapfilter>] [attrs=<attrlist>]\n"
892                 "<attrlist> ::= <attr> | <attr> , <attrlist>\n"
893                 "<attr> ::= <attrname> | entry | children\n"
894                 "<who> ::= [ * | anonymous | users | self | dn=<regex> ]\n"
895                         "\t[dnattr=<attrname>]\n"
896                         "\t[group[/<objectclass>[/<attrname>]]=<regex>]\n"
897                         "\t[peername=<regex>] [sockname=<regex>]\n"
898                         "\t[domain=<regex>] [sockurl=<regex>]\n"
899 #ifdef SLAPD_ACI_ENABLED
900                         "\t[aci=<attrname>]\n"
901 #endif
902                 "<access> ::= [self]{<level>|<priv>}\n"
903                 "<level> ::= none | auth | compare | search | read | write\n"
904                 "<priv> ::= {=|+|-}{w|r|s|c|x}+\n"
905                 "<control> ::= [ stop | continue | break ]\n"
906                 );
907         exit( EXIT_FAILURE );
908 }
909
910 static void
911 split(
912     char        *line,
913     int         splitchar,
914     char        **left,
915     char        **right
916 )
917 {
918         *left = line;
919         if ( (*right = strchr( line, splitchar )) != NULL ) {
920                 *((*right)++) = '\0';
921         }
922 }
923
924 static void
925 access_append( Access **l, Access *a )
926 {
927         for ( ; *l != NULL; l = &(*l)->a_next )
928                 ;       /* NULL */
929
930         *l = a;
931 }
932
933 void
934 acl_append( AccessControl **l, AccessControl *a )
935 {
936         for ( ; *l != NULL; l = &(*l)->acl_next )
937                 ;       /* NULL */
938
939         *l = a;
940 }
941
942 char *
943 access2str( slap_access_t access )
944 {
945         if ( access == ACL_NONE ) {
946                 return "none";
947
948         } else if ( access == ACL_AUTH ) {
949                 return "auth";
950
951         } else if ( access == ACL_COMPARE ) {
952                 return "compare";
953
954         } else if ( access == ACL_SEARCH ) {
955                 return "search";
956
957         } else if ( access == ACL_READ ) {
958                 return "read";
959
960         } else if ( access == ACL_WRITE ) {
961                 return "write";
962         }
963
964         return "unknown";
965 }
966
967 slap_access_t
968 str2access( const char *str )
969 {
970         if ( strcasecmp( str, "none" ) == 0 ) {
971                 return ACL_NONE;
972
973         } else if ( strcasecmp( str, "auth" ) == 0 ) {
974                 return ACL_AUTH;
975
976         } else if ( strcasecmp( str, "compare" ) == 0 ) {
977                 return ACL_COMPARE;
978
979         } else if ( strcasecmp( str, "search" ) == 0 ) {
980                 return ACL_SEARCH;
981
982         } else if ( strcasecmp( str, "read" ) == 0 ) {
983                 return ACL_READ;
984
985         } else if ( strcasecmp( str, "write" ) == 0 ) {
986                 return ACL_WRITE;
987         }
988
989         return( ACL_INVALID_ACCESS );
990 }
991
992 #ifdef LDAP_DEBUG
993
994 static void
995 print_access( Access *b )
996 {
997         char maskbuf[ACCESSMASK_MAXLEN];
998
999         fprintf( stderr, "\tby" );
1000
1001         if ( b->a_dn_pat != NULL ) {
1002                 if( strcmp(b->a_dn_pat, "*") == 0
1003                         || strcmp(b->a_dn_pat, "users") == 0 
1004                         || strcmp(b->a_dn_pat, "anonymous") == 0 
1005                         || strcmp(b->a_dn_pat, "self") == 0 )
1006                 {
1007                         fprintf( stderr, " %s", b->a_dn_pat );
1008
1009                 } else {
1010                         fprintf( stderr, " dn=%s", b->a_dn_pat );
1011                 }
1012         }
1013
1014         if ( b->a_dn_at != NULL ) {
1015 #ifdef SLAPD_SCHEMA_NOT_COMPAT
1016                 fprintf( stderr, " dnattr=%s", b->a_dn_at->ad_cname->bv_val );
1017 #else
1018                 fprintf( stderr, " dnattr=%s", b->a_dn_at );
1019 #endif
1020         }
1021
1022         if ( b->a_group_pat != NULL ) {
1023                 fprintf( stderr, " group: %s", b->a_group_pat );
1024
1025                 if ( b->a_group_oc ) {
1026                         fprintf( stderr, " objectClass: %s", b->a_group_oc );
1027
1028                         if ( b->a_group_at ) {
1029 #ifdef SLAPD_SCHEMA_NOT_COMPAT
1030                                 fprintf( stderr, " attributeType: %s", b->a_group_at->ad_cname->bv_val );
1031 #else
1032                                 fprintf( stderr, " attributeType: %s", b->a_group_at );
1033 #endif
1034                         }
1035                 }
1036     }
1037
1038         if ( b->a_peername_pat != NULL ) {
1039                 fprintf( stderr, " peername=%s", b->a_peername_pat );
1040         }
1041
1042         if ( b->a_sockname_pat != NULL ) {
1043                 fprintf( stderr, " sockname=%s", b->a_sockname_pat );
1044         }
1045
1046         if ( b->a_domain_pat != NULL ) {
1047                 fprintf( stderr, " domain=%s", b->a_domain_pat );
1048         }
1049
1050         if ( b->a_sockurl_pat != NULL ) {
1051                 fprintf( stderr, " sockurl=%s", b->a_sockurl_pat );
1052         }
1053
1054 #ifdef SLAPD_ACI_ENABLED
1055         if ( b->a_aci_at != NULL ) {
1056 #ifdef SLAPD_SCHEMA_NOT_COMPAT
1057                 fprintf( stderr, " aci=%s", b->a_aci_at->ad_cname->bv_val );
1058 #else
1059                 fprintf( stderr, " aci=%s", b->a_aci_at );
1060 #endif
1061         }
1062 #endif
1063
1064         fprintf( stderr, " %s%s",
1065                 b->a_dn_self ? "self" : "",
1066                 accessmask2str( b->a_mask, maskbuf ) );
1067
1068         if( b->a_type == ACL_BREAK ) {
1069                 fprintf( stderr, " break" );
1070
1071         } else if( b->a_type == ACL_CONTINUE ) {
1072                 fprintf( stderr, " continue" );
1073
1074         } else if( b->a_type != ACL_STOP ) {
1075                 fprintf( stderr, " unknown-control" );
1076         }
1077
1078         fprintf( stderr, "\n" );
1079 }
1080
1081
1082 static void
1083 print_acl( Backend *be, AccessControl *a )
1084 {
1085         int             to = 0;
1086         Access  *b;
1087
1088         fprintf( stderr, "%s ACL: access to",
1089                 be == NULL ? "Global" : "Backend" );
1090
1091         if ( a->acl_dn_pat != NULL ) {
1092                 to++;
1093                 fprintf( stderr, " dn=%s\n",
1094                         a->acl_dn_pat );
1095         }
1096
1097         if ( a->acl_filter != NULL ) {
1098                 to++;
1099                 fprintf( stderr, " filter=" );
1100                 filter_print( a->acl_filter );
1101                 fprintf( stderr, "\n" );
1102         }
1103
1104         if ( a->acl_attrs != NULL ) {
1105                 int     i, first = 1;
1106                 to++;
1107
1108                 fprintf( stderr, " attrs=" );
1109                 for ( i = 0; a->acl_attrs[i] != NULL; i++ ) {
1110                         if ( ! first ) {
1111                                 fprintf( stderr, "," );
1112                         }
1113                         fprintf( stderr, a->acl_attrs[i] );
1114                         first = 0;
1115                 }
1116                 fprintf(  stderr, "\n" );
1117         }
1118
1119         if( !to ) {
1120                 fprintf( stderr, " *\n" );
1121         }
1122
1123         for ( b = a->acl_access; b != NULL; b = b->a_next ) {
1124                 print_access( b );
1125         }
1126
1127         fprintf( stderr, "\n" );
1128 }
1129
1130 #endif /* LDAP_DEBUG */