summaryrefslogtreecommitdiffstats
path: root/python/samba/tests/samba_startup_fl_change.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/samba/tests/samba_startup_fl_change.py')
-rw-r--r--python/samba/tests/samba_startup_fl_change.py180
1 files changed, 180 insertions, 0 deletions
diff --git a/python/samba/tests/samba_startup_fl_change.py b/python/samba/tests/samba_startup_fl_change.py
new file mode 100644
index 0000000..54fa9f8
--- /dev/null
+++ b/python/samba/tests/samba_startup_fl_change.py
@@ -0,0 +1,180 @@
+# Unix SMB/CIFS implementation. Tests for dsdb
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2023
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+"""Tests for samba.dsdb."""
+
+from samba.credentials import Credentials
+from samba.samdb import SamDB
+from samba.auth import system_session
+from samba.param import LoadParm
+from samba import dsdb, functional_level
+import ldb
+
+
+from samba.tests.samba_tool.base import SambaToolCmdTest
+import os
+import shutil
+import tempfile
+
+class SambaFLStartUpTests(SambaToolCmdTest):
+ """Test the samba binary sets the DC FL on startup for RW DCs"""
+
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ cls.classtempdir = tempfile.mkdtemp()
+ cls.tempsambadir = os.path.join(cls.classtempdir, "samba")
+
+ command = (
+ "samba-tool " +
+ "domain provision " +
+ "--realm=foo.example.com " +
+ "--domain=FOO " +
+ ("--targetdir=%s " % cls.tempsambadir) +
+ "--use-ntvfs"
+ )
+
+ (result, out, err) = cls.run_command(command)
+ if (result != 0):
+ raise AssertionError
+
+ @classmethod
+ def tearDownClass(cls):
+ super().tearDownClass()
+ shutil.rmtree(cls.tempsambadir)
+
+ def setUp(self):
+ super().setUp()
+ path = os.path.join(self.tempsambadir, "etc/smb.conf")
+ self.lp = LoadParm(filename_for_non_global_lp=path)
+ self.creds = Credentials()
+ self.creds.guess(self.lp)
+ self.session = system_session()
+ self.samdb = SamDB(session_info=self.session,
+ credentials=self.creds,
+ lp=self.lp)
+
+
+ def test_initial_db_fl_state(self):
+ server_dn = self.samdb.get_dsServiceName()
+ res = self.samdb.search(base=server_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=["msDS-Behavior-Version"])
+ # This confirms the domain is in FL 2008 R2 by default, this is
+ # important to verify the original state
+ self.assertEqual(int(res[0]["msDS-Behavior-Version"][0]),
+ dsdb.DS_DOMAIN_FUNCTION_2008_R2)
+
+ def test_initial_rootdse_domain_fl_state(self):
+ res = self.samdb.search(base="",
+ scope=ldb.SCOPE_BASE,
+ attrs=["domainControllerFunctionality"])
+ self.assertEqual(int(res[0]["domainControllerFunctionality"][0]),
+ dsdb.DS_DOMAIN_FUNCTION_2008_R2)
+
+ def test_initial_rootdse_dc_fl_state(self):
+ res = self.samdb.search(base="",
+ scope=ldb.SCOPE_BASE,
+ attrs=["domainFunctionality"])
+ self.assertEqual(int(res[0]["domainFunctionality"][0]),
+ dsdb.DS_DOMAIN_FUNCTION_2008_R2)
+
+ def test_initial_lp_fl_state(self):
+ lp_fl = self.lp.get("ad dc functional level")
+ # This confirms the domain is in FL 2008 R2 by default, this is
+ # important to verify the original state
+ self.assertEqual(lp_fl, "2008_R2")
+
+ def test_initial_lp_fl_state_mapped(self):
+ # Confirm the same via the dc_level_from_lp wrapper
+ self.assertEqual(functional_level.dc_level_from_lp(self.lp),
+ dsdb.DS_DOMAIN_FUNCTION_2008_R2)
+
+ def fixup_fl(self, dn, fl):
+ msg = ldb.Message()
+ msg.dn = dn
+ msg["msDS-Behavior-Version"] = (
+ ldb.MessageElement(str(fl),
+ ldb.FLAG_MOD_REPLACE,
+ "msDS-Behavior-Version"))
+ self.samdb.modify(msg)
+
+ def test_change_db_dc_fl(self):
+ server_dn = ldb.Dn(self.samdb, self.samdb.get_dsServiceName())
+ msg = ldb.Message()
+ msg.dn = server_dn
+ msg["msDS-Behavior-Version"] = (
+ ldb.MessageElement(str(dsdb.DS_DOMAIN_FUNCTION_2012_R2),
+ ldb.FLAG_MOD_REPLACE,
+ "msDS-Behavior-Version"))
+ self.samdb.modify(msg)
+ self.addCleanup(self.fixup_fl, msg.dn, dsdb.DS_DOMAIN_FUNCTION_2008_R2)
+
+ samdb2 = SamDB(session_info=self.session,
+ credentials=self.creds,
+ lp=self.lp)
+
+ # Check that the DB set to 2012_R2 has got as far as the rootDSE handler on a new connection
+ res = samdb2.search(base="",
+ scope=ldb.SCOPE_BASE,
+ attrs=["domainControllerFunctionality"])
+ self.assertEqual(int(res[0]["domainControllerFunctionality"][0]),
+ dsdb.DS_DOMAIN_FUNCTION_2012_R2)
+
+ def test_incorrect_db_dc_fl(self):
+ server_dn = ldb.Dn(self.samdb, self.samdb.get_dsServiceName())
+ self.addCleanup(self.fixup_fl, server_dn, dsdb.DS_DOMAIN_FUNCTION_2008_R2)
+
+ old_lp_fl = self.lp.get("ad dc functional level")
+ self.lp.set("ad dc functional level",
+ "2016")
+ self.addCleanup(self.lp.set, "ad dc functional level", old_lp_fl)
+
+ dsdb.check_and_update_fl(self.samdb, self.lp)
+
+ # Check this has been set to 2016 per the smb.conf setting
+ res = self.samdb.search(base="",
+ scope=ldb.SCOPE_BASE,
+ attrs=["domainControllerFunctionality"])
+ self.assertEqual(int(res[0]["domainControllerFunctionality"][0]),
+ dsdb.DS_DOMAIN_FUNCTION_2016)
+
+ samdb3 = SamDB(session_info=self.session,
+ credentials=self.creds,
+ lp=self.lp)
+
+ # Check this is still set on re-read (not just the opaque)
+ res = samdb3.search(base="",
+ scope=ldb.SCOPE_BASE,
+ attrs=["domainControllerFunctionality"])
+ self.assertEqual(int(res[0]["domainControllerFunctionality"][0]),
+ dsdb.DS_DOMAIN_FUNCTION_2016)
+
+ res = self.samdb.search(base=server_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=["msDS-Behavior-Version"])
+ self.assertEqual(int(res[0]["msDS-Behavior-Version"][0]),
+ dsdb.DS_DOMAIN_FUNCTION_2016)
+
+ self.assertEqual(functional_level.dc_level_from_lp(self.lp),
+ dsdb.DS_DOMAIN_FUNCTION_2016)
+ self.assertEqual(self.lp.get("ad dc functional level"),
+ "2016")
+
+if __name__ == "__main__":
+ import unittest
+ unittest.main()