1
0
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:
Andrew Bartlett 2012-12-24 08:56:50 +11:00 committed by Stefan Metzmacher
parent bdab6f9431
commit b106d9090e
4 changed files with 88 additions and 9 deletions

View File

@ -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."""

View File

@ -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)

View File

@ -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)

View File

@ -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}