diff options
Diffstat (limited to 'source4/scripting')
-rwxr-xr-x | source4/scripting/bin/samba_dnsupdate | 87 | ||||
-rwxr-xr-x | source4/scripting/devel/getncchanges | 1 | ||||
-rwxr-xr-x | source4/scripting/devel/ldapcmp | 14 | ||||
-rwxr-xr-x | source4/scripting/devel/rodcdns | 43 | ||||
-rw-r--r-- | source4/scripting/python/samba/join.py | 2 | ||||
-rw-r--r-- | source4/scripting/python/samba/samdb.py | 8 |
6 files changed, 145 insertions, 10 deletions
diff --git a/source4/scripting/bin/samba_dnsupdate b/source4/scripting/bin/samba_dnsupdate index b295224ddc..d3abcb1052 100755 --- a/source4/scripting/bin/samba_dnsupdate +++ b/source4/scripting/bin/samba_dnsupdate @@ -36,17 +36,20 @@ from samba import getopt as options from ldb import SCOPE_BASE from samba.auth import system_session from samba.samdb import SamDB +from samba.dcerpc import netlogon, winbind samba.ensure_external_module("dns", "dnspython") import dns.resolver as resolver default_ttl = 900 +am_rodc = False parser = optparse.OptionParser("samba_dnsupdate") sambaopts = options.SambaOptions(parser) parser.add_option_group(sambaopts) parser.add_option_group(options.VersionOptions(parser)) parser.add_option("--verbose", action="store_true") +parser.add_option("--all-names", action="store_true") parser.add_option("--all-interfaces", action="store_true") parser.add_option("--use-file", type="string", help="Use a file, rather than real DNS calls") @@ -75,7 +78,8 @@ if len(IPs) == 0: print "No IP interfaces - skipping DNS updates" sys.exit(0) - +if opts.verbose: + print "IPs: %s" % IPs ######################################################## # get credentials if we haven't got them already @@ -189,19 +193,22 @@ def check_dns_name(d): ########################################### # get the list of substitution vars def get_subst_vars(): - global lp + global lp, am_rodc vars = {} samdb = SamDB(url=lp.get("sam database"), session_info=system_session(), lp=lp) vars['DNSDOMAIN'] = lp.get('realm').lower() + vars['DNSFOREST'] = lp.get('realm').lower() vars['HOSTNAME'] = lp.get('netbios name').lower() + "." + vars['DNSDOMAIN'] vars['NTDSGUID'] = samdb.get_ntds_GUID() vars['SITE'] = samdb.server_site_name() res = samdb.search(base=None, scope=SCOPE_BASE, attrs=["objectGUID"]) guid = samdb.schema_format_value("objectGUID", res[0]['objectGUID'][0]) vars['DOMAINGUID'] = guid + am_rodc = samdb.am_rodc() + return vars @@ -241,6 +248,75 @@ def call_nsupdate(d): os.unlink(tmpfile) + +def rodc_dns_update(d, t): + '''a single DNS update via the RODC netlogon call''' + global sub_vars + + if opts.verbose: + print "Calling netlogon RODC update for %s" % d + + typemap = { + netlogon.NlDnsLdapAtSite : netlogon.NlDnsInfoTypeNone, + netlogon.NlDnsGcAtSite : netlogon.NlDnsDomainNameAlias, + netlogon.NlDnsDsaCname : netlogon.NlDnsDomainNameAlias, + netlogon.NlDnsKdcAtSite : netlogon.NlDnsInfoTypeNone, + netlogon.NlDnsDcAtSite : netlogon.NlDnsInfoTypeNone, + netlogon.NlDnsRfc1510KdcAtSite : netlogon.NlDnsInfoTypeNone, + netlogon.NlDnsGenericGcAtSite : netlogon.NlDnsDomainNameAlias + } + + w = winbind.winbind("irpc:winbind_server", lp) + dns_names = netlogon.NL_DNS_NAME_INFO_ARRAY() + dns_names.count = 1 + name = netlogon.NL_DNS_NAME_INFO() + name.type = t + name.dns_domain_info_type = typemap[t] + name.priority = 0 + name.weight = 0 + if d.port is not None: + name.port = int(d.port) + name.dns_register = True + dns_names.names = [ name ] + site_name = sub_vars['SITE'].decode('utf-8') + + try: + ret_names = w.DsrUpdateReadOnlyServerDnsRecords(site_name, default_ttl, dns_names) + if ret_names.names[0].status != 0: + print("Failed to set DNS entry: %s (status %u)" % (d, ret_names.names[0].status)) + except RuntimeError, reason: + print("Error setting DNS entry of type %u: %s: %s" % (t, d, reason)) + + +def call_rodc_update(d): + '''RODCs need to use the netlogon API for nsupdate''' + global lp, sub_vars + + # we expect failure for 3268 if we aren't a GC + if d.port is not None and int(d.port) == 3268: + return + + # map the DNS request to a netlogon update type + map = { + netlogon.NlDnsLdapAtSite : '_ldap._tcp.${SITE}._sites.${DNSDOMAIN}', + netlogon.NlDnsGcAtSite : '_ldap._tcp.${SITE}._sites.gc._msdcs.${DNSDOMAIN}', + netlogon.NlDnsDsaCname : '${NTDSGUID}._msdcs.${DNSFOREST}', + netlogon.NlDnsKdcAtSite : '_kerberos._tcp.${SITE}._sites.dc._msdcs.${DNSDOMAIN}', + netlogon.NlDnsDcAtSite : '_ldap._tcp.${SITE}._sites.dc._msdcs.${DNSDOMAIN}', + netlogon.NlDnsRfc1510KdcAtSite : '_kerberos._tcp.${SITE}._sites.${DNSDOMAIN}', + netlogon.NlDnsGenericGcAtSite : '_gc._tcp.${SITE}._sites.${DNSFOREST}' + } + + for t in map: + subname = samba.substitute_var(map[t], sub_vars) + if subname.lower() == d.name.lower(): + # found a match - do the update + rodc_dns_update(d, t) + return + if opts.verbose: + print("Unable to map to netlogon DNS update: %s" % d) + + # get the list of DNS entries we should have dns_update_list = lp.private_path('dns_update_list') @@ -273,7 +349,7 @@ for d in dns_list: # now check if the entries already exist on the DNS server for d in dns_list: - if not check_dns_name(d): + if opts.all_names or not check_dns_name(d): update_list.append(d) if len(update_list) == 0: @@ -286,7 +362,10 @@ get_credentials(lp) # ask nsupdate to add entries as needed for d in update_list: - call_nsupdate(d) + if am_rodc: + call_rodc_update(d) + else: + call_nsupdate(d) # delete the ccache if we created it if ccachename is not None: diff --git a/source4/scripting/devel/getncchanges b/source4/scripting/devel/getncchanges index 7656c22ea4..99f14eafe9 100755 --- a/source4/scripting/devel/getncchanges +++ b/source4/scripting/devel/getncchanges @@ -54,6 +54,7 @@ def do_DsBind(drs): if __name__ == "__main__": parser = OptionParser("getncchanges [options] server") sambaopts = options.SambaOptions(parser) + parser.add_option_group(sambaopts) credopts = options.CredentialsOptionsDouble(parser) parser.add_option_group(credopts) diff --git a/source4/scripting/devel/ldapcmp b/source4/scripting/devel/ldapcmp index 76b4e8eec6..edf37d36d0 100755 --- a/source4/scripting/devel/ldapcmp +++ b/source4/scripting/devel/ldapcmp @@ -518,13 +518,10 @@ class LDAPBundel(object): if __name__ == "__main__": parser = OptionParser("ldapcmp [options] domain|configuration|schema") sambaopts = options.SambaOptions(parser) + parser.add_option_group(sambaopts) credopts = options.CredentialsOptionsDouble(parser) parser.add_option_group(credopts) - lp = sambaopts.get_loadparm() - creds = credopts.get_credentials(lp) - creds2 = credopts.get_credentials2(lp) - parser.add_option("", "--host", dest="host", help="IP of the first LDAP server",) parser.add_option("", "--host2", dest="host2", @@ -537,6 +534,15 @@ if __name__ == "__main__": help="Print all DN pairs that have been compared",) (opts, args) = parser.parse_args() + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp) + creds2 = credopts.get_credentials2(lp) + if creds2.is_anonymous(): + creds2 = creds + + if creds.is_anonymous(): + parser.error("You must supply at least one username/password pair") + if not (len(args) == 1 and args[0].upper() in ["DOMAIN", "CONFIGURATION", "SCHEMA"]): parser.error("Incorrect arguments") diff --git a/source4/scripting/devel/rodcdns b/source4/scripting/devel/rodcdns new file mode 100755 index 0000000000..bd24342ab8 --- /dev/null +++ b/source4/scripting/devel/rodcdns @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# script to call a netlogon RODC DNS update + +import sys +from optparse import OptionParser + +sys.path.insert(0, "bin/python") + +import samba +import samba.getopt as options +from samba.dcerpc import netlogon, winbind + +########### main code ########### +if __name__ == "__main__": + parser = OptionParser("rodcdns [options]") + sambaopts = options.SambaOptions(parser) + + parser.add_option("", "--weight", dest="weight", help="record weight", default=0, type='int') + parser.add_option("", "--priority", dest="priority", help="record priority", default=100, type='int') + parser.add_option("", "--port", dest="port", help="port number", default=389, type='int') + parser.add_option("", "--type", dest="type", help="record type", default=netlogon.NlDnsLdapAtSite, type='int') + parser.add_option("", "--site", dest="site", help="site name", default="Default-First-Site-Name") + + (opts, args) = parser.parse_args() + + lp = sambaopts.get_loadparm() + + w = winbind.winbind("irpc:winbind_server", lp) + + dns_names = netlogon.NL_DNS_NAME_INFO_ARRAY() + dns_names.count = 1 + name = netlogon.NL_DNS_NAME_INFO() + name.type = opts.type + name.priority = opts.priority + name.weight = opts.weight + name.port = opts.port + name.dns_register = True + dns_names.names = [ name ] + site_name = opts.site.decode('utf-8') + + ret_names = w.DsrUpdateReadOnlyServerDnsRecords(site_name, 600, dns_names) + print("Status: %u" % ret_names.names[0].status) diff --git a/source4/scripting/python/samba/join.py b/source4/scripting/python/samba/join.py index 2cb1e3da0b..679dc5bf99 100644 --- a/source4/scripting/python/samba/join.py +++ b/source4/scripting/python/samba/join.py @@ -69,6 +69,8 @@ def join_rodc(server=None, creds=None, lp=None, site=None, netbios_name=None, def find_dc(ctx, domain): '''find a writeable DC for the given domain''' ctx.cldap_ret = ctx.net.finddc(domain, nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS | nbt.NBT_SERVER_WRITABLE) + if ctx.cldap_ret.client_site is not None and ctx.cldap_ret.client_site != "": + ctx.site = ctx.cldap_ret.client_site return ctx.cldap_ret.pdc_dns_name; diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index e2ac37a240..bbc52a9ebd 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -40,7 +40,7 @@ class SamDB(samba.Ldb): def __init__(self, url=None, lp=None, modules_dir=None, session_info=None, credentials=None, flags=0, options=None, global_schema=True, - auto_connect=True, am_rodc=False): + auto_connect=True, am_rodc=None): self.lp = lp if not auto_connect: url = None @@ -54,7 +54,8 @@ class SamDB(samba.Ldb): if global_schema: dsdb._dsdb_set_global_schema(self) - dsdb._dsdb_set_am_rodc(self, am_rodc) + if am_rodc is not None: + dsdb._dsdb_set_am_rodc(self, am_rodc) def connect(self, url=None, flags=0, options=None): if self.lp is not None: @@ -63,6 +64,9 @@ class SamDB(samba.Ldb): super(SamDB, self).connect(url=url, flags=flags, options=options) + def am_rodc(self): + return dsdb._am_rodc(self) + def domain_dn(self): # find the DNs for the domain res = self.search(base="", |