1c155e
From b0954a5df7841330732a5ab532c528a68cf380cf Mon Sep 17 00:00:00 2001
1c155e
From: William Brown <firstyear@redhat.com>
1c155e
Date: Fri, 18 Aug 2017 13:00:46 +1000
1c155e
Subject: [PATCH] Ticket 49356 - mapping tree crash can occur during tot init
1c155e
1c155e
Bug Description:  Two faults were found in the handling of the mapping
1c155e
tree of 389 directory server. The first fault was that the tree-free
1c155e
check was not performed atomically and may cause an incorrect operations
1c155e
error to be returned. The second was that during a total init the referral
1c155e
would not lock the be, but the pw_verify code assumed a be was locked.
1c155e
This caused a segfault.
1c155e
1c155e
Fix Description:  Fix the freed check to use atomics. Fix the pw_verify
1c155e
to assert be is NULL (which is correct, there is no backend).
1c155e
1c155e
https://pagure.io/389-ds-base/issue/49356
1c155e
1c155e
Author: wibrown
1c155e
1c155e
Review by: mreynolds (THanks!)
1c155e
---
1c155e
 .../mapping_tree/referral_during_tot_init.py       |  57 ++++++++
1c155e
 ldap/servers/slapd/fedse.c                         |  10 ++
1c155e
 ldap/servers/slapd/main.c                          |  10 --
1c155e
 ldap/servers/slapd/mapping_tree.c                  | 150 +++++++++++----------
1c155e
 ldap/servers/slapd/pw_verify.c                     |   8 +-
1c155e
 5 files changed, 150 insertions(+), 85 deletions(-)
1c155e
 create mode 100644 dirsrvtests/tests/suites/mapping_tree/referral_during_tot_init.py
1c155e
1c155e
diff --git a/dirsrvtests/tests/suites/mapping_tree/referral_during_tot_init.py b/dirsrvtests/tests/suites/mapping_tree/referral_during_tot_init.py
1c155e
new file mode 100644
1c155e
index 0000000..e5aee7d
1c155e
--- /dev/null
1c155e
+++ b/dirsrvtests/tests/suites/mapping_tree/referral_during_tot_init.py
1c155e
@@ -0,0 +1,57 @@
1c155e
+# --- BEGIN COPYRIGHT BLOCK ---
1c155e
+# Copyright (C) 2017 Red Hat, Inc.
1c155e
+# All rights reserved.
1c155e
+#
1c155e
+# License: GPL (version 3 or any later version).
1c155e
+# See LICENSE for details.
1c155e
+# --- END COPYRIGHT BLOCK ---
1c155e
+#
1c155e
+import ldap
1c155e
+import pytest
1c155e
+from lib389.topologies import topology_m2
1c155e
+from lib389._constants import (DEFAULT_SUFFIX, HOST_MASTER_2, PORT_MASTER_2, TASK_WAIT)
1c155e
+
1c155e
+from lib389.idm.user import (TEST_USER_PROPERTIES, UserAccounts)
1c155e
+
1c155e
+def test_referral_during_tot(topology_m2):
1c155e
+
1c155e
+    master1 = topology_m2.ms["master1"]
1c155e
+    master2 = topology_m2.ms["master2"]
1c155e
+
1c155e
+    # Create a bunch of entries on master1
1c155e
+    ldif_dir = master1.get_ldif_dir()
1c155e
+    import_ldif = ldif_dir + '/ref_during_tot_import.ldif'
1c155e
+    master1.buildLDIF(10000, import_ldif)
1c155e
+
1c155e
+    master1.stop()
1c155e
+    try:
1c155e
+        master1.ldif2db(bename=None, excludeSuffixes=None, encrypt=False, suffixes=[DEFAULT_SUFFIX], import_file=import_ldif)
1c155e
+    except:
1c155e
+        pass
1c155e
+    # master1.tasks.importLDIF(suffix=DEFAULT_SUFFIX, input_file=import_ldif, args={TASK_WAIT: True})
1c155e
+    master1.start()
1c155e
+    users = UserAccounts(master1, DEFAULT_SUFFIX, rdn='ou=Accounting')
1c155e
+
1c155e
+    u = users.create(properties=TEST_USER_PROPERTIES)
1c155e
+    u.set('userPassword', 'password')
1c155e
+
1c155e
+    binddn = u.dn
1c155e
+    bindpw = 'password'
1c155e
+
1c155e
+    # Now export them to master2
1c155e
+    master1.agreement.init(DEFAULT_SUFFIX, HOST_MASTER_2, PORT_MASTER_2)
1c155e
+
1c155e
+    # While that's happening try to bind as a user to master 2
1c155e
+    # This should trigger the referral code.
1c155e
+    for i in range(0, 100):
1c155e
+        conn = ldap.initialize(master2.toLDAPURL())
1c155e
+        conn.set_option(ldap.OPT_REFERRALS, False)
1c155e
+        try:
1c155e
+            conn.simple_bind_s(binddn, bindpw)
1c155e
+            conn.unbind_s()
1c155e
+        except ldap.REFERRAL:
1c155e
+            pass
1c155e
+
1c155e
+    # Done.
1c155e
+
1c155e
+
1c155e
diff --git a/ldap/servers/slapd/fedse.c b/ldap/servers/slapd/fedse.c
1c155e
index 13a3c74..c2a862b 100644
1c155e
--- a/ldap/servers/slapd/fedse.c
1c155e
+++ b/ldap/servers/slapd/fedse.c
1c155e
@@ -1853,6 +1853,16 @@ setup_internal_backends(char *configdir)
1c155e
 		be_addsuffix(be,&monitor);
1c155e
 		be_addsuffix(be,&config);
1c155e
 
1c155e
+        /*
1c155e
+         * Now that the be's are in place, we can
1c155e
+         * setup the mapping tree.
1c155e
+         */
1c155e
+
1c155e
+        if (mapping_tree_init()) {
1c155e
+            slapi_log_err(SLAPI_LOG_EMERG, "setup_internal_backends", "Failed to init mapping tree\n");
1c155e
+            exit(1);
1c155e
+        }
1c155e
+
1c155e
 		add_internal_entries();
1c155e
 
1c155e
 		add_easter_egg_entry();
1c155e
diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c
1c155e
index 552d54d..1d9afce 100644
1c155e
--- a/ldap/servers/slapd/main.c
1c155e
+++ b/ldap/servers/slapd/main.c
1c155e
@@ -1034,16 +1034,6 @@ main( int argc, char **argv)
1c155e
 
1c155e
 		ps_init_psearch_system();   /* must come before plugin_startall() */
1c155e
 
1c155e
-		/* Initailize the mapping tree */
1c155e
-
1c155e
-		if (mapping_tree_init())
1c155e
-		{
1c155e
-			slapi_log_err(SLAPI_LOG_EMERG, "main", "Failed to init mapping tree\n");
1c155e
-			return_value = 1;
1c155e
-			goto cleanup;
1c155e
-		}
1c155e
-
1c155e
-
1c155e
 		/* initialize UniqueID generator - must be done once backends are started
1c155e
 		   and event queue is initialized but before plugins are started */
1c155e
 		/* Note: This DN is no need to be normalized. */
1c155e
diff --git a/ldap/servers/slapd/mapping_tree.c b/ldap/servers/slapd/mapping_tree.c
1c155e
index 1b8d2d9..dfb6584 100644
1c155e
--- a/ldap/servers/slapd/mapping_tree.c
1c155e
+++ b/ldap/servers/slapd/mapping_tree.c
1c155e
@@ -88,13 +88,13 @@ struct mt_node
1c155e
  *      release backend lock 
1c155e
  *
1c155e
  */
1c155e
-static Slapi_RWLock    *myLock;    /* global lock on the mapping tree structures */
1c155e
+static Slapi_RWLock *myLock = NULL; /* global lock on the mapping tree structures */
1c155e
 
1c155e
 
1c155e
 static mapping_tree_node *mapping_tree_root = NULL;
1c155e
-static int mapping_tree_inited = 0;
1c155e
-static int mapping_tree_freed = 0;
1c155e
-static int extension_type = -1;    /* type returned from the factory */
1c155e
+static int32_t mapping_tree_inited = 0;
1c155e
+static int32_t mapping_tree_freed = 0;
1c155e
+static int extension_type = -1; /* type returned from the factory */
1c155e
 
1c155e
 /* The different states a mapping tree node can be in. */
1c155e
 #define    MTN_DISABLED                 0    /* The server acts like the node isn't there. */
1c155e
@@ -1659,22 +1659,24 @@ add_internal_mapping_tree_node(const char *subtree, Slapi_Backend *be, mapping_t
1c155e
 {
1c155e
     Slapi_DN *dn;
1c155e
     mapping_tree_node *node;
1c155e
-    backend ** be_list = (backend **) slapi_ch_malloc(sizeof(backend *));
1c155e
+    backend **be_list = (backend **)slapi_ch_malloc(sizeof(backend *));
1c155e
+    int *be_states = (int *)slapi_ch_malloc(sizeof(int));
1c155e
 
1c155e
     be_list[0] = be;
1c155e
+    be_states[0] = SLAPI_BE_STATE_ON;
1c155e
 
1c155e
     dn = slapi_sdn_new_dn_byval(subtree);
1c155e
-    node= mapping_tree_node_new(
1c155e
-            dn,
1c155e
-            be_list,
1c155e
-            NULL, /* backend_name */
1c155e
-            NULL,
1c155e
-            1,    /* number of backends at this node */
1c155e
-            1,    /* size of backend list structure */
1c155e
-            NULL, /* referral */
1c155e
-            parent,
1c155e
-            MTN_BACKEND,
1c155e
-            1, /* The config  node is a private node.
1c155e
+    node = mapping_tree_node_new(
1c155e
+        dn,
1c155e
+        be_list,
1c155e
+        NULL, /* backend_name */
1c155e
+        be_states, /* be state */
1c155e
+        1,    /* number of backends at this node */
1c155e
+        1,    /* size of backend list structure */
1c155e
+        NULL, /* referral */
1c155e
+        parent,
1c155e
+        MTN_BACKEND,
1c155e
+        1,                    /* The config  node is a private node.
1c155e
                 *  People can't see or change it. */
1c155e
             NULL, NULL, NULL, 0); /* no distribution */
1c155e
     return node;
1c155e
@@ -1722,17 +1724,20 @@ mapping_tree_init()
1c155e
     
1c155e
     /* we call this function from a single thread, so it should be ok */
1c155e
 
1c155e
-    if(mapping_tree_freed){
1c155e
-    /* shutdown has been detected */
1c155e
-      return 0;
1c155e
-    }
1c155e
-
1c155e
-    if (mapping_tree_inited)
1c155e
+    if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
1c155e
+        /* shutdown has been detected */
1c155e
         return 0;
1c155e
+    }
1c155e
 
1c155e
-    /* ONREPL - I have moved this up because otherwise we can endup calling this 
1c155e
+    /* ONREPL - I have moved this up because otherwise we can endup calling this
1c155e
      * function recursively */
1c155e
+    if (myLock != NULL) {
1c155e
+        return 0;
1c155e
+    }
1c155e
+    myLock = slapi_new_rwlock();
1c155e
+    slapi_rwlock_wrlock(myLock);
1c155e
 
1c155e
+    /* Should be fenced by the rwlock. */
1c155e
     mapping_tree_inited = 1;
1c155e
 
1c155e
     slapi_register_supported_control(MTN_CONTROL_USE_ONE_BACKEND_OID,
1c155e
@@ -1740,10 +1745,8 @@ mapping_tree_init()
1c155e
     slapi_register_supported_control(MTN_CONTROL_USE_ONE_BACKEND_EXT_OID,
1c155e
                      SLAPI_OPERATION_SEARCH);
1c155e
 
1c155e
-    myLock = slapi_new_rwlock();
1c155e
-
1c155e
-    be= slapi_be_select_by_instance_name(DSE_BACKEND);
1c155e
-    mapping_tree_root= add_internal_mapping_tree_node("", be, NULL);
1c155e
+    be = slapi_be_select_by_instance_name(DSE_BACKEND);
1c155e
+    mapping_tree_root = add_internal_mapping_tree_node("", be, NULL);
1c155e
 
1c155e
     /* We also need to add the config and schema backends to the mapping tree.
1c155e
      * They are special in that users will not know about it's node in the 
1c155e
@@ -1757,17 +1760,23 @@ mapping_tree_init()
1c155e
     node= add_internal_mapping_tree_node("cn=schema", be, mapping_tree_root);
1c155e
     mapping_tree_node_add_child(mapping_tree_root, node);
1c155e
 
1c155e
-    /* 
1c155e
+    slapi_rwlock_unlock(myLock);
1c155e
+
1c155e
+    /*
1c155e
      * Now we need to look under cn=mapping tree, cn=config to find the rest
1c155e
      * of the mapping tree entries.
1c155e
      * Builds the mapping tree from entries in the DIT.  This function just
1c155e
      * calls mapping_tree_node_get_children with the special case for the
1c155e
      * root node.
1c155e
      */
1c155e
-    if (mapping_tree_node_get_children(mapping_tree_root, 1))
1c155e
+
1c155e
+    if (mapping_tree_node_get_children(mapping_tree_root, 1)) {
1c155e
         return -1;
1c155e
+    }
1c155e
 
1c155e
+    slapi_rwlock_wrlock(myLock);
1c155e
     mtn_create_extension(mapping_tree_root);
1c155e
+    slapi_rwlock_unlock(myLock);
1c155e
 
1c155e
     /* setup the dse callback functions for the ldbm instance config entry */
1c155e
     {
1c155e
@@ -1840,8 +1849,8 @@ mapping_tree_free ()
1c155e
      */ 
1c155e
     slapi_unregister_backend_state_change_all();
1c155e
     /* recursively free tree nodes */
1c155e
-    mtn_free_node (&mapping_tree_root);
1c155e
-    mapping_tree_freed = 1;
1c155e
+    mtn_free_node(&mapping_tree_root);
1c155e
+    __atomic_store_4(&mapping_tree_freed, 1, __ATOMIC_RELAXED);
1c155e
 }
1c155e
 
1c155e
 /* This function returns the first node to parse when a search is done 
1c155e
@@ -2083,14 +2092,12 @@ int slapi_dn_write_needs_referral(Slapi_DN *target_sdn, Slapi_Entry **referral)
1c155e
     mapping_tree_node *target_node = NULL;
1c155e
     int ret = 0;
1c155e
 
1c155e
-    if(mapping_tree_freed){
1c155e
+    if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
1c155e
         /* shutdown detected */
1c155e
         goto done;
1c155e
     }
1c155e
 
1c155e
-    if(!mapping_tree_inited) {
1c155e
-        mapping_tree_init();
1c155e
-    }
1c155e
+    PR_ASSERT(mapping_tree_inited == 1);
1c155e
 
1c155e
     if (target_sdn) {
1c155e
         mtn_lock();
1c155e
@@ -2157,8 +2164,8 @@ int slapi_mapping_tree_select(Slapi_PBlock *pb, Slapi_Backend **be, Slapi_Entry
1c155e
     int fixup = 0;
1c155e
     
1c155e
 
1c155e
-    if(mapping_tree_freed){
1c155e
-        /* shutdown detected */ 
1c155e
+    if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
1c155e
+        /* shutdown detected */
1c155e
         return LDAP_OPERATIONS_ERROR;
1c155e
     }
1c155e
 
1c155e
@@ -2175,9 +2182,7 @@ int slapi_mapping_tree_select(Slapi_PBlock *pb, Slapi_Backend **be, Slapi_Entry
1c155e
     target_sdn = operation_get_target_spec (op);
1c155e
     fixup = operation_is_flag_set(op, OP_FLAG_TOMBSTONE_FIXUP);
1c155e
 
1c155e
-    if(!mapping_tree_inited) {
1c155e
-        mapping_tree_init();
1c155e
-    } 
1c155e
+    PR_ASSERT(mapping_tree_inited == 1);
1c155e
 
1c155e
     be[0] = NULL;
1c155e
     if (referral) {
1c155e
@@ -2188,8 +2193,9 @@ int slapi_mapping_tree_select(Slapi_PBlock *pb, Slapi_Backend **be, Slapi_Entry
1c155e
 
1c155e
     /* Get the mapping tree node that is the best match for the target dn. */
1c155e
     target_node = slapi_get_mapping_tree_node_by_dn(target_sdn);
1c155e
-    if (target_node == NULL)
1c155e
+    if (target_node == NULL) {
1c155e
         target_node = mapping_tree_root;
1c155e
+    }
1c155e
 
1c155e
     /* The processing of the base scope root DSE search and all other LDAP operations on "" 
1c155e
      *  will be transferred to the internal DSE backend 
1c155e
@@ -2266,8 +2272,8 @@ int slapi_mapping_tree_select_all(Slapi_PBlock *pb, Slapi_Backend **be_list,
1c155e
     Slapi_DN *sdn = NULL;
1c155e
     int flag_partial_result = 0;
1c155e
     int op_type;
1c155e
-    
1c155e
-    if(mapping_tree_freed){
1c155e
+
1c155e
+    if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
1c155e
         return LDAP_OPERATIONS_ERROR;
1c155e
     }
1c155e
 
1c155e
@@ -2287,9 +2293,7 @@ int slapi_mapping_tree_select_all(Slapi_PBlock *pb, Slapi_Backend **be_list,
1c155e
     slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &op_type);
1c155e
     slapi_pblock_get(pb, SLAPI_SEARCH_SCOPE, &scope);
1c155e
 
1c155e
-    if(!mapping_tree_inited){
1c155e
-        mapping_tree_init();
1c155e
-    } 
1c155e
+    PR_ASSERT(mapping_tree_inited == 1);
1c155e
 
1c155e
     mtn_lock();
1c155e
 
1c155e
@@ -2448,8 +2452,8 @@ int slapi_mapping_tree_select_and_check(Slapi_PBlock *pb,char *newdn, Slapi_Back
1c155e
     Slapi_Operation *op;
1c155e
     int ret;
1c155e
     int need_unlock = 0;
1c155e
-    
1c155e
-    if(mapping_tree_freed){
1c155e
+
1c155e
+    if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
1c155e
         return LDAP_OPERATIONS_ERROR;
1c155e
      }
1c155e
 
1c155e
@@ -2635,7 +2639,7 @@ static int mtn_get_be(mapping_tree_node *target_node, Slapi_PBlock *pb,
1c155e
     int flag_stop = 0;
1c155e
     struct slapi_componentid *cid = NULL;
1c155e
 
1c155e
-    if(mapping_tree_freed){
1c155e
+    if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
1c155e
         /* shut down detected */
1c155e
         return LDAP_OPERATIONS_ERROR; 
1c155e
     }
1c155e
@@ -2719,21 +2723,22 @@ static int mtn_get_be(mapping_tree_node *target_node, Slapi_PBlock *pb,
1c155e
                     } else {
1c155e
                         /* This MTN has not been linked to its backend
1c155e
                          * instance yet. */
1c155e
-                        target_node->mtn_be[*index] =
1c155e
-                            slapi_be_select_by_instance_name(
1c155e
-                                target_node->mtn_backend_names[*index]);
1c155e
-                        *be = target_node->mtn_be[*index];
1c155e
-                        if(*be==NULL) {
1c155e
-                            slapi_log_err(SLAPI_LOG_BACKLDBM, "mtn_get_be",
1c155e
-                                "Warning: Mapping tree node entry for %s "
1c155e
-                                "point to an unknown backend : %s\n",
1c155e
-                                slapi_sdn_get_dn(target_node->mtn_subtree),
1c155e
-                                target_node->mtn_backend_names[*index]);
1c155e
-                            /* Well there's still not backend instance for
1c155e
-                             * this MTN, so let's have the default backend
1c155e
-                             * deal with this.
1c155e
-                             */
1c155e
-                            *be = defbackend_get_backend();
1c155e
+                        /* WARNING: internal memory dse backends don't provide NAMES */
1c155e
+                        if (target_node->mtn_backend_names != NULL) {
1c155e
+                            target_node->mtn_be[*index] = slapi_be_select_by_instance_name(target_node->mtn_backend_names[*index]);
1c155e
+                            *be = target_node->mtn_be[*index];
1c155e
+                            if (*be == NULL) {
1c155e
+                                slapi_log_err(SLAPI_LOG_BACKLDBM, "mtn_get_be",
1c155e
+                                              "Warning: Mapping tree node entry for %s "
1c155e
+                                              "point to an unknown backend : %s\n",
1c155e
+                                              slapi_sdn_get_dn(target_node->mtn_subtree),
1c155e
+                                              target_node->mtn_backend_names[*index]);
1c155e
+                                /* Well there's still not backend instance for
1c155e
+                                 * this MTN, so let's have the default backend
1c155e
+                                 * deal with this.
1c155e
+                                 */
1c155e
+                                *be = defbackend_get_backend();
1c155e
+                            }
1c155e
                         }
1c155e
                     }
1c155e
                 }
1c155e
@@ -2745,10 +2750,11 @@ static int mtn_get_be(mapping_tree_node *target_node, Slapi_PBlock *pb,
1c155e
             result = LDAP_OPERATIONS_ERROR;
1c155e
                     *be = defbackend_get_backend();
1c155e
                 }
1c155e
-                if (flag_stop)
1c155e
+                if (flag_stop) {
1c155e
                     *index = SLAPI_BE_NO_BACKEND;
1c155e
-                else
1c155e
+                } else {
1c155e
                     (*index)++;
1c155e
+                }
1c155e
             }
1c155e
         }        
1c155e
     } else {
1c155e
@@ -2822,7 +2828,7 @@ static mapping_tree_node *best_matching_child(mapping_tree_node *parent,
1c155e
     mapping_tree_node *highest_match_node = NULL;
1c155e
     mapping_tree_node *current;
1c155e
 
1c155e
-    if(mapping_tree_freed){
1c155e
+    if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
1c155e
         /* shutdown detected */
1c155e
         return NULL;
1c155e
     }
1c155e
@@ -2849,7 +2855,7 @@ mtn_get_mapping_tree_node_by_entry(mapping_tree_node* node, const Slapi_DN *dn)
1c155e
 {
1c155e
     mapping_tree_node *found_node = NULL;
1c155e
 
1c155e
-    if(mapping_tree_freed){
1c155e
+    if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
1c155e
         /* shutdown detected */
1c155e
         return NULL;
1c155e
     }
1c155e
@@ -2895,7 +2901,7 @@ slapi_get_mapping_tree_node_by_dn(const Slapi_DN *dn)
1c155e
     mapping_tree_node *current_best_match = mapping_tree_root;
1c155e
     mapping_tree_node *next_best_match = mapping_tree_root;
1c155e
 
1c155e
-    if(mapping_tree_freed){
1c155e
+    if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
1c155e
         /* shutdown detected */
1c155e
         return NULL;
1c155e
     }
1c155e
@@ -2929,7 +2935,7 @@ get_mapping_tree_node_by_name(mapping_tree_node * node, char * be_name)
1c155e
     int i;
1c155e
     mapping_tree_node *found_node = NULL;
1c155e
 
1c155e
-    if(mapping_tree_freed){
1c155e
+    if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
1c155e
         /* shutdown detected */
1c155e
         return NULL;
1c155e
     }
1c155e
@@ -2980,7 +2986,7 @@ slapi_get_mapping_tree_node_configdn (const Slapi_DN *root)
1c155e
 {
1c155e
     char *dn = NULL;
1c155e
 
1c155e
-    if(mapping_tree_freed){
1c155e
+    if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
1c155e
         /* shutdown detected */
1c155e
         return NULL;
1c155e
     }
1c155e
@@ -3007,7 +3013,7 @@ slapi_get_mapping_tree_node_configsdn (const Slapi_DN *root)
1c155e
     char *dn = NULL;
1c155e
     Slapi_DN *sdn = NULL;
1c155e
 
1c155e
-    if(mapping_tree_freed){
1c155e
+    if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
1c155e
         /* shutdown detected */
1c155e
         return NULL;
1c155e
     }
1c155e
diff --git a/ldap/servers/slapd/pw_verify.c b/ldap/servers/slapd/pw_verify.c
1c155e
index cb182ed..1f0c18a 100644
1c155e
--- a/ldap/servers/slapd/pw_verify.c
1c155e
+++ b/ldap/servers/slapd/pw_verify.c
1c155e
@@ -58,12 +58,14 @@ pw_verify_be_dn(Slapi_PBlock *pb, Slapi_Entry **referral)
1c155e
     int rc = SLAPI_BIND_SUCCESS;
1c155e
     Slapi_Backend *be = NULL;
1c155e
 
1c155e
-    if (slapi_mapping_tree_select(pb, &be, referral, NULL, 0) != LDAP_SUCCESS) {
1c155e
+    int mt_result = slapi_mapping_tree_select(pb, &be, referral, NULL, 0);
1c155e
+    if (mt_result != LDAP_SUCCESS) {
1c155e
         return SLAPI_BIND_NO_BACKEND;
1c155e
     }
1c155e
 
1c155e
     if (*referral) {
1c155e
-        slapi_be_Unlock(be);
1c155e
+        /* If we have a referral, this is NULL */
1c155e
+        PR_ASSERT(be == NULL);
1c155e
         return SLAPI_BIND_REFERRAL;
1c155e
     }
1c155e
 
1c155e
@@ -128,7 +130,7 @@ pw_validate_be_dn(Slapi_PBlock *pb, Slapi_Entry **referral)
1c155e
     }
1c155e
 
1c155e
     if (*referral) {
1c155e
-        slapi_be_Unlock(be);
1c155e
+        PR_ASSERT(be == NULL);
1c155e
         return SLAPI_BIND_REFERRAL;
1c155e
     }
1c155e
 
1c155e
-- 
1c155e
2.9.4
1c155e