summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2021-09-13 10:21:03 +1200
committerJule Anger <janger@samba.org>2021-11-09 19:45:32 +0000
commit23983fb50b475b74eea8571e0d9c7923fd2ca76e (patch)
tree390d0d581e7d73b8d8d20d289bf3f5530931d33c
parent2bdff65b333365740e5e9c8c2b2fc176323f5108 (diff)
downloadsamba-23983fb50b475b74eea8571e0d9c7923fd2ca76e.tar.gz
CVE-2020-25722 selftest: Test combinations of account type and objectclass for creating a user
The idea here is to split out the restrictions seen on Windows 2019 at the schema level, as seen when acting as an administrator. These pass against Windows 2019 except for the account type swapping which is not wanted. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 Signed-off-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
-rw-r--r--selftest/knownfail.d/user_account_control-uac_mod_lock11
-rwxr-xr-xsource4/dsdb/tests/python/user_account_control.py165
2 files changed, 176 insertions, 0 deletions
diff --git a/selftest/knownfail.d/user_account_control-uac_mod_lock b/selftest/knownfail.d/user_account_control-uac_mod_lock
new file mode 100644
index 00000000000..a70534506f3
--- /dev/null
+++ b/selftest/knownfail.d/user_account_control-uac_mod_lock
@@ -0,0 +1,11 @@
+# We do not want user account control account type swapping, so we mark these as knownfail
+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_NORMAL_ACCOUNT_computer_replace
+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_NORMAL_ACCOUNT_user_replace
+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_SERVER_TRUST_ACCOUNT_computer_replace
+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_computer_replace
+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_WORKSTATION_TRUST_ACCOUNT_deladd
+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_WORKSTATION_TRUST_ACCOUNT_replace
+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_SERVER_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_deladd
+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_SERVER_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_replace
+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_deladd
+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_replace
diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py
index 4602b3e97d4..246a869e6c1 100755
--- a/source4/dsdb/tests/python/user_account_control.py
+++ b/source4/dsdb/tests/python/user_account_control.py
@@ -90,6 +90,41 @@ account_types = set([UF_NORMAL_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT, UF_SERVER_
class UserAccountControlTests(samba.tests.TestCase):
@classmethod
def setUpDynamicTestCases(cls):
+ for account_type in [UF_NORMAL_ACCOUNT,
+ UF_WORKSTATION_TRUST_ACCOUNT,
+ UF_SERVER_TRUST_ACCOUNT]:
+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type)
+ for objectclass in ["computer", "user"]:
+ test_name = f"{account_type_str}_{objectclass}"
+ cls.generate_dynamic_test("test_objectclass_uac_lock",
+ test_name,
+ account_type,
+ objectclass)
+
+ for account_type in [UF_NORMAL_ACCOUNT,
+ UF_WORKSTATION_TRUST_ACCOUNT,
+ UF_SERVER_TRUST_ACCOUNT]:
+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type)
+ for account_type2 in [UF_NORMAL_ACCOUNT,
+ UF_WORKSTATION_TRUST_ACCOUNT,
+ UF_SERVER_TRUST_ACCOUNT]:
+ for how in ["replace", "deladd"]:
+ account_type2_str = dsdb.user_account_control_flag_bit_to_string(account_type2)
+ test_name = f"{account_type_str}_{account_type2_str}_{how}"
+ cls.generate_dynamic_test("test_objectclass_uac_mod_lock",
+ test_name,
+ account_type,
+ account_type2,
+ how)
+ for objectclass in ["user", "computer"]:
+ for how in ["replace", "deladd"]:
+ test_name = f"{account_type_str}_{objectclass}_{how}"
+ cls.generate_dynamic_test("test_objectclass_mod_lock",
+ test_name,
+ account_type,
+ objectclass,
+ how)
+
for account_type in [UF_NORMAL_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT]:
account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type)
cls.generate_dynamic_test("test_uac_bits_unrelated_modify",
@@ -843,6 +878,136 @@ class UserAccountControlTests(samba.tests.TestCase):
"primaryGroupID")
self.admin_samdb.modify(m)
+ def _test_objectclass_uac_lock_with_args(self,
+ account_type,
+ objectclass):
+ name = "oc_uac_lock$"
+ dn = "CN=%s,%s" % (name, self.OU)
+ msg_dict = {
+ "dn": dn,
+ "objectclass": objectclass,
+ "samAccountName": name,
+ "userAccountControl": str(account_type | UF_PASSWD_NOTREQD)}
+
+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type)
+
+ print(f"Adding account {name} as {account_type_str} with objectclass {objectclass}")
+
+ if (objectclass == "user" \
+ and account_type == UF_NORMAL_ACCOUNT):
+ self.admin_samdb.add(msg_dict)
+ elif objectclass == "computer":
+ self.admin_samdb.add(msg_dict)
+ else:
+ self.assertRaisesLdbError(ldb.ERR_OBJECT_CLASS_VIOLATION,
+ "Should have been unable to {account_type_str} on {objectclass}",
+ self.admin_samdb.add, msg_dict)
+
+ def _test_objectclass_uac_mod_lock_with_args(self,
+ account_type,
+ account_type2,
+ how):
+ name = "uac_mod_lock$"
+ dn = "CN=%s,%s" % (name, self.OU)
+ if account_type == UF_NORMAL_ACCOUNT:
+ objectclass = "user"
+ else:
+ objectclass = "computer"
+
+ msg_dict = {
+ "dn": dn,
+ "objectclass": objectclass,
+ "samAccountName": name,
+ "userAccountControl": str(account_type | UF_PASSWD_NOTREQD)}
+
+ account_type_str \
+ = dsdb.user_account_control_flag_bit_to_string(account_type)
+ account_type2_str \
+ = dsdb.user_account_control_flag_bit_to_string(account_type2)
+
+ print(f"Adding account {name} as {account_type_str} with objectclass {objectclass}")
+
+ self.admin_samdb.add(msg_dict)
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.admin_samdb, dn)
+ if how == "replace":
+ m["userAccountControl"] = ldb.MessageElement(str(account_type2 | UF_PASSWD_NOTREQD),
+ ldb.FLAG_MOD_REPLACE, "userAccountControl")
+ elif how == "deladd":
+ m["0userAccountControl"] = ldb.MessageElement([],
+ ldb.FLAG_MOD_DELETE, "userAccountControl")
+ m["1userAccountControl"] = ldb.MessageElement(str(account_type2 | UF_PASSWD_NOTREQD),
+ ldb.FLAG_MOD_ADD, "userAccountControl")
+ else:
+ raise ValueError(f"{how} was not a valid argument")
+
+ if (account_type in [UF_SERVER_TRUST_ACCOUNT,
+ UF_WORKSTATION_TRUST_ACCOUNT]) and \
+ (account_type2 in [UF_SERVER_TRUST_ACCOUNT,
+ UF_WORKSTATION_TRUST_ACCOUNT]):
+ self.admin_samdb.modify(m)
+ elif (account_type == account_type2):
+ self.admin_samdb.modify(m)
+ else:
+ self.assertRaisesLdbError(ldb.ERR_UNWILLING_TO_PERFORM,
+ f"Should have been unable to change {account_type_str} to {account_type2_str}",
+ self.admin_samdb.modify, m)
+
+ def _test_objectclass_mod_lock_with_args(self,
+ account_type,
+ objectclass,
+ how):
+ name = "uac_mod_lock$"
+ dn = "CN=%s,%s" % (name, self.OU)
+ if objectclass == "computer":
+ new_objectclass = ["top",
+ "person",
+ "organizationalPerson",
+ "user"]
+ elif objectclass == "user":
+ new_objectclass = ["top",
+ "person",
+ "organizationalPerson",
+ "user",
+ "computer"]
+
+ msg_dict = {
+ "dn": dn,
+ "objectclass": objectclass,
+ "samAccountName": name,
+ "userAccountControl": str(account_type | UF_PASSWD_NOTREQD)}
+
+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type)
+
+ print(f"Adding account {name} as {account_type_str} with objectclass {objectclass}")
+
+ try:
+ self.admin_samdb.add(msg_dict)
+ if (objectclass == "user" \
+ and account_type != UF_NORMAL_ACCOUNT):
+ self.fail("Able to create {account_type_str} on {objectclass}")
+ except LdbError as e:
+ (enum, estr) = e.args
+ self.assertEqual(enum, ldb.ERR_OBJECT_CLASS_VIOLATION)
+
+ if objectclass == "user" and account_type != UF_NORMAL_ACCOUNT:
+ return
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.admin_samdb, dn)
+ if how == "replace":
+ m["objectclass"] = ldb.MessageElement(new_objectclass,
+ ldb.FLAG_MOD_REPLACE, "objectclass")
+ elif how == "adddel":
+ m["0objectclass"] = ldb.MessageElement([],
+ ldb.FLAG_MOD_DELETE, "objectclass")
+ m["1objectclass"] = ldb.MessageElement(new_objectclass,
+ ldb.FLAG_MOD_ADD, "objectclass")
+
+ self.assertRaisesLdbError(ldb.ERR_UNWILLING_TO_PERFORM,
+ "Should have been unable Able to change objectclass of a {objectclass}",
+ self.admin_samdb.modify, m)
runner = SubunitTestRunner()
rc = 0