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