From e2f62e211efd4eb83e7402b83bb7de9d5d1097a3 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Wed, 20 Sep 2017 14:55:11 +1200 Subject: [PATCH] subnet: Avoid a segfault when renaming subnet objects BUG: https://bugzilla.samba.org/show_bug.cgi?id=13031 Signed-off-by: Garming Sam Reviewed-by: Douglas Bagnall --- python/samba/subnets.py | 33 ++++++++++++++++++++++++ source4/dsdb/samdb/ldb_modules/samldb.c | 8 +++--- source4/dsdb/tests/python/sites.py | 45 +++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 4 deletions(-) diff --git a/python/samba/subnets.py b/python/samba/subnets.py index e859f06e46d..72eeb0f70d4 100644 --- a/python/samba/subnets.py +++ b/python/samba/subnets.py @@ -127,6 +127,39 @@ def delete_subnet(samdb, configDn, subnet_name): samdb.delete(dnsubnet) +def rename_subnet(samdb, configDn, subnet_name, new_name): + """Rename a subnet. + + :param samdb: A samdb connection + :param configDn: The DN of the configuration partition + :param subnet_name: Name of the subnet to rename + :param new_name: New name for the subnet + :return: None + :raise SubnetNotFound: if the subnet to be renamed does not exist. + :raise SubnetExists: if the subnet to be created already exists. + """ + dnsubnet = ldb.Dn(samdb, "CN=Subnets,CN=Sites") + if dnsubnet.add_base(configDn) == False: + raise SubnetException("dnsubnet.add_base() failed") + if dnsubnet.add_child("CN=X") == False: + raise SubnetException("dnsubnet.add_child() failed") + dnsubnet.set_component(0, "CN", subnet_name) + + newdnsubnet = ldb.Dn(samdb, str(dnsubnet)) + newdnsubnet.set_component(0, "CN", new_name) + try: + samdb.rename(dnsubnet, newdnsubnet) + except LdbError as (enum, estr): + if enum == ldb.ERR_NO_SUCH_OBJECT: + raise SubnetNotFound('Subnet %s does not exist' % subnet) + elif enum == ldb.ERR_ENTRY_ALREADY_EXISTS: + raise SubnetAlreadyExists('A subnet with the CIDR %s already exists' + % new_name) + elif enum == ldb.ERR_INVALID_DN_SYNTAX: + raise SubnetInvalid("%s is not a valid subnet: %s" % (new_name, + estr)) + else: + raise def set_subnet_site(samdb, configDn, subnet_name, site_name): """Assign a subnet to a site. diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c index 971048d455f..3e429e1476a 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -3351,13 +3351,13 @@ static int verify_cidr(const char *cidr) } -static int samldb_verify_subnet(struct samldb_ctx *ac) +static int samldb_verify_subnet(struct samldb_ctx *ac, struct ldb_dn *dn) { struct ldb_context *ldb = ldb_module_get_ctx(ac->module); const char *cidr = NULL; const struct ldb_val *rdn_value = NULL; - rdn_value = ldb_dn_get_rdn_val(ac->msg->dn); + rdn_value = ldb_dn_get_rdn_val(dn); if (rdn_value == NULL) { ldb_set_errstring(ldb, "samldb: ldb_dn_get_rdn_val " "failed"); @@ -3588,7 +3588,7 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req) if (samdb_find_attribute(ldb, ac->msg, "objectclass", "subnet") != NULL) { - ret = samldb_verify_subnet(ac); + ret = samldb_verify_subnet(ac, ac->msg->dn); if (ret != LDB_SUCCESS) { talloc_free(ac); return ret; @@ -3991,7 +3991,7 @@ static int check_rename_constraints(struct ldb_message *msg, /* subnet objects */ if (samdb_find_attribute(ldb, msg, "objectclass", "subnet") != NULL) { - ret = samldb_verify_subnet(ac); + ret = samldb_verify_subnet(ac, newdn); if (ret != LDB_SUCCESS) { talloc_free(ac); return ret; diff --git a/source4/dsdb/tests/python/sites.py b/source4/dsdb/tests/python/sites.py index a894da327a9..123e1ece60f 100755 --- a/source4/dsdb/tests/python/sites.py +++ b/source4/dsdb/tests/python/sites.py @@ -183,6 +183,51 @@ class SimpleSubnetTests(SitesBaseTests): self.assertRaises(subnets.SubnetNotFound, subnets.delete_subnet, self.ldb, basedn, cidr) + def test_rename_good_subnet_to_good_subnet(self): + """Make sure that we can rename subnets""" + basedn = self.ldb.get_config_basedn() + cidr = "10.16.0.0/24" + new_cidr = "10.16.1.0/24" + + subnets.create_subnet(self.ldb, basedn, cidr, self.sitename) + + subnets.rename_subnet(self.ldb, basedn, cidr, new_cidr) + + ret = self.ldb.search(base=basedn, scope=SCOPE_SUBTREE, + expression='(&(objectclass=subnet)(cn=%s))' % new_cidr) + + self.assertEqual(len(ret), 1, 'Failed to rename subnet %s' % cidr) + + ret = self.ldb.search(base=basedn, scope=SCOPE_SUBTREE, + expression='(&(objectclass=subnet)(cn=%s))' % cidr) + + self.assertEqual(len(ret), 0, 'Failed to remove old subnet during rename %s' % cidr) + + subnets.delete_subnet(self.ldb, basedn, new_cidr) + + def test_rename_good_subnet_to_bad_subnet(self): + """Make sure that the CIDR checking runs during rename""" + basedn = self.ldb.get_config_basedn() + cidr = "10.17.0.0/24" + bad_cidr = "10.11.12.0/14" + + subnets.create_subnet(self.ldb, basedn, cidr, self.sitename) + + self.assertRaises(subnets.SubnetInvalid, subnets.rename_subnet, + self.ldb, basedn, cidr, bad_cidr) + + ret = self.ldb.search(base=basedn, scope=SCOPE_SUBTREE, + expression='(&(objectclass=subnet)(cn=%s))' % bad_cidr) + + self.assertEqual(len(ret), 0, 'Failed to rename subnet %s' % cidr) + + ret = self.ldb.search(base=basedn, scope=SCOPE_SUBTREE, + expression='(&(objectclass=subnet)(cn=%s))' % cidr) + + self.assertEqual(len(ret), 1, 'Failed to remove old subnet during rename %s' % cidr) + + subnets.delete_subnet(self.ldb, basedn, cidr) + def test_create_bad_ranges(self): """These CIDR ranges all have something wrong with them, and they should all fail.""" -- 2.14.1