Hello community, here is the log from the commit of package 389-ds for openSUSE:Factory checked in at 2015-04-30 11:51:19 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/389-ds (Old) and /work/SRC/openSUSE:Factory/.389-ds.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "389-ds" Changes: -------- --- /work/SRC/openSUSE:Factory/389-ds/389-ds.changes 2015-04-23 08:05:18.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.389-ds.new/389-ds.changes 2015-04-30 11:51:20.000000000 +0200 @@ -1,0 +2,7 @@ +Wed Apr 29 10:17:58 UTC 2015 - aj@ajaissle.de + +- Update to new upstream release 1.3.3.10 + * One important security bug was fixed: + Bug 1216203 - CVE-2015-1854 389ds-base: access control bypass with modrdn + +------------------------------------------------------------------- Old: ---- 389-ds-base-1.3.3.9.tar.bz2 New: ---- 389-ds-base-1.3.3.10.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ 389-ds.spec ++++++ --- /var/tmp/diff_new_pack.8URQRY/_old 2015-04-30 11:51:21.000000000 +0200 +++ /var/tmp/diff_new_pack.8URQRY/_new 2015-04-30 11:51:21.000000000 +0200 @@ -18,7 +18,7 @@ Name: 389-ds Summary: 389 Directory Server -Version: 1.3.3.9 +Version: 1.3.3.10 Release: 0 Group: Productivity/Networking/LDAP/Servers License: GPL-2.0 ++++++ 389-ds-base-1.3.3.9.tar.bz2 -> 389-ds-base-1.3.3.10.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/389-ds-base-1.3.3.9/VERSION.sh new/389-ds-base-1.3.3.10/VERSION.sh --- old/389-ds-base-1.3.3.9/VERSION.sh 2015-03-07 01:46:09.000000000 +0100 +++ new/389-ds-base-1.3.3.10/VERSION.sh 2015-04-28 19:16:17.000000000 +0200 @@ -10,7 +10,7 @@ # PACKAGE_VERSION is constructed from these VERSION_MAJOR=1 VERSION_MINOR=3 -VERSION_MAINT=3.9 +VERSION_MAINT=3.10 # if this is a PRERELEASE, set VERSION_PREREL # otherwise, comment it out # be sure to include the dot prefix in the prerel diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/389-ds-base-1.3.3.9/dirsrvtests/tickets/ticket47553_rdn_write_test.py new/389-ds-base-1.3.3.10/dirsrvtests/tickets/ticket47553_rdn_write_test.py --- old/389-ds-base-1.3.3.9/dirsrvtests/tickets/ticket47553_rdn_write_test.py 1970-01-01 01:00:00.000000000 +0100 +++ new/389-ds-base-1.3.3.10/dirsrvtests/tickets/ticket47553_rdn_write_test.py 2015-04-28 19:16:17.000000000 +0200 @@ -0,0 +1,132 @@ +import os +import sys +import time +import ldap +import logging +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 lib389.utils import * +from ldap.controls.simple import GetEffectiveRightsControl + +logging.getLogger(__name__).setLevel(logging.DEBUG) +log = logging.getLogger(__name__) + +installation1_prefix = None + +SRC_ENTRY_CN = "tuser" +EXT_RDN = "01" +DST_ENTRY_CN = SRC_ENTRY_CN + EXT_RDN + +SRC_ENTRY_DN = "cn=%s,%s" % (SRC_ENTRY_CN, SUFFIX) +DST_ENTRY_DN = "cn=%s,%s" % (DST_ENTRY_CN, SUFFIX) + +class TopologyStandalone(object): + def __init__(self, standalone): + standalone.open() + self.standalone = standalone + + +#@pytest.fixture(scope="module") +def topology(request): + global installation1_prefix + + # Creating standalone instance ... + standalone = DirSrv(verbose=False) + if installation1_prefix: + args_instance[SER_DEPLOYED_DIR] = installation1_prefix + args_instance[SER_HOST] = HOST_STANDALONE + args_instance[SER_PORT] = PORT_STANDALONE + args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE + args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX + args_standalone = args_instance.copy() + standalone.allocate(args_standalone) + instance_standalone = standalone.exists() + if instance_standalone: + standalone.delete() + standalone.create() + standalone.open() + + # Clear out the tmp dir + standalone.clearTmpDir(__file__) + + return TopologyStandalone(standalone) + +def test_ticket47553_rdn_write_init(topology): + topology.standalone.log.info("\n\n######################### Add entry tuser ######################\n") + topology.standalone.add_s(Entry((SRC_ENTRY_DN, { + 'objectclass': "top person".split(), + 'sn': SRC_ENTRY_CN, + 'cn': SRC_ENTRY_CN}))) + +def test_ticket47553_rdn_write_get_ger(topology): + ANONYMOUS_DN = "" + topology.standalone.log.info("\n\n######################### GER rights for anonymous ######################\n") + request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn:" + ANONYMOUS_DN) + msg_id = topology.standalone.search_ext(SUFFIX, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl]) + rtype, rdata, rmsgid, response_ctrl = topology.standalone.result3(msg_id) + value = '' + for dn, attrs in rdata: + topology.standalone.log.info("dn: %s" % dn) + for value in attrs['entryLevelRights']: + topology.standalone.log.info("############### entryLevelRights: %r" % value) + assert 'n' not in value + +def test_ticket47553_rdn_write_modrdn_anonymous(topology): + ANONYMOUS_DN = "" + topology.standalone.close() + topology.standalone.binddn = ANONYMOUS_DN + topology.standalone.open() + msg_id = topology.standalone.search_ext("", ldap.SCOPE_BASE, "objectclass=*") + rtype, rdata, rmsgid, response_ctrl = topology.standalone.result3(msg_id) + value = '' + for dn, attrs in rdata: + topology.standalone.log.info("dn: %s" % dn) + for attr in attrs: + topology.standalone.log.info("############### %r: %r" % (attr, attrs[attr])) + + + try: + topology.standalone.rename_s(SRC_ENTRY_DN, "cn=%s" % DST_ENTRY_CN, delold=True) + except Exception as e: + topology.standalone.log.info("Exception (expected): %s" % type(e).__name__) + isinstance(e, ldap.INSUFFICIENT_ACCESS) + + try: + topology.standalone.getEntry(DST_ENTRY_DN, ldap.SCOPE_BASE, "objectclass=*") + assert False + except Exception as e: + topology.standalone.log.info("The entry was not renamed (expected)") + isinstance(e, ldap.NO_SUCH_OBJECT) + +def test_ticket47553_rdn_write(topology): + ''' + Write your testcase here... + ''' + + log.info('Test complete') + + +def test_ticket47553_rdn_write_final(topology): + topology.standalone.delete() + log.info('Testcase PASSED') + + +def run_isolated(): + global installation1_prefix + installation1_prefix = '/home/tbordaz/install_master' + + topo = topology(True) + test_ticket47553_rdn_write_init(topo) + test_ticket47553_rdn_write_get_ger(topo) + test_ticket47553_rdn_write(topo) + test_ticket47553_rdn_write_modrdn_anonymous(topo) + test_ticket47553_rdn_write_final(topo) + + +if __name__ == '__main__': + run_isolated() + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/389-ds-base-1.3.3.9/dirsrvtests/tickets/ticket47553_single_aci_test.py new/389-ds-base-1.3.3.10/dirsrvtests/tickets/ticket47553_single_aci_test.py --- old/389-ds-base-1.3.3.9/dirsrvtests/tickets/ticket47553_single_aci_test.py 2015-03-07 01:46:09.000000000 +0100 +++ new/389-ds-base-1.3.3.10/dirsrvtests/tickets/ticket47553_single_aci_test.py 2015-04-28 19:16:17.000000000 +0200 @@ -276,7 +276,27 @@ #topology.master1.modify_s(SUFFIX, mod) topology.master1.log.info("Add a DENY aci under %s " % PROD_EXCEPT_DN) topology.master1.modify_s(PROD_EXCEPT_DN, mod) - + +def _write_aci_staging(topology, mod_type=None): + assert mod_type is not None + + ACI_TARGET = "(targetattr= \"cn\")(target=\"ldap:///cn=*,%s\")" % STAGING_DN + ACI_ALLOW = "(version 3.0; acl \"write staging entries\"; allow (write)" + ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN + ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT + mod = [(mod_type, 'aci', ACI_BODY)] + topology.master1.modify_s(SUFFIX, mod) + +def _write_aci_production(topology, mod_type=None): + assert mod_type is not None + + ACI_TARGET = "(targetattr= \"cn\")(target=\"ldap:///cn=*,%s\")" % PRODUCTION_DN + ACI_ALLOW = "(version 3.0; acl \"write production entries\"; allow (write)" + ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN + ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT + mod = [(mod_type, 'aci', ACI_BODY)] + topology.master1.modify_s(SUFFIX, mod) + def _moddn_aci_staging_to_production(topology, mod_type=None, target_from=STAGING_DN, target_to=PRODUCTION_DN): assert mod_type != None @@ -293,6 +313,8 @@ ACI_BODY = ACI_TARGET_FROM + ACI_TARGET_TO + ACI_ALLOW + ACI_SUBJECT mod = [(mod_type, 'aci', ACI_BODY)] topology.master1.modify_s(SUFFIX, mod) + + _write_aci_staging(topology, mod_type=mod_type) def _moddn_aci_from_production_to_staging(topology, mod_type=None): assert mod_type != None @@ -303,6 +325,8 @@ ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT mod = [(mod_type, 'aci', ACI_BODY)] topology.master1.modify_s(SUFFIX, mod) + + _write_aci_production(topology, mod_type=mod_type) def test_ticket47553_init(topology): @@ -347,12 +371,9 @@ 'description': "production except DIT"}))) # enable acl error logging - #mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', '128')] - #topology.master1.modify_s(DN_CONFIG, mod) - #topology.master2.modify_s(DN_CONFIG, mod) - - - + mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', str(128+262144))] + topology.master1.modify_s(DN_CONFIG, mod) + topology.master2.modify_s(DN_CONFIG, mod) # add dummy entries in the staging DIT @@ -883,6 +904,7 @@ _bind_manager(topology) mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)] topology.master1.modify_s(PRODUCTION_DN, mod) + _write_aci_staging(topology, mod_type=ldap.MOD_ADD) _bind_normal(topology) topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior)) @@ -891,6 +913,7 @@ _bind_manager(topology) mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)] topology.master1.modify_s(PRODUCTION_DN, mod) + _write_aci_staging(topology, mod_type=ldap.MOD_DELETE) _bind_normal(topology) @@ -934,6 +957,7 @@ _bind_manager(topology) mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)] topology.master1.modify_s(PRODUCTION_DN, mod) + _write_aci_staging(topology, mod_type=ldap.MOD_ADD) _bind_normal(topology) try: @@ -949,6 +973,7 @@ _bind_manager(topology) mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)] topology.master1.modify_s(PRODUCTION_DN, mod) + _write_aci_staging(topology, mod_type=ldap.MOD_DELETE) _bind_normal(topology) # Add the moddn aci that will be evaluated because of the config flag @@ -1009,7 +1034,12 @@ old_dn = "%s,%s" % (old_rdn, PRODUCTION_DN) new_rdn = old_rdn new_superior = STAGING_DN - + + # add the write right because we want to check the moddn + _bind_manager(topology) + _write_aci_production(topology, mod_type=ldap.MOD_ADD) + _bind_normal(topology) + try: topology.master1.log.info("Try to move back MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior)) topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior) @@ -1019,7 +1049,11 @@ except Exception as e: topology.master1.log.info("Exception (expected): %s" % type(e).__name__) assert isinstance(e, ldap.INSUFFICIENT_ACCESS) - + + _bind_manager(topology) + _write_aci_production(topology, mod_type=ldap.MOD_DELETE) + _bind_normal(topology) + # successfull MOD with the both ACI _bind_manager(topology) _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/389-ds-base-1.3.3.9/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c new/389-ds-base-1.3.3.10/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c --- old/389-ds-base-1.3.3.9/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c 2015-03-07 01:46:09.000000000 +0100 +++ new/389-ds-base-1.3.3.10/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c 2015-04-28 19:16:17.000000000 +0200 @@ -677,31 +677,17 @@ /* JCMACL - Should be performed before the child check. */ /* JCMACL - Why is the check performed against the copy, rather than the existing entry? */ + /* This check must be performed even if the entry is renamed with its own name + * No optimization here we need to check we have the write access to the target entry + */ + ldap_result_code = plugin_call_acl_plugin(pb, ec->ep_entry, + NULL /*attr*/, NULL /*value*/, SLAPI_ACL_WRITE, + ACLPLUGIN_ACCESS_MODRDN, &errbuf); + if (ldap_result_code != LDAP_SUCCESS) { - Slapi_RDN *new_rdn; - Slapi_RDN *old_rdn; + goto error_return; + } - /* Taken from the entry */ - old_rdn = slapi_entry_get_srdn(ec->ep_entry); - - /* Taken from the request */ - new_rdn = slapi_rdn_new(); - slapi_sdn_get_rdn(&dn_newrdn, new_rdn); - - /* Only if we change the RDN value, we need the write access to the entry */ - if (slapi_rdn_compare(old_rdn, new_rdn)) { - ldap_result_code = plugin_call_acl_plugin(pb, ec->ep_entry, - NULL /*attr*/, NULL /*value*/, SLAPI_ACL_WRITE, - ACLPLUGIN_ACCESS_MODRDN, &errbuf); - } - - slapi_rdn_free(&new_rdn); - - if (ldap_result_code != LDAP_SUCCESS) { - goto error_return; - } - } - /* Set the new dn to the copy of the entry */ slapi_entry_set_sdn( ec->ep_entry, &dn_newdn ); if (entryrdn_get_switch()) { /* subtree-rename: on */