]> git.sur5r.net Git - openldap/blob - servers/slapd/aclparse.c
More header work toward draft-ietf-ldapext-ldap-c-api-01.
[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                                 regtest(fname, lineno, right);
214                                 b->a_group = dn_upcase(strdup( right ));
215 #endif /* SLAPD_ACLGROUPS */
216                         } else if ( strcasecmp( left, "domain" ) == 0 ) {
217                                 char    *s;
218                                 regtest(fname, lineno, right);
219                                 b->a_domainpat = strdup( right );
220
221                                 /* normalize the domain */
222                                 for ( s = b->a_domainpat; *s; s++ ) {
223                                         *s = TOLOWER( *s );
224                                 }
225                         } else if ( strcasecmp( left, "addr" ) == 0 ) {
226                                 regtest(fname, lineno, right);
227                                 b->a_addrpat = strdup( right );
228                         } else {
229                                 fprintf( stderr,
230                                     "%s: line %d: expecting <who> got \"%s\"\n",
231                                     fname, lineno, left );
232                                 acl_usage();
233                         }
234
235                         if ( ++i == argc ) {
236                                 fprintf( stderr,
237                             "%s: line %d: premature eol: expecting <access>\n",
238                                     fname, lineno );
239                                 acl_usage();
240                         }
241
242                         /* get <access> */
243                         split( argv[i], '=', &left, &right );
244                         if ( (b->a_access = str2access( left )) == -1 ) {
245                                 fprintf( stderr,
246                             "%s: line %d: expecting <access> got \"%s\"\n",
247                                     fname, lineno, left );
248                                 acl_usage();
249                         }
250                         access_append( &a->acl_access, b );
251
252                 } else {
253                         fprintf( stderr,
254                     "%s: line %d: expecting \"to\" or \"by\" got \"%s\"\n",
255                             fname, lineno, argv[i] );
256                         acl_usage();
257                 }
258         }
259
260         /* if we have no real access clause, complain and do nothing */
261         if ( a == NULL ) {
262                         fprintf( stderr,
263                                 "%s: line %d: warning: no access clause(s) specified in access line\n",
264                             fname, lineno );
265
266         } else {
267         
268                 if ( a->acl_access == NULL ) {
269                         fprintf( stderr,
270                         "%s: line %d: warning: no by clause(s) specified in access line\n",
271                             fname, lineno );
272                 }
273
274                 if ( be != NULL ) {
275                         acl_append( &be->be_acl, a );
276                 } else {
277                         acl_append( &global_acl, a );
278                 }
279         }
280 }
281
282 char *
283 access2str( int access )
284 {
285         static char     buf[12];
286
287         if ( access & ACL_SELF ) {
288                 strcpy( buf, "self" );
289         } else {
290                 buf[0] = '\0';
291         }
292
293         if ( access & ACL_NONE ) {
294                 strcat( buf, "none" );
295         } else if ( access & ACL_COMPARE ) {
296                 strcat( buf, "compare" );
297         } else if ( access & ACL_SEARCH ) {
298                 strcat( buf, "search" );
299         } else if ( access & ACL_READ ) {
300                 strcat( buf, "read" );
301         } else if ( access & ACL_WRITE ) {
302                 strcat( buf, "write" );
303         } else {
304                 strcat( buf, "unknown" );
305         }
306
307         return( buf );
308 }
309
310 int
311 str2access( char *str )
312 {
313         int     access;
314
315         access = 0;
316         if ( strncasecmp( str, "self", 4 ) == 0 ) {
317                 access |= ACL_SELF;
318                 str += 4;
319         }
320
321         if ( strcasecmp( str, "none" ) == 0 ) {
322                 access |= ACL_NONE;
323         } else if ( strcasecmp( str, "compare" ) == 0 ) {
324                 access |= ACL_COMPARE;
325         } else if ( strcasecmp( str, "search" ) == 0 ) {
326                 access |= ACL_SEARCH;
327         } else if ( strcasecmp( str, "read" ) == 0 ) {
328                 access |= ACL_READ;
329         } else if ( strcasecmp( str, "write" ) == 0 ) {
330                 access |= ACL_WRITE;
331         } else {
332                 access = -1;
333         }
334
335         return( access );
336 }
337
338 static void
339 acl_usage()
340 {
341         fprintf( stderr, "\n<access clause> ::= access to <what> [ by <who> <access> ]+ \n" );
342         fprintf( stderr, "<what> ::= * | [dn=<regex>] [filter=<ldapfilter>] [attrs=<attrlist>]\n" );
343         fprintf( stderr, "<attrlist> ::= <attr> | <attr> , <attrlist>\n" );
344         fprintf( stderr, "<attr> ::= <attrname> | entry | children\n" );
345         fprintf( stderr, "<who> ::= * | self | dn=<regex> | addr=<regex> |\n\tdomain=<regex> | dnattr=<dnattrname>\n" );
346         fprintf( stderr, "<access> ::= [self]{none | compare | search | read | write }\n" );
347         exit( 1 );
348 }
349
350 static void
351 split(
352     char        *line,
353     int         splitchar,
354     char        **left,
355     char        **right
356 )
357 {
358         *left = line;
359         if ( (*right = strchr( line, splitchar )) != NULL ) {
360                 *((*right)++) = '\0';
361         }
362 }
363
364 static void
365 access_append( struct access **l, struct access *a )
366 {
367         for ( ; *l != NULL; l = &(*l)->a_next )
368                 ;       /* NULL */
369
370         *l = a;
371 }
372
373 static void
374 acl_append( struct acl **l, struct acl *a )
375 {
376         for ( ; *l != NULL; l = &(*l)->acl_next )
377                 ;       /* NULL */
378
379         *l = a;
380 }
381
382 #ifdef LDAP_DEBUG
383
384 static void
385 print_access( struct access *b )
386 {
387         printf( "\tby" );
388         if ( b->a_dnpat != NULL ) {
389                 printf( " dn=%s", b->a_dnpat );
390         } else if ( b->a_addrpat != NULL ) {
391                 printf( " addr=%s", b->a_addrpat );
392         } else if ( b->a_domainpat != NULL ) {
393                 printf( " domain=%s", b->a_domainpat );
394         } else if ( b->a_dnattr != NULL ) {
395                 printf( " dnattr=%s", b->a_dnattr );
396         }
397         printf( " %s\n", access2str( b->a_access ) );
398 }
399
400 static void
401 print_acl( struct acl *a )
402 {
403         int             i;
404         struct access   *b;
405
406         if ( a == NULL ) {
407                 printf( "NULL\n" );
408         }
409         printf( "access to" );
410         if ( a->acl_filter != NULL ) {
411                 printf( " filter=" );
412                 filter_print( a->acl_filter );
413         }
414         if ( a->acl_dnpat != NULL ) {
415                 printf( " dn=" );
416                 printf( a->acl_dnpat );
417         }
418         if ( a->acl_attrs != NULL ) {
419                 int     first = 1;
420
421                 printf( " attrs=" );
422                 for ( i = 0; a->acl_attrs[i] != NULL; i++ ) {
423                         if ( ! first ) {
424                                 printf( "," );
425                         }
426                         printf( a->acl_attrs[i] );
427                         first = 0;
428                 }
429         }
430         printf( "\n" );
431         for ( b = a->acl_access; b != NULL; b = b->a_next ) {
432                 print_access( b );
433         }
434 }
435
436 #endif /* LDAP_DEBUG */