def verify_fqdn(host_name, no_host_dns=False, local_hostname=True): """ Run fqdn checks for given host: - test hostname format - test that hostname is fully qualified - test forward and reverse hostname DNS lookup Raises `BadHostError` or derived Exceptions if there is an error :param host_name: The host name to verify. :param no_host_dns: If true, skip DNS resolution tests of the host name. :param local_hostname: If true, run additional checks for local hostnames """ if len(host_name.split(".")) < 2 or host_name == "localhost.localdomain": raise BadHostError("Invalid hostname '%s', must be fully-qualified." % host_name) if host_name != host_name.lower(): raise BadHostError("Invalid hostname '%s', must be lower-case." % host_name) if ipautil.valid_ip(host_name): raise BadHostError("IP address not allowed as a hostname") try: # make sure that the host name meets the requirements in ipalib validate_hostname(host_name) except ValueError, e: raise BadHostError("Invalid hostname '%s', %s" % (host_name, unicode(e)))
def search(self, domain="", servers="", realm=None, hostname=None, ca_cert_path=None): """ Use DNS discovery to identify valid IPA servers. servers may contain an optional list of servers which will be used instead of discovering available LDAP SRV records. Returns a constant representing the overall search result. """ root_logger.debug("[IPA Discovery]") root_logger.debug( 'Starting IPA discovery with domain=%s, servers=%s, hostname=%s', domain, servers, hostname) self.server = None autodiscovered = False if not servers: if not domain: #domain not provided do full DNS discovery # get the local host name if not hostname: hostname = socket.getfqdn() root_logger.debug('Hostname: %s', hostname) if not hostname: return BAD_HOST_CONFIG if valid_ip(hostname): return NOT_FQDN # first, check for an LDAP server for the local domain p = hostname.find(".") if p == -1: #no domain name return NOT_FQDN domain = hostname[p + 1:] # Get the list of domains from /etc/resolv.conf, we'll search # them all. We search the domain of our hostname first though. # This is to avoid the situation where domain isn't set in # /etc/resolv.conf and the search list has the hostname domain # not first. We could end up with the wrong SRV record. domains = self.__get_resolver_domains() domains = [(domain, 'domain of the hostname')] + domains tried = set() for domain, reason in domains: servers, domain = self.check_domain(domain, tried, reason) if servers: autodiscovered = True self.domain = domain self.server_source = self.domain_source = ( 'Discovered LDAP SRV records from %s (%s)' % (domain, reason)) break if not self.domain: #no ldap server found root_logger.debug('No LDAP server found') return NO_LDAP_SERVER else: root_logger.debug("Search for LDAP SRV record in %s", domain) servers = self.ipadns_search_srv(domain, '_ldap._tcp', 389, break_on_first=False) if servers: autodiscovered = True self.domain = domain self.server_source = self.domain_source = ( 'Discovered LDAP SRV records from %s' % domain) else: self.server = None root_logger.debug('No LDAP server found') return NO_LDAP_SERVER else: root_logger.debug("Server and domain forced") self.domain = domain self.domain_source = self.server_source = 'Forced' #search for kerberos root_logger.debug("[Kerberos realm search]") if realm: root_logger.debug("Kerberos realm forced") self.realm = realm self.realm_source = 'Forced' else: realm = self.ipadnssearchkrbrealm() self.realm = realm self.realm_source = ('Discovered Kerberos DNS records from %s' % self.domain) if not servers and not realm: return REALM_NOT_FOUND self.kdc = self.ipadnssearchkrbkdc() self.kdc_source = ('Discovered Kerberos DNS records from %s' % self.domain) # We may have received multiple servers corresponding to the domain # Iterate through all of those to check if it is IPA LDAP server ldapret = [NOT_IPA_SERVER] ldapaccess = True root_logger.debug("[LDAP server check]") valid_servers = [] for server in servers: root_logger.debug('Verifying that %s (realm %s) is an IPA server', server, self.realm) # check ldap now ldapret = self.ipacheckldap(server, self.realm, ca_cert_path=ca_cert_path) if ldapret[0] == 0: self.server = ldapret[1] self.realm = ldapret[2] self.server_source = self.realm_source = ( 'Discovered from LDAP DNS records in %s' % self.server) valid_servers.append(server) # verified, we actually talked to the remote server and it # is definetely an IPA server if autodiscovered: # No need to keep verifying servers if we discovered them # via DNS break elif ldapret[0] == NO_ACCESS_TO_LDAP or ldapret[0] == NO_TLS_LDAP: ldapaccess = False valid_servers.append(server) # we may set verified_servers below, we don't have it yet if autodiscovered: # No need to keep verifying servers if we discovered them # via DNS break elif ldapret[0] == NOT_IPA_SERVER: root_logger.warn('Skip %s: not an IPA server', server) elif ldapret[0] == NO_LDAP_SERVER: root_logger.warn( 'Skip %s: LDAP server is not responding, unable to verify if ' 'this is an IPA server', server) else: root_logger.warn( 'Skip %s: cannot verify if this is an IPA server', server) # If one of LDAP servers checked rejects access (maybe anonymous # bind is disabled), assume realm and basedn generated off domain. # Note that in case ldapret[0] == 0 and ldapaccess == False (one of # servers didn't provide access but another one succeeded), self.realm # will be set already to a proper value above, self.basdn will be # initialized during the LDAP check itself and we'll skip these two checks. if not ldapaccess and self.realm is None: # Assume realm is the same as domain.upper() self.realm = self.domain.upper() self.realm_source = 'Assumed same as domain' root_logger.debug("Assuming realm is the same as domain: %s", self.realm) if not ldapaccess and self.basedn is None: # Generate suffix from realm self.basedn = realm_to_suffix(self.realm) self.basedn_source = 'Generated from Kerberos realm' root_logger.debug("Generated basedn from realm: %s" % self.basedn) root_logger.debug( "Discovery result: %s; server=%s, domain=%s, kdc=%s, basedn=%s", error_names.get(ldapret[0], ldapret[0]), self.server, self.domain, self.kdc, self.basedn) root_logger.debug("Validated servers: %s" % ','.join(valid_servers)) self.servers = valid_servers # If we have any servers left then override the last return value # to indicate success. if valid_servers: self.server = servers[0] ldapret[0] = 0 return ldapret[0]
def search(self, domain="", servers="", realm=None, hostname=None, ca_cert_path=None): """ Use DNS discovery to identify valid IPA servers. servers may contain an optional list of servers which will be used instead of discovering available LDAP SRV records. Returns a constant representing the overall search result. """ root_logger.debug("[IPA Discovery]") root_logger.debug( 'Starting IPA discovery with domain=%s, servers=%s, hostname=%s', domain, servers, hostname) self.server = None autodiscovered = False if not servers: if not domain: #domain not provided do full DNS discovery # get the local host name if not hostname: hostname = socket.getfqdn() root_logger.debug('Hostname: %s', hostname) if not hostname: return BAD_HOST_CONFIG if valid_ip(hostname): return NOT_FQDN # first, check for an LDAP server for the local domain p = hostname.find(".") if p == -1: #no domain name return NOT_FQDN domain = hostname[p+1:] # Get the list of domains from /etc/resolv.conf, we'll search # them all. We search the domain of our hostname first though. # This is to avoid the situation where domain isn't set in # /etc/resolv.conf and the search list has the hostname domain # not first. We could end up with the wrong SRV record. domains = self.__get_resolver_domains() domains = [(domain, 'domain of the hostname')] + domains tried = set() for domain, reason in domains: servers, domain = self.check_domain(domain, tried, reason) if servers: autodiscovered = True self.domain = domain self.server_source = self.domain_source = ( 'Discovered LDAP SRV records from %s (%s)' % (domain, reason)) break if not self.domain: #no ldap server found root_logger.debug('No LDAP server found') return NO_LDAP_SERVER else: root_logger.debug("Search for LDAP SRV record in %s", domain) servers = self.ipadns_search_srv(domain, '_ldap._tcp', 389, break_on_first=False) if servers: autodiscovered = True self.domain = domain self.server_source = self.domain_source = ( 'Discovered LDAP SRV records from %s' % domain) else: self.server = None root_logger.debug('No LDAP server found') return NO_LDAP_SERVER else: root_logger.debug("Server and domain forced") self.domain = domain self.domain_source = self.server_source = 'Forced' #search for kerberos root_logger.debug("[Kerberos realm search]") if realm: root_logger.debug("Kerberos realm forced") self.realm = realm self.realm_source = 'Forced' else: realm = self.ipadnssearchkrbrealm() self.realm = realm self.realm_source = ( 'Discovered Kerberos DNS records from %s' % self.domain) if not servers and not realm: return REALM_NOT_FOUND if autodiscovered: self.kdc = self.ipadnssearchkrbkdc() self.kdc_source = ( 'Discovered Kerberos DNS records from %s' % self.domain) else: self.kdc = ', '.join(servers) self.kdc_source = "Kerberos DNS record discovery bypassed" # We may have received multiple servers corresponding to the domain # Iterate through all of those to check if it is IPA LDAP server ldapret = [NOT_IPA_SERVER] ldapaccess = True root_logger.debug("[LDAP server check]") valid_servers = [] for server in servers: root_logger.debug('Verifying that %s (realm %s) is an IPA server', server, self.realm) # check ldap now ldapret = self.ipacheckldap(server, self.realm, ca_cert_path=ca_cert_path) if ldapret[0] == 0: self.server = ldapret[1] self.realm = ldapret[2] self.server_source = self.realm_source = ( 'Discovered from LDAP DNS records in %s' % self.server) valid_servers.append(server) # verified, we actually talked to the remote server and it # is definetely an IPA server if autodiscovered: # No need to keep verifying servers if we discovered them # via DNS break elif ldapret[0] == NO_ACCESS_TO_LDAP or ldapret[0] == NO_TLS_LDAP: ldapaccess = False valid_servers.append(server) # we may set verified_servers below, we don't have it yet if autodiscovered: # No need to keep verifying servers if we discovered them # via DNS break elif ldapret[0] == NOT_IPA_SERVER: root_logger.warning( 'Skip %s: not an IPA server', server) elif ldapret[0] == NO_LDAP_SERVER: root_logger.warning( 'Skip %s: LDAP server is not responding, unable to verify if ' 'this is an IPA server', server) else: root_logger.warning( 'Skip %s: cannot verify if this is an IPA server', server) # If one of LDAP servers checked rejects access (maybe anonymous # bind is disabled), assume realm and basedn generated off domain. # Note that in case ldapret[0] == 0 and ldapaccess == False (one of # servers didn't provide access but another one succeeded), self.realm # will be set already to a proper value above, self.basdn will be # initialized during the LDAP check itself and we'll skip these two checks. if not ldapaccess and self.realm is None: # Assume realm is the same as domain.upper() self.realm = self.domain.upper() self.realm_source = 'Assumed same as domain' root_logger.debug( "Assuming realm is the same as domain: %s", self.realm) if not ldapaccess and self.basedn is None: # Generate suffix from realm self.basedn = realm_to_suffix(self.realm) self.basedn_source = 'Generated from Kerberos realm' root_logger.debug("Generated basedn from realm: %s" % self.basedn) root_logger.debug( "Discovery result: %s; server=%s, domain=%s, kdc=%s, basedn=%s", error_names.get(ldapret[0], ldapret[0]), self.server, self.domain, self.kdc, self.basedn) root_logger.debug("Validated servers: %s" % ','.join(valid_servers)) self.servers = valid_servers # If we have any servers left then override the last return value # to indicate success. if valid_servers: self.server = servers[0] ldapret[0] = 0 return ldapret[0]
def verify_fqdn(host_name, no_host_dns=False, local_hostname=True): """ Run fqdn checks for given host: - test hostname format - test that hostname is fully qualified - test forward and reverse hostname DNS lookup Raises `BadHostError` or derived Exceptions if there is an error :param host_name: The host name to verify. :param no_host_dns: If true, skip DNS resolution tests of the host name. :param local_hostname: If true, run additional checks for local hostnames """ if len(host_name.split(".")) < 2 or host_name == "localhost.localdomain": raise BadHostError("Invalid hostname '%s', must be fully-qualified." % host_name) if host_name != host_name.lower(): raise BadHostError("Invalid hostname '%s', must be lower-case." % host_name) if ipautil.valid_ip(host_name): raise BadHostError("IP address not allowed as a hostname") try: # make sure that the host name meets the requirements in ipalib validate_hostname(host_name) except ValueError as e: raise BadHostError("Invalid hostname '%s', %s" % (host_name, unicode(e))) if local_hostname: try: logger.debug('Check if %s is a primary hostname for localhost', host_name) ex_name = socket.gethostbyaddr(host_name) logger.debug('Primary hostname for localhost: %s', ex_name[0]) if host_name != ex_name[0]: raise HostLookupError("The host name %s does not match the primary host name %s. "\ "Please check /etc/hosts or DNS name resolution" % (host_name, ex_name[0])) except socket.gaierror: pass except socket.error as e: logger.debug( 'socket.gethostbyaddr() error: %d: %s', e.errno, e.strerror) # pylint: disable=no-member if no_host_dns: print("Warning: skipping DNS resolution of host", host_name) return try: logger.debug('Search DNS for %s', host_name) hostaddr = socket.getaddrinfo(host_name, None) except Exception as e: logger.debug('Search failed: %s', e) raise HostForwardLookupError("Unable to resolve host name, check /etc/hosts or DNS name resolution") if len(hostaddr) == 0: raise HostForwardLookupError("Unable to resolve host name, check /etc/hosts or DNS name resolution") # Verify this is NOT a CNAME try: logger.debug('Check if %s is not a CNAME', host_name) resolver.query(host_name, rdatatype.CNAME) raise HostReverseLookupError("The IPA Server Hostname cannot be a CNAME, only A and AAAA names are allowed.") except DNSException: pass # list of verified addresses to prevent multiple searches for the same address verified = set() for a in hostaddr: address = a[4][0] if address in verified: continue if address in ('127.0.0.1', '::1'): raise HostForwardLookupError("The IPA Server hostname must not resolve to localhost (%s). A routable IP address must be used. Check /etc/hosts to see if %s is an alias for %s" % (address, host_name, address)) try: logger.debug('Check reverse address of %s', address) revname = socket.gethostbyaddr(address)[0] except Exception as e: logger.debug('Check failed: %s', e) logger.error( "Unable to resolve the IP address %s to a host name, " "check /etc/hosts and DNS name resolution", address) else: logger.debug('Found reverse name: %s', revname) if revname != host_name: logger.error( "The host name %s does not match the value %s obtained " "by reverse lookup on IP address %s", host_name, revname, address) verified.add(address)
def verify_fqdn(host_name, no_host_dns=False, local_hostname=True): """ Run fqdn checks for given host: - test hostname format - test that hostname is fully qualified - test forward and reverse hostname DNS lookup Raises `BadHostError` or derived Exceptions if there is an error :param host_name: The host name to verify. :param no_host_dns: If true, skip DNS resolution tests of the host name. :param local_hostname: If true, run additional checks for local hostnames """ if len(host_name.split(".")) < 2 or host_name == "localhost.localdomain": raise BadHostError("Invalid hostname '%s', must be fully-qualified." % host_name) if host_name != host_name.lower(): raise BadHostError("Invalid hostname '%s', must be lower-case." % host_name) if ipautil.valid_ip(host_name): raise BadHostError("IP address not allowed as a hostname") try: # make sure that the host name meets the requirements in ipalib validate_hostname(host_name) except ValueError as e: raise BadHostError("Invalid hostname '%s', %s" % (host_name, unicode(e))) if local_hostname: try: root_logger.debug('Check if %s is a primary hostname for localhost', host_name) ex_name = socket.gethostbyaddr(host_name) root_logger.debug('Primary hostname for localhost: %s', ex_name[0]) if host_name != ex_name[0]: raise HostLookupError("The host name %s does not match the primary host name %s. "\ "Please check /etc/hosts or DNS name resolution" % (host_name, ex_name[0])) except socket.gaierror: pass except socket.error as e: root_logger.debug( 'socket.gethostbyaddr() error: %d: %s', e.errno, e.strerror) # pylint: disable=no-member if no_host_dns: print("Warning: skipping DNS resolution of host", host_name) return try: root_logger.debug('Search DNS for %s', host_name) hostaddr = socket.getaddrinfo(host_name, None) except Exception as e: root_logger.debug('Search failed: %s', e) raise HostForwardLookupError("Unable to resolve host name, check /etc/hosts or DNS name resolution") if len(hostaddr) == 0: raise HostForwardLookupError("Unable to resolve host name, check /etc/hosts or DNS name resolution") # Verify this is NOT a CNAME try: root_logger.debug('Check if %s is not a CNAME', host_name) resolver.query(host_name, rdatatype.CNAME) raise HostReverseLookupError("The IPA Server Hostname cannot be a CNAME, only A and AAAA names are allowed.") except DNSException: pass # list of verified addresses to prevent multiple searches for the same address verified = set() for a in hostaddr: address = a[4][0] if address in verified: continue if address == '127.0.0.1' or address == '::1': raise HostForwardLookupError("The IPA Server hostname must not resolve to localhost (%s). A routable IP address must be used. Check /etc/hosts to see if %s is an alias for %s" % (address, host_name, address)) try: root_logger.debug('Check reverse address of %s', address) revname = socket.gethostbyaddr(address)[0] except Exception as e: root_logger.debug('Check failed: %s', e) root_logger.error( "Unable to resolve the IP address %s to a host name, " "check /etc/hosts and DNS name resolution", address) else: root_logger.debug('Found reverse name: %s', revname) if revname != host_name: root_logger.error( "The host name %s does not match the value %s obtained " "by reverse lookup on IP address %s", host_name, revname, address) verified.add(address)