From 48e99c1d2ffba4b83df4a499d37bb444ea9b5673 Mon Sep 17 00:00:00 2001 From: Noriko Hosoi Date: Jan 18 2012 18:09:34 +0000 Subject: Trac Ticket 168 - minssf should not apply to rootdse https://fedorahosted.org/389/ticket/168 Fix description: This patch is for supporting a request to allow accessing rootdse with lower ssf than minssf configuration setting. . introduced a on/off type config parameter: nsslapd-minssf-exclude-rootdse. . by default, the value is off. . when it is off, the server's behavior remains intact. . when it is on, the server allows to access rootdse even if the ssf value is less than nsslapd-minssf value. --- diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c index 12d6650..1d860b6 100644 --- a/ldap/servers/slapd/bind.c +++ b/ldap/servers/slapd/bind.c @@ -138,6 +138,7 @@ do_bind( Slapi_PBlock *pb ) Slapi_Entry *bind_target_entry = NULL; int auto_bind = 0; int minssf = 0; + int minssf_exclude_rootdse = 0; LDAPDebug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 ); @@ -493,7 +494,15 @@ do_bind( Slapi_PBlock *pb ) /* Check if the minimum SSF requirement has been met. */ minssf = config_get_minssf(); - if ((pb->pb_conn->c_sasl_ssf < minssf) && (pb->pb_conn->c_ssl_ssf < minssf) && + /* + * If nsslapd-minssf-exclude-rootdse is on, we have to go to the + * next step and check if the operation is against rootdse or not. + * Once found it's not on rootdse, return LDAP_UNWILLING_TO_PERFORM + * there. + */ + minssf_exclude_rootdse = config_get_minssf_exclude_rootdse(); + if (!minssf_exclude_rootdse && (pb->pb_conn->c_sasl_ssf < minssf) && + (pb->pb_conn->c_ssl_ssf < minssf) && (pb->pb_conn->c_local_ssf < minssf)) { send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Minimum SSF not met.", 0, NULL); @@ -560,7 +569,7 @@ do_bind( Slapi_PBlock *pb ) goto free_and_return; } /* Check if simple binds are allowed over an insecure channel. We only check - * this for authenticated binds. */ + * this for authenticated binds. */ } else if (config_get_require_secure_binds() == 1) { Connection *conn = NULL; int sasl_ssf = 0; diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c index 27e4fe1..cabfe71 100644 --- a/ldap/servers/slapd/connection.c +++ b/ldap/servers/slapd/connection.c @@ -496,6 +496,7 @@ static void connection_dispatch_operation(Connection *conn, Operation *op, Slapi_PBlock *pb) { int minssf = config_get_minssf(); + int minssf_exclude_rootdse = 0; /* Get the effective key length now since the first SSL handshake should be complete */ connection_set_ssl_ssf( conn ); @@ -508,7 +509,14 @@ connection_dispatch_operation(Connection *conn, Operation *op, Slapi_PBlock *pb) * code will ensure that only SASL binds and startTLS are * allowed, which gives the connection a chance to meet the * SSF requirements. We also allow UNBIND and ABANDON.*/ - if ((conn->c_sasl_ssf < minssf) && (conn->c_ssl_ssf < minssf) && + /* + * If nsslapd-minssf-exclude-rootdse is on, we have to go to the + * next step and check if the operation is against rootdse or not. + * Once found it's not on rootdse, return LDAP_UNWILLING_TO_PERFORM there. + */ + minssf_exclude_rootdse = config_get_minssf_exclude_rootdse(); + if (!minssf_exclude_rootdse && + (conn->c_sasl_ssf < minssf) && (conn->c_ssl_ssf < minssf) && (conn->c_local_ssf < minssf) &&(op->o_tag != LDAP_REQ_BIND) && (op->o_tag != LDAP_REQ_EXTENDED) && (op->o_tag != LDAP_REQ_UNBIND) && (op->o_tag != LDAP_REQ_ABANDON)) { diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c index 2177934..4c4c31f 100644 --- a/ldap/servers/slapd/libglobs.c +++ b/ldap/servers/slapd/libglobs.c @@ -626,6 +626,11 @@ static struct config_get_and_set { {CONFIG_MINSSF_ATTRIBUTE, config_set_minssf, NULL, 0, (void**)&global_slapdFrontendConfig.minssf, CONFIG_INT, NULL}, + {CONFIG_MINSSF_EXCLUDE_ROOTDSE, config_set_minssf_exclude_rootdse, + NULL, 0, + (void**)&global_slapdFrontendConfig.minssf_exclude_rootdse, + CONFIG_ON_OFF, + (ConfigGetFunc)config_get_minssf_exclude_rootdse}, {CONFIG_FORCE_SASL_EXTERNAL_ATTRIBUTE, config_set_force_sasl_external, NULL, 0, (void**)&global_slapdFrontendConfig.force_sasl_external, CONFIG_ON_OFF, @@ -918,6 +923,8 @@ FrontendConfig_init () { cfg->maxsasliosize = SLAPD_DEFAULT_MAX_SASLIO_SIZE; cfg->localssf = SLAPD_DEFAULT_LOCAL_SSF; cfg->minssf = SLAPD_DEFAULT_MIN_SSF; + cfg->minssf_exclude_rootdse = LDAP_OFF; /* minssf is applied to rootdse, + by default */ cfg->validate_cert = SLAPD_VALIDATE_CERT_WARN; #ifdef _WIN32 @@ -4881,6 +4888,22 @@ config_set_minssf( const char *attrname, char *value, char *errorbuf, int apply } int +config_set_minssf_exclude_rootdse( const char *attrname, char *value, + char *errorbuf, int apply ) +{ + int retVal = LDAP_SUCCESS; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + + retVal = config_set_onoff ( attrname, + value, + &(slapdFrontendConfig->minssf_exclude_rootdse), + errorbuf, + apply ); + + return retVal; +} + +int config_get_localssf() { int localssf; @@ -4903,6 +4926,18 @@ config_get_minssf() } int +config_get_minssf_exclude_rootdse() +{ + int retVal; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + CFG_LOCK_READ(slapdFrontendConfig); + retVal = slapdFrontendConfig->minssf_exclude_rootdse; + CFG_UNLOCK_READ(slapdFrontendConfig); + + return retVal; +} + +int config_set_max_filter_nest_level( const char *attrname, char *value, char *errorbuf, int apply ) { diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c index e872f35..563512d 100644 --- a/ldap/servers/slapd/modify.c +++ b/ldap/servers/slapd/modify.c @@ -141,6 +141,7 @@ do_modify( Slapi_PBlock *pb ) int has_password_mod = 0; /* number of password mods */ char *old_pw = NULL; /* remember the old password */ char *rawdn = NULL; + int minssf_exclude_rootdse = 0; LDAPDebug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 ); @@ -197,6 +198,27 @@ do_modify( Slapi_PBlock *pb ) LDAPDebug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", rawdn, 0, 0 ); + /* + * If nsslapd-minssf-exclude-rootdse is on, the minssf check has been + * postponed until here. We should do it now. + */ + minssf_exclude_rootdse = config_get_minssf_exclude_rootdse(); + if (minssf_exclude_rootdse) { + int minssf = 0; + /* Check if the minimum SSF requirement has been met. */ + minssf = config_get_minssf(); + if ((pb->pb_conn->c_sasl_ssf < minssf) && + (pb->pb_conn->c_ssl_ssf < minssf) && + (pb->pb_conn->c_local_ssf < minssf)) { + op_shared_log_error_access(pb, "MOD", rawdn?rawdn:"", + "Minimum SSF not met"); + send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, + "Minimum SSF not met.", 0, NULL); + slapi_ch_free((void **) &rawdn); + return; + } + } + slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &pb->pb_op->o_isroot); slapi_pblock_set( pb, SLAPI_ORIGINAL_TARGET, rawdn ); diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h index a3fcc5f..f3e85c9 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -370,6 +370,7 @@ int config_set_require_secure_binds(const char *attrname, char *value, char *err int config_set_anon_access_switch(const char *attrname, char *value, char *errorbuf, int apply ); int config_set_localssf(const char *attrname, char *value, char *errorbuf, int apply ); int config_set_minssf(const char *attrname, char *value, char *errorbuf, int apply ); +int config_set_minssf_exclude_rootdse( const char *attrname, char *value, char *errorbuf, int apply ); int config_set_validate_cert_switch(const char *attrname, char *value, char *errorbuf, int apply ); int config_set_accesslogbuffering(const char *attrname, char *value, char *errorbuf, int apply); int config_set_csnlogging(const char *attrname, char *value, char *errorbuf, int apply); @@ -510,6 +511,7 @@ int config_get_require_secure_binds(void); int config_get_anon_access_switch(void); int config_get_localssf(void); int config_get_minssf(void); +int config_get_minssf_exclude_rootdse(void); int config_get_validate_cert_switch(void); int config_get_csnlogging(); #ifdef MEMPOOL_EXPERIMENTAL diff --git a/ldap/servers/slapd/search.c b/ldap/servers/slapd/search.c index 6da7aa0..5beb8ce 100644 --- a/ldap/servers/slapd/search.c +++ b/ldap/servers/slapd/search.c @@ -80,6 +80,7 @@ do_search( Slapi_PBlock *pb ) int changesonly = 0; int rc = -1; int strict = 0; + int minssf_exclude_rootdse = 0; LDAPDebug( LDAP_DEBUG_TRACE, "do_search\n", 0, 0, 0 ); @@ -141,7 +142,8 @@ do_search( Slapi_PBlock *pb ) if ((slapi_sdn_get_dn(&(operation->o_sdn)) == NULL) && (scope != LDAP_SCOPE_BASE) && (config_get_anon_access_switch() == SLAPD_ANON_ACCESS_ROOTDSE)) { - op_shared_log_error_access(pb, "SRCH", base?base:"", "anonymous search not allowed"); + op_shared_log_error_access(pb, "SRCH", rawbase?rawbase:"", + "anonymous search not allowed"); send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL, "Anonymous access is not allowed.", 0, NULL ); @@ -149,6 +151,31 @@ do_search( Slapi_PBlock *pb ) goto free_and_return; } + /* + * If nsslapd-minssf-exclude-rootdse is on, the minssf check has been + * postponed till this moment since we need to know whether the basedn + * is rootdse or not. + * + * If (minssf_exclude_rootdse && (basedn is rootdse), + * then we allow accessing rootdse. + * Otherwise, return Minimum SSF not met. + */ + minssf_exclude_rootdse = config_get_minssf_exclude_rootdse(); + if (!minssf_exclude_rootdse || (rawbase && strlen(rawbase) > 0)) { + int minssf = 0; + /* Check if the minimum SSF requirement has been met. */ + minssf = config_get_minssf(); + if ((pb->pb_conn->c_sasl_ssf < minssf) && + (pb->pb_conn->c_ssl_ssf < minssf) && + (pb->pb_conn->c_local_ssf < minssf)) { + op_shared_log_error_access(pb, "SRCH", rawbase?rawbase:"", + "Minimum SSF not met"); + send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, + "Minimum SSF not met.", 0, NULL); + goto free_and_return; + } + } + /* * ignore negative time and size limits since they make no sense */ diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h index b59299c..d0ae067 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -1869,6 +1869,7 @@ typedef struct _slapdEntryPoints { #define CONFIG_ANON_ACCESS_ATTRIBUTE "nsslapd-allow-anonymous-access" #define CONFIG_LOCALSSF_ATTRIBUTE "nsslapd-localssf" #define CONFIG_MINSSF_ATTRIBUTE "nsslapd-minssf" +#define CONFIG_MINSSF_EXCLUDE_ROOTDSE "nsslapd-minssf-exclude-rootdse" #define CONFIG_VALIDATE_CERT_ATTRIBUTE "nsslapd-validate-cert" #ifndef _WIN32 #define CONFIG_LOCALUSER_ATTRIBUTE "nsslapd-localuser" @@ -2176,6 +2177,7 @@ typedef struct _slapdFrontendConfig { int allow_anon_access; /* switch to enable/disable anonymous access */ int localssf; /* the security strength factor to assign to local conns (ldapi) */ int minssf; /* minimum security strength factor (for SASL and SSL/TLS) */ + int minssf_exclude_rootdse; /* ON: minssf is ignored when searching rootdse */ size_t maxsasliosize; /* limit incoming SASL IO packet size */ char *anon_limits_dn; /* template entry for anonymous resource limits */ #ifndef _WIN32