mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
scripting/join.py: Handle creating the dns-NAME account during a DC join
This will ensure that the DLZ plugin works out of the box when joining a second Samba DC to the domain. Andrew Bartlett Reviewed-by: Stefan Metzmacher <metze@samba.org> Signed-off-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
parent
bdab6f9431
commit
b106d9090e
@ -26,9 +26,12 @@ from samba.ndr import ndr_pack
|
|||||||
from samba.dcerpc import security, drsuapi, misc, nbt, lsa, drsblobs
|
from samba.dcerpc import security, drsuapi, misc, nbt, lsa, drsblobs
|
||||||
from samba.credentials import Credentials, DONT_USE_KERBEROS
|
from samba.credentials import Credentials, DONT_USE_KERBEROS
|
||||||
from samba.provision import secretsdb_self_join, provision, provision_fill, FILL_DRS, FILL_SUBDOMAIN
|
from samba.provision import secretsdb_self_join, provision, provision_fill, FILL_DRS, FILL_SUBDOMAIN
|
||||||
|
from samba.provision.common import setup_path
|
||||||
from samba.schema import Schema
|
from samba.schema import Schema
|
||||||
from samba.net import Net
|
from samba.net import Net
|
||||||
from samba.provision.sambadns import setup_bind9_dns
|
from samba.provision.sambadns import setup_bind9_dns
|
||||||
|
from samba import read_and_sub_file
|
||||||
|
from base64 import b64encode
|
||||||
import logging
|
import logging
|
||||||
import talloc
|
import talloc
|
||||||
import random
|
import random
|
||||||
@ -179,6 +182,19 @@ class dc_join(object):
|
|||||||
attrs=["msDS-krbTgtLink"])
|
attrs=["msDS-krbTgtLink"])
|
||||||
if res:
|
if res:
|
||||||
ctx.del_noerror(res[0].dn, recursive=True)
|
ctx.del_noerror(res[0].dn, recursive=True)
|
||||||
|
|
||||||
|
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 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.connection_dn is not None:
|
if ctx.connection_dn is not None:
|
||||||
ctx.del_noerror(ctx.connection_dn)
|
ctx.del_noerror(ctx.connection_dn)
|
||||||
if ctx.krbtgt_dn is not None:
|
if ctx.krbtgt_dn is not None:
|
||||||
@ -579,6 +595,56 @@ class dc_join(object):
|
|||||||
"userAccountControl")
|
"userAccountControl")
|
||||||
ctx.samdb.modify(m)
|
ctx.samdb.modify(m)
|
||||||
|
|
||||||
|
if ctx.dns_backend.startswith("BIND9_"):
|
||||||
|
ctx.dnspass = samba.generate_random_password(128, 255)
|
||||||
|
|
||||||
|
recs = ctx.samdb.parse_ldif(read_and_sub_file(setup_path("provision_dns_add_samba.ldif"),
|
||||||
|
{"DNSDOMAIN": ctx.dnsdomain,
|
||||||
|
"DOMAINDN": ctx.base_dn,
|
||||||
|
"HOSTNAME" : ctx.myname,
|
||||||
|
"DNSPASS_B64": b64encode(ctx.dnspass),
|
||||||
|
"DNSNAME" : ctx.dnshostname}))
|
||||||
|
for changetype, msg in recs:
|
||||||
|
assert changetype == ldb.CHANGETYPE_NONE
|
||||||
|
print "Adding DNS account %s with dns/ SPN" % msg["dn"]
|
||||||
|
|
||||||
|
# Remove dns password (we will set it as a modify, as we can't do clearTextPassword over LDAP)
|
||||||
|
del msg["clearTextPassword"]
|
||||||
|
# Remove isCriticalSystemObject for similar reasons, it cannot be set over LDAP
|
||||||
|
del msg["isCriticalSystemObject"]
|
||||||
|
try:
|
||||||
|
ctx.samdb.add(msg)
|
||||||
|
dns_acct_dn = msg["dn"]
|
||||||
|
except ldb.LdbError, (num, _):
|
||||||
|
if num != ldb.ERR_ENTRY_ALREADY_EXISTS:
|
||||||
|
raise
|
||||||
|
|
||||||
|
# The account password set operation should normally be done over
|
||||||
|
# LDAP. Windows 2000 DCs however allow this only with SSL
|
||||||
|
# connections which are hard to set up and otherwise refuse with
|
||||||
|
# ERR_UNWILLING_TO_PERFORM. In this case we fall back to libnet
|
||||||
|
# over SAMR.
|
||||||
|
print "Setting account password for %s" % ctx.samname
|
||||||
|
try:
|
||||||
|
ctx.samdb.setpassword("(&(objectClass=user)(samAccountName=dns-%s))"
|
||||||
|
% ldb.binary_encode(ctx.myname),
|
||||||
|
ctx.dnspass,
|
||||||
|
force_change_at_next_login=False,
|
||||||
|
username=ctx.samname)
|
||||||
|
except ldb.LdbError, (num, _):
|
||||||
|
if num != ldb.ERR_UNWILLING_TO_PERFORM:
|
||||||
|
pass
|
||||||
|
ctx.net.set_password(account_name="dns-" % ctx.myname,
|
||||||
|
domain_name=ctx.domain_name,
|
||||||
|
newpassword=ctx.dnspass)
|
||||||
|
|
||||||
|
res = ctx.samdb.search(base=dns_acct_dn, scope=ldb.SCOPE_BASE,
|
||||||
|
attrs=["msDS-KeyVersionNumber"])
|
||||||
|
if "msDS-KeyVersionNumber" in res[0]:
|
||||||
|
ctx.dns_key_version_number = int(res[0]["msDS-KeyVersionNumber"][0])
|
||||||
|
else:
|
||||||
|
ctx.dns_key_version_number = None
|
||||||
|
|
||||||
def join_add_objects2(ctx):
|
def join_add_objects2(ctx):
|
||||||
"""add the various objects needed for the join, for subdomains post replication"""
|
"""add the various objects needed for the join, for subdomains post replication"""
|
||||||
|
|
||||||
@ -861,13 +927,12 @@ class dc_join(object):
|
|||||||
key_version_number=ctx.key_version_number)
|
key_version_number=ctx.key_version_number)
|
||||||
|
|
||||||
if ctx.dns_backend.startswith("BIND9_"):
|
if ctx.dns_backend.startswith("BIND9_"):
|
||||||
dnspass = samba.generate_random_password(128, 255)
|
|
||||||
|
|
||||||
setup_bind9_dns(ctx.local_samdb, secrets_ldb, security.dom_sid(ctx.domsid),
|
setup_bind9_dns(ctx.local_samdb, secrets_ldb, security.dom_sid(ctx.domsid),
|
||||||
ctx.names, ctx.paths, ctx.lp, logger,
|
ctx.names, ctx.paths, ctx.lp, logger,
|
||||||
dns_backend=ctx.dns_backend,
|
dns_backend=ctx.dns_backend,
|
||||||
dnspass=dnspass, os_level=ctx.behavior_version,
|
dnspass=ctx.dnspass, os_level=ctx.behavior_version,
|
||||||
targetdir=ctx.targetdir)
|
targetdir=ctx.targetdir,
|
||||||
|
key_version_number=ctx.dns_key_version_number)
|
||||||
|
|
||||||
def join_setup_trusts(ctx):
|
def join_setup_trusts(ctx):
|
||||||
"""provision the local SAM."""
|
"""provision the local SAM."""
|
||||||
|
@ -620,7 +620,7 @@ def add_dc_msdcs_records(samdb, forestdn, prefix, site, dnsforest, hostname,
|
|||||||
|
|
||||||
|
|
||||||
def secretsdb_setup_dns(secretsdb, names, private_dir, realm,
|
def secretsdb_setup_dns(secretsdb, names, private_dir, realm,
|
||||||
dnsdomain, dns_keytab_path, dnspass):
|
dnsdomain, dns_keytab_path, dnspass, key_version_number):
|
||||||
"""Add DNS specific bits to a secrets database.
|
"""Add DNS specific bits to a secrets database.
|
||||||
|
|
||||||
:param secretsdb: Ldb Handle to the secrets database
|
:param secretsdb: Ldb Handle to the secrets database
|
||||||
@ -632,11 +632,15 @@ def secretsdb_setup_dns(secretsdb, names, private_dir, realm,
|
|||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
if key_version_number is None:
|
||||||
|
key_version_number = 1
|
||||||
|
|
||||||
setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), {
|
setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), {
|
||||||
"REALM": realm,
|
"REALM": realm,
|
||||||
"DNSDOMAIN": dnsdomain,
|
"DNSDOMAIN": dnsdomain,
|
||||||
"DNS_KEYTAB": dns_keytab_path,
|
"DNS_KEYTAB": dns_keytab_path,
|
||||||
"DNSPASS_B64": b64encode(dnspass),
|
"DNSPASS_B64": b64encode(dnspass),
|
||||||
|
"KEY_VERSION_NUMBER": str(key_version_number),
|
||||||
"HOSTNAME": names.hostname,
|
"HOSTNAME": names.hostname,
|
||||||
"DNSNAME" : '%s.%s' % (
|
"DNSNAME" : '%s.%s' % (
|
||||||
names.netbiosname.lower(), names.dnsdomain.lower())
|
names.netbiosname.lower(), names.dnsdomain.lower())
|
||||||
@ -1074,7 +1078,7 @@ def setup_ad_dns(samdb, secretsdb, domainsid, names, paths, lp, logger,
|
|||||||
|
|
||||||
def setup_bind9_dns(samdb, secretsdb, domainsid, names, paths, lp, logger,
|
def setup_bind9_dns(samdb, secretsdb, domainsid, names, paths, lp, logger,
|
||||||
dns_backend, os_level, site=None, dnspass=None, hostip=None,
|
dns_backend, os_level, site=None, dnspass=None, hostip=None,
|
||||||
hostip6=None, targetdir=None):
|
hostip6=None, targetdir=None, key_version_number=None):
|
||||||
"""Provision DNS information (assuming BIND9 backend in DC role)
|
"""Provision DNS information (assuming BIND9 backend in DC role)
|
||||||
|
|
||||||
:param samdb: LDB object connected to sam.ldb file
|
:param samdb: LDB object connected to sam.ldb file
|
||||||
@ -1107,7 +1111,8 @@ def setup_bind9_dns(samdb, secretsdb, domainsid, names, paths, lp, logger,
|
|||||||
secretsdb_setup_dns(secretsdb, names,
|
secretsdb_setup_dns(secretsdb, names,
|
||||||
paths.private_dir, realm=names.realm,
|
paths.private_dir, realm=names.realm,
|
||||||
dnsdomain=names.dnsdomain,
|
dnsdomain=names.dnsdomain,
|
||||||
dns_keytab_path=paths.dns_keytab, dnspass=dnspass)
|
dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
|
||||||
|
key_version_number=key_version_number)
|
||||||
|
|
||||||
create_dns_dir(logger, paths)
|
create_dns_dir(logger, paths)
|
||||||
|
|
||||||
|
@ -436,10 +436,19 @@ if __name__ == '__main__':
|
|||||||
"DNSNAME" : dnsname }
|
"DNSNAME" : dnsname }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
res = ldbs.sam.search(base=domaindn, scope=ldb.SCOPE_DEFAULT,
|
||||||
|
expression='(sAMAccountName=dns-%s)' % (hostname),
|
||||||
|
attrs=["msDS-KeyVersionNumber"])
|
||||||
|
if "msDS-KeyVersionNumber" in res[0]:
|
||||||
|
dns_key_version_number = int(res[0]["msDS-KeyVersionNumber"][0])
|
||||||
|
else:
|
||||||
|
dns_key_version_number = None
|
||||||
|
|
||||||
secretsdb_setup_dns(ldbs.secrets, names,
|
secretsdb_setup_dns(ldbs.secrets, names,
|
||||||
paths.private_dir, realm=names.realm,
|
paths.private_dir, realm=names.realm,
|
||||||
dnsdomain=names.dnsdomain,
|
dnsdomain=names.dnsdomain,
|
||||||
dns_keytab_path=paths.dns_keytab, dnspass=dnspass)
|
dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
|
||||||
|
key_version_number=dns_key_version_number)
|
||||||
else:
|
else:
|
||||||
logger.info("dns-%s account already exists" % hostname)
|
logger.info("dns-%s account already exists" % hostname)
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ objectClass: secret
|
|||||||
objectClass: kerberosSecret
|
objectClass: kerberosSecret
|
||||||
realm: ${REALM}
|
realm: ${REALM}
|
||||||
servicePrincipalName: DNS/${DNSNAME}
|
servicePrincipalName: DNS/${DNSNAME}
|
||||||
msDS-KeyVersionNumber: 1
|
msDS-KeyVersionNumber: ${KEY_VERSION_NUMBER}
|
||||||
privateKeytab: ${DNS_KEYTAB}
|
privateKeytab: ${DNS_KEYTAB}
|
||||||
secret:: ${DNSPASS_B64}
|
secret:: ${DNSPASS_B64}
|
||||||
samAccountName: dns-${HOSTNAME}
|
samAccountName: dns-${HOSTNAME}
|
||||||
|
Loading…
Reference in New Issue
Block a user