From 5fd0cdfcc1e409c43ab700e35079ada7701c63a4 Mon Sep 17 00:00:00 2001 From: Noriko Hosoi Date: Jun 09 2015 22:43:35 +0000 Subject: Ticket #48191 - RFE: Adding nsslapd-maxsimplepaged-per-conn Description: Asynchronous simple paged results requests could add too much load the server can handle. Adding a config parameter to restrict the requests. cn=config nsslapd-maxsimplepaged-per-conn: INT If nsslapd-maxsimplepaged-per-conn is configured with a positive integer, Asynchronous simple paged results requests per connection is limitted by the value. If the requests exceed the value, it returns LDAP_UNWILLING_TO_PERFORM. If the value is negative, there is no limit (default behaviour). If the value is 0, a simple paged results is disabled. https://fedorahosted.org/389/ticket/48191 Reviewed by rmeggins@redhat.com (Thank you, Rich!) --- diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c index 5aee1c4..3b53f32 100644 --- a/ldap/servers/slapd/libglobs.c +++ b/ldap/servers/slapd/libglobs.c @@ -186,6 +186,8 @@ static int invalid_sasl_mech(char *str); #define DEFAULT_MAXBERSIZE 2097152 #define DEFAULT_SASL_MAXBUFSIZE "2097152" #define SLAPD_DEFAULT_SASL_MAXBUFSIZE 2097152 +#define DEFAULT_MAXSIMPLEPAGED_PER_CONN (-1) +#define DEFAULT_MAXSIMPLEPAGED_PER_CONN_STR "-1" #ifdef MEMPOOL_EXPERIMENTAL #define DEFAULT_MEMPOOL_MAXFREELIST "1024" #endif @@ -1130,7 +1132,11 @@ static struct config_get_and_set { {CONFIG_GLOBAL_BACKEND_LOCK, config_set_global_backend_lock, NULL, 0, (void**)&global_slapdFrontendConfig.global_backend_lock, - CONFIG_ON_OFF, (ConfigGetFunc)config_get_global_backend_lock, &init_global_backend_local} + CONFIG_ON_OFF, (ConfigGetFunc)config_get_global_backend_lock, &init_global_backend_local}, + {CONFIG_MAXSIMPLEPAGED_PER_CONN_ATTRIBUTE, config_set_maxsimplepaged_per_conn, + NULL, 0, + (void**)&global_slapdFrontendConfig.maxsimplepaged_per_conn, + CONFIG_INT, config_get_maxsimplepaged_per_conn, DEFAULT_MAXSIMPLEPAGED_PER_CONN_STR}, #ifdef ENABLE_NUNC_STANS ,{CONFIG_ENABLE_NUNC_STANS, config_set_enable_nunc_stans, NULL, 0, @@ -1585,6 +1591,7 @@ FrontendConfig_init () { init_dynamic_plugins = cfg->dynamic_plugins = LDAP_OFF; init_cn_uses_dn_syntax_in_dns = cfg->cn_uses_dn_syntax_in_dns = LDAP_OFF; init_global_backend_local = LDAP_OFF; + cfg->maxsimplepaged_per_conn = DEFAULT_MAXSIMPLEPAGED_PER_CONN; #ifdef ENABLE_NUNC_STANS init_enable_nunc_stans = cfg->enable_nunc_stans = LDAP_OFF; #endif @@ -7864,6 +7871,49 @@ config_set_auditlog_enabled(int value){ CFG_ONOFF_UNLOCK_WRITE(slapdFrontendConfig); } +int +config_set_maxsimplepaged_per_conn( const char *attrname, char *value, char *errorbuf, int apply ) +{ + int retVal = LDAP_SUCCESS; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + long size; + char *endp; + + if ( config_value_is_null( attrname, value, errorbuf, 0 )) { + return LDAP_OPERATIONS_ERROR; + } + + errno = 0; + size = strtol(value, &endp, 10); + if ( *endp != '\0' || errno == ERANGE){ + retVal = LDAP_OPERATIONS_ERROR; + PR_snprintf(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "(%s) value (%s) is invalid\n", + attrname, value); + return retVal; + } + + if ( !apply ) { + return retVal; + } + + CFG_LOCK_WRITE(slapdFrontendConfig); + + slapdFrontendConfig->maxsimplepaged_per_conn = size; + + CFG_UNLOCK_WRITE(slapdFrontendConfig); + return retVal; +} + +int +config_get_maxsimplepaged_per_conn() +{ + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + int retVal; + + retVal = slapdFrontendConfig->maxsimplepaged_per_conn; + return retVal; +} + #if defined(LINUX) int config_set_malloc_mxfast(const char *attrname, char *value, char *errorbuf, int apply) diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c index 9a5a141..cab911a 100644 --- a/ldap/servers/slapd/opshared.c +++ b/ldap/servers/slapd/opshared.c @@ -552,6 +552,11 @@ op_shared_search (Slapi_PBlock *pb, int send_result) rc = LDAP_SUCCESS; goto free_and_return; } + } else if (LDAP_UNWILLING_TO_PERFORM == rc) { + send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, + "Simple Paged Results Search exceeded administration limit", + 0, NULL); + goto free_and_return; } else { /* parse paged-results-control failed */ if (iscritical) { /* return an error since it's critical */ diff --git a/ldap/servers/slapd/pagedresults.c b/ldap/servers/slapd/pagedresults.c index a7fe2cd..9a78540 100644 --- a/ldap/servers/slapd/pagedresults.c +++ b/ldap/servers/slapd/pagedresults.c @@ -89,6 +89,7 @@ pagedresults_parse_control_value( Slapi_PBlock *pb, PagedResults *prp = NULL; time_t ctime = current_time(); int i; + int maxreqs = config_get_maxsimplepaged_per_conn(); LDAPDebug0Args(LDAP_DEBUG_TRACE, "--> pagedresults_parse_control_value\n"); if ( NULL == conn || NULL == op || NULL == pagesize || NULL == index ) { @@ -118,6 +119,13 @@ pagedresults_parse_control_value( Slapi_PBlock *pb, "<-- pagedresults_parse_control_value: corrupted control value\n"); return LDAP_PROTOCOL_ERROR; } + if (!maxreqs) + { + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "pagedresults_parse_control_value: simple paged results requests per conn exeeded the limit: %d\n", + maxreqs); + return LDAP_UNWILLING_TO_PERFORM; + } PR_Lock(conn->c_mutex); /* the ber encoding is no longer needed */ @@ -158,6 +166,14 @@ pagedresults_parse_control_value( Slapi_PBlock *pb, } } } + if ((maxreqs > 0) && (*index >= maxreqs)) { + rc = LDAP_UNWILLING_TO_PERFORM; + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "pagedresults_parse_control_value: simple paged results requests per conn exeeded the limit: %d\n", + maxreqs); + goto bail; + } + if ((*index > -1) && (*index < conn->c_pagedresults.prl_maxlen) && !conn->c_pagedresults.prl_list[*index].pr_mutex) { conn->c_pagedresults.prl_list[*index].pr_mutex = PR_NewLock(); diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h index 8410e66..ea5ff53 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -428,6 +428,8 @@ int config_set_mempool_switch( const char *attrname, char *value, char *errorbuf int config_set_mempool_maxfreelist( const char *attrname, char *value, char *errorbuf, int apply ); #endif /* MEMPOOL_EXPERIMENTAL */ +int config_set_maxsimplepaged_per_conn( const char *attrname, char *value, char *errorbuf, int apply ); + int config_get_SSLclientAuth(); int config_get_ssl_check_hostname(); char *config_get_SSL3ciphers(); @@ -613,6 +615,8 @@ int config_get_malloc_trim_threshold(); int config_get_malloc_mmap_threshold(); #endif +int config_get_maxsimplepaged_per_conn(); + int is_abspath(const char *); char* rel2abspath( char * ); char* rel2abspath_ext( char *, char * ); diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h index b7c6e80..dd4fc68 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -2169,6 +2169,8 @@ typedef struct _slapdEntryPoints { #define CONFIG_CN_USES_DN_SYNTAX_IN_DNS "nsslapd-cn-uses-dn-syntax-in-dns" +#define CONFIG_MAXSIMPLEPAGED_PER_CONN_ATTRIBUTE "nsslapd-maxsimplepaged-per-conn" + /* getenv alternative */ #define CONFIG_MALLOC_MXFAST "nsslapd-malloc-mxfast" #define CONFIG_MALLOC_TRIM_THRESHOLD "nsslapd-malloc-trim-threshold" @@ -2435,6 +2437,7 @@ typedef struct _slapdFrontendConfig { slapi_onoff_t dynamic_plugins; /* allow plugins to be dynamically enabled/disabled */ slapi_onoff_t cn_uses_dn_syntax_in_dns; /* indicates the cn value in dns has dn syntax */ slapi_onoff_t global_backend_lock; + slapi_int_t maxsimplepaged_per_conn;/* max simple paged results reqs handled per connection */ #ifdef ENABLE_NUNC_STANS slapi_onoff_t enable_nunc_stans; #endif