]> git.sur5r.net Git - openldap/blob - servers/slapd/limits.c
Fixup bdb_entry_release now that entry_decode uses two memory blocks
[openldap] / servers / slapd / limits.c
1 /* limits.c - routines to handle regex-based size and time limits */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdio.h>
10
11 #include <ac/regex.h>
12 #include <ac/string.h>
13
14 #include "slap.h"
15
16 int
17 get_limits( 
18         Backend                 *be, 
19         const char              *ndn, 
20         struct slap_limits_set  **limit
21 )
22 {
23         struct slap_limits **lm;
24
25         assert( be );
26         assert( limit );
27
28         /*
29          * default values
30          */
31         *limit = &be->be_def_limit;
32
33         if ( be->be_limits == NULL ) {
34                 return( 0 );
35         }
36
37         for ( lm = be->be_limits; lm[0] != NULL; lm++ ) {
38                 switch ( lm[0]->lm_type ) {
39                 case SLAP_LIMITS_EXACT:
40                         if ( ndn == NULL || ndn[0] == '\0' ) {
41                                 break;
42                         }
43                         if ( strcmp( lm[0]->lm_dn_pat->bv_val, ndn ) == 0 ) {
44                                 *limit = &lm[0]->lm_limits;
45                                 return( 0 );
46                         }
47                         break;
48
49                 case SLAP_LIMITS_ONE:
50                 case SLAP_LIMITS_SUBTREE:
51                 case SLAP_LIMITS_CHILDREN: {
52                         long    d;
53                         
54                         if ( ndn == NULL || ndn[0] == '\0' ) {
55                                 break;
56                         }
57
58                         d = strlen( ndn ) - lm[0]->lm_dn_pat->bv_len;
59                         /* ndn shorter than dn_pat */
60                         if ( d < 0 ) {
61                                 break;
62                         }
63
64                         /* allow exact match for SUBTREE only */
65                         if ( d == 0 ) {
66                                 if ( lm[0]->lm_type != SLAP_LIMITS_SUBTREE ) {
67                                         break;
68                                 }
69                         } else {
70                                 /* check for unescaped rdn separator */
71                                 if ( !DN_SEPARATOR( ndn[d-1] ) || DN_ESCAPE( ndn[d-2] ) ) {
72                                         break;
73                                 }
74                         }
75
76                         /* in case of (sub)match ... */
77                         if ( strcmp( lm[0]->lm_dn_pat->bv_val, &ndn[d] ) == 0 ) {
78                                 /* check for exacctly one rdn in case of ONE */
79                                 if ( lm[0]->lm_type == SLAP_LIMITS_ONE ) {
80                                         char *rdn;
81                                         
82                                         /*
83                                          * if ndn is more that one rdn
84                                          * below dn_pat, continue
85                                          */
86                                         rdn = dn_rdn( NULL, ndn );
87                                         if ( strlen( rdn ) != d - 1 ) {
88                                                 break;
89                                         }
90                                 }
91
92                                 *limit = &lm[0]->lm_limits;
93                                 return( 0 );
94                         }
95
96                         break;
97                 }
98
99                 case SLAP_LIMITS_REGEX:
100                         if ( ndn == NULL || ndn[0] == '\0' ) {
101                                 break;
102                         }
103                         if ( regexec( &lm[0]->lm_dn_regex, ndn, 0, NULL, 0 ) == 0 ) {
104                                 *limit = &lm[0]->lm_limits;
105                                 return( 0 );
106                         }
107                         break;
108
109                 case SLAP_LIMITS_ANONYMOUS:
110                         if ( ndn == NULL || ndn[0] == '\0' ) {
111                                 *limit = &lm[0]->lm_limits;
112                                 return( 0 );
113                         }
114                         break;
115
116                 case SLAP_LIMITS_USERS:
117                         if ( ndn != NULL && ndn[0] != '\0' ) {
118                                 *limit = &lm[0]->lm_limits;
119                                 return( 0 );
120                         }
121                         break;
122
123                 default:
124                         assert( 0 );    /* unreachable */
125                         return( -1 );
126                 }
127         }
128
129         return( 0 );
130 }
131
132 int
133 add_limits(
134         Backend                 *be,
135         int                     type,
136         const char              *pattern,
137         struct slap_limits_set  *limit
138 )
139 {
140         int                     i;
141         struct slap_limits      *lm;
142         
143         assert( be );
144         assert( limit );
145
146         lm = ( struct slap_limits * )ch_calloc( sizeof( struct slap_limits ), 1 );
147
148         switch ( type ) {
149         case SLAP_LIMITS_EXACT:
150         case SLAP_LIMITS_ONE:
151         case SLAP_LIMITS_SUBTREE:
152         case SLAP_LIMITS_CHILDREN:
153                 lm->lm_type = type;
154                 lm->lm_dn_pat = ber_bvstrdup( pattern );
155                 if ( dn_normalize( lm->lm_dn_pat->bv_val ) == NULL ) {
156                         ber_bvfree( lm->lm_dn_pat );
157                         ch_free( lm );
158                         return( -1 );
159                 }
160                 break;
161                 
162         case SLAP_LIMITS_REGEX:
163         case SLAP_LIMITS_UNDEFINED:
164                 lm->lm_type = SLAP_LIMITS_REGEX;
165                 lm->lm_dn_pat = ber_bvstrdup( pattern );
166                 if ( regcomp( &lm->lm_dn_regex, lm->lm_dn_pat->bv_val, 
167                                         REG_EXTENDED | REG_ICASE ) ) {
168                         ber_bvfree( lm->lm_dn_pat );
169                         ch_free( lm );
170                         return( -1 );
171                 }
172                 break;
173
174         case SLAP_LIMITS_ANONYMOUS:
175         case SLAP_LIMITS_USERS:
176                 lm->lm_type = type;
177                 lm->lm_dn_pat = NULL;
178                 break;
179         }
180
181         lm->lm_limits = *limit;
182
183         i = 0;
184         if ( be->be_limits != NULL ) {
185                 for ( ; be->be_limits[i]; i++ );
186         }
187
188         be->be_limits = ( struct slap_limits ** )ch_realloc( be->be_limits,
189                         sizeof( struct slap_limits * ) * ( i + 2 ) );
190         be->be_limits[i] = lm;
191         be->be_limits[i+1] = NULL;
192         
193         return( 0 );
194 }
195
196 int
197 parse_limits(
198         Backend     *be,
199         const char  *fname,
200         int         lineno,
201         int         argc,
202         char        **argv
203 )
204 {
205         int     type = SLAP_LIMITS_UNDEFINED;
206         char    *pattern;
207         struct slap_limits_set limit;
208         int     i;
209
210         assert( be );
211
212         if ( argc < 3 ) {
213 #ifdef NEW_LOGGING
214                 LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
215                         "%s : line %d: missing arg(s) in "
216                         "\"limits <pattern> <limits>\" line.\n",
217                         fname, lineno ));
218 #else
219                 Debug( LDAP_DEBUG_ANY,
220                         "%s : line %d: missing arg(s) in "
221                         "\"limits <pattern> <limits>\" line.\n%s",
222                         fname, lineno, "" );
223 #endif
224                 return( -1 );
225         }
226
227         limit = be->be_def_limit;
228
229         /*
230          * syntax:
231          *
232          * "limits" <pattern> <limit> [ ... ]
233          * 
234          * 
235          * <pattern>:
236          * 
237          * "anonymous"
238          * "users"
239          * [ "dn" [ "." { "exact" | "base" | "one" | "sub" | children" 
240          *      | "regex" | "anonymous" } ] "=" ] <dn pattern>
241          *
242          * Note:
243          *      "exact" and "base" are the same (exact match);
244          *      "one" means exactly one rdn below, NOT including the pattern
245          *      "sub" means any rdn below, including the pattern
246          *      "children" means any rdn below, NOT including the pattern
247          *      
248          *      "anonymous" may be deprecated in favour 
249          *      of the pattern = "anonymous" form
250          *
251          *
252          * <limit>:
253          *
254          * "time" [ "." { "soft" | "hard" } ] "=" <integer>
255          *
256          * "size" [ "." { "soft" | "hard" | "unchecked" } ] "=" <integer>
257          */
258         
259         pattern = argv[1];
260         if ( strcasecmp( pattern, "anonymous" ) == 0 ) {
261                 type = SLAP_LIMITS_ANONYMOUS;
262
263         } else if ( strcasecmp( pattern, "users" ) == 0 ) {
264                 type = SLAP_LIMITS_USERS;
265                 
266         } else if ( strncasecmp( pattern, "dn", 2 ) == 0 ) {
267                 pattern += 2;
268                 if ( pattern[0] == '.' ) {
269                         pattern++;
270                         if ( strncasecmp( pattern, "exact", 5 ) == 0 ) {
271                                 type = SLAP_LIMITS_EXACT;
272                                 pattern += 5;
273
274                         } else if ( strncasecmp( pattern, "base", 4 ) == 0 ) {
275                                 type = SLAP_LIMITS_BASE;
276                                 pattern += 4;
277
278                         } else if ( strncasecmp( pattern, "one", 3 ) == 0 ) {
279                                 type = SLAP_LIMITS_ONE;
280                                 pattern += 3;
281
282                         } else if ( strncasecmp( pattern, "subtree", 7 ) == 0 ) {
283                                 type = SLAP_LIMITS_SUBTREE;
284                                 pattern += 7;
285
286                         } else if ( strncasecmp( pattern, "children", 8 ) == 0 ) {
287                                 type = SLAP_LIMITS_CHILDREN;
288                                 pattern += 8;
289
290                         } else if ( strncasecmp( pattern, "regex", 5 ) == 0 ) {
291                                 type = SLAP_LIMITS_REGEX;
292                                 pattern += 5;
293
294                         /* 
295                          * this could be deprecated in favour
296                          * of the pattern = "anonymous" form
297                          */
298                         } else if ( strncasecmp( pattern, "anonymous", 9 ) == 0 ) {
299                                 type = SLAP_LIMITS_ANONYMOUS;
300                                 pattern = NULL;
301                         }
302                 }
303
304                 /* pre-check the data */
305                 switch ( type ) {
306                 case SLAP_LIMITS_ANONYMOUS:
307                 case SLAP_LIMITS_USERS:
308
309                         /* no need for pattern */
310                         pattern = NULL;
311                         break;
312
313                 default:
314                         if ( pattern[0] != '=' ) {
315 #ifdef NEW_LOGGING
316                                 LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
317                                         "%s : line %d: missing '=' in "
318                                         "\"dn[.{exact|base|one|subtree"
319                                         "|children|regex|anonymous}]"
320                                         "=<pattern>\" in "
321                                         "\"limits <pattern> <limits>\" line.\n",
322                                         fname, lineno ));
323 #else
324                                 Debug( LDAP_DEBUG_ANY,
325                                         "%s : line %d: missing '=' in "
326                                         "\"dn[.{exact|base|one|subtree"
327                                         "|children|regex|anonymous}]"
328                                         "=<pattern>\" in "
329                                         "\"limits <pattern> <limits>\" "
330                                         "line.\n%s",
331                                         fname, lineno, "" );
332 #endif
333                                 return( -1 );
334                         }
335
336                         /* skip '=' (required) */
337                         pattern++;
338                 }
339         }
340
341         /* get the limits */
342         for ( i = 2; i < argc; i++ ) {
343                 if ( parse_limit( argv[i], &limit ) ) {
344
345 #ifdef NEW_LOGGING
346                         LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
347                                 "%s : line %d: unknown limit type \"%s\" in "
348                                 "\"limits <pattern> <limits>\" line.\n",
349                         fname, lineno, argv[i] ));
350 #else
351                         Debug( LDAP_DEBUG_ANY,
352                                 "%s : line %d: unknown limit type \"%s\" in "
353                                 "\"limits <pattern> <limits>\" line.\n",
354                         fname, lineno, argv[i] );
355 #endif
356
357                         return( 1 );
358                 }
359         }
360
361         /*
362          * sanity checks ...
363          */
364         if ( limit.lms_t_hard > 0 && limit.lms_t_hard < limit.lms_t_soft ) {
365                 limit.lms_t_hard = limit.lms_t_soft;
366         }
367         
368         if ( limit.lms_s_hard > 0 && limit.lms_s_hard < limit.lms_s_soft ) {
369                 limit.lms_s_hard = limit.lms_s_soft;
370         }
371         
372         return( add_limits( be, type, pattern, &limit ) );
373 }
374
375 int
376 parse_limit(
377         const char              *arg,
378         struct slap_limits_set  *limit
379 )
380 {
381         assert( arg );
382         assert( limit );
383
384         if ( strncasecmp( arg, "time", 4 ) == 0 ) {
385                 arg += 4;
386
387                 if ( arg[0] == '.' ) {
388                         arg++;
389                         if ( strncasecmp( arg, "soft", 4 ) == 0 ) {
390                                 arg += 4;
391                                 if ( arg[0] != '=' ) {
392                                         return( 1 );
393                                 }
394                                 arg++;
395                                 limit->lms_t_soft = atoi( arg );
396                                 
397                         } else if ( strncasecmp( arg, "hard", 4 ) == 0 ) {
398                                 arg += 4;
399                                 if ( arg[0] != '=' ) {
400                                         return( 1 );
401                                 }
402                                 arg++;
403                                 if ( strcasecmp( arg, "soft" ) == 0 ) {
404                                         limit->lms_t_hard = 0;
405                                 } else if ( strcasecmp( arg, "none" ) == 0 ) {
406                                         limit->lms_t_hard = -1;
407                                 } else {
408                                         limit->lms_t_hard = atoi( arg );
409                                 }
410                                 
411                         } else {
412                                 return( 1 );
413                         }
414                         
415                 } else if ( arg[0] == '=' ) {
416                         limit->lms_t_soft = atoi( arg );
417                         limit->lms_t_hard = 0;
418                         
419                 } else {
420                         return( 1 );
421                 }
422
423         } else if ( strncasecmp( arg, "size", 4 ) == 0 ) {
424                 arg += 4;
425                 
426                 if ( arg[0] == '.' ) {
427                         arg++;
428                         if ( strncasecmp( arg, "soft", 4 ) == 0 ) {
429                                 arg += 4;
430                                 if ( arg[0] != '=' ) {
431                                         return( 1 );
432                                 }
433                                 arg++;
434                                 limit->lms_s_soft = atoi( arg );
435                                 
436                         } else if ( strncasecmp( arg, "hard", 4 ) == 0 ) {
437                                 arg += 4;
438                                 if ( arg[0] != '=' ) {
439                                         return( 1 );
440                                 }
441                                 arg++;
442                                 if ( strcasecmp( arg, "soft" ) == 0 ) {
443                                         limit->lms_s_hard = 0;
444                                 } else if ( strcasecmp( arg, "none" ) == 0 ) {
445                                         limit->lms_s_hard = -1;
446                                 } else {
447                                         limit->lms_s_hard = atoi( arg );
448                                 }
449                                 
450                         } else if ( strncasecmp( arg, "unchecked", 9 ) == 0 ) {
451                                 arg += 9;
452                                 if ( arg[0] != '=' ) {
453                                         return( 1 );
454                                 }
455                                 arg++;
456                                 if ( strcasecmp( arg, "none" ) == 0 ) {
457                                         limit->lms_s_unchecked = -1;
458                                 } else {
459                                         limit->lms_s_unchecked = atoi( arg );
460                                 }
461                                 
462                         } else {
463                                 return( 1 );
464                         }
465                         
466                 } else if ( arg[0] == '=' ) {
467                         limit->lms_s_soft = atoi( arg );
468                         limit->lms_s_hard = 0;
469                         
470                 } else {
471                         return( 1 );
472                 }
473         }
474
475         return 0;
476 }
477