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