Beispiel #1
0
class DogtagInstallInterface(service.ServiceInstallInterface):
    """
    Interface common to all Dogtag-based service installers
    """

    ca_file = knob(
        str,
        None,
        description="location of CA PKCS#12 file",
        cli_metavar='FILE',
    )
    ca_file = prepare_only(ca_file)
    ca_file = replica_install_only(ca_file)

    pki_config_override = knob(
        str,
        None,
        cli_names='--pki-config-override',
        description="Path to ini file with config overrides.",
    )

    @pki_config_override.validator
    def pki_config_override(self, value):
        if value is not None:
            PKIIniLoader.verify_pki_config_override(value)
Beispiel #2
0
class DogtagInstallInterface(service.ServiceInstallInterface):
    """
    Interface common to all Dogtag-based service installers
    """

    ca_file = knob(
        str,
        None,
        description="location of CA PKCS#12 file",
        cli_metavar='FILE',
    )
    ca_file = prepare_only(ca_file)
    ca_file = replica_install_only(ca_file)
Beispiel #3
0
class ServerCertificateInstallInterface(service.ServiceInstallInterface):
    description = "SSL certificate"

    dirsrv_cert_files = knob(
        # pylint: disable=invalid-sequence-index
        typing.List[str],
        None,
        description=("File containing the Directory Server SSL certificate "
                     "and private key"),
        cli_names='--dirsrv-cert-file',
        cli_deprecated_names='--dirsrv_pkcs12',
        cli_metavar='FILE',
    )
    dirsrv_cert_files = prepare_only(dirsrv_cert_files)

    http_cert_files = knob(
        # pylint: disable=invalid-sequence-index
        typing.List[str],
        None,
        description=("File containing the Apache Server SSL certificate and "
                     "private key"),
        cli_names='--http-cert-file',
        cli_deprecated_names='--http_pkcs12',
        cli_metavar='FILE',
    )
    http_cert_files = prepare_only(http_cert_files)

    pkinit_cert_files = knob(
        # pylint: disable=invalid-sequence-index
        typing.List[str],
        None,
        description=("File containing the Kerberos KDC SSL certificate and "
                     "private key"),
        cli_names='--pkinit-cert-file',
        cli_deprecated_names='--pkinit_pkcs12',
        cli_metavar='FILE',
    )
    pkinit_cert_files = prepare_only(pkinit_cert_files)

    dirsrv_pin = knob(
        str,
        None,
        sensitive=True,
        description="The password to unlock the Directory Server private key",
        cli_deprecated_names='--dirsrv_pin',
        cli_metavar='PIN',
    )
    dirsrv_pin = prepare_only(dirsrv_pin)

    http_pin = knob(
        str,
        None,
        sensitive=True,
        description="The password to unlock the Apache Server private key",
        cli_deprecated_names='--http_pin',
        cli_metavar='PIN',
    )
    http_pin = prepare_only(http_pin)

    pkinit_pin = knob(
        str,
        None,
        sensitive=True,
        description="The password to unlock the Kerberos KDC private key",
        cli_deprecated_names='--pkinit_pin',
        cli_metavar='PIN',
    )
    pkinit_pin = prepare_only(pkinit_pin)

    dirsrv_cert_name = knob(
        str,
        None,
        description="Name of the Directory Server SSL certificate to install",
        cli_metavar='NAME',
    )
    dirsrv_cert_name = prepare_only(dirsrv_cert_name)

    http_cert_name = knob(
        str,
        None,
        description="Name of the Apache Server SSL certificate to install",
        cli_metavar='NAME',
    )
    http_cert_name = prepare_only(http_cert_name)

    pkinit_cert_name = knob(
        str,
        None,
        description="Name of the Kerberos KDC SSL certificate to install",
        cli_metavar='NAME',
    )
    pkinit_cert_name = prepare_only(pkinit_cert_name)
Beispiel #4
0
class ServerInstallInterface(
        ServerCertificateInstallInterface, client.ClientInstallInterface,
        ca.CAInstallInterface, kra.KRAInstallInterface,
        dns.DNSInstallInterface, adtrust.ADTrustInstallInterface,
        conncheck.ConnCheckInterface, ServerUninstallInterface):
    """
    Interface of server installers

    Knobs defined here will be available in:
    * ipa-server-install
    * ipa-replica-prepare
    * ipa-replica-install
    """
    description = "Server"

    kinit_attempts = 1
    fixed_primary = True
    permit = False
    enable_dns_updates = False
    no_krb5_offline_passwords = False
    preserve_sssd = False
    no_sssd = False

    domain_name = client.ClientInstallInterface.domain_name
    domain_name = extend_knob(
        domain_name,
        # pylint: disable=no-member
        cli_names=list(domain_name.cli_names) + ['-n'],
    )

    servers = extend_knob(
        client.ClientInstallInterface.servers,
        description="fully qualified name of IPA server to enroll to",
    )
    servers = enroll_only(servers)

    realm_name = client.ClientInstallInterface.realm_name
    realm_name = extend_knob(
        realm_name,
        cli_names=list(realm_name.cli_names) + ['-r'],
    )

    host_name = extend_knob(
        client.ClientInstallInterface.host_name,
        description="fully qualified name of this host",
    )

    ca_cert_files = extend_knob(
        client.ClientInstallInterface.ca_cert_files,
        description="File containing CA certificates for the service "
        "certificate files",
        cli_deprecated_names='--root-ca-file',
    )
    ca_cert_files = prepare_only(ca_cert_files)

    dm_password = extend_knob(
        client.ClientInstallInterface.dm_password,
        description="Directory Manager password",
    )

    ip_addresses = extend_knob(
        client.ClientInstallInterface.ip_addresses,
        description="Server IP Address. This option can be used multiple "
        "times",
    )

    principal = client.ClientInstallInterface.principal
    principal = extend_knob(
        principal,
        description="User Principal allowed to promote replicas and join IPA "
        "realm",
        cli_names=list(principal.cli_names) + ['-P'],
    )
    principal = replica_install_only(principal)

    admin_password = extend_knob(
        client.ClientInstallInterface.admin_password, )

    master_password = knob(
        str,
        None,
        sensitive=True,
        deprecated=True,
        description="kerberos master password (normally autogenerated)",
    )
    master_password = master_install_only(master_password)

    domain_level = knob(
        int,
        constants.MAX_DOMAIN_LEVEL,
        description="IPA domain level",
        deprecated=True,
    )
    domain_level = master_install_only(domain_level)

    @domain_level.validator
    def domain_level(self, value):
        # Check that Domain Level is within the allowed range
        if value < constants.MIN_DOMAIN_LEVEL:
            raise ValueError("Domain Level cannot be lower than {0}".format(
                constants.MIN_DOMAIN_LEVEL))
        elif value > constants.MAX_DOMAIN_LEVEL:
            raise ValueError("Domain Level cannot be higher than {0}".format(
                constants.MAX_DOMAIN_LEVEL))

    setup_adtrust = knob(None, description="configure AD trust capability")
    setup_ca = knob(
        None,
        description="configure a dogtag CA",
    )
    setup_ca = enroll_only(setup_ca)

    setup_kra = knob(
        None,
        description="configure a dogtag KRA",
    )
    setup_kra = enroll_only(setup_kra)

    setup_dns = knob(
        None,
        description="configure bind with our zone",
    )
    setup_dns = enroll_only(setup_dns)

    idstart = knob(
        int,
        random.randint(1, 10000) * 200000,
        description="The starting value for the IDs range (default random)",
    )
    idstart = master_install_only(idstart)

    idmax = knob(
        int,
        description=("The max value for the IDs range (default: "
                     "idstart+199999)"),
    )
    idmax = master_install_only(idmax)

    @idmax.default_getter
    def idmax(self):
        return self.idstart + 200000 - 1

    no_hbac_allow = knob(
        None,
        description="Don't install allow_all HBAC rule",
        cli_deprecated_names='--no_hbac_allow',
    )
    no_hbac_allow = master_install_only(no_hbac_allow)

    no_pkinit = knob(
        None,
        description="disables pkinit setup steps",
    )
    no_pkinit = prepare_only(no_pkinit)

    no_ui_redirect = knob(
        None,
        description="Do not automatically redirect to the Web UI",
    )
    no_ui_redirect = enroll_only(no_ui_redirect)

    dirsrv_config_file = knob(
        str,
        None,
        description="The path to LDIF file that will be used to modify "
        "configuration of dse.ldif during installation of the "
        "directory server instance",
        cli_metavar='FILE',
    )
    dirsrv_config_file = enroll_only(dirsrv_config_file)

    @dirsrv_config_file.validator
    def dirsrv_config_file(self, value):
        if not os.path.exists(value):
            raise ValueError("File %s does not exist." % value)

    def _is_promote(self):
        """
        :returns: True if domain level options correspond to domain level > 0
        """
        raise NotImplementedError()

    def __init__(self, **kwargs):
        super(ServerInstallInterface, self).__init__(**kwargs)

        # pkinit is not supported on DL0, don't allow related options
        if not self._is_promote():
            if (self.no_pkinit or self.pkinit_cert_files is not None
                    or self.pkinit_pin is not None):
                raise RuntimeError(
                    "pkinit on domain level 0 is not supported. Please "
                    "don't use any pkinit-related options.")
            self.no_pkinit = True

        # If any of the key file options are selected, all are required.
        cert_file_req = (self.dirsrv_cert_files, self.http_cert_files)
        cert_file_opt = (self.pkinit_cert_files, )
        if not self.no_pkinit:
            cert_file_req += cert_file_opt
        if self.no_pkinit and self.pkinit_cert_files:
            raise RuntimeError(
                "--no-pkinit and --pkinit-cert-file cannot be specified "
                "together")
        if any(cert_file_req + cert_file_opt) and not all(cert_file_req):
            raise RuntimeError(
                "--dirsrv-cert-file, --http-cert-file, and --pkinit-cert-file "
                "or --no-pkinit are required if any key file options are used."
            )

        if not self.interactive:
            if self.dirsrv_cert_files and self.dirsrv_pin is None:
                raise RuntimeError(
                    "You must specify --dirsrv-pin with --dirsrv-cert-file")
            if self.http_cert_files and self.http_pin is None:
                raise RuntimeError(
                    "You must specify --http-pin with --http-cert-file")
            if self.pkinit_cert_files and self.pkinit_pin is None:
                raise RuntimeError(
                    "You must specify --pkinit-pin with --pkinit-cert-file")

        if not self.setup_dns:
            if self.forwarders:
                raise RuntimeError(
                    "You cannot specify a --forwarder option without the "
                    "--setup-dns option")
            if self.auto_forwarders:
                raise RuntimeError(
                    "You cannot specify a --auto-forwarders option without "
                    "the --setup-dns option")
            if self.no_forwarders:
                raise RuntimeError(
                    "You cannot specify a --no-forwarders option without the "
                    "--setup-dns option")
            if self.forward_policy:
                raise RuntimeError(
                    "You cannot specify a --forward-policy option without the "
                    "--setup-dns option")
            if self.reverse_zones:
                raise RuntimeError(
                    "You cannot specify a --reverse-zone option without the "
                    "--setup-dns option")
            if self.auto_reverse:
                raise RuntimeError(
                    "You cannot specify a --auto-reverse option without the "
                    "--setup-dns option")
            if self.no_reverse:
                raise RuntimeError(
                    "You cannot specify a --no-reverse option without the "
                    "--setup-dns option")
            if self.no_dnssec_validation:
                raise RuntimeError(
                    "You cannot specify a --no-dnssec-validation option "
                    "without the --setup-dns option")
        elif self.forwarders and self.no_forwarders:
            raise RuntimeError(
                "You cannot specify a --forwarder option together with "
                "--no-forwarders")
        elif self.auto_forwarders and self.no_forwarders:
            raise RuntimeError(
                "You cannot specify a --auto-forwarders option together with "
                "--no-forwarders")
        elif self.reverse_zones and self.no_reverse:
            raise RuntimeError(
                "You cannot specify a --reverse-zone option together with "
                "--no-reverse")
        elif self.auto_reverse and self.no_reverse:
            raise RuntimeError(
                "You cannot specify a --auto-reverse option together with "
                "--no-reverse")

        if not self.setup_adtrust:
            if self.add_agents:
                raise RuntimeError(
                    "You cannot specify an --add-agents option without the "
                    "--setup-adtrust option")

            if self.enable_compat:
                raise RuntimeError(
                    "You cannot specify an --enable-compat option without the "
                    "--setup-adtrust option")

            if self.netbios_name:
                raise RuntimeError(
                    "You cannot specify a --netbios-name option without the "
                    "--setup-adtrust option")

            if self.no_msdcs:
                raise RuntimeError(
                    "You cannot specify a --no-msdcs option without the "
                    "--setup-adtrust option")

        if not hasattr(self, 'replica_file'):
            if self.external_cert_files and self.dirsrv_cert_files:
                raise RuntimeError(
                    "Service certificate file options cannot be used with the "
                    "external CA options.")

            if self.external_ca_type and not self.external_ca:
                raise RuntimeError(
                    "You cannot specify --external-ca-type without "
                    "--external-ca")

            if self.external_ca_profile and not self.external_ca:
                raise RuntimeError(
                    "You cannot specify --external-ca-profile without "
                    "--external-ca")

            if self.uninstalling:
                if (self.realm_name or self.admin_password
                        or self.master_password):
                    raise RuntimeError(
                        "In uninstall mode, -a, -r and -P options are not "
                        "allowed")
            elif not self.interactive:
                if (not self.realm_name or not self.dm_password
                        or not self.admin_password):
                    raise RuntimeError(
                        "In unattended mode you need to provide at least -r, "
                        "-p and -a options")
                if self.setup_dns:
                    if (not self.forwarders and not self.no_forwarders
                            and not self.auto_forwarders):
                        raise RuntimeError(
                            "You must specify at least one of --forwarder, "
                            "--auto-forwarders, or --no-forwarders options")

            any_ignore_option_true = any(
                [self.ignore_topology_disconnect, self.ignore_last_of_role])
            if any_ignore_option_true and not self.uninstalling:
                raise RuntimeError(
                    "'--ignore-topology-disconnect/--ignore-last-of-role' "
                    "options can be used only during uninstallation")

            if self.idmax < self.idstart:
                raise RuntimeError(
                    "idmax (%s) cannot be smaller than idstart (%s)" %
                    (self.idmax, self.idstart))
        else:
            # replica installers
            if self.replica_file is None:
                if self.servers and not self.domain_name:
                    raise RuntimeError(
                        "The --server option cannot be used without providing "
                        "domain via the --domain option")

            else:
                if not os.path.isfile(self.replica_file):
                    raise RuntimeError("Replica file %s does not exist" %
                                       self.replica_file)

                if any(cert_file_req + cert_file_opt):
                    raise RuntimeError(
                        "You cannot specify any of --dirsrv-cert-file, "
                        "--http-cert-file, or --pkinit-cert-file together "
                        "with replica file")

                CLIKnob = collections.namedtuple('CLIKnob', ('value', 'name'))

                conflicting_knobs = (
                    CLIKnob(self.realm_name, '--realm'),
                    CLIKnob(self.domain_name, '--domain'),
                    CLIKnob(self.host_name, '--hostname'),
                    CLIKnob(self.servers, '--server'),
                    CLIKnob(self.principal, '--principal'),
                )

                if any([k.value is not None for k in conflicting_knobs]):
                    conflicting_knob_names = [
                        knob.name for knob in conflicting_knobs
                        if knob.value is not None
                    ]

                    raise RuntimeError(
                        "You cannot specify '{0}' option(s) with replica file."
                        .format(", ".join(conflicting_knob_names)))

            if self.setup_dns:
                if (not self.forwarders and not self.no_forwarders
                        and not self.auto_forwarders):
                    raise RuntimeError(
                        "You must specify at least one of --forwarder, "
                        "--auto-forwarders, or --no-forwarders options")
Beispiel #5
0
class DNSInstallInterface(hostname.HostNameInstallInterface):
    """
    Interface of the DNS installer

    Knobs defined here will be available in:
    * ipa-server-install
    * ipa-replica-prepare
    * ipa-replica-install
    * ipa-dns-install
    """
    description = "DNS"

    allow_zone_overlap = knob(
        None,
        description="Create DNS zone even if it already exists",
    )
    allow_zone_overlap = prepare_only(allow_zone_overlap)

    reverse_zones = knob(
        # pylint: disable=invalid-sequence-index
        typing.List[str],
        [],
        description=("The reverse DNS zone to use. This option can be used "
                     "multiple times"),
        cli_names='--reverse-zone',
        cli_metavar='REVERSE_ZONE',
    )
    reverse_zones = prepare_only(reverse_zones)

    @reverse_zones.validator
    def reverse_zones(self, values):
        if not self.allow_zone_overlap:
            for zone in values:
                check_zone_overlap(zone)

    no_reverse = knob(
        None,
        description="Do not create new reverse DNS zone",
    )
    no_reverse = prepare_only(no_reverse)

    auto_reverse = knob(
        None,
        description="Create necessary reverse zones",
    )
    auto_reverse = prepare_only(auto_reverse)

    zonemgr = knob(
        str,
        None,
        description=("DNS zone manager e-mail address. Defaults to "
                     "hostmaster@DOMAIN"),
    )
    zonemgr = prepare_only(zonemgr)

    @zonemgr.validator
    def zonemgr(self, value):
        # validate the value first
        try:
            # IDNA support requires unicode
            encoding = getattr(sys.stdin, 'encoding', None)
            if encoding is None:
                encoding = 'utf-8'

            # value is string in py2 and py3
            if not isinstance(value, unicode):
                value = value.decode(encoding)

            bindinstance.validate_zonemgr_str(value)
        except ValueError as e:
            # FIXME we can do this in better way
            # https://fedorahosted.org/freeipa/ticket/4804
            # decode to proper stderr encoding
            stderr_encoding = getattr(sys.stderr, 'encoding', None)
            if stderr_encoding is None:
                stderr_encoding = 'utf-8'
            error = unicode(e).encode(stderr_encoding)
            raise ValueError(error)

    forwarders = knob(
        # pylint: disable=invalid-sequence-index
        typing.List[ipautil.CheckedIPAddressLoopback],
        None,
        description=("Add a DNS forwarder. This option can be used multiple "
                     "times"),
        cli_names='--forwarder',
    )
    forwarders = enroll_only(forwarders)

    no_forwarders = knob(
        None,
        description="Do not add any DNS forwarders, use root servers instead",
    )
    no_forwarders = enroll_only(no_forwarders)

    auto_forwarders = knob(
        None,
        description="Use DNS forwarders configured in /etc/resolv.conf",
    )
    auto_forwarders = enroll_only(auto_forwarders)

    forward_policy = knob(
        DNSForwardPolicy,
        None,
        description=("DNS forwarding policy for global forwarders"),
    )
    forward_policy = enroll_only(forward_policy)

    no_dnssec_validation = knob(
        None,
        description="Disable DNSSEC validation",
    )
    no_dnssec_validation = enroll_only(no_dnssec_validation)

    dnssec_master = False
    disable_dnssec_master = False
    kasp_db_file = None
    force = False
Beispiel #6
0
class ServerInstallInterface(client.ClientInstallInterface,
                             ca.CAInstallInterface, kra.KRAInstallInterface,
                             dns.DNSInstallInterface,
                             conncheck.ConnCheckInterface):
    """
    Interface of server installers

    Knobs defined here will be available in:
    * ipa-server-install
    * ipa-replica-prepare
    * ipa-replica-install
    """

    force_join = False
    kinit_attempts = 1
    fixed_primary = True
    ntp_servers = None
    force_ntpd = False
    permit = False
    enable_dns_updates = False
    no_krb5_offline_passwords = False
    preserve_sssd = False

    domain_name = knob(
        bases=client.ClientInstallInterface.domain_name,
        # pylint: disable=no-member
        cli_names=(list(client.ClientInstallInterface.domain_name.cli_names) +
                   ['-n']),
    )

    servers = knob(
        bases=client.ClientInstallInterface.servers,
        description="fully qualified name of IPA server to enroll to",
    )
    servers = enroll_only(servers)

    realm_name = knob(
        bases=client.ClientInstallInterface.realm_name,
        cli_names=(list(client.ClientInstallInterface.realm_name.cli_names) +
                   ['-r']),
    )

    host_name = knob(
        bases=client.ClientInstallInterface.host_name,
        description="fully qualified name of this host",
    )

    ca_cert_files = knob(
        bases=client.ClientInstallInterface.ca_cert_files,
        description="File containing CA certificates for the service "
        "certificate files",
        cli_deprecated_names='--root-ca-file',
    )
    ca_cert_files = prepare_only(ca_cert_files)

    dm_password = knob(
        bases=client.ClientInstallInterface.dm_password,
        description="Directory Manager password",
    )

    ip_addresses = knob(
        bases=client.ClientInstallInterface.ip_addresses,
        description="Server IP Address. This option can be used multiple "
        "times",
    )

    principal = knob(
        bases=client.ClientInstallInterface.principal,
        description="User Principal allowed to promote replicas and join IPA "
        "realm",
        cli_names=(list(client.ClientInstallInterface.principal.cli_names) +
                   ['-P']),
    )
    principal = replica_install_only(principal)

    master_password = knob(
        str,
        None,
        sensitive=True,
        deprecated=True,
        description="kerberos master password (normally autogenerated)",
    )
    master_password = master_install_only(master_password)

    domain_level = knob(
        int,
        constants.MAX_DOMAIN_LEVEL,
        description="IPA domain level",
        deprecated=True,
    )
    domain_level = master_install_only(domain_level)

    @domain_level.validator
    def domain_level(self, value):
        # Check that Domain Level is within the allowed range
        if value < constants.MIN_DOMAIN_LEVEL:
            raise ValueError("Domain Level cannot be lower than {0}".format(
                constants.MIN_DOMAIN_LEVEL))
        elif value > constants.MAX_DOMAIN_LEVEL:
            raise ValueError("Domain Level cannot be higher than {0}".format(
                constants.MAX_DOMAIN_LEVEL))

    setup_ca = knob(
        None,
        description="configure a dogtag CA",
    )
    setup_ca = enroll_only(setup_ca)

    setup_kra = knob(
        None,
        description="configure a dogtag KRA",
    )
    setup_kra = enroll_only(setup_kra)

    setup_dns = knob(
        None,
        description="configure bind with our zone",
    )
    setup_dns = enroll_only(setup_dns)

    idstart = knob(
        int,
        random.randint(1, 10000) * 200000,
        description="The starting value for the IDs range (default random)",
    )
    idstart = master_install_only(idstart)

    idmax = knob(
        int,
        description=("The max value for the IDs range (default: "
                     "idstart+199999)"),
    )
    idmax = master_install_only(idmax)

    @idmax.default_getter
    def idmax(self):
        return self.idstart + 200000 - 1

    no_hbac_allow = knob(
        None,
        description="Don't install allow_all HBAC rule",
        cli_deprecated_names='--no_hbac_allow',
    )
    no_hbac_allow = master_install_only(no_hbac_allow)

    ignore_topology_disconnect = knob(
        None,
        description="do not check whether server uninstall disconnects the "
        "topology (domain level 1+)",
    )
    ignore_topology_disconnect = master_install_only(
        ignore_topology_disconnect)

    ignore_last_of_role = knob(
        None,
        description="do not check whether server uninstall removes last "
        "CA/DNS server or DNSSec master (domain level 1+)",
    )
    ignore_last_of_role = master_install_only(ignore_last_of_role)

    no_pkinit = knob(
        None,
        description="disables pkinit setup steps",
    )
    no_pkinit = prepare_only(no_pkinit)

    no_ui_redirect = knob(
        None,
        description="Do not automatically redirect to the Web UI",
    )
    no_ui_redirect = enroll_only(no_ui_redirect)

    ssh_trust_dns = knob(
        None,
        description="configure OpenSSH client to trust DNS SSHFP records",
    )
    ssh_trust_dns = enroll_only(ssh_trust_dns)

    no_ssh = knob(
        None,
        description="do not configure OpenSSH client",
    )
    no_ssh = enroll_only(no_ssh)

    no_sshd = knob(
        None,
        description="do not configure OpenSSH server",
    )
    no_sshd = enroll_only(no_sshd)

    no_dns_sshfp = knob(
        None,
        description="Do not automatically create DNS SSHFP records",
    )
    no_dns_sshfp = enroll_only(no_dns_sshfp)

    dirsrv_config_file = knob(
        str,
        None,
        description="The path to LDIF file that will be used to modify "
        "configuration of dse.ldif during installation of the "
        "directory server instance",
        cli_metavar='FILE',
    )
    dirsrv_config_file = enroll_only(dirsrv_config_file)

    @dirsrv_config_file.validator
    def dirsrv_config_file(self, value):
        if not os.path.exists(value):
            raise ValueError("File %s does not exist." % value)

    dirsrv_cert_files = knob(
        # pylint: disable=invalid-sequence-index
        typing.List[str],
        None,
        description=("File containing the Directory Server SSL certificate "
                     "and private key"),
        cli_names='--dirsrv-cert-file',
        cli_deprecated_names='--dirsrv_pkcs12',
        cli_metavar='FILE',
    )
    dirsrv_cert_files = prepare_only(dirsrv_cert_files)

    http_cert_files = knob(
        # pylint: disable=invalid-sequence-index
        typing.List[str],
        None,
        description=("File containing the Apache Server SSL certificate and "
                     "private key"),
        cli_names='--http-cert-file',
        cli_deprecated_names='--http_pkcs12',
        cli_metavar='FILE',
    )
    http_cert_files = prepare_only(http_cert_files)

    pkinit_cert_files = knob(
        # pylint: disable=invalid-sequence-index
        typing.List[str],
        None,
        description=("File containing the Kerberos KDC SSL certificate and "
                     "private key"),
        cli_names='--pkinit-cert-file',
        cli_deprecated_names='--pkinit_pkcs12',
        cli_metavar='FILE',
    )
    pkinit_cert_files = prepare_only(pkinit_cert_files)

    dirsrv_pin = knob(
        str,
        None,
        sensitive=True,
        description="The password to unlock the Directory Server private key",
        cli_deprecated_names='--dirsrv_pin',
        cli_metavar='PIN',
    )
    dirsrv_pin = prepare_only(dirsrv_pin)

    http_pin = knob(
        str,
        None,
        sensitive=True,
        description="The password to unlock the Apache Server private key",
        cli_deprecated_names='--http_pin',
        cli_metavar='PIN',
    )
    http_pin = prepare_only(http_pin)

    pkinit_pin = knob(
        str,
        None,
        sensitive=True,
        description="The password to unlock the Kerberos KDC private key",
        cli_deprecated_names='--pkinit_pin',
        cli_metavar='PIN',
    )
    pkinit_pin = prepare_only(pkinit_pin)

    dirsrv_cert_name = knob(
        str,
        None,
        description="Name of the Directory Server SSL certificate to install",
        cli_metavar='NAME',
    )
    dirsrv_cert_name = prepare_only(dirsrv_cert_name)

    http_cert_name = knob(
        str,
        None,
        description="Name of the Apache Server SSL certificate to install",
        cli_metavar='NAME',
    )
    http_cert_name = prepare_only(http_cert_name)

    pkinit_cert_name = knob(
        str,
        None,
        description="Name of the Kerberos KDC SSL certificate to install",
        cli_metavar='NAME',
    )
    pkinit_cert_name = prepare_only(pkinit_cert_name)

    def __init__(self, **kwargs):
        super(ServerInstallInterface, self).__init__(**kwargs)

        # If any of the key file options are selected, all are required.
        cert_file_req = (self.dirsrv_cert_files, self.http_cert_files)
        cert_file_opt = (self.pkinit_cert_files, )
        if any(cert_file_req + cert_file_opt) and not all(cert_file_req):
            raise RuntimeError(
                "--dirsrv-cert-file and --http-cert-file are required if any "
                "key file options are used.")

        if not self.interactive:
            if self.dirsrv_cert_files and self.dirsrv_pin is None:
                raise RuntimeError(
                    "You must specify --dirsrv-pin with --dirsrv-cert-file")
            if self.http_cert_files and self.http_pin is None:
                raise RuntimeError(
                    "You must specify --http-pin with --http-cert-file")
            if self.pkinit_cert_files and self.pkinit_pin is None:
                raise RuntimeError(
                    "You must specify --pkinit-pin with --pkinit-cert-file")

        if not self.setup_dns:
            if self.forwarders:
                raise RuntimeError(
                    "You cannot specify a --forwarder option without the "
                    "--setup-dns option")
            if self.auto_forwarders:
                raise RuntimeError(
                    "You cannot specify a --auto-forwarders option without "
                    "the --setup-dns option")
            if self.no_forwarders:
                raise RuntimeError(
                    "You cannot specify a --no-forwarders option without the "
                    "--setup-dns option")
            if self.forward_policy:
                raise RuntimeError(
                    "You cannot specify a --forward-policy option without the "
                    "--setup-dns option")
            if self.reverse_zones:
                raise RuntimeError(
                    "You cannot specify a --reverse-zone option without the "
                    "--setup-dns option")
            if self.auto_reverse:
                raise RuntimeError(
                    "You cannot specify a --auto-reverse option without the "
                    "--setup-dns option")
            if self.no_reverse:
                raise RuntimeError(
                    "You cannot specify a --no-reverse option without the "
                    "--setup-dns option")
            if self.no_dnssec_validation:
                raise RuntimeError(
                    "You cannot specify a --no-dnssec-validation option "
                    "without the --setup-dns option")
        elif self.forwarders and self.no_forwarders:
            raise RuntimeError(
                "You cannot specify a --forwarder option together with "
                "--no-forwarders")
        elif self.auto_forwarders and self.no_forwarders:
            raise RuntimeError(
                "You cannot specify a --auto-forwarders option together with "
                "--no-forwarders")
        elif self.reverse_zones and self.no_reverse:
            raise RuntimeError(
                "You cannot specify a --reverse-zone option together with "
                "--no-reverse")
        elif self.auto_reverse and self.no_reverse:
            raise RuntimeError(
                "You cannot specify a --auto-reverse option together with "
                "--no-reverse")

        if not hasattr(self, 'replica_file'):
            if self.external_cert_files and self.dirsrv_cert_files:
                raise RuntimeError(
                    "Service certificate file options cannot be used with the "
                    "external CA options.")

            if self.external_ca_type and not self.external_ca:
                raise RuntimeError(
                    "You cannot specify --external-ca-type without "
                    "--external-ca")

            if self.uninstalling:
                if (self.realm_name or self.admin_password
                        or self.master_password):
                    raise RuntimeError(
                        "In uninstall mode, -a, -r and -P options are not "
                        "allowed")
            elif not self.interactive:
                if (not self.realm_name or not self.dm_password
                        or not self.admin_password):
                    raise RuntimeError(
                        "In unattended mode you need to provide at least -r, "
                        "-p and -a options")
                if self.setup_dns:
                    if (not self.forwarders and not self.no_forwarders
                            and not self.auto_forwarders):
                        raise RuntimeError(
                            "You must specify at least one of --forwarder, "
                            "--auto-forwarders, or --no-forwarders options")

            any_ignore_option_true = any(
                [self.ignore_topology_disconnect, self.ignore_last_of_role])
            if any_ignore_option_true and not self.uninstalling:
                raise RuntimeError(
                    "'--ignore-topology-disconnect/--ignore-last-of-role' "
                    "options can be used only during uninstallation")

            if self.idmax < self.idstart:
                raise RuntimeError(
                    "idmax (%s) cannot be smaller than idstart (%s)" %
                    (self.idmax, self.idstart))
        else:
            cert_file_req = (self.dirsrv_cert_files, self.http_cert_files)
            cert_file_opt = (self.pkinit_cert_files, )

            if self.replica_file is None:
                # If any of the PKCS#12 options are selected, all are required.
                if any(cert_file_req +
                       cert_file_opt) and not all(cert_file_req):
                    raise RuntimeError(
                        "--dirsrv-cert-file and --http-cert-file are required "
                        "if any PKCS#12 options are used")

                if self.servers and not self.domain_name:
                    raise RuntimeError(
                        "The --server option cannot be used without providing "
                        "domain via the --domain option")

            else:
                if not ipautil.file_exists(self.replica_file):
                    raise RuntimeError("Replica file %s does not exist" %
                                       self.replica_file)

                if any(cert_file_req + cert_file_opt):
                    raise RuntimeError(
                        "You cannot specify any of --dirsrv-cert-file, "
                        "--http-cert-file, or --pkinit-cert-file together "
                        "with replica file")

                CLIKnob = collections.namedtuple('CLIKnob', ('value', 'name'))

                conflicting_knobs = (
                    CLIKnob(self.realm_name, '--realm'),
                    CLIKnob(self.domain_name, '--domain'),
                    CLIKnob(self.host_name, '--hostname'),
                    CLIKnob(self.servers, '--server'),
                    CLIKnob(self.principal, '--principal'),
                )

                if any([k.value is not None for k in conflicting_knobs]):
                    conflicting_knob_names = [
                        knob.name for knob in conflicting_knobs
                        if knob.value is not None
                    ]

                    raise RuntimeError(
                        "You cannot specify '{0}' option(s) with replica file."
                        .format(", ".join(conflicting_knob_names)))

            if self.setup_dns:
                if (not self.forwarders and not self.no_forwarders
                        and not self.auto_forwarders):
                    raise RuntimeError(
                        "You must specify at least one of --forwarder, "
                        "--auto-forwarders, or --no-forwarders options")

        # Automatically enable pkinit w/ dogtag
        self.no_pkinit = not self.setup_ca