1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-03 12:58:35 +03:00

samba_dnsupdate: Extend possible server list to all NS servers for the zone

This should eventually be removed, but for now this unblocks samba_dnsupdate operation
in existing domains that have lost the original Samba DC

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
This commit is contained in:
Andrew Bartlett 2017-04-11 14:14:15 +12:00
parent c1bf6d2493
commit 2f42f55ad4

View File

@ -121,6 +121,64 @@ for i in IPs:
if opts.verbose:
print "IPs: %s" % IPs
def get_possible_rw_dns_server(creds, domain):
"""Get a list of possible read-write DNS servers, starting with
the SOA. The SOA is the correct answer, but old Samba domains
(4.6 and prior) do not maintain this value, so add NS servers
as well"""
hostnames = []
ans_soa = check_one_dns_name(domain, 'SOA')
# Actually there is only one
for i in range(len(ans_soa)):
hostnames.append(str(ans_soa[i].mname).rstrip('.'))
# This is not strictly legit, but old Samba domains may have an
# unmaintained SOA record, so go for any NS that we can get a
# ticket to.
ans_ns = check_one_dns_name(domain, 'NS')
# Actually there is only one
for i in range(len(ans_ns)):
hostnames.append(str(ans_ns[i].target).rstrip('.'))
return hostnames
def get_krb5_rw_dns_server(creds, domain):
"""Get a list of read-write DNS servers that we can obtain a ticket
for, starting with the SOA. The SOA is the correct answer, but
old Samba domains (4.6 and prior) do not maintain this value,
so continue with the NS servers as well until we get one that
the KDC will issue a ticket to.
"""
rw_dns_servers = get_possible_rw_dns_server(creds, domain)
# Actually there is only one
for i in range(len(rw_dns_servers)):
target_hostname = str(rw_dns_servers[i])
settings = {}
settings["lp_ctx"] = lp
settings["target_hostname"] = target_hostname
gensec_client = gensec.Security.start_client(settings)
gensec_client.set_credentials(creds)
gensec_client.set_target_service("DNS")
gensec_client.set_target_hostname(target_hostname)
gensec_client.want_feature(gensec.FEATURE_SEAL)
gensec_client.start_mech_by_sasl_name("GSSAPI")
server_to_client = ""
try:
(client_finished, client_to_server) = gensec_client.update(server_to_client)
if opts.verbose:
print "Successfully obtained Kerberos ticket to DNS/%s as %s" \
% (target_hostname, creds.get_username())
return target_hostname
except RuntimeError:
# Only raise an exception if they all failed
if i != len(rw_dns_servers) - 1:
pass
raise
def get_credentials(lp):
"""# get credentials if we haven't got them already."""
@ -138,33 +196,8 @@ def get_credentials(lp):
return
# Now confirm we can get a ticket to the DNS server
ans = check_one_dns_name(sub_vars['DNSDOMAIN'] + '.', 'SOA')
# Actually there is only one
for i in range(len(ans)):
target_hostname = str(ans[i].mname).rstrip('.')
settings = {}
settings["lp_ctx"] = lp
settings["target_hostname"] = target_hostname
gensec_client = gensec.Security.start_client(settings)
gensec_client.set_credentials(creds)
gensec_client.set_target_service("DNS")
gensec_client.set_target_hostname(target_hostname)
gensec_client.want_feature(gensec.FEATURE_SEAL)
gensec_client.start_mech_by_sasl_name("GSSAPI")
server_to_client = ""
try:
(client_finished, client_to_server) = gensec_client.update(server_to_client)
if opts.verbose:
print "Successfully obtained Kerberos ticket to DNS/%s as %s" \
% (target_hostname, creds.get_username())
return
except RuntimeError:
# Only raise an exception if they all failed
if i != len(ans) - 1:
pass
raise
get_krb5_rw_dns_server(creds, sub_vars['DNSDOMAIN'] + '.')
return creds
except RuntimeError as e:
os.unlink(ccachename)
@ -452,11 +485,18 @@ def call_nsupdate(d, op="add"):
f.write('server %s\n' % d.nameservers[0])
else:
resolver = get_resolver(d)
# Local the zone for this name
zone = dns.resolver.zone_for_name(normalised_name,
resolver=resolver)
soa = resolver.query(zone, "SOA")
f.write('server %s\n' % soa[0].mname)
# Now find the SOA, or if we can't get a ticket to the SOA,
# any server with an NS record we can get a ticket for.
#
# Thanks to the Kerberos Crednetials cache this is not
# expensive inside the loop
server = get_krb5_rw_dns_server(creds, zone)
f.write('server %s\n' % server)
if d.type == "A":
f.write("update %s %s %u A %s\n" % (op, normalised_name, default_ttl, d.ip))