]> git.sur5r.net Git - openldap/blob - servers/slapd/limits.c
aee2f7f7f17e943d081b6691b1f5140713e9593c
[openldap] / servers / slapd / limits.c
1 /* limits.c - routines to handle regex-based size and time limits */
2 /*
3  * Copyright 1998-2003 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         struct berval           *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->bv_len == 0 ) {
41                                 break;
42                         }
43                         if ( dn_match( &lm[0]->lm_dn_pat, ndn ) ) {
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                         size_t d;
53                         
54                         if ( ndn->bv_len == 0 ) {
55                                 break;
56                         }
57
58                         /* ndn shorter than dn_pat */
59                         if ( ndn->bv_len < lm[0]->lm_dn_pat.bv_len ) {
60                                 break;
61                         }
62                         d = ndn->bv_len - lm[0]->lm_dn_pat.bv_len;
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->bv_val[d-1] ) ) {
72                                         break;
73                                 }
74                         }
75
76                         /* in case of (sub)match ... */
77                         if ( lm[0]->lm_dn_pat.bv_len == ( ndn->bv_len - d )
78                                         && strcmp( lm[0]->lm_dn_pat.bv_val, &ndn->bv_val[d] ) == 0 ) {
79                                 /* check for exactly one rdn in case of ONE */
80                                 if ( lm[0]->lm_type == SLAP_LIMITS_ONE ) {
81                                         /*
82                                          * if ndn is more that one rdn
83                                          * below dn_pat, continue
84                                          */
85                                         if ( (size_t) dn_rdnlen( NULL, ndn ) != d - 1 ) {
86                                                 break;
87                                         }
88                                 }
89
90                                 *limit = &lm[0]->lm_limits;
91                                 return( 0 );
92                         }
93
94                         break;
95                 }
96
97                 case SLAP_LIMITS_REGEX:
98                         if ( ndn->bv_len == 0 ) {
99                                 break;
100                         }
101                         if ( regexec( &lm[0]->lm_dn_regex, ndn->bv_val, 0, NULL, 0 )
102                                 == 0 )
103                         {
104                                 *limit = &lm[0]->lm_limits;
105                                 return( 0 );
106                         }
107                         break;
108
109                 case SLAP_LIMITS_ANONYMOUS:
110                         if ( ndn->bv_len == 0 ) {
111                                 *limit = &lm[0]->lm_limits;
112                                 return( 0 );
113                         }
114                         break;
115
116                 case SLAP_LIMITS_USERS:
117                         if ( ndn->bv_len != 0 ) {
118                                 *limit = &lm[0]->lm_limits;
119                                 return( 0 );
120                         }
121                         break;
122
123                 case SLAP_LIMITS_ANY:
124                         *limit = &lm[0]->lm_limits;
125                         return( 0 );
126
127                 default:
128                         assert( 0 );    /* unreachable */
129                         return( -1 );
130                 }
131         }
132
133         return( 0 );
134 }
135
136 static int
137 add_limits(
138         Backend                 *be,
139         int                     type,
140         const char              *pattern,
141         struct slap_limits_set  *limit
142 )
143 {
144         int                     i;
145         struct slap_limits      *lm;
146         
147         assert( be );
148         assert( limit );
149
150         switch ( type ) {
151         case SLAP_LIMITS_ANONYMOUS:
152         case SLAP_LIMITS_USERS:
153         case SLAP_LIMITS_ANY:
154                 for ( i = 0; be->be_limits && be->be_limits[ i ]; i++ ) {
155                         if ( be->be_limits[ i ]->lm_type == type ) {
156                                 return( -1 );
157                         }
158                 }
159                 break;
160         }
161
162
163         lm = ( struct slap_limits * )ch_calloc( sizeof( struct slap_limits ), 1 );
164
165         switch ( type ) {
166         case SLAP_LIMITS_EXACT:
167         case SLAP_LIMITS_ONE:
168         case SLAP_LIMITS_SUBTREE:
169         case SLAP_LIMITS_CHILDREN:
170                 lm->lm_type = type;
171                 {
172                         int rc;
173                         struct berval bv;
174                         bv.bv_val = (char *) pattern;
175                         bv.bv_len = strlen( pattern );
176
177                         rc = dnNormalize( 0, NULL, NULL, &bv, &lm->lm_dn_pat, NULL );
178                         if ( rc != LDAP_SUCCESS ) {
179                                 ch_free( lm );
180                                 return( -1 );
181                         }
182                 }
183                 break;
184                 
185         case SLAP_LIMITS_REGEX:
186         case SLAP_LIMITS_UNDEFINED:
187                 lm->lm_type = SLAP_LIMITS_REGEX;
188                 ber_str2bv( pattern, 0, 1, &lm->lm_dn_pat );
189                 if ( regcomp( &lm->lm_dn_regex, lm->lm_dn_pat.bv_val, 
190                                         REG_EXTENDED | REG_ICASE ) ) {
191                         free( lm->lm_dn_pat.bv_val );
192                         ch_free( lm );
193                         return( -1 );
194                 }
195                 break;
196
197         case SLAP_LIMITS_ANONYMOUS:
198         case SLAP_LIMITS_USERS:
199         case SLAP_LIMITS_ANY:
200                 lm->lm_type = type;
201                 lm->lm_dn_pat.bv_val = NULL;
202                 lm->lm_dn_pat.bv_len = 0;
203                 break;
204         }
205
206         lm->lm_limits = *limit;
207
208         i = 0;
209         if ( be->be_limits != NULL ) {
210                 for ( ; be->be_limits[i]; i++ );
211         }
212
213         be->be_limits = ( struct slap_limits ** )ch_realloc( be->be_limits,
214                         sizeof( struct slap_limits * ) * ( i + 2 ) );
215         be->be_limits[i] = lm;
216         be->be_limits[i+1] = NULL;
217         
218         return( 0 );
219 }
220
221 int
222 parse_limits(
223         Backend     *be,
224         const char  *fname,
225         int         lineno,
226         int         argc,
227         char        **argv
228 )
229 {
230         int     type = SLAP_LIMITS_UNDEFINED;
231         char    *pattern;
232         struct slap_limits_set limit;
233         int     i, rc = 0;
234
235         assert( be );
236
237         if ( argc < 3 ) {
238 #ifdef NEW_LOGGING
239                 LDAP_LOG( CONFIG, CRIT, 
240                         "%s : line %d: missing arg(s) in "
241                         "\"limits <pattern> <limits>\" line.\n", fname, lineno, 0 );
242 #else
243                 Debug( LDAP_DEBUG_ANY,
244                         "%s : line %d: missing arg(s) in "
245                         "\"limits <pattern> <limits>\" line.\n%s",
246                         fname, lineno, "" );
247 #endif
248                 return( -1 );
249         }
250
251         limit = be->be_def_limit;
252
253         /*
254          * syntax:
255          *
256          * "limits" <pattern> <limit> [ ... ]
257          * 
258          * 
259          * <pattern>:
260          * 
261          * "anonymous"
262          * "users"
263          * [ "dn" [ "." { "exact" | "base" | "one" | "sub" | children" 
264          *      | "regex" | "anonymous" } ] "=" ] <dn pattern>
265          *
266          * Note:
267          *      "exact" and "base" are the same (exact match);
268          *      "one" means exactly one rdn below, NOT including the pattern
269          *      "sub" means any rdn below, including the pattern
270          *      "children" means any rdn below, NOT including the pattern
271          *      
272          *      "anonymous" may be deprecated in favour 
273          *      of the pattern = "anonymous" form
274          *
275          *
276          * <limit>:
277          *
278          * "time" [ "." { "soft" | "hard" } ] "=" <integer>
279          *
280          * "size" [ "." { "soft" | "hard" | "unchecked" } ] "=" <integer>
281          */
282         
283         pattern = argv[1];
284         if ( strcmp( pattern, "*" ) == 0) {
285                 type = SLAP_LIMITS_ANY;
286
287         } else if ( strcasecmp( pattern, "anonymous" ) == 0 ) {
288                 type = SLAP_LIMITS_ANONYMOUS;
289
290         } else if ( strcasecmp( pattern, "users" ) == 0 ) {
291                 type = SLAP_LIMITS_USERS;
292                 
293         } else if ( strncasecmp( pattern, "dn", sizeof( "dn") - 1 ) == 0 ) {
294                 pattern += 2;
295                 if ( pattern[0] == '.' ) {
296                         pattern++;
297                         if ( strncasecmp( pattern, "exact", sizeof( "exact" ) - 1 ) == 0 ) {
298                                 type = SLAP_LIMITS_EXACT;
299                                 pattern += 5;
300
301                         } else if ( strncasecmp( pattern, "base", sizeof( "base " ) - 1 ) == 0 ) {
302                                 type = SLAP_LIMITS_BASE;
303                                 pattern += 4;
304
305                         } else if ( strncasecmp( pattern, "one", sizeof( "one" ) - 1 ) == 0 ) {
306                                 type = SLAP_LIMITS_ONE;
307                                 pattern += 3;
308
309                         } else if ( strncasecmp( pattern, "subtree", sizeof( "subtree" ) - 1 ) == 0 ) {
310                                 type = SLAP_LIMITS_SUBTREE;
311                                 pattern += 7;
312
313                         } else if ( strncasecmp( pattern, "children", sizeof( "children" ) - 1 ) == 0 ) {
314                                 type = SLAP_LIMITS_CHILDREN;
315                                 pattern += 8;
316
317                         } else if ( strncasecmp( pattern, "regex", sizeof( "regex" ) - 1 ) == 0 ) {
318                                 type = SLAP_LIMITS_REGEX;
319                                 pattern += 5;
320
321                         /* 
322                          * this could be deprecated in favour
323                          * of the pattern = "anonymous" form
324                          */
325                         } else if ( strncasecmp( pattern, "anonymous", sizeof( "anonymous" ) - 1 ) == 0 ) {
326                                 type = SLAP_LIMITS_ANONYMOUS;
327                                 pattern = NULL;
328                         }
329                 }
330
331                 /* pre-check the data */
332                 switch ( type ) {
333                 case SLAP_LIMITS_ANONYMOUS:
334                 case SLAP_LIMITS_USERS:
335
336                         /* no need for pattern */
337                         pattern = NULL;
338                         break;
339
340                 default:
341                         if ( pattern[0] != '=' ) {
342 #ifdef NEW_LOGGING
343                                 LDAP_LOG( CONFIG, CRIT, 
344                                         "%s : line %d: missing '=' in "
345                                         "\"dn[.{exact|base|one|subtree"
346                                         "|children|regex|anonymous}]" "=<pattern>\" in "
347                                         "\"limits <pattern> <limits>\" line.\n", fname, lineno, 0 );
348 #else
349                                 Debug( LDAP_DEBUG_ANY,
350                                         "%s : line %d: missing '=' in "
351                                         "\"dn[.{exact|base|one|subtree"
352                                         "|children|regex|anonymous}]"
353                                         "=<pattern>\" in "
354                                         "\"limits <pattern> <limits>\" "
355                                         "line.\n%s",
356                                         fname, lineno, "" );
357 #endif
358                                 return( -1 );
359                         }
360
361                         /* skip '=' (required) */
362                         pattern++;
363
364                         /* trim obvious cases */
365                         if ( strcmp( pattern, "*" ) == 0 ) {
366                                 type = SLAP_LIMITS_ANY;
367                                 pattern = NULL;
368
369                         } else if ( ( type == SLAP_LIMITS_REGEX || type == SLAP_LIMITS_UNDEFINED ) 
370                                         && strcmp( pattern, ".*" ) == 0 ) {
371                                 type = SLAP_LIMITS_ANY;
372                                 pattern = NULL;
373                         }
374                 }
375         }
376
377         /* get the limits */
378         for ( i = 2; i < argc; i++ ) {
379                 if ( parse_limit( argv[i], &limit ) ) {
380
381 #ifdef NEW_LOGGING
382                         LDAP_LOG( CONFIG, CRIT, 
383                                 "%s : line %d: unknown limit type \"%s\" in "
384                                 "\"limits <pattern> <limits>\" line.\n",
385                                 fname, lineno, argv[i] );
386 #else
387                         Debug( LDAP_DEBUG_ANY,
388                                 "%s : line %d: unknown limit type \"%s\" in "
389                                 "\"limits <pattern> <limits>\" line.\n",
390                         fname, lineno, argv[i] );
391 #endif
392
393                         return( 1 );
394                 }
395         }
396
397         /*
398          * sanity checks ...
399          */
400         if ( limit.lms_t_hard > 0 && 
401                         ( limit.lms_t_hard < limit.lms_t_soft 
402                           || limit.lms_t_soft == -1 ) ) {
403                 limit.lms_t_hard = limit.lms_t_soft;
404         }
405         
406         if ( limit.lms_s_hard > 0 && 
407                         ( limit.lms_s_hard < limit.lms_s_soft 
408                           || limit.lms_s_soft == -1 ) ) {
409                 limit.lms_s_hard = limit.lms_s_soft;
410         }
411         
412         rc = add_limits( be, type, pattern, &limit );
413         if ( rc ) {
414
415 #ifdef NEW_LOGGING
416                 LDAP_LOG( CONFIG, CRIT, 
417                         "%s : line %d: unable to add limit in "
418                         "\"limits <pattern> <limits>\" line.\n",
419                         fname, lineno, 0 );
420 #else
421                 Debug( LDAP_DEBUG_ANY,
422                         "%s : line %d: unable to add limit in "
423                         "\"limits <pattern> <limits>\" line.\n",
424                 fname, lineno, 0 );
425 #endif
426         }
427
428         return( rc );
429 }
430
431 int
432 parse_limit(
433         const char              *arg,
434         struct slap_limits_set  *limit
435 )
436 {
437         assert( arg );
438         assert( limit );
439
440         if ( strncasecmp( arg, "time", sizeof( "time" ) - 1 ) == 0 ) {
441                 arg += 4;
442
443                 if ( arg[0] == '.' ) {
444                         arg++;
445                         if ( strncasecmp( arg, "soft", sizeof( "soft" ) - 1 ) == 0 ) {
446                                 arg += 4;
447                                 if ( arg[0] != '=' ) {
448                                         return( 1 );
449                                 }
450                                 arg++;
451                                 if ( strcasecmp( arg, "none" ) == 0 ) {
452                                         limit->lms_t_soft = -1;
453                                 } else {
454                                         char    *next = NULL;
455
456                                         limit->lms_t_soft = 
457                                                 strtol( arg, &next, 10 );
458                                         if ( next == arg || limit->lms_t_soft < -1 ) {
459                                                 return( 1 );
460                                         }
461                                 }
462                                 
463                         } else if ( strncasecmp( arg, "hard", sizeof( "hard" ) - 1 ) == 0 ) {
464                                 arg += 4;
465                                 if ( arg[0] != '=' ) {
466                                         return( 1 );
467                                 }
468                                 arg++;
469                                 if ( strcasecmp( arg, "soft" ) == 0 ) {
470                                         limit->lms_t_hard = 0;
471                                 } else if ( strcasecmp( arg, "none" ) == 0 ) {
472                                         limit->lms_t_hard = -1;
473                                 } else {
474                                         char    *next = NULL;
475
476                                         limit->lms_t_hard = 
477                                                 strtol( arg, &next, 10 );
478                                         if ( next == arg || limit->lms_t_hard < -1 ) {
479                                                 return( 1 );
480                                         }
481                                 }
482                                 
483                         } else {
484                                 return( 1 );
485                         }
486                         
487                 } else if ( arg[0] == '=' ) {
488                         arg++;
489                         if ( strcasecmp( arg, "none" ) == 0 ) {
490                                 limit->lms_t_soft = -1;
491                         } else {
492                                 char    *next = NULL;
493
494                                 limit->lms_t_soft = strtol( arg, &next, 10 );
495                                 if ( next == arg || limit->lms_t_soft < -1 ) {
496                                         return( 1 );
497                                 }
498                         }
499                         limit->lms_t_hard = 0;
500                         
501                 } else {
502                         return( 1 );
503                 }
504
505         } else if ( strncasecmp( arg, "size", sizeof( "size" ) - 1 ) == 0 ) {
506                 arg += 4;
507                 
508                 if ( arg[0] == '.' ) {
509                         arg++;
510                         if ( strncasecmp( arg, "soft", sizeof( "soft" ) - 1 ) == 0 ) {
511                                 arg += 4;
512                                 if ( arg[0] != '=' ) {
513                                         return( 1 );
514                                 }
515                                 arg++;
516                                 if ( strcasecmp( arg, "none" ) == 0 ) {
517                                         limit->lms_s_soft = -1;
518                                 } else {
519                                         char    *next = NULL;
520
521                                         limit->lms_s_soft = 
522                                                 strtol( arg, &next, 10 );
523                                         if ( next == arg || limit->lms_s_soft < -1 ) {
524                                                 return( 1 );
525                                         }
526                                 }
527                                 
528                         } else if ( strncasecmp( arg, "hard", sizeof( "hard" ) - 1 ) == 0 ) {
529                                 arg += 4;
530                                 if ( arg[0] != '=' ) {
531                                         return( 1 );
532                                 }
533                                 arg++;
534                                 if ( strcasecmp( arg, "soft" ) == 0 ) {
535                                         limit->lms_s_hard = 0;
536                                 } else if ( strcasecmp( arg, "none" ) == 0 ) {
537                                         limit->lms_s_hard = -1;
538                                 } else {
539                                         char    *next = NULL;
540
541                                         limit->lms_s_hard = 
542                                                 strtol( arg, &next, 10 );
543                                         if ( next == arg || limit->lms_s_hard < -1 ) {
544                                                 return( 1 );
545                                         }
546                                 }
547                                 
548                         } else if ( strncasecmp( arg, "unchecked", sizeof( "unchecked" ) - 1 ) == 0 ) {
549                                 arg += 9;
550                                 if ( arg[0] != '=' ) {
551                                         return( 1 );
552                                 }
553                                 arg++;
554                                 if ( strcasecmp( arg, "none" ) == 0 ) {
555                                         limit->lms_s_unchecked = -1;
556                                 } else {
557                                         char    *next = NULL;
558
559                                         limit->lms_s_unchecked = 
560                                                 strtol( arg, &next, 10 );
561                                         if ( next == arg || limit->lms_s_unchecked < -1 ) {
562                                                 return( 1 );
563                                         }
564                                 }
565
566                         } else if ( strncasecmp( arg, "pr", sizeof( "pr" ) - 1 ) == 0 ) {
567                                 arg += sizeof( "pr" ) - 1;
568                                 if ( arg[0] != '=' ) {
569                                         return( 1 );
570                                 }
571                                 arg++;
572                                 if ( strcasecmp( arg, "noEstimate" ) == 0 ) {
573                                         limit->lms_s_pr_hide = 1;
574                                 } else {
575                                         char    *next = NULL;
576
577                                         limit->lms_s_pr = 
578                                                 strtol( arg, &next, 10 );
579                                         if ( next == arg || limit->lms_s_pr < -1 ) {
580                                                 return( 1 );
581                                         }
582                                 }
583                                 
584                         } else {
585                                 return( 1 );
586                         }
587                         
588                 } else if ( arg[0] == '=' ) {
589                         arg++;
590                         if ( strcasecmp( arg, "none" ) == 0 ) {
591                                 limit->lms_s_soft = -1;
592                         } else {
593                                 char    *next = NULL;
594
595                                 limit->lms_s_soft = strtol( arg, &next, 10 );
596                                 if ( next == arg || limit->lms_s_soft < -1 ) {
597                                         return( 1 );
598                                 }
599                         }
600                         limit->lms_s_hard = 0;
601                         
602                 } else {
603                         return( 1 );
604                 }
605         }
606
607         return 0;
608 }
609