From 14e5422328d8f116916efb4a9e192b8db4686e44 Mon Sep 17 00:00:00 2001 From: Mark Reynolds Date: Dec 30 2014 18:44:01 +0000 Subject: Ticket 47451 - Dynamic plugins - fixed thread synchronization Description: Made various fixes and overall improvements to the dynamic plugin feature,and Tthe CI test suite. dirsrvtests/suites/dynamic-plugins/plugin_tests.py dirsrvtests/suites/dynamic-plugins/stress_tests.py dirsrvtests/suites/dynamic-plugins/test_dynamic_plugins.py - Improved/intensified stress test - Improved task monitoring - Added a replication run to the entire test suite - Added tests for "shared config areas": MO & RI plugins ldap/servers/plugins/acctpolicy/acct_config.c ldap/servers/plugins/acctpolicy/acct_init.c ldap/servers/plugins/acctpolicy/acct_plugin.c ldap/servers/plugins/acctpolicy/acct_util.c ldap/servers/plugins/acctpolicy/acctpolicy.h - Added the necessary postop calls to check for config updates ldap/servers/plugins/linkedattrs/fixup_task.c - Fixed logging issue ldap/servers/plugins/memberof/memberof_config.c - Fixed double free/crash ldap/servers/slapd/dse.c - The ADD entry was incorrectly being set to NULL(memory leak) ldap/servers/slapd/plugin.c - Improved thread sychronization/fixed race condition - Fixed memory leak when deleting plugin for the plugin config area ldap/servers/slapd/slapi-plugin.h ldap/servers/slapd/thread_data.c - Revised plugin lock thread data wrappers https://fedorahosted.org/389/ticket/47451 Jenkins: Passed Valgrind: Passed Reviewed by: nhosoi(Thanks!) --- diff --git a/dirsrvtests/suites/dynamic-plugins/plugin_tests.py b/dirsrvtests/suites/dynamic-plugins/plugin_tests.py index fa88145..e147be5 100644 --- a/dirsrvtests/suites/dynamic-plugins/plugin_tests.py +++ b/dirsrvtests/suites/dynamic-plugins/plugin_tests.py @@ -31,6 +31,7 @@ BRANCH2_DN = 'ou=branch2,' + DEFAULT_SUFFIX GROUP_OU = 'ou=groups,' + DEFAULT_SUFFIX PEOPLE_OU = 'ou=people,' + DEFAULT_SUFFIX GROUP_DN = 'cn=group,' + DEFAULT_SUFFIX +CONFIG_AREA = 'nsslapd-pluginConfigArea' ''' Functional tests for each plugin @@ -85,6 +86,35 @@ def test_dependency(inst, plugin): ################################################################################ # +# Wait for task to complete +# +################################################################################ +def wait_for_task(conn, task_dn): + finished = False + count = 0 + while count < 60: + try: + task_entry = conn.search_s(task_dn, ldap.SCOPE_BASE, 'objectclass=*') + if not task_entry: + log.fatal('wait_for_task: Search failed to find task: ' + task_dn) + assert False + if task_entry[0].hasAttr('nstaskexitcode'): + # task is done + finished = True + break + except ldap.LDAPError, e: + log.fatal('wait_for_task: Search failed: ' + e.message['desc']) + assert False + + time.sleep(1) + count += 1 + if not finished: + log.error('wait_for_task: Task (%s) did not complete!' % task_dn) + assert False + + +################################################################################ +# # Test Account Policy Plugin (0) # ################################################################################ @@ -97,6 +127,7 @@ def test_acctpolicy(inst, args=None): return True CONFIG_DN = 'cn=config,cn=Account Policy Plugin,cn=plugins,cn=config' + log.info('Testing ' + PLUGIN_ACCT_POLICY + '...') ############################################################################ @@ -123,23 +154,12 @@ def test_acctpolicy(inst, args=None): log.error('test_acctpolicy: Failed to add config entry: error ' + e.message['desc']) assert False - # Now set the config entry in the plugin entry - #try: - # inst.modify_s('cn=' + PLUGIN_ACCT_POLICY + ',cn=plugins,cn=config', - # [(ldap.MOD_REPLACE, 'nsslapd-pluginarg0', CONFIG_DN)]) - #except ldap.LDAPError, e: - # log.error('test_acctpolicy: Failed to set config entry in plugin entry: error ' + e.message['desc']) - # assert False - ############################################################################ # Test plugin ############################################################################ - # !!!! acctpolicy does have have a dse callabck to check for live updates - restart plugin for now !!!! - inst.plugins.disable(name=PLUGIN_ACCT_POLICY) - inst.plugins.enable(name=PLUGIN_ACCT_POLICY) - # Add an entry + time.sleep(1) try: inst.add_s(Entry((USER1_DN, {'objectclass': "top extensibleObject".split(), 'sn': '1', @@ -154,10 +174,11 @@ def test_acctpolicy(inst, args=None): try: inst.simple_bind_s(USER1_DN, "password") except ldap.LDAPError, e: - log.error('test_acctpolicy:Failed to bind as user1: ' + e.message['desc']) + log.error('test_acctpolicy: Failed to bind as user1: ' + e.message['desc']) assert False # Bind as Root DN + time.sleep(1) try: inst.simple_bind_s(DN_DM, PASSWORD) except ldap.LDAPError, e: @@ -185,14 +206,11 @@ def test_acctpolicy(inst, args=None): log.error('test_acctpolicy: Failed to modify config entry: error ' + e.message['desc']) assert False - # !!!! must restart for now !!!!! - inst.plugins.disable(name=PLUGIN_ACCT_POLICY) - inst.plugins.enable(name=PLUGIN_ACCT_POLICY) - ############################################################################ # Test plugin ############################################################################ + time.sleep(1) # login as user try: inst.simple_bind_s(USER1_DN, "password") @@ -200,6 +218,7 @@ def test_acctpolicy(inst, args=None): log.error('test_acctpolicy: Failed to bind(2nd) as user1: ' + e.message['desc']) assert False + time.sleep(1) # Bind as Root DN try: inst.simple_bind_s(DN_DM, PASSWORD) @@ -498,7 +517,7 @@ def test_automember(inst, args=None): log.error('test_automember: Failed to user3 to branch2: error ' + e.message['desc']) assert False - # Check the group - uniquemember sahould not exist + # Check the group - uniquemember should not exist try: entries = inst.search_s(GROUP_DN, ldap.SCOPE_BASE, '(uniquemember=' + BUSER3_DN + ')') @@ -512,9 +531,10 @@ def test_automember(inst, args=None): # Enable plugin inst.plugins.enable(name=PLUGIN_AUTOMEMBER) + TASK_DN = 'cn=task-' + str(int(time.time())) + ',cn=automember rebuild membership,cn=tasks,cn=config' # Add the task try: - inst.add_s(Entry(('cn=task-' + str(int(time.time())) + ',cn=automember rebuild membership,cn=tasks,cn=config', { + inst.add_s(Entry((TASK_DN, { 'objectclass': 'top extensibleObject'.split(), 'basedn': 'ou=branch2,' + DEFAULT_SUFFIX, 'filter': 'objectclass=top'}))) @@ -522,7 +542,7 @@ def test_automember(inst, args=None): log.error('test_automember: Failed to add task: error ' + e.message['desc']) assert False - time.sleep(3) # Wait for the task to do its work + wait_for_task(inst, TASK_DN) # Verify the fixup task worked try: @@ -722,7 +742,7 @@ def test_dna(inst, args=None): try: inst.delete_s(USER1_DN) except ldap.LDAPError, e: - log.error('test_automember: Failed to delete test entry1: ' + e.message['desc']) + log.error('test_dna: Failed to delete test entry1: ' + e.message['desc']) assert False inst.plugins.disable(name=PLUGIN_DNA) @@ -914,32 +934,11 @@ def test_linkedattrs(inst, args=None): log.fatal('test_linkedattrs: Search for user1 failed: ' + e.message['desc']) assert False - # Verify that the task does not work yet(not until we enable the plugin) - try: - inst.add_s(Entry(('cn=task-' + str(int(time.time())) + ',cn=fixup linked attributes,cn=tasks,cn=config', { - 'objectclass': 'top extensibleObject'.split(), - 'basedn': DEFAULT_SUFFIX, - 'filter': '(objectclass=top)'}))) - except ldap.LDAPError, e: - log.error('test_linkedattrs: Failed to add task: error ' + e.message['desc']) - assert False - - time.sleep(3) # Wait for the task to do, or not do, its work - - # The entry should still not have a manager attribute - try: - entries = inst.search_s(USER2_DN, ldap.SCOPE_BASE, '(manager=*)') - if entries: - log.fatal('test_linkedattrs: user2 incorrectly has a "manager" attr') - assert False - except ldap.LDAPError, e: - log.fatal('test_linkedattrs: Search for user2 failed: ' + e.message['desc']) - assert False - # Enable the plugin and rerun the task entry inst.plugins.enable(name=PLUGIN_LINKED_ATTRS) # Add the task again + TASK_DN = 'cn=task-' + str(int(time.time())) + ',cn=fixup linked attributes,cn=tasks,cn=config' try: inst.add_s(Entry(('cn=task-' + str(int(time.time())) + ',cn=fixup linked attributes,cn=tasks,cn=config', { 'objectclass': 'top extensibleObject'.split(), @@ -949,7 +948,7 @@ def test_linkedattrs(inst, args=None): log.error('test_linkedattrs: Failed to add task: error ' + e.message['desc']) assert False - time.sleep(3) # Wait for the task to do its work + wait_for_task(inst, TASK_DN) # Check if user2 now has a manager attribute now try: @@ -1011,6 +1010,7 @@ def test_memberof(inst, args=None): return PLUGIN_DN = 'cn=' + PLUGIN_MEMBER_OF + ',cn=plugins,cn=config' + SHARED_CONFIG_DN = 'cn=memberOf Config,' + DEFAULT_SUFFIX log.info('Testing ' + PLUGIN_MEMBER_OF + '...') @@ -1048,6 +1048,16 @@ def test_memberof(inst, args=None): log.error('test_memberof: Failed to add group: error ' + e.message['desc']) assert False + try: + inst.add_s(Entry((SHARED_CONFIG_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'memberofgroupattr': 'member', + 'memberofattr': 'memberof' + }))) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to shared config entry: error ' + e.message['desc']) + assert False + # Check if the user now has a "memberOf" attribute try: entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') @@ -1069,7 +1079,7 @@ def test_memberof(inst, args=None): try: entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') if entries: - log.fatal('test_memberof: user1 incorrect has memberOf attr') + log.fatal('test_memberof: user1 incorrectly has memberOf attr') assert False except ldap.LDAPError, e: log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) @@ -1116,51 +1126,169 @@ def test_memberof(inst, args=None): try: entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') if entries: - log.fatal('test_memberof: user1 incorrect has memberOf attr') + log.fatal('test_memberof: user1 incorrectly has memberOf attr') assert False except ldap.LDAPError, e: log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) assert False ############################################################################ - # Test Fixup Task + # Set the shared config entry and test the plugin ############################################################################ - inst.plugins.disable(name=PLUGIN_MEMBER_OF) + # The shared config entry uses "member" - the above test uses "uniquemember" + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_REPLACE, CONFIG_AREA, SHARED_CONFIG_DN)]) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to set plugin area: error ' + e.message['desc']) + assert False + + # Delete the test entries then readd them to start with a clean slate + try: + inst.delete_s(USER1_DN) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to delete test entry1: ' + e.message['desc']) + assert False + + try: + inst.delete_s(GROUP_DN) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to delete test group: ' + e.message['desc']) + assert False + + try: + inst.add_s(Entry((USER1_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'user1' + }))) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to add user1: error ' + e.message['desc']) + assert False + + try: + inst.add_s(Entry((GROUP_DN, { + 'objectclass': 'top groupOfNames groupOfUniqueNames extensibleObject'.split(), + 'cn': 'group', + 'member': USER1_DN + }))) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to add group: error ' + e.message['desc']) + assert False + + # Test the shared config + # Check if the user now has a "memberOf" attribute + try: + entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') + if not entries: + log.fatal('test_memberof: user1 missing memberOf') + assert False + except ldap.LDAPError, e: + log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) + assert False + + # Remove "member" should remove "memberOf" from the entry + try: + inst.modify_s(GROUP_DN, [(ldap.MOD_DELETE, 'member', None)]) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to delete member: error ' + e.message['desc']) + assert False + + # Check that "memberOf" was removed + try: + entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') + if entries: + log.fatal('test_memberof: user1 incorrectly has memberOf attr') + assert False + except ldap.LDAPError, e: + log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) + assert False + + ############################################################################ + # Change the shared config entry to use 'uniquemember' and test the plugin + ############################################################################ + + try: + inst.modify_s(SHARED_CONFIG_DN, [(ldap.MOD_REPLACE, 'memberofgroupattr', 'uniquemember')]) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to set shared plugin entry(uniquemember): error ' + + e.message['desc']) + assert False - # Add uniquemember, should not update USER1 try: inst.modify_s(GROUP_DN, [(ldap.MOD_REPLACE, 'uniquemember', USER1_DN)]) except ldap.LDAPError, e: log.error('test_memberof: Failed to add uniquemember: error ' + e.message['desc']) assert False - # Check for "memberOf" + # Check if the user now has a "memberOf" attribute + try: + entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') + if not entries: + log.fatal('test_memberof: user1 missing memberOf') + assert False + except ldap.LDAPError, e: + log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) + assert False + + # Remove "uniquemember" should remove "memberOf" from the entry + try: + inst.modify_s(GROUP_DN, [(ldap.MOD_DELETE, 'uniquemember', None)]) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to delete member: error ' + e.message['desc']) + assert False + + # Check that "memberOf" was removed try: entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') if entries: - log.fatal('test_memberof: user1 incorrect has memberOf attr') + log.fatal('test_memberof: user1 incorrectly has memberOf attr') assert False except ldap.LDAPError, e: log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) assert False - # Run fixup task while plugin disabled - should not add "memberOf - # Verify that the task does not work yet(not until we enable the plugin) + ############################################################################ + # Remove shared config from plugin, and retest + ############################################################################ + + # First change the plugin to use member before we move the shared config that uses uniquemember try: - inst.add_s(Entry(('cn=task-' + str(int(time.time())) + ',' + DN_MBO_TASK, { - 'objectclass': 'top extensibleObject'.split(), - 'basedn': DEFAULT_SUFFIX, - 'filter': 'objectclass=top'}))) - except ldap.NO_SUCH_OBJECT: - pass + inst.modify_s(PLUGIN_DN, [(ldap.MOD_REPLACE, 'memberofgroupattr', 'member')]) except ldap.LDAPError, e: - log.error('test_memberof: Failed to add task: error ' + e.message['desc']) + log.error('test_memberof: Failed to update config(uniquemember): error ' + e.message['desc']) assert False - time.sleep(3) # Wait for the task to do, or not do, its work + # Remove shared config from plugin + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_DELETE, CONFIG_AREA, None)]) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to add uniquemember: error ' + e.message['desc']) + assert False - # Check for "memberOf" + try: + inst.modify_s(GROUP_DN, [(ldap.MOD_REPLACE, 'member', USER1_DN)]) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to add uniquemember: error ' + e.message['desc']) + assert False + + # Check if the user now has a "memberOf" attribute + try: + entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') + if not entries: + log.fatal('test_memberof: user1 missing memberOf') + assert False + except ldap.LDAPError, e: + log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) + assert False + + # Remove "uniquemember" should remove "memberOf" from the entry + try: + inst.modify_s(GROUP_DN, [(ldap.MOD_DELETE, 'member', None)]) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to delete member: error ' + e.message['desc']) + assert False + + # Check that "memberOf" was removed try: entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') if entries: @@ -1170,11 +1298,42 @@ def test_memberof(inst, args=None): log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) assert False + ############################################################################ + # Test Fixup Task + ############################################################################ + + inst.plugins.disable(name=PLUGIN_MEMBER_OF) + + # First change the plugin to use uniquemember + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_REPLACE, 'memberofgroupattr', 'uniquemember')]) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to update config(uniquemember): error ' + e.message['desc']) + assert False + + # Add uniquemember, should not update USER1 + try: + inst.modify_s(GROUP_DN, [(ldap.MOD_REPLACE, 'uniquemember', USER1_DN)]) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to add uniquemember: error ' + e.message['desc']) + assert False + + # Check for "memberOf" + try: + entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') + if entries: + log.fatal('test_memberof: user1 incorrect has memberOf attr') + assert False + except ldap.LDAPError, e: + log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) + assert False + # Enable the plugin, and run the task inst.plugins.enable(name=PLUGIN_MEMBER_OF) + TASK_DN = 'cn=task-' + str(int(time.time())) + ',' + DN_MBO_TASK try: - inst.add_s(Entry(('cn=task-' + str(int(time.time())) + ',' + DN_MBO_TASK, { + inst.add_s(Entry((TASK_DN, { 'objectclass': 'top extensibleObject'.split(), 'basedn': DEFAULT_SUFFIX, 'filter': 'objectclass=top'}))) @@ -1182,7 +1341,7 @@ def test_memberof(inst, args=None): log.error('test_memberof: Failed to add task: error ' + e.message['desc']) assert False - time.sleep(3) # Wait for the task to do its work + wait_for_task(inst, TASK_DN) # Check for "memberOf" try: @@ -1216,6 +1375,12 @@ def test_memberof(inst, args=None): log.error('test_memberof: Failed to delete test group: ' + e.message['desc']) assert False + try: + inst.delete_s(SHARED_CONFIG_DN) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to delete shared config entry: ' + e.message['desc']) + assert False + ############################################################################ # Test passed ############################################################################ @@ -1286,9 +1451,6 @@ def test_mep(inst, args=None): log.error('test_mep: Failed to add template entry: error ' + e.message['desc']) assert False - # log.info('geb.....') - # time.sleep(30) - # Add the config entry try: inst.add_s(Entry((CONFIG_DN, { @@ -1456,19 +1618,10 @@ def test_passthru(inst, args=None): # Create second instance passthru_inst = DirSrv(verbose=False) - #if installation1_prefix: - # args_instance[SER_DEPLOYED_DIR] = installation1_prefix - - # Args for the master1 instance - """ - args_instance[SER_HOST] = '127.0.0.1' - args_instance[SER_PORT] = '33333' - args_instance[SER_SERVERID_PROP] = 'passthru' - """ - args_instance[SER_HOST] = 'localhost.localdomain' + # Args for the instance + args_instance[SER_HOST] = LOCALHOST args_instance[SER_PORT] = 33333 args_instance[SER_SERVERID_PROP] = 'passthru' - args_instance[SER_CREATION_SUFFIX] = PASS_SUFFIX1 args_passthru_inst = args_instance.copy() passthru_inst.allocate(args_passthru_inst) @@ -1615,6 +1768,7 @@ def test_referint(inst, args=None): log.info('Testing ' + PLUGIN_REFER_INTEGRITY + '...') PLUGIN_DN = 'cn=' + PLUGIN_REFER_INTEGRITY + ',cn=plugins,cn=config' + SHARED_CONFIG_DN = 'cn=RI Config,' + DEFAULT_SUFFIX ############################################################################ # Configure plugin @@ -1660,6 +1814,28 @@ def test_referint(inst, args=None): log.error('test_referint: Failed to add group: error ' + e.message['desc']) assert False + # Grab the referint log file from the plugin + + try: + entries = inst.search_s(PLUGIN_DN, ldap.SCOPE_BASE, '(objectclass=top)') + REFERINT_LOGFILE = entries[0].getValue('referint-logfile') + except ldap.LDAPError, e: + log.fatal('test_referint: Unable to search plugin entry: ' + e.message['desc']) + assert False + + # Add shared config entry + try: + inst.add_s(Entry((SHARED_CONFIG_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'referint-membership-attr': 'member', + 'referint-update-delay': '0', + 'referint-logfile': REFERINT_LOGFILE, + 'referint-logchanges': '0' + }))) + except ldap.LDAPError, e: + log.error('test_referint: Failed to shared config entry: error ' + e.message['desc']) + assert False + # Delete a user try: inst.delete_s(USER1_DN) @@ -1709,6 +1885,150 @@ def test_referint(inst, args=None): assert False ############################################################################ + # Set the shared config entry and test the plugin + ############################################################################ + + # The shared config entry uses "member" - the above test used "uniquemember" + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_REPLACE, CONFIG_AREA, SHARED_CONFIG_DN)]) + except ldap.LDAPError, e: + log.error('test_referint: Failed to set plugin area: error ' + e.message['desc']) + assert False + + # Delete the group, and readd everything + try: + inst.delete_s(GROUP_DN) + except ldap.LDAPError, e: + log.error('test_referint: Failed to delete group: ' + e.message['desc']) + assert False + + try: + inst.add_s(Entry((USER1_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'user1' + }))) + except ldap.LDAPError, e: + log.error('test_referint: Failed to add user1: error ' + e.message['desc']) + assert False + + try: + inst.add_s(Entry((USER2_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'user2' + }))) + except ldap.LDAPError, e: + log.error('test_referint: Failed to add user2: error ' + e.message['desc']) + assert False + + try: + inst.add_s(Entry((GROUP_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'cn': 'group', + 'member': USER1_DN, + 'uniquemember': USER2_DN + }))) + except ldap.LDAPError, e: + log.error('test_referint: Failed to add group: error ' + e.message['desc']) + assert False + + # Delete a user + try: + inst.delete_s(USER1_DN) + except ldap.LDAPError, e: + log.error('test_referint: Failed to delete user1: ' + e.message['desc']) + assert False + + # Check for integrity + try: + entry = inst.search_s(GROUP_DN, ldap.SCOPE_BASE, '(member=' + USER1_DN + ')') + if entry: + log.error('test_referint: user1 was not removed from group') + assert False + except ldap.LDAPError, e: + log.fatal('test_referint: Unable to search group: ' + e.message['desc']) + assert False + + ############################################################################ + # Change the shared config entry to use 'uniquemember' and test the plugin + ############################################################################ + + try: + inst.modify_s(SHARED_CONFIG_DN, [(ldap.MOD_REPLACE, 'referint-membership-attr', 'uniquemember')]) + except ldap.LDAPError, e: + log.error('test_referint: Failed to set shared plugin entry(uniquemember): error ' + + e.message['desc']) + assert False + + # Delete a user + try: + inst.delete_s(USER2_DN) + except ldap.LDAPError, e: + log.error('test_referint: Failed to delete user1: ' + e.message['desc']) + assert False + + # Check for integrity + try: + entry = inst.search_s(GROUP_DN, ldap.SCOPE_BASE, '(uniquemember=' + USER2_DN + ')') + if entry: + log.error('test_referint: user2 was not removed from group') + assert False + except ldap.LDAPError, e: + log.fatal('test_referint: Unable to search group: ' + e.message['desc']) + assert False + + ############################################################################ + # Remove shared config from plugin, and retest + ############################################################################ + + # First change the plugin to use member before we move the shared config that uses uniquemember + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_REPLACE, 'referint-membership-attr', 'member')]) + except ldap.LDAPError, e: + log.error('test_referint: Failed to update config(uniquemember): error ' + e.message['desc']) + assert False + + # Remove shared config from plugin + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_DELETE, CONFIG_AREA, None)]) + except ldap.LDAPError, e: + log.error('test_referint: Failed to add uniquemember: error ' + e.message['desc']) + assert False + + # Add test user + try: + inst.add_s(Entry((USER1_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'user1' + }))) + except ldap.LDAPError, e: + log.error('test_referint: Failed to add user1: error ' + e.message['desc']) + assert False + + # Add user to group + try: + inst.modify_s(GROUP_DN, [(ldap.MOD_REPLACE, 'member', USER1_DN)]) + except ldap.LDAPError, e: + log.error('test_referint: Failed to add uniquemember: error ' + e.message['desc']) + assert False + + # Delete a user + try: + inst.delete_s(USER1_DN) + except ldap.LDAPError, e: + log.error('test_referint: Failed to delete user1: ' + e.message['desc']) + assert False + + # Check for integrity + try: + entry = inst.search_s(GROUP_DN, ldap.SCOPE_BASE, '(member=' + USER1_DN + ')') + if entry: + log.error('test_referint: user1 was not removed from group') + assert False + except ldap.LDAPError, e: + log.fatal('test_referint: Unable to search group: ' + e.message['desc']) + assert False + + ############################################################################ # Test plugin dependency ############################################################################ @@ -1721,7 +2041,13 @@ def test_referint(inst, args=None): try: inst.delete_s(GROUP_DN) except ldap.LDAPError, e: - log.error('test_referint: Failed to delete user1: ' + e.message['desc']) + log.error('test_referint: Failed to delete group: ' + e.message['desc']) + assert False + + try: + inst.delete_s(SHARED_CONFIG_DN) + except ldap.LDAPError, e: + log.error('test_referint: Failed to delete shared config entry: ' + e.message['desc']) assert False ############################################################################ @@ -1863,7 +2189,7 @@ def test_rootdn(inst, args=None): 'userpassword': 'password' }))) except ldap.LDAPError, e: - log.error('test_retrocl: Failed to add user1: error ' + e.message['desc']) + log.error('test_rootdn: Failed to add user1: error ' + e.message['desc']) assert False # Set an aci so we can modify the plugin after ew deny the root dn diff --git a/dirsrvtests/suites/dynamic-plugins/stress_tests.py b/dirsrvtests/suites/dynamic-plugins/stress_tests.py index a1f666d..f1a34b4 100644 --- a/dirsrvtests/suites/dynamic-plugins/stress_tests.py +++ b/dirsrvtests/suites/dynamic-plugins/stress_tests.py @@ -21,6 +21,7 @@ from constants import * log = logging.getLogger(__name__) NUM_USERS = 250 +GROUP_DN = 'cn=stress-group,' + DEFAULT_SUFFIX def openConnection(inst): @@ -58,6 +59,14 @@ def configureMO(inst): assert False +def cleanup(conn): + try: + conn.delete_s(GROUP_DN) + except ldap.LDAPError, e: + log.error('cleanup: failed to delete group (' + GROUP_DN + ') error: ' + e.message['desc']) + assert False + + class DelUsers(threading.Thread): def __init__(self, inst, rdnval): threading.Thread.__init__(self) @@ -97,7 +106,6 @@ class AddUsers(threading.Thread): idx = 0 if self.addToGroup: - GROUP_DN = 'cn=stress-group,' + DEFAULT_SUFFIX try: conn.add_s(Entry((GROUP_DN, {'objectclass': 'top groupOfNames groupOfUniqueNames extensibleObject'.split(), diff --git a/dirsrvtests/suites/dynamic-plugins/test_dynamic_plugins.py b/dirsrvtests/suites/dynamic-plugins/test_dynamic_plugins.py index 3677fd5..288505b 100644 --- a/dirsrvtests/suites/dynamic-plugins/test_dynamic_plugins.py +++ b/dirsrvtests/suites/dynamic-plugins/test_dynamic_plugins.py @@ -31,6 +31,12 @@ class TopologyStandalone(object): self.standalone = standalone +def repl_fail(replica): + # remove replica instance, and assert failure + replica.delete() + assert False + + @pytest.fixture(scope="module") def topology(request): ''' @@ -128,7 +134,10 @@ def test_dynamic_plugins(topology): Test Dynamic Plugins - exercise each plugin and its main features, while changing the configuration without restarting the server. - Need to test: functionality, stability, and stress. + Need to test: functionality, stability, and stress. These tests need to run + with replication disabled, and with replication setup with a + second instance. Then test if replication is working, and we have + same entries on each side. Functionality - Make sure that as configuration changes are made they take effect immediately. Cross plugin interaction (e.g. automember/memberOf) @@ -137,17 +146,21 @@ def test_dynamic_plugins(topology): Memory Corruption - Restart the plugins many times, and in different orders and test functionality, and stability. This will excerise the internal - plugin linked lists, dse callabcks, and task handlers. + plugin linked lists, dse callbacks, and task handlers. - Stress - Put the server under some type of load that is using a particular - plugin for each operation, and then make changes to that plugin. - The new changes should take effect, and the server should not crash. + Stress - Put the server under load that will trigger multiple plugins(MO, RI, DNA, etc) + Restart various plugins while these operations are going on. Perform this test + 5 times(stress_max_run). """ - ############################################################################ - # Test plugin functionality - ############################################################################ + REPLICA_PORT = 33334 + RUV_FILTER = '(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))' + master_maxcsn = 0 + replica_maxcsn = 0 + msg = ' (no replication)' + replication_run = False + stress_max_runs = 5 # First enable dynamic plugins try: @@ -156,132 +169,337 @@ def test_dynamic_plugins(topology): ldap.error('Failed to enable dynamic plugin!' + e.message['desc']) assert False - log.info('#####################################################') - log.info('Testing Dynamic Plugins Functionality...') - log.info('#####################################################\n') - - plugin_tests.test_all_plugins(topology.standalone) - - log.info('#####################################################') - log.info('Successfully Tested Dynamic Plugins Functionality.') - log.info('#####################################################\n') - - ############################################################################ - # Test the stability by exercising the internal lists, callabcks, and task handlers - ############################################################################ - - log.info('#####################################################') - log.info('Testing Dynamic Plugins for Memory Corruption...') - log.info('#####################################################\n') - prev_plugin_test = None - prev_prev_plugin_test = None - for plugin_test in plugin_tests.func_tests: + while 1: # - # Restart the plugin several times (and prev plugins) - work that linked list + # First run the tests with replication disabled, then rerun them with replication set up # - plugin_test(topology.standalone, "restart") - if prev_prev_plugin_test: - prev_prev_plugin_test(topology.standalone, "restart") + ############################################################################ + # Test plugin functionality + ############################################################################ + + log.info('####################################################################') + log.info('Testing Dynamic Plugins Functionality' + msg + '...') + log.info('####################################################################\n') + + plugin_tests.test_all_plugins(topology.standalone) + + log.info('####################################################################') + log.info('Successfully Tested Dynamic Plugins Functionality' + msg + '.') + log.info('####################################################################\n') + + ############################################################################ + # Test the stability by exercising the internal lists, callabcks, and task handlers + ############################################################################ + + log.info('####################################################################') + log.info('Testing Dynamic Plugins for Memory Corruption' + msg + '...') + log.info('####################################################################\n') + prev_plugin_test = None + prev_prev_plugin_test = None + + for plugin_test in plugin_tests.func_tests: + # + # Restart the plugin several times (and prev plugins) - work that linked list + # + plugin_test(topology.standalone, "restart") + + if prev_prev_plugin_test: + prev_prev_plugin_test(topology.standalone, "restart") + + plugin_test(topology.standalone, "restart") + + if prev_plugin_test: + prev_plugin_test(topology.standalone, "restart") + + plugin_test(topology.standalone, "restart") + + # Now run the functional test + plugin_test(topology.standalone) + + # Set the previous tests + if prev_plugin_test: + prev_prev_plugin_test = prev_plugin_test + prev_plugin_test = plugin_test + + log.info('####################################################################') + log.info('Successfully Tested Dynamic Plugins for Memory Corruption' + msg + '.') + log.info('####################################################################\n') + + ############################################################################ + # Stress two plugins while restarting it, and while restarting other plugins. + # The goal is to not crash, and have the plugins work after stressing them. + ############################################################################ + + log.info('####################################################################') + log.info('Stressing Dynamic Plugins' + msg + '...') + log.info('####################################################################\n') + + stress_tests.configureMO(topology.standalone) + stress_tests.configureRI(topology.standalone) + + stress_count = 0 + while stress_count < stress_max_runs: + log.info('####################################################################') + log.info('Running stress test' + msg + '. Run (%d/%d)...' % (stress_count + 1, stress_max_runs)) + log.info('####################################################################\n') + + try: + # Launch three new threads to add a bunch of users + add_users = stress_tests.AddUsers(topology.standalone, 'employee', True) + add_users.start() + add_users2 = stress_tests.AddUsers(topology.standalone, 'entry', True) + add_users2.start() + add_users3 = stress_tests.AddUsers(topology.standalone, 'person', True) + add_users3.start() + time.sleep(1) + + # While we are adding users restart the MO plugin and an idle plugin + topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) + topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) + time.sleep(1) + topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) + time.sleep(1) + topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) + topology.standalone.plugins.disable(name=PLUGIN_LINKED_ATTRS) + topology.standalone.plugins.enable(name=PLUGIN_LINKED_ATTRS) + time.sleep(1) + topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) + topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) + time.sleep(2) + topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) + time.sleep(1) + topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) + topology.standalone.plugins.disable(name=PLUGIN_LINKED_ATTRS) + topology.standalone.plugins.enable(name=PLUGIN_LINKED_ATTRS) + topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) + time.sleep(1) + topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) + topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) + topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) + + # Wait for the 'adding' threads to complete + add_users.join() + add_users2.join() + add_users3.join() + + # Now launch three threads to delete the users + del_users = stress_tests.DelUsers(topology.standalone, 'employee') + del_users.start() + del_users2 = stress_tests.DelUsers(topology.standalone, 'entry') + del_users2.start() + del_users3 = stress_tests.DelUsers(topology.standalone, 'person') + del_users3.start() + time.sleep(1) + + # Restart both the MO, RI plugins during these deletes, and an idle plugin + topology.standalone.plugins.disable(name=PLUGIN_REFER_INTEGRITY) + topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) + topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) + topology.standalone.plugins.enable(name=PLUGIN_REFER_INTEGRITY) + time.sleep(1) + topology.standalone.plugins.disable(name=PLUGIN_REFER_INTEGRITY) + time.sleep(1) + topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) + time.sleep(1) + topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) + time.sleep(1) + topology.standalone.plugins.enable(name=PLUGIN_REFER_INTEGRITY) + topology.standalone.plugins.disable(name=PLUGIN_LINKED_ATTRS) + topology.standalone.plugins.enable(name=PLUGIN_LINKED_ATTRS) + topology.standalone.plugins.disable(name=PLUGIN_REFER_INTEGRITY) + topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) + topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) + topology.standalone.plugins.enable(name=PLUGIN_REFER_INTEGRITY) + time.sleep(2) + topology.standalone.plugins.disable(name=PLUGIN_REFER_INTEGRITY) + time.sleep(1) + topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) + time.sleep(1) + topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) + time.sleep(1) + topology.standalone.plugins.enable(name=PLUGIN_REFER_INTEGRITY) + topology.standalone.plugins.disable(name=PLUGIN_LINKED_ATTRS) + topology.standalone.plugins.enable(name=PLUGIN_LINKED_ATTRS) + + # Wait for the 'deleting' threads to complete + del_users.join() + del_users2.join() + del_users3.join() + + # Now make sure both the MO and RI plugins still work correctly + plugin_tests.func_tests[8](topology.standalone) # RI plugin + plugin_tests.func_tests[5](topology.standalone) # MO plugin + + # Cleanup the stress tests + stress_tests.cleanup(topology.standalone) + + except: + log.info('Stress test failed!') + repl_fail(replica_inst) + + stress_count += 1 + log.info('####################################################################') + log.info('Successfully Stressed Dynamic Plugins' + msg + + '. Completed (%d/%d)' % (stress_count, stress_max_runs)) + log.info('####################################################################\n') + + if replication_run: + # We're done. + break + else: + # + # Enable replication and run everything one more time + # + log.info('Setting up replication, and rerunning the tests...\n') + + # Create replica instance + replica_inst = DirSrv(verbose=False) + args_instance[SER_HOST] = LOCALHOST + args_instance[SER_PORT] = REPLICA_PORT + args_instance[SER_SERVERID_PROP] = 'replica' + args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX + + args_replica_inst = args_instance.copy() + replica_inst.allocate(args_replica_inst) + replica_inst.create() + replica_inst.open() + + try: + topology.standalone.replica.enableReplication(suffix=DEFAULT_SUFFIX, + role=REPLICAROLE_MASTER, + replicaId=1) + replica_inst.replica.enableReplication(suffix=DEFAULT_SUFFIX, + role=REPLICAROLE_CONSUMER, + replicaId=65535) + properties = {RA_NAME: r'to_replica', + RA_BINDDN: defaultProperties[REPLICATION_BIND_DN], + RA_BINDPW: defaultProperties[REPLICATION_BIND_PW], + RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD], + RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]} + + repl_agreement = topology.standalone.agreement.create(suffix=DEFAULT_SUFFIX, + host=LOCALHOST, + port=REPLICA_PORT, + properties=properties) + + if not repl_agreement: + log.fatal("Fail to create a replica agreement") + repl_fail(replica_inst) + + topology.standalone.agreement.init(DEFAULT_SUFFIX, LOCALHOST, REPLICA_PORT) + topology.standalone.waitForReplInit(repl_agreement) + except: + log.info('Failed to setup replication!') + repl_fail(replica_inst) + + replication_run = True + msg = ' (replication enabled)' + time.sleep(1) - plugin_test(topology.standalone, "restart") + ############################################################################ + # Check replication, and data are in sync, and remove the instance + ############################################################################ - if prev_plugin_test: - prev_plugin_test(topology.standalone, "restart") + log.info('Checking if replication is in sync...') - plugin_test(topology.standalone, "restart") + try: + # Grab master's max CSN + entry = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, RUV_FILTER) + if not entry: + log.error('Failed to find db tombstone entry from master') + repl_fail(replica_inst) + elements = entry[0].getValues('nsds50ruv') + for ruv in elements: + if 'replica 1' in ruv: + parts = ruv.split() + if len(parts) == 5: + master_maxcsn = parts[4] + break + else: + log.error('RUV is incomplete') + repl_fail(replica_inst) + if master_maxcsn == 0: + log.error('Failed to find maxcsn on master') + repl_fail(replica_inst) - # Now run the functional test - plugin_test(topology.standalone) + except ldap.LDAPError, e: + log.fatal('Unable to search masterfor db tombstone: ' + e.message['desc']) + repl_fail(replica_inst) + + # Loop on the consumer - waiting for it to catch up + count = 0 + insync = False + while count < 10: + try: + # Grab master's max CSN + entry = replica_inst.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, RUV_FILTER) + if not entry: + log.error('Failed to find db tombstone entry on consumer') + repl_fail(replica_inst) + elements = entry[0].getValues('nsds50ruv') + for ruv in elements: + if 'replica 1' in ruv: + parts = ruv.split() + if len(parts) == 5: + replica_maxcsn = parts[4] + break + if replica_maxcsn == 0: + log.error('Failed to find maxcsn on consumer') + repl_fail(replica_inst) + except ldap.LDAPError, e: + log.fatal('Unable to search for db tombstone on consumer: ' + e.message['desc']) + repl_fail(replica_inst) + + if master_maxcsn == replica_maxcsn: + insync = True + log.info('Replication is in sync.\n') + break + count += 1 + time.sleep(1) + + # Report on replication status + if not insync: + log.error('Consumer not in sync with master!') + repl_fail(replica_inst) - # Set the previous tests - if prev_plugin_test: - prev_prev_plugin_test = prev_plugin_test - prev_plugin_test = plugin_test + # + # Verify the databases are identical. There should not be any "user, entry, employee" entries + # + log.info('Checking if the data is the same between the replicas...') - log.info('#####################################################') - log.info('Successfully Tested Dynamic Plugins for Memory Corruption.') - log.info('#####################################################\n') + # Check the master + try: + entries = topology.standalone.search_s(DEFAULT_SUFFIX, + ldap.SCOPE_SUBTREE, + "(|(uid=person*)(uid=entry*)(uid=employee*))") + if len(entries) > 0: + log.error('Master database has incorrect data set!\n') + repl_fail(replica_inst) + except ldap.LDAPError, e: + log.fatal('Unable to search db on master: ' + e.message['desc']) + repl_fail(replica_inst) - ############################################################################ - # Stress two plugins while restarting it, and while restarting other plugins. - # The goal is to not crash, and have the plugins work after stressing it. - ############################################################################ + # Check the consumer + try: + entries = replica_inst.search_s(DEFAULT_SUFFIX, + ldap.SCOPE_SUBTREE, + "(|(uid=person*)(uid=entry*)(uid=employee*))") + if len(entries) > 0: + log.error('Consumer database in not consistent with master database') + repl_fail(replica_inst) + except ldap.LDAPError, e: + log.fatal('Unable to search db on consumer: ' + e.message['desc']) + repl_fail(replica_inst) - log.info('#####################################################') - log.info('Stressing Dynamic Plugins...') - log.info('#####################################################\n') + log.info('Data is consistent across the replicas.\n') - # Configure the plugins - stress_tests.configureMO(topology.standalone) - stress_tests.configureRI(topology.standalone) - - # Launch three new threads to add a bunch of users - add_users = stress_tests.AddUsers(topology.standalone, 'user', True) - add_users.start() - add_users2 = stress_tests.AddUsers(topology.standalone, 'entry', True) - add_users2.start() - add_users3 = stress_tests.AddUsers(topology.standalone, 'person', True) - add_users3.start() - time.sleep(1) - - # While we are adding users restart the MO plugin - topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) - topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) - time.sleep(3) - topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) - time.sleep(1) - topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) - - # Restart idle plugin - topology.standalone.plugins.disable(name=PLUGIN_LINKED_ATTRS) - topology.standalone.plugins.enable(name=PLUGIN_LINKED_ATTRS) - - # Wait for the 'adding' threads to complete - add_users.join() - add_users2.join() - add_users3.join() - - # Now launch three threads to delete the users, and restart both the MO and RI plugins - del_users = stress_tests.DelUsers(topology.standalone, 'user') - del_users.start() - del_users2 = stress_tests.DelUsers(topology.standalone, 'entry') - del_users2.start() - del_users3 = stress_tests.DelUsers(topology.standalone, 'person') - del_users3.start() - time.sleep(1) - - # Restart the both the MO and RI plugins during these deletes - - topology.standalone.plugins.disable(name=PLUGIN_REFER_INTEGRITY) - topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) - topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) - topology.standalone.plugins.enable(name=PLUGIN_REFER_INTEGRITY) - time.sleep(3) - topology.standalone.plugins.disable(name=PLUGIN_REFER_INTEGRITY) - time.sleep(1) - topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) - time.sleep(1) - topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) - time.sleep(1) - topology.standalone.plugins.enable(name=PLUGIN_REFER_INTEGRITY) - - # Restart idle plugin - topology.standalone.plugins.disable(name=PLUGIN_LINKED_ATTRS) - topology.standalone.plugins.enable(name=PLUGIN_LINKED_ATTRS) - - # Wait for the 'deleting' threads to complete - del_users.join() - del_users2.join() - del_users3.join() - - # Now make sure both the MO and RI plugins still work - plugin_tests.func_tests[8](topology.standalone) # RI plugin - plugin_tests.func_tests[5](topology.standalone) # MO plugin + log.info('####################################################################') + log.info('Replication consistency test passed') + log.info('####################################################################\n') - log.info('#####################################################') - log.info('Successfully Stressed Dynamic Plugins.') - log.info('#####################################################\n') + # Remove the replica instance + replica_inst.delete() ############################################################################ # We made it to the end! @@ -291,7 +509,8 @@ def test_dynamic_plugins(topology): log.info('#####################################################') log.info("Dynamic Plugins Testsuite: Completed Successfully!") log.info('#####################################################') - log.info('#####################################################') + log.info('#####################################################\n') + def test_dynamic_plugins_final(topology): topology.standalone.stop(timeout=10) diff --git a/dirsrvtests/tickets/ticket47560_test.py b/dirsrvtests/tickets/ticket47560_test.py index 0b7e436..af7fdc3 100644 --- a/dirsrvtests/tickets/ticket47560_test.py +++ b/dirsrvtests/tickets/ticket47560_test.py @@ -146,7 +146,7 @@ def test_ticket47560(topology): Enable or disable mbo plugin depending on 'value' ('on'/'off') """ # enable/disable the mbo plugin - if value != 'on': + if value == 'on': topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) else: topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) diff --git a/ldap/servers/plugins/acctpolicy/acct_config.c b/ldap/servers/plugins/acctpolicy/acct_config.c index 25352b1..d1acf1a 100644 --- a/ldap/servers/plugins/acctpolicy/acct_config.c +++ b/ldap/servers/plugins/acctpolicy/acct_config.c @@ -53,9 +53,11 @@ acct_policy_load_config_startup( Slapi_PBlock* pb, void* plugin_id ) { PLUGIN_CONFIG_DN, rc ); return( -1 ); } - + config_wr_lock(); + free_config(); newcfg = get_config(); rc = acct_policy_entry2config( config_entry, newcfg ); + config_unlock(); slapi_entry_free( config_entry ); @@ -85,8 +87,8 @@ acct_policy_entry2config( Slapi_Entry *e, acctPluginCfg *newcfg ) { } else if (!update_is_allowed_attr(newcfg->state_attr_name)) { /* log a warning that this attribute cannot be updated */ slapi_log_error( SLAPI_LOG_FATAL, PLUGIN_NAME, - "The configured state attribute [%s] cannot be updated, accounts will always become inactive.\n", - newcfg->state_attr_name ); + "The configured state attribute [%s] cannot be updated, accounts will always become inactive.\n", + newcfg->state_attr_name ); } newcfg->alt_state_attr_name = get_attr_string_val( e, CFG_ALT_LASTLOGIN_STATE_ATTR ); diff --git a/ldap/servers/plugins/acctpolicy/acct_init.c b/ldap/servers/plugins/acctpolicy/acct_init.c index c4dba22..0b1af91 100644 --- a/ldap/servers/plugins/acctpolicy/acct_init.c +++ b/ldap/servers/plugins/acctpolicy/acct_init.c @@ -63,6 +63,47 @@ int acct_postop_init( Slapi_PBlock *pb ); int acct_bind_preop( Slapi_PBlock *pb ); int acct_bind_postop( Slapi_PBlock *pb ); +static void *_PluginID = NULL; +static Slapi_DN *_PluginDN = NULL; +static Slapi_DN *_ConfigAreaDN = NULL; +static Slapi_RWLock *config_rwlock = NULL; + +void +acct_policy_set_plugin_id(void *pluginID) +{ + _PluginID = pluginID; +} + +void * +acct_policy_get_plugin_id() +{ + return _PluginID; +} + +void +acct_policy_set_plugin_sdn(Slapi_DN *pluginDN) +{ + _PluginDN = pluginDN; +} + +Slapi_DN * +acct_policy_get_plugin_sdn() +{ + return _PluginDN; +} + +void +acct_policy_set_config_area(Slapi_DN *sdn) +{ + _ConfigAreaDN = sdn; +} + +Slapi_DN * +acct_policy_get_config_area() +{ + return _ConfigAreaDN; +} + /* Master init function for the account plugin */ @@ -120,14 +161,32 @@ acct_policy_init( Slapi_PBlock *pb ) which is needed to retrieve the plugin configuration */ int -acct_policy_start( Slapi_PBlock *pb ) { +acct_policy_start( Slapi_PBlock *pb ) +{ acctPluginCfg *cfg; void *plugin_id = get_identity(); + Slapi_DN *plugindn = NULL; + char *config_area = NULL; if(slapi_plugin_running(pb)){ return 0; } + slapi_pblock_get(pb, SLAPI_TARGET_SDN, &plugindn); + acct_policy_set_plugin_sdn(slapi_sdn_dup(plugindn)); + + /* Set the alternate config area if one is defined. */ + slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_AREA, &config_area); + if (config_area) { + acct_policy_set_config_area(slapi_sdn_new_normdn_byval(config_area)); + } + + if(config_rwlock == NULL){ + if((config_rwlock = slapi_new_rwlock()) == NULL){ + return( CALLBACK_ERR ); + } + } + /* Load plugin configuration */ if( acct_policy_load_config_startup( pb, plugin_id ) ) { slapi_log_error( SLAPI_LOG_FATAL, PLUGIN_NAME, @@ -151,6 +210,10 @@ acct_policy_close( Slapi_PBlock *pb ) { int rc = 0; + slapi_destroy_rwlock(config_rwlock); + config_rwlock = NULL; + slapi_sdn_free(&_PluginDN); + slapi_sdn_free(&_ConfigAreaDN); free_config(); return rc; @@ -168,8 +231,11 @@ acct_preop_init( Slapi_PBlock *pb ) { return( CALLBACK_ERR ); } - if ( slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_BIND_FN, - (void *) acct_bind_preop ) != 0 ) { + if ( slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_BIND_FN, (void *) acct_bind_preop ) != 0 || + slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN, (void *) acct_add_pre_op) != 0 || + slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN, (void *) acct_mod_pre_op) != 0 || + slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_DELETE_FN, (void *) acct_del_pre_op) != 0) + { slapi_log_error( SLAPI_LOG_FATAL, PRE_PLUGIN_NAME, "Failed to set plugin callback function\n" ); return( CALLBACK_ERR ); @@ -192,8 +258,11 @@ acct_postop_init( Slapi_PBlock *pb ) return( CALLBACK_ERR ); } - if ( slapi_pblock_set( pb, SLAPI_PLUGIN_POST_BIND_FN, - (void *)acct_bind_postop ) != 0 ) { + + if ( slapi_pblock_set( pb, SLAPI_PLUGIN_POST_BIND_FN, (void *)acct_bind_postop ) != 0 || + slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN, (void *) acct_post_op) != 0 || + slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN, (void *) acct_post_op) != 0) + { slapi_log_error( SLAPI_LOG_FATAL, POST_PLUGIN_NAME, "Failed to set plugin callback function\n" ); return( CALLBACK_ERR ); @@ -208,3 +277,23 @@ acct_postop_init( Slapi_PBlock *pb ) return( CALLBACK_OK ); } +/* + * Wrappers for config locking + */ +void +config_rd_lock() +{ + slapi_rwlock_rdlock(config_rwlock); +} + +void +config_wr_lock() +{ + slapi_rwlock_wrlock(config_rwlock); +} + +void +config_unlock() +{ + slapi_rwlock_unlock(config_rwlock); +} diff --git a/ldap/servers/plugins/acctpolicy/acct_plugin.c b/ldap/servers/plugins/acctpolicy/acct_plugin.c index 5719f27..a61a50c 100644 --- a/ldap/servers/plugins/acctpolicy/acct_plugin.c +++ b/ldap/servers/plugins/acctpolicy/acct_plugin.c @@ -28,6 +28,46 @@ Hewlett-Packard Development Company, L.P. #include "acctpolicy.h" /* + * acct_policy_dn_is_config() + * + * Checks if dn is a plugin config entry. + */ +static int +acct_policy_dn_is_config(Slapi_DN *sdn) +{ + int ret = 0; + + slapi_log_error(SLAPI_LOG_TRACE, PLUGIN_NAME, + "--> automember_dn_is_config\n"); + + if (sdn == NULL) { + goto bail; + } + + /* If an alternate config area is configured, treat it's child + * entries as config entries. If the alternate config area is + * not configured, treat children of the top-level plug-in + * config entry as our config entries. */ + if (acct_policy_get_config_area()) { + if (slapi_sdn_issuffix(sdn, acct_policy_get_config_area()) && + slapi_sdn_compare(sdn, acct_policy_get_config_area())) { + ret = 1; + } + } else { + if (slapi_sdn_issuffix(sdn, acct_policy_get_plugin_sdn()) && + slapi_sdn_compare(sdn, acct_policy_get_plugin_sdn())) { + ret = 1; + } + } + +bail: + slapi_log_error(SLAPI_LOG_TRACE, PLUGIN_NAME, + "<-- automember_dn_is_config\n"); + + return ret; +} + +/* Checks bind entry for last login state and compares current time with last login time plus the limit to decide whether to deny the bind. */ @@ -39,6 +79,7 @@ acct_inact_limit( Slapi_PBlock *pb, const char *dn, Slapi_Entry *target_entry, a int rc = 0; /* Optimistic default */ acctPluginCfg *cfg; + config_rd_lock(); cfg = get_config(); if( ( lasttimestr = get_attr_string_val( target_entry, cfg->state_attr_name ) ) != NULL ) { @@ -75,6 +116,7 @@ acct_inact_limit( Slapi_PBlock *pb, const char *dn, Slapi_Entry *target_entry, a } done: + config_unlock(); /* Deny bind; the account has exceeded the inactivity limit */ if( rc == 1 ) { slapi_send_ldap_result( pb, LDAP_CONSTRAINT_VIOLATION, NULL, @@ -106,13 +148,14 @@ acct_record_login( const char *dn ) Slapi_PBlock *modpb = NULL; int skip_mod_attrs = 1; /* value doesn't matter as long as not NULL */ + config_rd_lock(); cfg = get_config(); /* if we are not allowed to modify the state attr we're done * this could be intentional, so just return */ if (! update_is_allowed_attr(cfg->always_record_login_attr) ) - return rc; + goto done; plugin_id = get_identity(); @@ -152,6 +195,7 @@ acct_record_login( const char *dn ) } done: + config_unlock(); slapi_pblock_destroy( modpb ); slapi_ch_free_string( ×tr ); @@ -274,6 +318,7 @@ acct_bind_postop( Slapi_PBlock *pb ) goto done; } + config_rd_lock(); cfg = get_config(); tracklogin = cfg->always_record_login; @@ -296,6 +341,7 @@ acct_bind_postop( Slapi_PBlock *pb ) } } } + config_unlock(); if( tracklogin ) { rc = acct_record_login( dn ); @@ -319,3 +365,133 @@ done: return( rc == 0 ? CALLBACK_OK : CALLBACK_ERR ); } + +static int acct_pre_op( Slapi_PBlock *pb, int modop ) +{ + Slapi_DN *sdn = 0; + Slapi_Entry *e = 0; + Slapi_Mods *smods = 0; + LDAPMod **mods; + int free_entry = 0; + char *errstr = NULL; + int ret = SLAPI_PLUGIN_SUCCESS; + + slapi_log_error(SLAPI_LOG_TRACE, PRE_PLUGIN_NAME, "--> acct_pre_op\n"); + + slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn); + + if (acct_policy_dn_is_config(sdn)) { + /* Validate config changes, but don't apply them. + * This allows us to reject invalid config changes + * here at the pre-op stage. Applying the config + * needs to be done at the post-op stage. */ + + if (LDAP_CHANGETYPE_ADD == modop) { + slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e); + + /* If the entry doesn't exist, just bail and + * let the server handle it. */ + if (e == NULL) { + goto bail; + } + } else if (LDAP_CHANGETYPE_MODIFY == modop) { + /* Fetch the entry being modified so we can + * create the resulting entry for validation. */ + if (sdn) { + slapi_search_internal_get_entry(sdn, 0, &e, get_identity()); + free_entry = 1; + } + + /* If the entry doesn't exist, just bail and + * let the server handle it. */ + if (e == NULL) { + goto bail; + } + + /* Grab the mods. */ + slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods); + smods = slapi_mods_new(); + slapi_mods_init_byref(smods, mods); + + /* Apply the mods to create the resulting entry. */ + if (mods && (slapi_entry_apply_mods(e, mods) != LDAP_SUCCESS)) { + /* The mods don't apply cleanly, so we just let this op go + * to let the main server handle it. */ + goto bailmod; + } + } else if (modop == LDAP_CHANGETYPE_DELETE){ + ret = LDAP_UNWILLING_TO_PERFORM; + slapi_log_error(SLAPI_LOG_FATAL, PRE_PLUGIN_NAME, + "acct_pre_op: can not delete plugin config entry [%d]\n", ret); + } else { + errstr = slapi_ch_smprintf("acct_pre_op: invalid op type %d", modop); + ret = LDAP_PARAM_ERROR; + goto bail; + } + } + + bailmod: + /* Clean up smods. */ + if (LDAP_CHANGETYPE_MODIFY == modop) { + slapi_mods_free(&smods); + } + + bail: + if (free_entry && e) + slapi_entry_free(e); + + if (ret) { + slapi_log_error(SLAPI_LOG_PLUGIN, PRE_PLUGIN_NAME, + "acct_pre_op: operation failure [%d]\n", ret); + slapi_send_ldap_result(pb, ret, NULL, errstr, 0, NULL); + slapi_ch_free((void **)&errstr); + slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret); + ret = SLAPI_PLUGIN_FAILURE; + } + + slapi_log_error(SLAPI_LOG_TRACE, PRE_PLUGIN_NAME, "<-- acct_pre_op\n"); + + return ret; +} + +int +acct_add_pre_op( Slapi_PBlock *pb ) +{ + return acct_pre_op(pb, LDAP_CHANGETYPE_ADD); +} + +int +acct_mod_pre_op( Slapi_PBlock *pb ) +{ + return acct_pre_op(pb, LDAP_CHANGETYPE_MODIFY); +} + +int +acct_del_pre_op( Slapi_PBlock *pb ) +{ + return acct_pre_op(pb, LDAP_CHANGETYPE_DELETE); +} + +int +acct_post_op(Slapi_PBlock *pb) +{ + Slapi_DN *sdn = NULL; + + slapi_log_error(SLAPI_LOG_TRACE, POST_PLUGIN_NAME, + "--> acct_policy_post_op\n"); + + slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn); + if (acct_policy_dn_is_config(sdn)){ + if( acct_policy_load_config_startup( pb, get_identity() ) ) { + slapi_log_error( SLAPI_LOG_FATAL, PLUGIN_NAME, + "acct_policy_start failed to load configuration\n" ); + return( CALLBACK_ERR ); + } + } + + slapi_log_error(SLAPI_LOG_TRACE, POST_PLUGIN_NAME, + "<-- acct_policy_mod_post_op\n"); + + return SLAPI_PLUGIN_SUCCESS; +} + diff --git a/ldap/servers/plugins/acctpolicy/acct_util.c b/ldap/servers/plugins/acctpolicy/acct_util.c index 2e24da2..cff0176 100644 --- a/ldap/servers/plugins/acctpolicy/acct_util.c +++ b/ldap/servers/plugins/acctpolicy/acct_util.c @@ -82,7 +82,8 @@ get_attr_string_val( Slapi_Entry* target_entry, char* attr_name ) { */ int get_acctpolicy( Slapi_PBlock *pb, Slapi_Entry *target_entry, void *plugin_id, - acctPolicy **policy ) { + acctPolicy **policy ) +{ Slapi_DN *sdn = NULL; Slapi_Entry *policy_entry = NULL; Slapi_Attr *attr; @@ -93,8 +94,6 @@ get_acctpolicy( Slapi_PBlock *pb, Slapi_Entry *target_entry, void *plugin_id, acctPluginCfg *cfg; int rc = 0; - cfg = get_config(); - if( policy == NULL ) { /* Bad parameter */ return( -1 ); @@ -102,19 +101,22 @@ get_acctpolicy( Slapi_PBlock *pb, Slapi_Entry *target_entry, void *plugin_id, *policy = NULL; + config_rd_lock(); + cfg = get_config(); /* Return success and NULL policy */ policy_dn = get_attr_string_val( target_entry, cfg->spec_attr_name ); if( policy_dn == NULL ) { slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "\"%s\" is not governed by an account inactivity " "policy subentry\n", slapi_entry_get_ndn( target_entry ) ); - if (cfg->inactivitylimit != ULONG_MAX) { - goto dopolicy; - } + if (cfg->inactivitylimit != ULONG_MAX) { + goto dopolicy; + } slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "\"%s\" is not governed by an account inactivity " "global policy\n", slapi_entry_get_ndn( target_entry ) ); - return rc; + config_unlock(); + return rc; } sdn = slapi_sdn_new_dn_byref( policy_dn ); @@ -153,7 +155,8 @@ dopolicy: } } done: - slapi_ch_free_string( &policy_dn ); + config_unlock(); + slapi_ch_free_string( &policy_dn ); slapi_entry_free( policy_entry ); return( rc ); } diff --git a/ldap/servers/plugins/acctpolicy/acctpolicy.h b/ldap/servers/plugins/acctpolicy/acctpolicy.h index 2185b95..64f37fb 100644 --- a/ldap/servers/plugins/acctpolicy/acctpolicy.h +++ b/ldap/servers/plugins/acctpolicy/acctpolicy.h @@ -69,10 +69,9 @@ typedef struct accountpolicy { int get_acctpolicy( Slapi_PBlock *pb, Slapi_Entry *target_entry, void *plugin_id, acctPolicy **policy ); void free_acctpolicy( acctPolicy **policy ); -int has_attr( Slapi_Entry* target_entry, char* attr_name, - char** val ); +int has_attr( Slapi_Entry* target_entry, char* attr_name, char** val ); char* get_attr_string_val( Slapi_Entry* e, char* attr_name ); -void* get_identity(); +void* get_identity(void); void set_identity(void*); time_t gentimeToEpochtime( char *gentimestr ); char* epochtimeToGentime( time_t epochtime ); @@ -80,6 +79,22 @@ int update_is_allowed_attr (const char *attr); /* acct_config.c */ int acct_policy_load_config_startup( Slapi_PBlock* pb, void* plugin_id ); -acctPluginCfg* get_config(); -void free_config(); +acctPluginCfg* get_config(void); +void free_config(void); + +/* acct_init.c */ +void acct_policy_set_plugin_sdn(Slapi_DN *pluginDN); +Slapi_DN * acct_policy_get_plugin_sdn(void); +void acct_policy_set_config_area(Slapi_DN *sdn); +Slapi_DN * acct_policy_get_config_area(void); +void config_rd_lock(void); +void config_wr_lock(void); +void config_unlock(void); + +/* acc_plugins.c */ +int acct_add_pre_op( Slapi_PBlock *pb ); +int acct_mod_pre_op( Slapi_PBlock *pb ); +int acct_del_pre_op( Slapi_PBlock *pb ); +int acct_post_op( Slapi_PBlock *pb ); + diff --git a/ldap/servers/plugins/linkedattrs/fixup_task.c b/ldap/servers/plugins/linkedattrs/fixup_task.c index db3c693..f3f5c04 100644 --- a/ldap/servers/plugins/linkedattrs/fixup_task.c +++ b/ldap/servers/plugins/linkedattrs/fixup_task.c @@ -197,8 +197,8 @@ linked_attrs_fixup_task_thread(void *arg) linked_attrs_unlock(); /* Log finished message. */ - slapi_task_log_notice(task, "Linked attributes fixup task complete.\n"); - slapi_task_log_status(task, "Linked attributes fixup task complete.\n"); + slapi_task_log_notice(task, "Linked attributes fixup task complete."); + slapi_task_log_status(task, "Linked attributes fixup task complete."); slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM, "Linked attributes fixup task complete.\n"); slapi_task_inc_progress(task); diff --git a/ldap/servers/plugins/memberof/memberof_config.c b/ldap/servers/plugins/memberof/memberof_config.c index 012e2d0..7fa5897 100644 --- a/ldap/servers/plugins/memberof/memberof_config.c +++ b/ldap/servers/plugins/memberof/memberof_config.c @@ -867,7 +867,6 @@ memberof_shared_config_validate(Slapi_PBlock *pb) } slapi_ch_free_string(&configarea_dn); slapi_sdn_free(&config_sdn); - slapi_entry_free(config_entry); } } } diff --git a/ldap/servers/slapd/dse.c b/ldap/servers/slapd/dse.c index f0ce255..f80178e 100644 --- a/ldap/servers/slapd/dse.c +++ b/ldap/servers/slapd/dse.c @@ -2426,8 +2426,6 @@ dse_add(Slapi_PBlock *pb) /* JCM There should only be one exit point from this f } } - /* entry has been freed, so make sure no one tries to use it later */ - slapi_pblock_set(pb, SLAPI_ADD_ENTRY, NULL); slapi_send_ldap_result(pb, returncode, NULL, returntext[0] ? returntext : NULL, 0, NULL ); return dse_add_return(rc, e); } diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c index 5530c70..b0b18e7 100644 --- a/ldap/servers/slapd/plugin.c +++ b/ldap/servers/slapd/plugin.c @@ -454,10 +454,21 @@ plugin_call_plugins( Slapi_PBlock *pb, int whichfunction ) { /* We stash the pblock plugin pointer to preserve the callers context */ struct slapdplugin *p; + int locked = 0; + + locked = slapi_td_get_plugin_locked(); + if (!locked) { + slapi_rwlock_rdlock(global_rwlock); + } + slapi_pblock_get(pb, SLAPI_PLUGIN, &p); /* Call the operation on the Global Plugins */ rc = plugin_call_list(global_plugin_list[plugin_list_number], whichfunction, pb); slapi_pblock_set(pb, SLAPI_PLUGIN, p); + + if (!locked) { + slapi_rwlock_unlock(global_rwlock); + } } else { @@ -1080,12 +1091,6 @@ plugin_start(Slapi_Entry *entry, char *returntext) int ret = 0; int i = 0; - /* - * Disable registered plugin functions so preops/postops/etc - * dont get called prior to the plugin being started (due to - * plugins performing ops on the DIT) - */ - global_plugin_callbacks_enabled = 0; global_plugins_started = 0; /* Count the plugins so we can allocate memory for the config array */ @@ -1404,6 +1409,7 @@ plugin_free_plugin_dep_config(plugin_dep_config **cfg) } slapi_ch_free_string(&config[index].type); slapi_ch_free_string(&config[index].name); + slapi_ch_free_string(&config[index].config_area); pblock_done(&config[index].pb); index++; } @@ -1909,16 +1915,6 @@ plugin_call_func (struct slapdplugin *list, int operation, Slapi_PBlock *pb, int int rc; int return_value = 0; int count = 0; - int *locked = 0; - - /* - * Take the read lock - */ - slapi_td_get_plugin_locked(&locked); - if(locked == 0){ - slapi_rwlock_rdlock(global_rwlock); - } - for (; list != NULL; list = list->plg_next) { @@ -1998,9 +1994,6 @@ plugin_call_func (struct slapdplugin *list, int operation, Slapi_PBlock *pb, int if(call_one) break; } - if(locked == 0){ - slapi_rwlock_unlock(global_rwlock); - } return( return_value ); } @@ -2323,6 +2316,7 @@ plugin_restart(Slapi_Entry *pentryBefore, Slapi_Entry *pentryAfter) } slapi_rwlock_wrlock(global_rwlock); + slapi_td_set_plugin_locked(); if(plugin_delete(pentryBefore, returntext, 1) == LDAP_SUCCESS){ if(plugin_add(pentryAfter, returntext, 1) == LDAP_SUCCESS){ @@ -2346,6 +2340,7 @@ plugin_restart(Slapi_Entry *pentryBefore, Slapi_Entry *pentryAfter) } slapi_rwlock_unlock(global_rwlock); + slapi_td_set_plugin_unlocked(); return rc; } @@ -2995,12 +2990,11 @@ int plugin_add(Slapi_Entry *entry, char *returntext, int locked) { int rc = LDAP_SUCCESS; - int td_locked = 1; if(!locked){ slapi_rwlock_wrlock(global_rwlock); + slapi_td_set_plugin_locked(); } - slapi_td_set_plugin_locked(&td_locked); if((rc = plugin_setup(entry, 0, 0, 1, returntext)) != LDAP_SUCCESS){ LDAPDebug(LDAP_DEBUG_PLUGIN, "plugin_add: plugin_setup failed for (%s)\n",slapi_entry_get_dn(entry), rc, 0); @@ -3015,9 +3009,8 @@ plugin_add(Slapi_Entry *entry, char *returntext, int locked) done: if(!locked){ slapi_rwlock_unlock(global_rwlock); + slapi_td_set_plugin_unlocked(); } - td_locked = 0; - slapi_td_set_plugin_locked(&td_locked); return rc; } @@ -3372,7 +3365,6 @@ plugin_delete(Slapi_Entry *plugin_entry, char *returntext, int locked) struct slapdplugin *plugin = NULL; const char *plugin_dn = slapi_entry_get_dn_const(plugin_entry); char *value = NULL; - int td_locked = 1; int removed = PLUGIN_BUSY; int type = 0; int rc = LDAP_SUCCESS; @@ -3400,8 +3392,8 @@ plugin_delete(Slapi_Entry *plugin_entry, char *returntext, int locked) removed = PLUGIN_NOT_FOUND; if(!locked){ slapi_rwlock_wrlock(global_rwlock); + slapi_td_set_plugin_locked(); } - slapi_td_set_plugin_locked(&td_locked); rc = plugin_get_type_and_list(value, &type, &plugin_list); if ( rc != 0 ) { @@ -3445,9 +3437,8 @@ plugin_delete(Slapi_Entry *plugin_entry, char *returntext, int locked) unlock: if(!locked){ slapi_rwlock_unlock(global_rwlock); + slapi_td_set_plugin_unlocked(); } - td_locked = 0; - slapi_td_set_plugin_locked(&td_locked); } } diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index cb8aad0..a61d954 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -5585,8 +5585,10 @@ int slapi_td_dn_init(void); int slapi_td_set_dn(char *dn); void slapi_td_get_dn(char **dn); int slapi_td_plugin_lock_init(void); -int slapi_td_set_plugin_locked(int *value); -void slapi_td_get_plugin_locked(int **value); +int slapi_td_get_plugin_locked(void); +int slapi_td_set_plugin_locked(void); +int slapi_td_set_plugin_unlocked(void); + /* Thread Local Storage Index Types */ #define SLAPI_TD_REQUESTOR_DN 1 diff --git a/ldap/servers/slapd/thread_data.c b/ldap/servers/slapd/thread_data.c index 121e2d8..4d9bb93 100644 --- a/ldap/servers/slapd/thread_data.c +++ b/ldap/servers/slapd/thread_data.c @@ -168,19 +168,38 @@ slapi_td_plugin_lock_init() } int -slapi_td_set_plugin_locked(int *value) +slapi_td_set_plugin_locked() { - if(slapi_td_set_val(SLAPI_TD_PLUGIN_LIST_LOCK, (void *)value) == PR_FAILURE){ + int val = 12345; + + if(slapi_td_set_val(SLAPI_TD_PLUGIN_LIST_LOCK, (void *)&val) == PR_FAILURE){ return PR_FAILURE; } return PR_SUCCESS; } -void -slapi_td_get_plugin_locked(int **value) +int +slapi_td_set_plugin_unlocked() { - slapi_td_get_val(SLAPI_TD_PLUGIN_LIST_LOCK, (void **)value); + if(slapi_td_set_val(SLAPI_TD_PLUGIN_LIST_LOCK, NULL) == PR_FAILURE){ + return PR_FAILURE; + } + + return PR_SUCCESS; +} + +int +slapi_td_get_plugin_locked() +{ + int *value = 0; + + slapi_td_get_val(SLAPI_TD_PLUGIN_LIST_LOCK, (void **)&value); + if(value){ + return 1; + } else{ + return 0; + } } /* requestor dn */