]> git.sur5r.net Git - openldap/blob - servers/slapd/aclparse.c
f8dea06bd530ebdb348b1325b000ab9ecb4c2702
[openldap] / servers / slapd / aclparse.c
1 /* acl.c - routines to parse and check acl's */
2
3 #include "portable.h"
4
5 #include <stdio.h>
6
7 #include <ac/ctype.h>
8 #include <ac/regex.h>
9 #include <ac/socket.h>
10 #include <ac/string.h>
11 #include <ac/unistd.h>
12
13 #include "slap.h"
14
15 extern Filter           *str2filter();
16 extern struct acl       *global_acl;
17 extern char             **str2charray();
18 extern char             *dn_upcase();
19
20 static void             split();
21 static void             acl_append();
22 static void             access_append();
23 static void             acl_usage();
24 #ifdef LDAP_DEBUG
25 static void             print_acl();
26 static void             print_access();
27 #endif
28
29 int
30 regtest(char *fname, int lineno, char *pat) {
31         int e;
32         regex_t re;
33
34         char buf[512];
35         int 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, 0 );
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     char        *fname,
89     int         lineno,
90     int         argc,
91     char        **argv
92 )
93 {
94         int             i;
95         char            *e, *left, *right;
96         struct acl      *a;
97         struct access   *b;
98
99         a = NULL;
100         for ( i = 1; i < argc; i++ ) {
101                 /* to clause - select which entries are protected */
102                 if ( strcasecmp( argv[i], "to" ) == 0 ) {
103                         if ( a != NULL ) {
104                                 fprintf( stderr,
105                 "%s: line %d: only one to clause allowed in access line\n",
106                                     fname, lineno );
107                                 acl_usage();
108                         }
109                         a = (struct acl *) ch_calloc( 1, sizeof(struct acl) );
110                         for ( ++i; i < argc; i++ ) {
111                                 if ( strcasecmp( argv[i], "by" ) == 0 ) {
112                                         i--;
113                                         break;
114                                 }
115
116                                 if ( strcasecmp( argv[i], "*" ) == 0 ) {
117                                         int e;
118                                         if ((e = regcomp( &a->acl_dnre, ".*",
119                                                 REG_EXTENDED|REG_ICASE)))
120                                         {
121                                                 char buf[512];
122                                                 regerror(e, &a->acl_dnre, buf, sizeof(buf));
123                                                 fprintf( stderr,
124                                                         "%s: line %d: regular expression \"%s\" bad because of %s\n",
125                                                         fname, lineno, right, buf );
126                                                 acl_usage();
127                                         }
128                                         a->acl_dnpat = strdup( ".*" );
129                                         continue;
130                                 }
131
132                                 split( argv[i], '=', &left, &right );
133                                 if ( right == NULL || *right == '\0' ) {
134                                         fprintf( stderr,
135         "%s: line %d: missing \"=\" in (or value after) \"%s\" in to clause\n",
136                                             fname, lineno, left );
137                                         acl_usage();
138                                 }
139
140                                 if ( strcasecmp( left, "filter" ) == 0 ) {
141                                         if ( (a->acl_filter = str2filter(
142                                             right )) == NULL ) {
143                                                 fprintf( stderr,
144                                 "%s: line %d: bad filter \"%s\" in to clause\n",
145                                                     fname, lineno, right );
146                                                 acl_usage();
147                                         }
148                                 } else if ( strcasecmp( left, "dn" ) == 0 ) {
149                                         int e;
150                                         if ((e = regcomp(&a->acl_dnre, right,
151                                                 REG_EXTENDED|REG_ICASE))) {
152                                                 char buf[512];
153                                                 regerror(e, &a->acl_dnre, buf, sizeof(buf));
154                                                 fprintf( stderr,
155                                 "%s: line %d: regular expression \"%s\" bad because of %s\n",
156                                                         fname, lineno, right, buf );
157                                                 acl_usage();
158
159                                         } else {
160                                                 a->acl_dnpat = dn_upcase(strdup( right ));
161                                         }
162                                 } else if ( strncasecmp( left, "attr", 4 )
163                                     == 0 ) {
164                                         char    **alist;
165
166                                         alist = str2charray( right, "," );
167                                         charray_merge( &a->acl_attrs, alist );
168                                         free( alist );
169                                 } else {
170                                         fprintf( stderr,
171                                                 "%s: line %d: expecting <what> got \"%s\"\n",
172                                             fname, lineno, left );
173                                         acl_usage();
174                                 }
175                         }
176
177                 /* by clause - select who has what access to entries */
178                 } else if ( strcasecmp( argv[i], "by" ) == 0 ) {
179                         if ( a == NULL ) {
180                                 fprintf( stderr,
181                                         "%s: line %d: to clause required before by clause in access line\n",
182                                     fname, lineno );
183                                 acl_usage();
184                         }
185                         /*
186                          * by clause consists of <who> and <access>
187                          */
188
189                         b = (struct access *) ch_calloc( 1,
190                             sizeof(struct access) );
191
192                         if ( ++i == argc ) {
193                                 fprintf( stderr,
194                             "%s: line %d: premature eol: expecting <who>\n",
195                                     fname, lineno );
196                                 acl_usage();
197                         }
198
199                         /* get <who> */
200                         split( argv[i], '=', &left, &right );
201                         if ( strcasecmp( argv[i], "*" ) == 0 ) {
202                                 b->a_dnpat = strdup( ".*" );
203                         } else if ( strcasecmp( argv[i], "self" ) == 0 ) {
204                                 b->a_dnpat = strdup( "self" );
205                         } else if ( strcasecmp( left, "dn" ) == 0 ) {
206                                 regtest(fname, lineno, right);
207                                 b->a_dnpat = dn_upcase( strdup( right ) );
208                         } else if ( strcasecmp( left, "dnattr" ) == 0 ) {
209                                 b->a_dnattr = strdup( right );
210
211 #ifdef SLAPD_ACLGROUPS
212                         } else if ( strcasecmp( left, "group" ) == 0 ) {
213                                 char *name = NULL;
214                                 char *value = NULL;
215                                 regtest(fname, lineno, right);
216
217                                 /* format of string is "group/objectClassValue/groupAttrName"
218                                  */
219                                 if ((value = strchr(right, '/')) != NULL) {
220                                         *value++ = '\0';
221                                         if (value && *value && (name = strchr(value, '/')) != NULL) 
222                                             *name++ = '\0';
223                                 }
224
225                                 b->a_group = dn_upcase(strdup( right ));
226
227                                 if (value && *value) {
228                                         b->a_objectclassvalue = strdup(value);
229                                         *--value = '/';
230                                 }
231                                 else
232                                         b->a_objectclassvalue = strdup("groupOfNames");
233
234                                 if (name && *name) {
235                                         b->a_groupattrname = strdup(name);
236                                         *--name = '/';
237                                 }
238                                 else
239                                         b->a_groupattrname = strdup("member");
240
241
242
243 #endif /* SLAPD_ACLGROUPS */
244                         } else if ( strcasecmp( left, "domain" ) == 0 ) {
245                                 char    *s;
246                                 regtest(fname, lineno, right);
247                                 b->a_domainpat = strdup( right );
248
249                                 /* normalize the domain */
250                                 for ( s = b->a_domainpat; *s; s++ ) {
251                                         *s = TOLOWER( *s );
252                                 }
253                         } else if ( strcasecmp( left, "addr" ) == 0 ) {
254                                 regtest(fname, lineno, right);
255                                 b->a_addrpat = strdup( right );
256                         } else {
257                                 fprintf( stderr,
258                                     "%s: line %d: expecting <who> got \"%s\"\n",
259                                     fname, lineno, left );
260                                 acl_usage();
261                         }
262
263                         if ( ++i == argc ) {
264                                 fprintf( stderr,
265                             "%s: line %d: premature eol: expecting <access>\n",
266                                     fname, lineno );
267                                 acl_usage();
268                         }
269
270                         /* get <access> */
271                         split( argv[i], '=', &left, &right );
272                         if ( (b->a_access = str2access( left )) == -1 ) {
273                                 fprintf( stderr,
274                             "%s: line %d: expecting <access> got \"%s\"\n",
275                                     fname, lineno, left );
276                                 acl_usage();
277                         }
278                         access_append( &a->acl_access, b );
279
280                 } else {
281                         fprintf( stderr,
282                     "%s: line %d: expecting \"to\" or \"by\" got \"%s\"\n",
283                             fname, lineno, argv[i] );
284                         acl_usage();
285                 }
286         }
287
288         /* if we have no real access clause, complain and do nothing */
289         if ( a == NULL ) {
290                         fprintf( stderr,
291                                 "%s: line %d: warning: no access clause(s) specified in access line\n",
292                             fname, lineno );
293
294         } else {
295
296 #ifdef LDAP_DEBUG
297                 if (ldap_debug & LDAP_DEBUG_ACL)
298                         print_acl(a);
299 #endif
300         
301                 if ( a->acl_access == NULL ) {
302                         fprintf( stderr,
303                         "%s: line %d: warning: no by clause(s) specified in access line\n",
304                             fname, lineno );
305                 }
306
307                 if ( be != NULL ) {
308                         acl_append( &be->be_acl, a );
309                 } else {
310                         acl_append( &global_acl, a );
311                 }
312         }
313 }
314
315 char *
316 access2str( int access )
317 {
318         static char     buf[12];
319
320         if ( access & ACL_SELF ) {
321                 strcpy( buf, "self" );
322         } else {
323                 buf[0] = '\0';
324         }
325
326         if ( access & ACL_NONE ) {
327                 strcat( buf, "none" );
328         } else if ( access & ACL_COMPARE ) {
329                 strcat( buf, "compare" );
330         } else if ( access & ACL_SEARCH ) {
331                 strcat( buf, "search" );
332         } else if ( access & ACL_READ ) {
333                 strcat( buf, "read" );
334         } else if ( access & ACL_WRITE ) {
335                 strcat( buf, "write" );
336         } else {
337                 strcat( buf, "unknown" );
338         }
339
340         return( buf );
341 }
342
343 int
344 str2access( char *str )
345 {
346         int     access;
347
348         access = 0;
349         if ( strncasecmp( str, "self", 4 ) == 0 ) {
350                 access |= ACL_SELF;
351                 str += 4;
352         }
353
354         if ( strcasecmp( str, "none" ) == 0 ) {
355                 access |= ACL_NONE;
356         } else if ( strcasecmp( str, "compare" ) == 0 ) {
357                 access |= ACL_COMPARE;
358         } else if ( strcasecmp( str, "search" ) == 0 ) {
359                 access |= ACL_SEARCH;
360         } else if ( strcasecmp( str, "read" ) == 0 ) {
361                 access |= ACL_READ;
362         } else if ( strcasecmp( str, "write" ) == 0 ) {
363                 access |= ACL_WRITE;
364         } else {
365                 access = -1;
366         }
367
368         return( access );
369 }
370
371 static void
372 acl_usage()
373 {
374         fprintf( stderr, "\n<access clause> ::= access to <what> [ by <who> <access> ]+ \n" );
375         fprintf( stderr, "<what> ::= * | [dn=<regex>] [filter=<ldapfilter>] [attrs=<attrlist>]\n" );
376         fprintf( stderr, "<attrlist> ::= <attr> | <attr> , <attrlist>\n" );
377         fprintf( stderr, "<attr> ::= <attrname> | entry | children\n" );
378         fprintf( stderr, "<who> ::= * | self | dn=<regex> | addr=<regex> |\n\tdomain=<regex> | dnattr=<dnattrname>\n" );
379         fprintf( stderr, "<access> ::= [self]{none | compare | search | read | write }\n" );
380         exit( 1 );
381 }
382
383 static void
384 split(
385     char        *line,
386     int         splitchar,
387     char        **left,
388     char        **right
389 )
390 {
391         *left = line;
392         if ( (*right = strchr( line, splitchar )) != NULL ) {
393                 *((*right)++) = '\0';
394         }
395 }
396
397 static void
398 access_append( struct access **l, struct access *a )
399 {
400         for ( ; *l != NULL; l = &(*l)->a_next )
401                 ;       /* NULL */
402
403         *l = a;
404 }
405
406 static void
407 acl_append( struct acl **l, struct acl *a )
408 {
409         for ( ; *l != NULL; l = &(*l)->acl_next )
410                 ;       /* NULL */
411
412         *l = a;
413 }
414
415 #ifdef LDAP_DEBUG
416
417 static void
418 print_access( struct access *b )
419 {
420         printf( "\tby" );
421         if ( b->a_dnpat != NULL ) {
422                 fprintf( stderr, " dn=%s", b->a_dnpat );
423         } else if ( b->a_addrpat != NULL ) {
424                 fprintf( stderr, " addr=%s", b->a_addrpat );
425         } else if ( b->a_domainpat != NULL ) {
426                 fprintf( stderr, " domain=%s", b->a_domainpat );
427         } else if ( b->a_dnattr != NULL ) {
428                 fprintf( stderr, " dnattr=%s", b->a_dnattr );
429         }
430 #ifdef SLAPD_ACLGROUPS
431         else if ( b->a_group != NULL ) {
432                 fprintf( stderr, " group: %s", b->a_group );
433                 if ( b->a_objectclassvalue )
434                         fprintf( stderr, " objectClassValue: %s", b->a_objectclassvalue );
435                 if ( b->a_groupattrname )
436                         fprintf( stderr, " groupAttrName: %s", b->a_groupattrname );
437         }
438 #endif
439         fprintf( stderr, "\n" );
440 }
441
442 static void
443 print_acl( struct acl *a )
444 {
445         int             i;
446         struct access   *b;
447
448         if ( a == NULL ) {
449                 fprintf( stderr, "NULL\n" );
450         }
451         fprintf( stderr, "ACL: access to" );
452         if ( a->acl_filter != NULL ) {
453                 fprintf(  stderr," filter=" );
454                 filter_print( a->acl_filter );
455         }
456         if ( a->acl_dnpat != NULL ) {
457                 fprintf( stderr, " dn=" );
458                 fprintf( stderr, a->acl_dnpat );
459         }
460         if ( a->acl_attrs != NULL ) {
461                 int     first = 1;
462
463                 fprintf( stderr, "\n attrs=" );
464                 for ( i = 0; a->acl_attrs[i] != NULL; i++ ) {
465                         if ( ! first ) {
466                                 fprintf( stderr, "," );
467                         }
468                         fprintf( stderr, a->acl_attrs[i] );
469                         first = 0;
470                 }
471         }
472         fprintf( stderr, "\n" );
473         for ( b = a->acl_access; b != NULL; b = b->a_next ) {
474                 print_access( b );
475         }
476         fprintf( stderr, "\n" );
477 }
478
479 #endif /* LDAP_DEBUG */