mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
s4-dsdb: Tests for security checks on undelete operation
Implemented according to MS-ADTS 3.1.1.5.3.7.1. Unfortunately it appears LC is also necessary, and it is not granted by default to anyone but System and Administrator, so tests had to be done negatively Signed-off-by: Nadezhda Ivanova <nivanova@symas.com> Reviewed-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Garming Sam <garming@catalyst.net.nz> Change-Id: Ic03b8fc4e222e7842ec8a9645a1bb33e7df9c438
This commit is contained in:
parent
def9d26868
commit
ac8b8e5539
@ -62,7 +62,7 @@ class SDUtils(object):
|
||||
def dacl_add_ace(self, object_dn, ace):
|
||||
"""Add an ACE to an objects security descriptor
|
||||
"""
|
||||
desc = self.read_sd_on_dn(object_dn)
|
||||
desc = self.read_sd_on_dn(object_dn,["show_deleted:1"])
|
||||
desc_sddl = desc.as_sddl(self.domain_sid)
|
||||
if ace in desc_sddl:
|
||||
return
|
||||
@ -71,10 +71,10 @@ class SDUtils(object):
|
||||
desc_sddl[desc_sddl.index("("):])
|
||||
else:
|
||||
desc_sddl = desc_sddl + ace
|
||||
self.modify_sd_on_dn(object_dn, desc_sddl)
|
||||
self.modify_sd_on_dn(object_dn, desc_sddl, ["show_deleted:1"])
|
||||
|
||||
def get_sd_as_sddl(self, object_dn, controls=None):
|
||||
def get_sd_as_sddl(self, object_dn, controls=[]):
|
||||
"""Return object nTSecutiryDescriptor in SDDL format
|
||||
"""
|
||||
desc = self.read_sd_on_dn(object_dn, controls=controls)
|
||||
desc = self.read_sd_on_dn(object_dn, controls + ["show_deleted:1"])
|
||||
return desc.as_sddl(self.domain_sid)
|
||||
|
@ -20,7 +20,7 @@ from ldb import (
|
||||
from ldb import ERR_CONSTRAINT_VIOLATION
|
||||
from ldb import ERR_OPERATIONS_ERROR
|
||||
from ldb import Message, MessageElement, Dn
|
||||
from ldb import FLAG_MOD_REPLACE, FLAG_MOD_ADD
|
||||
from ldb import FLAG_MOD_REPLACE, FLAG_MOD_ADD, FLAG_MOD_DELETE
|
||||
from samba.dcerpc import security, drsuapi, misc
|
||||
|
||||
from samba.auth import system_session
|
||||
@ -1637,6 +1637,136 @@ class AclExtendedTests(AclTests):
|
||||
self.assertEqual(len(res),1)
|
||||
self.assertTrue("nTSecurityDescriptor" in res[0].keys())
|
||||
|
||||
class AclUndeleteTests(AclTests):
|
||||
|
||||
def setUp(self):
|
||||
super(AclUndeleteTests, self).setUp()
|
||||
self.regular_user = "undeleter1"
|
||||
self.ou1 = "OU=undeleted_ou,"
|
||||
self.testuser1 = "to_be_undeleted1"
|
||||
self.testuser2 = "to_be_undeleted2"
|
||||
self.testuser3 = "to_be_undeleted3"
|
||||
self.testuser4 = "to_be_undeleted4"
|
||||
self.testuser5 = "to_be_undeleted5"
|
||||
self.testuser6 = "to_be_undeleted6"
|
||||
|
||||
self.new_dn_ou = "CN="+ self.testuser4 + "," + self.ou1 + self.base_dn
|
||||
|
||||
# Create regular user
|
||||
self.testuser1_dn = self.get_user_dn(self.testuser1)
|
||||
self.testuser2_dn = self.get_user_dn(self.testuser2)
|
||||
self.testuser3_dn = self.get_user_dn(self.testuser3)
|
||||
self.testuser4_dn = self.get_user_dn(self.testuser4)
|
||||
self.testuser5_dn = self.get_user_dn(self.testuser5)
|
||||
self.deleted_dn1 = self.create_delete_user(self.testuser1)
|
||||
self.deleted_dn2 = self.create_delete_user(self.testuser2)
|
||||
self.deleted_dn3 = self.create_delete_user(self.testuser3)
|
||||
self.deleted_dn4 = self.create_delete_user(self.testuser4)
|
||||
self.deleted_dn5 = self.create_delete_user(self.testuser5)
|
||||
|
||||
self.ldb_admin.create_ou(self.ou1 + self.base_dn)
|
||||
|
||||
self.ldb_admin.newuser(self.regular_user, self.user_pass)
|
||||
self.ldb_admin.add_remove_group_members("Domain Admins", [self.regular_user],
|
||||
add_members_operation=True)
|
||||
self.ldb_user = self.get_ldb_connection(self.regular_user, self.user_pass)
|
||||
self.sid = self.sd_utils.get_object_sid(self.get_user_dn(self.regular_user))
|
||||
|
||||
def tearDown(self):
|
||||
super(AclUndeleteTests, self).tearDown()
|
||||
delete_force(self.ldb_admin, self.get_user_dn(self.regular_user))
|
||||
delete_force(self.ldb_admin, self.get_user_dn(self.testuser1))
|
||||
delete_force(self.ldb_admin, self.get_user_dn(self.testuser2))
|
||||
delete_force(self.ldb_admin, self.get_user_dn(self.testuser3))
|
||||
delete_force(self.ldb_admin, self.get_user_dn(self.testuser4))
|
||||
delete_force(self.ldb_admin, self.get_user_dn(self.testuser5))
|
||||
delete_force(self.ldb_admin, self.new_dn_ou)
|
||||
delete_force(self.ldb_admin, self.ou1 + self.base_dn)
|
||||
|
||||
def GUID_string(self, guid):
|
||||
return ldb.schema_format_value("objectGUID", guid)
|
||||
|
||||
def create_delete_user(self, new_user):
|
||||
self.ldb_admin.newuser(new_user, self.user_pass)
|
||||
|
||||
res = self.ldb_admin.search(expression="(objectClass=*)",
|
||||
base=self.get_user_dn(new_user),
|
||||
scope=SCOPE_BASE,
|
||||
controls=["show_deleted:1"])
|
||||
guid = res[0]["objectGUID"][0]
|
||||
self.ldb_admin.delete(self.get_user_dn(new_user))
|
||||
res = self.ldb_admin.search(base="<GUID=%s>" % self.GUID_string(guid),
|
||||
scope=SCOPE_BASE, controls=["show_deleted:1"])
|
||||
self.assertEquals(len(res), 1)
|
||||
return str(res[0].dn)
|
||||
|
||||
def undelete_deleted(self, olddn, newdn):
|
||||
msg = Message()
|
||||
msg.dn = Dn(self.ldb_user, olddn)
|
||||
msg["isDeleted"] = MessageElement([], FLAG_MOD_DELETE, "isDeleted")
|
||||
msg["distinguishedName"] = MessageElement([newdn], FLAG_MOD_REPLACE, "distinguishedName")
|
||||
res = self.ldb_user.modify(msg, ["show_recycled:1"])
|
||||
|
||||
def undelete_deleted_with_mod(self, olddn, newdn):
|
||||
msg = Message()
|
||||
msg.dn = Dn(ldb, olddn)
|
||||
msg["isDeleted"] = MessageElement([], FLAG_MOD_DELETE, "isDeleted")
|
||||
msg["distinguishedName"] = MessageElement([newdn], FLAG_MOD_REPLACE, "distinguishedName")
|
||||
msg["url"] = MessageElement(["www.samba.org"], FLAG_MOD_REPLACE, "url")
|
||||
res = self.ldb_user.modify(msg, ["show_deleted:1"])
|
||||
|
||||
def test_undelete(self):
|
||||
# it appears the user has to have LC on the old parent to be able to move the object
|
||||
# otherwise we get no such object. Since only System can modify the SD on deleted object
|
||||
# we cannot grant this permission via LDAP, and this leaves us with "negative" tests at the moment
|
||||
|
||||
# deny write property on rdn, should fail
|
||||
mod = "(OD;;WP;bf967a0e-0de6-11d0-a285-00aa003049e2;;%s)" % str(self.sid)
|
||||
self.sd_utils.dacl_add_ace(self.deleted_dn1, mod)
|
||||
try:
|
||||
self.undelete_deleted(self.deleted_dn1, self.testuser1_dn)
|
||||
self.fail()
|
||||
except LdbError, (num, _):
|
||||
self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
|
||||
|
||||
# seems that permissions on isDeleted and distinguishedName are irrelevant
|
||||
mod = "(OD;;WP;bf96798f-0de6-11d0-a285-00aa003049e2;;%s)" % str(self.sid)
|
||||
self.sd_utils.dacl_add_ace(self.deleted_dn2, mod)
|
||||
mod = "(OD;;WP;bf9679e4-0de6-11d0-a285-00aa003049e2;;%s)" % str(self.sid)
|
||||
self.sd_utils.dacl_add_ace(self.deleted_dn2, mod)
|
||||
self.undelete_deleted(self.deleted_dn2, self.testuser2_dn)
|
||||
|
||||
# attempt undelete with simultanious addition of url, WP to which is denied
|
||||
mod = "(OD;;WP;9a9a0221-4a5b-11d1-a9c3-0000f80367c1;;%s)" % str(self.sid)
|
||||
self.sd_utils.dacl_add_ace(self.deleted_dn3, mod)
|
||||
try:
|
||||
self.undelete_deleted_with_mod(self.deleted_dn3, self.testuser3_dn)
|
||||
self.fail()
|
||||
except LdbError, (num, _):
|
||||
self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
|
||||
|
||||
# undelete in an ou, in which we have no right to create children
|
||||
mod = "(D;;CC;;;%s)" % str(self.sid)
|
||||
self.sd_utils.dacl_add_ace(self.ou1 + self.base_dn, mod)
|
||||
try:
|
||||
self.undelete_deleted(self.deleted_dn4, self.new_dn_ou)
|
||||
self.fail()
|
||||
except LdbError, (num, _):
|
||||
self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
|
||||
|
||||
# delete is not required
|
||||
mod = "(D;;SD;;;%s)" % str(self.sid)
|
||||
self.sd_utils.dacl_add_ace(self.deleted_dn5, mod)
|
||||
self.undelete_deleted(self.deleted_dn5, self.testuser5_dn)
|
||||
|
||||
# deny Reanimate-Tombstone, should fail
|
||||
mod = "(OD;;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;%s)" % str(self.sid)
|
||||
self.sd_utils.dacl_add_ace(self.base_dn, mod)
|
||||
try:
|
||||
self.undelete_deleted(self.deleted_dn4, self.testuser4_dn)
|
||||
self.fail()
|
||||
except LdbError, (num, _):
|
||||
self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
|
||||
|
||||
class AclSPNTests(AclTests):
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user