1 /* limits.c - routines to handle regex-based size and time limits */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2004 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
22 #include <ac/string.h>
30 struct slap_limits_set **limit
33 struct slap_limits **lm;
41 *limit = &be->be_def_limit;
43 if ( be->be_limits == NULL ) {
47 for ( lm = be->be_limits; lm[0] != NULL; lm++ ) {
48 switch ( lm[0]->lm_type ) {
49 case SLAP_LIMITS_EXACT:
50 if ( ndn->bv_len == 0 ) {
53 if ( dn_match( &lm[0]->lm_dn_pat, ndn ) ) {
54 *limit = &lm[0]->lm_limits;
60 case SLAP_LIMITS_SUBTREE:
61 case SLAP_LIMITS_CHILDREN: {
64 if ( ndn->bv_len == 0 ) {
68 /* ndn shorter than dn_pat */
69 if ( ndn->bv_len < lm[0]->lm_dn_pat.bv_len ) {
72 d = ndn->bv_len - lm[0]->lm_dn_pat.bv_len;
74 /* allow exact match for SUBTREE only */
76 if ( lm[0]->lm_type != SLAP_LIMITS_SUBTREE ) {
80 /* check for unescaped rdn separator */
81 if ( !DN_SEPARATOR( ndn->bv_val[d-1] ) ) {
86 /* in case of (sub)match ... */
87 if ( lm[0]->lm_dn_pat.bv_len == ( ndn->bv_len - d )
88 && strcmp( lm[0]->lm_dn_pat.bv_val, &ndn->bv_val[d] ) == 0 ) {
89 /* check for exactly one rdn in case of ONE */
90 if ( lm[0]->lm_type == SLAP_LIMITS_ONE ) {
92 * if ndn is more that one rdn
93 * below dn_pat, continue
95 if ( (size_t) dn_rdnlen( NULL, ndn ) != d - 1 ) {
100 *limit = &lm[0]->lm_limits;
107 case SLAP_LIMITS_REGEX:
108 if ( ndn->bv_len == 0 ) {
111 if ( regexec( &lm[0]->lm_dn_regex, ndn->bv_val, 0, NULL, 0 )
114 *limit = &lm[0]->lm_limits;
119 case SLAP_LIMITS_ANONYMOUS:
120 if ( ndn->bv_len == 0 ) {
121 *limit = &lm[0]->lm_limits;
126 case SLAP_LIMITS_USERS:
127 if ( ndn->bv_len != 0 ) {
128 *limit = &lm[0]->lm_limits;
133 case SLAP_LIMITS_ANY:
134 *limit = &lm[0]->lm_limits;
138 assert( 0 ); /* unreachable */
151 struct slap_limits_set *limit
155 struct slap_limits *lm;
161 case SLAP_LIMITS_ANONYMOUS:
162 case SLAP_LIMITS_USERS:
163 case SLAP_LIMITS_ANY:
164 for ( i = 0; be->be_limits && be->be_limits[ i ]; i++ ) {
165 if ( be->be_limits[ i ]->lm_type == type ) {
173 lm = ( struct slap_limits * )ch_calloc( sizeof( struct slap_limits ), 1 );
176 case SLAP_LIMITS_EXACT:
177 case SLAP_LIMITS_ONE:
178 case SLAP_LIMITS_SUBTREE:
179 case SLAP_LIMITS_CHILDREN:
184 bv.bv_val = (char *) pattern;
185 bv.bv_len = strlen( pattern );
187 rc = dnNormalize( 0, NULL, NULL, &bv, &lm->lm_dn_pat, NULL );
188 if ( rc != LDAP_SUCCESS ) {
195 case SLAP_LIMITS_REGEX:
196 case SLAP_LIMITS_UNDEFINED:
197 lm->lm_type = SLAP_LIMITS_REGEX;
198 ber_str2bv( pattern, 0, 1, &lm->lm_dn_pat );
199 if ( regcomp( &lm->lm_dn_regex, lm->lm_dn_pat.bv_val,
200 REG_EXTENDED | REG_ICASE ) ) {
201 free( lm->lm_dn_pat.bv_val );
207 case SLAP_LIMITS_ANONYMOUS:
208 case SLAP_LIMITS_USERS:
209 case SLAP_LIMITS_ANY:
211 lm->lm_dn_pat.bv_val = NULL;
212 lm->lm_dn_pat.bv_len = 0;
216 lm->lm_limits = *limit;
219 if ( be->be_limits != NULL ) {
220 for ( ; be->be_limits[i]; i++ );
223 be->be_limits = ( struct slap_limits ** )ch_realloc( be->be_limits,
224 sizeof( struct slap_limits * ) * ( i + 2 ) );
225 be->be_limits[i] = lm;
226 be->be_limits[i+1] = NULL;
240 int type = SLAP_LIMITS_UNDEFINED;
242 struct slap_limits_set limit;
249 LDAP_LOG( CONFIG, CRIT,
250 "%s : line %d: missing arg(s) in "
251 "\"limits <pattern> <limits>\" line.\n", fname, lineno, 0 );
253 Debug( LDAP_DEBUG_ANY,
254 "%s : line %d: missing arg(s) in "
255 "\"limits <pattern> <limits>\" line.\n%s",
261 limit = be->be_def_limit;
266 * "limits" <pattern> <limit> [ ... ]
273 * [ "dn" [ "." { "exact" | "base" | "one" | "sub" | children"
274 * | "regex" | "anonymous" } ] "=" ] <dn pattern>
277 * "exact" and "base" are the same (exact match);
278 * "one" means exactly one rdn below, NOT including the pattern
279 * "sub" means any rdn below, including the pattern
280 * "children" means any rdn below, NOT including the pattern
282 * "anonymous" may be deprecated in favour
283 * of the pattern = "anonymous" form
288 * "time" [ "." { "soft" | "hard" } ] "=" <integer>
290 * "size" [ "." { "soft" | "hard" | "unchecked" } ] "=" <integer>
294 if ( strcmp( pattern, "*" ) == 0) {
295 type = SLAP_LIMITS_ANY;
297 } else if ( strcasecmp( pattern, "anonymous" ) == 0 ) {
298 type = SLAP_LIMITS_ANONYMOUS;
300 } else if ( strcasecmp( pattern, "users" ) == 0 ) {
301 type = SLAP_LIMITS_USERS;
303 } else if ( strncasecmp( pattern, "dn", sizeof( "dn") - 1 ) == 0 ) {
305 if ( pattern[0] == '.' ) {
307 if ( strncasecmp( pattern, "exact", sizeof( "exact" ) - 1 ) == 0 ) {
308 type = SLAP_LIMITS_EXACT;
311 } else if ( strncasecmp( pattern, "base", sizeof( "base " ) - 1 ) == 0 ) {
312 type = SLAP_LIMITS_BASE;
315 } else if ( strncasecmp( pattern, "one", sizeof( "one" ) - 1 ) == 0 ) {
316 type = SLAP_LIMITS_ONE;
319 } else if ( strncasecmp( pattern, "subtree", sizeof( "subtree" ) - 1 ) == 0 ) {
320 type = SLAP_LIMITS_SUBTREE;
323 } else if ( strncasecmp( pattern, "children", sizeof( "children" ) - 1 ) == 0 ) {
324 type = SLAP_LIMITS_CHILDREN;
327 } else if ( strncasecmp( pattern, "regex", sizeof( "regex" ) - 1 ) == 0 ) {
328 type = SLAP_LIMITS_REGEX;
332 * this could be deprecated in favour
333 * of the pattern = "anonymous" form
335 } else if ( strncasecmp( pattern, "anonymous", sizeof( "anonymous" ) - 1 ) == 0 ) {
336 type = SLAP_LIMITS_ANONYMOUS;
341 /* pre-check the data */
343 case SLAP_LIMITS_ANONYMOUS:
344 case SLAP_LIMITS_USERS:
346 /* no need for pattern */
351 if ( pattern[0] != '=' ) {
353 LDAP_LOG( CONFIG, CRIT,
354 "%s : line %d: missing '=' in "
355 "\"dn[.{exact|base|one|subtree"
356 "|children|regex|anonymous}]" "=<pattern>\" in "
357 "\"limits <pattern> <limits>\" line.\n", fname, lineno, 0 );
359 Debug( LDAP_DEBUG_ANY,
360 "%s : line %d: missing '=' in "
361 "\"dn[.{exact|base|one|subtree"
362 "|children|regex|anonymous}]"
364 "\"limits <pattern> <limits>\" "
371 /* skip '=' (required) */
374 /* trim obvious cases */
375 if ( strcmp( pattern, "*" ) == 0 ) {
376 type = SLAP_LIMITS_ANY;
379 } else if ( ( type == SLAP_LIMITS_REGEX || type == SLAP_LIMITS_UNDEFINED )
380 && strcmp( pattern, ".*" ) == 0 ) {
381 type = SLAP_LIMITS_ANY;
388 for ( i = 2; i < argc; i++ ) {
389 if ( parse_limit( argv[i], &limit ) ) {
392 LDAP_LOG( CONFIG, CRIT,
393 "%s : line %d: unknown limit type \"%s\" in "
394 "\"limits <pattern> <limits>\" line.\n",
395 fname, lineno, argv[i] );
397 Debug( LDAP_DEBUG_ANY,
398 "%s : line %d: unknown limit type \"%s\" in "
399 "\"limits <pattern> <limits>\" line.\n",
400 fname, lineno, argv[i] );
410 if ( limit.lms_t_hard > 0 &&
411 ( limit.lms_t_hard < limit.lms_t_soft
412 || limit.lms_t_soft == -1 ) ) {
413 limit.lms_t_hard = limit.lms_t_soft;
416 if ( limit.lms_s_hard > 0 &&
417 ( limit.lms_s_hard < limit.lms_s_soft
418 || limit.lms_s_soft == -1 ) ) {
419 limit.lms_s_hard = limit.lms_s_soft;
422 rc = add_limits( be, type, pattern, &limit );
426 LDAP_LOG( CONFIG, CRIT,
427 "%s : line %d: unable to add limit in "
428 "\"limits <pattern> <limits>\" line.\n",
431 Debug( LDAP_DEBUG_ANY,
432 "%s : line %d: unable to add limit in "
433 "\"limits <pattern> <limits>\" line.\n",
444 struct slap_limits_set *limit
450 if ( strncasecmp( arg, "time", sizeof( "time" ) - 1 ) == 0 ) {
453 if ( arg[0] == '.' ) {
455 if ( strncasecmp( arg, "soft", sizeof( "soft" ) - 1 ) == 0 ) {
457 if ( arg[0] != '=' ) {
461 if ( strcasecmp( arg, "none" ) == 0 ) {
462 limit->lms_t_soft = -1;
467 strtol( arg, &next, 10 );
468 if ( next == arg || limit->lms_t_soft < -1 ) {
473 } else if ( strncasecmp( arg, "hard", sizeof( "hard" ) - 1 ) == 0 ) {
475 if ( arg[0] != '=' ) {
479 if ( strcasecmp( arg, "soft" ) == 0 ) {
480 limit->lms_t_hard = 0;
481 } else if ( strcasecmp( arg, "none" ) == 0 ) {
482 limit->lms_t_hard = -1;
487 strtol( arg, &next, 10 );
488 if ( next == arg || limit->lms_t_hard < -1 ) {
497 } else if ( arg[0] == '=' ) {
499 if ( strcasecmp( arg, "none" ) == 0 ) {
500 limit->lms_t_soft = -1;
504 limit->lms_t_soft = strtol( arg, &next, 10 );
505 if ( next == arg || limit->lms_t_soft < -1 ) {
509 limit->lms_t_hard = 0;
515 } else if ( strncasecmp( arg, "size", sizeof( "size" ) - 1 ) == 0 ) {
518 if ( arg[0] == '.' ) {
520 if ( strncasecmp( arg, "soft", sizeof( "soft" ) - 1 ) == 0 ) {
522 if ( arg[0] != '=' ) {
526 if ( strcasecmp( arg, "none" ) == 0 ) {
527 limit->lms_s_soft = -1;
532 strtol( arg, &next, 10 );
533 if ( next == arg || limit->lms_s_soft < -1 ) {
538 } else if ( strncasecmp( arg, "hard", sizeof( "hard" ) - 1 ) == 0 ) {
540 if ( arg[0] != '=' ) {
544 if ( strcasecmp( arg, "soft" ) == 0 ) {
545 limit->lms_s_hard = 0;
546 } else if ( strcasecmp( arg, "none" ) == 0 ) {
547 limit->lms_s_hard = -1;
552 strtol( arg, &next, 10 );
553 if ( next == arg || limit->lms_s_hard < -1 ) {
558 } else if ( strncasecmp( arg, "unchecked", sizeof( "unchecked" ) - 1 ) == 0 ) {
560 if ( arg[0] != '=' ) {
564 if ( strcasecmp( arg, "none" ) == 0 ) {
565 limit->lms_s_unchecked = -1;
569 limit->lms_s_unchecked =
570 strtol( arg, &next, 10 );
571 if ( next == arg || limit->lms_s_unchecked < -1 ) {
576 } else if ( strncasecmp( arg, "pr", sizeof( "pr" ) - 1 ) == 0 ) {
577 arg += sizeof( "pr" ) - 1;
578 if ( arg[0] != '=' ) {
582 if ( strcasecmp( arg, "noEstimate" ) == 0 ) {
583 limit->lms_s_pr_hide = 1;
588 strtol( arg, &next, 10 );
589 if ( next == arg || limit->lms_s_pr < -1 ) {
598 } else if ( arg[0] == '=' ) {
600 if ( strcasecmp( arg, "none" ) == 0 ) {
601 limit->lms_s_soft = -1;
605 limit->lms_s_soft = strtol( arg, &next, 10 );
606 if ( next == arg || limit->lms_s_soft < -1 ) {
610 limit->lms_s_hard = 0;