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