From d8eff4d1b5dc2dc582307c65f8a3d5b333339963 Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Tue, 22 Jun 2004 09:43:41 +0000 Subject: [PATCH] use hard limit instead of returning adminLimitExceeded when requested limit exceeds hard; improve (and document) syntax; modify test025 accordingly --- doc/man/man5/slapd.conf.5 | 67 +++++++++++++++++++++--------------- servers/slapd/limits.c | 54 ++++++++++++++++++++--------- tests/data/slapd-limits.conf | 8 ++--- tests/scripts/test025-limits | 62 +++++++++++++++++++++------------ 4 files changed, 122 insertions(+), 69 deletions(-) diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5 index 5a26bcf907..d495e94000 100644 --- a/doc/man/man5/slapd.conf.5 +++ b/doc/man/man5/slapd.conf.5 @@ -807,8 +807,6 @@ e.g. ldapi:// (and eventually IPSEC). It is not normally used. Specify the maximum number of entries to return from a search operation. The default size limit is 500. Use -.B -1 -or .B unlimited to specify no limits. The second format allows a fine grain setting of the size limits. @@ -841,8 +839,6 @@ Specify the maximum number of seconds (in real time) .B slapd will spend answering a search request. The default time limit is 3600. Use -.B -1 -or .B unlimited to specify no limits. The second format allows a fine grain setting of the time limits. @@ -1070,21 +1066,22 @@ and The syntax for time limits is .BR time[.{soft|hard}]= , where -.BR integer +.I integer is the number of seconds slapd will spend answering a search request. If no time limit is explicitly requested by the client, the .BR soft limit is used; if the requested time limit exceeds the .BR hard -limit, an -.I "Administrative limit exceeded" -error is returned. +.\"limit, an +.\".I "Administrative limit exceeded" +.\"error is returned. +limit, the value of the limit is used instead. If the .BR hard limit is set to the keyword .IR soft , the soft limit is used in either case; if it is set to the keyword -.IR none , +.IR unlimited , no hard limit is enforced. Explicit requests for time limits smaller or equal to the .BR hard @@ -1093,27 +1090,30 @@ If no limit specifier is set, the value is assigned to the .BR soft limit, and the .BR hard -limit is set to soft, to preserve the original behavior. +limit is set to +.IR soft , +to preserve the original behavior. The syntax for size limits is .BR size[.{soft|hard|unchecked}]= , where -.BR integer +.I integer is the maximum number of entries slapd will return answering a search request. If no size limit is explicitly requested by the client, the .BR soft limit is used; if the requested size limit exceeds the .BR hard -limit, an -.I "Administrative limit exceeded" -error is returned. +.\"limit, an +.\".I "Administrative limit exceeded" +.\"error is returned. +limit, the value of the limit is used instead. If the .BR hard limit is set to the keyword .IR soft , the soft limit is used in either case; if it is set to the keyword -.IR none , +.IR unlimited , no hard limit is enforced. Explicit requests for size limits smaller or equal to the .BR hard @@ -1122,12 +1122,21 @@ The .BR unchecked specifier sets a limit on the number of candidates a search request is allowed to examine. +The rationale behind it is that searches for non-properly indicized +attributes may result in large sets of candidates, which must be +examined by +.BR slapd (8) +to determine whether they match the search filter or not. +The +.B unckeched +limit provides a means to drop such operations before they are even +started. If the selected candidates exceed the .BR unchecked limit, the search will abort with .IR "Unwilling to perform" . If it is set to the keyword -.IR none , +.IR unlimited , no limit is applied (the default). If it is set to .IR disable , @@ -1137,7 +1146,9 @@ If no limit specifier is set, the value is assigned to the .BR soft limit, and the .BR hard -limit is set to soft, to preserve the original behavior. +limit is set to +.IR soft , +to preserve the original behavior. In case of no match, the global limits are used. The default values are the same of @@ -1157,31 +1168,33 @@ of entries to be returned. However, the size limit applies to the total count of entries returned within the search, and not to a single page. Additional size limits may be enforced; the syntax is -.BR size.pr={|noEstimate|none} , +.BR size.pr={|noEstimate|unlimited} , where -.B integer +.I integer is the max page size if no explicit limit is set; the keyword .I noEstimate inhibits the server from returning an estimate of the total number -of entries that might be returned; the keyword -.I none +of entries that might be returned +(note: the current implementation does not return any estimate). +The keyword +.I unlimited indicates that no limit is applied to the pagedResults control page size. The syntax -.B size.prtotal={|none|disabled} +.B size.prtotal={|unlimited|disabled} allows to set a limit on the total number of entries that a pagedResults control allows to return. By default it is set to the .B hard limit. When set, -.B integer +.I integer is the max number of entries that the whole search with pagedResults control can return. Use -.B none -to allow unlimited number of entries to be returned, i.e. to use -pagedResults as a means to allow clients to circumvent size limitations -on regular searches; the keyword +.I unlimited +to allow unlimited number of entries to be returned, e.g. to allow +the use of the pagedResults control as a means to circumvent size +limitations on regular searches; the keyword .I disabled disables the control, i.e. no paged results can be returned. Note that the total number of entries returned when the pagedResults control diff --git a/servers/slapd/limits.c b/servers/slapd/limits.c index ff4479ce03..c60e734068 100644 --- a/servers/slapd/limits.c +++ b/servers/slapd/limits.c @@ -23,6 +23,9 @@ #include "slap.h" +/* define to get an error if requesting limit higher than hard */ +#undef ABOVE_HARD_LIMIT_IS_ERROR + static char * limits2str( unsigned i ) { @@ -734,7 +737,7 @@ limits_parse_one( arg++; if ( strncasecmp( arg, "soft=", STRLENOF( "soft=" ) ) == 0 ) { arg += STRLENOF( "soft=" ); - if ( strcasecmp( arg, "none" ) == 0 ) { + if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { limit->lms_t_soft = -1; } else { @@ -750,7 +753,7 @@ limits_parse_one( } if ( soft == -1 ) { - /* FIXME: use "none" instead */ + /* FIXME: use "unlimited" instead; issue warning? */ } limit->lms_t_soft = soft; @@ -761,7 +764,7 @@ limits_parse_one( if ( strcasecmp( arg, "soft" ) == 0 ) { limit->lms_t_hard = 0; - } else if ( strcasecmp( arg, "none" ) == 0 ) { + } else if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { limit->lms_t_hard = -1; } else { @@ -777,7 +780,7 @@ limits_parse_one( } if ( hard == -1 ) { - /* FIXME: use "none" instead */ + /* FIXME: use "unlimited" instead */ } if ( hard == 0 ) { @@ -793,7 +796,7 @@ limits_parse_one( } else if ( arg[0] == '=' ) { arg++; - if ( strcasecmp( arg, "none" ) == 0 ) { + if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { limit->lms_t_soft = -1; } else { @@ -817,7 +820,7 @@ limits_parse_one( arg++; if ( strncasecmp( arg, "soft=", STRLENOF( "soft=" ) ) == 0 ) { arg += STRLENOF( "soft=" ); - if ( strcasecmp( arg, "none" ) == 0 ) { + if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { limit->lms_s_soft = -1; } else { @@ -833,7 +836,7 @@ limits_parse_one( } if ( soft == -1 ) { - /* FIXME: use "none" instead */ + /* FIXME: use "unlimited" instead */ } limit->lms_s_soft = soft; @@ -844,7 +847,7 @@ limits_parse_one( if ( strcasecmp( arg, "soft" ) == 0 ) { limit->lms_s_hard = 0; - } else if ( strcasecmp( arg, "none" ) == 0 ) { + } else if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { limit->lms_s_hard = -1; } else { @@ -860,7 +863,7 @@ limits_parse_one( } if ( hard == -1 ) { - /* FIXME: use "none" instead */ + /* FIXME: use "unlimited" instead */ } if ( hard == 0 ) { @@ -872,7 +875,7 @@ limits_parse_one( } else if ( strncasecmp( arg, "unchecked=", STRLENOF( "unchecked=" ) ) == 0 ) { arg += STRLENOF( "unchecked=" ); - if ( strcasecmp( arg, "none" ) == 0 ) { + if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { limit->lms_s_unchecked = -1; } else if ( strcasecmp( arg, "disabled" ) == 0 ) { @@ -891,7 +894,7 @@ limits_parse_one( } if ( unchecked == -1 ) { - /* FIXME: use "none" instead */ + /* FIXME: use "unlimited" instead */ } limit->lms_s_unchecked = unchecked; @@ -902,7 +905,7 @@ limits_parse_one( if ( strcasecmp( arg, "noEstimate" ) == 0 ) { limit->lms_s_pr_hide = 1; - } else if ( strcasecmp( arg, "none" ) == 0 ) { + } else if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { limit->lms_s_pr = -1; } else { @@ -918,7 +921,7 @@ limits_parse_one( } if ( pr == -1 ) { - /* FIXME: use "none" instead */ + /* FIXME: use "unlimited" instead */ } limit->lms_s_pr = pr; @@ -927,7 +930,7 @@ limits_parse_one( } else if ( strncasecmp( arg, "prtotal=", STRLENOF( "prtotal=" ) ) == 0 ) { arg += STRLENOF( "prtotal=" ); - if ( strcasecmp( arg, "none" ) == 0 ) { + if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { limit->lms_s_pr_total = -1; } else if ( strcasecmp( arg, "disabled" ) == 0 ) { @@ -950,7 +953,7 @@ limits_parse_one( } if ( total == -1 ) { - /* FIXME: use "none" instead */ + /* FIXME: use "unlimited" instead */ } if ( total == 0 ) { @@ -966,7 +969,7 @@ limits_parse_one( } else if ( arg[0] == '=' ) { arg++; - if ( strcasecmp( arg, "none" ) == 0 ) { + if ( strcasecmp( arg, "unlimited" ) == 0 || strcasecmp( arg, "none" ) == 0 ) { limit->lms_s_soft = -1; } else { @@ -1040,6 +1043,7 @@ limits_check( Operation *op, SlapReply *rs ) } } else if ( op->ors_limit->lms_t_hard > 0 ) { +#ifdef ABOVE_HARD_LIMIT_IS_ERROR if ( op->ors_tlimit == SLAP_MAX_LIMIT ) { op->ors_tlimit = op->ors_limit->lms_t_hard; @@ -1050,6 +1054,11 @@ limits_check( Operation *op, SlapReply *rs ) rs->sr_err = LDAP_SUCCESS; return -1; } +#else /* ! ABOVE_HARD_LIMIT_IS_ERROR */ + if ( op->ors_tlimit > op->ors_limit->lms_t_hard ) { + op->ors_tlimit = op->ors_limit->lms_t_hard; + } +#endif /* ! ABOVE_HARD_LIMIT_IS_ERROR */ } } @@ -1105,6 +1114,7 @@ limits_check( Operation *op, SlapReply *rs ) slimit = op->ors_slimit - op->o_pagedresults_state.ps_count; } +#ifdef ABOVE_HARD_LIMIT_IS_ERROR } else if ( pr_total > 0 && op->ors_slimit != SLAP_MAX_LIMIT && ( op->ors_slimit == SLAP_NO_LIMIT || op->ors_slimit > pr_total ) ) { @@ -1112,6 +1122,7 @@ limits_check( Operation *op, SlapReply *rs ) send_ldap_result( op, rs ); rs->sr_err = LDAP_SUCCESS; return -1; +#endif /* ! ABOVE_HARD_LIMIT_IS_ERROR */ } else { /* if no limit is required, use soft limit */ @@ -1121,8 +1132,13 @@ limits_check( Operation *op, SlapReply *rs ) /* first round of pagedResults: set count to any appropriate limit */ /* if the limit is set, check that it does not violate any server-side limit */ +#ifdef ABOVE_HARD_LIMIT_IS_ERROR if ( op->ors_slimit == SLAP_MAX_LIMIT ) { slimit2 = op->ors_slimit = pr_total; +#else /* ! ABOVE_HARD_LIMIT_IS_ERROR */ + if ( op->ors_slimit == SLAP_MAX_LIMIT || op->ors_slimit > pr_total ) { + slimit2 = op->ors_slimit = pr_total; +#endif /* ! ABOVE_HARD_LIMIT_IS_ERROR */ } else if ( op->ors_slimit == 0 ) { slimit2 = pr_total; @@ -1196,6 +1212,7 @@ limits_check( Operation *op, SlapReply *rs ) /* explicit hard limit: error if violated */ } else if ( op->ors_limit->lms_s_hard > 0 ) { +#ifdef ABOVE_HARD_LIMIT_IS_ERROR if ( op->ors_slimit == SLAP_MAX_LIMIT ) { op->ors_slimit = op->ors_limit->lms_s_hard; @@ -1206,6 +1223,11 @@ limits_check( Operation *op, SlapReply *rs ) rs->sr_err = LDAP_SUCCESS; return -1; } +#else /* ! ABOVE_HARD_LIMIT_IS_ERROR */ + if ( op->ors_slimit > op->ors_limit->lms_s_hard ) { + op->ors_slimit = op->ors_limit->lms_s_hard; + } +#endif /* ! ABOVE_HARD_LIMIT_IS_ERROR */ } } diff --git a/tests/data/slapd-limits.conf b/tests/data/slapd-limits.conf index cf5894aabf..e284f54942 100644 --- a/tests/data/slapd-limits.conf +++ b/tests/data/slapd-limits.conf @@ -43,18 +43,18 @@ rootpw secret #hdb#index uid eq # Need extra limits for pagedResults on backends that support it... -#bdb#limits dn.exact="cn=Unlimited User,ou=Paged Results Users,dc=example,dc=com" size=4 size.pr=none +#bdb#limits dn.exact="cn=Unlimited User,ou=Paged Results Users,dc=example,dc=com" size=4 size.pr=unlimited #bdb#limits dn.exact="cn=Page Size Limited User,ou=Paged Results Users,dc=example,dc=com" size=4 size.pr=4 #bdb#limits dn.exact="cn=Paged Results Disabled User,ou=Paged Results Users,dc=example,dc=com" size=4 size.prtotal=disabled #bdb#limits dn.exact="cn=Paged Results Limited User,ou=Paged Results Users,dc=example,dc=com" size=4 size.prtotal=10 -#hdb#limits dn.exact="cn=Unlimited User,ou=Paged Results Users,dc=example,dc=com" size=4 size.pr=none +#hdb#limits dn.exact="cn=Unlimited User,ou=Paged Results Users,dc=example,dc=com" size=4 size.pr=unlimited #hdb#limits dn.exact="cn=Page Size Limited User,ou=Paged Results Users,dc=example,dc=com" size=4 size.pr=4 #hdb#limits dn.exact="cn=Paged Results Disabled User,ou=Paged Results Users,dc=example,dc=com" size=4 size.prtotal=disabled #hdb#limits dn.exact="cn=Paged Results Limited User,ou=Paged Results Users,dc=example,dc=com" size=4 size.prtotal=10 -limits dn.exact="cn=Unlimited User,ou=People,dc=example,dc=com" size=none time=none -limits dn.exact="cn=Soft Limited User,ou=People,dc=example,dc=com" size.soft=4 size.hard=none +limits dn.exact="cn=Unlimited User,ou=People,dc=example,dc=com" size=unlimited time=unlimited +limits dn.exact="cn=Soft Limited User,ou=People,dc=example,dc=com" size.soft=4 size.hard=unlimited limits dn.exact="cn=Hard Limited User,ou=People,dc=example,dc=com" size.soft=4 size.hard=8 limits dn.exact="cn=Unchecked Limited User,ou=People,dc=example,dc=com" size.unchecked=4 limits group="cn=Unchecked Limited Users,ou=Groups,dc=example,dc=com" size.unchecked=4 diff --git a/tests/scripts/test025-limits b/tests/scripts/test025-limits index 7bcc4fcda3..812419d663 100755 --- a/tests/scripts/test025-limits +++ b/tests/scripts/test025-limits @@ -406,13 +406,23 @@ case $RC in fi ;; 4) - echo "...error: bumped into server-side size limit instead of hard size administrative limit" - test $KILLSERVERS != no && kill -HUP $KILLPIDS - exit $RC - ;; - 11) - echo "...bumped into server-side hard size administrative limit" + if test x"$COUNT" != x ; then + if test "$COUNT" = "$SIZELIMIT" ; then + echo "...error: bumped into requested ($SIZELIMIT) size limit" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + else + echo "...got size limit $COUNT instead of requested $SIZELIMIT entries" + fi + else + echo "...error: bumped into server-side size limit, but got no entries!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + fi ;; +# 11) +# echo "...bumped into server-side hard size administrative limit" +# ;; *) echo "ldapsearch failed ($RC)!" test $KILLSERVERS != no && kill -HUP $KILLPIDS @@ -446,9 +456,9 @@ case $RC in exit $RC fi ;; - 11) - echo "...bumped into server-side hard size administrative limit" - ;; +# 11) +# echo "...bumped into server-side hard size administrative limit" +# ;; *) echo "ldapsearch failed ($RC)!" test $KILLSERVERS != no && kill -HUP $KILLPIDS @@ -1037,18 +1047,20 @@ case $RC in if test x"$COUNT" != x ; then if test "$COUNT" = "$SIZELIMIT" ; then echo "...error: bumped into requested ($SIZELIMIT) size limit" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC else - echo "...error: got size limit $SIZELIMIT but $COUNT entries" + echo "...got size limit $COUNT instead of requested $SIZELIMIT entries" fi else echo "...error: bumped into server-side size limit, but got no entries!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC fi - test $KILLSERVERS != no && kill -HUP $KILLPIDS - exit $RC - ;; - 11) - echo "...bumped into hard size administrative limit" ;; +# 11) +# echo "...bumped into hard size administrative limit" +# ;; *) echo "ldapsearch failed ($RC)!" test $KILLSERVERS != no && kill -HUP $KILLPIDS @@ -1074,11 +1086,17 @@ case $RC in fi ;; 4) - echo "...bumped into requested ($SIZELIMIT=$COUNT) size limit" - ;; - 11) - echo "...bumped into hard size administrative limit" + if test x"$COUNT" != x ; then + echo "...bumped into requested ($SIZELIMIT=$COUNT) size limit" + else + echo "...error: bumped into size limit but got no entries!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + fi ;; +# 11) +# echo "...bumped into hard size administrative limit" +# ;; *) echo "ldapsearch failed ($RC)!" test $KILLSERVERS != no && kill -HUP $KILLPIDS @@ -1102,9 +1120,9 @@ case $RC in exit $RC fi ;; - 11) - echo "...bumped into unchecked administrative limit" - ;; +# 11) +# echo "...bumped into unchecked administrative limit" +# ;; *) echo "ldapsearch failed ($RC)!" test $KILLSERVERS != no && kill -HUP $KILLPIDS -- 2.39.5