]> git.sur5r.net Git - openldap/blob - servers/slapd/aclparse.c
cc208217bbb1a7bc39ca3bf27cebe9c1ce8b87cf
[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                 if (ldap_debug&LDAP_DEBUG_ACL)
297                     print_acl(a);
298
299         
300                 if ( a->acl_access == NULL ) {
301                         fprintf( stderr,
302                         "%s: line %d: warning: no by clause(s) specified in access line\n",
303                             fname, lineno );
304                 }
305
306                 if ( be != NULL ) {
307                         acl_append( &be->be_acl, a );
308                 } else {
309                         acl_append( &global_acl, a );
310                 }
311         }
312 }
313
314 char *
315 access2str( int access )
316 {
317         static char     buf[12];
318
319         if ( access & ACL_SELF ) {
320                 strcpy( buf, "self" );
321         } else {
322                 buf[0] = '\0';
323         }
324
325         if ( access & ACL_NONE ) {
326                 strcat( buf, "none" );
327         } else if ( access & ACL_COMPARE ) {
328                 strcat( buf, "compare" );
329         } else if ( access & ACL_SEARCH ) {
330                 strcat( buf, "search" );
331         } else if ( access & ACL_READ ) {
332                 strcat( buf, "read" );
333         } else if ( access & ACL_WRITE ) {
334                 strcat( buf, "write" );
335         } else {
336                 strcat( buf, "unknown" );
337         }
338
339         return( buf );
340 }
341
342 int
343 str2access( char *str )
344 {
345         int     access;
346
347         access = 0;
348         if ( strncasecmp( str, "self", 4 ) == 0 ) {
349                 access |= ACL_SELF;
350                 str += 4;
351         }
352
353         if ( strcasecmp( str, "none" ) == 0 ) {
354                 access |= ACL_NONE;
355         } else if ( strcasecmp( str, "compare" ) == 0 ) {
356                 access |= ACL_COMPARE;
357         } else if ( strcasecmp( str, "search" ) == 0 ) {
358                 access |= ACL_SEARCH;
359         } else if ( strcasecmp( str, "read" ) == 0 ) {
360                 access |= ACL_READ;
361         } else if ( strcasecmp( str, "write" ) == 0 ) {
362                 access |= ACL_WRITE;
363         } else {
364                 access = -1;
365         }
366
367         return( access );
368 }
369
370 static void
371 acl_usage()
372 {
373         fprintf( stderr, "\n<access clause> ::= access to <what> [ by <who> <access> ]+ \n" );
374         fprintf( stderr, "<what> ::= * | [dn=<regex>] [filter=<ldapfilter>] [attrs=<attrlist>]\n" );
375         fprintf( stderr, "<attrlist> ::= <attr> | <attr> , <attrlist>\n" );
376         fprintf( stderr, "<attr> ::= <attrname> | entry | children\n" );
377         fprintf( stderr, "<who> ::= * | self | dn=<regex> | addr=<regex> |\n\tdomain=<regex> | dnattr=<dnattrname>\n" );
378         fprintf( stderr, "<access> ::= [self]{none | compare | search | read | write }\n" );
379         exit( 1 );
380 }
381
382 static void
383 split(
384     char        *line,
385     int         splitchar,
386     char        **left,
387     char        **right
388 )
389 {
390         *left = line;
391         if ( (*right = strchr( line, splitchar )) != NULL ) {
392                 *((*right)++) = '\0';
393         }
394 }
395
396 static void
397 access_append( struct access **l, struct access *a )
398 {
399         for ( ; *l != NULL; l = &(*l)->a_next )
400                 ;       /* NULL */
401
402         *l = a;
403 }
404
405 static void
406 acl_append( struct acl **l, struct acl *a )
407 {
408         for ( ; *l != NULL; l = &(*l)->acl_next )
409                 ;       /* NULL */
410
411         *l = a;
412 }
413
414 #ifdef LDAP_DEBUG
415
416 static void
417 print_access( struct access *b )
418 {
419         printf( "\tby" );
420         if ( b->a_dnpat != NULL ) {
421                 fprintf( stderr, " dn=%s", b->a_dnpat );
422         } else if ( b->a_addrpat != NULL ) {
423                 fprintf( stderr, " addr=%s", b->a_addrpat );
424         } else if ( b->a_domainpat != NULL ) {
425                 fprintf( stderr, " domain=%s", b->a_domainpat );
426         } else if ( b->a_dnattr != NULL ) {
427                 fprintf( stderr, " dnattr=%s", b->a_dnattr );
428         }
429 #ifdef SLAPD_ACLGROUPS
430         else if ( b->a_group != NULL ) {
431                 fprintf( stderr, " group: %s", b->a_group );
432                 if ( b->a_objectclassvalue )
433                         fprintf( stderr, " objectClassValue: %s", b->a_objectclassvalue );
434                 if ( b->a_groupattrname )
435                         fprintf( stderr, " groupAttrName: %s", b->a_groupattrname );
436         }
437 #endif
438         fprintf( stderr, "\n" );
439 }
440
441 static void
442 print_acl( struct acl *a )
443 {
444         int             i;
445         struct access   *b;
446
447         if ( a == NULL ) {
448                 fprintf( stderr, "NULL\n" );
449         }
450         fprintf( stderr, "ACL: access to" );
451         if ( a->acl_filter != NULL ) {
452                 fprintf(  stderr," filter=" );
453                 filter_print( a->acl_filter );
454         }
455         if ( a->acl_dnpat != NULL ) {
456                 fprintf( stderr, " dn=" );
457                 fprintf( stderr, a->acl_dnpat );
458         }
459         if ( a->acl_attrs != NULL ) {
460                 int     first = 1;
461
462                 fprintf( stderr, "\n attrs=" );
463                 for ( i = 0; a->acl_attrs[i] != NULL; i++ ) {
464                         if ( ! first ) {
465                                 fprintf( stderr, "," );
466                         }
467                         fprintf( stderr, a->acl_attrs[i] );
468                         first = 0;
469                 }
470         }
471         fprintf( stderr, "\n" );
472         for ( b = a->acl_access; b != NULL; b = b->a_next ) {
473                 print_access( b );
474         }
475         fprintf( stderr, "\n" );
476 }
477
478 #endif /* LDAP_DEBUG */