Browse Source

Bug 588791 - Allow anonymous rootDSE access only

This patch changes the nsslapd-allow-anonymous-access config
setting to allow a third value that gives anonymous access to
search the rootDSE.  If you set this attribute to "rootdse", an
anonymous bind identity is only allowed to do a rootDSE search
or prove that it is someone other than anonymous.  This also
required allowing explicit anonymous BIND operations through since
ldapsearch performs an explicit bind before searching.  The old
behavior with the "on" and "off" settings remains unchanged.
Nathan Kinder 15 years ago
parent
commit
b3b0217acd

+ 4 - 3
ldap/servers/slapd/bind.c

@@ -514,8 +514,9 @@ do_bind( Slapi_PBlock *pb )
                that counter */
                that counter */
             slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds);
             slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds);
 
 
-            /* Refuse the operation if anonymous access is disabled. */
-            if (!config_get_anon_access_switch()) {
+            /* Refuse the operation if anonymous access is disabled.  We need to allow
+             * an anonymous bind through if only root DSE anonymous access is set too. */
+            if (config_get_anon_access_switch() == SLAPD_ANON_ACCESS_OFF) {
                 send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL,
                 send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL,
                                  "Anonymous access is not allowed", 0, NULL);
                                  "Anonymous access is not allowed", 0, NULL);
                 /* increment BindSecurityErrorcount */
                 /* increment BindSecurityErrorcount */
@@ -544,7 +545,7 @@ do_bind( Slapi_PBlock *pb )
             slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds);
             slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds);
 
 
             /* Refuse the operation if anonymous access is disabled. */
             /* Refuse the operation if anonymous access is disabled. */
-            if (!config_get_anon_access_switch()) {
+            if (config_get_anon_access_switch() != SLAPD_ANON_ACCESS_ON) {
                 send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL,
                 send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL,
                                  "Anonymous access is not allowed", 0, NULL);
                                  "Anonymous access is not allowed", 0, NULL);
                 /* increment BindSecurityErrorcount */
                 /* increment BindSecurityErrorcount */

+ 14 - 4
ldap/servers/slapd/connection.c

@@ -522,10 +522,20 @@ connection_dispatch_operation(Connection *conn, Operation *op, Slapi_PBlock *pb)
 	 * not authenticated, only allow bind and extended operations.
 	 * not authenticated, only allow bind and extended operations.
 	 * We allow extended operations so one can do a startTLS prior
 	 * We allow extended operations so one can do a startTLS prior
 	 * to binding to protect their credentials in transit. 
 	 * to binding to protect their credentials in transit. 
-	 * We also allow UNBIND and ABANDON. */
-	if (!config_get_anon_access_switch() && (op->o_tag != LDAP_REQ_BIND) &&
-	    (op->o_tag != LDAP_REQ_EXTENDED) && (op->o_tag != LDAP_REQ_UNBIND) &&
-	    (op->o_tag != LDAP_REQ_ABANDON) && (slapi_sdn_get_dn(&(op->o_sdn)) == NULL )) {
+	 * We also allow UNBIND and ABANDON.
+	 *
+	 * If anonymous access is only allowed for root DSE searches,
+	 * we let SEARCH operations through as well.  The search code
+	 * is responsible for checking if the operation is a root DSE
+	 * search. */
+        if ((slapi_sdn_get_dn(&(op->o_sdn)) == NULL ) &&
+            /* anon access off and something other than BIND, EXTOP, UNBIND or ABANDON */
+	    (((config_get_anon_access_switch() == SLAPD_ANON_ACCESS_OFF) && (op->o_tag != LDAP_REQ_BIND) &&
+             (op->o_tag != LDAP_REQ_EXTENDED) && (op->o_tag != LDAP_REQ_UNBIND) && (op->o_tag != LDAP_REQ_ABANDON)) ||
+            /* root DSE access only and something other than BIND, EXTOP, UNBIND, ABANDON, or SEARCH */
+	    ((config_get_anon_access_switch() == SLAPD_ANON_ACCESS_ROOTDSE) && (op->o_tag != LDAP_REQ_BIND) &&
+	     (op->o_tag != LDAP_REQ_EXTENDED) && (op->o_tag != LDAP_REQ_UNBIND) &&
+	     (op->o_tag != LDAP_REQ_ABANDON) && (op->o_tag != LDAP_REQ_SEARCH)))) {
 		slapi_log_access( LDAP_DEBUG_STATS,
 		slapi_log_access( LDAP_DEBUG_STATS,
 			"conn=%" NSPRIu64 " op=%d UNPROCESSED OPERATION"
 			"conn=%" NSPRIu64 " op=%d UNPROCESSED OPERATION"
 			" - Anonymous access not allowed\n",
 			" - Anonymous access not allowed\n",

+ 1 - 1
ldap/servers/slapd/extendop.c

@@ -327,7 +327,7 @@ do_extended( Slapi_PBlock *pb )
 
 
 		/* If anonymous access is disabled and we haven't
 		/* If anonymous access is disabled and we haven't
 		 * authenticated yet, only allow startTLS. */
 		 * authenticated yet, only allow startTLS. */
-		if (!config_get_anon_access_switch() && ((pb->pb_op->o_authtype == NULL) ||
+		if ((config_get_anon_access_switch() != SLAPD_ANON_ACCESS_ON) && ((pb->pb_op->o_authtype == NULL) ||
     		        (strcasecmp(pb->pb_op->o_authtype, SLAPD_AUTH_NONE) == 0))) {
     		        (strcasecmp(pb->pb_op->o_authtype, SLAPD_AUTH_NONE) == 0))) {
 			send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL,
 			send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL,
 				"Anonymous access is not allowed.", 0, NULL );
 				"Anonymous access is not allowed.", 0, NULL );

+ 49 - 11
ldap/servers/slapd/libglobs.c

@@ -115,7 +115,8 @@ typedef enum {
 	CONFIG_SPECIAL_REFERRALLIST, /* this is a berval list */
 	CONFIG_SPECIAL_REFERRALLIST, /* this is a berval list */
 	CONFIG_SPECIAL_SSLCLIENTAUTH, /* maps strings to an enumeration */
 	CONFIG_SPECIAL_SSLCLIENTAUTH, /* maps strings to an enumeration */
     CONFIG_SPECIAL_ERRORLOGLEVEL, /* requires & with LDAP_DEBUG_ANY */
     CONFIG_SPECIAL_ERRORLOGLEVEL, /* requires & with LDAP_DEBUG_ANY */
-	CONFIG_STRING_OR_EMPTY /* use an empty string */
+	CONFIG_STRING_OR_EMPTY, /* use an empty string */
+	CONFIG_SPECIAL_ANON_ACCESS_SWITCH /* maps strings to an enumeration */
 } ConfigVarType;
 } ConfigVarType;
 
 
 static int config_set_onoff( const char *attrname, char *value,
 static int config_set_onoff( const char *attrname, char *value,
@@ -616,7 +617,7 @@ static struct config_get_and_set {
 		(ConfigGetFunc)config_get_require_secure_binds},
 		(ConfigGetFunc)config_get_require_secure_binds},
 	{CONFIG_ANON_ACCESS_ATTRIBUTE, config_set_anon_access_switch,
 	{CONFIG_ANON_ACCESS_ATTRIBUTE, config_set_anon_access_switch,
 		NULL, 0,
 		NULL, 0,
-		(void**)&global_slapdFrontendConfig.allow_anon_access, CONFIG_ON_OFF,
+		(void**)&global_slapdFrontendConfig.allow_anon_access, CONFIG_SPECIAL_ANON_ACCESS_SWITCH,
 		(ConfigGetFunc)config_get_anon_access_switch},
 		(ConfigGetFunc)config_get_anon_access_switch},
 	{CONFIG_MINSSF_ATTRIBUTE, config_set_minssf,
 	{CONFIG_MINSSF_ATTRIBUTE, config_set_minssf,
 		NULL, 0,
 		NULL, 0,
@@ -885,7 +886,7 @@ FrontendConfig_init () {
 #endif
 #endif
   cfg->allow_unauth_binds = LDAP_OFF;
   cfg->allow_unauth_binds = LDAP_OFF;
   cfg->require_secure_binds = LDAP_OFF;
   cfg->require_secure_binds = LDAP_OFF;
-  cfg->allow_anon_access = LDAP_ON;
+  cfg->allow_anon_access = SLAPD_ANON_ACCESS_ON;
   cfg->slapi_counters = LDAP_ON;
   cfg->slapi_counters = LDAP_ON;
   cfg->threadnumber = SLAPD_DEFAULT_MAX_THREADS;
   cfg->threadnumber = SLAPD_DEFAULT_MAX_THREADS;
   cfg->maxthreadsperconn = SLAPD_DEFAULT_MAX_THREADS_PER_CONN;
   cfg->maxthreadsperconn = SLAPD_DEFAULT_MAX_THREADS_PER_CONN;
@@ -4628,12 +4629,11 @@ config_get_require_secure_binds(void)
 int
 int
 config_get_anon_access_switch(void)
 config_get_anon_access_switch(void)
 {
 {
-	int retVal;
+	char *retVal = NULL;
 	slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
 	slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
 	CFG_LOCK_READ(slapdFrontendConfig);
 	CFG_LOCK_READ(slapdFrontendConfig);
-	retVal = slapdFrontendConfig->allow_anon_access;
+        retVal = slapdFrontendConfig->allow_anon_access;
 	CFG_UNLOCK_READ(slapdFrontendConfig);
 	CFG_UNLOCK_READ(slapdFrontendConfig);
-
 	return retVal;
 	return retVal;
 }
 }
 
 
@@ -5503,12 +5503,34 @@ config_set_anon_access_switch( const char *attrname, char *value,
 	int retVal = LDAP_SUCCESS;
 	int retVal = LDAP_SUCCESS;
 	slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
 	slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
 
 
-	retVal = config_set_onoff(attrname,
-		value,
-		&(slapdFrontendConfig->allow_anon_access),
-		errorbuf,
-		apply);
+	if (config_value_is_null(attrname, value, errorbuf, 0)) {
+		return LDAP_OPERATIONS_ERROR;
+	}
+
+	if ((strcasecmp(value, "on") != 0) && (strcasecmp(value, "off") != 0) &&
+	    (strcasecmp(value, "rootdse") != 0)) {
+		PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+			"%s: invalid value \"%s\". Valid values are \"on\", "
+			"\"off\", or \"rootdse\".", attrname, value);
+		retVal = LDAP_OPERATIONS_ERROR;
+	}
+
+	if (!apply) {
+		/* we can return now if we aren't applying the changes */
+		return retVal;
+	}
 
 
+	CFG_LOCK_WRITE(slapdFrontendConfig);
+
+	if (strcasecmp(value, "on") == 0 ) {
+		slapdFrontendConfig->allow_anon_access = SLAPD_ANON_ACCESS_ON;
+	} else if (strcasecmp(value, "off") == 0 ) {
+		slapdFrontendConfig->allow_anon_access = SLAPD_ANON_ACCESS_OFF;
+	} else if (strcasecmp(value, "rootdse") == 0) {
+		slapdFrontendConfig->allow_anon_access = SLAPD_ANON_ACCESS_ROOTDSE;
+	}
+
+	CFG_UNLOCK_WRITE(slapdFrontendConfig);
 	return retVal;
 	return retVal;
 }
 }
 
 
@@ -5776,6 +5798,22 @@ config_set_value(
             slapi_entry_attr_set_charptr(e, cgas->attr_name, "");
             slapi_entry_attr_set_charptr(e, cgas->attr_name, "");
         break;
         break;
 
 
+    case CONFIG_SPECIAL_ANON_ACCESS_SWITCH:
+        if (!value) {
+            slapi_entry_attr_set_charptr(e, cgas->attr_name, "off");
+            break;
+        }
+
+        if (*((int *)value) == SLAPD_ANON_ACCESS_ON) {
+            sval = "on";
+        } else if (*((int *)value) == SLAPD_ANON_ACCESS_ROOTDSE) {
+            sval = "rootdse";
+        } else {
+            sval = "off";
+        }
+        slapi_entry_attr_set_charptr(e, cgas->attr_name, sval);
+        break;
+
     default:
     default:
         PR_ASSERT(0); /* something went horribly wrong . . . */
         PR_ASSERT(0); /* something went horribly wrong . . . */
         break;
         break;

+ 1 - 1
ldap/servers/slapd/saslbind.c

@@ -663,7 +663,7 @@ void ids_sasl_server_new(Connection *conn)
     secprops.max_ssf = 0xffffffff;
     secprops.max_ssf = 0xffffffff;
     secprops.min_ssf = config_get_minssf();
     secprops.min_ssf = config_get_minssf();
     /* If anonymous access is disabled, set the appropriate flag */
     /* If anonymous access is disabled, set the appropriate flag */
-    if (!config_get_anon_access_switch()) {
+    if (config_get_anon_access_switch() != SLAPD_ANON_ACCESS_ON) {
         secprops.security_flags = SASL_SEC_NOANONYMOUS;
         secprops.security_flags = SASL_SEC_NOANONYMOUS;
     }
     }
 
 

+ 12 - 0
ldap/servers/slapd/search.c

@@ -152,6 +152,18 @@ do_search( Slapi_PBlock *pb )
 		*(base + baselen) = '\0';
 		*(base + baselen) = '\0';
 	}
 	}
 
 
+	/* If anonymous access is only allowed for searching the root DSE,
+	 * we need to reject any other anonymous search attempts. */
+	if ((slapi_sdn_get_dn(&(operation->o_sdn)) == NULL) && ((baselen != 0) || (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");
+
+		send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL,
+			"Anonymous access is not allowed.", 0, NULL );
+
+		goto free_and_return;
+	}
+
 	/*
 	/*
 	 * ignore negative time and size limits since they make no sense
 	 * ignore negative time and size limits since they make no sense
 	 */
 	 */

+ 5 - 0
ldap/servers/slapd/slap.h

@@ -328,6 +328,11 @@ typedef void	(*VFP0)(void);
 #define SLAPD_LDAPI_DEFAULT_FILENAME "/var/run/ldapi"
 #define SLAPD_LDAPI_DEFAULT_FILENAME "/var/run/ldapi"
 #define SLAPD_LDAPI_DEFAULT_STATUS "off"
 #define SLAPD_LDAPI_DEFAULT_STATUS "off"
 
 
+/* Anonymous access */
+#define SLAPD_ANON_ACCESS_OFF           0
+#define SLAPD_ANON_ACCESS_ON            1
+#define SLAPD_ANON_ACCESS_ROOTDSE       2
+
 struct subfilt {
 struct subfilt {
 	char	*sf_type;
 	char	*sf_type;
 	char	*sf_initial;
 	char	*sf_initial;