Blame SOURCES/0030-Ticket-49231-fix-sasl-mech-handling.patch

6f51e1
From 88a0ce3c3f89244a77dfa618c8a5064bda30f376 Mon Sep 17 00:00:00 2001
6f51e1
From: William Brown <firstyear@redhat.com>
6f51e1
Date: Wed, 26 Apr 2017 15:48:30 +1000
6f51e1
Subject: [PATCH] Ticket 49231 - fix sasl mech handling
6f51e1
6f51e1
Bug Description:  In our sasl code we had two issues. One was that
6f51e1
we did not correctly apply the list of sasl allowed mechs to our
6f51e1
rootdse list in ids_sasl_listmech. The second was that on config
6f51e1
reset, we did not correctly set null to the value.
6f51e1
6f51e1
Fix Description:  Fix the handling of the mech lists to allow
6f51e1
reset, and allow the mech list to be updated properly.
6f51e1
6f51e1
https://pagure.io/389-ds-base/issue/49231
6f51e1
6f51e1
Author: wibrown
6f51e1
6f51e1
Review by: mreynolds (Thanks!)
6f51e1
---
6f51e1
 dirsrvtests/tests/suites/sasl/allowed_mechs.py | 43 ++++++++++++++++++
6f51e1
 ldap/servers/slapd/charray.c                   | 48 +++++++++++++++++---
6f51e1
 ldap/servers/slapd/libglobs.c                  | 62 ++++++++++++++++++++------
6f51e1
 ldap/servers/slapd/proto-slap.h                |  1 +
6f51e1
 ldap/servers/slapd/saslbind.c                  | 21 ++++++++-
6f51e1
 ldap/servers/slapd/slap.h                      |  1 +
6f51e1
 ldap/servers/slapd/slapi-private.h             |  1 +
6f51e1
 7 files changed, 156 insertions(+), 21 deletions(-)
6f51e1
 create mode 100644 dirsrvtests/tests/suites/sasl/allowed_mechs.py
6f51e1
6f51e1
diff --git a/dirsrvtests/tests/suites/sasl/allowed_mechs.py b/dirsrvtests/tests/suites/sasl/allowed_mechs.py
6f51e1
new file mode 100644
6f51e1
index 0000000..a3e385e
6f51e1
--- /dev/null
6f51e1
+++ b/dirsrvtests/tests/suites/sasl/allowed_mechs.py
6f51e1
@@ -0,0 +1,43 @@
6f51e1
+# --- BEGIN COPYRIGHT BLOCK ---
6f51e1
+# Copyright (C) 2017 Red Hat, Inc.
6f51e1
+# All rights reserved.
6f51e1
+#
6f51e1
+# License: GPL (version 3 or any later version).
6f51e1
+# See LICENSE for details.
6f51e1
+# --- END COPYRIGHT BLOCK ---
6f51e1
+#
6f51e1
+
6f51e1
+import pytest
6f51e1
+import ldap
6f51e1
+
6f51e1
+import time
6f51e1
+
6f51e1
+from lib389.topologies import topology_st
6f51e1
+
6f51e1
+def test_sasl_allowed_mechs(topology_st):
6f51e1
+    standalone = topology_st.standalone
6f51e1
+
6f51e1
+    # Get the supported mechs. This should contain PLAIN, GSSAPI, EXTERNAL at least
6f51e1
+    orig_mechs = standalone.rootdse.supported_sasl()
6f51e1
+    print(orig_mechs)
6f51e1
+    assert('GSSAPI' in orig_mechs)
6f51e1
+    assert('PLAIN' in orig_mechs)
6f51e1
+    assert('EXTERNAL' in orig_mechs)
6f51e1
+
6f51e1
+    # Now edit the supported mechs. CHeck them again.
6f51e1
+    standalone.config.set('nsslapd-allowed-sasl-mechanisms', 'EXTERNAL, PLAIN')
6f51e1
+
6f51e1
+    limit_mechs = standalone.rootdse.supported_sasl()
6f51e1
+    print(limit_mechs)
6f51e1
+    assert('PLAIN' in limit_mechs)
6f51e1
+    assert('EXTERNAL' in limit_mechs)
6f51e1
+    assert('GSSAPI' not in limit_mechs)
6f51e1
+
6f51e1
+    # Do a config reset
6f51e1
+    standalone.config.reset('nsslapd-allowed-sasl-mechanisms')
6f51e1
+
6f51e1
+    # check the supported list is the same as our first check.
6f51e1
+    final_mechs = standalone.rootdse.supported_sasl()
6f51e1
+    print(final_mechs)
6f51e1
+    assert(set(final_mechs) == set(orig_mechs))
6f51e1
+
6f51e1
diff --git a/ldap/servers/slapd/charray.c b/ldap/servers/slapd/charray.c
6f51e1
index 5551dcc..6b89714 100644
6f51e1
--- a/ldap/servers/slapd/charray.c
6f51e1
+++ b/ldap/servers/slapd/charray.c
6f51e1
@@ -348,8 +348,9 @@ slapi_str2charray_ext( char *str, char *brkstr, int allow_dups )
6f51e1
             }
6f51e1
         }
6f51e1
 
6f51e1
-        if ( !dup_found )
6f51e1
+        if ( !dup_found ) {
6f51e1
             res[i++] = slapi_ch_strdup( s );
6f51e1
+        }
6f51e1
     }
6f51e1
     res[i] = NULL;
6f51e1
 
6f51e1
@@ -413,10 +414,11 @@ charray_subtract(char **a, char **b, char ***c)
6f51e1
     char **bp, **cp, **tmp;
6f51e1
     char **p;
6f51e1
 
6f51e1
-    if (c)
6f51e1
+    if (c) {
6f51e1
         tmp = *c = cool_charray_dup(a);
6f51e1
-    else
6f51e1
+    } else {
6f51e1
         tmp = a;
6f51e1
+    }
6f51e1
 
6f51e1
     for (cp = tmp; cp && *cp; cp++) {
6f51e1
         for (bp = b; bp && *bp; bp++) {
6f51e1
@@ -433,12 +435,48 @@ charray_subtract(char **a, char **b, char ***c)
6f51e1
             for (p = cp+1; *p && *p == (char *)SUBTRACT_DEL; p++)
6f51e1
                 ;
6f51e1
             *cp = *p;    
6f51e1
-            if (*p == NULL)
6f51e1
+            if (*p == NULL) {
6f51e1
                 break;
6f51e1
-            else
6f51e1
+            } else {
6f51e1
                 *p = SUBTRACT_DEL;
6f51e1
+            }
6f51e1
+        }
6f51e1
+    }
6f51e1
+}
6f51e1
+
6f51e1
+/*
6f51e1
+ * Provides the intersection of two arrays.
6f51e1
+ * IE if you have:
6f51e1
+ * (A, B, C)
6f51e1
+ * (B, D, E)
6f51e1
+ * result is (B,)
6f51e1
+ * a and b are NOT consumed in the process.
6f51e1
+ */
6f51e1
+char **
6f51e1
+charray_intersection(char **a, char **b) {
6f51e1
+    char **result;
6f51e1
+    size_t rp = 0;
6f51e1
+
6f51e1
+    if (a == NULL || b == NULL) {
6f51e1
+        return NULL;
6f51e1
+    }
6f51e1
+
6f51e1
+    size_t a_len = 0;
6f51e1
+    /* Find how long A is. */
6f51e1
+    for (; a[a_len] != NULL; a_len++);
6f51e1
+
6f51e1
+    /* Allocate our result, it can't be bigger than A */
6f51e1
+    result = (char **)slapi_ch_calloc(1, sizeof(char *) * (a_len + 1));
6f51e1
+
6f51e1
+    /* For each in A, see if it's in b */
6f51e1
+    for (size_t i = 0; a[i] != NULL; i++) {
6f51e1
+        if (charray_get_index(b, a[i]) != -1) {
6f51e1
+            result[rp] = slapi_ch_strdup(a[i]);
6f51e1
+            rp++;
6f51e1
         }
6f51e1
     }
6f51e1
+
6f51e1
+    return result;
6f51e1
 }
6f51e1
 
6f51e1
 int
6f51e1
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
6f51e1
index 0e818a9..2fc9fbf 100644
6f51e1
--- a/ldap/servers/slapd/libglobs.c
6f51e1
+++ b/ldap/servers/slapd/libglobs.c
6f51e1
@@ -7090,9 +7090,30 @@ config_set_entryusn_import_init( const char *attrname, char *value,
6f51e1
     return retVal;
6f51e1
 }
6f51e1
 
6f51e1
+char **
6f51e1
+config_get_allowed_sasl_mechs_array(void)
6f51e1
+{
6f51e1
+    /*
6f51e1
+     * array of mechs. If is null, returns NULL thanks to ch_array_dup.
6f51e1
+     * Caller must free!
6f51e1
+     */
6f51e1
+    char **retVal;
6f51e1
+    slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
6f51e1
+
6f51e1
+    CFG_LOCK_READ(slapdFrontendConfig);
6f51e1
+    retVal = slapi_ch_array_dup(slapdFrontendConfig->allowed_sasl_mechs_array);
6f51e1
+    CFG_UNLOCK_READ(slapdFrontendConfig);
6f51e1
+
6f51e1
+    return retVal;
6f51e1
+}
6f51e1
+
6f51e1
 char *
6f51e1
-config_get_allowed_sasl_mechs()
6f51e1
+config_get_allowed_sasl_mechs(void)
6f51e1
 {
6f51e1
+    /*
6f51e1
+     * Space seperated list of allowed mechs
6f51e1
+     * if this is NULL, means *all* mechs are allowed!
6f51e1
+     */
6f51e1
     char *retVal;
6f51e1
     slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
6f51e1
 
6f51e1
@@ -7113,22 +7134,35 @@ config_set_allowed_sasl_mechs(const char *attrname, char *value, char *errorbuf,
6f51e1
         return LDAP_SUCCESS;
6f51e1
     }
6f51e1
 
6f51e1
-    /* cyrus sasl doesn't like comma separated lists */
6f51e1
-    remove_commas(value);
6f51e1
+    /* During a reset, the value is "", so we have to handle this case. */
6f51e1
+    if (strcmp(value, "") != 0) {
6f51e1
+        /* cyrus sasl doesn't like comma separated lists */
6f51e1
+        remove_commas(value);
6f51e1
+
6f51e1
+        if(invalid_sasl_mech(value)){
6f51e1
+            slapi_log_err(SLAPI_LOG_ERR,"config_set_allowed_sasl_mechs",
6f51e1
+                    "Invalid value/character for sasl mechanism (%s).  Use ASCII "
6f51e1
+                    "characters, upto 20 characters, that are upper-case letters, "
6f51e1
+                    "digits, hyphens, or underscores\n", value);
6f51e1
+            return LDAP_UNWILLING_TO_PERFORM;
6f51e1
+        }
6f51e1
 
6f51e1
-    if(invalid_sasl_mech(value)){
6f51e1
-        slapi_log_err(SLAPI_LOG_ERR,"config_set_allowed_sasl_mechs",
6f51e1
-                "Invalid value/character for sasl mechanism (%s).  Use ASCII "
6f51e1
-                "characters, upto 20 characters, that are upper-case letters, "
6f51e1
-                "digits, hyphens, or underscores\n", value);
6f51e1
-        return LDAP_UNWILLING_TO_PERFORM;
6f51e1
+        CFG_LOCK_WRITE(slapdFrontendConfig);
6f51e1
+        slapi_ch_free_string(&slapdFrontendConfig->allowed_sasl_mechs);
6f51e1
+        slapi_ch_array_free(slapdFrontendConfig->allowed_sasl_mechs_array);
6f51e1
+        slapdFrontendConfig->allowed_sasl_mechs = slapi_ch_strdup(value);
6f51e1
+        slapdFrontendConfig->allowed_sasl_mechs_array = slapi_str2charray_ext(value, " ", 0);
6f51e1
+        CFG_UNLOCK_WRITE(slapdFrontendConfig);
6f51e1
+    } else {
6f51e1
+        /* If this value is "", we need to set the list to *all* possible mechs */
6f51e1
+        CFG_LOCK_WRITE(slapdFrontendConfig);
6f51e1
+        slapi_ch_free_string(&slapdFrontendConfig->allowed_sasl_mechs);
6f51e1
+        slapi_ch_array_free(slapdFrontendConfig->allowed_sasl_mechs_array);
6f51e1
+        slapdFrontendConfig->allowed_sasl_mechs = NULL;
6f51e1
+        slapdFrontendConfig->allowed_sasl_mechs_array = NULL;
6f51e1
+        CFG_UNLOCK_WRITE(slapdFrontendConfig);
6f51e1
     }
6f51e1
 
6f51e1
-    CFG_LOCK_WRITE(slapdFrontendConfig);
6f51e1
-    slapi_ch_free_string(&slapdFrontendConfig->allowed_sasl_mechs);
6f51e1
-    slapdFrontendConfig->allowed_sasl_mechs = slapi_ch_strdup(value);
6f51e1
-    CFG_UNLOCK_WRITE(slapdFrontendConfig);
6f51e1
-
6f51e1
     return LDAP_SUCCESS;
6f51e1
 }
6f51e1
 
6f51e1
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
6f51e1
index fdb4bf0..9696ead 100644
6f51e1
--- a/ldap/servers/slapd/proto-slap.h
6f51e1
+++ b/ldap/servers/slapd/proto-slap.h
6f51e1
@@ -553,6 +553,7 @@ size_t config_get_ndn_cache_size(void);
6f51e1
 int config_get_ndn_cache_enabled(void);
6f51e1
 int config_get_return_orig_type_switch(void);
6f51e1
 char *config_get_allowed_sasl_mechs(void);
6f51e1
+char **config_get_allowed_sasl_mechs_array(void);
6f51e1
 int config_set_allowed_sasl_mechs(const char *attrname, char *value, char *errorbuf, int apply);
6f51e1
 int config_get_schemamod(void);
6f51e1
 int config_set_ignore_vattrs(const char *attrname, char *value, char *errorbuf, int apply);
6f51e1
diff --git a/ldap/servers/slapd/saslbind.c b/ldap/servers/slapd/saslbind.c
6f51e1
index 2d6fb64..6e544e6 100644
6f51e1
--- a/ldap/servers/slapd/saslbind.c
6f51e1
+++ b/ldap/servers/slapd/saslbind.c
6f51e1
@@ -744,7 +744,10 @@ void ids_sasl_server_new(Connection *conn)
6f51e1
  */
6f51e1
 char **ids_sasl_listmech(Slapi_PBlock *pb)
6f51e1
 {
6f51e1
-    char **ret, **others;
6f51e1
+    char **ret;
6f51e1
+    char **config_ret;
6f51e1
+    char **sup_ret;
6f51e1
+    char **others;
6f51e1
     const char *str;
6f51e1
     char *dupstr;
6f51e1
     sasl_conn_t *sasl_conn;
6f51e1
@@ -754,7 +757,7 @@ char **ids_sasl_listmech(Slapi_PBlock *pb)
6f51e1
     PR_ASSERT(pb);
6f51e1
 
6f51e1
     /* hard-wired mechanisms and slapi plugin registered mechanisms */
6f51e1
-    ret = slapi_get_supported_saslmechanisms_copy();
6f51e1
+    sup_ret = slapi_get_supported_saslmechanisms_copy();
6f51e1
 
6f51e1
     if (pb->pb_conn == NULL) return ret;
6f51e1
 
6f51e1
@@ -777,6 +780,20 @@ char **ids_sasl_listmech(Slapi_PBlock *pb)
6f51e1
     }
6f51e1
     PR_ExitMonitor(pb->pb_conn->c_mutex);
6f51e1
 
6f51e1
+    /* Get the servers "allowed" list */
6f51e1
+    config_ret = config_get_allowed_sasl_mechs_array();
6f51e1
+
6f51e1
+    /* Remove any content that isn't in the allowed list */
6f51e1
+    if (config_ret != NULL) {
6f51e1
+        /* Get the set of supported mechs in the insection of the two */
6f51e1
+        ret = charray_intersection(sup_ret, config_ret);
6f51e1
+        charray_free(sup_ret);
6f51e1
+        charray_free(config_ret);
6f51e1
+    } else {
6f51e1
+        /* The allowed list was empty, just take our supported list. */
6f51e1
+        ret = sup_ret;
6f51e1
+    }
6f51e1
+
6f51e1
     slapi_log_err(SLAPI_LOG_TRACE, "ids_sasl_listmech", "<=\n");
6f51e1
 
6f51e1
     return ret;
6f51e1
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
6f51e1
index abfad20..5e44cc8 100644
6f51e1
--- a/ldap/servers/slapd/slap.h
6f51e1
+++ b/ldap/servers/slapd/slap.h
6f51e1
@@ -2577,6 +2577,7 @@ typedef struct _slapdFrontendConfig {
6f51e1
   int pagedsizelimit;
6f51e1
   char *default_naming_context; /* Default naming context (normalized) */
6f51e1
   char *allowed_sasl_mechs;     /* comma/space separated list of allowed sasl mechs */
6f51e1
+  char **allowed_sasl_mechs_array;     /* Array of allow sasl mechs */
6f51e1
   int sasl_max_bufsize;         /* The max receive buffer size for SASL */
6f51e1
 
6f51e1
   /* disk monitoring */
6f51e1
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
6f51e1
index d9547d8..3f732e8 100644
6f51e1
--- a/ldap/servers/slapd/slapi-private.h
6f51e1
+++ b/ldap/servers/slapd/slapi-private.h
6f51e1
@@ -831,6 +831,7 @@ int charray_remove(char **a, const char *s, int freeit);
6f51e1
 char ** cool_charray_dup( char **a );
6f51e1
 void cool_charray_free( char **array );
6f51e1
 void charray_subtract( char **a, char **b, char ***c );
6f51e1
+char **charray_intersection(char **a, char **b);
6f51e1
 int charray_get_index(char **array, char *s);
6f51e1
 int charray_normdn_add(char ***chararray, char *dn, char *errstr);
6f51e1
 
6f51e1
-- 
6f51e1
2.9.3
6f51e1