From f6d77fec542b8fb9762af1318b23e56b75c1d3dd Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 22 Jan 2019 11:59:11 -0800 Subject: [PATCH] DO NOT PUSH !!! python: Wrap all net.finddc() calls so they attempt lookup 3 times before failing. Cope with flakey DNS/CLDAP servers. Signed-off-by: Jeremy Allison --- python/samba/emulate/traffic_packets.py | 10 +++++++-- python/samba/gpclass.py | 11 +++++++--- python/samba/join.py | 27 +++++++++++++++++-------- python/samba/netcmd/common.py | 22 ++++++++++++++------ python/samba/netcmd/domain.py | 8 +++++++- python/samba/netcmd/gpo.py | 16 +++++++++++++-- source4/scripting/bin/samba_spnupdate | 13 +++++++----- 7 files changed, 80 insertions(+), 27 deletions(-) diff --git a/python/samba/emulate/traffic_packets.py b/python/samba/emulate/traffic_packets.py index 518bffac390..dffc152a189 100644 --- a/python/samba/emulate/traffic_packets.py +++ b/python/samba/emulate/traffic_packets.py @@ -131,13 +131,19 @@ def null_packet(packet, conversation, context): return False -def packet_cldap_3(packet, conversation, context): +def packet_cldap_3(packet, conversation, context, retry_attempts=3): # searchRequest net = Net(creds=context.creds, lp=context.lp) - net.finddc(domain=context.lp.get('realm'), + for i in range(retry_attempts): + try: + net.finddc(domain=context.lp.get('realm'), flags=(nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS | nbt.NBT_SERVER_WRITABLE)) + break; + except NTSTATUSError as error: + if i == retry_attempts - 1: + raise return True diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index 0040f235e6e..8bad80e95d7 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -360,11 +360,16 @@ class gp_inf_ext(gp_ext): ''' Fetch the hostname of a writable DC ''' -def get_dc_hostname(creds, lp): +def get_dc_hostname(creds, lp, retry_attempts=3): net = Net(creds=creds, lp=lp) - cldap_ret = net.finddc(domain=lp.get('realm'), flags=(nbt.NBT_SERVER_LDAP | + for i in range(retry_attempts): + try: + cldap_ret = net.finddc(domain=lp.get('realm'), flags=(nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)) - return cldap_ret.pdc_dns_name + return cldap_ret.pdc_dns_name + except NTSTATUSError as error: + if i == retry_attempts - 1: + raise ''' Fetch a list of GUIDs for applicable GPOs ''' diff --git a/python/samba/join.py b/python/samba/join.py index da8dcb050d3..177a6b19bde 100644 --- a/python/samba/join.py +++ b/python/samba/join.py @@ -344,9 +344,14 @@ class DCJoinContext(object): def find_dc(ctx, domain): """find a writeable DC for the given domain""" try: - ctx.cldap_ret = ctx.net.finddc(domain=domain, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS | nbt.NBT_SERVER_WRITABLE) - except NTSTATUSError as error: - raise CommandError("Failed to find a writeable DC for domain '%s': %s" % + """Try the query 3 times before failing""" + for i in range(3): + try: + ctx.cldap_ret = ctx.net.finddc(domain=domain, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS | nbt.NBT_SERVER_WRITABLE) + break + except NTSTATUSError as error: + if i == 2: + raise CommandError("Failed to find a writeable DC for domain '%s': %s" % (domain, error.args[1])) except Exception: raise CommandError("Failed to find a writeable DC for domain '%s'" % domain) @@ -356,11 +361,17 @@ class DCJoinContext(object): def find_dc_site(ctx, server): site = None - cldap_ret = ctx.net.finddc(address=server, - flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS) - if cldap_ret.client_site is not None and cldap_ret.client_site != "": - site = cldap_ret.client_site - return site + """Try the query 3 times before failing""" + for i in range(3): + try: + cldap_ret = ctx.net.finddc(address=server, + flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS) + if cldap_ret.client_site is not None and cldap_ret.client_site != "": + site = cldap_ret.client_site + return site + except NTSTATUSError as error: + if i == 2: + raise def get_behavior_version(ctx): res = ctx.samdb.search(base=ctx.base_dn, scope=ldb.SCOPE_BASE, attrs=["msDS-Behavior-Version"]) diff --git a/python/samba/netcmd/common.py b/python/samba/netcmd/common.py index c68cbabf42e..eb7d5cb1dee 100644 --- a/python/samba/netcmd/common.py +++ b/python/samba/netcmd/common.py @@ -50,22 +50,32 @@ def netcmd_dnsname(lp): return lp.get('netbios name').lower() + "." + lp.get('realm').lower() -def netcmd_finddc(lp, creds, realm=None): +def netcmd_finddc(lp, creds, realm=None, retry_attempts=3): '''Return domain-name of a writable/ldap-capable DC for the default domain (parameter "realm" in smb.conf) unless another realm has been specified as argument''' net = Net(creds=creds, lp=lp) if realm is None: realm = lp.get('realm') - cldap_ret = net.finddc(domain=realm, + for i in range(retry_attempts): + try: + cldap_ret = net.finddc(domain=realm, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS | nbt.NBT_SERVER_WRITABLE) - return cldap_ret.pdc_dns_name + return cldap_ret.pdc_dns_name + except NTSTATUSError as error: + if i == retry_attempts - 1: + raise -def netcmd_get_domain_infos_via_cldap(lp, creds, address=None): +def netcmd_get_domain_infos_via_cldap(lp, creds, address=None, retry_attempts=3): '''Return domain informations (CLDAP record) of the ldap-capable DC with the specified address''' net = Net(creds=creds, lp=lp) - cldap_ret = net.finddc(address=address, + for i in range(retry_attempts): + try: + cldap_ret = net.finddc(address=address, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS) - return cldap_ret + return cldap_ret + except NTSTATUSError as error: + if i == retry_attempts - 1: + raise diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py index b7aedc16a91..74d793e8c50 100644 --- a/python/samba/netcmd/domain.py +++ b/python/samba/netcmd/domain.py @@ -1799,7 +1799,13 @@ class DomainTrustCommand(Command): remote_flags |= nbt.NBT_SERVER_WRITABLE if require_pdc: remote_flags |= nbt.NBT_SERVER_PDC - remote_info = remote_net.finddc(flags=remote_flags, domain=domain, address=remote_server) + for i in range(3): + try: + remote_info = remote_net.finddc(flags=remote_flags, domain=domain, address=remote_server) + break + except NTSTATUSError as error: + if i == 2: + raise except NTSTATUSError as error: raise CommandError("Failed to find a writeable DC for domain '%s': %s" % (domain, error.args[1])) diff --git a/python/samba/netcmd/gpo.py b/python/samba/netcmd/gpo.py index 1b5e927f633..80ffdf4ce48 100644 --- a/python/samba/netcmd/gpo.py +++ b/python/samba/netcmd/gpo.py @@ -1158,12 +1158,24 @@ class cmd_create(GPOCommand): flags = (nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS | nbt.NBT_SERVER_WRITABLE) - cldap_ret = net.finddc(address=dc_hostname, flags=flags) + for i in range(3): + try: + cldap_ret = net.finddc(address=dc_hostname, flags=flags) + break + except NTSTATUSError as error: + if i == 2: + raise else: flags = (nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS | nbt.NBT_SERVER_WRITABLE) - cldap_ret = net.finddc(domain=self.lp.get('realm'), flags=flags) + for i in range(3): + try: + cldap_ret = net.finddc(domain=self.lp.get('realm'), flags=flags) + break + except NTSTATUSError as error: + if i == 2: + raise dc_hostname = cldap_ret.pdc_dns_name self.url = dc_url(self.lp, self.creds, dc=dc_hostname) diff --git a/source4/scripting/bin/samba_spnupdate b/source4/scripting/bin/samba_spnupdate index 9d3a7fab4d9..50eef4a3f4c 100755 --- a/source4/scripting/bin/samba_spnupdate +++ b/source4/scripting/bin/samba_spnupdate @@ -213,11 +213,14 @@ def call_rodc_update(d): creds.set_machine_account(lp) net = Net(creds=creds, lp=lp) - try: - cldap_ret = net.finddc(domain=domain, flags=nbt.NBT_SERVER_DS | nbt.NBT_SERVER_WRITABLE) - except Exception as reason: - print("Unable to find writeable DC for domain '%s' to send DRS writeSPN to : %s" % (domain, reason)) - sys.exit(1) + for i in range(3): + try: + cldap_ret = net.finddc(domain=domain, flags=nbt.NBT_SERVER_DS | nbt.NBT_SERVER_WRITABLE) + break + except Exception as reason: + if i == 2: + print("Unable to find writeable DC for domain '%s' to send DRS writeSPN to : %s" % (domain, reason)) + sys.exit(1) server = cldap_ret.pdc_dns_name try: binding_options = "seal" -- 2.20.1.321.g9e740568ce-goog