summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2015-10-20 13:48:07 +1300
committerAndrew Bartlett <abartlet@samba.org>2015-10-26 05:11:22 +0100
commit55a13e17b36adc69eb4ec7d706cb9a55906f8275 (patch)
tree50bf146ba9a33c4a6c7fd6a85209123af5bb4c33 /python
parente57dcddfe8ca4c2b5591cf3e1687d1ef89112c1a (diff)
downloadsamba-55a13e17b36adc69eb4ec7d706cb9a55906f8275.tar.gz
samba-tool domain demote: Add support for removing by NTDS GUID
This would help remove a DC that is a conflict record, for example Signed-off-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Garming Sam <garming@catalyst.net.nz>
Diffstat (limited to 'python')
-rw-r--r--python/samba/netcmd/domain.py3
-rw-r--r--python/samba/remove_dc.py90
-rw-r--r--python/samba/tests/blackbox/samba_tool_drs.py37
3 files changed, 96 insertions, 34 deletions
diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py
index 689371aaafa..6726538fc1b 100644
--- a/python/samba/netcmd/domain.py
+++ b/python/samba/netcmd/domain.py
@@ -671,7 +671,8 @@ class cmd_domain_demote(Command):
Option("--server", help="writable DC to write demotion changes on", type=str),
Option("-H", "--URL", help="LDB URL for database or target server", type=str,
metavar="URL", dest="H"),
- Option("--remove-other-dead-server", help="Dead DC to remove ALL references to (rather than this DC)", type=str),
+ Option("--remove-other-dead-server", help="Dead DC (name or NTDS GUID) "
+ "to remove ALL references to (rather than this DC)", type=str),
Option("--quiet", help="Be quiet", action="store_true"),
Option("--verbose", help="Be verbose", action="store_true"),
]
diff --git a/python/samba/remove_dc.py b/python/samba/remove_dc.py
index 90ad7c6eafc..055a5166e58 100644
--- a/python/samba/remove_dc.py
+++ b/python/samba/remove_dc.py
@@ -16,6 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+import uuid
import ldb
from ldb import LdbError
from samba.ndr import ndr_unpack
@@ -357,46 +358,69 @@ def remove_dc(samdb, logger, dc_name):
samdb.transaction_start()
- msgs = samdb.search(base=samdb.get_config_basedn(),
- attrs=["serverReference"],
- expression="(&(objectClass=server)(cn=%s))"
- % ldb.binary_encode(dc_name))
- if (len(msgs) == 0):
- raise DemoteException("%s is not an AD DC in %s"
- % (dc_name, samdb.domain_dns_name()))
- server_dn = msgs[0].dn
+ server_dn = None
- ntds_dn = ldb.Dn(samdb, "CN=NTDS Settings")
- ntds_dn.add_base(msgs[0].dn)
+ # Allow the name to be a the nTDS-DSA GUID
+ try:
+ ntds_guid = uuid.UUID(hex=dc_name)
+ ntds_dn = "<GUID=%s>" % ntds_guid
+ except ValueError:
+ try:
+ server_msgs = samdb.search(base=samdb.get_config_basedn(),
+ attrs=[],
+ expression="(&(objectClass=server)"
+ "(cn=%s))"
+ % ldb.binary_encode(dc_name))
+ except LdbError as (enum, estr):
+ raise DemoteException("Failure checking if %s is an server "
+ "object in %s: "
+ % (dc_name, samdb.domain_dns_name()), estr)
+
+ if (len(server_msgs) == 0):
+ raise DemoteException("%s is not an AD DC in %s"
+ % (dc_name, samdb.domain_dns_name()))
+ server_dn = server_msgs[0].dn
+
+ ntds_dn = ldb.Dn(samdb, "CN=NTDS Settings")
+ ntds_dn.add_base(server_dn)
+ pass
# Confirm this is really an ntdsDSA object
try:
- msgs = samdb.search(base=ntds_dn, attrs=[], scope=ldb.SCOPE_BASE,
- expression="(objectClass=ntdsdsa)")
+ ntds_msgs = samdb.search(base=ntds_dn, attrs=[], scope=ldb.SCOPE_BASE,
+ expression="(objectClass=ntdsdsa)")
except LdbError as (enum, estr):
if enum == ldb.ERR_NO_SUCH_OBJECT:
- offline_remove_server(samdb, logger,
- msgs[0].dn,
- remove_computer_obj=True,
- remove_server_obj=True,
- remove_sysvol_obj=True,
- remove_dns_names=True,
- remove_dns_account=True)
-
- samdb.transaction_commit()
- return
- else:
+ ntds_msgs = []
pass
-
- offline_remove_ntds_dc(samdb, logger,
- msgs[0].dn,
- remove_computer_obj=True,
- remove_server_obj=True,
- remove_connection_obj=True,
- seize_stale_fsmo=True,
- remove_sysvol_obj=True,
- remove_dns_names=True,
- remove_dns_account=True)
+ else:
+ raise DemoteException("Failure checking if %s is an NTDS DSA in %s: "
+ % (ntds_dn, samdb.domain_dns_name()), estr)
+
+ # If the NTDS Settings child DN wasn't found or wasnt an ntdsDSA
+ # object, just remove the server object located above
+ if (len(ntds_msgs) == 0):
+ if server_dn is None:
+ raise DemoteException("%s is not an AD DC in %s"
+ % (dc_name, samdb.domain_dns_name()))
+
+ offline_remove_server(samdb, logger,
+ server_dn,
+ remove_computer_obj=True,
+ remove_server_obj=True,
+ remove_sysvol_obj=True,
+ remove_dns_names=True,
+ remove_dns_account=True)
+ else:
+ offline_remove_ntds_dc(samdb, logger,
+ ntds_msgs[0].dn,
+ remove_computer_obj=True,
+ remove_server_obj=True,
+ remove_connection_obj=True,
+ seize_stale_fsmo=True,
+ remove_sysvol_obj=True,
+ remove_dns_names=True,
+ remove_dns_account=True)
samdb.transaction_commit()
diff --git a/python/samba/tests/blackbox/samba_tool_drs.py b/python/samba/tests/blackbox/samba_tool_drs.py
index 7ca7c33ede1..6056645e267 100644
--- a/python/samba/tests/blackbox/samba_tool_drs.py
+++ b/python/samba/tests/blackbox/samba_tool_drs.py
@@ -130,6 +130,43 @@ class SambaToolDrsTests(samba.tests.BlackboxTestCase):
def get_krbtgt_pw():
krbtgt_pw = samdb.searchone("unicodePwd", "cn=krbtgt,CN=users,%s" % nc_name)
self.assertRaises(KeyError, get_krbtgt_pw)
+
+ server_dn = samdb.searchone("serverReferenceBL", "cn=%s,ou=domain controllers,%s" % (self.dc2, server_nc_name))
+ ntds_guid = samdb.searchone("objectGUID", "cn=ntds settings,%s" % server_dn)
+
+ res = samdb.search(base=str(server_nc_name),
+ expression="(&(objectclass=user)(cn=dns-%s))" % (self.dc2),
+ attrs=[], scope=ldb.SCOPE_SUBTREE)
+ if len(res) == 1:
+ dns_obj = res[0]
+ else:
+ dns_obj = None
+
+ # While we have this cloned, try demoting the other server on the clone, by GUID
+ out = self.check_output("samba-tool domain demote --remove-other-dead-server=%s -H %s/private/sam.ldb"
+ % (ntds_guid,
+ self.tempdir))
+
+ # Check some of the objects that should have been removed
+ def check_machine_obj():
+ samdb.searchone("CN", "cn=%s,ou=domain controllers,%s" % (self.dc2, server_nc_name))
+ self.assertRaises(ldb.LdbError, check_machine_obj)
+
+ def check_server_obj():
+ samdb.searchone("CN", server_dn)
+ self.assertRaises(ldb.LdbError, check_server_obj)
+
+ def check_ntds_guid():
+ samdb.searchone("CN", "<GUID=%s>" % ntds_guid)
+ self.assertRaises(ldb.LdbError, check_ntds_guid)
+
+ if dns_obj is not None:
+ # Check some of the objects that should have been removed
+ def check_dns_account_obj():
+ samdb.search(base=dns_obj.dn, scope=ldb.SCOPE_BASE,
+ attrs=[])
+ self.assertRaises(ldb.LdbError, check_dns_account_obj)
+
shutil.rmtree(os.path.join(self.tempdir, "private"))
shutil.rmtree(os.path.join(self.tempdir, "etc"))
shutil.rmtree(os.path.join(self.tempdir, "msg.lock"))