The Samba-Bugzilla – Attachment 17315 Details for
Bug 14833
CVE-2022-32743 [SECURITY] Validated dnsHostname write right needs to be implemented
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
WIP patch for master
validated-dns-host-name.patch (text/plain), 27.95 KB, created by
Jennifer Sutton
on 2022-06-01 04:42:34 UTC
(
hide
)
Description:
WIP patch for master
Filename:
MIME Type:
Creator:
Jennifer Sutton
Created:
2022-06-01 04:42:34 UTC
Size:
27.95 KB
patch
obsolete
>From 3c3d94263f457eea03bc3ddbf1c510e748a75902 Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Wed, 1 Jun 2022 16:07:17 +1200 >Subject: [PATCH 1/2] s4-acl: Add tests for validated dNSHostName write > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14833 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >--- > selftest/knownfail.d/validated-dns-host-name | 11 + > source4/dsdb/tests/python/acl.py | 522 +++++++++++++++++++ > 2 files changed, 533 insertions(+) > create mode 100644 selftest/knownfail.d/validated-dns-host-name > >diff --git a/selftest/knownfail.d/validated-dns-host-name b/selftest/knownfail.d/validated-dns-host-name >new file mode 100644 >index 00000000000..3e22a57111d >--- /dev/null >+++ b/selftest/knownfail.d/validated-dns-host-name >@@ -0,0 +1,11 @@ >+^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name\( >+^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_account_no_dollar\( >+^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_allowed_suffixes\( >+^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_case\( >+^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_dollar\( >+^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_empty_string\( >+^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_invalid\( >+^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_no_suffix\( >+^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_no_value\( >+^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_wrong_prefix\( >+^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_wrong_suffix\( >diff --git a/source4/dsdb/tests/python/acl.py b/source4/dsdb/tests/python/acl.py >index 70dca9b7678..a778267e2d9 100755 >--- a/source4/dsdb/tests/python/acl.py >+++ b/source4/dsdb/tests/python/acl.py >@@ -300,6 +300,7 @@ class AclModifyTests(AclTests): > delete_force(self.ldb_admin, "CN=test_modify_group1,CN=Users," + self.base_dn) > delete_force(self.ldb_admin, "CN=test_modify_group2,CN=Users," + self.base_dn) > delete_force(self.ldb_admin, "CN=test_modify_group3,CN=Users," + self.base_dn) >+ delete_force(self.ldb_admin, "CN=test_mod_hostname,OU=test_modify_ou1," + self.base_dn) > delete_force(self.ldb_admin, "OU=test_modify_ou1," + self.base_dn) > delete_force(self.ldb_admin, self.get_user_dn(self.user_with_wp)) > delete_force(self.ldb_admin, self.get_user_dn(self.user_with_sm)) >@@ -651,6 +652,527 @@ Member: CN=test_modify_user2,CN=Users,""" + self.base_dn > else: > self.fail() > >+ def test_modify_dns_host_name(self): >+ '''Test modifying dNSHostName with validated write''' >+ >+ ou_dn = f'OU=test_modify_ou1,{self.base_dn}' >+ >+ account_name = 'test_mod_hostname' >+ dn = f'CN={account_name},{ou_dn}' >+ >+ self.ldb_admin.create_ou(ou_dn) >+ >+ # Grant Validated Write. >+ mod = (f'(OA;CI;SW;{security.GUID_DRS_DNS_HOST_NAME};;' >+ f'{self.user_sid})') >+ self.sd_utils.dacl_add_ace(ou_dn, mod) >+ >+ # Create the account. >+ self.ldb_admin.add({ >+ 'dn': dn, >+ 'objectClass': 'computer', >+ 'sAMAccountName': f'{account_name}$', >+ }) >+ >+ host_name = f'{account_name}.{self.ldb_user.domain_dns_name()}' >+ >+ m = Message(Dn(self.ldb_user, dn)) >+ m['dNSHostName'] = MessageElement(host_name, >+ FLAG_MOD_REPLACE, >+ 'dNSHostName') >+ try: >+ self.ldb_user.modify(m) >+ except LdbError: >+ self.fail() >+ >+ def test_modify_dns_host_name_no_validated_write(self): >+ '''Test modifying dNSHostName without validated write''' >+ >+ ou_dn = f'OU=test_modify_ou1,{self.base_dn}' >+ >+ account_name = 'test_mod_hostname' >+ dn = f'CN={account_name},{ou_dn}' >+ >+ self.ldb_admin.create_ou(ou_dn) >+ >+ # Create the account. >+ self.ldb_admin.add({ >+ 'dn': dn, >+ 'objectClass': 'computer', >+ 'sAMAccountName': f'{account_name}$', >+ }) >+ >+ host_name = f'{account_name}.{self.ldb_user.domain_dns_name()}' >+ >+ m = Message(Dn(self.ldb_user, dn)) >+ m['dNSHostName'] = MessageElement(host_name, >+ FLAG_MOD_REPLACE, >+ 'dNSHostName') >+ try: >+ self.ldb_user.modify(m) >+ except LdbError as err: >+ num, estr = err.args >+ self.assertEqual(ERR_INSUFFICIENT_ACCESS_RIGHTS, num) >+ else: >+ self.fail() >+ >+ def test_modify_dns_host_name_invalid(self): >+ '''Test modifying dNSHostName to an invalid value''' >+ >+ ou_dn = f'OU=test_modify_ou1,{self.base_dn}' >+ >+ account_name = 'test_mod_hostname' >+ dn = f'CN={account_name},{ou_dn}' >+ >+ self.ldb_admin.create_ou(ou_dn) >+ >+ # Grant Validated Write. >+ mod = (f'(OA;CI;SW;{security.GUID_DRS_DNS_HOST_NAME};;' >+ f'{self.user_sid})') >+ self.sd_utils.dacl_add_ace(ou_dn, mod) >+ >+ # Create the account. >+ self.ldb_admin.add({ >+ 'dn': dn, >+ 'objectClass': 'computer', >+ 'sAMAccountName': f'{account_name}$', >+ }) >+ >+ host_name = 'invalid' >+ >+ m = Message(Dn(self.ldb_user, dn)) >+ m['dNSHostName'] = MessageElement(host_name, >+ FLAG_MOD_REPLACE, >+ 'dNSHostName') >+ try: >+ self.ldb_user.modify(m) >+ except LdbError as err: >+ num, estr = err.args >+ self.assertEqual(ERR_CONSTRAINT_VIOLATION, num) >+ else: >+ self.fail() >+ >+ def test_modify_dns_host_name_invalid_wp(self): >+ '''Test modifying dNSHostName to an invalid value when we have WP''' >+ >+ ou_dn = f'OU=test_modify_ou1,{self.base_dn}' >+ >+ account_name = 'test_mod_hostname' >+ dn = f'CN={account_name},{ou_dn}' >+ >+ self.ldb_admin.create_ou(ou_dn) >+ >+ # Grant Validated Write and Write Property. >+ mod = (f'(OA;CI;SWWP;{security.GUID_DRS_DNS_HOST_NAME};;' >+ f'{self.user_sid})') >+ self.sd_utils.dacl_add_ace(ou_dn, mod) >+ >+ # Create the account. >+ self.ldb_admin.add({ >+ 'dn': dn, >+ 'objectClass': 'computer', >+ 'sAMAccountName': f'{account_name}$', >+ }) >+ >+ host_name = 'invalid' >+ >+ m = Message(Dn(self.ldb_user, dn)) >+ m['dNSHostName'] = MessageElement(host_name, >+ FLAG_MOD_REPLACE, >+ 'dNSHostName') >+ try: >+ self.ldb_user.modify(m) >+ except LdbError: >+ self.fail() >+ >+ def test_modify_dns_host_name_invalid_non_computer(self): >+ '''Test modifying dNSHostName to an invalid value on a non-computer''' >+ >+ ou_dn = f'OU=test_modify_ou1,{self.base_dn}' >+ >+ account_name = 'test_mod_hostname' >+ dn = f'CN={account_name},{ou_dn}' >+ >+ self.ldb_admin.create_ou(ou_dn) >+ >+ # Grant Validated Write. >+ mod = (f'(OA;CI;SW;{security.GUID_DRS_DNS_HOST_NAME};;' >+ f'{self.user_sid})') >+ self.sd_utils.dacl_add_ace(ou_dn, mod) >+ >+ # Create the account. >+ self.ldb_admin.add({ >+ 'dn': dn, >+ 'objectClass': 'user', >+ 'sAMAccountName': f'{account_name}', >+ }) >+ >+ host_name = 'invalid' >+ >+ m = Message(Dn(self.ldb_user, dn)) >+ m['dNSHostName'] = MessageElement(host_name, >+ FLAG_MOD_REPLACE, >+ 'dNSHostName') >+ try: >+ self.ldb_user.modify(m) >+ except LdbError as err: >+ num, estr = err.args >+ self.assertEqual(ERR_INSUFFICIENT_ACCESS_RIGHTS, num) >+ else: >+ self.fail() >+ >+ def test_modify_dns_host_name_no_value(self): >+ '''Test modifying dNSHostName with validated write with no value''' >+ >+ ou_dn = f'OU=test_modify_ou1,{self.base_dn}' >+ >+ account_name = 'test_mod_hostname' >+ dn = f'CN={account_name},{ou_dn}' >+ >+ self.ldb_admin.create_ou(ou_dn) >+ >+ # Grant Validated Write. >+ mod = (f'(OA;CI;SW;{security.GUID_DRS_DNS_HOST_NAME};;' >+ f'{self.user_sid})') >+ self.sd_utils.dacl_add_ace(ou_dn, mod) >+ >+ # Create the account. >+ self.ldb_admin.add({ >+ 'dn': dn, >+ 'objectClass': 'computer', >+ 'sAMAccountName': f'{account_name}$', >+ }) >+ >+ m = Message(Dn(self.ldb_user, dn)) >+ m['dNSHostName'] = MessageElement([], >+ FLAG_MOD_REPLACE, >+ 'dNSHostName') >+ try: >+ self.ldb_user.modify(m) >+ except LdbError as err: >+ num, estr = err.args >+ self.assertEqual(ERR_OPERATIONS_ERROR, num) >+ else: >+ # Windows accepts this. >+ pass >+ >+ def test_modify_dns_host_name_empty_string(self): >+ '''Test modifying dNSHostName with validated write of an empty string''' >+ >+ ou_dn = f'OU=test_modify_ou1,{self.base_dn}' >+ >+ account_name = 'test_mod_hostname' >+ dn = f'CN={account_name},{ou_dn}' >+ >+ self.ldb_admin.create_ou(ou_dn) >+ >+ # Grant Validated Write. >+ mod = (f'(OA;CI;SW;{security.GUID_DRS_DNS_HOST_NAME};;' >+ f'{self.user_sid})') >+ self.sd_utils.dacl_add_ace(ou_dn, mod) >+ >+ # Create the account. >+ self.ldb_admin.add({ >+ 'dn': dn, >+ 'objectClass': 'computer', >+ 'sAMAccountName': f'{account_name}$', >+ }) >+ >+ m = Message(Dn(self.ldb_user, dn)) >+ m['dNSHostName'] = MessageElement('\0', >+ FLAG_MOD_REPLACE, >+ 'dNSHostName') >+ try: >+ self.ldb_user.modify(m) >+ except LdbError as err: >+ num, estr = err.args >+ self.assertEqual(ERR_CONSTRAINT_VIOLATION, num) >+ else: >+ self.fail() >+ >+ def test_modify_dns_host_name_dollar(self): >+ '''Test modifying dNSHostName with validated write of a value including a dollar''' >+ >+ ou_dn = f'OU=test_modify_ou1,{self.base_dn}' >+ >+ account_name = 'test_mod_hostname' >+ dn = f'CN={account_name},{ou_dn}' >+ >+ self.ldb_admin.create_ou(ou_dn) >+ >+ # Grant Validated Write. >+ mod = (f'(OA;CI;SW;{security.GUID_DRS_DNS_HOST_NAME};;' >+ f'{self.user_sid})') >+ self.sd_utils.dacl_add_ace(ou_dn, mod) >+ >+ # Create the account. >+ self.ldb_admin.add({ >+ 'dn': dn, >+ 'objectClass': 'computer', >+ 'sAMAccountName': f'{account_name}$', >+ }) >+ >+ host_name = f'{account_name}$.{self.ldb_user.domain_dns_name()}' >+ >+ m = Message(Dn(self.ldb_user, dn)) >+ m['dNSHostName'] = MessageElement(host_name, >+ FLAG_MOD_REPLACE, >+ 'dNSHostName') >+ try: >+ self.ldb_user.modify(m) >+ except LdbError as err: >+ num, estr = err.args >+ self.assertEqual(ERR_CONSTRAINT_VIOLATION, num) >+ else: >+ self.fail() >+ >+ def test_modify_dns_host_name_account_no_dollar(self): >+ '''Test modifying dNSHostName with validated write with no dollar in sAMAccountName''' >+ >+ ou_dn = f'OU=test_modify_ou1,{self.base_dn}' >+ >+ account_name = 'test_mod_hostname' >+ dn = f'CN={account_name},{ou_dn}' >+ >+ self.ldb_admin.create_ou(ou_dn) >+ >+ # Grant Validated Write. >+ mod = (f'(OA;CI;SW;{security.GUID_DRS_DNS_HOST_NAME};;' >+ f'{self.user_sid})') >+ self.sd_utils.dacl_add_ace(ou_dn, mod) >+ >+ # Create the account. >+ self.ldb_admin.add({ >+ 'dn': dn, >+ 'objectClass': 'computer', >+ 'sAMAccountName': f'{account_name}', >+ }) >+ >+ host_name = f'{account_name}.{self.ldb_user.domain_dns_name()}' >+ >+ m = Message(Dn(self.ldb_user, dn)) >+ m['dNSHostName'] = MessageElement(host_name, >+ FLAG_MOD_REPLACE, >+ 'dNSHostName') >+ try: >+ self.ldb_user.modify(m) >+ except LdbError: >+ self.fail() >+ >+ def test_modify_dns_host_name_no_suffix(self): >+ '''Test modifying dNSHostName with validated write of a value missing the suffix''' >+ >+ ou_dn = f'OU=test_modify_ou1,{self.base_dn}' >+ >+ account_name = 'test_mod_hostname' >+ dn = f'CN={account_name},{ou_dn}' >+ >+ self.ldb_admin.create_ou(ou_dn) >+ >+ # Grant Validated Write. >+ mod = (f'(OA;CI;SW;{security.GUID_DRS_DNS_HOST_NAME};;' >+ f'{self.user_sid})') >+ self.sd_utils.dacl_add_ace(ou_dn, mod) >+ >+ # Create the account. >+ self.ldb_admin.add({ >+ 'dn': dn, >+ 'objectClass': 'computer', >+ 'sAMAccountName': f'{account_name}$', >+ }) >+ >+ host_name = f'{account_name}' >+ >+ m = Message(Dn(self.ldb_user, dn)) >+ m['dNSHostName'] = MessageElement(host_name, >+ FLAG_MOD_REPLACE, >+ 'dNSHostName') >+ try: >+ self.ldb_user.modify(m) >+ except LdbError as err: >+ num, estr = err.args >+ self.assertEqual(ERR_CONSTRAINT_VIOLATION, num) >+ else: >+ self.fail() >+ >+ def test_modify_dns_host_name_wrong_prefix(self): >+ '''Test modifying dNSHostName with validated write of a value with the wrong prefix''' >+ >+ ou_dn = f'OU=test_modify_ou1,{self.base_dn}' >+ >+ account_name = 'test_mod_hostname' >+ dn = f'CN={account_name},{ou_dn}' >+ >+ self.ldb_admin.create_ou(ou_dn) >+ >+ # Grant Validated Write. >+ mod = (f'(OA;CI;SW;{security.GUID_DRS_DNS_HOST_NAME};;' >+ f'{self.user_sid})') >+ self.sd_utils.dacl_add_ace(ou_dn, mod) >+ >+ # Create the account. >+ self.ldb_admin.add({ >+ 'dn': dn, >+ 'objectClass': 'computer', >+ 'sAMAccountName': f'{account_name}$', >+ }) >+ >+ host_name = f'invalid.{self.ldb_user.domain_dns_name()}' >+ >+ m = Message(Dn(self.ldb_user, dn)) >+ m['dNSHostName'] = MessageElement(host_name, >+ FLAG_MOD_REPLACE, >+ 'dNSHostName') >+ try: >+ self.ldb_user.modify(m) >+ except LdbError as err: >+ num, estr = err.args >+ self.assertEqual(ERR_CONSTRAINT_VIOLATION, num) >+ else: >+ self.fail() >+ >+ def test_modify_dns_host_name_wrong_suffix(self): >+ '''Test modifying dNSHostName with validated write of a value with the wrong suffix''' >+ >+ ou_dn = f'OU=test_modify_ou1,{self.base_dn}' >+ >+ account_name = 'test_mod_hostname' >+ dn = f'CN={account_name},{ou_dn}' >+ >+ self.ldb_admin.create_ou(ou_dn) >+ >+ # Grant Validated Write. >+ mod = (f'(OA;CI;SW;{security.GUID_DRS_DNS_HOST_NAME};;' >+ f'{self.user_sid})') >+ self.sd_utils.dacl_add_ace(ou_dn, mod) >+ >+ # Create the account. >+ self.ldb_admin.add({ >+ 'dn': dn, >+ 'objectClass': 'computer', >+ 'sAMAccountName': f'{account_name}$', >+ }) >+ >+ host_name = f'{account_name}.invalid.example.com' >+ >+ m = Message(Dn(self.ldb_user, dn)) >+ m['dNSHostName'] = MessageElement(host_name, >+ FLAG_MOD_REPLACE, >+ 'dNSHostName') >+ try: >+ self.ldb_user.modify(m) >+ except LdbError as err: >+ num, estr = err.args >+ self.assertEqual(ERR_CONSTRAINT_VIOLATION, num) >+ else: >+ self.fail() >+ >+ def test_modify_dns_host_name_case(self): >+ '''Test modifying dNSHostName with validated write of a value with irregular case''' >+ >+ ou_dn = f'OU=test_modify_ou1,{self.base_dn}' >+ >+ account_name = 'test_mod_hostname' >+ dn = f'CN={account_name},{ou_dn}' >+ >+ self.ldb_admin.create_ou(ou_dn) >+ >+ # Grant Validated Write. >+ mod = (f'(OA;CI;SW;{security.GUID_DRS_DNS_HOST_NAME};;' >+ f'{self.user_sid})') >+ self.sd_utils.dacl_add_ace(ou_dn, mod) >+ >+ # Create the account. >+ self.ldb_admin.add({ >+ 'dn': dn, >+ 'objectClass': 'computer', >+ 'sAMAccountName': f'{account_name}$', >+ }) >+ >+ host_name = f'{account_name}.{self.ldb_user.domain_dns_name()}' >+ host_name = host_name.capitalize() >+ >+ m = Message(Dn(self.ldb_user, dn)) >+ m['dNSHostName'] = MessageElement(host_name, >+ FLAG_MOD_REPLACE, >+ 'dNSHostName') >+ try: >+ self.ldb_user.modify(m) >+ except LdbError: >+ self.fail() >+ >+ def test_modify_dns_host_name_allowed_suffixes(self): >+ '''Test modifying dNSHostName with validated write and an allowed suffix''' >+ >+ allowed_suffix = 'suffix.that.is.allowed' >+ >+ # Add the allowed suffix. >+ >+ res = self.ldb_admin.search(self.base_dn, >+ scope=SCOPE_BASE, >+ attrs=['msDS-AllowedDNSSuffixes']) >+ self.assertEqual(1, len(res)) >+ old_allowed_suffixes = res[0].get('msDS-AllowedDNSSuffixes') >+ >+ def modify_allowed_suffixes(suffixes): >+ if suffixes is None: >+ suffixes = [] >+ flag = FLAG_MOD_DELETE >+ else: >+ flag = FLAG_MOD_REPLACE >+ >+ m = Message(Dn(self.ldb_admin, self.base_dn)) >+ m['msDS-AllowedDNSSuffixes'] = MessageElement( >+ suffixes, >+ flag, >+ 'msDS-AllowedDNSSuffixes') >+ self.ldb_admin.modify(m) >+ >+ self.addCleanup(modify_allowed_suffixes, old_allowed_suffixes) >+ >+ if old_allowed_suffixes is None: >+ allowed_suffixes = [] >+ else: >+ allowed_suffixes = list(old_allowed_suffixes) >+ >+ if (allowed_suffix not in allowed_suffixes and >+ allowed_suffix.encode('utf-8') not in allowed_suffixes): >+ allowed_suffixes.append(allowed_suffix) >+ >+ modify_allowed_suffixes(allowed_suffixes) >+ >+ # Create the account and run the test. >+ >+ ou_dn = f'OU=test_modify_ou1,{self.base_dn}' >+ >+ account_name = 'test_mod_hostname' >+ dn = f'CN={account_name},{ou_dn}' >+ >+ self.ldb_admin.create_ou(ou_dn) >+ >+ # Grant Validated Write. >+ mod = (f'(OA;CI;SW;{security.GUID_DRS_DNS_HOST_NAME};;' >+ f'{self.user_sid})') >+ self.sd_utils.dacl_add_ace(ou_dn, mod) >+ >+ # Create the account. >+ self.ldb_admin.add({ >+ 'dn': dn, >+ 'objectClass': 'computer', >+ 'sAMAccountName': f'{account_name}$', >+ }) >+ >+ host_name = f'{account_name}.{allowed_suffix}' >+ >+ m = Message(Dn(self.ldb_user, dn)) >+ m['dNSHostName'] = MessageElement(host_name, >+ FLAG_MOD_REPLACE, >+ 'dNSHostName') >+ try: >+ self.ldb_user.modify(m) >+ except LdbError: >+ self.fail() >+ > # enable these when we have search implemented > > >-- >2.35.0 > > >From 9476d6ad8e735144918c390a77dba2ebf2acaa53 Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Wed, 1 Jun 2022 16:08:42 +1200 >Subject: [PATCH 2/2] dsdb: Implement validated dNSHostName write > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14833 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >--- > selftest/knownfail.d/validated-dns-host-name | 11 - > source4/dsdb/samdb/ldb_modules/acl.c | 237 +++++++++++++++++++ > 2 files changed, 237 insertions(+), 11 deletions(-) > delete mode 100644 selftest/knownfail.d/validated-dns-host-name > >diff --git a/selftest/knownfail.d/validated-dns-host-name b/selftest/knownfail.d/validated-dns-host-name >deleted file mode 100644 >index 3e22a57111d..00000000000 >--- a/selftest/knownfail.d/validated-dns-host-name >+++ /dev/null >@@ -1,11 +0,0 @@ >-^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name\( >-^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_account_no_dollar\( >-^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_allowed_suffixes\( >-^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_case\( >-^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_dollar\( >-^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_empty_string\( >-^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_invalid\( >-^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_no_suffix\( >-^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_no_value\( >-^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_wrong_prefix\( >-^samba4.ldap.acl.python.*__main__.AclModifyTests.test_modify_dns_host_name_wrong_suffix\( >diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c >index 289c885cdb1..61cd74f0510 100644 >--- a/source4/dsdb/samdb/ldb_modules/acl.c >+++ b/source4/dsdb/samdb/ldb_modules/acl.c >@@ -801,6 +801,231 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx, > return LDB_SUCCESS; > } > >+static int acl_check_dns_host_name(TALLOC_CTX *mem_ctx, >+ struct ldb_module *module, >+ struct ldb_request *req, >+ const struct ldb_message_element *el, >+ struct security_descriptor *sd, >+ struct dom_sid *sid, >+ const struct dsdb_attribute *attr, >+ const struct dsdb_class *objectclass) >+{ >+ int ret; >+ unsigned i; >+ TALLOC_CTX *tmp_ctx = NULL; >+ struct ldb_context *ldb = ldb_module_get_ctx(module); >+ const struct ldb_message_element *oc_el = NULL; >+ const struct ldb_message_element *allowed_suffixes = NULL; >+ struct ldb_result *nc_res = NULL; >+ struct ldb_dn *nc_root = NULL; >+ const char *nc_dns_name = NULL; >+ const char *dns_host_name = NULL; >+ const char *samAccountName = NULL; >+ size_t account_name_len; >+ const struct ldb_message *search_res = NULL; >+ >+ static const char *nc_attrs[] = { >+ "msDS-AllowedDNSSuffixes", >+ NULL >+ }; >+ >+ if (el->num_values == 0) { >+ return LDB_SUCCESS; >+ } >+ >+ tmp_ctx = talloc_new(mem_ctx); >+ if (tmp_ctx == NULL) { >+ return ldb_oom(ldb); >+ } >+ >+ /* if we have wp, we can do whatever we like */ >+ ret = acl_check_access_on_attribute(module, >+ tmp_ctx, >+ sd, >+ sid, >+ SEC_ADS_WRITE_PROP, >+ attr, objectclass); >+ if (ret == LDB_SUCCESS) { >+ talloc_free(tmp_ctx); >+ return LDB_SUCCESS; >+ } >+ >+ ret = acl_check_extended_right(tmp_ctx, >+ module, >+ req, >+ objectclass, >+ sd, >+ acl_user_token(module), >+ GUID_DRS_DNS_HOST_NAME, >+ SEC_ADS_SELF_WRITE, >+ sid); >+ >+ if (ret != LDB_SUCCESS) { >+ dsdb_acl_debug(sd, acl_user_token(module), >+ req->op.mod.message->dn, >+ true, >+ 10); >+ talloc_free(tmp_ctx); >+ return ret; >+ } >+ >+ /* >+ * If we have "validated write spn", allow delete of any >+ * existing value (this keeps constrained delete to the same >+ * rules as unconstrained) >+ */ >+ if (req->operation == LDB_MODIFY) { >+ struct ldb_result *acl_res = NULL; >+ >+ static const char *acl_attrs[] = { >+ "sAMAccountName", >+ "objectClass", >+ NULL >+ }; >+ >+ /* >+ * If not add or replace (eg delete), >+ * return success >+ */ >+ if ((el->flags >+ & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE)) == 0) { >+ talloc_free(tmp_ctx); >+ return LDB_SUCCESS; >+ } >+ >+ ret = dsdb_module_search_dn(module, tmp_ctx, >+ &acl_res, req->op.mod.message->dn, >+ acl_attrs, >+ DSDB_FLAG_NEXT_MODULE | >+ DSDB_FLAG_AS_SYSTEM | >+ DSDB_SEARCH_SHOW_RECYCLED, >+ req); >+ if (ret != LDB_SUCCESS) { >+ talloc_free(tmp_ctx); >+ return ret; >+ } >+ >+ search_res = acl_res->msgs[0]; >+ } else if (req->operation == LDB_ADD) { >+ search_res = req->op.add.message; >+ } else { >+ talloc_free(tmp_ctx); >+ return LDB_ERR_OPERATIONS_ERROR; >+ } >+ >+ /* Check if the account has objectclass 'computer' or 'server'. */ >+ oc_el = samdb_find_attribute(ldb, >+ search_res, >+ "objectclass", >+ "computer"); >+ if (oc_el == NULL) { >+ oc_el = samdb_find_attribute(ldb, >+ search_res, >+ "objectclass", >+ "server"); >+ >+ if (oc_el == NULL) { >+ /* Not a computer or server, so return. */ >+ talloc_free(tmp_ctx); >+ return LDB_SUCCESS; >+ } >+ } >+ >+ samAccountName = ldb_msg_find_attr_as_string(search_res, "sAMAccountName", NULL); >+ if (samAccountName == NULL) { >+ talloc_free(tmp_ctx); >+ return ldb_operr(ldb); >+ } >+ account_name_len = strlen(samAccountName); >+ if (account_name_len && samAccountName[account_name_len - 1] == '$') { >+ /* Account for the '$' character. */ >+ --account_name_len; >+ } >+ >+ dns_host_name = (const char *)el->values[0].data; >+ /* TODO: Ensure string is zero-terminated */ >+ SMB_ASSERT(dns_host_name[el->values[0].length] == '\0'); >+ >+ /* Check that sAMAccountName matches the new dNSHostName. */ >+ if (strncasecmp(dns_host_name, samAccountName, >+ account_name_len) != 0) { >+ goto fail; >+ } >+ >+ dns_host_name += account_name_len; >+ >+ /* Check the '.' character */ >+ if (*dns_host_name++ != '.') { >+ goto fail; >+ } >+ >+ /* Now we check the suffix. */ >+ >+ ret = dsdb_find_nc_root(ldb, >+ tmp_ctx, >+ search_res->dn, >+ &nc_root); >+ if (ret != LDB_SUCCESS) { >+ talloc_free(tmp_ctx); >+ return ret; >+ } >+ >+ nc_dns_name = samdb_dn_to_dns_domain(tmp_ctx, nc_root); >+ if (nc_dns_name == NULL) { >+ talloc_free(tmp_ctx); >+ return ret; >+ } >+ >+ if (strcasecmp(dns_host_name, nc_dns_name) == 0) { >+ /* It matches - success. */ >+ talloc_free(tmp_ctx); >+ return LDB_SUCCESS; >+ } >+ >+ /* We didn't get a match, so now try msDS-AllowedDNSSuffixes. */ >+ >+ ret = dsdb_module_search_dn(module, tmp_ctx, >+ &nc_res, nc_root, >+ nc_attrs, >+ DSDB_FLAG_NEXT_MODULE | >+ DSDB_FLAG_AS_SYSTEM | >+ DSDB_SEARCH_SHOW_RECYCLED, >+ req); >+ if (ret != LDB_SUCCESS) { >+ talloc_free(tmp_ctx); >+ return ret; >+ } >+ >+ allowed_suffixes = ldb_msg_find_element(nc_res->msgs[0], >+ "msDS-AllowedDNSSuffixes"); >+ if (allowed_suffixes == NULL) { >+ goto fail; >+ } >+ >+ for (i = 0; i < allowed_suffixes->num_values; ++i) { >+ const struct ldb_val *val = &allowed_suffixes->values[i]; >+ >+ /* TODO: Ensure string is zero-terminated */ >+ SMB_ASSERT(val->data[val->length] == '\0'); >+ >+ if (strcasecmp(dns_host_name, (const char *)val->data) == 0) { >+ /* It matches - success. */ >+ talloc_free(tmp_ctx); >+ return LDB_SUCCESS; >+ } >+ } >+ >+fail: >+ // TODO: ensure that variables printed are non-NULL! >+ >+ talloc_free(tmp_ctx); >+ ldb_debug_set(ldb, LDB_DEBUG_WARNING, >+ "acl: hostname validation failed for " >+ "account[%s] hostname[%s]\n", >+ samAccountName, el->values[0].data); >+ return LDB_ERR_CONSTRAINT_VIOLATION; >+} >+ > static int acl_add(struct ldb_module *module, struct ldb_request *req) > { > int ret; >@@ -1535,6 +1760,18 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) > if (ret != LDB_SUCCESS) { > goto fail; > } >+ } else if (ldb_attr_cmp("dnsHostName", el->name) == 0) { >+ ret = acl_check_dns_host_name(tmp_ctx, >+ module, >+ req, >+ el, >+ sd, >+ sid, >+ attr, >+ objectclass); >+ if (ret != LDB_SUCCESS) { >+ goto fail; >+ } > } else if (is_undelete != NULL && (ldb_attr_cmp("isDeleted", el->name) == 0)) { > /* > * in case of undelete op permissions on >-- >2.35.0 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 14833
:
17315
|
17333