1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-24 21:34:56 +03:00

samba-tool domain join: Refuse to re-join a DC with a still-valid password

While the DC will eventually get back to the same state, it can take a
while, so try harder not to overwrite our already-working account

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
This commit is contained in:
Andrew Bartlett 2016-05-31 14:54:45 +12:00 committed by Garming Sam
parent 2d79b61731
commit 215c20b94b
3 changed files with 111 additions and 54 deletions

View File

@ -170,6 +170,7 @@ class dc_join(object):
ctx.managedby = None
ctx.subdomain = False
ctx.adminpass = None
ctx.partition_dn = None
def del_noerror(ctx, dn, recursive=False):
if recursive:
@ -185,71 +186,97 @@ class dc_join(object):
except Exception:
pass
def cleanup_old_accounts(ctx):
res = ctx.samdb.search(base=ctx.samdb.get_default_basedn(),
expression='sAMAccountName=%s' % ldb.binary_encode(ctx.samname),
attrs=["msDS-krbTgtLink", "objectSID"])
if len(res) == 0:
return
creds = Credentials()
creds.guess(ctx.lp)
try:
creds.set_machine_account(ctx.lp)
machine_samdb = SamDB(url="ldap://%s" % ctx.server,
session_info=system_session(),
credentials=creds, lp=ctx.lp)
except:
pass
else:
token_res = machine_samdb.search(scope=ldb.SCOPE_BASE, base="", attrs=["tokenGroups"])
if token_res[0]["tokenGroups"][0] \
== res[0]["objectSID"][0]:
raise DCJoinException("Not removing account %s which "
"looks like a Samba DC account "
"maching the password we already have. "
"To override, remove secrets.ldb and secrets.tdb"
% ctx.samname)
ctx.del_noerror(res[0].dn, recursive=True)
if "msDS-Krbtgtlink" in res[0]:
new_krbtgt_dn = res[0]["msDS-Krbtgtlink"][0]
del_noerror(ctx.new_krbtgt_dn)
res = ctx.samdb.search(base=ctx.samdb.get_default_basedn(),
expression='(&(sAMAccountName=%s)(servicePrincipalName=%s))' %
(ldb.binary_encode("dns-%s" % ctx.myname),
ldb.binary_encode("dns/%s" % ctx.dnshostname)),
attrs=[])
if res:
ctx.del_noerror(res[0].dn, recursive=True)
res = ctx.samdb.search(base=ctx.samdb.get_default_basedn(),
expression='(sAMAccountName=%s)' % ldb.binary_encode("dns-%s" % ctx.myname),
attrs=[])
if res:
raise DCJoinException("Not removing account %s which looks like "
"a Samba DNS service account but does not "
"have servicePrincipalName=%s" %
(ldb.binary_encode("dns-%s" % ctx.myname),
ldb.binary_encode("dns/%s" % ctx.dnshostname)))
def cleanup_old_join(ctx):
"""Remove any DNs from a previous join."""
try:
# find the krbtgt link
print("checking sAMAccountName")
if ctx.subdomain:
res = None
else:
res = ctx.samdb.search(base=ctx.samdb.get_default_basedn(),
expression='sAMAccountName=%s' % ldb.binary_encode(ctx.samname),
attrs=["msDS-krbTgtLink"])
if res:
ctx.del_noerror(res[0].dn, recursive=True)
# find the krbtgt link
if not ctx.subdomain:
ctx.cleanup_old_accounts()
res = ctx.samdb.search(base=ctx.samdb.get_default_basedn(),
expression='(&(sAMAccountName=%s)(servicePrincipalName=%s))' % (ldb.binary_encode("dns-%s" % ctx.myname), ldb.binary_encode("dns/%s" % ctx.dnshostname)),
attrs=[])
if res:
ctx.del_noerror(res[0].dn, recursive=True)
if ctx.connection_dn is not None:
ctx.del_noerror(ctx.connection_dn)
if ctx.krbtgt_dn is not None:
ctx.del_noerror(ctx.krbtgt_dn)
ctx.del_noerror(ctx.ntds_dn)
ctx.del_noerror(ctx.server_dn, recursive=True)
if ctx.topology_dn:
ctx.del_noerror(ctx.topology_dn)
if ctx.partition_dn:
ctx.del_noerror(ctx.partition_dn)
res = ctx.samdb.search(base=ctx.samdb.get_default_basedn(),
expression='(sAMAccountName=%s)' % ldb.binary_encode("dns-%s" % ctx.myname),
attrs=[])
if res:
raise RuntimeError("Not removing account %s which looks like a Samba DNS service account but does not have servicePrincipalName=%s" % (ldb.binary_encode("dns-%s" % ctx.myname), ldb.binary_encode("dns/%s" % ctx.dnshostname)))
if ctx.subdomain:
binding_options = "sign"
lsaconn = lsa.lsarpc("ncacn_ip_tcp:%s[%s]" % (ctx.server, binding_options),
ctx.lp, ctx.creds)
if ctx.connection_dn is not None:
ctx.del_noerror(ctx.connection_dn)
if ctx.krbtgt_dn is not None:
ctx.del_noerror(ctx.krbtgt_dn)
ctx.del_noerror(ctx.ntds_dn)
ctx.del_noerror(ctx.server_dn, recursive=True)
if ctx.topology_dn:
ctx.del_noerror(ctx.topology_dn)
if ctx.partition_dn:
ctx.del_noerror(ctx.partition_dn)
if res:
ctx.new_krbtgt_dn = res[0]["msDS-Krbtgtlink"][0]
ctx.del_noerror(ctx.new_krbtgt_dn)
objectAttr = lsa.ObjectAttribute()
objectAttr.sec_qos = lsa.QosInfo()
if ctx.subdomain:
binding_options = "sign"
lsaconn = lsa.lsarpc("ncacn_ip_tcp:%s[%s]" % (ctx.server, binding_options),
ctx.lp, ctx.creds)
pol_handle = lsaconn.OpenPolicy2(''.decode('utf-8'),
objectAttr, security.SEC_FLAG_MAXIMUM_ALLOWED)
objectAttr = lsa.ObjectAttribute()
objectAttr.sec_qos = lsa.QosInfo()
name = lsa.String()
name.string = ctx.realm
info = lsaconn.QueryTrustedDomainInfoByName(pol_handle, name, lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
pol_handle = lsaconn.OpenPolicy2(''.decode('utf-8'),
objectAttr, security.SEC_FLAG_MAXIMUM_ALLOWED)
lsaconn.DeleteTrustedDomain(pol_handle, info.info_ex.sid)
name = lsa.String()
name.string = ctx.realm
info = lsaconn.QueryTrustedDomainInfoByName(pol_handle, name, lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
name = lsa.String()
name.string = ctx.forest_domain_name
info = lsaconn.QueryTrustedDomainInfoByName(pol_handle, name, lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
lsaconn.DeleteTrustedDomain(pol_handle, info.info_ex.sid)
lsaconn.DeleteTrustedDomain(pol_handle, info.info_ex.sid)
name = lsa.String()
name.string = ctx.forest_domain_name
info = lsaconn.QueryTrustedDomainInfoByName(pol_handle, name, lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
lsaconn.DeleteTrustedDomain(pol_handle, info.info_ex.sid)
except Exception:
pass
def promote_possible(ctx):
"""confirm that the account is just a bare NT4 BDC or a member server, so can be safely promoted"""

View File

@ -0,0 +1,29 @@
# Unix SMB/CIFS implementation.
# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2016
#
# 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/>.
#
import os, ldb
from samba.tests.samba_tool.base import SambaToolCmdTest
class JoinCmdTestCase(SambaToolCmdTest):
"""Test for samba-tool fsmo show subcommand"""
def test_rejoin(self):
"""Run domain join to confirm it errors because we are already joined"""
(result, out, err) = self.runsubcmd("domain", "join", os.environ["REALM"], "dc", "-U%s%%%s" % (os.environ["USERNAME"], os.environ["PASSWORD"]))
self.assertCmdFail(result)
self.assertTrue("Not removing account" in err,"Should fail with exception")

View File

@ -540,6 +540,7 @@ planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.dcerpc.bare")
planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.dcerpc.unix")
planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.dcerpc.srvsvc")
planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.samba_tool.timecmd")
planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.samba_tool.join")
# test fsmo show
for env in ["ad_dc_ntvfs", "fl2000dc", "fl2003dc", "fl2008r2dc"]: