Blame SOURCES/0070-Ticket-49379-Allowed-sasl-mapping-requires-restart.patch

6f51e1
From 8a7b47602acc910d2f64439b81af3299b60359c8 Mon Sep 17 00:00:00 2001
6f51e1
From: Mark Reynolds <mreynolds@redhat.com>
6f51e1
Date: Mon, 18 Sep 2017 10:35:20 -0400
6f51e1
Subject: [PATCH] Ticket 49379 - Allowed sasl mapping requires restart
6f51e1
6f51e1
Bug Description:  If allowed sasl mechanisms are configured, and the server is
6f51e1
                  restarted, trying to add new sasl mechanisms does not get applied
6f51e1
                  until the server is restarted again. [1]
6f51e1
6f51e1
                  We were also overwriting memory when we stripped the commas from
6f51e1
                  the allowed machanism list.  THis lead to the allowed mechanisms
6f51e1
                  to get truncated,and permanently lose certain mechs. [2]
6f51e1
6f51e1
                  A crash with PLAIN sasl mechanism was also found. [3]
6f51e1
6f51e1
Fix Description:  To address allowed sasl mechs, we no longer explicitly the mechanisms
6f51e1
                  during the sasl_init at server startup.  Instead we check the allowed
6f51e1
                  list ourselves during a bind. [1]
6f51e1
6f51e1
                  When setting the allowed sasl mechs, make a copy of the value to
6f51e1
                  apply the changes to(removing coamms), and do not change the original
6f51e1
                  value as it's still being used. [2]
6f51e1
6f51e1
                  The crash when using sasl PLAIN was due to unlocking a rwlock that
6f51e1
                  was not locked. [3]
6f51e1
6f51e1
https://pagure.io/389-ds-base/issue/49379
6f51e1
6f51e1
Reviewed by: tbordaz(Thanks!)
6f51e1
6f51e1
(cherry picked from commit c78f41db31752a99aadd6abcbf7a1d852a8e7931)
6f51e1
---
6f51e1
 dirsrvtests/tests/suites/sasl/allowed_mechs.py | 114 ++++++++++++++++++++++--
6f51e1
 dirsrvtests/tests/suites/sasl/plain.py         |  10 ++-
6f51e1
 ldap/servers/slapd/libglobs.c                  |  23 ++---
6f51e1
 ldap/servers/slapd/saslbind.c                  | 116 +++++++++++++------------
6f51e1
 4 files changed, 187 insertions(+), 76 deletions(-)
6f51e1
6f51e1
diff --git a/dirsrvtests/tests/suites/sasl/allowed_mechs.py b/dirsrvtests/tests/suites/sasl/allowed_mechs.py
6f51e1
index 7958db4..5b1b92c 100644
6f51e1
--- a/dirsrvtests/tests/suites/sasl/allowed_mechs.py
6f51e1
+++ b/dirsrvtests/tests/suites/sasl/allowed_mechs.py
6f51e1
@@ -8,45 +8,141 @@
6f51e1
 #
6f51e1
 
6f51e1
 import pytest
6f51e1
-import ldap
6f51e1
-
6f51e1
-import time
6f51e1
-
6f51e1
+import os
6f51e1
 from lib389.topologies import topology_st
6f51e1
 
6f51e1
+
6f51e1
 def test_sasl_allowed_mechs(topology_st):
6f51e1
+    """Test the alloweed sasl mechanism feature
6f51e1
+
6f51e1
+    :ID: ab7d9f86-8cfe-48c3-8baa-739e599f006a
6f51e1
+    :feature: Allowed sasl mechanisms
6f51e1
+    :steps: 1.  Get the default list of mechanisms
6f51e1
+            2.  Set allowed mechanism PLAIN, and verify it's correctly listed
6f51e1
+            3.  Restart server, and verify list is still correct
6f51e1
+            4.  Test EXTERNAL is properly listed
6f51e1
+            5.  Add GSSAPI to the existing list, and verify it's correctly listed
6f51e1
+            6.  Restart server and verify list is still correct
6f51e1
+            7.  Add ANONYMOUS to the existing list, and veirfy it's correctly listed
6f51e1
+            8.  Restart server and verify list is still correct
6f51e1
+            9.  Remove GSSAPI and verify it's correctly listed
6f51e1
+            10. Restart server and verify list is still correct
6f51e1
+            11. Reset allowed list to nothing, verify "all" the mechanisms are returned
6f51e1
+            12. Restart server and verify list is still correct
6f51e1
+
6f51e1
+    :expectedresults: The supported mechanisms supported what is set for the allowed
6f51e1
+                      mechanisms
6f51e1
+    """
6f51e1
     standalone = topology_st.standalone
6f51e1
 
6f51e1
     # Get the supported mechs. This should contain PLAIN, GSSAPI, EXTERNAL at least
6f51e1
+    standalone.log.info("Test we have some of the default mechanisms")
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
+    # Now edit the supported mechs. Check them again.
6f51e1
+    standalone.log.info("Edit mechanisms to allow just PLAIN")
6f51e1
     standalone.config.set('nsslapd-allowed-sasl-mechanisms', 'PLAIN')
6f51e1
+    limit_mechs = standalone.rootdse.supported_sasl()
6f51e1
+    assert('PLAIN' in limit_mechs)
6f51e1
+    assert('EXTERNAL' in limit_mechs)  # Should always be in the allowed list, even if not set.
6f51e1
+    assert('GSSAPI' not in limit_mechs)  # Should not be there!
6f51e1
 
6f51e1
+    # Restart the server a few times and make sure nothing changes
6f51e1
+    standalone.log.info("Restart server and make sure we still have correct allowed mechs")
6f51e1
+    standalone.restart()
6f51e1
+    standalone.restart()
6f51e1
     limit_mechs = standalone.rootdse.supported_sasl()
6f51e1
     assert('PLAIN' in limit_mechs)
6f51e1
-    # Should always be in the allowed list, even if not set.
6f51e1
     assert('EXTERNAL' in limit_mechs)
6f51e1
-    # Should not be there!
6f51e1
     assert('GSSAPI' not in limit_mechs)
6f51e1
 
6f51e1
+    # Set EXTERNAL, even though its always supported
6f51e1
+    standalone.log.info("Edit mechanisms to allow just PLAIN and EXTERNAL")
6f51e1
     standalone.config.set('nsslapd-allowed-sasl-mechanisms', 'PLAIN, EXTERNAL')
6f51e1
+    limit_mechs = standalone.rootdse.supported_sasl()
6f51e1
+    assert('PLAIN' in limit_mechs)
6f51e1
+    assert('EXTERNAL' in limit_mechs)
6f51e1
+    assert('GSSAPI' not in limit_mechs)
6f51e1
+
6f51e1
+    # Now edit the supported mechs. Check them again.
6f51e1
+    standalone.log.info("Edit mechanisms to allow just PLAIN and GSSAPI")
6f51e1
+    standalone.config.set('nsslapd-allowed-sasl-mechanisms', 'PLAIN, GSSAPI')
6f51e1
+    limit_mechs = standalone.rootdse.supported_sasl()
6f51e1
+    assert('PLAIN' in limit_mechs)
6f51e1
+    assert('EXTERNAL' in limit_mechs)
6f51e1
+    assert('GSSAPI' in limit_mechs)
6f51e1
+    assert(len(limit_mechs) == 3)
6f51e1
+
6f51e1
+    # Restart server twice and make sure the allowed list is the same
6f51e1
+    standalone.restart()
6f51e1
+    standalone.restart()  # For ticket 49379 (test double restart)
6f51e1
+    limit_mechs = standalone.rootdse.supported_sasl()
6f51e1
+    assert('PLAIN' in limit_mechs)
6f51e1
+    assert('EXTERNAL' in limit_mechs)
6f51e1
+    assert('GSSAPI' in limit_mechs)
6f51e1
+    assert(len(limit_mechs) == 3)
6f51e1
+
6f51e1
+    # Add ANONYMOUS to the supported mechs and test again.
6f51e1
+    standalone.log.info("Edit mechanisms to allow just PLAIN, GSSAPI, and ANONYMOUS")
6f51e1
+    standalone.config.set('nsslapd-allowed-sasl-mechanisms', 'PLAIN, GSSAPI, ANONYMOUS')
6f51e1
+    limit_mechs = standalone.rootdse.supported_sasl()
6f51e1
+    assert('PLAIN' in limit_mechs)
6f51e1
+    assert('EXTERNAL' in limit_mechs)
6f51e1
+    assert('GSSAPI' in limit_mechs)
6f51e1
+    assert('ANONYMOUS' in limit_mechs)
6f51e1
+    assert(len(limit_mechs) == 4)
6f51e1
+
6f51e1
+    # Restart server and make sure the allowed list is the same
6f51e1
+    standalone.restart()
6f51e1
+    standalone.restart()  # For ticket 49379 (test double restart)
6f51e1
+    limit_mechs = standalone.rootdse.supported_sasl()
6f51e1
+    assert('PLAIN' in limit_mechs)
6f51e1
+    assert('EXTERNAL' in limit_mechs)
6f51e1
+    assert('GSSAPI' in limit_mechs)
6f51e1
+    assert('ANONYMOUS' in limit_mechs)
6f51e1
+    assert(len(limit_mechs) == 4)
6f51e1
 
6f51e1
+    # Remove GSSAPI
6f51e1
+    standalone.log.info("Edit mechanisms to allow just PLAIN and ANONYMOUS")
6f51e1
+    standalone.config.set('nsslapd-allowed-sasl-mechanisms', 'PLAIN, ANONYMOUS')
6f51e1
     limit_mechs = standalone.rootdse.supported_sasl()
6f51e1
     assert('PLAIN' in limit_mechs)
6f51e1
     assert('EXTERNAL' in limit_mechs)
6f51e1
-    # Should not be there!
6f51e1
     assert('GSSAPI' not in limit_mechs)
6f51e1
+    assert('ANONYMOUS' in limit_mechs)
6f51e1
+    assert(len(limit_mechs) == 3)
6f51e1
+
6f51e1
+    # Restart server and make sure the allowed list is the same
6f51e1
+    standalone.restart()
6f51e1
+    limit_mechs = standalone.rootdse.supported_sasl()
6f51e1
+    assert('PLAIN' in limit_mechs)
6f51e1
+    assert('EXTERNAL' in limit_mechs)
6f51e1
+    assert('GSSAPI' not in limit_mechs)
6f51e1
+    assert('ANONYMOUS' in limit_mechs)
6f51e1
+    assert(len(limit_mechs) == 3)
6f51e1
 
6f51e1
     # Do a config reset
6f51e1
+    standalone.log.info("Reset allowed mechaisms")
6f51e1
     standalone.config.reset('nsslapd-allowed-sasl-mechanisms')
6f51e1
 
6f51e1
     # check the supported list is the same as our first check.
6f51e1
+    standalone.log.info("Check that we have the original set of mechanisms")
6f51e1
     final_mechs = standalone.rootdse.supported_sasl()
6f51e1
-    print(final_mechs)
6f51e1
     assert(set(final_mechs) == set(orig_mechs))
6f51e1
 
6f51e1
+    # Check it after a restart
6f51e1
+    standalone.log.info("Check that we have the original set of mechanisms after a restart")
6f51e1
+    standalone.restart()
6f51e1
+    final_mechs = standalone.rootdse.supported_sasl()
6f51e1
+    assert(set(final_mechs) == set(orig_mechs))
6f51e1
+
6f51e1
+
6f51e1
+if __name__ == '__main__':
6f51e1
+    # Run isolated
6f51e1
+    # -s for DEBUG mode
6f51e1
+    CURRENT_FILE = os.path.realpath(__file__)
6f51e1
+    pytest.main("-s %s" % CURRENT_FILE)
6f51e1
diff --git a/dirsrvtests/tests/suites/sasl/plain.py b/dirsrvtests/tests/suites/sasl/plain.py
6f51e1
index 91ccb02..6bf39a8 100644
6f51e1
--- a/dirsrvtests/tests/suites/sasl/plain.py
6f51e1
+++ b/dirsrvtests/tests/suites/sasl/plain.py
6f51e1
@@ -15,9 +15,11 @@ from lib389.topologies import topology_st
6f51e1
 from lib389.utils import *
6f51e1
 from lib389.sasl import PlainSASL
6f51e1
 from lib389.idm.services import ServiceAccounts
6f51e1
+from lib389._constants import (SECUREPORT_STANDALONE1, DEFAULT_SUFFIX)
6f51e1
 
6f51e1
 log = logging.getLogger(__name__)
6f51e1
 
6f51e1
+
6f51e1
 def test_sasl_plain(topology_st):
6f51e1
 
6f51e1
     standalone = topology_st.standalone
6f51e1
@@ -38,7 +40,7 @@ def test_sasl_plain(topology_st):
6f51e1
     standalone.rsa.create()
6f51e1
     # Set the secure port and nsslapd-security
6f51e1
     # Could this fail with selinux?
6f51e1
-    standalone.config.set('nsslapd-secureport', '%s' % SECUREPORT_STANDALONE1 )
6f51e1
+    standalone.config.set('nsslapd-secureport', '%s' % SECUREPORT_STANDALONE1)
6f51e1
     standalone.config.set('nsslapd-security', 'on')
6f51e1
     # Do we need to restart to allow starttls?
6f51e1
     standalone.restart()
6f51e1
@@ -65,12 +67,14 @@ def test_sasl_plain(topology_st):
6f51e1
     # I can not solve. I think it's leaking state across connections in start_tls_s?
6f51e1
 
6f51e1
     # Check that it works with TLS
6f51e1
-    conn = standalone.openConnection(saslmethod='PLAIN', sasltoken=auth_tokens, starttls=True, connOnly=True, certdir=standalone.get_cert_dir(), reqcert=ldap.OPT_X_TLS_NEVER)
6f51e1
+    conn = standalone.openConnection(saslmethod='PLAIN', sasltoken=auth_tokens, starttls=True, connOnly=True,
6f51e1
+                                    certdir=standalone.get_cert_dir(), reqcert=ldap.OPT_X_TLS_NEVER)
6f51e1
     conn.close()
6f51e1
 
6f51e1
     # Check that it correct fails our bind if we don't have the password.
6f51e1
     auth_tokens = PlainSASL("dn:%s" % sa.dn, 'password-wrong')
6f51e1
     with pytest.raises(ldap.INVALID_CREDENTIALS):
6f51e1
-        standalone.openConnection(saslmethod='PLAIN', sasltoken=auth_tokens, starttls=False, connOnly=True, certdir=standalone.get_cert_dir(), reqcert=ldap.OPT_X_TLS_NEVER)
6f51e1
+        standalone.openConnection(saslmethod='PLAIN', sasltoken=auth_tokens, starttls=True, connOnly=True,
6f51e1
+                                  certdir=standalone.get_cert_dir(), reqcert=ldap.OPT_X_TLS_NEVER)
6f51e1
 
6f51e1
     # Done!
6f51e1
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
6f51e1
index bb51827..2fb4bab 100644
6f51e1
--- a/ldap/servers/slapd/libglobs.c
6f51e1
+++ b/ldap/servers/slapd/libglobs.c
6f51e1
@@ -7137,22 +7137,25 @@ config_set_allowed_sasl_mechs(const char *attrname, char *value, char *errorbuf,
6f51e1
 
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
+        char *nval = slapi_ch_strdup(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
+        /* cyrus sasl doesn't like comma separated lists */
6f51e1
+        remove_commas(nval);
6f51e1
+
6f51e1
+        if (invalid_sasl_mech(nval)) {
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",
6f51e1
+                          nval);
6f51e1
+            slapi_ch_free_string(&nval);
6f51e1
             return LDAP_UNWILLING_TO_PERFORM;
6f51e1
         }
6f51e1
-
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
+        slapdFrontendConfig->allowed_sasl_mechs = nval;
6f51e1
+        slapdFrontendConfig->allowed_sasl_mechs_array = slapi_str2charray_ext(nval, " ", 0);
6f51e1
         CFG_UNLOCK_WRITE(slapdFrontendConfig);
6f51e1
     } else {
6f51e1
         /* If this value is "", we need to set the list to *all* possible mechs */
6f51e1
diff --git a/ldap/servers/slapd/saslbind.c b/ldap/servers/slapd/saslbind.c
6f51e1
index 134f5aa..03e2a97 100644
6f51e1
--- a/ldap/servers/slapd/saslbind.c
6f51e1
+++ b/ldap/servers/slapd/saslbind.c
6f51e1
@@ -169,8 +169,6 @@ static int ids_sasl_getopt(
6f51e1
         }
6f51e1
     } else if (strcasecmp(option, "auxprop_plugin") == 0) {
6f51e1
         *result = "iDS";
6f51e1
-    } else if (strcasecmp(option, "mech_list") == 0){
6f51e1
-        *result = config_get_allowed_sasl_mechs();
6f51e1
     }
6f51e1
 
6f51e1
     if (*result) *len = strlen(*result);
6f51e1
@@ -572,12 +570,8 @@ static int ids_sasl_userdb_checkpass(sasl_conn_t *conn, void *context, const cha
6f51e1
         slapi_pblock_set(pb, SLAPI_BIND_METHOD, &method);
6f51e1
         /* Feed it to pw_verify_be_dn */
6f51e1
         bind_result = pw_verify_be_dn(pb, &referral);
6f51e1
-        /* Now check the result, and unlock be if needed. */
6f51e1
-        if (bind_result == SLAPI_BIND_SUCCESS || bind_result == SLAPI_BIND_ANONYMOUS) {
6f51e1
-            Slapi_Backend *be = NULL;
6f51e1
-            slapi_pblock_get(pb, SLAPI_BACKEND, &be);
6f51e1
-            slapi_be_Unlock(be);
6f51e1
-        } else if (bind_result == SLAPI_BIND_REFERRAL) {
6f51e1
+        /* Now check the result. */
6f51e1
+        if (bind_result == SLAPI_BIND_REFERRAL) {
6f51e1
             /* If we have a referral do we ignore it for sasl? */
6f51e1
             slapi_entry_free(referral);
6f51e1
         }
6f51e1
@@ -760,22 +754,25 @@ char **ids_sasl_listmech(Slapi_PBlock *pb)
6f51e1
     sup_ret = slapi_get_supported_saslmechanisms_copy();
6f51e1
 
6f51e1
     /* If we have a connection, get the provided list from SASL */
6f51e1
-    if (pb->pb_conn != NULL) {
6f51e1
-        sasl_conn = (sasl_conn_t*)pb->pb_conn->c_sasl_conn;
6f51e1
-
6f51e1
-        /* sasl library mechanisms are connection dependent */
6f51e1
-        PR_EnterMonitor(pb->pb_conn->c_mutex);
6f51e1
-        if (sasl_listmech(sasl_conn,
6f51e1
-                          NULL,     /* username */
6f51e1
-                          "", ",", "",
6f51e1
-                          &str, NULL, NULL) == SASL_OK) {
6f51e1
-            slapi_log_err(SLAPI_LOG_TRACE, "ids_sasl_listmech", "sasl library mechs: %s\n", str);
6f51e1
-            /* merge into result set */
6f51e1
-            dupstr = slapi_ch_strdup(str);
6f51e1
-            others = slapi_str2charray_ext(dupstr, ",", 0 /* don't list duplicate mechanisms */);
6f51e1
-            charray_merge(&sup_ret, others, 1);
6f51e1
-            charray_free(others);
6f51e1
-            slapi_ch_free((void**)&dupstr);
6f51e1
+    if (pb_conn != NULL) {
6f51e1
+        sasl_conn = (sasl_conn_t*)pb_conn->c_sasl_conn;
6f51e1
+        if (sasl_conn != NULL) {
6f51e1
+            /* sasl library mechanisms are connection dependent */
6f51e1
+            PR_EnterMonitor(pb_conn->c_mutex);
6f51e1
+            if (sasl_listmech(sasl_conn,
6f51e1
+                              NULL,     /* username */
6f51e1
+                              "", ",", "",
6f51e1
+                              &str, NULL, NULL) == SASL_OK) {
6f51e1
+                slapi_log_err(SLAPI_LOG_TRACE, "ids_sasl_listmech", "sasl library mechs: %s\n", str);
6f51e1
+                /* merge into result set */
6f51e1
+                dupstr = slapi_ch_strdup(str);
6f51e1
+                others = slapi_str2charray_ext(dupstr, ",", 0 /* don't list duplicate mechanisms */);
6f51e1
+
6f51e1
+                charray_merge(&sup_ret, others, 1);
6f51e1
+                charray_free(others);
6f51e1
+                slapi_ch_free((void**)&dupstr);
6f51e1
+            }
6f51e1
+            PR_ExitMonitor(pb_conn->c_mutex);
6f51e1
         }
6f51e1
         PR_ExitMonitor(pb->pb_conn->c_mutex);
6f51e1
     }
6f51e1
@@ -785,7 +782,7 @@ char **ids_sasl_listmech(Slapi_PBlock *pb)
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
+        /* Get the set of supported mechs in the intersection of the two */
6f51e1
         ret = charray_intersection(sup_ret, config_ret);
6f51e1
         charray_free(sup_ret);
6f51e1
         charray_free(config_ret);
6f51e1
@@ -816,41 +813,52 @@ char **ids_sasl_listmech(Slapi_PBlock *pb)
6f51e1
 static int
6f51e1
 ids_sasl_mech_supported(Slapi_PBlock *pb, const char *mech)
6f51e1
 {
6f51e1
-  int i, ret = 0;
6f51e1
-  char **mechs;
6f51e1
-  char *dupstr;
6f51e1
-  const char *str;
6f51e1
-  int sasl_result = 0;
6f51e1
-  sasl_conn_t *sasl_conn = (sasl_conn_t *)pb->pb_conn->c_sasl_conn;
6f51e1
-
6f51e1
-  slapi_log_err(SLAPI_LOG_TRACE, "ids_sasl_mech_supported", "=>\n");
6f51e1
-
6f51e1
-
6f51e1
-  /* sasl_listmech is not thread-safe - caller must lock pb_conn */
6f51e1
-  sasl_result = sasl_listmech(sasl_conn, 
6f51e1
-                    NULL,     /* username */
6f51e1
-                    "", ",", "",
6f51e1
-                    &str, NULL, NULL);
6f51e1
-  if (sasl_result != SASL_OK) {
6f51e1
-    return 0;
6f51e1
-  }
6f51e1
+    int i, ret = 0;
6f51e1
+    char **mechs;
6f51e1
+    char **allowed_mechs = NULL;
6f51e1
+    char *dupstr;
6f51e1
+    const char *str;
6f51e1
+    int sasl_result = 0;
6f51e1
+    Connection *pb_conn = NULL;
6f51e1
+
6f51e1
+    slapi_pblock_get(pb, SLAPI_CONNECTION, &pb_conn);
6f51e1
+    sasl_conn_t *sasl_conn = (sasl_conn_t *)pb_conn->c_sasl_conn;
6f51e1
+    slapi_log_err(SLAPI_LOG_TRACE, "ids_sasl_mech_supported", "=>\n");
6f51e1
+
6f51e1
+    /* sasl_listmech is not thread-safe - caller must lock pb_conn */
6f51e1
+    sasl_result = sasl_listmech(sasl_conn,
6f51e1
+                                NULL, /* username */
6f51e1
+                                "", ",", "",
6f51e1
+                                &str, NULL, NULL);
6f51e1
+    if (sasl_result != SASL_OK) {
6f51e1
+        return 0;
6f51e1
+    }
6f51e1
 
6f51e1
-  dupstr = slapi_ch_strdup(str);
6f51e1
-  mechs = slapi_str2charray(dupstr, ",");
6f51e1
+    dupstr = slapi_ch_strdup(str);
6f51e1
+    mechs = slapi_str2charray(dupstr, ",");
6f51e1
+    allowed_mechs = config_get_allowed_sasl_mechs_array();
6f51e1
 
6f51e1
-  for (i = 0; mechs[i] != NULL; i++) {
6f51e1
-    if (strcasecmp(mech, mechs[i]) == 0) {
6f51e1
-      ret = 1;
6f51e1
-      break;
6f51e1
+    for (i = 0; mechs[i] != NULL; i++) {
6f51e1
+        if (strcasecmp(mech, mechs[i]) == 0) {
6f51e1
+            if (allowed_mechs) {
6f51e1
+                if (charray_inlist(allowed_mechs, (char *)mech) == 0) {
6f51e1
+                    ret = 1;
6f51e1
+                }
6f51e1
+                break;
6f51e1
+            } else {
6f51e1
+                ret = 1;
6f51e1
+                break;
6f51e1
+            }
6f51e1
+        }
6f51e1
     }
6f51e1
-  }
6f51e1
 
6f51e1
-  charray_free(mechs);
6f51e1
-  slapi_ch_free((void**)&dupstr);
6f51e1
+    charray_free(allowed_mechs);
6f51e1
+    charray_free(mechs);
6f51e1
+    slapi_ch_free((void **)&dupstr);
6f51e1
 
6f51e1
-  slapi_log_err(SLAPI_LOG_TRACE, "ids_sasl_mech_supported", "<=\n");
6f51e1
+    slapi_log_err(SLAPI_LOG_TRACE, "ids_sasl_mech_supported", "<=\n");
6f51e1
 
6f51e1
-  return ret;
6f51e1
+    return ret;
6f51e1
 }
6f51e1
 
6f51e1
 /*
6f51e1
-- 
6f51e1
2.9.5
6f51e1