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