Branch '389-ds-base-1.3.2' - dirsrvtests/tickets ldap/servers
by Mark Reynolds
dirsrvtests/tickets/ticket47981_test.py | 345 ++++++++++++++++++++++++++++++++
ldap/servers/plugins/cos/cos_cache.c | 34 +--
2 files changed, 359 insertions(+), 20 deletions(-)
New commits:
commit df7bafae3c069ecf90d951d0c0f1ede26ab521fd
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Wed Jan 7 08:59:06 2015 -0500
Ticket 47981 - COS cache doesn't properly mark vattr cache as
invalid when there are multiple suffixes
Bug Description: When rebuilding the COS cache, we check each suffix for COS entries.
If the last suffix checked does not contain any COS entries, then the
virtual attribute cache is incorrectly not invalidated. This allows
for already cached entries to hold onto the old COS attributes/values.
Fix Description: Only set the vattr_cacheable flag if a suffix contains COS entries, not
if it does not - by default the flag is not set.
https://fedorahosted.org/389/ticket/47981
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit 42e2df3858a4e14706d57b5c907d1d3768f4d970)
diff --git a/dirsrvtests/tickets/ticket47981_test.py b/dirsrvtests/tickets/ticket47981_test.py
new file mode 100644
index 0000000..2a16ce6
--- /dev/null
+++ b/dirsrvtests/tickets/ticket47981_test.py
@@ -0,0 +1,345 @@
+import os
+import sys
+import time
+import ldap
+import ldap.sasl
+import logging
+import socket
+import pytest
+from lib389 import DirSrv, Entry, tools, tasks
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from lib389.tasks import *
+from constants import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+BRANCH = 'ou=people,' + DEFAULT_SUFFIX
+USER_DN = 'uid=user1,%s' % (BRANCH)
+BRANCH_CONTAINER = 'cn=nsPwPolicyContainer,ou=people,dc=example,dc=com'
+BRANCH_COS_DEF = 'cn=nsPwPolicy_CoS,ou=people,dc=example,dc=com'
+BRANCH_PWP = 'cn=cn\\3DnsPwPolicyEntry\\2Cou\\3DPeople\\2Cdc\\3Dexample\\2Cdc\\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
+BRANCH_COS_TMPL = 'cn=cn\\3DnsPwTemplateEntry\\2Cou\\3DPeople\\2Cdc\\3Dexample\\2Cdc\\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
+SECOND_SUFFIX = 'o=netscaperoot'
+BE_NAME = 'netscaperoot'
+
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ At the beginning, It may exists a standalone instance.
+ It may also exists a backup for the standalone instance.
+
+ Principle:
+ If standalone instance exists:
+ restart it
+ If backup of standalone exists:
+ create/rebind to standalone
+
+ restore standalone instance from backup
+ else:
+ Cleanup everything
+ remove instance
+ remove backup
+ Create instance
+ Create backup
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the backups
+ backup_standalone = standalone.checkBackupFS()
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+ if instance_standalone:
+ # assuming the instance is already stopped, just wait 5 sec max
+ standalone.stop(timeout=5)
+ standalone.start(timeout=10)
+
+ if backup_standalone:
+ # The backup exist, assuming it is correct
+ # we just re-init the instance with it
+ if not instance_standalone:
+ standalone.create()
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # restore standalone instance from backup
+ standalone.stop(timeout=10)
+ standalone.restoreFS(backup_standalone)
+ standalone.start(timeout=10)
+
+ else:
+ # We should be here only in two conditions
+ # - This is the first time a test involve standalone instance
+ # - Something weird happened (instance/backup destroyed)
+ # so we discard everything and recreate all
+
+ # Remove the backup. So even if we have a specific backup file
+ # (e.g backup_standalone) we clear backup that an instance may have created
+ if backup_standalone:
+ standalone.clearBackupFS()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # Time to create the backups
+ standalone.stop(timeout=10)
+ standalone.backupfile = standalone.backupFS()
+ standalone.start(timeout=10)
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
+ #
+ # Here we have standalone instance up and running
+ # Either coming from a backup recovery
+ # or from a fresh (re)init
+ # Time to return the topology
+ return TopologyStandalone(standalone)
+
+
+def addSubtreePwPolicy(inst):
+ #
+ # Add subtree policy to the people branch
+ #
+ try:
+ inst.add_s(Entry((BRANCH_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for ou=people: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ inst.add_s(Entry((BRANCH_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ inst.add_s(Entry((BRANCH_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=people,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ inst.add_s(Entry((BRANCH_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'costemplatedn': BRANCH_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def: error ' + e.message['desc'])
+ assert False
+ time.sleep(0.5)
+
+
+def delSubtreePwPolicy(inst):
+ try:
+ inst.delete_s(BRANCH_COS_DEF)
+ except ldap.LDAPError, e:
+ log.error('Failed to delete COS def: error ' + e.message['desc'])
+ assert False
+
+ try:
+ inst.delete_s(BRANCH_COS_TMPL)
+ except ldap.LDAPError, e:
+ log.error('Failed to delete COS template: error ' + e.message['desc'])
+ assert False
+
+ try:
+ inst.delete_s(BRANCH_PWP)
+ except ldap.LDAPError, e:
+ log.error('Failed to delete COS password policy: error ' + e.message['desc'])
+ assert False
+
+ try:
+ inst.delete_s(BRANCH_CONTAINER)
+ except ldap.LDAPError, e:
+ log.error('Failed to delete COS container: error ' + e.message['desc'])
+ assert False
+ time.sleep(0.5)
+
+
+def test_ticket47981(topology):
+ """
+ If there are multiple suffixes, and the last suffix checked does not contain any COS entries,
+ while other suffixes do, then the vattr cache is not invalidated as it should be. Then any
+ cached entries will still contain the old COS attributes/values.
+ """
+
+ log.info('Testing Ticket 47981 - Test that COS def changes are correctly reflected in affected users')
+
+ #
+ # Create a second backend that does not have any COS entries
+ #
+ log.info('Adding second suffix that will not contain any COS entries...\n')
+
+ topology.standalone.backend.create(SECOND_SUFFIX, {BACKEND_NAME: BE_NAME})
+ topology.standalone.mappingtree.create(SECOND_SUFFIX, bename=BE_NAME)
+ try:
+ topology.standalone.add_s(Entry((SECOND_SUFFIX, {
+ 'objectclass': 'top organization'.split(),
+ 'o': BE_NAME})))
+ except ldap.ALREADY_EXISTS:
+ pass
+ except ldap.LDAPError, e:
+ log.error('Failed to create suffix entry: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add People branch, it might already exist
+ #
+ log.info('Add our test entries to the default suffix, and proceed with the test...')
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level4'
+ })))
+ except ldap.ALREADY_EXISTS:
+ pass
+ except ldap.LDAPError, e:
+ log.error('Failed to add ou=people: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add a user to the branch
+ #
+ try:
+ topology.standalone.add_s(Entry((USER_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user1'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user1: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Enable password policy and add the subtree policy
+ #
+ try:
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on')])
+ except ldap.LDAPError, e:
+ log.error('Failed to set pwpolicy-local: error ' + e.message['desc'])
+ assert False
+
+ addSubtreePwPolicy(topology.standalone)
+
+ #
+ # Now check the user has its expected passwordPolicy subentry
+ #
+ try:
+ entries = topology.standalone.search_s(USER_DN,
+ ldap.SCOPE_BASE,
+ '(objectclass=top)',
+ ['pwdpolicysubentry', 'dn'])
+ if not entries[0].hasAttr('pwdpolicysubentry'):
+ log.fatal('User does not have expected pwdpolicysubentry!')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER_DN, e.message['desc']))
+ assert False
+
+ #
+ # Delete the password policy and make sure it is removed from the same user
+ #
+ delSubtreePwPolicy(topology.standalone)
+ try:
+ entries = topology.standalone.search_s(USER_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if entries[0].hasAttr('pwdpolicysubentry'):
+ log.fatal('User unexpectedly does have the pwdpolicysubentry!')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER_DN, e.message['desc']))
+ assert False
+
+ #
+ # Add the subtree policvy back and see if the user now has it
+ #
+ addSubtreePwPolicy(topology.standalone)
+ try:
+ entries = topology.standalone.search_s(USER_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasAttr('pwdpolicysubentry'):
+ log.fatal('User does not have expected pwdpolicysubentry!')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER_DN, e.message['desc']))
+ assert False
+
+ # If we got here the test passed
+ log.info('Test PASSED')
+
+
+def test_ticket47981_final(topology):
+ topology.standalone.stop(timeout=10)
+
+
+def run_isolated():
+ '''
+ run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
+ To run isolated without py.test, you need to
+ - edit this file and comment '@pytest.fixture' line before 'topology' function.
+ - set the installation prefix
+ - run this program
+ '''
+ global installation_prefix
+ installation_prefix = None
+
+ topo = topology(True)
+ test_ticket47981(topo)
+
+if __name__ == '__main__':
+ run_isolated()
\ No newline at end of file
diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
index 3214f82..d3d97f4 100644
--- a/ldap/servers/plugins/cos/cos_cache.c
+++ b/ldap/servers/plugins/cos/cos_cache.c
@@ -260,7 +260,7 @@ static int cos_cache_add_tmpl(cosTemplates **pTemplates, cosAttrValue *dn, cosAt
/* cosDefinitions manipulation */
static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_cacheable);
-static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs, int *vattr_cacheable);
+static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs);
static int cos_cache_add_defn(cosDefinitions **pDefs, cosAttrValue **dn, int cosType, cosAttrValue **tree, cosAttrValue **tmpDn, cosAttrValue **spec, cosAttrValue **pAttrs, cosAttrValue **pOverrides, cosAttrValue **pOperational, cosAttrValue **pCosMerge, cosAttrValue **pCosOpDefault);
static int cos_cache_entry_is_cos_related( Slapi_Entry *e);
@@ -619,9 +619,9 @@ static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_ca
LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_build_definition_list\n",0,0,0);
/*
- the class of service definitions may be anywhere in the DIT,
- so our first task is to find them.
- */
+ * The class of service definitions may be anywhere in the DIT,
+ * so our first task is to find them.
+ */
attrs[0] = "namingcontexts";
attrs[1] = 0;
@@ -629,9 +629,9 @@ static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_ca
LDAPDebug( LDAP_DEBUG_PLUGIN, "cos: Building class of service cache after status change.\n",0,0,0);
/*
- * XXXrbyrne: this looks really ineficient--should be using
+ * XXXrbyrne: this looks really inefficient--should be using
* slapi_get_next_suffix(), rather than searching for namingcontexts.
- */
+ */
pSuffixSearch = slapi_search_internal("",LDAP_SCOPE_BASE,"(objectclass=*)",NULL,attrs,0);
if(pSuffixSearch)
@@ -671,19 +671,21 @@ static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_ca
{
/* here's a suffix, lets search it... */
if(suffixVals[valIndex]->bv_val)
- if(!cos_cache_add_dn_defs(suffixVals[valIndex]->bv_val ,pDefs, vattr_cacheable))
+ {
+ if(!cos_cache_add_dn_defs(suffixVals[valIndex]->bv_val ,pDefs))
+ {
+ *vattr_cacheable = -1;
cos_def_available = 1;
-
+ break;
+ }
+ }
valIndex++;
}
-
-
ber_bvecfree( suffixVals );
suffixVals = NULL;
}
}
}
-
} while(!slapi_entry_next_attr(pSuffixList[suffixIndex], suffixAttr, &suffixAttr));
}
suffixIndex++;
@@ -709,7 +711,6 @@ next:
slapi_pblock_destroy(pSuffixSearch);
}
-
LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_build_definition_list\n",0,0,0);
return ret;
}
@@ -750,10 +751,6 @@ cos_dn_defs_cb (Slapi_Entry* e, void *callback_data)
char *norm_dn = NULL;
info=(struct dn_defs_info *)callback_data;
-
- /* assume cacheable */
- info->vattr_cacheable = -1;
-
cos_cache_add_attrval(&pDn, slapi_entry_get_dn(e));
if(slapi_entry_first_attr(e, &dnAttr)) {
goto bail;
@@ -1076,7 +1073,7 @@ bail:
#define DN_DEF_FILTER "(&(|(objectclass=cosSuperDefinition)(objectclass=cosDefinition))(objectclass=ldapsubentry))"
-static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs, int *vattr_cacheable)
+static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs)
{
Slapi_PBlock *pDnSearch = 0;
struct dn_defs_info info = {NULL, 0, 0};
@@ -1084,7 +1081,6 @@ static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs, int *vattr_ca
if (pDnSearch) {
info.ret=-1; /* assume no good defs */
info.pDefs=pDefs;
- info.vattr_cacheable = 0; /* assume not cacheable */
slapi_search_internal_set_pb(pDnSearch, dn, LDAP_SCOPE_SUBTREE,
DN_DEF_FILTER,NULL,0,
NULL,NULL,cos_get_plugin_identity(),0);
@@ -1096,8 +1092,6 @@ static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs, int *vattr_ca
slapi_pblock_destroy (pDnSearch);
}
- *vattr_cacheable = info.vattr_cacheable;
-
return info.ret;
}
9 years, 3 months
Branch '389-ds-base-1.3.3' - dirsrvtests/tickets ldap/servers
by Mark Reynolds
dirsrvtests/tickets/ticket47981_test.py | 345 ++++++++++++++++++++++++++++++++
ldap/servers/plugins/cos/cos_cache.c | 34 +--
2 files changed, 359 insertions(+), 20 deletions(-)
New commits:
commit 6229ad9a3d78cf6d83f09f2893c39dce5bbc71ca
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Wed Jan 7 08:59:06 2015 -0500
Ticket 47981 - COS cache doesn't properly mark vattr cache as
invalid when there are multiple suffixes
Bug Description: When rebuilding the COS cache, we check each suffix for COS entries.
If the last suffix checked does not contain any COS entries, then the
virtual attribute cache is incorrectly not invalidated. This allows
for already cached entries to hold onto the old COS attributes/values.
Fix Description: Only set the vattr_cacheable flag if a suffix contains COS entries, not
if it does not - by default the flag is not set.
https://fedorahosted.org/389/ticket/47981
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit 42e2df3858a4e14706d57b5c907d1d3768f4d970)
diff --git a/dirsrvtests/tickets/ticket47981_test.py b/dirsrvtests/tickets/ticket47981_test.py
new file mode 100644
index 0000000..2a16ce6
--- /dev/null
+++ b/dirsrvtests/tickets/ticket47981_test.py
@@ -0,0 +1,345 @@
+import os
+import sys
+import time
+import ldap
+import ldap.sasl
+import logging
+import socket
+import pytest
+from lib389 import DirSrv, Entry, tools, tasks
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from lib389.tasks import *
+from constants import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+BRANCH = 'ou=people,' + DEFAULT_SUFFIX
+USER_DN = 'uid=user1,%s' % (BRANCH)
+BRANCH_CONTAINER = 'cn=nsPwPolicyContainer,ou=people,dc=example,dc=com'
+BRANCH_COS_DEF = 'cn=nsPwPolicy_CoS,ou=people,dc=example,dc=com'
+BRANCH_PWP = 'cn=cn\\3DnsPwPolicyEntry\\2Cou\\3DPeople\\2Cdc\\3Dexample\\2Cdc\\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
+BRANCH_COS_TMPL = 'cn=cn\\3DnsPwTemplateEntry\\2Cou\\3DPeople\\2Cdc\\3Dexample\\2Cdc\\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
+SECOND_SUFFIX = 'o=netscaperoot'
+BE_NAME = 'netscaperoot'
+
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ At the beginning, It may exists a standalone instance.
+ It may also exists a backup for the standalone instance.
+
+ Principle:
+ If standalone instance exists:
+ restart it
+ If backup of standalone exists:
+ create/rebind to standalone
+
+ restore standalone instance from backup
+ else:
+ Cleanup everything
+ remove instance
+ remove backup
+ Create instance
+ Create backup
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the backups
+ backup_standalone = standalone.checkBackupFS()
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+ if instance_standalone:
+ # assuming the instance is already stopped, just wait 5 sec max
+ standalone.stop(timeout=5)
+ standalone.start(timeout=10)
+
+ if backup_standalone:
+ # The backup exist, assuming it is correct
+ # we just re-init the instance with it
+ if not instance_standalone:
+ standalone.create()
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # restore standalone instance from backup
+ standalone.stop(timeout=10)
+ standalone.restoreFS(backup_standalone)
+ standalone.start(timeout=10)
+
+ else:
+ # We should be here only in two conditions
+ # - This is the first time a test involve standalone instance
+ # - Something weird happened (instance/backup destroyed)
+ # so we discard everything and recreate all
+
+ # Remove the backup. So even if we have a specific backup file
+ # (e.g backup_standalone) we clear backup that an instance may have created
+ if backup_standalone:
+ standalone.clearBackupFS()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # Time to create the backups
+ standalone.stop(timeout=10)
+ standalone.backupfile = standalone.backupFS()
+ standalone.start(timeout=10)
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
+ #
+ # Here we have standalone instance up and running
+ # Either coming from a backup recovery
+ # or from a fresh (re)init
+ # Time to return the topology
+ return TopologyStandalone(standalone)
+
+
+def addSubtreePwPolicy(inst):
+ #
+ # Add subtree policy to the people branch
+ #
+ try:
+ inst.add_s(Entry((BRANCH_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for ou=people: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ inst.add_s(Entry((BRANCH_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ inst.add_s(Entry((BRANCH_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=people,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ inst.add_s(Entry((BRANCH_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'costemplatedn': BRANCH_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def: error ' + e.message['desc'])
+ assert False
+ time.sleep(0.5)
+
+
+def delSubtreePwPolicy(inst):
+ try:
+ inst.delete_s(BRANCH_COS_DEF)
+ except ldap.LDAPError, e:
+ log.error('Failed to delete COS def: error ' + e.message['desc'])
+ assert False
+
+ try:
+ inst.delete_s(BRANCH_COS_TMPL)
+ except ldap.LDAPError, e:
+ log.error('Failed to delete COS template: error ' + e.message['desc'])
+ assert False
+
+ try:
+ inst.delete_s(BRANCH_PWP)
+ except ldap.LDAPError, e:
+ log.error('Failed to delete COS password policy: error ' + e.message['desc'])
+ assert False
+
+ try:
+ inst.delete_s(BRANCH_CONTAINER)
+ except ldap.LDAPError, e:
+ log.error('Failed to delete COS container: error ' + e.message['desc'])
+ assert False
+ time.sleep(0.5)
+
+
+def test_ticket47981(topology):
+ """
+ If there are multiple suffixes, and the last suffix checked does not contain any COS entries,
+ while other suffixes do, then the vattr cache is not invalidated as it should be. Then any
+ cached entries will still contain the old COS attributes/values.
+ """
+
+ log.info('Testing Ticket 47981 - Test that COS def changes are correctly reflected in affected users')
+
+ #
+ # Create a second backend that does not have any COS entries
+ #
+ log.info('Adding second suffix that will not contain any COS entries...\n')
+
+ topology.standalone.backend.create(SECOND_SUFFIX, {BACKEND_NAME: BE_NAME})
+ topology.standalone.mappingtree.create(SECOND_SUFFIX, bename=BE_NAME)
+ try:
+ topology.standalone.add_s(Entry((SECOND_SUFFIX, {
+ 'objectclass': 'top organization'.split(),
+ 'o': BE_NAME})))
+ except ldap.ALREADY_EXISTS:
+ pass
+ except ldap.LDAPError, e:
+ log.error('Failed to create suffix entry: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add People branch, it might already exist
+ #
+ log.info('Add our test entries to the default suffix, and proceed with the test...')
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level4'
+ })))
+ except ldap.ALREADY_EXISTS:
+ pass
+ except ldap.LDAPError, e:
+ log.error('Failed to add ou=people: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add a user to the branch
+ #
+ try:
+ topology.standalone.add_s(Entry((USER_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user1'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user1: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Enable password policy and add the subtree policy
+ #
+ try:
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on')])
+ except ldap.LDAPError, e:
+ log.error('Failed to set pwpolicy-local: error ' + e.message['desc'])
+ assert False
+
+ addSubtreePwPolicy(topology.standalone)
+
+ #
+ # Now check the user has its expected passwordPolicy subentry
+ #
+ try:
+ entries = topology.standalone.search_s(USER_DN,
+ ldap.SCOPE_BASE,
+ '(objectclass=top)',
+ ['pwdpolicysubentry', 'dn'])
+ if not entries[0].hasAttr('pwdpolicysubentry'):
+ log.fatal('User does not have expected pwdpolicysubentry!')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER_DN, e.message['desc']))
+ assert False
+
+ #
+ # Delete the password policy and make sure it is removed from the same user
+ #
+ delSubtreePwPolicy(topology.standalone)
+ try:
+ entries = topology.standalone.search_s(USER_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if entries[0].hasAttr('pwdpolicysubentry'):
+ log.fatal('User unexpectedly does have the pwdpolicysubentry!')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER_DN, e.message['desc']))
+ assert False
+
+ #
+ # Add the subtree policvy back and see if the user now has it
+ #
+ addSubtreePwPolicy(topology.standalone)
+ try:
+ entries = topology.standalone.search_s(USER_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasAttr('pwdpolicysubentry'):
+ log.fatal('User does not have expected pwdpolicysubentry!')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER_DN, e.message['desc']))
+ assert False
+
+ # If we got here the test passed
+ log.info('Test PASSED')
+
+
+def test_ticket47981_final(topology):
+ topology.standalone.stop(timeout=10)
+
+
+def run_isolated():
+ '''
+ run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
+ To run isolated without py.test, you need to
+ - edit this file and comment '@pytest.fixture' line before 'topology' function.
+ - set the installation prefix
+ - run this program
+ '''
+ global installation_prefix
+ installation_prefix = None
+
+ topo = topology(True)
+ test_ticket47981(topo)
+
+if __name__ == '__main__':
+ run_isolated()
\ No newline at end of file
diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
index 0d9a61e..7d8e877 100644
--- a/ldap/servers/plugins/cos/cos_cache.c
+++ b/ldap/servers/plugins/cos/cos_cache.c
@@ -260,7 +260,7 @@ static int cos_cache_add_tmpl(cosTemplates **pTemplates, cosAttrValue *dn, cosAt
/* cosDefinitions manipulation */
static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_cacheable);
-static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs, int *vattr_cacheable);
+static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs);
static int cos_cache_add_defn(cosDefinitions **pDefs, cosAttrValue **dn, int cosType, cosAttrValue **tree, cosAttrValue **tmpDn, cosAttrValue **spec, cosAttrValue **pAttrs, cosAttrValue **pOverrides, cosAttrValue **pOperational, cosAttrValue **pCosMerge, cosAttrValue **pCosOpDefault);
static int cos_cache_entry_is_cos_related( Slapi_Entry *e);
@@ -619,9 +619,9 @@ static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_ca
LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_build_definition_list\n",0,0,0);
/*
- the class of service definitions may be anywhere in the DIT,
- so our first task is to find them.
- */
+ * The class of service definitions may be anywhere in the DIT,
+ * so our first task is to find them.
+ */
attrs[0] = "namingcontexts";
attrs[1] = 0;
@@ -629,9 +629,9 @@ static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_ca
LDAPDebug( LDAP_DEBUG_PLUGIN, "cos: Building class of service cache after status change.\n",0,0,0);
/*
- * XXXrbyrne: this looks really ineficient--should be using
+ * XXXrbyrne: this looks really inefficient--should be using
* slapi_get_next_suffix(), rather than searching for namingcontexts.
- */
+ */
pSuffixSearch = slapi_search_internal("",LDAP_SCOPE_BASE,"(objectclass=*)",NULL,attrs,0);
if(pSuffixSearch)
@@ -671,19 +671,21 @@ static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_ca
{
/* here's a suffix, lets search it... */
if(suffixVals[valIndex]->bv_val)
- if(!cos_cache_add_dn_defs(suffixVals[valIndex]->bv_val ,pDefs, vattr_cacheable))
+ {
+ if(!cos_cache_add_dn_defs(suffixVals[valIndex]->bv_val ,pDefs))
+ {
+ *vattr_cacheable = -1;
cos_def_available = 1;
-
+ break;
+ }
+ }
valIndex++;
}
-
-
ber_bvecfree( suffixVals );
suffixVals = NULL;
}
}
}
-
} while(!slapi_entry_next_attr(pSuffixList[suffixIndex], suffixAttr, &suffixAttr));
}
suffixIndex++;
@@ -709,7 +711,6 @@ next:
slapi_pblock_destroy(pSuffixSearch);
}
-
LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_build_definition_list\n",0,0,0);
return ret;
}
@@ -750,10 +751,6 @@ cos_dn_defs_cb (Slapi_Entry* e, void *callback_data)
char *norm_dn = NULL;
info=(struct dn_defs_info *)callback_data;
-
- /* assume cacheable */
- info->vattr_cacheable = -1;
-
cos_cache_add_attrval(&pDn, slapi_entry_get_dn(e));
if(slapi_entry_first_attr(e, &dnAttr)) {
goto bail;
@@ -1076,7 +1073,7 @@ bail:
#define DN_DEF_FILTER "(&(|(objectclass=cosSuperDefinition)(objectclass=cosDefinition))(objectclass=ldapsubentry))"
-static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs, int *vattr_cacheable)
+static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs)
{
Slapi_PBlock *pDnSearch = 0;
struct dn_defs_info info = {NULL, 0, 0};
@@ -1084,7 +1081,6 @@ static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs, int *vattr_ca
if (pDnSearch) {
info.ret=-1; /* assume no good defs */
info.pDefs=pDefs;
- info.vattr_cacheable = 0; /* assume not cacheable */
slapi_search_internal_set_pb(pDnSearch, dn, LDAP_SCOPE_SUBTREE,
DN_DEF_FILTER,NULL,0,
NULL,NULL,cos_get_plugin_identity(),0);
@@ -1096,8 +1092,6 @@ static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs, int *vattr_ca
slapi_pblock_destroy (pDnSearch);
}
- *vattr_cacheable = info.vattr_cacheable;
-
return info.ret;
}
9 years, 3 months
dirsrvtests/tickets ldap/servers
by Mark Reynolds
dirsrvtests/tickets/ticket47981_test.py | 345 ++++++++++++++++++++++++++++++++
ldap/servers/plugins/cos/cos_cache.c | 34 +--
2 files changed, 359 insertions(+), 20 deletions(-)
New commits:
commit 42e2df3858a4e14706d57b5c907d1d3768f4d970
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Wed Jan 7 08:59:06 2015 -0500
Ticket 47981 - COS cache doesn't properly mark vattr cache as
invalid when there are multiple suffixes
Bug Description: When rebuilding the COS cache, we check each suffix for COS entries.
If the last suffix checked does not contain any COS entries, then the
virtual attribute cache is incorrectly not invalidated. This allows
for already cached entries to hold onto the old COS attributes/values.
Fix Description: Only set the vattr_cacheable flag if a suffix contains COS entries, not
if it does not - by default the flag is not set.
https://fedorahosted.org/389/ticket/47981
Reviewed by: nhosoi(Thanks!)
diff --git a/dirsrvtests/tickets/ticket47981_test.py b/dirsrvtests/tickets/ticket47981_test.py
new file mode 100644
index 0000000..2a16ce6
--- /dev/null
+++ b/dirsrvtests/tickets/ticket47981_test.py
@@ -0,0 +1,345 @@
+import os
+import sys
+import time
+import ldap
+import ldap.sasl
+import logging
+import socket
+import pytest
+from lib389 import DirSrv, Entry, tools, tasks
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from lib389.tasks import *
+from constants import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+BRANCH = 'ou=people,' + DEFAULT_SUFFIX
+USER_DN = 'uid=user1,%s' % (BRANCH)
+BRANCH_CONTAINER = 'cn=nsPwPolicyContainer,ou=people,dc=example,dc=com'
+BRANCH_COS_DEF = 'cn=nsPwPolicy_CoS,ou=people,dc=example,dc=com'
+BRANCH_PWP = 'cn=cn\\3DnsPwPolicyEntry\\2Cou\\3DPeople\\2Cdc\\3Dexample\\2Cdc\\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
+BRANCH_COS_TMPL = 'cn=cn\\3DnsPwTemplateEntry\\2Cou\\3DPeople\\2Cdc\\3Dexample\\2Cdc\\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
+SECOND_SUFFIX = 'o=netscaperoot'
+BE_NAME = 'netscaperoot'
+
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ At the beginning, It may exists a standalone instance.
+ It may also exists a backup for the standalone instance.
+
+ Principle:
+ If standalone instance exists:
+ restart it
+ If backup of standalone exists:
+ create/rebind to standalone
+
+ restore standalone instance from backup
+ else:
+ Cleanup everything
+ remove instance
+ remove backup
+ Create instance
+ Create backup
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the backups
+ backup_standalone = standalone.checkBackupFS()
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+ if instance_standalone:
+ # assuming the instance is already stopped, just wait 5 sec max
+ standalone.stop(timeout=5)
+ standalone.start(timeout=10)
+
+ if backup_standalone:
+ # The backup exist, assuming it is correct
+ # we just re-init the instance with it
+ if not instance_standalone:
+ standalone.create()
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # restore standalone instance from backup
+ standalone.stop(timeout=10)
+ standalone.restoreFS(backup_standalone)
+ standalone.start(timeout=10)
+
+ else:
+ # We should be here only in two conditions
+ # - This is the first time a test involve standalone instance
+ # - Something weird happened (instance/backup destroyed)
+ # so we discard everything and recreate all
+
+ # Remove the backup. So even if we have a specific backup file
+ # (e.g backup_standalone) we clear backup that an instance may have created
+ if backup_standalone:
+ standalone.clearBackupFS()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # Time to create the backups
+ standalone.stop(timeout=10)
+ standalone.backupfile = standalone.backupFS()
+ standalone.start(timeout=10)
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
+ #
+ # Here we have standalone instance up and running
+ # Either coming from a backup recovery
+ # or from a fresh (re)init
+ # Time to return the topology
+ return TopologyStandalone(standalone)
+
+
+def addSubtreePwPolicy(inst):
+ #
+ # Add subtree policy to the people branch
+ #
+ try:
+ inst.add_s(Entry((BRANCH_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for ou=people: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ inst.add_s(Entry((BRANCH_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ inst.add_s(Entry((BRANCH_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=people,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ inst.add_s(Entry((BRANCH_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'costemplatedn': BRANCH_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def: error ' + e.message['desc'])
+ assert False
+ time.sleep(0.5)
+
+
+def delSubtreePwPolicy(inst):
+ try:
+ inst.delete_s(BRANCH_COS_DEF)
+ except ldap.LDAPError, e:
+ log.error('Failed to delete COS def: error ' + e.message['desc'])
+ assert False
+
+ try:
+ inst.delete_s(BRANCH_COS_TMPL)
+ except ldap.LDAPError, e:
+ log.error('Failed to delete COS template: error ' + e.message['desc'])
+ assert False
+
+ try:
+ inst.delete_s(BRANCH_PWP)
+ except ldap.LDAPError, e:
+ log.error('Failed to delete COS password policy: error ' + e.message['desc'])
+ assert False
+
+ try:
+ inst.delete_s(BRANCH_CONTAINER)
+ except ldap.LDAPError, e:
+ log.error('Failed to delete COS container: error ' + e.message['desc'])
+ assert False
+ time.sleep(0.5)
+
+
+def test_ticket47981(topology):
+ """
+ If there are multiple suffixes, and the last suffix checked does not contain any COS entries,
+ while other suffixes do, then the vattr cache is not invalidated as it should be. Then any
+ cached entries will still contain the old COS attributes/values.
+ """
+
+ log.info('Testing Ticket 47981 - Test that COS def changes are correctly reflected in affected users')
+
+ #
+ # Create a second backend that does not have any COS entries
+ #
+ log.info('Adding second suffix that will not contain any COS entries...\n')
+
+ topology.standalone.backend.create(SECOND_SUFFIX, {BACKEND_NAME: BE_NAME})
+ topology.standalone.mappingtree.create(SECOND_SUFFIX, bename=BE_NAME)
+ try:
+ topology.standalone.add_s(Entry((SECOND_SUFFIX, {
+ 'objectclass': 'top organization'.split(),
+ 'o': BE_NAME})))
+ except ldap.ALREADY_EXISTS:
+ pass
+ except ldap.LDAPError, e:
+ log.error('Failed to create suffix entry: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add People branch, it might already exist
+ #
+ log.info('Add our test entries to the default suffix, and proceed with the test...')
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level4'
+ })))
+ except ldap.ALREADY_EXISTS:
+ pass
+ except ldap.LDAPError, e:
+ log.error('Failed to add ou=people: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add a user to the branch
+ #
+ try:
+ topology.standalone.add_s(Entry((USER_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user1'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user1: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Enable password policy and add the subtree policy
+ #
+ try:
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on')])
+ except ldap.LDAPError, e:
+ log.error('Failed to set pwpolicy-local: error ' + e.message['desc'])
+ assert False
+
+ addSubtreePwPolicy(topology.standalone)
+
+ #
+ # Now check the user has its expected passwordPolicy subentry
+ #
+ try:
+ entries = topology.standalone.search_s(USER_DN,
+ ldap.SCOPE_BASE,
+ '(objectclass=top)',
+ ['pwdpolicysubentry', 'dn'])
+ if not entries[0].hasAttr('pwdpolicysubentry'):
+ log.fatal('User does not have expected pwdpolicysubentry!')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER_DN, e.message['desc']))
+ assert False
+
+ #
+ # Delete the password policy and make sure it is removed from the same user
+ #
+ delSubtreePwPolicy(topology.standalone)
+ try:
+ entries = topology.standalone.search_s(USER_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if entries[0].hasAttr('pwdpolicysubentry'):
+ log.fatal('User unexpectedly does have the pwdpolicysubentry!')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER_DN, e.message['desc']))
+ assert False
+
+ #
+ # Add the subtree policvy back and see if the user now has it
+ #
+ addSubtreePwPolicy(topology.standalone)
+ try:
+ entries = topology.standalone.search_s(USER_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasAttr('pwdpolicysubentry'):
+ log.fatal('User does not have expected pwdpolicysubentry!')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER_DN, e.message['desc']))
+ assert False
+
+ # If we got here the test passed
+ log.info('Test PASSED')
+
+
+def test_ticket47981_final(topology):
+ topology.standalone.stop(timeout=10)
+
+
+def run_isolated():
+ '''
+ run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
+ To run isolated without py.test, you need to
+ - edit this file and comment '@pytest.fixture' line before 'topology' function.
+ - set the installation prefix
+ - run this program
+ '''
+ global installation_prefix
+ installation_prefix = None
+
+ topo = topology(True)
+ test_ticket47981(topo)
+
+if __name__ == '__main__':
+ run_isolated()
\ No newline at end of file
diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
index 0d9a61e..7d8e877 100644
--- a/ldap/servers/plugins/cos/cos_cache.c
+++ b/ldap/servers/plugins/cos/cos_cache.c
@@ -260,7 +260,7 @@ static int cos_cache_add_tmpl(cosTemplates **pTemplates, cosAttrValue *dn, cosAt
/* cosDefinitions manipulation */
static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_cacheable);
-static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs, int *vattr_cacheable);
+static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs);
static int cos_cache_add_defn(cosDefinitions **pDefs, cosAttrValue **dn, int cosType, cosAttrValue **tree, cosAttrValue **tmpDn, cosAttrValue **spec, cosAttrValue **pAttrs, cosAttrValue **pOverrides, cosAttrValue **pOperational, cosAttrValue **pCosMerge, cosAttrValue **pCosOpDefault);
static int cos_cache_entry_is_cos_related( Slapi_Entry *e);
@@ -619,9 +619,9 @@ static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_ca
LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_build_definition_list\n",0,0,0);
/*
- the class of service definitions may be anywhere in the DIT,
- so our first task is to find them.
- */
+ * The class of service definitions may be anywhere in the DIT,
+ * so our first task is to find them.
+ */
attrs[0] = "namingcontexts";
attrs[1] = 0;
@@ -629,9 +629,9 @@ static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_ca
LDAPDebug( LDAP_DEBUG_PLUGIN, "cos: Building class of service cache after status change.\n",0,0,0);
/*
- * XXXrbyrne: this looks really ineficient--should be using
+ * XXXrbyrne: this looks really inefficient--should be using
* slapi_get_next_suffix(), rather than searching for namingcontexts.
- */
+ */
pSuffixSearch = slapi_search_internal("",LDAP_SCOPE_BASE,"(objectclass=*)",NULL,attrs,0);
if(pSuffixSearch)
@@ -671,19 +671,21 @@ static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_ca
{
/* here's a suffix, lets search it... */
if(suffixVals[valIndex]->bv_val)
- if(!cos_cache_add_dn_defs(suffixVals[valIndex]->bv_val ,pDefs, vattr_cacheable))
+ {
+ if(!cos_cache_add_dn_defs(suffixVals[valIndex]->bv_val ,pDefs))
+ {
+ *vattr_cacheable = -1;
cos_def_available = 1;
-
+ break;
+ }
+ }
valIndex++;
}
-
-
ber_bvecfree( suffixVals );
suffixVals = NULL;
}
}
}
-
} while(!slapi_entry_next_attr(pSuffixList[suffixIndex], suffixAttr, &suffixAttr));
}
suffixIndex++;
@@ -709,7 +711,6 @@ next:
slapi_pblock_destroy(pSuffixSearch);
}
-
LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_build_definition_list\n",0,0,0);
return ret;
}
@@ -750,10 +751,6 @@ cos_dn_defs_cb (Slapi_Entry* e, void *callback_data)
char *norm_dn = NULL;
info=(struct dn_defs_info *)callback_data;
-
- /* assume cacheable */
- info->vattr_cacheable = -1;
-
cos_cache_add_attrval(&pDn, slapi_entry_get_dn(e));
if(slapi_entry_first_attr(e, &dnAttr)) {
goto bail;
@@ -1076,7 +1073,7 @@ bail:
#define DN_DEF_FILTER "(&(|(objectclass=cosSuperDefinition)(objectclass=cosDefinition))(objectclass=ldapsubentry))"
-static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs, int *vattr_cacheable)
+static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs)
{
Slapi_PBlock *pDnSearch = 0;
struct dn_defs_info info = {NULL, 0, 0};
@@ -1084,7 +1081,6 @@ static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs, int *vattr_ca
if (pDnSearch) {
info.ret=-1; /* assume no good defs */
info.pDefs=pDefs;
- info.vattr_cacheable = 0; /* assume not cacheable */
slapi_search_internal_set_pb(pDnSearch, dn, LDAP_SCOPE_SUBTREE,
DN_DEF_FILTER,NULL,0,
NULL,NULL,cos_get_plugin_identity(),0);
@@ -1096,8 +1092,6 @@ static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs, int *vattr_ca
slapi_pblock_destroy (pDnSearch);
}
- *vattr_cacheable = info.vattr_cacheable;
-
return info.ret;
}
9 years, 3 months
Branch '389-ds-base-1.2.11' - 2 commits - ldap/servers
by Mark Reynolds
ldap/servers/slapd/dn.c | 28 ++++++++++++++++++++--------
1 file changed, 20 insertions(+), 8 deletions(-)
New commits:
commit c49b03070c275575ba879e4e9cee98fc038ce7e6
Author: Noriko Hosoi <nhosoi(a)totoro.usersys.redhat.com>
Date: Wed Sep 26 16:55:39 2012 -0700
Coverity defects
13093: Resource leak
Fix description: If udn is allocated in ndn_cache_lookup and it
has no chance to be consumed in ndn_cache_add, udn is released.
(cherry picked from commit 4754fb7da3066119576a115a04470b91c4184257)
Conflicts:
ldap/servers/slapd/dn.c
diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c
index 53c378a..9c1084f 100644
--- a/ldap/servers/slapd/dn.c
+++ b/ldap/servers/slapd/dn.c
@@ -535,7 +535,7 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
char *ends = NULL;
char *endd = NULL;
char *lastesc = NULL;
- char *udn;
+ char *udn = NULL;
/* rdn avs for the main DN */
char *typestart = NULL;
int rdn_av_count = 0;
@@ -1130,8 +1130,13 @@ bail:
*d = '\0';
}
/* add this dn to the normalized dn cache */
- if(*dest)
- ndn_cache_add(udn, src_len, *dest, *dest_len);
+ if (udn) {
+ if(dest && *dest && dest_len && *dest_len) {
+ ndn_cache_add(udn, src_len, *dest, *dest_len);
+ } else {
+ slapi_ch_free_string(&udn);
+ }
+ }
return rc;
}
@@ -2774,6 +2779,10 @@ ndn_cache_lookup(char *dn, size_t dn_len, char **result, char **udn, int *rc)
char *ndn, *key;
int rv = 0;
+ if(NULL == udn){
+ return rv;
+ }
+ *udn = NULL;
if(ndn_started == 0){
return rv;
}
commit 10ddfbc793a77f5c1a19302034239a53c07e3ab2
Author: Noriko Hosoi <nhosoi(a)totoro.usersys.redhat.com>
Date: Mon Jan 7 17:07:52 2013 -0800
Ticket #547 - Incorrect assumption in ndn cache
Bug Description: In ndn_cache_lookup, to determine the given dn
is already normalized or not, the length is compared with the
normalized dn length. If they match, it considers the given dn
is already normalized. But there are cases even if the lengths
are equal, the given dn may not be normalized yet.
(e.g., 'cn="o=ABC",o=XYZ' vs. 'cn=o\3DABC,o=XYZ')
Fix Description: This patch adds another check: if the dn and
normalized dn length match, call memcmp to compare the 2 dn's.
When memcmp returns 0, ndn_cache_lookup returns the passed dn.
https://fedorahosted.org/389/ticket/547
Reviewed by mreynolds (Thanks, Mark!).
(cherry picked from commit 0c44a46448595fdb1e079b5f4c91d4d8bfa2e0f2)
Conflicts:
ldap/servers/slapd/dn.c
diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c
index 283f265..53c378a 100644
--- a/ldap/servers/slapd/dn.c
+++ b/ldap/servers/slapd/dn.c
@@ -2788,16 +2788,19 @@ ndn_cache_lookup(char *dn, size_t dn_len, char **result, char **udn, int *rc)
if(ndn_ht_val){
ndn_cache_update_lru(&ndn_ht_val->lru_node);
slapi_counter_increment(ndn_cache->cache_hits);
- if(ndn_ht_val->len == dn_len ){
- /* the dn was already normalized, just return the dn as the result */
- *result = dn;
- *rc = 0;
- } else {
+ if ((ndn_ht_val->len != dn_len) ||
+ /* even if the lengths match, dn may not be normalized yet.
+ * (e.g., 'cn="o=ABC",o=XYZ' vs. 'cn=o\3DABC,o=XYZ') */
+ (memcmp(dn, ndn_ht_val->ndn, dn_len))){
*rc = 1; /* free result */
ndn = slapi_ch_malloc(ndn_ht_val->len + 1);
memcpy(ndn, ndn_ht_val->ndn, ndn_ht_val->len);
ndn[ndn_ht_val->len] = '\0';
*result = ndn;
+ } else {
+ /* the dn was already normalized, just return the dn as the result */
+ *result = dn;
+ *rc = 0;
}
rv = 1;
} else {
9 years, 4 months
Branch '389-ds-base-1.2.11' - ldap/admin
by Mark Reynolds
ldap/admin/src/scripts/template-bak2db.pl.in | 2 +
ldap/admin/src/scripts/template-cleanallruv.pl.in | 2 +
ldap/admin/src/scripts/template-db2bak.pl.in | 2 +
ldap/admin/src/scripts/template-db2index.pl.in | 2 +
ldap/admin/src/scripts/template-db2ldif.pl.in | 2 +
ldap/admin/src/scripts/template-fixup-linkedattrs.pl.in | 2 +
ldap/admin/src/scripts/template-fixup-memberof.pl.in | 2 +
ldap/admin/src/scripts/template-ldif2db.pl.in | 2 +
ldap/admin/src/scripts/template-ns-newpwpolicy.pl.in | 13 ++++++------
ldap/admin/src/scripts/template-schema-reload.pl.in | 2 +
ldap/admin/src/scripts/template-syntax-validate.pl.in | 2 +
ldap/admin/src/scripts/template-usn-tombstone-cleanup.pl.in | 2 +
12 files changed, 29 insertions(+), 6 deletions(-)
New commits:
commit d8e79122c33e619f0950503a3a3b9a4b38f20e54
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Wed Dec 17 11:56:42 2014 -0500
Ticket 47962 - perl scripts not returning expected error code
Bug Description: WHne one o the instance perl scripts fails, it either
returns sucess, or the wrong the error code.
Fix Description: The perl scripts need to bit shift the result code by 8,
and return the result.
https://fedorahosted.org/389/ticket/47962
Reviewed by: rmeggins(Thanks!)
diff --git a/ldap/admin/src/scripts/template-bak2db.pl.in b/ldap/admin/src/scripts/template-bak2db.pl.in
index 4ab79cc..2f243ba 100644
--- a/ldap/admin/src/scripts/template-bak2db.pl.in
+++ b/ldap/admin/src/scripts/template-bak2db.pl.in
@@ -135,6 +135,8 @@ $ENV{'SHLIB_PATH'} = "$ENV{'LD_LIBRARY_PATH'}";
open(FOO, "| ldapmodify @ldaptool_opts@ $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
print(FOO "$entry");
close(FOO);
+$retcode = $?>>8;
+exit ($retcode);
sub libpath_add {
my $libpath = shift;
diff --git a/ldap/admin/src/scripts/template-cleanallruv.pl.in b/ldap/admin/src/scripts/template-cleanallruv.pl.in
index be95a6d..437a3c0 100644
--- a/ldap/admin/src/scripts/template-cleanallruv.pl.in
+++ b/ldap/admin/src/scripts/template-cleanallruv.pl.in
@@ -171,6 +171,8 @@ $entry = "${dn}${misc}${cn}${basedn}${rid}";
open(FOO, "| ldapmodify @ldaptool_opts@ $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
print(FOO "$entry");
close(FOO);
+$retcode = $?>>8;
+exit ($retcode);
sub libpath_add {
my $libpath = shift;
diff --git a/ldap/admin/src/scripts/template-db2bak.pl.in b/ldap/admin/src/scripts/template-db2bak.pl.in
index 8a0cb1c..329664f 100644
--- a/ldap/admin/src/scripts/template-db2bak.pl.in
+++ b/ldap/admin/src/scripts/template-db2bak.pl.in
@@ -125,6 +125,8 @@ print("Back up directory: $archivedir\n");
open(FOO, "| ldapmodify @ldaptool_opts@ $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
print(FOO "$entry");
close(FOO);
+$retcode = $?>>8;
+exit ($retcode);
sub libpath_add {
my $libpath = shift;
diff --git a/ldap/admin/src/scripts/template-db2index.pl.in b/ldap/admin/src/scripts/template-db2index.pl.in
index e598b05..39454c5 100644
--- a/ldap/admin/src/scripts/template-db2index.pl.in
+++ b/ldap/admin/src/scripts/template-db2index.pl.in
@@ -229,6 +229,8 @@ $entry = "${dn}${misc}${cn}${nsinstance}${attribute}${vlvattribute}";
open(FOO, "| ldapmodify @ldaptool_opts@ $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
print(FOO "$entry");
close(FOO);
+$retcode = $?>>8;
+exit ($retcode);
sub libpath_add {
my $libpath = shift;
diff --git a/ldap/admin/src/scripts/template-db2ldif.pl.in b/ldap/admin/src/scripts/template-db2ldif.pl.in
index a4929ba..febedd4 100644
--- a/ldap/admin/src/scripts/template-db2ldif.pl.in
+++ b/ldap/admin/src/scripts/template-db2ldif.pl.in
@@ -269,6 +269,8 @@ print("Exporting to ldif file: ${ldiffile}\n");
open(FOO, "| ldapmodify @ldaptool_opts@ $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
print(FOO "$entry");
close(FOO);
+$retcode = $?>>8;
+exit ($retcode);
sub libpath_add {
my $libpath = shift;
diff --git a/ldap/admin/src/scripts/template-fixup-linkedattrs.pl.in b/ldap/admin/src/scripts/template-fixup-linkedattrs.pl.in
index f181a7a..67f0b31 100644
--- a/ldap/admin/src/scripts/template-fixup-linkedattrs.pl.in
+++ b/ldap/admin/src/scripts/template-fixup-linkedattrs.pl.in
@@ -155,6 +155,8 @@ $entry = "${dn}${misc}${cn}${basedn}${linkdn}";
open(FOO, "| ldapmodify @ldaptool_opts@ $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
print(FOO "$entry");
close(FOO);
+$retcode = $?>>8;
+exit ($retcode);
sub libpath_add {
my $libpath = shift;
diff --git a/ldap/admin/src/scripts/template-fixup-memberof.pl.in b/ldap/admin/src/scripts/template-fixup-memberof.pl.in
index b43c21a..77a1528 100644
--- a/ldap/admin/src/scripts/template-fixup-memberof.pl.in
+++ b/ldap/admin/src/scripts/template-fixup-memberof.pl.in
@@ -166,6 +166,8 @@ $entry = "${dn}${misc}${cn}${basedn}${filter}";
open(FOO, "| ldapmodify @ldaptool_opts@ $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
print(FOO "$entry");
close(FOO);
+$retcode = $?>>8;
+exit ($retcode);
sub libpath_add {
my $libpath = shift;
diff --git a/ldap/admin/src/scripts/template-ldif2db.pl.in b/ldap/admin/src/scripts/template-ldif2db.pl.in
index 089c95d..1cf83b4 100644
--- a/ldap/admin/src/scripts/template-ldif2db.pl.in
+++ b/ldap/admin/src/scripts/template-ldif2db.pl.in
@@ -227,6 +227,8 @@ $ENV{'SHLIB_PATH'} = "$ENV{'LD_LIBRARY_PATH'}";
open(FOO, "| ldapmodify @ldaptool_opts@ $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
print(FOO "$entry");
close(FOO);
+$retcode = $?>>8;
+exit ($retcode);
sub libpath_add {
my $libpath = shift;
diff --git a/ldap/admin/src/scripts/template-ns-newpwpolicy.pl.in b/ldap/admin/src/scripts/template-ns-newpwpolicy.pl.in
index 50ce047..bd9b238 100755
--- a/ldap/admin/src/scripts/template-ns-newpwpolicy.pl.in
+++ b/ldap/admin/src/scripts/template-ns-newpwpolicy.pl.in
@@ -186,9 +186,9 @@ sub usage {
open(FD,"| $modifyCfg ");
print(FD $modConfig);
close(FD);
- $retcode = $?;
+ $retcode = $?>>8;
if ( $retcode != 0 ) {
- print( STDERR "Error $retcode while modifing \"cn=config\". Exiting.\n" );
+ print( STDERR "Error $retcode while modifying \"cn=config\". Exiting.\n" );
exit ($retcode);
}
else {
@@ -203,6 +203,7 @@ sub usage {
$esc_opt_U =~ s/=/\\=/g;
print (STDERR "host = $opt_h, port = $opt_p, userDN = \"$norm_opt_U\"\n\n") if $opt_v;
$retcode = `$ldapsearch -h $opt_h -p $opt_p -b \"$norm_opt_U\" -s base \"\"`;
+ $retcode = $retcode>>8;
if ($retcode != 0 ) {
print( STDERR "the user entry $norm_opt_U does not exist. Exiting.\n");
exit ($retcode);
@@ -267,9 +268,9 @@ sub usage {
open(FD,"| $modifyCfg ");
print(FD $modConfig);
close(FD);
- $retcode = $?;
+ $retcode = $?>>8;
if ( $retcode != 0 ) {
- print( STDERR "Error $retcode while modifing $norm_opt_U. Exiting.\n" );
+ print( STDERR "Error $retcode while modifying $norm_opt_U. Exiting.\n" );
exit ($retcode);
}
else {
@@ -280,9 +281,9 @@ sub usage {
open(FD,"| $modifyCfg ");
print(FD $modConfig);
close(FD);
- $retcode = $?;
+ $retcode = $?>>8;
if ( $retcode != 0 ) {
- print( STDERR "Error $retcode while modifing \"cn=config\". Exiting.\n" );
+ print( STDERR "Error $retcode while modifying \"cn=config\". Exiting.\n" );
exit ($retcode);
}
else {
diff --git a/ldap/admin/src/scripts/template-schema-reload.pl.in b/ldap/admin/src/scripts/template-schema-reload.pl.in
index f7a1dbb..6b64b5e 100644
--- a/ldap/admin/src/scripts/template-schema-reload.pl.in
+++ b/ldap/admin/src/scripts/template-schema-reload.pl.in
@@ -155,6 +155,8 @@ $entry = "${dn}${misc}${cn}${basedn}${schemadir}";
open(FOO, "| ldapmodify @ldaptool_opts@ $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
print(FOO "$entry");
close(FOO);
+$retcode = $?>>8;
+exit ($retcode);
sub libpath_add {
my $libpath = shift;
diff --git a/ldap/admin/src/scripts/template-syntax-validate.pl.in b/ldap/admin/src/scripts/template-syntax-validate.pl.in
index b87e12d..b40ef69 100644
--- a/ldap/admin/src/scripts/template-syntax-validate.pl.in
+++ b/ldap/admin/src/scripts/template-syntax-validate.pl.in
@@ -166,6 +166,8 @@ $entry = "${dn}${misc}${cn}${basedn}${filter}";
open(FOO, "| ldapmodify @ldaptool_opts@ $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
print(FOO "$entry");
close(FOO);
+$retcode = $?>>8;
+exit ($retcode);
sub libpath_add {
my $libpath = shift;
diff --git a/ldap/admin/src/scripts/template-usn-tombstone-cleanup.pl.in b/ldap/admin/src/scripts/template-usn-tombstone-cleanup.pl.in
index 3e17be0..92c106d 100644
--- a/ldap/admin/src/scripts/template-usn-tombstone-cleanup.pl.in
+++ b/ldap/admin/src/scripts/template-usn-tombstone-cleanup.pl.in
@@ -183,6 +183,8 @@ $entry = "${dn}${misc}${cn}${basedn}${args}";
open(FOO, "| ldapmodify @ldaptool_opts@ $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
print(FOO "$entry");
close(FOO);
+$retcode = $?>>8;
+exit ($retcode);
sub libpath_add {
my $libpath = shift;
9 years, 4 months
ldap/servers
by Noriko Hosoi
ldap/servers/slapd/back-ldbm/back-ldbm.h | 4 -
ldap/servers/slapd/back-ldbm/dblayer.c | 71 +++++++++++++++++--------------
ldap/servers/slapd/back-ldbm/vlv.c | 24 ++++++++--
ldap/servers/slapd/back-ldbm/vlv_srch.c | 17 +++----
4 files changed, 70 insertions(+), 46 deletions(-)
New commits:
commit ebf24ffd5ac79adcb288960377605feb60c52d7f
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Mon Jan 5 13:07:07 2015 -0800
Ticket #47966 - slapd crashes during Dogtag clone reinstallation
Bug description: There were 2 VLV index issues.
1) When a VLV index is removed, it did not call dblayer_erase_index_file_
nolock, which removes the physical index file as well as a back pointer
set to the dblayer handle. The back pointer is scanned at the backend
close time where the garbage address is used to close the already removed
vlv index.
2) VLV plugin callbacks are registered in vlv_init. The function could be
called multiple times without unregster the VLV plugin callbacks, e.g.,
from bulk import, which reopens the backend instance. If create an
instance and a vlv index, then initialize the database with bulk import,
2 VLV index callbacks are registered. The first set points the old instance
address, which is already freed.
Note: the unregister callback functions are called only when the instance
is deleted in vlv_remove_callbacks via ldbm_instance_unregister_callbacks.
The callback is set as the post delete plugin with "(objectclass=nsBackendInstance)".
Fix description:
1) When a VLV index is removed, it calls dblayer_erase_index_file_nolock.
2) Before registering VLV plugin callbacks, calling unregister callbacks to
make sure cleaning up the existing callbacks.
https://fedorahosted.org/389/ticket/47966
Reviewed by rmeggins(a)redhat.com and mreynolds(a)redhat.com (Thank you, Rich and Mark!!)
diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h b/ldap/servers/slapd/back-ldbm/back-ldbm.h
index fd17453..b3badbc 100644
--- a/ldap/servers/slapd/back-ldbm/back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h
@@ -718,15 +718,15 @@ typedef struct _modify_context modify_context;
/* This structure was moved here from dblayer.c because the ldbm_instance
* structure uses the dblayer_handle structure. */
-struct tag_dblayer_handle; typedef struct tag_dblayer_handle dblayer_handle;
struct tag_dblayer_handle
{
DB* dblayer_dbp;
PRLock *dblayer_lock; /* used when anyone wants exclusive access to a file */
- dblayer_handle *dblayer_handle_next;
+ struct tag_dblayer_handle *dblayer_handle_next;
void **dblayer_handle_ai_backpointer; /* Voodo magic pointer to the place where we store a
pointer to this handle in the attrinfo structure */
};
+typedef struct tag_dblayer_handle dblayer_handle;
/* This structure was moved here from perfctrs.c so the ldbm_instance structure
* could use it. */
diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c
index 2524355..e7339fb 100644
--- a/ldap/servers/slapd/back-ldbm/dblayer.c
+++ b/ldap/servers/slapd/back-ldbm/dblayer.c
@@ -2740,7 +2740,7 @@ int dblayer_close_indexes(backend *be)
pDB = handle->dblayer_dbp;
return_value |= pDB->close(pDB,0);
next = handle->dblayer_handle_next;
- *(handle->dblayer_handle_ai_backpointer) = NULL;
+ *((dblayer_handle **)handle->dblayer_handle_ai_backpointer) = NULL;
slapi_ch_free((void**)&handle);
}
@@ -3341,39 +3341,32 @@ int dblayer_get_index_file(backend *be, struct attrinfo *a, DB** ppDB, int open_
a, &pDB);
if (0 == return_value) {
/* Opened it OK */
- dblayer_handle *handle = (dblayer_handle *)
- slapi_ch_calloc(1, sizeof(dblayer_handle));
-
- if (NULL == handle) {
- /* Memory allocation failed */
- return_value = -1;
- } else {
- dblayer_handle *prev_handle = inst->inst_handle_tail;
+ dblayer_handle *handle = (dblayer_handle *)slapi_ch_calloc(1, sizeof(dblayer_handle));
+ dblayer_handle *prev_handle = inst->inst_handle_tail;
- PR_ASSERT(NULL != pDB);
- /* Store the returned DB* in our own private list of
- * open files */
- if (NULL == prev_handle) {
+ PR_ASSERT(NULL != pDB);
+ /* Store the returned DB* in our own private list of
+ * open files */
+ if (NULL == prev_handle) {
/* List was empty */
inst->inst_handle_tail = handle;
inst->inst_handle_head = handle;
- } else {
+ } else {
/* Chain the handle onto the last structure in the
* list */
inst->inst_handle_tail = handle;
prev_handle->dblayer_handle_next = handle;
- }
- /* Stash a pointer to our wrapper structure in the
- * attrinfo structure */
- handle->dblayer_dbp = pDB;
- /* And, most importantly, return something to the caller!*/
- *ppDB = pDB;
- /* and save the hande in the attrinfo structure for
- * next time */
- a->ai_dblayer = handle;
- /* don't need to update count -- we incr'd it already */
- handle->dblayer_handle_ai_backpointer = &(a->ai_dblayer);
}
+ /* Stash a pointer to our wrapper structure in the
+ * attrinfo structure */
+ handle->dblayer_dbp = pDB;
+ /* And, most importantly, return something to the caller!*/
+ *ppDB = pDB;
+ /* and save the hande in the attrinfo structure for
+ * next time */
+ a->ai_dblayer = handle;
+ /* don't need to update count -- we incr'd it already */
+ handle->dblayer_handle_ai_backpointer = &(a->ai_dblayer);
} else {
/* Did not open it OK ! */
/* Do nothing, because return value and fact that we didn't
@@ -3445,10 +3438,10 @@ dblayer_db_remove(dblayer_private_env * env, char const path[], char const dbNam
int dblayer_erase_index_file_ex(backend *be, struct attrinfo *a,
PRBool use_lock, int no_force_checkpoint)
{
- struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
- dblayer_private *priv = (dblayer_private*) li->li_dblayer_private;
- struct dblayer_private_env *pEnv = priv->dblayer_env;
- ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ struct ldbminfo *li = NULL;
+ dblayer_private *priv = NULL;
+ struct dblayer_private_env *pEnv = NULL;
+ ldbm_instance *inst = NULL;
dblayer_handle *handle = NULL;
char dbName[MAXPATHLEN];
char *dbNamep;
@@ -3457,9 +3450,25 @@ int dblayer_erase_index_file_ex(backend *be, struct attrinfo *a,
int rc = 0;
DB *db = 0;
- if (NULL == pEnv) /* db does not exist */
+ if ((NULL == be) || (NULL == be->be_database)) {
return rc;
-
+ }
+ inst = (ldbm_instance *)be->be_instance_info;
+ if (NULL == inst) {
+ return rc;
+ }
+ li = (struct ldbminfo *)be->be_database->plg_private;
+ if (NULL == li) {
+ return rc;
+ }
+ priv = (dblayer_private*)li->li_dblayer_private;
+ if (NULL == priv) {
+ return rc;
+ }
+ pEnv = priv->dblayer_env;
+ if (NULL == pEnv) { /* db does not exist */
+ return rc;
+ }
/* Added for bug 600401. Somehow the checkpoint thread deadlocked on
index file with this function, index file couldn't be removed on win2k.
Force a checkpoint here to break deadlock.
diff --git a/ldap/servers/slapd/back-ldbm/vlv.c b/ldap/servers/slapd/back-ldbm/vlv.c
index d061bf2..384fd46 100644
--- a/ldap/servers/slapd/back-ldbm/vlv.c
+++ b/ldap/servers/slapd/back-ldbm/vlv.c
@@ -74,7 +74,10 @@ int vlv_AddSearchEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
{
ldbm_instance *inst = (ldbm_instance *)arg;
struct vlvSearch* newVlvSearch= vlvSearch_new();
- backend *be = inst->inst_be;
+ backend *be = NULL;
+ if (inst) {
+ be = inst->inst_be;
+ }
if (NULL == be) { /* backend is not associated */
vlvSearch_delete(&newVlvSearch);
@@ -427,8 +430,19 @@ vlv_init(ldbm_instance *inst)
}
/* Only need to register these callbacks for SLAPD mode... */
- if(basedn!=NULL)
+ if(basedn)
{
+ /* In case the vlv indexes are already registered, clean them up before register them. */
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_SearchIndexEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_ADD,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_AddSearchEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_ADD,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_AddIndexEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_ModifySearchEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_ModifyIndexEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_DeleteSearchEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_DeleteIndexEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_ModifyRDNSearchEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_ModifyRDNIndexEntry);
+
slapi_config_register_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_SearchIndexEntry,(void*)inst);
slapi_config_register_callback(SLAPI_OPERATION_ADD,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_AddSearchEntry,(void*)inst);
slapi_config_register_callback(SLAPI_OPERATION_ADD,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_AddIndexEntry,(void*)inst);
@@ -438,7 +452,7 @@ vlv_init(ldbm_instance *inst)
slapi_config_register_callback(SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_DeleteIndexEntry,(void*)inst);
slapi_config_register_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_ModifyRDNSearchEntry,(void*)inst);
slapi_config_register_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_ModifyRDNIndexEntry,(void*)inst);
- slapi_ch_free_string(&basedn);
+ slapi_ch_free_string(&basedn);
}
out:
@@ -448,8 +462,8 @@ out:
/* Removes callbacks from above when instance is removed. */
int
-vlv_remove_callbacks(ldbm_instance *inst) {
-
+vlv_remove_callbacks(ldbm_instance *inst)
+{
int return_value= LDAP_SUCCESS;
int scope= LDAP_SCOPE_SUBTREE;
char *basedn = NULL;
diff --git a/ldap/servers/slapd/back-ldbm/vlv_srch.c b/ldap/servers/slapd/back-ldbm/vlv_srch.c
index d7e28c1..bd94865 100644
--- a/ldap/servers/slapd/back-ldbm/vlv_srch.c
+++ b/ldap/servers/slapd/back-ldbm/vlv_srch.c
@@ -572,6 +572,7 @@ vlvIndex_delete(struct vlvIndex** ppvs)
}
}
internal_ldap_free_sort_keylist((*ppvs)->vlv_sortkey);
+ dblayer_erase_index_file_nolock((*ppvs)->vlv_be, (*ppvs)->vlv_attrinfo, 1 /* chkpt if not busy */);
attrinfo_delete(&((*ppvs)->vlv_attrinfo));
slapi_ch_free((void**)&((*ppvs)->vlv_name));
slapi_ch_free((void**)&((*ppvs)->vlv_filename));
@@ -618,7 +619,7 @@ vlvIndex_init(struct vlvIndex* p, backend *be, struct vlvSearch* pSearch, const
{
if(p->vlv_sortkey[n]->sk_matchruleoid!=NULL)
{
- create_matchrule_indexer(&p->vlv_mrpb[n],p->vlv_sortkey[n]->sk_matchruleoid,p->vlv_sortkey[n]->sk_attrtype);
+ create_matchrule_indexer(&p->vlv_mrpb[n],p->vlv_sortkey[n]->sk_matchruleoid,p->vlv_sortkey[n]->sk_attrtype);
}
}
@@ -632,7 +633,7 @@ vlvIndex_init(struct vlvIndex* p, backend *be, struct vlvSearch* pSearch, const
/* Create an attrinfo structure */
p->vlv_attrinfo->ai_type= slapi_ch_smprintf("%s%s",file_prefix,filename);
- p->vlv_attrinfo->ai_indexmask= INDEX_VLV;
+ p->vlv_attrinfo->ai_indexmask= INDEX_VLV;
/* Check if the index file actually exists */
if(li!=NULL)
@@ -657,14 +658,14 @@ vlvIndex_get_indexlength(struct vlvIndex* p, DB *db, back_txn *txn)
if(!p->vlv_indexlength_cached)
{
- DBC *dbc = NULL;
- DB_TXN *db_txn = NULL;
+ DBC *dbc = NULL;
+ DB_TXN *db_txn = NULL;
int err= 0;
- if (NULL != txn)
+ if (NULL != txn)
{
- db_txn = txn->back_txn_txn;
+ db_txn = txn->back_txn_txn;
}
- err = db->cursor(db, db_txn, &dbc, 0);
+ err = db->cursor(db, db_txn, &dbc, 0);
if(err==0)
{
DBT key= {0};
@@ -924,7 +925,7 @@ vlvIndex_createfilename(struct vlvIndex* pIndex, char **ppc)
*p= '\0';
if(strlen(filename)==0)
{
- LDAPDebug( LDAP_DEBUG_ANY, "Couldn't generate valid filename from Virtual List View Index Name (%s). Need some alphabetical characters.\n", pIndex->vlv_name, 0, 0);
+ LDAPDebug( LDAP_DEBUG_ANY, "Couldn't generate valid filename from Virtual List View Index Name (%s). Need some alphabetical characters.\n", pIndex->vlv_name, 0, 0);
filenameValid= 0;
}
/* JCM: Check if this file clashes with another VLV Index filename */
9 years, 4 months
Branch '389-ds-base-1.2.11' - dirsrvtests/tickets ldap/servers
by Mark Reynolds
dirsrvtests/tickets/ticket47980_test.py | 710 ++++++++++++++++++++++++++++++++
ldap/servers/plugins/cos/cos_cache.c | 20
2 files changed, 717 insertions(+), 13 deletions(-)
New commits:
commit 322d7d0dabb0b3cf52a0c544f0e4fb09e9af9080
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Jan 5 16:56:09 2015 -0500
Ticket 47980 - Nested COS definitions can be incorrectly
processed
Bug Description: The COS cache attribute index gets incorrectly sorted
and results in unexpected COS values being applied to
an entry.
Fix Description: The sorting method for comparing the target tree does
not work as indended, but we don't need to sort by the
target tree if the cos attributes are the same, as the
list is already in the proper tree order as returned by
the internal search. The fix was just to remove the
target tree comparison from the qsort compare function.
https://fedorahosted.org/389/ticket/47980
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit 987580d6fb42e358d84539a78879ae9a00393bd1)
diff --git a/dirsrvtests/tickets/ticket47980_test.py b/dirsrvtests/tickets/ticket47980_test.py
new file mode 100644
index 0000000..406d72d
--- /dev/null
+++ b/dirsrvtests/tickets/ticket47980_test.py
@@ -0,0 +1,710 @@
+import os
+import sys
+import time
+import ldap
+import ldap.sasl
+import logging
+import socket
+import pytest
+from lib389 import DirSrv, Entry, tools, tasks
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from lib389.tasks import *
+from constants import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+BRANCH1 = 'ou=level1,' + DEFAULT_SUFFIX
+BRANCH2 = 'ou=level2,ou=level1,' + DEFAULT_SUFFIX
+BRANCH3 = 'ou=level3,ou=level2,ou=level1,' + DEFAULT_SUFFIX
+BRANCH4 = 'ou=people,' + DEFAULT_SUFFIX
+BRANCH5 = 'ou=lower,ou=people,' + DEFAULT_SUFFIX
+BRANCH6 = 'ou=lower,ou=lower,ou=people,' + DEFAULT_SUFFIX
+USER1_DN = 'uid=user1,%s' % (BRANCH1)
+USER2_DN = 'uid=user2,%s' % (BRANCH2)
+USER3_DN = 'uid=user3,%s' % (BRANCH3)
+USER4_DN = 'uid=user4,%s' % (BRANCH4)
+USER5_DN = 'uid=user5,%s' % (BRANCH5)
+USER6_DN = 'uid=user6,%s' % (BRANCH6)
+
+BRANCH1_CONTAINER = 'cn=nsPwPolicyContainer,ou=level1,dc=example,dc=com'
+BRANCH1_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level1,dc=example,dc=com'
+BRANCH1_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level1,dc=example,dc=com'
+BRANCH1_COS_DEF = 'cn=nsPwPolicy_CoS,ou=level1,dc=example,dc=com'
+
+BRANCH2_CONTAINER = 'cn=nsPwPolicyContainer,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH2_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH2_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH2_COS_DEF = 'cn=nsPwPolicy_CoS,ou=level2,ou=level1,dc=example,dc=com'
+
+BRANCH3_CONTAINER = 'cn=nsPwPolicyContainer,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH3_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlevel3\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH3_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlevel3\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH3_COS_DEF = 'cn=nsPwPolicy_CoS,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+
+BRANCH4_CONTAINER = 'cn=nsPwPolicyContainer,ou=people,dc=example,dc=com'
+BRANCH4_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
+BRANCH4_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
+BRANCH4_COS_DEF = 'cn=nsPwPolicy_CoS,ou=people,dc=example,dc=com'
+
+BRANCH5_CONTAINER = 'cn=nsPwPolicyContainer,ou=lower,ou=people,dc=example,dc=com'
+BRANCH5_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=People,dc=example,dc=com'
+BRANCH5_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=People,dc=example,dc=com'
+BRANCH5_COS_DEF = 'cn=nsPwPolicy_CoS,ou=lower,ou=People,dc=example,dc=com'
+
+BRANCH6_CONTAINER = 'cn=nsPwPolicyContainer,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+BRANCH6_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlower\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+BRANCH6_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlower\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+BRANCH6_COS_DEF = 'cn=nsPwPolicy_CoS,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ At the beginning, It may exists a standalone instance.
+ It may also exists a backup for the standalone instance.
+
+ Principle:
+ If standalone instance exists:
+ restart it
+ If backup of standalone exists:
+ create/rebind to standalone
+
+ restore standalone instance from backup
+ else:
+ Cleanup everything
+ remove instance
+ remove backup
+ Create instance
+ Create backup
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the backups
+ backup_standalone = standalone.checkBackupFS()
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+ if instance_standalone:
+ # assuming the instance is already stopped, just wait 5 sec max
+ standalone.stop(timeout=5)
+ standalone.start(timeout=10)
+
+ if backup_standalone:
+ # The backup exist, assuming it is correct
+ # we just re-init the instance with it
+ if not instance_standalone:
+ standalone.create()
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # restore standalone instance from backup
+ standalone.stop(timeout=10)
+ standalone.restoreFS(backup_standalone)
+ standalone.start(timeout=10)
+
+ else:
+ # We should be here only in two conditions
+ # - This is the first time a test involve standalone instance
+ # - Something weird happened (instance/backup destroyed)
+ # so we discard everything and recreate all
+
+ # Remove the backup. So even if we have a specific backup file
+ # (e.g backup_standalone) we clear backup that an instance may have created
+ if backup_standalone:
+ standalone.clearBackupFS()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # Time to create the backups
+ standalone.stop(timeout=10)
+ standalone.backupfile = standalone.backupFS()
+ standalone.start(timeout=10)
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
+ #
+ # Here we have standalone instance up and running
+ # Either coming from a backup recovery
+ # or from a fresh (re)init
+ # Time to return the topology
+ return TopologyStandalone(standalone)
+
+
+def test_ticket47980(topology):
+ """
+ Multiple COS pointer definitions that use the same attribute are not correctly ordered.
+ The cos plugin was incorrectly sorting the attribute indexes based on subtree, which lead
+ to the wrong cos attribute value being applied to the entry.
+ """
+
+ log.info('Testing Ticket 47980 - Testing multiple nested COS pointer definitions are processed correctly')
+
+ # Add our nested branches
+ try:
+ topology.standalone.add_s(Entry((BRANCH1, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level1'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level1: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH2, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level2'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level2: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH3, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'level3'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level3: error ' + e.message['desc'])
+ assert False
+
+ # People branch, might already exist
+ try:
+ topology.standalone.add_s(Entry((BRANCH4, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level4'
+ })))
+ except ldap.ALREADY_EXISTS:
+ pass
+ except ldap.LDAPError, e:
+ log.error('Failed to add level4: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH5, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level5'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level5: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH6, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'level6'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level6: error ' + e.message['desc'])
+ assert False
+
+ # Add users to each branch
+ try:
+ topology.standalone.add_s(Entry((USER1_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user1'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user1: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER2_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user2'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user2: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER3_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user3'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user3: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER4_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user4'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user4: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER5_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user5'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user5: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER6_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user6'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user6: error ' + e.message['desc'])
+ assert False
+
+ # Enable password policy
+ try:
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on')])
+ except ldap.LDAPError, e:
+ log.error('Failed to set pwpolicy-local: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 1
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level1: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level1,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for level1: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level1,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=level1,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH1_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level1: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level1,dc=example,dc=com',
+ 'costemplatedn': BRANCH1_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level1: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 2
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level2: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level2,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for level2: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level2,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=level2,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH2_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level2: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level2,dc=example,dc=com',
+ 'costemplatedn': BRANCH2_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level2: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 3
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=level3,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH3_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'costemplatedn': BRANCH3_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level3: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 4
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for branch4: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=people,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH4_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'costemplatedn': BRANCH4_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for branch4: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 5
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for branch5: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for branch5: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH5_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for branch5: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'costemplatedn': BRANCH5_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level3: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 6
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for branch6: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for branch6: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=lower,ou=people,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=lower,ou=lower,ou=people,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH6_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for branch6: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=lower,ou=people,dc=example,dc=com',
+ 'costemplatedn': BRANCH6_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for branch6: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Now check that each user has its expected passwordPolicy subentry
+ #
+ try:
+ entries = topology.standalone.search_s(USER1_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH1_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER1_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER2_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH2_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER2_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER2_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER3_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH3_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER3_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER3_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER4_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH4_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER4_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER4_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER5_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH5_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER5_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER5_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER6_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH6_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER6_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER6_DN, e.message['desc']))
+ assert False
+
+ # If we got here the test passed
+ log.info('Test PASSED')
+
+
+def test_ticket47980_final(topology):
+ topology.standalone.stop(timeout=10)
+
+
+def run_isolated():
+ '''
+ run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
+ To run isolated without py.test, you need to
+ - edit this file and comment '@pytest.fixture' line before 'topology' function.
+ - set the installation prefix
+ - run this program
+ '''
+ global installation_prefix
+ installation_prefix = None
+
+ topo = topology(True)
+ test_ticket47980(topo)
+
+if __name__ == '__main__':
+ run_isolated()
\ No newline at end of file
diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
index 10f475e..76cc8fd 100644
--- a/ldap/servers/plugins/cos/cos_cache.c
+++ b/ldap/servers/plugins/cos/cos_cache.c
@@ -3097,25 +3097,19 @@ static int cos_cache_attr_compare(const void *e1, const void *e2)
int com_Result;
cosAttributes *pAttr = (*(cosAttributes**)e1);
cosTemplates *pTemplate = (cosTemplates*)pAttr->pParent;
- cosDefinitions *pDef = (cosDefinitions*)pTemplate->pParent;
- cosAttrValue *pcostt = pDef->pCosTargetTree;
cosAttributes *pAttr1 = (*(cosAttributes**)e2);
cosTemplates *pTemplate1 = (cosTemplates*)pAttr1->pParent;
- cosDefinitions *pDef1 = (cosDefinitions*)pTemplate1->pParent;
- cosAttrValue *pcostt1 = pDef1->pCosTargetTree;
/* Now compare the names of the attributes */
com_Result = slapi_utf8casecmp((unsigned char*)(*(cosAttributes**)e1)->pAttrName,(unsigned char*)(*(cosAttributes**)e2)->pAttrName);
+ if(0 == com_Result){
+ /* Now compare the cosPriorities */
+ com_Result = pTemplate->cosPriority - pTemplate1->cosPriority;
+ }
if(0 == com_Result)
- /* Now compare the definition Dn parents */
- com_Result = slapi_utf8casecmp((unsigned char*)pcostt1->val,(unsigned char*)pcostt->val);
- if(0 == com_Result)
- /* Now compare the cosPririoties */
- com_Result = pTemplate->cosPriority - pTemplate1->cosPriority;
- /* Now compare the prirority */
- if(0 == com_Result)
- return -1;
- return com_Result;
+ return -1;
+
+ return com_Result;
}
static int cos_cache_string_compare(const void *e1, const void *e2)
9 years, 4 months
Branch '389-ds-base-1.3.1' - dirsrvtests/tickets ldap/servers
by Mark Reynolds
dirsrvtests/tickets/ticket47980_test.py | 710 ++++++++++++++++++++++++++++++++
ldap/servers/plugins/cos/cos_cache.c | 20
2 files changed, 717 insertions(+), 13 deletions(-)
New commits:
commit 864b67740555b72fb31d084cec884e321704968c
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Jan 5 16:56:09 2015 -0500
Ticket 47980 - Nested COS definitions can be incorrectly
processed
Bug Description: The COS cache attribute index gets incorrectly sorted
and results in unexpected COS values being applied to
an entry.
Fix Description: The sorting method for comparing the target tree does
not work as indended, but we don't need to sort by the
target tree if the cos attributes are the same, as the
list is already in the proper tree order as returned by
the internal search. The fix was just to remove the
target tree comparison from the qsort compare function.
https://fedorahosted.org/389/ticket/47980
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit 987580d6fb42e358d84539a78879ae9a00393bd1)
diff --git a/dirsrvtests/tickets/ticket47980_test.py b/dirsrvtests/tickets/ticket47980_test.py
new file mode 100644
index 0000000..406d72d
--- /dev/null
+++ b/dirsrvtests/tickets/ticket47980_test.py
@@ -0,0 +1,710 @@
+import os
+import sys
+import time
+import ldap
+import ldap.sasl
+import logging
+import socket
+import pytest
+from lib389 import DirSrv, Entry, tools, tasks
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from lib389.tasks import *
+from constants import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+BRANCH1 = 'ou=level1,' + DEFAULT_SUFFIX
+BRANCH2 = 'ou=level2,ou=level1,' + DEFAULT_SUFFIX
+BRANCH3 = 'ou=level3,ou=level2,ou=level1,' + DEFAULT_SUFFIX
+BRANCH4 = 'ou=people,' + DEFAULT_SUFFIX
+BRANCH5 = 'ou=lower,ou=people,' + DEFAULT_SUFFIX
+BRANCH6 = 'ou=lower,ou=lower,ou=people,' + DEFAULT_SUFFIX
+USER1_DN = 'uid=user1,%s' % (BRANCH1)
+USER2_DN = 'uid=user2,%s' % (BRANCH2)
+USER3_DN = 'uid=user3,%s' % (BRANCH3)
+USER4_DN = 'uid=user4,%s' % (BRANCH4)
+USER5_DN = 'uid=user5,%s' % (BRANCH5)
+USER6_DN = 'uid=user6,%s' % (BRANCH6)
+
+BRANCH1_CONTAINER = 'cn=nsPwPolicyContainer,ou=level1,dc=example,dc=com'
+BRANCH1_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level1,dc=example,dc=com'
+BRANCH1_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level1,dc=example,dc=com'
+BRANCH1_COS_DEF = 'cn=nsPwPolicy_CoS,ou=level1,dc=example,dc=com'
+
+BRANCH2_CONTAINER = 'cn=nsPwPolicyContainer,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH2_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH2_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH2_COS_DEF = 'cn=nsPwPolicy_CoS,ou=level2,ou=level1,dc=example,dc=com'
+
+BRANCH3_CONTAINER = 'cn=nsPwPolicyContainer,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH3_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlevel3\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH3_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlevel3\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH3_COS_DEF = 'cn=nsPwPolicy_CoS,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+
+BRANCH4_CONTAINER = 'cn=nsPwPolicyContainer,ou=people,dc=example,dc=com'
+BRANCH4_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
+BRANCH4_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
+BRANCH4_COS_DEF = 'cn=nsPwPolicy_CoS,ou=people,dc=example,dc=com'
+
+BRANCH5_CONTAINER = 'cn=nsPwPolicyContainer,ou=lower,ou=people,dc=example,dc=com'
+BRANCH5_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=People,dc=example,dc=com'
+BRANCH5_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=People,dc=example,dc=com'
+BRANCH5_COS_DEF = 'cn=nsPwPolicy_CoS,ou=lower,ou=People,dc=example,dc=com'
+
+BRANCH6_CONTAINER = 'cn=nsPwPolicyContainer,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+BRANCH6_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlower\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+BRANCH6_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlower\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+BRANCH6_COS_DEF = 'cn=nsPwPolicy_CoS,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ At the beginning, It may exists a standalone instance.
+ It may also exists a backup for the standalone instance.
+
+ Principle:
+ If standalone instance exists:
+ restart it
+ If backup of standalone exists:
+ create/rebind to standalone
+
+ restore standalone instance from backup
+ else:
+ Cleanup everything
+ remove instance
+ remove backup
+ Create instance
+ Create backup
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the backups
+ backup_standalone = standalone.checkBackupFS()
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+ if instance_standalone:
+ # assuming the instance is already stopped, just wait 5 sec max
+ standalone.stop(timeout=5)
+ standalone.start(timeout=10)
+
+ if backup_standalone:
+ # The backup exist, assuming it is correct
+ # we just re-init the instance with it
+ if not instance_standalone:
+ standalone.create()
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # restore standalone instance from backup
+ standalone.stop(timeout=10)
+ standalone.restoreFS(backup_standalone)
+ standalone.start(timeout=10)
+
+ else:
+ # We should be here only in two conditions
+ # - This is the first time a test involve standalone instance
+ # - Something weird happened (instance/backup destroyed)
+ # so we discard everything and recreate all
+
+ # Remove the backup. So even if we have a specific backup file
+ # (e.g backup_standalone) we clear backup that an instance may have created
+ if backup_standalone:
+ standalone.clearBackupFS()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # Time to create the backups
+ standalone.stop(timeout=10)
+ standalone.backupfile = standalone.backupFS()
+ standalone.start(timeout=10)
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
+ #
+ # Here we have standalone instance up and running
+ # Either coming from a backup recovery
+ # or from a fresh (re)init
+ # Time to return the topology
+ return TopologyStandalone(standalone)
+
+
+def test_ticket47980(topology):
+ """
+ Multiple COS pointer definitions that use the same attribute are not correctly ordered.
+ The cos plugin was incorrectly sorting the attribute indexes based on subtree, which lead
+ to the wrong cos attribute value being applied to the entry.
+ """
+
+ log.info('Testing Ticket 47980 - Testing multiple nested COS pointer definitions are processed correctly')
+
+ # Add our nested branches
+ try:
+ topology.standalone.add_s(Entry((BRANCH1, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level1'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level1: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH2, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level2'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level2: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH3, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'level3'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level3: error ' + e.message['desc'])
+ assert False
+
+ # People branch, might already exist
+ try:
+ topology.standalone.add_s(Entry((BRANCH4, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level4'
+ })))
+ except ldap.ALREADY_EXISTS:
+ pass
+ except ldap.LDAPError, e:
+ log.error('Failed to add level4: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH5, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level5'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level5: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH6, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'level6'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level6: error ' + e.message['desc'])
+ assert False
+
+ # Add users to each branch
+ try:
+ topology.standalone.add_s(Entry((USER1_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user1'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user1: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER2_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user2'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user2: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER3_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user3'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user3: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER4_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user4'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user4: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER5_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user5'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user5: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER6_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user6'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user6: error ' + e.message['desc'])
+ assert False
+
+ # Enable password policy
+ try:
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on')])
+ except ldap.LDAPError, e:
+ log.error('Failed to set pwpolicy-local: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 1
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level1: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level1,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for level1: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level1,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=level1,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH1_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level1: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level1,dc=example,dc=com',
+ 'costemplatedn': BRANCH1_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level1: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 2
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level2: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level2,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for level2: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level2,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=level2,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH2_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level2: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level2,dc=example,dc=com',
+ 'costemplatedn': BRANCH2_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level2: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 3
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=level3,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH3_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'costemplatedn': BRANCH3_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level3: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 4
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for branch4: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=people,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH4_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'costemplatedn': BRANCH4_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for branch4: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 5
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for branch5: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for branch5: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH5_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for branch5: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'costemplatedn': BRANCH5_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level3: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 6
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for branch6: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for branch6: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=lower,ou=people,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=lower,ou=lower,ou=people,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH6_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for branch6: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=lower,ou=people,dc=example,dc=com',
+ 'costemplatedn': BRANCH6_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for branch6: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Now check that each user has its expected passwordPolicy subentry
+ #
+ try:
+ entries = topology.standalone.search_s(USER1_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH1_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER1_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER2_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH2_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER2_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER2_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER3_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH3_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER3_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER3_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER4_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH4_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER4_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER4_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER5_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH5_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER5_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER5_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER6_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH6_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER6_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER6_DN, e.message['desc']))
+ assert False
+
+ # If we got here the test passed
+ log.info('Test PASSED')
+
+
+def test_ticket47980_final(topology):
+ topology.standalone.stop(timeout=10)
+
+
+def run_isolated():
+ '''
+ run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
+ To run isolated without py.test, you need to
+ - edit this file and comment '@pytest.fixture' line before 'topology' function.
+ - set the installation prefix
+ - run this program
+ '''
+ global installation_prefix
+ installation_prefix = None
+
+ topo = topology(True)
+ test_ticket47980(topo)
+
+if __name__ == '__main__':
+ run_isolated()
\ No newline at end of file
diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
index 9175a39..bc1132f 100644
--- a/ldap/servers/plugins/cos/cos_cache.c
+++ b/ldap/servers/plugins/cos/cos_cache.c
@@ -3054,25 +3054,19 @@ static int cos_cache_attr_compare(const void *e1, const void *e2)
int com_Result;
cosAttributes *pAttr = (*(cosAttributes**)e1);
cosTemplates *pTemplate = (cosTemplates*)pAttr->pParent;
- cosDefinitions *pDef = (cosDefinitions*)pTemplate->pParent;
- cosAttrValue *pcostt = pDef->pCosTargetTree;
cosAttributes *pAttr1 = (*(cosAttributes**)e2);
cosTemplates *pTemplate1 = (cosTemplates*)pAttr1->pParent;
- cosDefinitions *pDef1 = (cosDefinitions*)pTemplate1->pParent;
- cosAttrValue *pcostt1 = pDef1->pCosTargetTree;
/* Now compare the names of the attributes */
com_Result = slapi_utf8casecmp((unsigned char*)(*(cosAttributes**)e1)->pAttrName,(unsigned char*)(*(cosAttributes**)e2)->pAttrName);
+ if(0 == com_Result){
+ /* Now compare the cosPriorities */
+ com_Result = pTemplate->cosPriority - pTemplate1->cosPriority;
+ }
if(0 == com_Result)
- /* Now compare the definition Dn parents */
- com_Result = slapi_utf8casecmp((unsigned char*)pcostt1->val,(unsigned char*)pcostt->val);
- if(0 == com_Result)
- /* Now compare the cosPririoties */
- com_Result = pTemplate->cosPriority - pTemplate1->cosPriority;
- /* Now compare the prirority */
- if(0 == com_Result)
- return -1;
- return com_Result;
+ return -1;
+
+ return com_Result;
}
static int cos_cache_string_compare(const void *e1, const void *e2)
9 years, 4 months
Branch '389-ds-base-1.3.2' - dirsrvtests/tickets ldap/servers
by Mark Reynolds
dirsrvtests/tickets/ticket47980_test.py | 710 ++++++++++++++++++++++++++++++++
ldap/servers/plugins/cos/cos_cache.c | 20
2 files changed, 717 insertions(+), 13 deletions(-)
New commits:
commit 3494fec27bd3a970aad30993d4867f677b3ebba1
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Jan 5 16:56:09 2015 -0500
Ticket 47980 - Nested COS definitions can be incorrectly
processed
Bug Description: The COS cache attribute index gets incorrectly sorted
and results in unexpected COS values being applied to
an entry.
Fix Description: The sorting method for comparing the target tree does
not work as indended, but we don't need to sort by the
target tree if the cos attributes are the same, as the
list is already in the proper tree order as returned by
the internal search. The fix was just to remove the
target tree comparison from the qsort compare function.
https://fedorahosted.org/389/ticket/47980
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit 987580d6fb42e358d84539a78879ae9a00393bd1)
diff --git a/dirsrvtests/tickets/ticket47980_test.py b/dirsrvtests/tickets/ticket47980_test.py
new file mode 100644
index 0000000..406d72d
--- /dev/null
+++ b/dirsrvtests/tickets/ticket47980_test.py
@@ -0,0 +1,710 @@
+import os
+import sys
+import time
+import ldap
+import ldap.sasl
+import logging
+import socket
+import pytest
+from lib389 import DirSrv, Entry, tools, tasks
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from lib389.tasks import *
+from constants import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+BRANCH1 = 'ou=level1,' + DEFAULT_SUFFIX
+BRANCH2 = 'ou=level2,ou=level1,' + DEFAULT_SUFFIX
+BRANCH3 = 'ou=level3,ou=level2,ou=level1,' + DEFAULT_SUFFIX
+BRANCH4 = 'ou=people,' + DEFAULT_SUFFIX
+BRANCH5 = 'ou=lower,ou=people,' + DEFAULT_SUFFIX
+BRANCH6 = 'ou=lower,ou=lower,ou=people,' + DEFAULT_SUFFIX
+USER1_DN = 'uid=user1,%s' % (BRANCH1)
+USER2_DN = 'uid=user2,%s' % (BRANCH2)
+USER3_DN = 'uid=user3,%s' % (BRANCH3)
+USER4_DN = 'uid=user4,%s' % (BRANCH4)
+USER5_DN = 'uid=user5,%s' % (BRANCH5)
+USER6_DN = 'uid=user6,%s' % (BRANCH6)
+
+BRANCH1_CONTAINER = 'cn=nsPwPolicyContainer,ou=level1,dc=example,dc=com'
+BRANCH1_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level1,dc=example,dc=com'
+BRANCH1_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level1,dc=example,dc=com'
+BRANCH1_COS_DEF = 'cn=nsPwPolicy_CoS,ou=level1,dc=example,dc=com'
+
+BRANCH2_CONTAINER = 'cn=nsPwPolicyContainer,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH2_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH2_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH2_COS_DEF = 'cn=nsPwPolicy_CoS,ou=level2,ou=level1,dc=example,dc=com'
+
+BRANCH3_CONTAINER = 'cn=nsPwPolicyContainer,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH3_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlevel3\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH3_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlevel3\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH3_COS_DEF = 'cn=nsPwPolicy_CoS,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+
+BRANCH4_CONTAINER = 'cn=nsPwPolicyContainer,ou=people,dc=example,dc=com'
+BRANCH4_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
+BRANCH4_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
+BRANCH4_COS_DEF = 'cn=nsPwPolicy_CoS,ou=people,dc=example,dc=com'
+
+BRANCH5_CONTAINER = 'cn=nsPwPolicyContainer,ou=lower,ou=people,dc=example,dc=com'
+BRANCH5_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=People,dc=example,dc=com'
+BRANCH5_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=People,dc=example,dc=com'
+BRANCH5_COS_DEF = 'cn=nsPwPolicy_CoS,ou=lower,ou=People,dc=example,dc=com'
+
+BRANCH6_CONTAINER = 'cn=nsPwPolicyContainer,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+BRANCH6_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlower\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+BRANCH6_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlower\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+BRANCH6_COS_DEF = 'cn=nsPwPolicy_CoS,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ At the beginning, It may exists a standalone instance.
+ It may also exists a backup for the standalone instance.
+
+ Principle:
+ If standalone instance exists:
+ restart it
+ If backup of standalone exists:
+ create/rebind to standalone
+
+ restore standalone instance from backup
+ else:
+ Cleanup everything
+ remove instance
+ remove backup
+ Create instance
+ Create backup
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the backups
+ backup_standalone = standalone.checkBackupFS()
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+ if instance_standalone:
+ # assuming the instance is already stopped, just wait 5 sec max
+ standalone.stop(timeout=5)
+ standalone.start(timeout=10)
+
+ if backup_standalone:
+ # The backup exist, assuming it is correct
+ # we just re-init the instance with it
+ if not instance_standalone:
+ standalone.create()
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # restore standalone instance from backup
+ standalone.stop(timeout=10)
+ standalone.restoreFS(backup_standalone)
+ standalone.start(timeout=10)
+
+ else:
+ # We should be here only in two conditions
+ # - This is the first time a test involve standalone instance
+ # - Something weird happened (instance/backup destroyed)
+ # so we discard everything and recreate all
+
+ # Remove the backup. So even if we have a specific backup file
+ # (e.g backup_standalone) we clear backup that an instance may have created
+ if backup_standalone:
+ standalone.clearBackupFS()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # Time to create the backups
+ standalone.stop(timeout=10)
+ standalone.backupfile = standalone.backupFS()
+ standalone.start(timeout=10)
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
+ #
+ # Here we have standalone instance up and running
+ # Either coming from a backup recovery
+ # or from a fresh (re)init
+ # Time to return the topology
+ return TopologyStandalone(standalone)
+
+
+def test_ticket47980(topology):
+ """
+ Multiple COS pointer definitions that use the same attribute are not correctly ordered.
+ The cos plugin was incorrectly sorting the attribute indexes based on subtree, which lead
+ to the wrong cos attribute value being applied to the entry.
+ """
+
+ log.info('Testing Ticket 47980 - Testing multiple nested COS pointer definitions are processed correctly')
+
+ # Add our nested branches
+ try:
+ topology.standalone.add_s(Entry((BRANCH1, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level1'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level1: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH2, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level2'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level2: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH3, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'level3'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level3: error ' + e.message['desc'])
+ assert False
+
+ # People branch, might already exist
+ try:
+ topology.standalone.add_s(Entry((BRANCH4, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level4'
+ })))
+ except ldap.ALREADY_EXISTS:
+ pass
+ except ldap.LDAPError, e:
+ log.error('Failed to add level4: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH5, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level5'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level5: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH6, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'level6'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level6: error ' + e.message['desc'])
+ assert False
+
+ # Add users to each branch
+ try:
+ topology.standalone.add_s(Entry((USER1_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user1'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user1: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER2_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user2'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user2: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER3_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user3'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user3: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER4_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user4'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user4: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER5_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user5'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user5: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER6_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user6'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user6: error ' + e.message['desc'])
+ assert False
+
+ # Enable password policy
+ try:
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on')])
+ except ldap.LDAPError, e:
+ log.error('Failed to set pwpolicy-local: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 1
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level1: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level1,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for level1: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level1,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=level1,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH1_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level1: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level1,dc=example,dc=com',
+ 'costemplatedn': BRANCH1_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level1: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 2
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level2: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level2,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for level2: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level2,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=level2,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH2_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level2: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level2,dc=example,dc=com',
+ 'costemplatedn': BRANCH2_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level2: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 3
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=level3,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH3_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'costemplatedn': BRANCH3_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level3: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 4
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for branch4: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=people,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH4_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'costemplatedn': BRANCH4_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for branch4: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 5
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for branch5: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for branch5: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH5_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for branch5: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'costemplatedn': BRANCH5_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level3: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 6
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for branch6: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for branch6: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=lower,ou=people,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=lower,ou=lower,ou=people,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH6_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for branch6: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=lower,ou=people,dc=example,dc=com',
+ 'costemplatedn': BRANCH6_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for branch6: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Now check that each user has its expected passwordPolicy subentry
+ #
+ try:
+ entries = topology.standalone.search_s(USER1_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH1_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER1_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER2_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH2_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER2_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER2_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER3_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH3_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER3_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER3_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER4_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH4_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER4_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER4_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER5_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH5_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER5_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER5_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER6_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH6_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER6_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER6_DN, e.message['desc']))
+ assert False
+
+ # If we got here the test passed
+ log.info('Test PASSED')
+
+
+def test_ticket47980_final(topology):
+ topology.standalone.stop(timeout=10)
+
+
+def run_isolated():
+ '''
+ run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
+ To run isolated without py.test, you need to
+ - edit this file and comment '@pytest.fixture' line before 'topology' function.
+ - set the installation prefix
+ - run this program
+ '''
+ global installation_prefix
+ installation_prefix = None
+
+ topo = topology(True)
+ test_ticket47980(topo)
+
+if __name__ == '__main__':
+ run_isolated()
\ No newline at end of file
diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
index de003fd..3214f82 100644
--- a/ldap/servers/plugins/cos/cos_cache.c
+++ b/ldap/servers/plugins/cos/cos_cache.c
@@ -3054,25 +3054,19 @@ static int cos_cache_attr_compare(const void *e1, const void *e2)
int com_Result;
cosAttributes *pAttr = (*(cosAttributes**)e1);
cosTemplates *pTemplate = (cosTemplates*)pAttr->pParent;
- cosDefinitions *pDef = (cosDefinitions*)pTemplate->pParent;
- cosAttrValue *pcostt = pDef->pCosTargetTree;
cosAttributes *pAttr1 = (*(cosAttributes**)e2);
cosTemplates *pTemplate1 = (cosTemplates*)pAttr1->pParent;
- cosDefinitions *pDef1 = (cosDefinitions*)pTemplate1->pParent;
- cosAttrValue *pcostt1 = pDef1->pCosTargetTree;
/* Now compare the names of the attributes */
com_Result = slapi_utf8casecmp((unsigned char*)(*(cosAttributes**)e1)->pAttrName,(unsigned char*)(*(cosAttributes**)e2)->pAttrName);
+ if(0 == com_Result){
+ /* Now compare the cosPriorities */
+ com_Result = pTemplate->cosPriority - pTemplate1->cosPriority;
+ }
if(0 == com_Result)
- /* Now compare the definition Dn parents */
- com_Result = slapi_utf8casecmp((unsigned char*)pcostt1->val,(unsigned char*)pcostt->val);
- if(0 == com_Result)
- /* Now compare the cosPririoties */
- com_Result = pTemplate->cosPriority - pTemplate1->cosPriority;
- /* Now compare the prirority */
- if(0 == com_Result)
- return -1;
- return com_Result;
+ return -1;
+
+ return com_Result;
}
static int cos_cache_string_compare(const void *e1, const void *e2)
9 years, 4 months
Branch '389-ds-base-1.3.3' - dirsrvtests/tickets ldap/servers
by Mark Reynolds
dirsrvtests/tickets/ticket47980_test.py | 710 ++++++++++++++++++++++++++++++++
ldap/servers/plugins/cos/cos_cache.c | 20
2 files changed, 717 insertions(+), 13 deletions(-)
New commits:
commit 18eb6cec9f3841ba7afb6fb489f420e36d40cb90
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Jan 5 16:56:09 2015 -0500
Ticket 47980 - Nested COS definitions can be incorrectly
processed
Bug Description: The COS cache attribute index gets incorrectly sorted
and results in unexpected COS values being applied to
an entry.
Fix Description: The sorting method for comparing the target tree does
not work as indended, but we don't need to sort by the
target tree if the cos attributes are the same, as the
list is already in the proper tree order as returned by
the internal search. The fix was just to remove the
target tree comparison from the qsort compare function.
https://fedorahosted.org/389/ticket/47980
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit 987580d6fb42e358d84539a78879ae9a00393bd1)
diff --git a/dirsrvtests/tickets/ticket47980_test.py b/dirsrvtests/tickets/ticket47980_test.py
new file mode 100644
index 0000000..406d72d
--- /dev/null
+++ b/dirsrvtests/tickets/ticket47980_test.py
@@ -0,0 +1,710 @@
+import os
+import sys
+import time
+import ldap
+import ldap.sasl
+import logging
+import socket
+import pytest
+from lib389 import DirSrv, Entry, tools, tasks
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from lib389.tasks import *
+from constants import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+BRANCH1 = 'ou=level1,' + DEFAULT_SUFFIX
+BRANCH2 = 'ou=level2,ou=level1,' + DEFAULT_SUFFIX
+BRANCH3 = 'ou=level3,ou=level2,ou=level1,' + DEFAULT_SUFFIX
+BRANCH4 = 'ou=people,' + DEFAULT_SUFFIX
+BRANCH5 = 'ou=lower,ou=people,' + DEFAULT_SUFFIX
+BRANCH6 = 'ou=lower,ou=lower,ou=people,' + DEFAULT_SUFFIX
+USER1_DN = 'uid=user1,%s' % (BRANCH1)
+USER2_DN = 'uid=user2,%s' % (BRANCH2)
+USER3_DN = 'uid=user3,%s' % (BRANCH3)
+USER4_DN = 'uid=user4,%s' % (BRANCH4)
+USER5_DN = 'uid=user5,%s' % (BRANCH5)
+USER6_DN = 'uid=user6,%s' % (BRANCH6)
+
+BRANCH1_CONTAINER = 'cn=nsPwPolicyContainer,ou=level1,dc=example,dc=com'
+BRANCH1_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level1,dc=example,dc=com'
+BRANCH1_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level1,dc=example,dc=com'
+BRANCH1_COS_DEF = 'cn=nsPwPolicy_CoS,ou=level1,dc=example,dc=com'
+
+BRANCH2_CONTAINER = 'cn=nsPwPolicyContainer,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH2_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH2_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH2_COS_DEF = 'cn=nsPwPolicy_CoS,ou=level2,ou=level1,dc=example,dc=com'
+
+BRANCH3_CONTAINER = 'cn=nsPwPolicyContainer,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH3_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlevel3\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH3_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlevel3\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+BRANCH3_COS_DEF = 'cn=nsPwPolicy_CoS,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
+
+BRANCH4_CONTAINER = 'cn=nsPwPolicyContainer,ou=people,dc=example,dc=com'
+BRANCH4_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
+BRANCH4_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
+BRANCH4_COS_DEF = 'cn=nsPwPolicy_CoS,ou=people,dc=example,dc=com'
+
+BRANCH5_CONTAINER = 'cn=nsPwPolicyContainer,ou=lower,ou=people,dc=example,dc=com'
+BRANCH5_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=People,dc=example,dc=com'
+BRANCH5_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=People,dc=example,dc=com'
+BRANCH5_COS_DEF = 'cn=nsPwPolicy_CoS,ou=lower,ou=People,dc=example,dc=com'
+
+BRANCH6_CONTAINER = 'cn=nsPwPolicyContainer,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+BRANCH6_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlower\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+BRANCH6_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlower\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
+ 'cn=nsPwPolicyContainer,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+BRANCH6_COS_DEF = 'cn=nsPwPolicy_CoS,ou=lower,ou=lower,ou=People,dc=example,dc=com'
+
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ At the beginning, It may exists a standalone instance.
+ It may also exists a backup for the standalone instance.
+
+ Principle:
+ If standalone instance exists:
+ restart it
+ If backup of standalone exists:
+ create/rebind to standalone
+
+ restore standalone instance from backup
+ else:
+ Cleanup everything
+ remove instance
+ remove backup
+ Create instance
+ Create backup
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the backups
+ backup_standalone = standalone.checkBackupFS()
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+ if instance_standalone:
+ # assuming the instance is already stopped, just wait 5 sec max
+ standalone.stop(timeout=5)
+ standalone.start(timeout=10)
+
+ if backup_standalone:
+ # The backup exist, assuming it is correct
+ # we just re-init the instance with it
+ if not instance_standalone:
+ standalone.create()
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # restore standalone instance from backup
+ standalone.stop(timeout=10)
+ standalone.restoreFS(backup_standalone)
+ standalone.start(timeout=10)
+
+ else:
+ # We should be here only in two conditions
+ # - This is the first time a test involve standalone instance
+ # - Something weird happened (instance/backup destroyed)
+ # so we discard everything and recreate all
+
+ # Remove the backup. So even if we have a specific backup file
+ # (e.g backup_standalone) we clear backup that an instance may have created
+ if backup_standalone:
+ standalone.clearBackupFS()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # Time to create the backups
+ standalone.stop(timeout=10)
+ standalone.backupfile = standalone.backupFS()
+ standalone.start(timeout=10)
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
+ #
+ # Here we have standalone instance up and running
+ # Either coming from a backup recovery
+ # or from a fresh (re)init
+ # Time to return the topology
+ return TopologyStandalone(standalone)
+
+
+def test_ticket47980(topology):
+ """
+ Multiple COS pointer definitions that use the same attribute are not correctly ordered.
+ The cos plugin was incorrectly sorting the attribute indexes based on subtree, which lead
+ to the wrong cos attribute value being applied to the entry.
+ """
+
+ log.info('Testing Ticket 47980 - Testing multiple nested COS pointer definitions are processed correctly')
+
+ # Add our nested branches
+ try:
+ topology.standalone.add_s(Entry((BRANCH1, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level1'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level1: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH2, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level2'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level2: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH3, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'level3'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level3: error ' + e.message['desc'])
+ assert False
+
+ # People branch, might already exist
+ try:
+ topology.standalone.add_s(Entry((BRANCH4, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level4'
+ })))
+ except ldap.ALREADY_EXISTS:
+ pass
+ except ldap.LDAPError, e:
+ log.error('Failed to add level4: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH5, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'ou': 'level5'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level5: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((BRANCH6, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'level6'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add level6: error ' + e.message['desc'])
+ assert False
+
+ # Add users to each branch
+ try:
+ topology.standalone.add_s(Entry((USER1_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user1'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user1: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER2_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user2'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user2: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER3_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user3'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user3: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER4_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user4'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user4: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER5_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user5'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user5: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry((USER6_DN, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'user6'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add user6: error ' + e.message['desc'])
+ assert False
+
+ # Enable password policy
+ try:
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on')])
+ except ldap.LDAPError, e:
+ log.error('Failed to set pwpolicy-local: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 1
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level1: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level1,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for level1: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level1,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=level1,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH1_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level1: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH1_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level1,dc=example,dc=com',
+ 'costemplatedn': BRANCH1_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level1: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 2
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level2: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level2,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for level2: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level2,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=level2,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH2_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level2: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH2_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level2,dc=example,dc=com',
+ 'costemplatedn': BRANCH2_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level2: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 3
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=level3,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH3_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH3_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'costemplatedn': BRANCH3_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level3: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 4
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for branch4: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=people,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH4_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for level3: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH4_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
+ 'costemplatedn': BRANCH4_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for branch4: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 5
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for branch5: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for branch5: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH5_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for branch5: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH5_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=people,dc=example,dc=com',
+ 'costemplatedn': BRANCH5_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for level3: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Add subtree policy to branch 6
+ #
+ # Add the container
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_CONTAINER, {
+ 'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container for branch6: error ' + e.message['desc'])
+ assert False
+
+ # Add the password policy subentry
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_PWP, {
+ 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'off',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'off',
+ 'passwordStorageScheme': 'ssha'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy for branch6: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS template
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_COS_TMPL, {
+ 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=lower,ou=people,dc=example,dc=com',
+ 'cosPriority': '1',
+ 'cn': 'cn=nsPwTemplateEntry,ou=lower,ou=lower,ou=people,dc=example,dc=com',
+ 'pwdpolicysubentry': BRANCH6_PWP
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template for branch6: error ' + e.message['desc'])
+ assert False
+
+ # Add the COS definition
+ try:
+ topology.standalone.add_s(Entry((BRANCH6_COS_DEF, {
+ 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=lower,ou=people,dc=example,dc=com',
+ 'costemplatedn': BRANCH6_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'
+ })))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def for branch6: error ' + e.message['desc'])
+ assert False
+
+ #
+ # Now check that each user has its expected passwordPolicy subentry
+ #
+ try:
+ entries = topology.standalone.search_s(USER1_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH1_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER1_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER2_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH2_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER2_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER2_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER3_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH3_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER3_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER3_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER4_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH4_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER4_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER4_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER5_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH5_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER5_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER5_DN, e.message['desc']))
+ assert False
+
+ try:
+ entries = topology.standalone.search_s(USER6_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
+ if not entries[0].hasValue('pwdpolicysubentry', BRANCH6_PWP):
+ log.fatal('User %s does not have expected pwdpolicysubentry!' % USER6_DN)
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Unable to search for entry %s: error %s' % (USER6_DN, e.message['desc']))
+ assert False
+
+ # If we got here the test passed
+ log.info('Test PASSED')
+
+
+def test_ticket47980_final(topology):
+ topology.standalone.stop(timeout=10)
+
+
+def run_isolated():
+ '''
+ run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
+ To run isolated without py.test, you need to
+ - edit this file and comment '@pytest.fixture' line before 'topology' function.
+ - set the installation prefix
+ - run this program
+ '''
+ global installation_prefix
+ installation_prefix = None
+
+ topo = topology(True)
+ test_ticket47980(topo)
+
+if __name__ == '__main__':
+ run_isolated()
\ No newline at end of file
diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
index a74389d..0d9a61e 100644
--- a/ldap/servers/plugins/cos/cos_cache.c
+++ b/ldap/servers/plugins/cos/cos_cache.c
@@ -3054,25 +3054,19 @@ static int cos_cache_attr_compare(const void *e1, const void *e2)
int com_Result;
cosAttributes *pAttr = (*(cosAttributes**)e1);
cosTemplates *pTemplate = (cosTemplates*)pAttr->pParent;
- cosDefinitions *pDef = (cosDefinitions*)pTemplate->pParent;
- cosAttrValue *pcostt = pDef->pCosTargetTree;
cosAttributes *pAttr1 = (*(cosAttributes**)e2);
cosTemplates *pTemplate1 = (cosTemplates*)pAttr1->pParent;
- cosDefinitions *pDef1 = (cosDefinitions*)pTemplate1->pParent;
- cosAttrValue *pcostt1 = pDef1->pCosTargetTree;
/* Now compare the names of the attributes */
com_Result = slapi_utf8casecmp((unsigned char*)(*(cosAttributes**)e1)->pAttrName,(unsigned char*)(*(cosAttributes**)e2)->pAttrName);
+ if(0 == com_Result){
+ /* Now compare the cosPriorities */
+ com_Result = pTemplate->cosPriority - pTemplate1->cosPriority;
+ }
if(0 == com_Result)
- /* Now compare the definition Dn parents */
- com_Result = slapi_utf8casecmp((unsigned char*)pcostt1->val,(unsigned char*)pcostt->val);
- if(0 == com_Result)
- /* Now compare the cosPririoties */
- com_Result = pTemplate->cosPriority - pTemplate1->cosPriority;
- /* Now compare the prirority */
- if(0 == com_Result)
- return -1;
- return com_Result;
+ return -1;
+
+ return com_Result;
}
static int cos_cache_string_compare(const void *e1, const void *e2)
9 years, 4 months