Example #1
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, e:
        raise BadHostError("Invalid hostname '%s', %s" % (host_name, unicode(e)))
Example #2
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, e:
        raise BadHostError("Invalid hostname '%s', %s" %
                           (host_name, unicode(e)))
Example #3
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

        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]
Example #4
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]
Example #5
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)
Example #6
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:
            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)