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