subnet: Avoid a segfault when renaming subnet objects
authorGarming Sam <garming@catalyst.net.nz>
Wed, 20 Sep 2017 02:55:11 +0000 (14:55 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Mon, 19 Feb 2018 18:17:12 +0000 (19:17 +0100)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13031

Signed-off-by: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
python/samba/subnets.py
source4/dsdb/samdb/ldb_modules/samldb.c
source4/dsdb/tests/python/sites.py

index e859f06e46de63dff1bc471e7f47cb04fc8d6127..72eeb0f70d4b2aaf87ec9ffd7e1d23d1c186fc70 100644 (file)
@@ -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.
index 971048d455f7ee6a7aa5a33ea070775b919c6de9..3e429e1476a2f63b78851f9f49d9de8e4ab7d914 100644 (file)
@@ -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;
index a24f9b576d96c91b411f7e83048ae6bd1a4a5b07..5c8a484f0bb6f84aa0cb2aa7b953c1c34f8c6d7c 100755 (executable)
@@ -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."""