Example #1
0
    def setup_firefox_extension(self, realm, domain):
        """Set up the signed browser configuration extension
        """

        target_fname = paths.KRB_JS
        sub_dict = dict(REALM=realm, DOMAIN=domain)
        db = certs.CertDB(realm)
        with open(db.passwd_fname) as pwdfile:
            pwd = pwdfile.read()

        ipautil.copy_template_file(ipautil.SHARE_DIR + "krb.js.template",
            target_fname, sub_dict)
        os.chmod(target_fname, 0644)

        # Setup extension
        tmpdir = tempfile.mkdtemp(prefix="tmp-")
        extdir = tmpdir + "/ext"
        target_fname = paths.KERBEROSAUTH_XPI
        shutil.copytree(paths.FFEXTENSION, extdir)
        if db.has_nickname('Signing-Cert'):
            db.run_signtool(["-k", "Signing-Cert",
                                "-p", pwd,
                                "-X", "-Z", target_fname,
                                extdir])
        else:
            root_logger.warning('Object-signing certificate was not found. '
                'Creating unsigned Firefox configuration extension.')
            filenames = os.listdir(extdir)
            ipautil.run([paths.ZIP, '-r', target_fname] + filenames,
                cwd=extdir)
        shutil.rmtree(tmpdir)
        os.chmod(target_fname, 0644)
Example #2
0
    def __setup_autoconfig(self):
        target_fname = paths.PREFERENCES_HTML
        ipautil.copy_template_file(
            ipautil.SHARE_DIR + "preferences.html.template",
            target_fname, self.sub_dict)
        os.chmod(target_fname, 0644)

        # The signing cert is generated in __setup_ssl
        db = certs.CertDB(self.realm, subject_base=self.subject_base)
        with open(db.passwd_fname) as pwdfile:
            pwd = pwdfile.read()

        # Setup configure.jar
        if db.has_nickname('Signing-Cert'):
            tmpdir = tempfile.mkdtemp(prefix="tmp-")
            target_fname = paths.CONFIGURE_JAR
            shutil.copy(paths.PREFERENCES_HTML, tmpdir)
            db.run_signtool(["-k", "Signing-Cert",
                            "-Z", target_fname,
                            "-e", ".html", "-p", pwd,
                            tmpdir])
            shutil.rmtree(tmpdir)
            os.chmod(target_fname, 0644)
        else:
            root_logger.warning('Object-signing certificate was not found; '
                'therefore, configure.jar was not created.')

        self.setup_firefox_extension(self.realm, self.domain)
Example #3
0
def add_ca_schema():
    """Copy IPA schema files into the CA DS instance
    """
    pki_pent = pwd.getpwnam(PKI_USER)
    ds_pent = pwd.getpwnam(DS_USER)
    for schema_fname in SCHEMA_FILENAMES:
        source_fname = os.path.join(paths.USR_SHARE_IPA_DIR, schema_fname)
        target_fname = os.path.join(schema_dirname(SERVERID), schema_fname)
        if not os.path.exists(source_fname):
            root_logger.debug("File does not exist: %s", source_fname)
            continue
        if os.path.exists(target_fname):
            target_sha1 = _sha1_file(target_fname)
            source_sha1 = _sha1_file(source_fname)
            if target_sha1 != source_sha1:
                target_size = os.stat(target_fname).st_size
                source_size = os.stat(source_fname).st_size
                root_logger.info("Target file %s exists but the content is " "different", target_fname)
                root_logger.info("\tTarget file: sha1: %s, size: %s B", target_sha1, target_size)
                root_logger.info("\tSource file: sha1: %s, size: %s B", source_sha1, source_size)
                if not ipautil.user_input("Do you want replace %s file?" % target_fname, True):
                    continue

            else:
                root_logger.info("Target exists, not overwriting: %s", target_fname)
                continue
        try:
            shutil.copyfile(source_fname, target_fname)
        except IOError as e:
            root_logger.warning("Could not install %s: %s", target_fname, e)
        else:
            root_logger.info("Installed %s", target_fname)
        os.chmod(target_fname, 0o440)  # read access for dirsrv user/group
        os.chown(target_fname, pki_pent.pw_uid, ds_pent.pw_gid)
Example #4
0
    def __setup_autoconfig(self):
        target_fname = paths.PREFERENCES_HTML
        ipautil.copy_template_file(
            ipautil.SHARE_DIR + "preferences.html.template",
            target_fname, self.sub_dict)
        os.chmod(target_fname, 0o644)

        # The signing cert is generated in __setup_ssl
        db = certs.CertDB(self.realm, subject_base=self.subject_base)
        with open(db.passwd_fname) as pwdfile:
            pwd = pwdfile.read()

        # Setup configure.jar
        if db.has_nickname('Signing-Cert'):
            tmpdir = tempfile.mkdtemp(prefix="tmp-")
            target_fname = paths.CONFIGURE_JAR
            shutil.copy(paths.PREFERENCES_HTML, tmpdir)
            db.run_signtool(["-k", "Signing-Cert",
                            "-Z", target_fname,
                            "-e", ".html", "-p", pwd,
                            tmpdir])
            shutil.rmtree(tmpdir)
            os.chmod(target_fname, 0o644)
        else:
            root_logger.warning('Object-signing certificate was not found; '
                'therefore, configure.jar was not created.')

        self.setup_firefox_extension(self.realm, self.domain)
Example #5
0
def check_zone_overlap(zone, raise_on_error=True):
    root_logger.info("Checking DNS domain %s, please wait ..." % zone)
    if not isinstance(zone, DNSName):
        zone = DNSName(zone).make_absolute()

    # automatic empty zones always exist so checking them is pointless,
    # do not report them to avoid meaningless error messages
    if is_auto_empty_zone(zone):
        return

    try:
        containing_zone = dns.resolver.zone_for_name(zone)
    except dns.exception.DNSException as e:
        msg = ("DNS check for domain %s failed: %s." % (zone, e))
        if raise_on_error:
            raise ValueError(msg)
        else:
            root_logger.warning(msg)
            return

    if containing_zone == zone:
        try:
            ns = [ans.to_text() for ans in dns.resolver.query(zone, 'NS')]
        except dns.exception.DNSException as e:
            root_logger.debug("Failed to resolve nameserver(s) for domain"
                              " {0}: {1}".format(zone, e))
            ns = []

        msg = u"DNS zone {0} already exists in DNS".format(zone)
        if ns:
            msg += u" and is handled by server(s): {0}".format(', '.join(ns))
        raise ValueError(msg)
Example #6
0
def broadcast_ip_address_warning(addr_list):
    for ip in addr_list:
        if ip.is_broadcast_addr():
            root_logger.warning("IP address %s might be broadcast address", ip)
            # fixme: once when loggers will be fixed, we can remove this
            # print
            print("WARNING: IP address {} might be broadcast address".format(ip), file=sys.stderr)
Example #7
0
def resolve_ip_addresses_nss(fqdn):
    """Get list of IP addresses for given host (using NSS/getaddrinfo).
    :returns:
        list of IP addresses as UnsafeIPAddress objects
    """
    # make sure the name is fully qualified
    # so search path from resolv.conf does not apply
    fqdn = str(dnsutil.DNSName(fqdn).make_absolute())
    try:
        addrinfos = socket.getaddrinfo(fqdn, None,
                                       socket.AF_UNSPEC, socket.SOCK_STREAM)
    except socket.error as ex:
        if ex.errno == socket.EAI_NODATA or ex.errno == socket.EAI_NONAME:
            root_logger.debug('Name %s does not have any address: %s',
                              fqdn, ex)
            return set()
        else:
            raise

    # accept whatever we got from NSS
    ip_addresses = set()
    for ai in addrinfos:
        try:
            ip = ipautil.UnsafeIPAddress(ai[4][0])
        except ValueError as ex:
            # getaddinfo may return link-local address other similar oddities
            # which are not accepted by CheckedIPAddress - skip these
            root_logger.warning('Name %s resolved to an unacceptable IP '
                                'address %s: %s', fqdn, ai[4][0], ex)
        else:
            ip_addresses.add(ip)
    root_logger.debug('Name %s resolved to %s', fqdn, ip_addresses)
    return ip_addresses
Example #8
0
def get_server_ip_address(host_name, unattended, setup_dns, ip_addresses):
    # Check we have a public IP that is associated with the hostname
    try:
        hostaddr = resolve_host(host_name)
    except HostnameLocalhost:
        print("The hostname resolves to the localhost address (127.0.0.1/::1)", file=sys.stderr)
        print("Please change your /etc/hosts file so that the hostname", file=sys.stderr)
        print("resolves to the ip address of your network interface.", file=sys.stderr)
        print("The KDC service does not listen on localhost", file=sys.stderr)
        print("", file=sys.stderr)
        print("Please fix your /etc/hosts file and restart the setup program", file=sys.stderr)
        sys.exit(1)

    ips = []
    if len(hostaddr):
        for ha in hostaddr:
            try:
                ips.append(ipautil.CheckedIPAddress(ha, match_local=True))
            except ValueError as e:
                root_logger.warning("Invalid IP address %s for %s: %s", ha, host_name, unicode(e))

    if not ips and not ip_addresses:
        if not unattended:
            ip_addresses = read_ip_addresses()

    if ip_addresses:
        if setup_dns:
            ips = ip_addresses
        else:
            # all specified addresses was resolved for this host
            if set(ip_addresses) <= set(ips):
                ips = ip_addresses
            else:
                print("Error: the hostname resolves to IP address(es) that are different", file=sys.stderr)
                print("from those provided on the command line.  Please fix your DNS", file=sys.stderr)
                print("or /etc/hosts file and restart the installation.", file=sys.stderr)
                print("Provided but not resolved address(es): %s" % \
                                    ", ".join(str(ip) for ip in (set(ip_addresses) - set(ips))), file=sys.stderr)
                sys.exit(1)

    if not ips:
        print("No usable IP address provided nor resolved.", file=sys.stderr)
        sys.exit(1)

    for ip_address in ips:
        # check /etc/hosts sanity
        hosts_record = record_in_hosts(str(ip_address))

        if hosts_record is not None:
            primary_host = hosts_record[1][0]
            if primary_host != host_name:
                print("Error: there is already a record in /etc/hosts for IP address %s:" \
                        % ip_address, file=sys.stderr)
                print(hosts_record[0], " ".join(hosts_record[1]), file=sys.stderr)
                print("Chosen hostname %s does not match configured canonical hostname %s" \
                        % (host_name, primary_host), file=sys.stderr)
                print("Please fix your /etc/hosts file and restart the installation.", file=sys.stderr)
                sys.exit(1)

    return ips
Example #9
0
def check_zone_overlap(zone, raise_on_error=True):
    root_logger.info("Checking DNS domain %s, please wait ..." % zone)
    if not isinstance(zone, DNSName):
        zone = DNSName(zone).make_absolute()

    # automatic empty zones always exist so checking them is pointless,
    # do not report them to avoid meaningless error messages
    if is_auto_empty_zone(zone):
        return

    try:
        containing_zone = dns.resolver.zone_for_name(zone)
    except dns.exception.DNSException as e:
        msg = ("DNS check for domain %s failed: %s." % (zone, e))
        if raise_on_error:
            raise ValueError(msg)
        else:
            root_logger.warning(msg)
            return

    if containing_zone == zone:
        try:
            ns = [ans.to_text() for ans in dns.resolver.query(zone, 'NS')]
        except dns.exception.DNSException as e:
            root_logger.debug("Failed to resolve nameserver(s) for domain"
                              " {0}: {1}".format(zone, e))
            ns = []

        msg = u"DNS zone {0} already exists in DNS".format(zone)
        if ns:
            msg += u" and is handled by server(s): {0}".format(', '.join(ns))
        raise ValueError(msg)
Example #10
0
def resolve_ip_addresses_nss(fqdn):
    """Get list of IP addresses for given host (using NSS/getaddrinfo).
    :returns:
        list of IP addresses as UnsafeIPAddress objects
    """
    # make sure the name is fully qualified
    # so search path from resolv.conf does not apply
    fqdn = str(dnsutil.DNSName(fqdn).make_absolute())
    try:
        addrinfos = socket.getaddrinfo(fqdn, None,
                                       socket.AF_UNSPEC, socket.SOCK_STREAM)
    except socket.error as ex:
        if ex.errno == socket.EAI_NODATA or ex.errno == socket.EAI_NONAME:
            root_logger.debug('Name %s does not have any address: %s',
                              fqdn, ex)
            return set()
        else:
            raise

    # accept whatever we got from NSS
    ip_addresses = set()
    for ai in addrinfos:
        try:
            ip = ipautil.UnsafeIPAddress(ai[4][0])
        except ValueError as ex:
            # getaddinfo may return link-local address other similar oddities
            # which are not accepted by CheckedIPAddress - skip these
            root_logger.warning('Name %s resolved to an unacceptable IP '
                                'address %s: %s', fqdn, ai[4][0], ex)
        else:
            ip_addresses.add(ip)
    root_logger.debug('Name %s resolved to %s', fqdn, ip_addresses)
    return ip_addresses
Example #11
0
    def setup_firefox_extension(self, realm, domain):
        """Set up the signed browser configuration extension
        """

        target_fname = paths.KRB_JS
        sub_dict = dict(REALM=realm, DOMAIN=domain)
        db = certs.CertDB(realm)
        with open(db.passwd_fname) as pwdfile:
            pwd = pwdfile.read()

        ipautil.copy_template_file(ipautil.SHARE_DIR + "krb.js.template",
            target_fname, sub_dict)
        os.chmod(target_fname, 0o644)

        # Setup extension
        tmpdir = tempfile.mkdtemp(prefix="tmp-")
        extdir = tmpdir + "/ext"
        target_fname = paths.KERBEROSAUTH_XPI
        shutil.copytree(paths.FFEXTENSION, extdir)
        if db.has_nickname('Signing-Cert'):
            db.run_signtool(["-k", "Signing-Cert",
                                "-p", pwd,
                                "-X", "-Z", target_fname,
                                extdir])
        else:
            root_logger.warning('Object-signing certificate was not found. '
                'Creating unsigned Firefox configuration extension.')
            filenames = os.listdir(extdir)
            ipautil.run([paths.ZIP, '-r', target_fname] + filenames,
                cwd=extdir)
        shutil.rmtree(tmpdir)
        os.chmod(target_fname, 0o644)
Example #12
0
def get_server_ip_address(host_name, unattended, setup_dns, ip_addresses):
    hostaddr = resolve_ip_addresses_nss(host_name)
    if hostaddr.intersection(
            {ipautil.UnsafeIPAddress(ip) for ip in ['127.0.0.1', '::1']}):
        print("The hostname resolves to the localhost address (127.0.0.1/::1)", file=sys.stderr)
        print("Please change your /etc/hosts file so that the hostname", file=sys.stderr)
        print("resolves to the ip address of your network interface.", file=sys.stderr)
        print("The KDC service does not listen on localhost", file=sys.stderr)
        print("", file=sys.stderr)
        print("Please fix your /etc/hosts file and restart the setup program", file=sys.stderr)
        raise ScriptError()

    ips = []
    if len(hostaddr):
        for ha in hostaddr:
            try:
                ips.append(ipautil.CheckedIPAddress(ha, match_local=True))
            except ValueError as e:
                root_logger.warning("Invalid IP address %s for %s: %s", ha, host_name, unicode(e))

    if not ips and not ip_addresses:
        if not unattended:
            ip_addresses = read_ip_addresses()

    if ip_addresses:
        if setup_dns:
            ips = ip_addresses
        else:
            # all specified addresses was resolved for this host
            if set(ip_addresses) <= set(ips):
                ips = ip_addresses
            else:
                print("Error: the hostname resolves to IP address(es) that are different", file=sys.stderr)
                print("from those provided on the command line.  Please fix your DNS", file=sys.stderr)
                print("or /etc/hosts file and restart the installation.", file=sys.stderr)
                print("Provided but not resolved address(es): %s" % \
                                    ", ".join(str(ip) for ip in (set(ip_addresses) - set(ips))), file=sys.stderr)
                raise ScriptError()

    if not ips:
        print("No usable IP address provided nor resolved.", file=sys.stderr)
        raise ScriptError()

    for ip_address in ips:
        # check /etc/hosts sanity
        hosts_record = record_in_hosts(str(ip_address))

        if hosts_record is not None:
            primary_host = hosts_record[1][0]
            if primary_host != host_name:
                print("Error: there is already a record in /etc/hosts for IP address %s:" \
                        % ip_address, file=sys.stderr)
                print(hosts_record[0], " ".join(hosts_record[1]), file=sys.stderr)
                print("Chosen hostname %s does not match configured canonical hostname %s" \
                        % (host_name, primary_host), file=sys.stderr)
                print("Please fix your /etc/hosts file and restart the installation.", file=sys.stderr)
                raise ScriptError()

    return ips
Example #13
0
def broadcast_ip_address_warning(addr_list):
    for ip in addr_list:
        if ip.is_broadcast_addr():
            root_logger.warning("IP address %s might be broadcast address", ip)
            # fixme: once when loggers will be fixed, we can remove this
            # print
            print("WARNING: IP address {} might be broadcast address".format(
                ip), file=sys.stderr)
Example #14
0
def _convert_strings_to_acis(acistrs):
    acis = []
    for a in acistrs:
        try:
            acis.append(ACI(a))
        except SyntaxError:
            root_logger.warning("Failed to parse: %s" % a)
    return acis
Example #15
0
def _convert_strings_to_acis(acistrs):
    acis = []
    for a in acistrs:
        try:
            acis.append(ACI(a))
        except SyntaxError as e:
            root_logger.warning("Failed to parse: %s" % a)
    return acis
Example #16
0
def check_reverse_zones(ip_addresses, reverse_zones, options, unattended,
                        search_reverse_zones=False):
    checked_reverse_zones = []

    if (not options.no_reverse and not reverse_zones
            and not options.auto_reverse):
        if unattended:
            options.no_reverse = True
        else:
            options.no_reverse = not create_reverse()

    # shortcut
    if options.no_reverse:
        return []

    # verify zones passed in options
    for rz in reverse_zones:
        # isn't the zone managed by someone else
        if not options.allow_zone_overlap:
            try:
                ipautil.check_zone_overlap(rz)
            except ValueError as e:
                msg = "Reverse zone %s will not be used: %s" % (rz, e)
                if unattended:
                    sys.exit(msg)
                else:
                    root_logger.warning(msg)
                continue
        checked_reverse_zones.append(normalize_zone(rz))

    # check that there is reverse zone for every IP
    ips_missing_reverse = []
    for ip in ip_addresses:
        if search_reverse_zones and find_reverse_zone(str(ip)):
            # reverse zone is already in LDAP
            continue
        for rz in checked_reverse_zones:
            if verify_reverse_zone(rz, ip):
                # reverse zone was entered by user
                break
        else:
            ips_missing_reverse.append(ip)

    # create reverse zone for IP addresses that does not have one
    for (ip, rz) in get_auto_reverse_zones(ips_missing_reverse):
        if options.auto_reverse:
            root_logger.info("Reverse zone %s will be created" % rz)
            checked_reverse_zones.append(rz)
        elif unattended:
            root_logger.warning("Missing reverse record for IP address %s"
                                % ip)
        else:
            if ipautil.user_input("Do you want to create reverse zone for IP "
                                  "%s" % ip, True):
                rz = read_reverse_zone(rz, str(ip), options.allow_zone_overlap)
                checked_reverse_zones.append(rz)

    return checked_reverse_zones
Example #17
0
def no_matching_interface_for_ip_address_warning(addr_list):
    for ip in addr_list:
        if not ip.get_matching_interface():
            root_logger.warning(
                "No network interface matches the IP address %s", ip)
            # fixme: once when loggers will be fixed, we can remove this
            # print
            print(
                "WARNING: No network interface matches the IP address "
                "{}".format(ip),
                file=sys.stderr
            )
Example #18
0
def remove_keytab(keytab_path):
    """
    Remove Kerberos keytab and issue a warning if the procedure fails

    :param keytab_path: path to the keytab file
    """
    try:
        root_logger.debug("Removing service keytab: {}".format(keytab_path))
        os.remove(keytab_path)
    except OSError as e:
        if e.errno != errno.ENOENT:
            root_logger.warning("Failed to remove Kerberos keytab '{}': "
                                "{}".format(keytab_path, e))
            root_logger.warning("You may have to remove it manually")
Example #19
0
def remove_keytab(keytab_path):
    """
    Remove Kerberos keytab and issue a warning if the procedure fails

    :param keytab_path: path to the keytab file
    """
    try:
        root_logger.debug("Removing service keytab: {}".format(keytab_path))
        os.remove(keytab_path)
    except OSError as e:
        if e.errno != errno.ENOENT:
            root_logger.warning("Failed to remove Kerberos keytab '{}': "
                                "{}".format(keytab_path, e))
            root_logger.warning("You may have to remove it manually")
Example #20
0
def remove_master_from_managed_topology(api_instance, options):
    try:
        # we may force the removal
        server_del_options = dict(
            force=True,
            ignore_topology_disconnect=options.ignore_topology_disconnect,
            ignore_last_of_role=options.ignore_last_of_role)

        replication.run_server_del_as_cli(api_instance, api_instance.env.host,
                                          **server_del_options)
    except errors.ServerRemovalError as e:
        raise ScriptError(str(e))
    except Exception as e:
        # if the master was already deleted we will just get a warning
        root_logger.warning("Failed to delete master: {}".format(e))
Example #21
0
def remove_master_from_managed_topology(api_instance, options):
    try:
        # we may force the removal
        # if the master was already deleted we will just get a warning
        server_del_options = dict(
            force=True,
            ignore_topology_disconnect=options.ignore_topology_disconnect,
            ignore_last_of_role=options.ignore_last_of_role
        )

        replication.run_server_del_as_cli(
            api_instance, api_instance.env.host, **server_del_options)

    except Exception as e:
        root_logger.warning("Failed to delete master: {}".format(e))
Example #22
0
def host_port_open(host,
                   port,
                   socket_type=socket.SOCK_STREAM,
                   socket_timeout=None,
                   log_errors=False):
    """
    host: either hostname or IP address;
          if hostname is provided, port MUST be open on ALL resolved IPs

    returns True is port is open, False otherwise
    """
    port_open = True

    # port has to be open on ALL resolved IPs
    for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket_type):
        af, socktype, proto, _canonname, sa = res
        s = None
        try:
            s = socket.socket(af, socktype, proto)

            if socket_timeout is not None:
                s.settimeout(socket_timeout)

            s.connect(sa)

            if socket_type == socket.SOCK_DGRAM:
                s.send('')
                s.recv(512)
        except socket.error:
            port_open = False

            if log_errors:
                msg = ('Failed to connect to port %(port)d %(proto)s on '
                       '%(addr)s' % dict(port=port,
                                         proto=PROTOCOL_NAMES[socket_type],
                                         addr=sa[0]))

                # Do not log udp failures as errors (to be consistent with
                # the rest of the code that checks for open ports)
                if socket_type == socket.SOCK_DGRAM:
                    root_logger.warning(msg)
                else:
                    root_logger.error(msg)
        finally:
            if s is not None:
                s.close()

    return port_open
Example #23
0
def get_proper_tls_version_span(tls_version_min, tls_version_max):
    """
    This function checks whether the given TLS versions are known in
    FreeIPA and that these versions fulfill the requirements for minimal
    TLS version (see
    `ipalib.constants: TLS_VERSIONS, TLS_VERSION_MINIMAL`).

    :param tls_version_min:
        the lower value in the TLS min-max span, raised to the lowest
        allowed value if too low
    :param tls_version_max:
        the higher value in the TLS min-max span, raised to tls_version_min
        if lower than TLS_VERSION_MINIMAL
    :raises: ValueError
    """
    min_allowed_idx = TLS_VERSIONS.index(TLS_VERSION_MINIMAL)

    try:
        min_version_idx = TLS_VERSIONS.index(tls_version_min)
    except ValueError:
        raise ValueError("tls_version_min ('{val}') is not a known "
                         "TLS version.".format(val=tls_version_min))

    try:
        max_version_idx = TLS_VERSIONS.index(tls_version_max)
    except ValueError:
        raise ValueError("tls_version_max ('{val}') is not a known "
                         "TLS version.".format(val=tls_version_max))

    if min_version_idx > max_version_idx:
        raise ValueError("tls_version_min is higher than "
                         "tls_version_max.")

    if min_version_idx < min_allowed_idx:
        min_version_idx = min_allowed_idx
        root_logger.warning("tls_version_min set too low ('{old}'),"
                            "using '{new}' instead"
                            .format(old=tls_version_min,
                                    new=TLS_VERSIONS[min_version_idx]))

    if max_version_idx < min_allowed_idx:
        max_version_idx = min_version_idx
        root_logger.warning("tls_version_max set too low ('{old}'),"
                            "using '{new}' instead"
                            .format(old=tls_version_max,
                                    new=TLS_VERSIONS[max_version_idx]))
    return TLS_VERSIONS[min_version_idx:max_version_idx+1]
Example #24
0
    def _parse(self, obj, full=True):
        """Extract certificate-specific data into a result object.

        ``obj``
            Result object containing certificate, into which extracted
            data will be inserted.
        ``full``
            Whether to include all fields, or only the ones we guess
            people want to see most of the time.  Also add
            recognised otherNames to the generic ``san_other``
            attribute when ``True`` in addition to the specialised
            attribute.

        """
        cert = obj.get('certificate')
        if cert is not None:
            cert = x509.load_certificate(cert)
            obj['subject'] = DN(unicode(cert.subject))
            obj['issuer'] = DN(unicode(cert.issuer))
            obj['serial_number'] = cert.serial_number
            if full:
                obj['valid_not_before'] = unicode(cert.valid_not_before_str)
                obj['valid_not_after'] = unicode(cert.valid_not_after_str)
                obj['md5_fingerprint'] = unicode(
                    nss.data_to_hex(nss.md5_digest(cert.der_data), 64)[0])
                obj['sha1_fingerprint'] = unicode(
                    nss.data_to_hex(nss.sha1_digest(cert.der_data), 64)[0])

            try:
                ext_san = cert.get_extension(nss.SEC_OID_X509_SUBJECT_ALT_NAME)
                general_names = x509.decode_generalnames(ext_san.value)
            except KeyError:
                general_names = []

            for name_type, desc, name, der_name in general_names:
                try:
                    self._add_san_attribute(
                        obj, full, name_type, name, der_name)
                except Exception as e:
                    # Invalid GeneralName (i.e. not a valid X.509 cert);
                    # don't fail but log something about it
                    root_logger.warning(
                        "Encountered bad GeneralName; skipping", exc_info=True)

        serial_number = obj.get('serial_number')
        if serial_number is not None:
            obj['serial_number_hex'] = u'0x%X' % serial_number
Example #25
0
    def _parse(self, obj, full=True):
        """Extract certificate-specific data into a result object.

        ``obj``
            Result object containing certificate, into which extracted
            data will be inserted.
        ``full``
            Whether to include all fields, or only the ones we guess
            people want to see most of the time.  Also add
            recognised otherNames to the generic ``san_other``
            attribute when ``True`` in addition to the specialised
            attribute.

        """
        cert = obj.get('certificate')
        if cert is not None:
            cert = x509.load_certificate(cert)
            obj['subject'] = DN(unicode(cert.subject))
            obj['issuer'] = DN(unicode(cert.issuer))
            obj['serial_number'] = cert.serial_number
            if full:
                obj['valid_not_before'] = unicode(cert.valid_not_before_str)
                obj['valid_not_after'] = unicode(cert.valid_not_after_str)
                obj['md5_fingerprint'] = unicode(
                    nss.data_to_hex(nss.md5_digest(cert.der_data), 64)[0])
                obj['sha1_fingerprint'] = unicode(
                    nss.data_to_hex(nss.sha1_digest(cert.der_data), 64)[0])

            try:
                ext_san = cert.get_extension(nss.SEC_OID_X509_SUBJECT_ALT_NAME)
                general_names = x509.decode_generalnames(ext_san.value)
            except KeyError:
                general_names = []

            for name_type, _desc, name, der_name in general_names:
                try:
                    self._add_san_attribute(obj, full, name_type, name,
                                            der_name)
                except Exception:
                    # Invalid GeneralName (i.e. not a valid X.509 cert);
                    # don't fail but log something about it
                    root_logger.warning(
                        "Encountered bad GeneralName; skipping", exc_info=True)

        serial_number = obj.get('serial_number')
        if serial_number is not None:
            obj['serial_number_hex'] = u'0x%X' % serial_number
Example #26
0
def get_proper_tls_version_span(tls_version_min, tls_version_max):
    """
    This function checks whether the given TLS versions are known in
    FreeIPA and that these versions fulfill the requirements for minimal
    TLS version (see
    `ipalib.constants: TLS_VERSIONS, TLS_VERSION_MINIMAL`).

    :param tls_version_min:
        the lower value in the TLS min-max span, raised to the lowest
        allowed value if too low
    :param tls_version_max:
        the higher value in the TLS min-max span, raised to tls_version_min
        if lower than TLS_VERSION_MINIMAL
    :raises: ValueError
    """
    min_allowed_idx = TLS_VERSIONS.index(TLS_VERSION_MINIMAL)

    try:
        min_version_idx = TLS_VERSIONS.index(tls_version_min)
    except ValueError:
        raise ValueError("tls_version_min ('{val}') is not a known "
                         "TLS version.".format(val=tls_version_min))

    try:
        max_version_idx = TLS_VERSIONS.index(tls_version_max)
    except ValueError:
        raise ValueError("tls_version_max ('{val}') is not a known "
                         "TLS version.".format(val=tls_version_max))

    if min_version_idx > max_version_idx:
        raise ValueError("tls_version_min is higher than " "tls_version_max.")

    if min_version_idx < min_allowed_idx:
        min_version_idx = min_allowed_idx
        root_logger.warning("tls_version_min set too low ('{old}'),"
                            "using '{new}' instead".format(
                                old=tls_version_min,
                                new=TLS_VERSIONS[min_version_idx]))

    if max_version_idx < min_allowed_idx:
        max_version_idx = min_version_idx
        root_logger.warning("tls_version_max set too low ('{old}'),"
                            "using '{new}' instead".format(
                                old=tls_version_max,
                                new=TLS_VERSIONS[max_version_idx]))
    return TLS_VERSIONS[min_version_idx:max_version_idx + 1]
Example #27
0
def host_port_open(host, port, socket_type=socket.SOCK_STREAM,
                   socket_timeout=None, log_errors=False):
    """
    host: either hostname or IP address;
          if hostname is provided, port MUST be open on ALL resolved IPs

    returns True is port is open, False otherwise
    """
    port_open = True

    # port has to be open on ALL resolved IPs
    for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket_type):
        af, socktype, proto, _canonname, sa = res
        s = None
        try:
            s = socket.socket(af, socktype, proto)

            if socket_timeout is not None:
                s.settimeout(socket_timeout)

            s.connect(sa)

            if socket_type == socket.SOCK_DGRAM:
                s.send('')
                s.recv(512)
        except socket.error:
            port_open = False

            if log_errors:
                msg = ('Failed to connect to port %(port)d %(proto)s on '
                       '%(addr)s' % dict(port=port,
                                         proto=PROTOCOL_NAMES[socket_type],
                                         addr=sa[0]))

                # Do not log udp failures as errors (to be consistent with
                # the rest of the code that checks for open ports)
                if socket_type == socket.SOCK_DGRAM:
                    root_logger.warning(msg)
                else:
                    root_logger.error(msg)
        finally:
            if s is not None:
                s.close()

    return port_open
Example #28
0
    def convert_ipa_ca_cnames(self, domain_name):
        # get ipa-ca CNAMEs
        cnames = get_rr(domain_name, IPA_CA_RECORD, "CNAME", api=self.api)
        if not cnames:
            return

        root_logger.info('Converting IPA CA CNAME records to A/AAAA records')

        # create CNAME to FQDN mapping
        cname_fqdn = {}
        for cname in cnames:
            if cname.endswith('.'):
                fqdn = cname[:-1]
            else:
                fqdn = '%s.%s' % (cname, domain_name)
            cname_fqdn[cname] = fqdn

        # get FQDNs of all IPA masters
        ldap = self.api.Backend.ldap2
        try:
            entries = ldap.get_entries(
                DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
                   self.api.env.basedn),
                ldap.SCOPE_ONELEVEL, None, ['cn'])
            masters = set(e['cn'][0] for e in entries)
        except errors.NotFound:
            masters = set()

        # check if all CNAMEs point to IPA masters
        for cname in cnames:
            fqdn = cname_fqdn[cname]
            if fqdn not in masters:
                root_logger.warning(
                    "Cannot convert IPA CA CNAME records to A/AAAA records, "
                    "please convert them manually if necessary")
                return

        # delete all CNAMEs
        for cname in cnames:
            del_rr(domain_name, IPA_CA_RECORD, "CNAME", cname, api=self.api)

        # add A/AAAA records
        for cname in cnames:
            fqdn = cname_fqdn[cname]
            self.add_ipa_ca_dns_records(fqdn, domain_name, None)
Example #29
0
def remove_ccache(ccache_path=None, run_as=None):
    """
    remove Kerberos credential cache, essentially a wrapper around kdestroy.

    :param ccache_path: path to the ccache file
    :param run_as: run kdestroy as this user
    """
    root_logger.debug("Removing service credentials cache")
    kdestroy_cmd = [paths.KDESTROY]
    if ccache_path is not None:
        root_logger.debug("Ccache path: '{}'".format(ccache_path))
        kdestroy_cmd.extend(['-c', ccache_path])

    try:
        ipautil.run(kdestroy_cmd, runas=run_as, env={})
    except ipautil.CalledProcessError as e:
        root_logger.warning(
            "Failed to clear Kerberos credentials cache: {}".format(e))
Example #30
0
def remove_ccache(ccache_path=None, run_as=None):
    """
    remove Kerberos credential cache, essentially a wrapper around kdestroy.

    :param ccache_path: path to the ccache file
    :param run_as: run kdestroy as this user
    """
    root_logger.debug("Removing service credentials cache")
    kdestroy_cmd = [paths.KDESTROY]
    if ccache_path is not None:
        root_logger.debug("Ccache path: '{}'".format(ccache_path))
        kdestroy_cmd.extend(['-c', ccache_path])

    try:
        ipautil.run(kdestroy_cmd, runas=run_as, env={})
    except ipautil.CalledProcessError as e:
        root_logger.warning(
            "Failed to clear Kerberos credentials cache: {}".format(e))
Example #31
0
    def __add_master_records(self, fqdn, addrs):
        host, zone = fqdn.split(".", 1)

        if normalize_zone(zone) == normalize_zone(self.domain):
            host_in_rr = host
        else:
            host_in_rr = normalize_zone(fqdn)

        srv_records = (
            ("_ldap._tcp", "0 100 389 %s" % host_in_rr),
            ("_kerberos._tcp", "0 100 88 %s" % host_in_rr),
            ("_kerberos._udp", "0 100 88 %s" % host_in_rr),
            ("_kerberos-master._tcp", "0 100 88 %s" % host_in_rr),
            ("_kerberos-master._udp", "0 100 88 %s" % host_in_rr),
            ("_kpasswd._tcp", "0 100 464 %s" % host_in_rr),
            ("_kpasswd._udp", "0 100 464 %s" % host_in_rr),
        )
        if self.ntp:
            srv_records += (
                ("_ntp._udp", "0 100 123 %s" % host_in_rr),
            )

        for (rname, rdata) in srv_records:
            add_rr(self.domain, rname, "SRV", rdata, self.dns_backup,
                   api=self.api)

        if not dns_zone_exists(zone, self.api):
            # check if master hostname is resolvable
            try:
                verify_host_resolvable(fqdn, root_logger)
            except errors.DNSNotARecordError:
                root_logger.warning("Master FQDN (%s) is not resolvable.",
                                    fqdn)

        # Add forward and reverse records to self
        for addr in addrs:
            try:
                add_fwd_rr(zone, host, addr, self.api)
            except errors.NotFound as e:
                pass

            reverse_zone = find_reverse_zone(addr, self.api)
            if reverse_zone:
                add_ptr_rr(reverse_zone, addr, fqdn, None, api=self.api)
Example #32
0
    def remove_ipa_ca_cnames(self, domain_name):
        # get ipa-ca CNAMEs
        try:
            cnames = get_rr(domain_name, IPA_CA_RECORD, "CNAME", api=self.api)
        except errors.NotFound:
            # zone does not exists
            cnames = None
        if not cnames:
            return

        root_logger.info('Removing IPA CA CNAME records')

        # create CNAME to FQDN mapping
        cname_fqdn = {}
        for cname in cnames:
            if cname.endswith('.'):
                fqdn = cname[:-1]
            else:
                fqdn = '%s.%s' % (cname, domain_name)
            cname_fqdn[cname] = fqdn

        # get FQDNs of all IPA masters
        ldap = self.api.Backend.ldap2
        try:
            entries = ldap.get_entries(
                DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
                   self.api.env.basedn), ldap.SCOPE_ONELEVEL, None, ['cn'])
            masters = set(e['cn'][0] for e in entries)
        except errors.NotFound:
            masters = set()

        # check if all CNAMEs point to IPA masters
        for cname in cnames:
            fqdn = cname_fqdn[cname]
            if fqdn not in masters:
                root_logger.warning(
                    "Cannot remove IPA CA CNAME please remove them manually "
                    "if necessary")
                return

        # delete all CNAMEs
        for cname in cnames:
            del_rr(domain_name, IPA_CA_RECORD, "CNAME", cname, api=self.api)
Example #33
0
    def _parse(self, obj, full=True):
        """Extract certificate-specific data into a result object.

        ``obj``
            Result object containing certificate, into which extracted
            data will be inserted.
        ``full``
            Whether to include all fields, or only the ones we guess
            people want to see most of the time.  Also add
            recognised otherNames to the generic ``san_other``
            attribute when ``True`` in addition to the specialised
            attribute.

        """
        if 'certificate' in obj:
            cert = x509.load_certificate(obj['certificate'])
            obj['subject'] = DN(cert.subject)
            obj['issuer'] = DN(cert.issuer)
            obj['serial_number'] = cert.serial
            obj['valid_not_before'] = x509.format_datetime(
                cert.not_valid_before)
            obj['valid_not_after'] = x509.format_datetime(cert.not_valid_after)
            if full:
                obj['md5_fingerprint'] = x509.to_hex_with_colons(
                    cert.fingerprint(hashes.MD5()))
                obj['sha1_fingerprint'] = x509.to_hex_with_colons(
                    cert.fingerprint(hashes.SHA1()))

            general_names = x509.process_othernames(
                x509.get_san_general_names(cert))

            for gn in general_names:
                try:
                    self._add_san_attribute(obj, full, gn)
                except Exception:
                    # Invalid GeneralName (i.e. not a valid X.509 cert);
                    # don't fail but log something about it
                    root_logger.warning(
                        "Encountered bad GeneralName; skipping", exc_info=True)

        serial_number = obj.get('serial_number')
        if serial_number is not None:
            obj['serial_number_hex'] = u'0x%X' % serial_number
Example #34
0
    def __add_sids(self):
        """
        Add SIDs for existing users and groups. Make sure the task is finished
        before continuing.
        """

        try:
            # Start the sidgen task
            self._ldap_mod("ipa-sidgen-task-run.ldif", self.sub_dict)

            # Notify the user about the possible delay
            self.print_msg("This step may take considerable amount of time, please wait..")

            # Wait for the task to complete
            task_dn = DN('cn=sidgen,cn=ipa-sidgen-task,cn=tasks,cn=config')
            wait_for_task(self.admin_conn, task_dn)

        except Exception as e:
            root_logger.warning("Exception occured during SID generation: {0}"
                                .format(str(e)))
def add_ca_schema():
    """Copy IPA schema files into the CA DS instance
    """
    pki_pent = pwd.getpwnam(PKI_USER)
    ds_pent = pwd.getpwnam(DS_USER)
    for schema_fname in SCHEMA_FILENAMES:
        source_fname = os.path.join(ipautil.SHARE_DIR, schema_fname)
        target_fname = os.path.join(schema_dirname(SERVERID), schema_fname)
        if not os.path.exists(source_fname):
            root_logger.debug('File does not exist: %s', source_fname)
            continue
        if os.path.exists(target_fname):
            target_sha1 = _sha1_file(target_fname)
            source_sha1 = _sha1_file(source_fname)
            if target_sha1 != source_sha1:
                target_size = os.stat(target_fname).st_size
                source_size = os.stat(source_fname).st_size
                root_logger.info(
                    'Target file %s exists but the content is '
                    'different', target_fname)
                root_logger.info('\tTarget file: sha1: %s, size: %s B',
                                 target_sha1, target_size)
                root_logger.info('\tSource file: sha1: %s, size: %s B',
                                 source_sha1, source_size)
                if not ipautil.user_input(
                        "Do you want replace %s file?" % target_fname, True):
                    continue

            else:
                root_logger.info('Target exists, not overwriting: %s',
                                 target_fname)
                continue
        try:
            shutil.copyfile(source_fname, target_fname)
        except IOError as e:
            root_logger.warning('Could not install %s: %s', target_fname, e)
        else:
            root_logger.info('Installed %s', target_fname)
        os.chmod(target_fname, 0o440)  # read access for dirsrv user/group
        os.chown(target_fname, pki_pent.pw_uid, ds_pent.pw_gid)
Example #36
0
def get_server_ip_address(host_name, fstore, unattended, setup_dns, ip_addresses):
    # Check we have a public IP that is associated with the hostname
    try:
        hostaddr = resolve_host(host_name)
    except HostnameLocalhost:
        print >> sys.stderr, "The hostname resolves to the localhost address (127.0.0.1/::1)"
        print >> sys.stderr, "Please change your /etc/hosts file so that the hostname"
        print >> sys.stderr, "resolves to the ip address of your network interface."
        print >> sys.stderr, "The KDC service does not listen on localhost"
        print >> sys.stderr, ""
        print >> sys.stderr, "Please fix your /etc/hosts file and restart the setup program"
        sys.exit(1)

    ip_add_to_hosts = False

    ips = []
    if len(hostaddr):
        for ha in hostaddr:
            try:
                ips.append(ipautil.CheckedIPAddress(ha, match_local=True))
            except ValueError, e:
                root_logger.warning("Invalid IP address %s for %s: %s", ha, host_name, unicode(e))
Example #37
0
    def __add_sids(self):
        """
        Add SIDs for existing users and groups. Make sure the task is finished
        before continuing.
        """

        try:
            # Start the sidgen task
            self._ldap_mod("ipa-sidgen-task-run.ldif", self.sub_dict)

            # Notify the user about the possible delay
            self.print_msg(
                "This step may take considerable amount of time, please wait.."
            )

            # Wait for the task to complete
            task_dn = DN('cn=sidgen,cn=ipa-sidgen-task,cn=tasks,cn=config')
            wait_for_task(api.Backend.ldap2, task_dn)

        except Exception as e:
            root_logger.warning(
                "Exception occured during SID generation: {0}".format(str(e)))
Example #38
0
def add_ca_schema():
    """Copy IPA schema files into the CA DS instance
    """
    pki_pent = pwd.getpwnam(PKI_USER)
    ds_pent = pwd.getpwnam(DS_USER)
    for schema_fname in SCHEMA_FILENAMES:
        source_fname = os.path.join(ipautil.SHARE_DIR, schema_fname)
        target_fname = os.path.join(schema_dirname(SERVERID), schema_fname)
        if not os.path.exists(source_fname):
            root_logger.debug('File does not exist: %s', source_fname)
            continue
        if os.path.exists(target_fname):
            root_logger.info('Target exists, not overwriting: %s',
                             target_fname)
            continue
        try:
            shutil.copyfile(source_fname, target_fname)
        except IOError, e:
            root_logger.warning('Could not install %s: %s', target_fname, e)
        else:
            root_logger.info('Installed %s', target_fname)
        os.chmod(target_fname, 0440)  # read access for dirsrv user/group
        os.chown(target_fname, pki_pent.pw_uid, ds_pent.pw_gid)
Example #39
0
def add_ca_schema():
    """Copy IPA schema files into the CA DS instance
    """
    pki_pent = pwd.getpwnam(PKI_USER)
    ds_pent = pwd.getpwnam(DS_USER)
    for schema_fname in SCHEMA_FILENAMES:
        source_fname = os.path.join(ipautil.SHARE_DIR, schema_fname)
        target_fname = os.path.join(schema_dirname(SERVERID), schema_fname)
        if not os.path.exists(source_fname):
            root_logger.debug('File does not exist: %s', source_fname)
            continue
        if os.path.exists(target_fname):
            root_logger.info(
                'Target exists, not overwriting: %s', target_fname)
            continue
        try:
            shutil.copyfile(source_fname, target_fname)
        except IOError, e:
            root_logger.warning('Could not install %s: %s', target_fname, e)
        else:
            root_logger.info('Installed %s', target_fname)
        os.chmod(target_fname, 0440)    # read access for dirsrv user/group
        os.chown(target_fname, pki_pent.pw_uid, ds_pent.pw_gid)
Example #40
0
def get_server_ip_address(host_name, fstore, unattended, setup_dns,
                          ip_addresses):
    # Check we have a public IP that is associated with the hostname
    try:
        hostaddr = resolve_host(host_name)
    except HostnameLocalhost:
        print >> sys.stderr, "The hostname resolves to the localhost address (127.0.0.1/::1)"
        print >> sys.stderr, "Please change your /etc/hosts file so that the hostname"
        print >> sys.stderr, "resolves to the ip address of your network interface."
        print >> sys.stderr, "The KDC service does not listen on localhost"
        print >> sys.stderr, ""
        print >> sys.stderr, "Please fix your /etc/hosts file and restart the setup program"
        sys.exit(1)

    ip_add_to_hosts = False

    ips = []
    if len(hostaddr):
        for ha in hostaddr:
            try:
                ips.append(ipautil.CheckedIPAddress(ha, match_local=True))
            except ValueError, e:
                root_logger.warning("Invalid IP address %s for %s: %s", ha,
                                    host_name, unicode(e))
Example #41
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 #42
0
def install_check(standalone, api, replica, options, hostname):
    global ip_addresses
    global reverse_zones
    fstore = sysrestore.FileStore(paths.SYSRESTORE)

    if not ipautil.file_exists(paths.IPA_DNS_INSTALL):
        raise RuntimeError("Integrated DNS requires '%s' package" %
                           constants.IPA_DNS_PACKAGE_NAME)

    # when installing first DNS instance we need to check zone overlap
    if replica or standalone:
        already_enabled = api.Command.dns_is_enabled()['result']
    else:
        already_enabled = False

    if not already_enabled:
        domain = dnsutil.DNSName(util.normalize_zone(api.env.domain))
        print("Checking DNS domain %s, please wait ..." % domain)
        try:
            dnsutil.check_zone_overlap(domain, raise_on_error=False)
        except ValueError as e:
            if options.force or options.allow_zone_overlap:
                root_logger.warning("%s Please make sure that the domain is "
                                    "properly delegated to this IPA server.",
                                    e)
            else:
                raise e

    for reverse_zone in options.reverse_zones:
        try:
            dnsutil.check_zone_overlap(reverse_zone)
        except ValueError as e:
            if options.force or options.allow_zone_overlap:
                root_logger.warning(six.text_type(e))
            else:
                raise e

    if standalone:
        print("==============================================================================")
        print("This program will setup DNS for the FreeIPA Server.")
        print("")
        print("This includes:")
        print("  * Configure DNS (bind)")
        print("  * Configure SoftHSM (required by DNSSEC)")
        print("  * Configure ipa-dnskeysyncd (required by DNSSEC)")
        if options.dnssec_master:
            print("  * Configure ipa-ods-exporter (required by DNSSEC key master)")
            print("  * Configure OpenDNSSEC (required by DNSSEC key master)")
            print("  * Generate DNSSEC master key (required by DNSSEC key master)")
        elif options.disable_dnssec_master:
            print("  * Unconfigure ipa-ods-exporter")
            print("  * Unconfigure OpenDNSSEC")
            print("")
            print("No new zones will be signed without DNSSEC key master IPA server.")
            print("")
            print(("Please copy file from %s after uninstallation. This file is needed "
                   "on new DNSSEC key " % paths.IPA_KASP_DB_BACKUP))
            print("master server")
        print("")
        print("NOTE: DNSSEC zone signing is not enabled by default")
        print("")
        if options.dnssec_master:
            print("Plan carefully, replacing DNSSEC key master is not recommended")
            print("")
        print("")
        print("To accept the default shown in brackets, press the Enter key.")
        print("")

    if (options.dnssec_master and not options.unattended and not
        ipautil.user_input(
            "Do you want to setup this IPA server as DNSSEC key master?",
            False)):
        sys.exit("Aborted")
    elif (options.disable_dnssec_master and not options.unattended and not
          ipautil.user_input(
            "Do you want to disable current DNSSEC key master?",
            False)):
        sys.exit("Aborted")

    if options.disable_dnssec_master:
        _is_master()

    if options.disable_dnssec_master or options.dnssec_master:
        dnssec_zones = _find_dnssec_enabled_zones(api.Backend.ldap2)

    if options.disable_dnssec_master:
        if dnssec_zones and not options.force:
            raise RuntimeError(
                "Cannot disable DNSSEC key master, DNSSEC signing is still "
                "enabled for following zone(s):\n"
                "%s\n"
                "It is possible to move DNSSEC key master role to a different "
                "server by using --force option to skip this check.\n\n"
                "WARNING: You have to immediatelly copy kasp.db file to a new "
                "server and run command 'ipa-dns-install --dnssec-master "
                "--kasp-db'.\n"
                "Your DNS zones will become unavailable if you "
                "do not reinstall the DNSSEC key master role immediatelly." %
                ", ".join([str(zone) for zone in dnssec_zones]))

    elif options.dnssec_master:
        ods = opendnssecinstance.OpenDNSSECInstance(fstore)
        ods.realm = api.env.realm
        dnssec_masters = ods.get_masters()
        # we can reinstall current server if it is dnssec master
        if dnssec_masters and api.env.host not in dnssec_masters:
            print("DNSSEC key master(s):", u','.join(dnssec_masters))
            raise ScriptError(
                "Only one DNSSEC key master is supported in current version.")

        if options.kasp_db_file:
            dnskeysyncd = services.service('ipa-dnskeysyncd', api)

            if not dnskeysyncd.is_installed():
                raise RuntimeError("ipa-dnskeysyncd is not configured on this "
                                   "server, you cannot reuse OpenDNSSEC "
                                   "database (kasp.db file)")

            # check if replica can be the DNSSEC master
            cmd = [paths.IPA_DNSKEYSYNCD_REPLICA]
            environment = {
                "SOFTHSM2_CONF": paths.DNSSEC_SOFTHSM2_CONF,
            }

            # stop dnskeysyncd before test
            dnskeysyncd_running = dnskeysyncd.is_running()
            dnskeysyncd.stop()
            try:
                ipautil.run(cmd, env=environment,
                            runas=constants.ODS_USER,
                            suplementary_groups=[constants.NAMED_GROUP])
            except CalledProcessError as e:
                root_logger.debug("%s", e)
                raise RuntimeError("This IPA server cannot be promoted to "
                                   "DNSSEC master role because some keys were "
                                   "not replicated from the original "
                                   "DNSSEC master server")
            finally:
                if dnskeysyncd_running:
                    dnskeysyncd.start()
        elif dnssec_zones and not options.force:
            # some zones have --dnssec=true, make sure a user really want to
            # install new database
            raise RuntimeError(
                "DNSSEC signing is already enabled for following zone(s): %s\n"
                "Installation cannot continue without the OpenDNSSEC database "
                "file from the original DNSSEC master server.\n"
                "Please use option --kasp-db to specify location "
                "of the kasp.db file copied from the original "
                "DNSSEC master server.\n"
                "WARNING: Zones will become unavailable if you do not provide "
                "the original kasp.db file." %
                ", ".join([str(zone) for zone in dnssec_zones]))

    ip_addresses = get_server_ip_address(hostname, options.unattended,
                                         True, options.ip_addresses)

    util.network_ip_address_warning(ip_addresses)
    util.broadcast_ip_address_warning(ip_addresses)

    if not options.forward_policy:
        # user did not specify policy, derive it: default is 'first' but
        # if any of local IP addresses belongs to private ranges use 'only'
        options.forward_policy = 'first'
        for ip in ip_addresses:
            if dnsutil.inside_auto_empty_zone(dnsutil.DNSName(ip.reverse_dns)):
                options.forward_policy = 'only'
                root_logger.debug('IP address %s belongs to a private range, '
                                  'using forward policy only', ip)
                break

    if options.no_forwarders:
        options.forwarders = []
    elif options.forwarders or options.auto_forwarders:
        if not options.forwarders:
            options.forwarders = []
        if options.auto_forwarders:
            options.forwarders += resolver.get_default_resolver().nameservers
    elif standalone or not replica:
        options.forwarders = read_dns_forwarders()

    # test DNSSEC forwarders
    if options.forwarders:
        if (not bindinstance.check_forwarders(options.forwarders,
                                              root_logger)
                and not options.no_dnssec_validation):
            options.no_dnssec_validation = True
            print("WARNING: DNSSEC validation will be disabled")

    root_logger.debug("will use DNS forwarders: %s\n", options.forwarders)

    if not standalone:
        search_reverse_zones = False
    else:
        search_reverse_zones = True

    if not standalone and replica:
        reverse_zones_unattended_check = True
    else:
        reverse_zones_unattended_check = options.unattended

    reverse_zones = bindinstance.check_reverse_zones(
        ip_addresses, options.reverse_zones, options,
        reverse_zones_unattended_check, search_reverse_zones
    )

    if reverse_zones:
        print("Using reverse zone(s) %s" % ', '.join(reverse_zones))
Example #43
0
    def insert_ca_certs_into_systemwide_ca_store(self, ca_certs):
        new_cacert_path = paths.SYSTEMWIDE_IPA_CA_CRT

        if os.path.exists(new_cacert_path):
            try:
                os.remove(new_cacert_path)
            except OSError as e:
                root_logger.error(
                    "Could not remove %s: %s", new_cacert_path, e)
                return False

        new_cacert_path = paths.IPA_P11_KIT

        try:
            f = open(new_cacert_path, 'w')
        except IOError as e:
            root_logger.info("Failed to open %s: %s" % (new_cacert_path, e))
            return False

        f.write("# This file was created by IPA. Do not edit.\n"
                "\n")

        has_eku = set()
        for cert, nickname, trusted, ext_key_usage in ca_certs:
            try:
                subject = x509.get_der_subject(cert, x509.DER)
                issuer = x509.get_der_issuer(cert, x509.DER)
                serial_number = x509.get_der_serial_number(cert, x509.DER)
                public_key_info = x509.get_der_public_key_info(cert, x509.DER)
            except (NSPRError, PyAsn1Error, ValueError) as e:
                root_logger.warning(
                    "Failed to decode certificate \"%s\": %s", nickname, e)
                continue

            label = urllib.parse.quote(nickname)
            subject = urllib.parse.quote(subject)
            issuer = urllib.parse.quote(issuer)
            serial_number = urllib.parse.quote(serial_number)
            public_key_info = urllib.parse.quote(public_key_info)

            cert = base64.b64encode(cert)
            cert = x509.make_pem(cert)

            obj = ("[p11-kit-object-v1]\n"
                   "class: certificate\n"
                   "certificate-type: x-509\n"
                   "certificate-category: authority\n"
                   "label: \"%(label)s\"\n"
                   "subject: \"%(subject)s\"\n"
                   "issuer: \"%(issuer)s\"\n"
                   "serial-number: \"%(serial_number)s\"\n"
                   "x-public-key-info: \"%(public_key_info)s\"\n" %
                   dict(label=label,
                        subject=subject,
                        issuer=issuer,
                        serial_number=serial_number,
                        public_key_info=public_key_info))
            if trusted is True:
                obj += "trusted: true\n"
            elif trusted is False:
                obj += "x-distrusted: true\n"
            obj += "%s\n\n" % cert
            f.write(obj)

            if ext_key_usage is not None and public_key_info not in has_eku:
                if not ext_key_usage:
                    ext_key_usage = {x509.EKU_PLACEHOLDER}
                try:
                    ext_key_usage = x509.encode_ext_key_usage(ext_key_usage)
                except PyAsn1Error as e:
                    root_logger.warning(
                        "Failed to encode extended key usage for \"%s\": %s",
                        nickname, e)
                    continue
                value = urllib.parse.quote(ext_key_usage)
                obj = ("[p11-kit-object-v1]\n"
                       "class: x-certificate-extension\n"
                       "label: \"ExtendedKeyUsage for %(label)s\"\n"
                       "x-public-key-info: \"%(public_key_info)s\"\n"
                       "object-id: 2.5.29.37\n"
                       "value: \"%(value)s\"\n\n" %
                       dict(label=label,
                            public_key_info=public_key_info,
                            value=value))
                f.write(obj)
                has_eku.add(public_key_info)

        f.close()

        # Add the CA to the systemwide CA trust database
        if not self.reload_systemwide_ca_store():
            return False

        return True
Example #44
0
def check_reverse_zones(ip_addresses,
                        reverse_zones,
                        options,
                        unattended,
                        search_reverse_zones=False):
    checked_reverse_zones = []

    if (not options.no_reverse and not reverse_zones
            and not options.auto_reverse):
        if unattended:
            options.no_reverse = True
        else:
            options.no_reverse = not create_reverse()

    # shortcut
    if options.no_reverse:
        return []

    # verify zones passed in options
    for rz in reverse_zones:
        # isn't the zone managed by someone else
        if not options.allow_zone_overlap:
            try:
                dnsutil.check_zone_overlap(rz)
            except ValueError as e:
                msg = "Reverse zone %s will not be used: %s" % (rz, e)
                if unattended:
                    raise ScriptError(msg)
                else:
                    root_logger.warning(msg)
                continue
        checked_reverse_zones.append(normalize_zone(rz))

    # check that there is reverse zone for every IP
    ips_missing_reverse = []
    for ip in ip_addresses:
        if search_reverse_zones and find_reverse_zone(str(ip)):
            # reverse zone is already in LDAP
            continue
        for rz in checked_reverse_zones:
            if verify_reverse_zone(rz, ip):
                # reverse zone was entered by user
                break
        else:
            ips_missing_reverse.append(ip)

    # create reverse zone for IP addresses that does not have one
    for (ip, rz) in get_auto_reverse_zones(ips_missing_reverse):
        if options.auto_reverse:
            root_logger.info("Reverse zone %s will be created" % rz)
            checked_reverse_zones.append(rz)
        elif unattended:
            root_logger.warning("Missing reverse record for IP address %s" %
                                ip)
        else:
            if ipautil.user_input(
                    "Do you want to create reverse zone for IP "
                    "%s" % ip, True):
                rz = read_reverse_zone(rz, str(ip), options.allow_zone_overlap)
                checked_reverse_zones.append(rz)

    return checked_reverse_zones
Example #45
0
    def import_files(self, files, import_keys=False, key_password=None,
                     key_nickname=None):
        """
        Import certificates and a single private key from multiple files

        The files may be in PEM and DER certificate, PKCS#7 certificate chain,
        PKCS#8 and raw private key and PKCS#12 formats.

        :param files: Names of files to import
        :param import_keys: Whether to import private keys
        :param key_password: Password to decrypt private keys
        :param key_nickname: Nickname of the private key to import from PKCS#12
            files
        """
        key_file = None
        extracted_key = None
        extracted_certs = []

        for filename in files:
            try:
                with open(filename, 'rb') as f:
                    data = f.read()
            except IOError as e:
                raise RuntimeError(
                    "Failed to open %s: %s" % (filename, e.strerror))

            # Try to parse the file as PEM file
            matches = list(re.finditer(
                r'-----BEGIN (.+?)-----(.*?)-----END \1-----', data, re.DOTALL))
            if matches:
                loaded = False
                for match in matches:
                    body = match.group()
                    label = match.group(1)
                    line = len(data[:match.start() + 1].splitlines())

                    if label in ('CERTIFICATE', 'X509 CERTIFICATE',
                                 'X.509 CERTIFICATE'):
                        try:
                            x509.load_certificate(match.group(2))
                        except ValueError as e:
                            if label != 'CERTIFICATE':
                                root_logger.warning(
                                    "Skipping certificate in %s at line %s: %s",
                                    filename, line, e)
                                continue
                        else:
                            extracted_certs.append(body)
                            loaded = True
                            continue

                    if label in ('PKCS7', 'PKCS #7 SIGNED DATA', 'CERTIFICATE'):
                        try:
                            certs = x509.pkcs7_to_pems(body)
                        except ipautil.CalledProcessError as e:
                            if label == 'CERTIFICATE':
                                root_logger.warning(
                                    "Skipping certificate in %s at line %s: %s",
                                    filename, line, e)
                            else:
                                root_logger.warning(
                                    "Skipping PKCS#7 in %s at line %s: %s",
                                    filename, line, e)
                            continue
                        else:
                            extracted_certs.extend(certs)
                            loaded = True
                            continue

                    if label in ('PRIVATE KEY', 'ENCRYPTED PRIVATE KEY',
                                 'RSA PRIVATE KEY', 'DSA PRIVATE KEY',
                                 'EC PRIVATE KEY'):
                        if not import_keys:
                            continue

                        if key_file:
                            raise RuntimeError(
                                "Can't load private key from both %s and %s" %
                                (key_file, filename))

                        args = [
                            OPENSSL, 'pkcs8',
                            '-topk8',
                            '-passout', 'file:' + self.pwd_file,
                        ]
                        if ((label != 'PRIVATE KEY' and key_password) or
                            label == 'ENCRYPTED PRIVATE KEY'):
                            key_pwdfile = ipautil.write_tmp_file(key_password)
                            args += [
                                '-passin', 'file:' + key_pwdfile.name,
                            ]
                        try:
                            result = ipautil.run(
                                args, stdin=body, capture_output=True)
                        except ipautil.CalledProcessError as e:
                            root_logger.warning(
                                "Skipping private key in %s at line %s: %s",
                                filename, line, e)
                            continue
                        else:
                            extracted_key = result.output
                            key_file = filename
                            loaded = True
                            continue
                if loaded:
                    continue
                raise RuntimeError("Failed to load %s" % filename)

            # Try to load the file as DER certificate
            try:
                x509.load_certificate(data, x509.DER)
            except ValueError:
                pass
            else:
                data = x509.make_pem(base64.b64encode(data))
                extracted_certs.append(data)
                continue

            # Try to import the file as PKCS#12 file
            if import_keys:
                try:
                    self.import_pkcs12(filename, key_password)
                except RuntimeError:
                    pass
                else:
                    if key_file:
                        raise RuntimeError(
                            "Can't load private key from both %s and %s" %
                            (key_file, filename))
                    key_file = filename

                    server_certs = self.find_server_certs()
                    if key_nickname:
                        for nickname, _trust_flags in server_certs:
                            if nickname == key_nickname:
                                break
                        else:
                            raise RuntimeError(
                                "Server certificate \"%s\" not found in %s" %
                                (key_nickname, filename))
                    else:
                        if len(server_certs) > 1:
                            raise RuntimeError(
                                "%s server certificates found in %s, "
                                "expecting only one" %
                                (len(server_certs), filename))

                    continue

            raise RuntimeError("Failed to load %s" % filename)

        if import_keys and not key_file:
            raise RuntimeError(
                "No server certificates found in %s" % (', '.join(files)))

        for cert_pem in extracted_certs:
            cert = x509.load_certificate(cert_pem)
            nickname = str(DN(cert.subject))
            data = cert.public_bytes(serialization.Encoding.DER)
            self.add_cert(data, nickname, ',,')

        if extracted_key:
            in_file = ipautil.write_tmp_file(
                    '\n'.join(extracted_certs) + '\n' + extracted_key)
            out_file = tempfile.NamedTemporaryFile()
            out_password = ipautil.ipa_generate_password()
            out_pwdfile = ipautil.write_tmp_file(out_password)
            args = [
                OPENSSL, 'pkcs12',
                '-export',
                '-in', in_file.name,
                '-out', out_file.name,
                '-passin', 'file:' + self.pwd_file,
                '-passout', 'file:' + out_pwdfile.name,
            ]
            try:
                ipautil.run(args)
            except ipautil.CalledProcessError as e:
                raise RuntimeError(
                    "No matching certificate found for private key from %s" %
                    key_file)

            self.import_pkcs12(out_file.name, out_password)
Example #46
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 #47
0
    def execute(self, **options):
        ldap = self.api.Backend.ldap2

        dn = DN(self.api.env.container_ranges, self.api.env.basedn)
        search_filter = "objectclass=ipaDomainIDRange"
        try:
            ldap.find_entries(search_filter, [], dn)
        except errors.NotFound:
            pass
        else:
            root_logger.debug("default_range: ipaDomainIDRange entry found, skip plugin")
            return False, []

        dn = DN(('cn', 'admins'), self.api.env.container_group,
                self.api.env.basedn)
        try:
            admins_entry = ldap.get_entry(dn, ['gidnumber'])
        except errors.NotFound:
            root_logger.error("default_range: No local ID range and no admins "
                              "group found. Cannot create default ID range")
            return False, []

        id_range_base_id = admins_entry['gidnumber'][0]
        id_range_name = '%s_id_range' % self.api.env.realm
        id_range_size = DEFAULT_ID_RANGE_SIZE

        range_entry = [
            dict(attr='objectclass', value='top'),
            dict(attr='objectclass', value='ipaIDrange'),
            dict(attr='objectclass', value='ipaDomainIDRange'),
            dict(attr='cn', value=id_range_name),
            dict(attr='ipabaseid', value=id_range_base_id),
            dict(attr='ipaidrangesize', value=id_range_size),
            dict(attr='iparangetype', value='ipa-local'),
        ]

        dn = DN(('cn', '%s_id_range' % self.api.env.realm),
                self.api.env.container_ranges, self.api.env.basedn)

        update = {'dn': dn, 'default': range_entry}

        # Default range entry has a hard-coded range size to 200000 which is
        # a default range size in ipa-server-install. This could cause issues
        # if user did not use a default range, but rather defined an own,
        # bigger range (option --idmax).
        # We should make our best to check if this is the case and provide
        # user with an information how to fix it.
        dn = DN(self.api.env.container_dna_posix_ids, self.api.env.basedn)
        search_filter = "objectclass=dnaSharedConfig"
        attrs = ['dnaHostname', 'dnaRemainingValues']
        try:
            (entries, _truncated) = ldap.find_entries(search_filter, attrs, dn)
        except errors.NotFound:
            root_logger.warning("default_range: no dnaSharedConfig object found. "
                                "Cannot check default range size.")
        else:
            masters = set()
            remaining_values_sum = 0
            for entry in entries:
                hostname = entry.get('dnahostname', [None])[0]
                if hostname is None or hostname in masters:
                    continue
                remaining_values = entry.get('dnaremainingvalues', [''])[0]
                try:
                    remaining_values = int(remaining_values)
                except ValueError:
                    root_logger.warning("default_range: could not parse "
                        "remaining values from '%s'", remaining_values)
                    continue
                else:
                    remaining_values_sum += remaining_values

                masters.add(hostname)

            if remaining_values_sum > DEFAULT_ID_RANGE_SIZE:
                msg = ['could not verify default ID range size',
                       'Please use the following command to set correct ID range size',
                       '  $ ipa range-mod %s --range-size=RANGE_SIZE' % id_range_name,
                       'RANGE_SIZE may be computed from --idstart and --idmax options '
                       'used during IPA server installation:',
                       '  RANGE_SIZE = (--idmax) - (--idstart) + 1'
                      ]

                root_logger.error("default_range: %s", "\n".join(msg))

        return False, [update]
Example #48
0
    def execute(self, **options):
        ldap = self.api.Backend.ldap2

        dn = DN(self.api.env.container_ranges, self.api.env.basedn)
        search_filter = "objectclass=ipaDomainIDRange"
        try:
            ldap.find_entries(search_filter, [], dn)
        except errors.NotFound:
            pass
        else:
            root_logger.debug("default_range: ipaDomainIDRange entry found, skip plugin")
            return False, []

        dn = DN(('cn', 'admins'), self.api.env.container_group,
                self.api.env.basedn)
        try:
            admins_entry = ldap.get_entry(dn, ['gidnumber'])
        except errors.NotFound:
            root_logger.error("default_range: No local ID range and no admins "
                              "group found. Cannot create default ID range")
            return False, []

        id_range_base_id = admins_entry['gidnumber'][0]
        id_range_name = '%s_id_range' % self.api.env.realm
        id_range_size = DEFAULT_ID_RANGE_SIZE

        range_entry = [
            dict(attr='objectclass', value='top'),
            dict(attr='objectclass', value='ipaIDrange'),
            dict(attr='objectclass', value='ipaDomainIDRange'),
            dict(attr='cn', value=id_range_name),
            dict(attr='ipabaseid', value=id_range_base_id),
            dict(attr='ipaidrangesize', value=id_range_size),
            dict(attr='iparangetype', value='ipa-local'),
        ]

        dn = DN(('cn', '%s_id_range' % self.api.env.realm),
                self.api.env.container_ranges, self.api.env.basedn)

        update = {'dn': dn, 'default': range_entry}

        # Default range entry has a hard-coded range size to 200000 which is
        # a default range size in ipa-server-install. This could cause issues
        # if user did not use a default range, but rather defined an own,
        # bigger range (option --idmax).
        # We should make our best to check if this is the case and provide
        # user with an information how to fix it.
        dn = DN(self.api.env.container_dna_posix_ids, self.api.env.basedn)
        search_filter = "objectclass=dnaSharedConfig"
        attrs = ['dnaHostname', 'dnaRemainingValues']
        try:
            (entries, _truncated) = ldap.find_entries(search_filter, attrs, dn)
        except errors.NotFound:
            root_logger.warning("default_range: no dnaSharedConfig object found. "
                                "Cannot check default range size.")
        else:
            masters = set()
            remaining_values_sum = 0
            for entry in entries:
                hostname = entry.get('dnahostname', [None])[0]
                if hostname is None or hostname in masters:
                    continue
                remaining_values = entry.get('dnaremainingvalues', [''])[0]
                try:
                    remaining_values = int(remaining_values)
                except ValueError:
                    root_logger.warning("default_range: could not parse "
                        "remaining values from '%s'", remaining_values)
                    continue
                else:
                    remaining_values_sum += remaining_values

                masters.add(hostname)

            if remaining_values_sum > DEFAULT_ID_RANGE_SIZE:
                msg = ['could not verify default ID range size',
                       'Please use the following command to set correct ID range size',
                       '  $ ipa range-mod %s --range-size=RANGE_SIZE' % id_range_name,
                       'RANGE_SIZE may be computed from --idstart and --idmax options '
                       'used during IPA server installation:',
                       '  RANGE_SIZE = (--idmax) - (--idstart) + 1'
                      ]

                root_logger.error("default_range: %s", "\n".join(msg))

        return False, [update]
Example #49
0
    def insert_ca_certs_into_systemwide_ca_store(self, ca_certs):
        # pylint: disable=ipa-forbidden-import
        from ipalib import x509  # FixMe: break import cycle
        from ipalib.errors import CertificateError
        # pylint: enable=ipa-forbidden-import

        new_cacert_path = paths.SYSTEMWIDE_IPA_CA_CRT

        if os.path.exists(new_cacert_path):
            try:
                os.remove(new_cacert_path)
            except OSError as e:
                root_logger.error("Could not remove %s: %s", new_cacert_path,
                                  e)
                return False

        new_cacert_path = paths.IPA_P11_KIT

        try:
            f = open(new_cacert_path, 'w')
        except IOError as e:
            root_logger.info("Failed to open %s: %s" % (new_cacert_path, e))
            return False

        f.write("# This file was created by IPA. Do not edit.\n" "\n")

        has_eku = set()
        for cert, nickname, trusted, ext_key_usage in ca_certs:
            try:
                subject = x509.get_der_subject(cert, x509.DER)
                issuer = x509.get_der_issuer(cert, x509.DER)
                serial_number = x509.get_der_serial_number(cert, x509.DER)
                public_key_info = x509.get_der_public_key_info(cert, x509.DER)
            except (PyAsn1Error, ValueError, CertificateError) as e:
                root_logger.warning("Failed to decode certificate \"%s\": %s",
                                    nickname, e)
                continue

            label = urllib.parse.quote(nickname)
            subject = urllib.parse.quote(subject)
            issuer = urllib.parse.quote(issuer)
            serial_number = urllib.parse.quote(serial_number)
            public_key_info = urllib.parse.quote(public_key_info)

            cert = base64.b64encode(cert)
            cert = x509.make_pem(cert)

            obj = ("[p11-kit-object-v1]\n"
                   "class: certificate\n"
                   "certificate-type: x-509\n"
                   "certificate-category: authority\n"
                   "label: \"%(label)s\"\n"
                   "subject: \"%(subject)s\"\n"
                   "issuer: \"%(issuer)s\"\n"
                   "serial-number: \"%(serial_number)s\"\n"
                   "x-public-key-info: \"%(public_key_info)s\"\n" %
                   dict(label=label,
                        subject=subject,
                        issuer=issuer,
                        serial_number=serial_number,
                        public_key_info=public_key_info))
            if trusted is True:
                obj += "trusted: true\n"
            elif trusted is False:
                obj += "x-distrusted: true\n"
            obj += "%s\n\n" % cert
            f.write(obj)

            if ext_key_usage is not None and public_key_info not in has_eku:
                if not ext_key_usage:
                    ext_key_usage = {x509.EKU_PLACEHOLDER}
                try:
                    ext_key_usage = x509.encode_ext_key_usage(ext_key_usage)
                except PyAsn1Error as e:
                    root_logger.warning(
                        "Failed to encode extended key usage for \"%s\": %s",
                        nickname, e)
                    continue
                value = urllib.parse.quote(ext_key_usage)
                obj = ("[p11-kit-object-v1]\n"
                       "class: x-certificate-extension\n"
                       "label: \"ExtendedKeyUsage for %(label)s\"\n"
                       "x-public-key-info: \"%(public_key_info)s\"\n"
                       "object-id: 2.5.29.37\n"
                       "value: \"%(value)s\"\n\n" %
                       dict(label=label,
                            public_key_info=public_key_info,
                            value=value))
                f.write(obj)
                has_eku.add(public_key_info)

        f.close()

        # Add the CA to the systemwide CA trust database
        if not self.reload_systemwide_ca_store():
            return False

        return True
Example #50
0
        except IOError, e:
            root_logger.info("Failed to open %s: %s" % (new_cacert_path, e))
            return False

        f.write("# This file was created by IPA. Do not edit.\n"
                "\n")

        has_eku = set()
        for cert, nickname, trusted, ext_key_usage in ca_certs:
            try:
                subject = x509.get_der_subject(cert, x509.DER)
                issuer = x509.get_der_issuer(cert, x509.DER)
                serial_number = x509.get_der_serial_number(cert, x509.DER)
                public_key_info = x509.get_der_public_key_info(cert, x509.DER)
            except (NSPRError, PyAsn1Error), e:
                root_logger.warning(
                    "Failed to decode certificate \"%s\": %s", nickname, e)
                continue

            label = urllib.quote(nickname)
            subject = urllib.quote(subject)
            issuer = urllib.quote(issuer)
            serial_number = urllib.quote(serial_number)
            public_key_info = urllib.quote(public_key_info)

            cert = base64.b64encode(cert)
            cert = x509.make_pem(cert)

            obj = ("[p11-kit-object-v1]\n"
                   "class: certificate\n"
                   "certificate-type: x-509\n"
                   "certificate-category: authority\n"
Example #51
0
    def import_files(self, files, db_password_filename, import_keys=False,
                     key_password=None, key_nickname=None):
        """
        Import certificates and a single private key from multiple files

        The files may be in PEM and DER certificate, PKCS#7 certificate chain,
        PKCS#8 and raw private key and PKCS#12 formats.

        :param files: Names of files to import
        :param db_password_filename: Name of file containing the database
            password
        :param import_keys: Whether to import private keys
        :param key_password: Password to decrypt private keys
        :param key_nickname: Nickname of the private key to import from PKCS#12
            files
        """
        key_file = None
        extracted_key = None
        extracted_certs = ''

        for filename in files:
            try:
                with open(filename, 'rb') as f:
                    data = f.read()
            except IOError as e:
                raise RuntimeError(
                    "Failed to open %s: %s" % (filename, e.strerror))

            # Try to parse the file as PEM file
            matches = list(re.finditer(
                r'-----BEGIN (.+?)-----(.*?)-----END \1-----', data, re.DOTALL))
            if matches:
                loaded = False
                for match in matches:
                    body = match.group()
                    label = match.group(1)
                    line = len(data[:match.start() + 1].splitlines())

                    if label in ('CERTIFICATE', 'X509 CERTIFICATE',
                                 'X.509 CERTIFICATE'):
                        try:
                            x509.load_certificate(match.group(2))
                        except NSPRError as e:
                            if label != 'CERTIFICATE':
                                root_logger.warning(
                                    "Skipping certificate in %s at line %s: %s",
                                    filename, line, e)
                                continue
                        else:
                            extracted_certs += body + '\n'
                            loaded = True
                            continue

                    if label in ('PKCS7', 'PKCS #7 SIGNED DATA', 'CERTIFICATE'):
                        args = [
                            paths.OPENSSL, 'pkcs7',
                            '-print_certs',
                        ]
                        try:
                            result = ipautil.run(
                                args, stdin=body, capture_output=True)
                        except ipautil.CalledProcessError as e:
                            if label == 'CERTIFICATE':
                                root_logger.warning(
                                    "Skipping certificate in %s at line %s: %s",
                                    filename, line, e)
                            else:
                                root_logger.warning(
                                    "Skipping PKCS#7 in %s at line %s: %s",
                                    filename, line, e)
                            continue
                        else:
                            extracted_certs += result.output + '\n'
                            loaded = True
                            continue

                    if label in ('PRIVATE KEY', 'ENCRYPTED PRIVATE KEY',
                                 'RSA PRIVATE KEY', 'DSA PRIVATE KEY',
                                 'EC PRIVATE KEY'):
                        if not import_keys:
                            continue

                        if key_file:
                            raise RuntimeError(
                                "Can't load private key from both %s and %s" %
                                (key_file, filename))

                        args = [
                            paths.OPENSSL, 'pkcs8',
                            '-topk8',
                            '-passout', 'file:' + db_password_filename,
                        ]
                        if ((label != 'PRIVATE KEY' and key_password) or
                            label == 'ENCRYPTED PRIVATE KEY'):
                            key_pwdfile = ipautil.write_tmp_file(key_password)
                            args += [
                                '-passin', 'file:' + key_pwdfile.name,
                            ]
                        try:
                            result = ipautil.run(
                                args, stdin=body, capture_output=True)
                        except ipautil.CalledProcessError as e:
                            root_logger.warning(
                                "Skipping private key in %s at line %s: %s",
                                filename, line, e)
                            continue
                        else:
                            extracted_key = result.output
                            key_file = filename
                            loaded = True
                            continue
                if loaded:
                    continue
                raise RuntimeError("Failed to load %s" % filename)

            # Try to load the file as DER certificate
            try:
                x509.load_certificate(data, x509.DER)
            except NSPRError:
                pass
            else:
                data = x509.make_pem(base64.b64encode(data))
                extracted_certs += data + '\n'
                continue

            # Try to import the file as PKCS#12 file
            if import_keys:
                try:
                    self.import_pkcs12(
                        filename, db_password_filename, key_password)
                except RuntimeError:
                    pass
                else:
                    if key_file:
                        raise RuntimeError(
                            "Can't load private key from both %s and %s" %
                            (key_file, filename))
                    key_file = filename

                    server_certs = self.find_server_certs()
                    if key_nickname:
                        for nickname, trust_flags in server_certs:
                            if nickname == key_nickname:
                                break
                        else:
                            raise RuntimeError(
                                "Server certificate \"%s\" not found in %s" %
                                (key_nickname, filename))
                    else:
                        if len(server_certs) > 1:
                            raise RuntimeError(
                                "%s server certificates found in %s, "
                                "expecting only one" %
                                (len(server_certs), filename))

                    continue

            raise RuntimeError("Failed to load %s" % filename)

        if import_keys and not key_file:
            raise RuntimeError(
                "No server certificates found in %s" % (', '.join(files)))

        nss_certs = x509.load_certificate_list(extracted_certs)
        nss_cert = None
        for nss_cert in nss_certs:
            nickname = str(nss_cert.subject)
            self.add_cert(nss_cert.der_data, nickname, ',,')
        del nss_certs, nss_cert

        if extracted_key:
            in_file = ipautil.write_tmp_file(extracted_certs + extracted_key)
            out_file = tempfile.NamedTemporaryFile()
            out_password = ipautil.ipa_generate_password()
            out_pwdfile = ipautil.write_tmp_file(out_password)
            args = [
                paths.OPENSSL, 'pkcs12',
                '-export',
                '-in', in_file.name,
                '-out', out_file.name,
                '-passin', 'file:' + db_password_filename,
                '-passout', 'file:' + out_pwdfile.name,
            ]
            try:
                ipautil.run(args)
            except ipautil.CalledProcessError as e:
                raise RuntimeError(
                    "No matching certificate found for private key from %s" %
                    key_file)

            self.import_pkcs12(out_file.name, db_password_filename,
                               out_password)
Example #52
0
def uninstall(installer):
    fstore = installer._fstore
    sstore = installer._sstore

    rv = 0

    # further steps assumes that temporary directories exists so rather
    # ensure they are created
    tasks.create_tmpfiles_dirs()

    print("Shutting down all IPA services")
    try:
        services.knownservices.ipa.stop()
    except Exception:
        # Fallback to direct ipactl stop only if system command fails
        try:
            run([paths.IPACTL, "stop"], raiseonerr=False)
        except Exception:
            pass

    ntpinstance.NTPInstance(fstore).uninstall()

    kra.uninstall()

    ca.uninstall()

    dns.uninstall()

    httpinstance.HTTPInstance(fstore).uninstall()
    krbinstance.KrbInstance(fstore).uninstall()
    dsinstance.DsInstance(fstore=fstore).uninstall()
    if _server_trust_ad_installed:
        adtrustinstance.ADTRUSTInstance(fstore).uninstall()
    custodiainstance.CustodiaInstance().uninstall()
    otpdinstance.OtpdInstance().uninstall()
    tasks.restore_hostname(fstore, sstore)
    fstore.restore_all_files()
    try:
        os.remove(paths.ROOT_IPA_CACHE)
    except Exception:
        pass
    try:
        os.remove(paths.ROOT_IPA_CSR)
    except Exception:
        pass

    # ipa-client-install removes /etc/ipa/default.conf

    sstore._load()

    ipaclient.install.ntpconf.restore_forced_ntpd(sstore)

    # Clean up group_exists (unused since IPA 2.2, not being set since 4.1)
    sstore.restore_state("install", "group_exists")

    services.knownservices.ipa.disable()

    # remove upgrade state file
    sysupgrade.remove_upgrade_file()

    if fstore.has_files():
        root_logger.error('Some files have not been restored, see '
                          '%s/sysrestore.index' % SYSRESTORE_DIR_PATH)
    has_state = False
    for module in IPA_MODULES:  # from installutils
        if sstore.has_state(module):
            root_logger.error('Some installation state for %s has not been '
                              'restored, see %s/sysrestore.state' %
                              (module, SYSRESTORE_DIR_PATH))
            has_state = True
            rv = 1

    if has_state:
        root_logger.error('Some installation state has not been restored.\n'
                          'This may cause re-installation to fail.\n'
                          'It should be safe to remove %s/sysrestore.state '
                          'but it may\n'
                          'mean your system hasn\'t be restored to its '
                          'pre-installation state.' % SYSRESTORE_DIR_PATH)

    # Note that this name will be wrong after the first uninstall.
    dirname = dsinstance.config_dirname(
        installutils.realm_to_serverid(api.env.realm))
    dirs = [dirname, paths.PKI_TOMCAT_ALIAS_DIR, paths.HTTPD_ALIAS_DIR]
    ids = certmonger.check_state(dirs)
    if ids:
        root_logger.error('Some certificates may still be tracked by '
                          'certmonger.\n'
                          'This will cause re-installation to fail.\n'
                          'Start the certmonger service and list the '
                          'certificates being tracked\n'
                          ' # getcert list\n'
                          'These may be untracked by executing\n'
                          ' # getcert stop-tracking -i <request_id>\n'
                          'for each id in: %s' % ', '.join(ids))

    # Remove the cert renewal lock file
    try:
        os.remove(paths.IPA_RENEWAL_LOCK)
    except OSError as e:
        if e.errno != errno.ENOENT:
            root_logger.warning("Failed to remove file %s: %s",
                                paths.IPA_RENEWAL_LOCK, e)

    print("Removing IPA client configuration")
    try:
        result = run([
            paths.IPA_CLIENT_INSTALL, "--on-master", "--unattended",
            "--uninstall"
        ],
                     raiseonerr=False,
                     redirect_output=True)
        if result.returncode not in [0, 2]:
            raise RuntimeError("Failed to configure the client")
    except Exception:
        rv = 1
        print("Uninstall of client side components failed!")

    sys.exit(rv)
Example #53
0
            f = open(new_cacert_path, 'w')
        except IOError, e:
            root_logger.info("Failed to open %s: %s" % (new_cacert_path, e))
            return False

        f.write("# This file was created by IPA. Do not edit.\n" "\n")

        has_eku = set()
        for cert, nickname, trusted, ext_key_usage in ca_certs:
            try:
                subject = x509.get_der_subject(cert, x509.DER)
                issuer = x509.get_der_issuer(cert, x509.DER)
                serial_number = x509.get_der_serial_number(cert, x509.DER)
                public_key_info = x509.get_der_public_key_info(cert, x509.DER)
            except (NSPRError, PyAsn1Error), e:
                root_logger.warning("Failed to decode certificate \"%s\": %s",
                                    nickname, e)
                continue

            label = urllib.quote(nickname)
            subject = urllib.quote(subject)
            issuer = urllib.quote(issuer)
            serial_number = urllib.quote(serial_number)
            public_key_info = urllib.quote(public_key_info)

            cert = base64.b64encode(cert)
            cert = x509.make_pem(cert)

            obj = ("[p11-kit-object-v1]\n"
                   "class: certificate\n"
                   "certificate-type: x-509\n"
                   "certificate-category: authority\n"
Example #54
0
def install_check(standalone, api, replica, options, hostname):
    global ip_addresses
    global reverse_zones
    fstore = sysrestore.FileStore(paths.SYSRESTORE)

    if not ipautil.file_exists(paths.IPA_DNS_INSTALL):
        raise RuntimeError("Integrated DNS requires '%s' package" %
                           constants.IPA_DNS_PACKAGE_NAME)

    # when installing first DNS instance we need to check zone overlap
    if replica or standalone:
        already_enabled = api.Command.dns_is_enabled()['result']
    else:
        already_enabled = False

    if not already_enabled:
        domain = dnsutil.DNSName(util.normalize_zone(api.env.domain))
        print("Checking DNS domain %s, please wait ..." % domain)
        try:
            dnsutil.check_zone_overlap(domain, raise_on_error=False)
        except ValueError as e:
            if options.force or options.allow_zone_overlap:
                root_logger.warning("%s Please make sure that the domain is "
                                    "properly delegated to this IPA server.",
                                    e.message)
            else:
                raise e

    for reverse_zone in options.reverse_zones:
        try:
            dnsutil.check_zone_overlap(reverse_zone)
        except ValueError as e:
            if options.force or options.allow_zone_overlap:
                root_logger.warning(e.message)
            else:
                raise e

    if standalone:
        print("==============================================================================")
        print("This program will setup DNS for the FreeIPA Server.")
        print("")
        print("This includes:")
        print("  * Configure DNS (bind)")
        print("  * Configure SoftHSM (required by DNSSEC)")
        print("  * Configure ipa-dnskeysyncd (required by DNSSEC)")
        if options.dnssec_master:
            print("  * Configure ipa-ods-exporter (required by DNSSEC key master)")
            print("  * Configure OpenDNSSEC (required by DNSSEC key master)")
            print("  * Generate DNSSEC master key (required by DNSSEC key master)")
        elif options.disable_dnssec_master:
            print("  * Unconfigure ipa-ods-exporter")
            print("  * Unconfigure OpenDNSSEC")
            print("")
            print("No new zones will be signed without DNSSEC key master IPA server.")
            print("")
            print(("Please copy file from %s after uninstallation. This file is needed "
                   "on new DNSSEC key " % paths.IPA_KASP_DB_BACKUP))
            print("master server")
        print("")
        print("NOTE: DNSSEC zone signing is not enabled by default")
        print("")
        if options.dnssec_master:
            print("Plan carefully, replacing DNSSEC key master is not recommended")
            print("")
        print("")
        print("To accept the default shown in brackets, press the Enter key.")
        print("")

    if (options.dnssec_master and not options.unattended and not
        ipautil.user_input(
            "Do you want to setup this IPA server as DNSSEC key master?",
            False)):
        sys.exit("Aborted")
    elif (options.disable_dnssec_master and not options.unattended and not
          ipautil.user_input(
            "Do you want to disable current DNSSEC key master?",
            False)):
        sys.exit("Aborted")

    if options.disable_dnssec_master:
        _is_master()

    if options.disable_dnssec_master or options.dnssec_master:
        dnssec_zones = _find_dnssec_enabled_zones(api.Backend.ldap2)

    if options.disable_dnssec_master:
        if dnssec_zones and not options.force:
            raise RuntimeError(
                "Cannot disable DNSSEC key master, DNSSEC signing is still "
                "enabled for following zone(s):\n"
                "%s\n"
                "It is possible to move DNSSEC key master role to a different "
                "server by using --force option to skip this check.\n\n"
                "WARNING: You have to immediatelly copy kasp.db file to a new "
                "server and run command 'ipa-dns-install --dnssec-master "
                "--kasp-db'.\n"
                "Your DNS zones will become unavailable if you "
                "do not reinstall the DNSSEC key master role immediatelly." %
                ", ".join([str(zone) for zone in dnssec_zones]))

    elif options.dnssec_master:
        ods = opendnssecinstance.OpenDNSSECInstance(fstore)
        ods.realm = api.env.realm
        dnssec_masters = ods.get_masters()
        # we can reinstall current server if it is dnssec master
        if dnssec_masters and api.env.host not in dnssec_masters:
            print("DNSSEC key master(s):", u','.join(dnssec_masters))
            raise ScriptError(
                "Only one DNSSEC key master is supported in current version.")

        if options.kasp_db_file:
            dnskeysyncd = services.service('ipa-dnskeysyncd')

            if not dnskeysyncd.is_installed():
                raise RuntimeError("ipa-dnskeysyncd is not configured on this "
                                   "server, you cannot reuse OpenDNSSEC "
                                   "database (kasp.db file)")

            # check if replica can be the DNSSEC master
            cmd = [paths.IPA_DNSKEYSYNCD_REPLICA]
            environment = {
                "SOFTHSM2_CONF": paths.DNSSEC_SOFTHSM2_CONF,
            }

            # stop dnskeysyncd before test
            dnskeysyncd_running = dnskeysyncd.is_running()
            dnskeysyncd.stop()
            try:
                ipautil.run(cmd, env=environment,
                            runas=constants.ODS_USER,
                            suplementary_groups=[constants.NAMED_GROUP])
            except CalledProcessError as e:
                root_logger.debug("%s", e)
                raise RuntimeError("This IPA server cannot be promoted to "
                                   "DNSSEC master role because some keys were "
                                   "not replicated from the original "
                                   "DNSSEC master server")
            finally:
                if dnskeysyncd_running:
                    dnskeysyncd.start()
        elif dnssec_zones and not options.force:
            # some zones have --dnssec=true, make sure a user really want to
            # install new database
            raise RuntimeError(
                "DNSSEC signing is already enabled for following zone(s): %s\n"
                "Installation cannot continue without the OpenDNSSEC database "
                "file from the original DNSSEC master server.\n"
                "Please use option --kasp-db to specify location "
                "of the kasp.db file copied from the original "
                "DNSSEC master server.\n"
                "WARNING: Zones will become unavailable if you do not provide "
                "the original kasp.db file." %
                ", ".join([str(zone) for zone in dnssec_zones]))

    ip_addresses = get_server_ip_address(hostname, options.unattended,
                                         True, options.ip_addresses)

    util.network_ip_address_warning(ip_addresses)
    util.broadcast_ip_address_warning(ip_addresses)

    if not options.forward_policy:
        # user did not specify policy, derive it: default is 'first' but
        # if any of local IP addresses belongs to private ranges use 'only'
        options.forward_policy = 'first'
        for ip in ip_addresses:
            if dnsutil.inside_auto_empty_zone(dnsutil.DNSName(ip.reverse_dns)):
                options.forward_policy = 'only'
                root_logger.debug('IP address %s belongs to a private range, '
                                  'using forward policy only', ip)
                break

    if options.no_forwarders:
        options.forwarders = []
    elif options.forwarders or options.auto_forwarders:
        if not options.forwarders:
            options.forwarders = []
        if options.auto_forwarders:
            options.forwarders += resolver.get_default_resolver().nameservers
    elif standalone or not replica:
        options.forwarders = read_dns_forwarders()

    # test DNSSEC forwarders
    if options.forwarders:
        if (not bindinstance.check_forwarders(options.forwarders,
                                              root_logger)
                and not options.no_dnssec_validation):
            options.no_dnssec_validation = True
            print("WARNING: DNSSEC validation will be disabled")

    root_logger.debug("will use DNS forwarders: %s\n", options.forwarders)

    if not standalone:
        search_reverse_zones = False
    else:
        search_reverse_zones = True

    if not standalone and replica:
        reverse_zones_unattended_check = True
    else:
        reverse_zones_unattended_check = options.unattended

    reverse_zones = bindinstance.check_reverse_zones(
        ip_addresses, options.reverse_zones, options,
        reverse_zones_unattended_check, search_reverse_zones
    )

    if reverse_zones:
        print("Using reverse zone(s) %s" % ', '.join(reverse_zones))
Example #55
0
def uninstall(installer):
    fstore = installer._fstore
    sstore = installer._sstore

    rv = 0

    print("Shutting down all IPA services")
    try:
        run([paths.IPACTL, "stop"], raiseonerr=False)
    except Exception:
        pass

    ntpinstance.NTPInstance(fstore).uninstall()

    kra.uninstall(False)

    ca.uninstall()

    dns.uninstall()

    httpinstance.HTTPInstance(fstore).uninstall()
    krbinstance.KrbInstance(fstore).uninstall()
    dsinstance.DsInstance(fstore=fstore).uninstall()
    if _server_trust_ad_installed:
        adtrustinstance.ADTRUSTInstance(fstore).uninstall()
    custodiainstance.CustodiaInstance().uninstall()
    memcacheinstance.MemcacheInstance().uninstall()
    otpdinstance.OtpdInstance().uninstall()
    tasks.restore_hostname(fstore, sstore)
    fstore.restore_all_files()
    try:
        os.remove(paths.ROOT_IPA_CACHE)
    except Exception:
        pass
    try:
        os.remove(paths.ROOT_IPA_CSR)
    except Exception:
        pass

    # ipa-client-install removes /etc/ipa/default.conf

    sstore._load()

    ipaclient.install.ntpconf.restore_forced_ntpd(sstore)

    # Clean up group_exists (unused since IPA 2.2, not being set since 4.1)
    sstore.restore_state("install", "group_exists")

    services.knownservices.ipa.disable()

    # remove upgrade state file
    sysupgrade.remove_upgrade_file()

    if fstore.has_files():
        root_logger.error('Some files have not been restored, see '
                          '%s/sysrestore.index' % SYSRESTORE_DIR_PATH)
    has_state = False
    for module in IPA_MODULES:  # from installutils
        if sstore.has_state(module):
            root_logger.error('Some installation state for %s has not been '
                              'restored, see %s/sysrestore.state' %
                              (module, SYSRESTORE_DIR_PATH))
            has_state = True
            rv = 1

    if has_state:
        root_logger.error('Some installation state has not been restored.\n'
                          'This may cause re-installation to fail.\n'
                          'It should be safe to remove %s/sysrestore.state '
                          'but it may\n'
                          'mean your system hasn\'t be restored to its '
                          'pre-installation state.' % SYSRESTORE_DIR_PATH)

    # Note that this name will be wrong after the first uninstall.
    dirname = dsinstance.config_dirname(
        installutils.realm_to_serverid(api.env.realm))
    dirs = [dirname, paths.PKI_TOMCAT_ALIAS_DIR, certs.NSS_DIR]
    ids = certmonger.check_state(dirs)
    if ids:
        root_logger.error('Some certificates may still be tracked by '
                          'certmonger.\n'
                          'This will cause re-installation to fail.\n'
                          'Start the certmonger service and list the '
                          'certificates being tracked\n'
                          ' # getcert list\n'
                          'These may be untracked by executing\n'
                          ' # getcert stop-tracking -i <request_id>\n'
                          'for each id in: %s' % ', '.join(ids))

    # Remove the cert renewal lock file
    try:
        os.remove(paths.IPA_RENEWAL_LOCK)
    except OSError as e:
        if e.errno != errno.ENOENT:
            root_logger.warning("Failed to remove file %s: %s",
                                paths.IPA_RENEWAL_LOCK, e)

    print("Removing IPA client configuration")
    try:
        result = run([paths.IPA_CLIENT_INSTALL, "--on-master",
                      "--unattended", "--uninstall"],
                     raiseonerr=False, redirect_output=True)
        if result.returncode not in [0, 2]:
            raise RuntimeError("Failed to configure the client")
    except Exception:
        rv = 1
        print("Uninstall of client side components failed!")

    sys.exit(rv)