from samba.netcmd.dns import cmd_dns
from samba import gensec
from samba.kcc import kcc_utils
-from samba.compat import get_string
-from samba.compat import text_type
+from samba.common import get_string
import ldb
import dns.resolver
am_rodc = False
error_count = 0
-parser = optparse.OptionParser("samba_dnsupdate")
+parser = optparse.OptionParser("samba_dnsupdate [options]")
sambaopts = options.SambaOptions(parser)
parser.add_option_group(sambaopts)
parser.add_option_group(options.VersionOptions(parser))
domain = lp.get("realm")
host = lp.get("netbios name")
-if opts.all_interfaces:
- all_interfaces = True
-else:
- all_interfaces = False
+all_interfaces = opts.all_interfaces
-if opts.current_ip:
- IPs = opts.current_ip
-else:
- IPs = samba.interface_ips(lp, all_interfaces)
+IPs = opts.current_ip or samba.interface_ips(lp, bool(all_interfaces)) or []
nsupdate_cmd = lp.get('nsupdate command')
dns_zone_scavenging = lp.get("dns zone scavenging")
if len(IPs) == 0:
- print("No IP interfaces - skipping DNS updates")
+ print("No IP interfaces - skipping DNS updates\n")
+ parser.print_usage()
sys.exit(0)
-if opts.rpc_server_ip:
- rpc_server_ip = opts.rpc_server_ip
-else:
- rpc_server_ip = IPs[0]
+rpc_server_ip = opts.rpc_server_ip or IPs[0]
-IP6s = []
-IP4s = []
-for i in IPs:
- if i.find(':') != -1:
- IP6s.append(i)
- else:
- IP4s.append(i)
+IP6s = [ip for ip in IPs if ':' in ip]
+IP4s = [ip for ip in IPs if ':' not in ip]
smb_conf = sambaopts.get_loadparm_path()
(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('.'))
+ hosts_soa = [str(a.mname).rstrip('.') for a in ans_soa]
# 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('.'))
+ hosts_ns = [str(a.target).rstrip('.') for a in ans_ns]
- return hostnames
+ return hosts_soa + hosts_ns
def get_krb5_rw_dns_server(creds, domain):
"""Get a list of read-write DNS servers that we can obtain a ticket
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])
+ for i, target_hostname in enumerate(rw_dns_servers):
settings = {}
settings["lp_ctx"] = lp
settings["target_hostname"] = target_hostname
return target_hostname
except RuntimeError:
# Only raise an exception if they all failed
- if i != len(rw_dns_servers) - 1:
- pass
- raise
+ if i == len(rw_dns_servers) - 1:
+ raise
def get_credentials(lp):
"""# get credentials if we haven't got them already."""
return h1.lower().rstrip('.') == h2.lower().rstrip('.')
def get_resolver(d=None):
- resolv_conf = os.getenv('RESOLV_CONF')
- if not resolv_conf:
- resolv_conf = '/etc/resolv.conf'
+ resolv_conf = os.getenv('RESOLV_CONF', default='/etc/resolv.conf')
resolver = dns.resolver.Resolver(filename=resolv_conf, configure=True)
if d is not None and d.nameservers != []:
def check_one_dns_name(name, name_type, d=None):
resolver = get_resolver(d)
- if d is not None and len(d.nameservers) == 0:
+ if d and not d.nameservers:
d.nameservers = resolver.nameservers
-
- ans = resolver.query(name, name_type)
- return ans
+ # dns.resolver.Answer
+ return resolver.query(name, name_type)
def check_dns_name(d):
"""check that a DNS entry exists."""
assert(op in ["add", "delete"])
- if opts.verbose:
- print("Calling nsupdate for %s (%s)" % (d, op))
-
if opts.use_file is not None:
+ if opts.verbose:
+ print("Use File instead of nsupdate for %s (%s)" % (d, op))
+
try:
rfile = open(opts.use_file, 'r+')
except IOError:
fcntl.lockf(rfile, fcntl.LOCK_UN)
return
+ if opts.verbose:
+ print("Calling nsupdate for %s (%s)" % (d, op))
+
normalised_name = d.name.rstrip('.') + '.'
(tmp_fd, tmpfile) = tempfile.mkstemp()
f = os.fdopen(tmp_fd, 'w')
- # Getting this line right is really important. When we are under
- # resolv_wrapper, then we want to use RESOLV_CONF and the
- # nameserver therein. The issue is that this parameter forces us
- # to only ever use that server, and not some other server that the
- # NS record may point to, even as we get a ticket to that other
- # server.
- #
- # Therefore we must not set this in production, instead we want
- # to find the name of a SOA for the zone and use that server.
-
- if os.getenv('RESOLV_CONF') and d.nameservers != []:
- f.write('server %s\n' % d.nameservers[0])
- else:
- resolver = get_resolver(d)
+ resolver = get_resolver(d)
- # Local the zone for this name
- zone = dns.resolver.zone_for_name(normalised_name,
- resolver=resolver)
+ # Local the zone for this name
+ zone = dns.resolver.zone_for_name(normalised_name,
+ resolver=resolver)
- # 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 Credentials cache this is not
- # expensive inside the loop
- server = get_krb5_rw_dns_server(creds, zone)
- f.write('server %s\n' % server)
+ # 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 Credentials 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))
args = [rpc_server_ip, zone, short_name, "AAAA", d.ip]
if d.type == "SRV":
if op == "add" and d.existing_port is not None:
- print("Not handling modify of exising SRV %s using samba-tool" % d)
+ print("Not handling modify of existing SRV %s using samba-tool" % d)
return False
- op = "update"
- args = [rpc_server_ip, zone, short_name, "SRV",
- "%s %s %s %s" % (d.existing_weight,
- d.existing_port, "0", "100"),
- "%s %s %s %s" % (d.dest, d.port, "0", "100")]
- else:
- args = [rpc_server_ip, zone, short_name, "SRV", "%s %s %s %s" % (d.dest, d.port, "0", "100")]
+ args = [rpc_server_ip, zone, short_name, "SRV",
+ "%s %s %s %s" % (d.dest, d.port, "0", "100")]
if d.type == "CNAME":
if d.existing_cname_target is None:
args = [rpc_server_ip, zone, short_name, "CNAME", d.dest]
print("Failed 'samba-tool dns' based update: %s : %s" % (str(d), estr))
raise
+irpc_wb = None
+def cached_irpc_wb(lp):
+ global irpc_wb
+ if irpc_wb is not None:
+ return irpc_wb
+ irpc_wb = winbind.winbind("irpc:winbind_server", lp)
+ return irpc_wb
+
def rodc_dns_update(d, t, op):
'''a single DNS update via the RODC netlogon call'''
global sub_vars
netlogon.NlDnsGenericGcAtSite : netlogon.NlDnsDomainNameAlias
}
- w = winbind.winbind("irpc:winbind_server", lp)
+ w = cached_irpc_wb(lp)
dns_names = netlogon.NL_DNS_NAME_INFO_ARRAY()
dns_names.count = 1
name = netlogon.NL_DNS_NAME_INFO()
else:
name.dns_register = False
dns_names.names = [ name ]
- site_name = text_type(sub_vars['SITE'])
+ site_name = sub_vars['SITE']
global error_count
print("Error setting DNS entry of type %u: %s: %s" % (t, d, reason))
error_count = error_count + 1
+ if opts.verbose:
+ print("Called netlogon RODC update for %s" % d)
+
if error_count != 0 and opts.fail_immediately:
sys.exit(1)
# get the list of DNS entries we should have
-if opts.update_list:
- dns_update_list = opts.update_list
-else:
- dns_update_list = lp.private_path('dns_update_list')
+dns_update_list = opts.update_list or lp.private_path('dns_update_list')
-if opts.update_cache:
- dns_update_cache = opts.update_cache
-else:
- dns_update_cache = lp.private_path('dns_update_cache')
+dns_update_cache = opts.update_cache or lp.private_path('dns_update_cache')
krb5conf = None
# only change the krb5.conf if we are not in selftest
krb5conf = lp.private_path('krb5.conf')
os.environ['KRB5_CONFIG'] = krb5conf
-file = open(dns_update_list, "r")
+try:
+ file = open(dns_update_list, "r")
+except OSError as e:
+ if opts.update_cache:
+ print("The specified update list does not exist")
+ else:
+ print("The server update list was not found, "
+ "and --update-list was not provided.")
+ print(e)
+ print()
+ parser.print_usage()
+ sys.exit(1)
if opts.nosubs:
sub_vars = {}
use_samba_tool = opts.use_samba_tool
use_nsupdate = opts.use_nsupdate
# get our krb5 creds
-if len(delete_list) != 0 or len(update_list) != 0 and not opts.nocreds:
+if (delete_list or update_list) and not opts.nocreds:
try:
creds = get_credentials(lp)
except RuntimeError as e:
for d in delete_list:
if d.rpc or (not use_nsupdate and use_samba_tool):
if opts.verbose:
- print("update (samba-tool): %s" % d)
+ print("delete (samba-tool): %s" % d)
call_samba_tool(d, op="delete", zone=d.zone)
elif am_rodc:
if opts.verbose:
print("Adding %s to %s" % (str(d), file_name))
wfile.write(str(d)+"\n")
+ wfile.flush()
os.rename(tmpfile, dns_update_cache)
fcntl.lockf(cfile, fcntl.LOCK_UN)