1 /* limits.c - routines to handle regex-based size and time limits */ 2 /* $OpenLDAP: pkg/ldap/servers/slapd/limits.c,v 1.73.2.6 2008/02/11 23:26:44 kurt Exp $ */ 3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2008 The OpenLDAP Foundation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted only as authorized by the OpenLDAP 10 * Public License. 11 * 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>. 15 */ 16 17 #include "portable.h" 18 19 #include <stdio.h> 20 21 #include <ac/regex.h> 22 #include <ac/string.h> 23 24 #include "slap.h" 25 #include "lutil.h" 26 27 /* define to get an error if requesting limit higher than hard */ 28 #undef ABOVE_HARD_LIMIT_IS_ERROR 29 30 static char * 31 limits2str( unsigned i ) 32 { 33 switch ( i ) { 34 case SLAP_LIMITS_UNDEFINED: 35 return "UNDEFINED"; 36 37 case SLAP_LIMITS_EXACT: 38 return "EXACT"; 39 40 case SLAP_LIMITS_ONE: 41 return "ONELEVEL"; 42 43 case SLAP_LIMITS_SUBTREE: 44 return "SUBTREE"; 45 46 case SLAP_LIMITS_CHILDREN: 47 return "CHILDREN"; 48 49 case SLAP_LIMITS_REGEX: 50 return "REGEX"; 51 52 case SLAP_LIMITS_ANONYMOUS: 53 return "ANONYMOUS"; 54 55 case SLAP_LIMITS_USERS: 56 return "USERS"; 57 58 case SLAP_LIMITS_ANY: 59 return "ANY"; 60 61 default: 62 return "UNKNOWN"; 63 } 64 } 65 66 int 67 limits_get( 68 Operation *op, 69 struct berval *ndn, 70 struct slap_limits_set **limit 71 ) 72 { 73 struct slap_limits **lm; 74 75 assert( op != NULL ); 76 assert( limit != NULL ); 77 78 Debug( LDAP_DEBUG_TRACE, "==> limits_get: %s dn=\"%s\"\n", 79 op->o_log_prefix, 80 BER_BVISNULL( ndn ) ? "[anonymous]" : ndn->bv_val, 0 ); 81 /* 82 * default values 83 */ 84 *limit = &op->o_bd->be_def_limit; 85 86 if ( op->o_bd->be_limits == NULL ) { 87 return( 0 ); 88 } 89 90 for ( lm = op->o_bd->be_limits; lm[0] != NULL; lm++ ) { 91 unsigned style = lm[0]->lm_flags & SLAP_LIMITS_MASK; 92 unsigned type = lm[0]->lm_flags & SLAP_LIMITS_TYPE_MASK; 93 94 switch ( style ) { 95 case SLAP_LIMITS_EXACT: 96 if ( BER_BVISEMPTY( ndn ) ) { 97 break; 98 } 99 100 if ( type == SLAP_LIMITS_TYPE_GROUP ) { 101 int rc; 102 103 rc = backend_group( op, NULL, 104 &lm[0]->lm_pat, ndn, 105 lm[0]->lm_group_oc, 106 lm[0]->lm_group_ad ); 107 if ( rc == 0 ) { 108 *limit = &lm[0]->lm_limits; 109 Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=GROUP match=EXACT " 110 "dn=\"%s\" oc=\"%s\" ad=\"%s\"\n", 111 lm[0]->lm_pat.bv_val, 112 lm[0]->lm_group_oc->soc_cname.bv_val, 113 lm[0]->lm_group_ad->ad_cname.bv_val ); 114 115 return( 0 ); 116 } 117 } else { 118 119 if ( dn_match( &lm[0]->lm_pat, ndn ) ) { 120 *limit = &lm[0]->lm_limits; 121 Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=DN match=EXACT dn=\"%s\"\n", 122 lm[0]->lm_pat.bv_val, 0, 0 ); 123 return( 0 ); 124 } 125 } 126 break; 127 128 case SLAP_LIMITS_ONE: 129 case SLAP_LIMITS_SUBTREE: 130 case SLAP_LIMITS_CHILDREN: { 131 size_t d; 132 133 if ( BER_BVISEMPTY( ndn ) ) { 134 break; 135 } 136 137 /* ndn shorter than dn_pat */ 138 if ( ndn->bv_len < lm[0]->lm_pat.bv_len ) { 139 break; 140 } 141 d = ndn->bv_len - lm[0]->lm_pat.bv_len; 142 143 /* allow exact match for SUBTREE only */ 144 if ( d == 0 ) { 145 if ( style != SLAP_LIMITS_SUBTREE ) { 146 break; 147 } 148 } else { 149 /* check for unescaped rdn separator */ 150 if ( !DN_SEPARATOR( ndn->bv_val[d - 1] ) ) { 151 break; 152 } 153 } 154 155 /* in case of (sub)match ... */ 156 if ( lm[0]->lm_pat.bv_len == ( ndn->bv_len - d ) 157 && strcmp( lm[0]->lm_pat.bv_val, 158 &ndn->bv_val[d] ) == 0 ) 159 { 160 /* check for exactly one rdn in case of ONE */ 161 if ( style == SLAP_LIMITS_ONE ) { 162 /* 163 * if ndn is more that one rdn 164 * below dn_pat, continue 165 */ 166 if ( (size_t) dn_rdnlen( NULL, ndn ) 167 != d - 1 ) 168 { 169 break; 170 } 171 } 172 173 *limit = &lm[0]->lm_limits; 174 Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=DN match=%s dn=\"%s\"\n", 175 limits2str( style ), lm[0]->lm_pat.bv_val, 0 ); 176 return( 0 ); 177 } 178 179 break; 180 } 181 182 case SLAP_LIMITS_REGEX: 183 if ( BER_BVISEMPTY( ndn ) ) { 184 break; 185 } 186 if ( regexec( &lm[0]->lm_regex, ndn->bv_val, 187 0, NULL, 0 ) == 0 ) 188 { 189 *limit = &lm[0]->lm_limits; 190 Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=DN match=%s dn=\"%s\"\n", 191 limits2str( style ), lm[0]->lm_pat.bv_val, 0 ); 192 return( 0 ); 193 } 194 break; 195 196 case SLAP_LIMITS_ANONYMOUS: 197 if ( BER_BVISEMPTY( ndn ) ) { 198 Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=DN match=%s\n", 199 limits2str( style ), 0, 0 ); 200 *limit = &lm[0]->lm_limits; 201 return( 0 ); 202 } 203 break; 204 205 case SLAP_LIMITS_USERS: 206 if ( !BER_BVISEMPTY( ndn ) ) { 207 *limit = &lm[0]->lm_limits; 208 Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=DN match=%s\n", 209 limits2str( style ), 0, 0 ); 210 return( 0 ); 211 } 212 break; 213 214 case SLAP_LIMITS_ANY: 215 *limit = &lm[0]->lm_limits; 216 return( 0 ); 217 218 default: 219 assert( 0 ); /* unreachable */ 220 return( -1 ); 221 } 222 } 223 224 return( 0 ); 225 } 226 227 static int 228 limits_add( 229 Backend *be, 230 unsigned flags, 231 const char *pattern, 232 ObjectClass *group_oc, 233 AttributeDescription *group_ad, 234 struct slap_limits_set *limit 235 ) 236 { 237 int i; 238 struct slap_limits *lm; 239 unsigned type, style; 240 241 assert( be != NULL ); 242 assert( limit != NULL ); 243 244 type = flags & SLAP_LIMITS_TYPE_MASK; 245 style = flags & SLAP_LIMITS_MASK; 246 247 switch ( style ) { 248 case SLAP_LIMITS_ANONYMOUS: 249 case SLAP_LIMITS_USERS: 250 case SLAP_LIMITS_ANY: 251 for ( i = 0; be->be_limits && be->be_limits[ i ]; i++ ) { 252 if ( be->be_limits[ i ]->lm_flags == style ) { 253 return( -1 ); 254 } 255 } 256 break; 257 } 258 259 260 lm = ( struct slap_limits * )ch_calloc( sizeof( struct slap_limits ), 1 ); 261 262 switch ( style ) { 263 case SLAP_LIMITS_UNDEFINED: 264 style = SLAP_LIMITS_EXACT; 265 /* continue to next cases */ 266 case SLAP_LIMITS_EXACT: 267 case SLAP_LIMITS_ONE: 268 case SLAP_LIMITS_SUBTREE: 269 case SLAP_LIMITS_CHILDREN: 270 lm->lm_flags = style | type; 271 { 272 int rc; 273 struct berval bv; 274 275 ber_str2bv( pattern, 0, 0, &bv ); 276 277 rc = dnNormalize( 0, NULL, NULL, &bv, &lm->lm_pat, NULL ); 278 if ( rc != LDAP_SUCCESS ) { 279 ch_free( lm ); 280 return( -1 ); 281 } 282 } 283 break; 284 285 case SLAP_LIMITS_REGEX: 286 lm->lm_flags = style | type; 287 ber_str2bv( pattern, 0, 1, &lm->lm_pat ); 288 if ( regcomp( &lm->lm_regex, lm->lm_pat.bv_val, 289 REG_EXTENDED | REG_ICASE ) ) { 290 free( lm->lm_pat.bv_val ); 291 ch_free( lm ); 292 return( -1 ); 293 } 294 break; 295 296 case SLAP_LIMITS_ANONYMOUS: 297 case SLAP_LIMITS_USERS: 298 case SLAP_LIMITS_ANY: 299 lm->lm_flags = style | type; 300 BER_BVZERO( &lm->lm_pat ); 301 break; 302 } 303 304 switch ( type ) { 305 case SLAP_LIMITS_TYPE_GROUP: 306 assert( group_oc != NULL ); 307 assert( group_ad != NULL ); 308 lm->lm_group_oc = group_oc; 309 lm->lm_group_ad = group_ad; 310 break; 311 } 312 313 lm->lm_limits = *limit; 314 315 i = 0; 316 if ( be->be_limits != NULL ) { 317 for ( ; be->be_limits[i]; i++ ); 318 } 319 320 be->be_limits = ( struct slap_limits ** )ch_realloc( be->be_limits, 321 sizeof( struct slap_limits * ) * ( i + 2 ) ); 322 be->be_limits[i] = lm; 323 be->be_limits[i+1] = NULL; 324 325 return( 0 ); 326 } 327 328 int 329 limits_parse( 330 Backend *be, 331 const char *fname, 332 int lineno, 333 int argc, 334 char **argv 335 ) 336 { 337 int flags = SLAP_LIMITS_UNDEFINED; 338 char *pattern; 339 struct slap_limits_set limit; 340 int i, rc = 0; 341 ObjectClass *group_oc = NULL; 342 AttributeDescription *group_ad = NULL; 343 344 assert( be != NULL ); 345 346 if ( argc < 3 ) { 347 Debug( LDAP_DEBUG_ANY, 348 "%s : line %d: missing arg(s) in " 349 "\"limits <pattern> <limits>\" line.\n%s", 350 fname, lineno, "" ); 351 return( -1 ); 352 } 353 354 limit = be->be_def_limit; 355 356 /* 357 * syntax: 358 * 359 * "limits" <pattern> <limit> [ ... ] 360 * 361 * 362 * <pattern>: 363 * 364 * "anonymous" 365 * "users" 366 * [ "dn" [ "." { "exact" | "base" | "onelevel" | "subtree" | children" 367 * | "regex" | "anonymous" } ] "=" ] <dn pattern> 368 * 369 * Note: 370 * "exact" and "base" are the same (exact match); 371 * "onelevel" means exactly one rdn below, NOT including pattern 372 * "subtree" means any rdn below, including pattern 373 * "children" means any rdn below, NOT including pattern 374 * 375 * "anonymous" may be deprecated in favour 376 * of the pattern = "anonymous" form 377 * 378 * "group[/objectClass[/attributeType]]" "=" "<dn pattern>" 379 * 380 * <limit>: 381 * 382 * "time" [ "." { "soft" | "hard" } ] "=" <integer> 383 * 384 * "size" [ "." { "soft" | "hard" | "unchecked" } ] "=" <integer> 385 */ 386 387 pattern = argv[1]; 388 if ( strcmp( pattern, "*" ) == 0) { 389 flags = SLAP_LIMITS_ANY; 390 391 } else if ( strcasecmp( pattern, "anonymous" ) == 0 ) { 392 flags = SLAP_LIMITS_ANONYMOUS; 393 394 } else if ( strcasecmp( pattern, "users" ) == 0 ) { 395 flags = SLAP_LIMITS_USERS; 396 397 } else if ( strncasecmp( pattern, "dn", STRLENOF( "dn" ) ) == 0 ) { 398 pattern += STRLENOF( "dn" ); 399 if ( pattern[0] == '.' ) { 400 pattern++; 401 if ( strncasecmp( pattern, "exact", STRLENOF( "exact" )) == 0 ) { 402 flags = SLAP_LIMITS_EXACT; 403 pattern += STRLENOF( "exact" ); 404 405 } else if ( strncasecmp( pattern, "base", STRLENOF( "base" ) ) == 0 ) { 406 flags = SLAP_LIMITS_BASE; 407 pattern += STRLENOF( "base" ); 408 409 } else if ( strncasecmp( pattern, "one", STRLENOF( "one" ) ) == 0 ) { 410 flags = SLAP_LIMITS_ONE; 411 pattern += STRLENOF( "one" ); 412 if ( strncasecmp( pattern, "level", STRLENOF( "level" ) ) == 0 ) { 413 pattern += STRLENOF( "level" ); 414 415 } else { 416 Debug( LDAP_DEBUG_ANY, 417 "%s : line %d: deprecated \"one\" style " 418 "\"limits <pattern> <limits>\" line; " 419 "use \"onelevel\" instead.\n", fname, lineno, 0 ); 420 } 421 422 } else if ( strncasecmp( pattern, "sub", STRLENOF( "sub" ) ) == 0 ) { 423 flags = SLAP_LIMITS_SUBTREE; 424 pattern += STRLENOF( "sub" ); 425 if ( strncasecmp( pattern, "tree", STRLENOF( "tree" ) ) == 0 ) { 426 pattern += STRLENOF( "tree" ); 427 428 } else { 429 Debug( LDAP_DEBUG_ANY, 430 "%s : line %d: deprecated \"sub\" style " 431 "\"limits <pattern> <limits>\" line; " 432 "use \"subtree\" instead.\n", fname, lineno, 0 ); 433 } 434 435 } else if ( strncasecmp( pattern, "children", STRLENOF( "children" ) ) == 0 ) { 436 flags = SLAP_LIMITS_CHILDREN; 437 pattern += STRLENOF( "children" ); 438 439 } else if ( strncasecmp( pattern, "regex", STRLENOF( "regex" ) ) == 0 ) { 440 flags = SLAP_LIMITS_REGEX; 441 pattern += STRLENOF( "regex" ); 442 443 /* 444 * this could be deprecated in favour 445 * of the pattern = "anonymous" form 446 */ 447 } else if ( strncasecmp( pattern, "anonymous", STRLENOF( "anonymous" ) ) == 0 ) { 448 flags = SLAP_LIMITS_ANONYMOUS; 449 pattern = NULL; 450 } 451 } 452 453 /* pre-check the data */ 454 switch ( flags ) { 455 case SLAP_LIMITS_ANONYMOUS: 456 case SLAP_LIMITS_USERS: 457 458 /* no need for pattern */ 459 pattern = NULL; 460 break; 461 462 default: 463 if ( pattern[0] != '=' ) { 464 Debug( LDAP_DEBUG_ANY, 465 "%s : line %d: missing '=' in " 466 "\"dn[.{exact|base|onelevel|subtree" 467 "|children|regex|anonymous}]" 468 "=<pattern>\" in " 469 "\"limits <pattern> <limits>\" " 470 "line.\n%s", 471 fname, lineno, "" ); 472 return( -1 ); 473 } 474 475 /* skip '=' (required) */ 476 pattern++; 477 478 /* trim obvious cases */ 479 if ( strcmp( pattern, "*" ) == 0 ) { 480 flags = SLAP_LIMITS_ANY; 481 pattern = NULL; 482 483 } else if ( flags == SLAP_LIMITS_REGEX 484 && strcmp( pattern, ".*" ) == 0 ) { 485 flags = SLAP_LIMITS_ANY; 486 pattern = NULL; 487 } 488 } 489 490 } else if (strncasecmp( pattern, "group", STRLENOF( "group" ) ) == 0 ) { 491 pattern += STRLENOF( "group" ); 492 493 if ( pattern[0] == '/' ) { 494 struct berval oc, ad; 495 496 oc.bv_val = pattern + 1; 497 pattern = strchr( pattern, '=' ); 498 if ( pattern == NULL ) { 499 return -1; 500 } 501 502 ad.bv_val = strchr( oc.bv_val, '/' ); 503 if ( ad.bv_val != NULL ) { 504 const char *text = NULL; 505 506 oc.bv_len = ad.bv_val - oc.bv_val; 507 508 ad.bv_val++; 509 ad.bv_len = pattern - ad.bv_val; 510 rc = slap_bv2ad( &ad, &group_ad, &text ); 511 if ( rc != LDAP_SUCCESS ) { 512 goto no_ad; 513 } 514 515 } else { 516 oc.bv_len = pattern - oc.bv_val; 517 } 518 519 group_oc = oc_bvfind( &oc ); 520 if ( group_oc == NULL ) { 521 goto no_oc; 522 } 523 } 524 525 if ( group_oc == NULL ) { 526 group_oc = oc_find( SLAPD_GROUP_CLASS ); 527 if ( group_oc == NULL ) { 528 no_oc:; 529 return( -1 ); 530 } 531 } 532 533 if ( group_ad == NULL ) { 534 const char *text = NULL; 535 536 rc = slap_str2ad( SLAPD_GROUP_ATTR, &group_ad, &text ); 537 538 if ( rc != LDAP_SUCCESS ) { 539 no_ad:; 540 return( -1 ); 541 } 542 } 543 544 flags = SLAP_LIMITS_TYPE_GROUP | SLAP_LIMITS_EXACT; 545 546 if ( pattern[0] != '=' ) { 547 Debug( LDAP_DEBUG_ANY, 548 "%s : line %d: missing '=' in " 549 "\"group[/objectClass[/attributeType]]" 550 "=<pattern>\" in " 551 "\"limits <pattern> <limits>\" line.\n", 552 fname, lineno, 0 ); 553 return( -1 ); 554 } 555 556 /* skip '=' (required) */ 557 pattern++; 558 } 559 560 /* get the limits */ 561 for ( i = 2; i < argc; i++ ) { 562 if ( limits_parse_one( argv[i], &limit ) ) { 563 564 Debug( LDAP_DEBUG_ANY, 565 "%s : line %d: unknown limit values \"%s\" in " 566 "\"limits <pattern> <limits>\" line.\n", 567 fname, lineno, argv[i] ); 568 569 return( 1 ); 570 } 571 } 572 573 /* 574 * sanity checks ... 575 * 576 * FIXME: add warnings? 577 */ 578 if ( limit.lms_t_hard > 0 && 579 ( limit.lms_t_hard < limit.lms_t_soft 580 || limit.lms_t_soft == -1 ) ) { 581 limit.lms_t_hard = limit.lms_t_soft; 582 } 583 584 if ( limit.lms_s_hard > 0 && 585 ( limit.lms_s_hard < limit.lms_s_soft 586 || limit.lms_s_soft == -1 ) ) { 587 limit.lms_s_hard = limit.lms_s_soft; 588 } 589 590 /* 591 * defaults ... 592 * 593 * lms_t_hard: 594 * -1 => no limits 595 * 0 => same as soft 596 * > 0 => limit (in seconds) 597 * 598 * lms_s_hard: 599 * -1 => no limits 600 * 0 0> same as soft 601 * > 0 => limit (in entries) 602 * 603 * lms_s_pr_total: 604 * -2 => disable the control 605 * -1 => no limits 606 * 0 => same as soft 607 * > 0 => limit (in entries) 608 * 609 * lms_s_pr: 610 * -1 => no limits 611 * 0 => no limits? 612 * > 0 => limit size (in entries) 613 */ 614 if ( limit.lms_s_pr_total > 0 && 615 limit.lms_s_pr > limit.lms_s_pr_total ) { 616 limit.lms_s_pr = limit.lms_s_pr_total; 617 } 618 619 rc = limits_add( be, flags, pattern, group_oc, group_ad, &limit ); 620 if ( rc ) { 621 622 Debug( LDAP_DEBUG_ANY, 623 "%s : line %d: unable to add limit in " 624 "\"limits <pattern> <limits>\" line.\n", 625 fname, lineno, 0 ); 626 } 627 628 return( rc ); 629 } 630 631 int 632 limits_parse_one( 633 const char *arg, 634 struct slap_limits_set *limit 635 ) 636 { 637 assert( arg != NULL ); 638 assert( limit != NULL ); 639 640 if ( strncasecmp( arg, "time", STRLENOF( "time" ) ) == 0 ) { 641 arg += STRLENOF( "time" ); 642 643 if ( arg[0] == '.' ) { 644 arg++; 645 if ( strncasecmp( arg, "soft=", STRLENOF( "soft=" ) ) == 0 ) { 646 arg += STRLENOF( "soft=" ); 647 if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { 648 limit->lms_t_soft = -1; 649 650 } else { 651 int soft; 652 653 if ( lutil_atoi( &soft, arg ) != 0 || soft < -1 ) { 654 return( 1 ); 655 } 656 657 if ( soft == -1 ) { 658 /* FIXME: use "unlimited" instead; issue warning? */ 659 } 660 661 limit->lms_t_soft = soft; 662 } 663 664 } else if ( strncasecmp( arg, "hard=", STRLENOF( "hard=" ) ) == 0 ) { 665 arg += STRLENOF( "hard=" ); 666 if ( strcasecmp( arg, "soft" ) == 0 ) { 667 limit->lms_t_hard = 0; 668 669 } else if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { 670 limit->lms_t_hard = -1; 671 672 } else { 673 int hard; 674 675 if ( lutil_atoi( &hard, arg ) != 0 || hard < -1 ) { 676 return( 1 ); 677 } 678 679 if ( hard == -1 ) { 680 /* FIXME: use "unlimited" instead */ 681 } 682 683 if ( hard == 0 ) { 684 /* FIXME: use "soft" instead */ 685 } 686 687 limit->lms_t_hard = hard; 688 } 689 690 } else { 691 return( 1 ); 692 } 693 694 } else if ( arg[0] == '=' ) { 695 arg++; 696 if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { 697 limit->lms_t_soft = -1; 698 699 } else { 700 if ( lutil_atoi( &limit->lms_t_soft, arg ) != 0 701 || limit->lms_t_soft < -1 ) 702 { 703 return( 1 ); 704 } 705 } 706 limit->lms_t_hard = 0; 707 708 } else { 709 return( 1 ); 710 } 711 712 } else if ( strncasecmp( arg, "size", STRLENOF( "size" ) ) == 0 ) { 713 arg += STRLENOF( "size" ); 714 715 if ( arg[0] == '.' ) { 716 arg++; 717 if ( strncasecmp( arg, "soft=", STRLENOF( "soft=" ) ) == 0 ) { 718 arg += STRLENOF( "soft=" ); 719 if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { 720 limit->lms_s_soft = -1; 721 722 } else { 723 int soft; 724 725 if ( lutil_atoi( &soft, arg ) != 0 || soft < -1 ) { 726 return( 1 ); 727 } 728 729 if ( soft == -1 ) { 730 /* FIXME: use "unlimited" instead */ 731 } 732 733 limit->lms_s_soft = soft; 734 } 735 736 } else if ( strncasecmp( arg, "hard=", STRLENOF( "hard=" ) ) == 0 ) { 737 arg += STRLENOF( "hard=" ); 738 if ( strcasecmp( arg, "soft" ) == 0 ) { 739 limit->lms_s_hard = 0; 740 741 } else if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { 742 limit->lms_s_hard = -1; 743 744 } else { 745 int hard; 746 747 if ( lutil_atoi( &hard, arg ) != 0 || hard < -1 ) { 748 return( 1 ); 749 } 750 751 if ( hard == -1 ) { 752 /* FIXME: use "unlimited" instead */ 753 } 754 755 if ( hard == 0 ) { 756 /* FIXME: use "soft" instead */ 757 } 758 759 limit->lms_s_hard = hard; 760 } 761 762 } else if ( strncasecmp( arg, "unchecked=", STRLENOF( "unchecked=" ) ) == 0 ) { 763 arg += STRLENOF( "unchecked=" ); 764 if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { 765 limit->lms_s_unchecked = -1; 766 767 } else if ( strcasecmp( arg, "disabled" ) == 0 ) { 768 limit->lms_s_unchecked = 0; 769 770 } else { 771 int unchecked; 772 773 if ( lutil_atoi( &unchecked, arg ) != 0 || unchecked < -1 ) { 774 return( 1 ); 775 } 776 777 if ( unchecked == -1 ) { 778 /* FIXME: use "unlimited" instead */ 779 } 780 781 limit->lms_s_unchecked = unchecked; 782 } 783 784 } else if ( strncasecmp( arg, "pr=", STRLENOF( "pr=" ) ) == 0 ) { 785 arg += STRLENOF( "pr=" ); 786 if ( strcasecmp( arg, "noEstimate" ) == 0 ) { 787 limit->lms_s_pr_hide = 1; 788 789 } else if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { 790 limit->lms_s_pr = -1; 791 792 } else { 793 int pr; 794 795 if ( lutil_atoi( &pr, arg ) != 0 || pr < -1 ) { 796 return( 1 ); 797 } 798 799 if ( pr == -1 ) { 800 /* FIXME: use "unlimited" instead */ 801 } 802 803 limit->lms_s_pr = pr; 804 } 805 806 } else if ( strncasecmp( arg, "prtotal=", STRLENOF( "prtotal=" ) ) == 0 ) { 807 arg += STRLENOF( "prtotal=" ); 808 809 if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { 810 limit->lms_s_pr_total = -1; 811 812 } else if ( strcasecmp( arg, "disabled" ) == 0 ) { 813 limit->lms_s_pr_total = -2; 814 815 } else if ( strcasecmp( arg, "hard" ) == 0 ) { 816 limit->lms_s_pr_total = 0; 817 818 } else { 819 int total; 820 821 if ( lutil_atoi( &total, arg ) != 0 || total < -1 ) { 822 return( 1 ); 823 } 824 825 if ( total == -1 ) { 826 /* FIXME: use "unlimited" instead */ 827 } 828 829 if ( total == 0 ) { 830 /* FIXME: use "pr=disable" instead */ 831 } 832 833 limit->lms_s_pr_total = total; 834 } 835 836 } else { 837 return( 1 ); 838 } 839 840 } else if ( arg[0] == '=' ) { 841 arg++; 842 if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { 843 limit->lms_s_soft = -1; 844 845 } else { 846 if ( lutil_atoi( &limit->lms_s_soft, arg ) != 0 847 || limit->lms_s_soft < -1 ) 848 { 849 return( 1 ); 850 } 851 } 852 limit->lms_s_hard = 0; 853 854 } else { 855 return( 1 ); 856 } 857 } 858 859 return 0; 860 } 861 862 static const char *lmpats[] = { 863 "base", 864 "base", 865 "onelevel", 866 "subtree", 867 "children", 868 "regex", 869 "anonymous", 870 "users", 871 "*" 872 }; 873 874 #define WHATSLEFT ( buflen - ( ptr - bv->bv_val ) ) 875 876 /* Caller must provide an adequately sized buffer in bv */ 877 int 878 limits_unparse( struct slap_limits *lim, struct berval *bv, ber_len_t buflen ) 879 { 880 struct berval btmp; 881 char *ptr; 882 int lm; 883 884 if ( !bv || !bv->bv_val ) return -1; 885 886 ptr = bv->bv_val; 887 888 if (( lim->lm_flags & SLAP_LIMITS_TYPE_MASK ) == SLAP_LIMITS_TYPE_GROUP ) { 889 if ( WHATSLEFT <= STRLENOF( "group/" "/" "=\"" "\"" ) 890 + lim->lm_group_oc->soc_cname.bv_len 891 + lim->lm_group_ad->ad_cname.bv_len 892 + lim->lm_pat.bv_len ) return -1; 893 894 ptr = lutil_strcopy( ptr, "group/" ); 895 ptr = lutil_strcopy( ptr, lim->lm_group_oc->soc_cname.bv_val ); 896 *ptr++ = '/'; 897 ptr = lutil_strcopy( ptr, lim->lm_group_ad->ad_cname.bv_val ); 898 ptr = lutil_strcopy( ptr, "=\"" ); 899 ptr = lutil_strcopy( ptr, lim->lm_pat.bv_val ); 900 *ptr++ = '"'; 901 } else { 902 lm = lim->lm_flags & SLAP_LIMITS_MASK; 903 switch( lm ) { 904 case SLAP_LIMITS_ANONYMOUS: 905 case SLAP_LIMITS_USERS: 906 case SLAP_LIMITS_ANY: 907 if ( WHATSLEFT <= strlen( lmpats[lm] ) ) return -1; 908 ptr = lutil_strcopy( ptr, lmpats[lm] ); 909 break; 910 case SLAP_LIMITS_UNDEFINED: 911 case SLAP_LIMITS_EXACT: 912 case SLAP_LIMITS_ONE: 913 case SLAP_LIMITS_SUBTREE: 914 case SLAP_LIMITS_CHILDREN: 915 case SLAP_LIMITS_REGEX: 916 if ( WHATSLEFT <= STRLENOF( "dn." "=" "\"" "\"" ) 917 + strlen( lmpats[lm] ) + lim->lm_pat.bv_len ) return -1; 918 ptr = lutil_strcopy( ptr, "dn." ); 919 ptr = lutil_strcopy( ptr, lmpats[lm] ); 920 *ptr++ = '='; 921 *ptr++ = '"'; 922 ptr = lutil_strcopy( ptr, lim->lm_pat.bv_val ); 923 *ptr++ = '"'; 924 break; 925 } 926 } 927 bv->bv_len = ptr - bv->bv_val; 928 btmp.bv_val = ptr; 929 btmp.bv_len = 0; 930 if ( limits_unparse_one( &lim->lm_limits, 931 SLAP_LIMIT_SIZE|SLAP_LIMIT_TIME, 932 &btmp, WHATSLEFT ) ) 933 { 934 return -1; 935 } 936 bv->bv_len += btmp.bv_len; 937 return 0; 938 } 939 940 /* Caller must provide an adequately sized buffer in bv */ 941 int 942 limits_unparse_one( struct slap_limits_set *lim, int which, struct berval *bv, ber_len_t buflen ) 943 { 944 char *ptr; 945 946 if ( !bv || !bv->bv_val ) return -1; 947 948 ptr = bv->bv_val; 949 950 if ( which & SLAP_LIMIT_SIZE ) { 951 if ( lim->lms_s_soft != SLAPD_DEFAULT_SIZELIMIT ) { 952 953 /* If same as global limit, drop it */ 954 if ( lim != &frontendDB->be_def_limit && 955 lim->lms_s_soft == frontendDB->be_def_limit.lms_s_soft ) 956 { 957 goto s_hard; 958 /* If there's also a hard limit, fully qualify this one */ 959 } else if ( lim->lms_s_hard ) { 960 if ( WHATSLEFT <= STRLENOF( " size.soft=" ) ) return -1; 961 ptr = lutil_strcopy( ptr, " size.soft=" ); 962 963 /* If doing both size & time, qualify this */ 964 } else if ( which & SLAP_LIMIT_TIME ) { 965 if ( WHATSLEFT <= STRLENOF( " size=" ) ) return -1; 966 ptr = lutil_strcopy( ptr, " size=" ); 967 } 968 969 if ( lim->lms_s_soft == -1 ) { 970 if ( WHATSLEFT <= STRLENOF( "unlimited" ) ) return -1; 971 ptr = lutil_strcopy( ptr, "unlimited" ); 972 } else { 973 ptr += snprintf( ptr, WHATSLEFT, "%d", lim->lms_s_soft ); 974 if ( WHATSLEFT < 0 ) return -1; 975 } 976 *ptr++ = ' '; 977 } 978 s_hard: 979 if ( lim->lms_s_hard ) { 980 if ( WHATSLEFT <= STRLENOF( " size.hard=" ) ) return -1; 981 ptr = lutil_strcopy( ptr, " size.hard=" ); 982 if ( lim->lms_s_hard == -1 ) { 983 if ( WHATSLEFT <= STRLENOF( "unlimited" ) ) return -1; 984 ptr = lutil_strcopy( ptr, "unlimited" ); 985 } else { 986 ptr += snprintf( ptr, WHATSLEFT, "%d", lim->lms_s_hard ); 987 if ( WHATSLEFT < 0 ) return -1; 988 } 989 *ptr++ = ' '; 990 } 991 if ( lim->lms_s_unchecked != -1 ) { 992 if ( WHATSLEFT <= STRLENOF( " size.unchecked=" ) ) return -1; 993 ptr = lutil_strcopy( ptr, " size.unchecked=" ); 994 if ( lim->lms_s_unchecked == 0 ) { 995 if ( WHATSLEFT <= STRLENOF( "disabled" ) ) return -1; 996 ptr = lutil_strcopy( ptr, "disabled" ); 997 } else { 998 ptr += snprintf( ptr, WHATSLEFT, "%d", lim->lms_s_unchecked ); 999 if ( WHATSLEFT < 0 ) return -1; 1000 } 1001 *ptr++ = ' '; 1002 } 1003 if ( lim->lms_s_pr_hide ) { 1004 if ( WHATSLEFT <= STRLENOF( " size.pr=noEstimate " ) ) return -1; 1005 ptr = lutil_strcopy( ptr, " size.pr=noEstimate " ); 1006 } 1007 if ( lim->lms_s_pr ) { 1008 if ( WHATSLEFT <= STRLENOF( " size.pr=" ) ) return -1; 1009 ptr = lutil_strcopy( ptr, " size.pr=" ); 1010 if ( lim->lms_s_pr == -1 ) { 1011 if ( WHATSLEFT <= STRLENOF( "unlimited" ) ) return -1; 1012 ptr = lutil_strcopy( ptr, "unlimited" ); 1013 } else { 1014 ptr += snprintf( ptr, WHATSLEFT, "%d", lim->lms_s_pr ); 1015 if ( WHATSLEFT < 0 ) return -1; 1016 } 1017 *ptr++ = ' '; 1018 } 1019 if ( lim->lms_s_pr_total ) { 1020 if ( WHATSLEFT <= STRLENOF( " size.prtotal=" ) ) return -1; 1021 ptr = lutil_strcopy( ptr, " size.prtotal=" ); 1022 if ( lim->lms_s_pr_total == -1 ) { 1023 if ( WHATSLEFT <= STRLENOF( "unlimited" ) ) return -1; 1024 ptr = lutil_strcopy( ptr, "unlimited" ); 1025 } else if ( lim->lms_s_pr_total == -2 ) { 1026 if ( WHATSLEFT <= STRLENOF( "disabled" ) ) return -1; 1027 ptr = lutil_strcopy( ptr, "disabled" ); 1028 } else { 1029 ptr += snprintf( ptr, WHATSLEFT, "%d", lim->lms_s_pr_total ); 1030 if ( WHATSLEFT < 0 ) return -1; 1031 } 1032 *ptr++ = ' '; 1033 } 1034 } 1035 1036 if ( which & SLAP_LIMIT_TIME ) { 1037 if ( lim->lms_t_soft != SLAPD_DEFAULT_TIMELIMIT ) { 1038 1039 /* If same as global limit, drop it */ 1040 if ( lim != &frontendDB->be_def_limit && 1041 lim->lms_t_soft == frontendDB->be_def_limit.lms_t_soft ) 1042 { 1043 goto t_hard; 1044 1045 /* If there's also a hard limit, fully qualify this one */ 1046 } else if ( lim->lms_t_hard ) { 1047 if ( WHATSLEFT <= STRLENOF( " time.soft=" ) ) return -1; 1048 ptr = lutil_strcopy( ptr, " time.soft=" ); 1049 1050 /* If doing both size & time, qualify this */ 1051 } else if ( which & SLAP_LIMIT_SIZE ) { 1052 if ( WHATSLEFT <= STRLENOF( " time=" ) ) return -1; 1053 ptr = lutil_strcopy( ptr, " time=" ); 1054 } 1055 1056 if ( lim->lms_t_soft == -1 ) { 1057 if ( WHATSLEFT <= STRLENOF( "unlimited" ) ) return -1; 1058 ptr = lutil_strcopy( ptr, "unlimited" ); 1059 } else { 1060 ptr += snprintf( ptr, WHATSLEFT, "%d", lim->lms_t_soft ); 1061 if ( WHATSLEFT < 0 ) return -1; 1062 } 1063 *ptr++ = ' '; 1064 } 1065 t_hard: 1066 if ( lim->lms_t_hard ) { 1067 if ( WHATSLEFT <= STRLENOF( " time.hard=" ) ) return -1; 1068 ptr = lutil_strcopy( ptr, " time.hard=" ); 1069 if ( lim->lms_t_hard == -1 ) { 1070 if ( WHATSLEFT <= STRLENOF( "unlimited" ) ) return -1; 1071 ptr = lutil_strcopy( ptr, "unlimited" ); 1072 } else { 1073 ptr += snprintf( ptr, WHATSLEFT, "%d", lim->lms_t_hard ); 1074 if ( WHATSLEFT < 0 ) return -1; 1075 } 1076 *ptr++ = ' '; 1077 } 1078 } 1079 if ( ptr != bv->bv_val ) { 1080 ptr--; 1081 *ptr = '\0'; 1082 bv->bv_len = ptr - bv->bv_val; 1083 } 1084 1085 return 0; 1086 } 1087 1088 int 1089 limits_check( Operation *op, SlapReply *rs ) 1090 { 1091 assert( op != NULL ); 1092 assert( rs != NULL ); 1093 /* FIXME: should this be always true? */ 1094 assert( op->o_tag == LDAP_REQ_SEARCH); 1095 1096 /* protocol only allows 0..maxInt; 1097 * 1098 * internal searches: 1099 * - may use SLAP_NO_LIMIT ( = -1 ) to indicate no limits; 1100 * - should use slimit = N and tlimit = SLAP_NO_LIMIT to 1101 * indicate searches that should return exactly N matches, 1102 * and handle errors thru a callback (see for instance 1103 * slap_sasl_match() and slap_sasl2dn()) 1104 */ 1105 if ( op->ors_tlimit == SLAP_NO_LIMIT && op->ors_slimit == SLAP_NO_LIMIT ) { 1106 return 0; 1107 } 1108 1109 /* allow root to set no limit */ 1110 if ( be_isroot( op ) ) { 1111 op->ors_limit = NULL; 1112 1113 if ( op->ors_tlimit == 0 ) { 1114 op->ors_tlimit = SLAP_NO_LIMIT; 1115 } 1116 1117 if ( op->ors_slimit == 0 ) { 1118 op->ors_slimit = SLAP_NO_LIMIT; 1119 } 1120 1121 /* if paged results and slimit are requested */ 1122 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED && 1123 op->ors_slimit != SLAP_NO_LIMIT ) { 1124 PagedResultsState *ps = op->o_pagedresults_state; 1125 int total = op->ors_slimit - ps->ps_count; 1126 if ( total > 0 ) { 1127 op->ors_slimit = total; 1128 } else { 1129 op->ors_slimit = 0; 1130 } 1131 } 1132 1133 /* if not root, get appropriate limits */ 1134 } else { 1135 ( void ) limits_get( op, &op->o_ndn, &op->ors_limit ); 1136 1137 assert( op->ors_limit != NULL ); 1138 1139 /* if no limit is required, use soft limit */ 1140 if ( op->ors_tlimit == 0 ) { 1141 op->ors_tlimit = op->ors_limit->lms_t_soft; 1142 1143 /* limit required: check if legal */ 1144 } else { 1145 if ( op->ors_limit->lms_t_hard == 0 ) { 1146 if ( op->ors_limit->lms_t_soft > 0 1147 && ( op->ors_tlimit > op->ors_limit->lms_t_soft ) ) { 1148 op->ors_tlimit = op->ors_limit->lms_t_soft; 1149 } 1150 1151 } else if ( op->ors_limit->lms_t_hard > 0 ) { 1152 #ifdef ABOVE_HARD_LIMIT_IS_ERROR 1153 if ( op->ors_tlimit == SLAP_MAX_LIMIT ) { 1154 op->ors_tlimit = op->ors_limit->lms_t_hard; 1155 1156 } else if ( op->ors_tlimit > op->ors_limit->lms_t_hard ) { 1157 /* error if exceeding hard limit */ 1158 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; 1159 send_ldap_result( op, rs ); 1160 rs->sr_err = LDAP_SUCCESS; 1161 return -1; 1162 } 1163 #else /* ! ABOVE_HARD_LIMIT_IS_ERROR */ 1164 if ( op->ors_tlimit > op->ors_limit->lms_t_hard ) { 1165 op->ors_tlimit = op->ors_limit->lms_t_hard; 1166 } 1167 #endif /* ! ABOVE_HARD_LIMIT_IS_ERROR */ 1168 } 1169 } 1170 1171 /* else leave as is */ 1172 1173 /* don't even get to backend if candidate check is disabled */ 1174 if ( op->ors_limit->lms_s_unchecked == 0 ) { 1175 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; 1176 send_ldap_result( op, rs ); 1177 rs->sr_err = LDAP_SUCCESS; 1178 return -1; 1179 } 1180 1181 /* if paged results is requested */ 1182 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { 1183 int slimit = -2; 1184 int pr_total; 1185 PagedResultsState *ps = op->o_pagedresults_state; 1186 1187 /* paged results is not allowed */ 1188 if ( op->ors_limit->lms_s_pr_total == -2 ) { 1189 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; 1190 rs->sr_text = "pagedResults control not allowed"; 1191 send_ldap_result( op, rs ); 1192 rs->sr_err = LDAP_SUCCESS; 1193 rs->sr_text = NULL; 1194 return -1; 1195 } 1196 1197 if ( op->ors_limit->lms_s_pr > 0 && ps->ps_size > op->ors_limit->lms_s_pr ) { 1198 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; 1199 rs->sr_text = "illegal pagedResults page size"; 1200 send_ldap_result( op, rs ); 1201 rs->sr_err = LDAP_SUCCESS; 1202 rs->sr_text = NULL; 1203 return -1; 1204 } 1205 1206 if ( op->ors_limit->lms_s_pr_total == 0 ) { 1207 if ( op->ors_limit->lms_s_hard == 0 ) { 1208 pr_total = op->ors_limit->lms_s_soft; 1209 } else { 1210 pr_total = op->ors_limit->lms_s_hard; 1211 } 1212 } else { 1213 pr_total = op->ors_limit->lms_s_pr_total; 1214 } 1215 1216 if ( pr_total == -1 ) { 1217 if ( op->ors_slimit == 0 || op->ors_slimit == SLAP_MAX_LIMIT ) { 1218 slimit = -1; 1219 1220 } else { 1221 slimit = op->ors_slimit - ps->ps_count; 1222 } 1223 1224 #ifdef ABOVE_HARD_LIMIT_IS_ERROR 1225 } else if ( pr_total > 0 && op->ors_slimit != SLAP_MAX_LIMIT 1226 && ( op->ors_slimit == SLAP_NO_LIMIT || op->ors_slimit > pr_total ) ) 1227 { 1228 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; 1229 send_ldap_result( op, rs ); 1230 rs->sr_err = LDAP_SUCCESS; 1231 return -1; 1232 #endif /* ! ABOVE_HARD_LIMIT_IS_ERROR */ 1233 1234 } else { 1235 /* if no limit is required, use soft limit */ 1236 int total; 1237 int slimit2; 1238 1239 /* first round of pagedResults: set count to any appropriate limit */ 1240 1241 /* if the limit is set, check that it does not violate any server-side limit */ 1242 #ifdef ABOVE_HARD_LIMIT_IS_ERROR 1243 if ( op->ors_slimit == SLAP_MAX_LIMIT ) { 1244 slimit2 = op->ors_slimit = pr_total; 1245 #else /* ! ABOVE_HARD_LIMIT_IS_ERROR */ 1246 if ( op->ors_slimit == SLAP_MAX_LIMIT || op->ors_slimit > pr_total ) { 1247 slimit2 = op->ors_slimit = pr_total; 1248 #endif /* ! ABOVE_HARD_LIMIT_IS_ERROR */ 1249 1250 } else if ( op->ors_slimit == 0 ) { 1251 slimit2 = pr_total; 1252 1253 } else { 1254 slimit2 = op->ors_slimit; 1255 } 1256 1257 total = slimit2 - ps->ps_count; 1258 1259 if ( total >= 0 ) { 1260 if ( op->ors_limit->lms_s_pr > 0 ) { 1261 /* use the smallest limit set by total/per page */ 1262 if ( total < op->ors_limit->lms_s_pr ) { 1263 slimit = total; 1264 1265 } else { 1266 /* use the perpage limit if any 1267 * NOTE: + 1 because the given value must be legal */ 1268 slimit = op->ors_limit->lms_s_pr + 1; 1269 } 1270 1271 } else { 1272 /* use the total limit if any */ 1273 slimit = total; 1274 } 1275 1276 } else if ( op->ors_limit->lms_s_pr > 0 ) { 1277 /* use the perpage limit if any 1278 * NOTE: + 1 because the given value must be legal */ 1279 slimit = op->ors_limit->lms_s_pr + 1; 1280 1281 } else { 1282 /* use the standard hard/soft limit if any */ 1283 slimit = op->ors_limit->lms_s_hard; 1284 } 1285 } 1286 1287 /* if got any limit, use it */ 1288 if ( slimit != -2 ) { 1289 if ( op->ors_slimit == 0 ) { 1290 op->ors_slimit = slimit; 1291 1292 } else if ( slimit > 0 ) { 1293 if ( op->ors_slimit - ps->ps_count > slimit ) { 1294 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; 1295 send_ldap_result( op, rs ); 1296 rs->sr_err = LDAP_SUCCESS; 1297 return -1; 1298 } 1299 op->ors_slimit = slimit; 1300 1301 } else if ( slimit == 0 ) { 1302 op->ors_slimit = 0; 1303 } 1304 1305 } else { 1306 /* use the standard hard/soft limit if any */ 1307 op->ors_slimit = pr_total; 1308 } 1309 1310 /* no limit requested: use soft, whatever it is */ 1311 } else if ( op->ors_slimit == 0 ) { 1312 op->ors_slimit = op->ors_limit->lms_s_soft; 1313 1314 /* limit requested: check if legal */ 1315 } else { 1316 /* hard limit as soft (traditional behavior) */ 1317 if ( op->ors_limit->lms_s_hard == 0 ) { 1318 if ( op->ors_limit->lms_s_soft > 0 1319 && op->ors_slimit > op->ors_limit->lms_s_soft ) { 1320 op->ors_slimit = op->ors_limit->lms_s_soft; 1321 } 1322 1323 /* explicit hard limit: error if violated */ 1324 } else if ( op->ors_limit->lms_s_hard > 0 ) { 1325 #ifdef ABOVE_HARD_LIMIT_IS_ERROR 1326 if ( op->ors_slimit == SLAP_MAX_LIMIT ) { 1327 op->ors_slimit = op->ors_limit->lms_s_hard; 1328 1329 } else if ( op->ors_slimit > op->ors_limit->lms_s_hard ) { 1330 /* if limit exceeds hard, error */ 1331 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; 1332 send_ldap_result( op, rs ); 1333 rs->sr_err = LDAP_SUCCESS; 1334 return -1; 1335 } 1336 #else /* ! ABOVE_HARD_LIMIT_IS_ERROR */ 1337 if ( op->ors_slimit > op->ors_limit->lms_s_hard ) { 1338 op->ors_slimit = op->ors_limit->lms_s_hard; 1339 } 1340 #endif /* ! ABOVE_HARD_LIMIT_IS_ERROR */ 1341 } 1342 } 1343 1344 /* else leave as is */ 1345 } 1346 1347 return 0; 1348 } 1349 1350 void 1351 limits_destroy( 1352 struct slap_limits **lm ) 1353 { 1354 int i; 1355 1356 if ( lm == NULL ) { 1357 return; 1358 } 1359 1360 for ( i = 0; lm[ i ]; i++ ) { 1361 switch ( lm[ i ]->lm_flags & SLAP_LIMITS_MASK ) { 1362 case SLAP_LIMITS_REGEX: 1363 regfree( &lm[ i ]->lm_regex ); 1364 break; 1365 1366 case SLAP_LIMITS_EXACT: 1367 case SLAP_LIMITS_ONE: 1368 case SLAP_LIMITS_SUBTREE: 1369 case SLAP_LIMITS_CHILDREN: 1370 if ( !BER_BVISNULL( &lm[ i ]->lm_pat ) ) { 1371 ch_free( lm[ i ]->lm_pat.bv_val ); 1372 } 1373 break; 1374 1375 default: 1376 break; 1377 } 1378 1379 ch_free( lm[ i ] ); 1380 } 1381 1382 ch_free( lm ); 1383 } 1384