Browse Source

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 [email protected] (Thank you, Rich!)
Noriko Hosoi 10 years ago
parent
commit
5fd0cdfcc1

+ 51 - 1
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)

+ 5 - 0
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 */

+ 16 - 0
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();

+ 4 - 0
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 * );

+ 3 - 0
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