Blame roles/ipaclient/library/ipaclient_test.py

Packit 8cb997
# -*- coding: utf-8 -*-
Packit 8cb997
Packit 8cb997
# Authors:
Packit 8cb997
#   Thomas Woerner <twoerner@redhat.com>
Packit 8cb997
#
Packit 8cb997
# Based on ipa-client-install code
Packit 8cb997
#
Packit 8cb997
# Copyright (C) 2017  Red Hat
Packit 8cb997
# see file 'COPYING' for use and warranty information
Packit 8cb997
#
Packit 8cb997
# This program is free software; you can redistribute it and/or modify
Packit 8cb997
# it under the terms of the GNU General Public License as published by
Packit 8cb997
# the Free Software Foundation, either version 3 of the License, or
Packit 8cb997
# (at your option) any later version.
Packit 8cb997
#
Packit 8cb997
# This program is distributed in the hope that it will be useful,
Packit 8cb997
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8cb997
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8cb997
# GNU General Public License for more details.
Packit 8cb997
#
Packit 8cb997
# You should have received a copy of the GNU General Public License
Packit 8cb997
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 8cb997
Packit 8cb997
ANSIBLE_METADATA = {
Packit 8cb997
    'metadata_version': '1.0',
Packit 8cb997
    'supported_by': 'community',
Packit 8cb997
    'status': ['preview'],
Packit 8cb997
}
Packit 8cb997
Packit 8cb997
DOCUMENTATION = '''
Packit 8cb997
---
Packit 8cb997
module: ipaclient_test
Packit 8cb997
short description: Tries to discover IPA server
Packit 8cb997
description:
Packit 8cb997
  Tries to discover IPA server using DNS or host name
Packit 8cb997
options:
Packit 8cb997
  domain:
Packit 8cb997
    description: Primary DNS domain of the IPA deployment
Packit 8cb997
    required: yes
Packit 8cb997
  servers:
Packit 8cb997
    description: Fully qualified name of IPA servers to enroll to
Packit 8cb997
    required: yes
Packit 8cb997
  realm:
Packit 8cb997
    description: Kerberos realm name of the IPA deployment
Packit 8cb997
    required: yes
Packit 8cb997
  hostname:
Packit 8cb997
    description: Fully qualified name of this host
Packit 8cb997
    required: yes
Packit 8cb997
  ntp_servers:
Packit 8cb997
    description: ntp servers to use
Packit 8cb997
    required: yes
Packit 8cb997
  ntp_pool:
Packit 8cb997
    description: ntp server pool to use
Packit 8cb997
    required: yes
Packit 8cb997
  no_ntp:
Packit 8cb997
    description: Do not configure ntp
Packit 8cb997
    required: yes
Packit 8cb997
  force_ntpd:
Packit 8cb997
    description:
Packit 8cb997
      Stop and disable any time&date synchronization services besides ntpd
Packit 8cb997
      Deprecated since 4.7
Packit 8cb997
    required: yes
Packit 8cb997
  nisdomain:
Packit 8cb997
    description: The NIS domain name
Packit 8cb997
    required: yes
Packit 8cb997
  no_nisdomain:
Packit 8cb997
    description: Do not configure NIS domain name
Packit 8cb997
    required: yes
Packit 8cb997
  kinit_attempts:
Packit 8cb997
    description: Repeat the request for host Kerberos ticket X times
Packit 8cb997
    required: yes
Packit 8cb997
  ca_cert_files:
Packit 8cb997
    description:
Packit 8cb997
      List of files containing CA certificates for the service certificate
Packit 8cb997
      files
Packit 8cb997
    required: yes
Packit 8cb997
  configure_firefox:
Packit 8cb997
    description: Configure Firefox to use IPA domain credentials
Packit 8cb997
    required: yes
Packit 8cb997
  firefox_dir:
Packit 8cb997
    description:
Packit 8cb997
      Specify directory where Firefox is installed (for example
Packit 8cb997
      '/usr/lib/firefox')
Packit 8cb997
    required: yes
Packit 8cb997
  ip_addresses:
Packit 8cb997
    description: List of Master Server IP Addresses
Packit 8cb997
    required: yes
Packit 8cb997
  all_ip_addresses:
Packit 8cb997
    description:
Packit 8cb997
      All routable IP addresses configured on any interface will be added
Packit 8cb997
      to DNS
Packit 8cb997
    required: yes
Packit 8cb997
  on_master:
Packit 8cb997
    description: Whether the configuration is done on the master or not
Packit 8cb997
    required: yes
Packit 8cb997
  enable_dns_updates:
Packit 8cb997
    description:
Packit 8cb997
      Configures the machine to attempt dns updates when the ip address
Packit 8cb997
      changes
Packit 8cb997
    required: yes
Packit 8cb997
author:
Packit 8cb997
    - Thomas Woerner
Packit 8cb997
'''
Packit 8cb997
Packit 8cb997
EXAMPLES = '''
Packit 8cb997
# Complete autodiscovery, register return values as ipaclient_test
Packit 8cb997
- name: IPA discovery
Packit 8cb997
  ipaclient_test:
Packit 8cb997
  register: register_ipaclient_test
Packit 8cb997
Packit 8cb997
# Discovery using servers, register return values as ipaclient_test
Packit 8cb997
- name: IPA discovery
Packit 8cb997
  ipaclient_test:
Packit 8cb997
    servers: server1.domain.com,server2.domain.com
Packit 8cb997
  register: register_ipaclient_test
Packit 8cb997
Packit 8cb997
# Discovery using domain name, register return values as ipaclient_test
Packit 8cb997
- name: IPA discovery
Packit 8cb997
  ipaclient_test:
Packit 8cb997
    domain: domain.com
Packit 8cb997
  register: register_ipaclient_test
Packit 8cb997
Packit 8cb997
# Discovery using realm, register return values as ipaclient_test
Packit 8cb997
- name: IPA discovery
Packit 8cb997
  ipaclient_test:
Packit 8cb997
    realm: DOMAIN.COM
Packit 8cb997
  register: register_ipaclient_test
Packit 8cb997
Packit 8cb997
# Discovery using hostname, register return values as ipaclient_test
Packit 8cb997
- name: IPA discovery
Packit 8cb997
  ipaclient_test:
Packit 8cb997
    hostname: host.domain.com
Packit 8cb997
  register: register_ipaclient_test
Packit 8cb997
'''
Packit 8cb997
Packit 8cb997
RETURN = '''
Packit 8cb997
servers:
Packit 8cb997
  description: The list of detected or passed in IPA servers.
Packit 8cb997
  returned: always
Packit 8cb997
  type: list
Packit 8cb997
  sample: ["server1.example.com","server2.example.com"]
Packit 8cb997
domain:
Packit 8cb997
  description: The DNS domain of the detected or passed in IPA deployment.
Packit 8cb997
  returned: always
Packit 8cb997
  type: string
Packit 8cb997
  sample: example.com
Packit 8cb997
realm:
Packit 8cb997
  description: The Kerberos realm of the detected or passed in IPA deployment.
Packit 8cb997
  returned: always
Packit 8cb997
  type: string
Packit 8cb997
  sample: EXAMPLE.COM
Packit 8cb997
kdc:
Packit 8cb997
  description: The detected KDC server name.
Packit 8cb997
  returned: always
Packit 8cb997
  type: string
Packit 8cb997
  sample: server1.example.com
Packit 8cb997
basedn:
Packit 8cb997
  description: The basedn of the detected IPA server.
Packit 8cb997
  returned: always
Packit 8cb997
  type: string
Packit 8cb997
  sample: dc=example,dc=com
Packit 8cb997
hostname:
Packit 8cb997
  description: The detected or passed in FQDN hostname of the client.
Packit 8cb997
  returned: always
Packit 8cb997
  type: string
Packit 8cb997
  sample: client1.example.com
Packit 8cb997
client_domain:
Packit 8cb997
  description: The domain name of the client.
Packit 8cb997
  returned: always
Packit 8cb997
  type: string
Packit 8cb997
  sample: example.com
Packit 8cb997
dnsok:
Packit 8cb997
  description: True if DNS discovery worked and not passed in any servers.
Packit 8cb997
  returned: always
Packit 8cb997
  type: bool
Packit 8cb997
ntp_servers:
Packit 8cb997
  description: The list of detected NTP servers.
Packit 8cb997
  returned: always
Packit 8cb997
  type: list
Packit 8cb997
  sample: ["ntp.example.com"]
Packit 8cb997
ipa_python_version:
Packit 8cb997
  description:
Packit 8cb997
  - The IPA python version as a number:
Packit 8cb997
  - <major version>*10000+<minor version>*100+<release>
Packit 8cb997
  returned: always
Packit 8cb997
  type: int
Packit 8cb997
  sample: 040400
Packit 8cb997
'''
Packit 8cb997
Packit 8cb997
import os
Packit 8cb997
import socket
Packit 8cb997
import inspect
Packit 8cb997
Packit 8cb997
try:
Packit 8cb997
    from six.moves.configparser import RawConfigParser
Packit 8cb997
except ImportError:
Packit 8cb997
    from ConfigParser import RawConfigParser
Packit 8cb997
Packit 8cb997
from ansible.module_utils.basic import AnsibleModule
Packit 8cb997
from ansible.module_utils.ansible_ipa_client import (
Packit Service 0f71a7
    setup_logging,
Packit 8cb997
    paths, sysrestore, options, CheckedIPAddress, validate_domain_name,
Packit 8cb997
    logger, x509, normalize_hostname, installer, version, ScriptError,
Packit 8cb997
    CLIENT_INSTALL_ERROR, tasks, check_ldap_conf, timeconf, constants,
Packit 8cb997
    validate_hostname, nssldap_exists, gssapi, remove_file,
Packit 8cb997
    check_ip_addresses, ipadiscovery, print_port_conf_info,
Packit 8cb997
    IPA_PYTHON_VERSION
Packit 8cb997
)
Packit 8cb997
Packit 8cb997
Packit 8cb997
def get_cert_path(cert_path):
Packit 8cb997
    """
Packit 8cb997
    If a CA certificate is passed in on the command line, use that.
Packit 8cb997
Packit 8cb997
    Else if a CA file exists in paths.IPA_CA_CRT then use that.
Packit 8cb997
Packit 8cb997
    Otherwise return None.
Packit 8cb997
    """
Packit 8cb997
    if cert_path is not None:
Packit 8cb997
        return cert_path
Packit 8cb997
Packit 8cb997
    if os.path.exists(paths.IPA_CA_CRT):
Packit 8cb997
        return paths.IPA_CA_CRT
Packit 8cb997
Packit 8cb997
    return None
Packit 8cb997
Packit 8cb997
Packit 8cb997
def is_client_configured():
Packit 8cb997
    """
Packit 8cb997
    Check if ipa client is configured.
Packit 8cb997
Packit 8cb997
    IPA client is configured when /etc/ipa/default.conf exists and
Packit 8cb997
    /var/lib/ipa-client/sysrestore/sysrestore.state exists.
Packit 8cb997
Packit 8cb997
    :returns: boolean
Packit 8cb997
    """
Packit 8cb997
    return (os.path.isfile(paths.IPA_DEFAULT_CONF) and
Packit 8cb997
            os.path.isfile(os.path.join(paths.IPA_CLIENT_SYSRESTORE,
Packit 8cb997
                                        sysrestore.SYSRESTORE_STATEFILE)))
Packit 8cb997
Packit 8cb997
Packit 8cb997
def get_ipa_conf():
Packit 8cb997
    """
Packit Service 0f71a7
    Return IPA configuration read from `/etc/ipa/default.conf`.
Packit 8cb997
Packit 8cb997
    :returns: dict containing key,value
Packit 8cb997
    """
Packit 8cb997
    parser = RawConfigParser()
Packit 8cb997
    parser.read(paths.IPA_DEFAULT_CONF)
Packit 8cb997
    result = dict()
Packit 8cb997
    for item in ['basedn', 'realm', 'domain', 'server', 'host', 'xmlrpc_uri']:
Packit 8cb997
        if parser.has_option('global', item):
Packit 8cb997
            value = parser.get('global', item)
Packit 8cb997
        else:
Packit 8cb997
            value = None
Packit 8cb997
        if value:
Packit 8cb997
            result[item] = value
Packit 8cb997
Packit 8cb997
    return result
Packit 8cb997
Packit 8cb997
Packit 8cb997
def main():
Packit 8cb997
    module = AnsibleModule(
Packit 8cb997
        argument_spec=dict(
Packit 8cb997
            # basic
Packit 8cb997
            domain=dict(required=False, default=None),
Packit 8cb997
            servers=dict(required=False, type='list', default=None),
Packit 8cb997
            realm=dict(required=False, default=None),
Packit 8cb997
            hostname=dict(required=False, default=None),
Packit 8cb997
            ntp_servers=dict(required=False, type='list', default=None),
Packit 8cb997
            ntp_pool=dict(required=False, default=None),
Packit 8cb997
            no_ntp=dict(required=False, type='bool', default=False),
Packit 8cb997
            force_ntpd=dict(required=False, type='bool', default=False),
Packit 8cb997
            nisdomain=dict(required=False, default=None),
Packit 8cb997
            no_nisdomain=dict(required=False, type='bool', default='no'),
Packit 8cb997
            kinit_attempts=dict(required=False, type='int'),
Packit 8cb997
            ca_cert_files=dict(required=False, type='list', default=None),
Packit 8cb997
            configure_firefox=dict(required=False, type='bool', default=False),
Packit 8cb997
            firefox_dir=dict(required=False),
Packit 8cb997
            ip_addresses=dict(required=False, type='list', default=None),
Packit 8cb997
            all_ip_addresses=dict(required=False, type='bool', default=False),
Packit 8cb997
            on_master=dict(required=False, type='bool', default=False),
Packit 8cb997
            # sssd
Packit 8cb997
            enable_dns_updates=dict(required=False, type='bool',
Packit 8cb997
                                    default=False),
Packit 8cb997
        ),
Packit 8cb997
        supports_check_mode=True,
Packit 8cb997
    )
Packit 8cb997
Packit 8cb997
    # module._ansible_debug = True
Packit Service 0f71a7
    setup_logging()
Packit Service 0f71a7
Packit 8cb997
    options.domain_name = module.params.get('domain')
Packit 8cb997
    options.servers = module.params.get('servers')
Packit 8cb997
    options.realm_name = module.params.get('realm')
Packit 8cb997
    options.host_name = module.params.get('hostname')
Packit 8cb997
    options.ntp_servers = module.params.get('ntp_servers')
Packit 8cb997
    options.ntp_pool = module.params.get('ntp_pool')
Packit 8cb997
    options.no_ntp = module.params.get('no_ntp')
Packit 8cb997
    options.force_ntpd = module.params.get('force_ntpd')
Packit 8cb997
    options.nisdomain = module.params.get('nisdomain')
Packit 8cb997
    options.no_nisdomain = module.params.get('no_nisdomain')
Packit 8cb997
    options.kinit_attempts = module.params.get('kinit_attempts')
Packit 8cb997
    options.ca_cert_files = module.params.get('ca_cert_files')
Packit 8cb997
    options.configure_firefox = module.params.get('configure_firefox')
Packit 8cb997
    options.firefox_dir = module.params.get('firefox_dir')
Packit 8cb997
    options.ip_addresses = module.params.get('ip_addresses')
Packit 8cb997
    options.all_ip_addresses = module.params.get('all_ip_addresses')
Packit 8cb997
    options.on_master = module.params.get('on_master')
Packit 8cb997
    options.enable_dns_updates = module.params.get('enable_dns_updates')
Packit 8cb997
Packit 8cb997
    # Get domain from first server if domain is not set, but if there are
Packit 8cb997
    # servers
Packit 8cb997
    if options.domain_name is None and options.servers is not None:
Packit 8cb997
        if len(options.servers) > 0:
Packit 8cb997
            options.domain_name = options.servers[0][
Packit 8cb997
                options.servers[0].find(".")+1:]
Packit 8cb997
Packit 8cb997
    try:
Packit 8cb997
        self = options
Packit 8cb997
Packit 8cb997
        # HostNameInstallInterface
Packit 8cb997
Packit 8cb997
        if options.ip_addresses is not None:
Packit 8cb997
            for value in options.ip_addresses:
Packit 8cb997
                try:
Packit 8cb997
                    CheckedIPAddress(value)
Packit 8cb997
                except Exception as e:
Packit 8cb997
                    raise ValueError("invalid IP address {0}: {1}".format(
Packit 8cb997
                        value, e))
Packit 8cb997
Packit 8cb997
        # ServiceInstallInterface
Packit 8cb997
Packit 8cb997
        if options.domain_name:
Packit 8cb997
            validate_domain_name(options.domain_name)
Packit 8cb997
Packit 8cb997
        if options.realm_name:
Packit 8cb997
            argspec = inspect.getargspec(validate_domain_name)
Packit 8cb997
            if "entity" in argspec.args:
Packit 8cb997
                # NUM_VERSION >= 40690:
Packit 8cb997
                validate_domain_name(options.realm_name, entity="realm")
Packit 8cb997
Packit 8cb997
        # ClientInstallInterface
Packit 8cb997
Packit 8cb997
        if options.kinit_attempts < 1:
Packit 8cb997
            raise ValueError("expects an integer greater than 0.")
Packit 8cb997
Packit 8cb997
        # ClientInstallInterface.__init__
Packit 8cb997
Packit 8cb997
        if self.servers and not self.domain_name:
Packit 8cb997
            raise RuntimeError(
Packit 8cb997
                "--server cannot be used without providing --domain")
Packit 8cb997
Packit 8cb997
        if self.force_ntpd:
Packit 8cb997
            logger.warning("Option --force-ntpd has been deprecated")
Packit 8cb997
Packit 8cb997
        if self.ntp_servers and self.no_ntp:
Packit 8cb997
            raise RuntimeError(
Packit 8cb997
                "--ntp-server cannot be used together with --no-ntp")
Packit 8cb997
Packit 8cb997
        if self.ntp_pool and self.no_ntp:
Packit 8cb997
            raise RuntimeError(
Packit 8cb997
                "--ntp-pool cannot be used together with --no-ntp")
Packit 8cb997
Packit 8cb997
        if self.no_nisdomain and self.nisdomain:
Packit 8cb997
            raise RuntimeError(
Packit 8cb997
                "--no-nisdomain cannot be used together with --nisdomain")
Packit 8cb997
Packit 8cb997
        if self.ip_addresses:
Packit 8cb997
            if self.enable_dns_updates:
Packit 8cb997
                raise RuntimeError(
Packit 8cb997
                    "--ip-address cannot be used together with"
Packit 8cb997
                    " --enable-dns-updates")
Packit 8cb997
Packit 8cb997
            if self.all_ip_addresses:
Packit 8cb997
                raise RuntimeError(
Packit 8cb997
                    "--ip-address cannot be used together with"
Packit 8cb997
                    "--all-ip-addresses")
Packit 8cb997
Packit 8cb997
        # SSSDInstallInterface
Packit 8cb997
Packit 8cb997
        self.no_sssd = False
Packit 8cb997
Packit 8cb997
        # ClientInstall
Packit 8cb997
Packit 8cb997
        if options.ca_cert_files is not None:
Packit 8cb997
            for value in options.ca_cert_files:
Packit 8cb997
                if not isinstance(value, list):
Packit 8cb997
                    raise ValueError("Expected list, got {!r}".format(value))
Packit 8cb997
                # this is what init() does
Packit 8cb997
                value = value[-1]
Packit 8cb997
                if not os.path.exists(value):
Packit 8cb997
                    raise ValueError("'%s' does not exist" % value)
Packit 8cb997
                if not os.path.isfile(value):
Packit 8cb997
                    raise ValueError("'%s' is not a file" % value)
Packit 8cb997
                if not os.path.isabs(value):
Packit 8cb997
                    raise ValueError("'%s' is not an absolute file path" %
Packit 8cb997
                                     value)
Packit 8cb997
Packit 8cb997
                try:
Packit 8cb997
                    x509.load_certificate_from_file(value)
Packit 8cb997
                except Exception:
Packit 8cb997
                    raise ValueError("'%s' is not a valid certificate file" %
Packit 8cb997
                                     value)
Packit 8cb997
Packit 8cb997
        # self.prompt_password = self.interactive
Packit 8cb997
Packit 8cb997
        self.no_ac = False
Packit 8cb997
Packit 8cb997
        # ClientInstall.__init__
Packit 8cb997
Packit 8cb997
        if self.firefox_dir and not self.configure_firefox:
Packit 8cb997
            raise RuntimeError(
Packit 8cb997
                "--firefox-dir cannot be used without --configure-firefox "
Packit 8cb997
                "option")
Packit 8cb997
Packit 8cb997
    except (RuntimeError, ValueError) as e:
Packit 8cb997
        module.fail_json(msg=str(e))
Packit 8cb997
Packit 8cb997
    # ipaclient.install.client.init
Packit 8cb997
Packit 8cb997
    # root_logger
Packit 8cb997
    options.debug = False
Packit 8cb997
    if options.domain_name:
Packit 8cb997
        options.domain = normalize_hostname(installer.domain_name)
Packit 8cb997
    else:
Packit 8cb997
        options.domain = None
Packit 8cb997
    options.server = options.servers
Packit 8cb997
    options.realm = options.realm_name
Packit 8cb997
    # installer.primary = installer.fixed_primary
Packit 8cb997
    # if installer.principal:
Packit 8cb997
    #     installer.password = installer.admin_password
Packit 8cb997
    # else:
Packit 8cb997
    #     installer.password = installer.host_password
Packit 8cb997
    installer.hostname = installer.host_name
Packit 8cb997
    options.conf_ntp = not options.no_ntp
Packit 8cb997
    # installer.trust_sshfp = installer.ssh_trust_dns
Packit 8cb997
    # installer.conf_ssh = not installer.no_ssh
Packit 8cb997
    # installer.conf_sshd = not installer.no_sshd
Packit 8cb997
    # installer.conf_sudo = not installer.no_sudo
Packit 8cb997
    # installer.create_sshfp = not installer.no_dns_sshfp
Packit 8cb997
    if installer.ca_cert_files:
Packit 8cb997
        installer.ca_cert_file = installer.ca_cert_files[-1]
Packit 8cb997
    else:
Packit 8cb997
        installer.ca_cert_file = None
Packit 8cb997
    # installer.location = installer.automount_location
Packit 8cb997
    installer.dns_updates = installer.enable_dns_updates
Packit 8cb997
    # installer.krb5_offline_passwords = \
Packit 8cb997
    #     not installer.no_krb5_offline_passwords
Packit 8cb997
    installer.sssd = not installer.no_sssd
Packit 8cb997
Packit 8cb997
    try:
Packit 8cb997
Packit 8cb997
        # client
Packit 8cb997
Packit 8cb997
        # global variables
Packit 8cb997
        hostname = None
Packit 8cb997
        hostname_source = None
Packit 8cb997
        nosssd_files = None
Packit 8cb997
        dnsok = False
Packit 8cb997
        cli_domain = None
Packit 8cb997
        cli_server = None
Packit 8cb997
        # subject_base = None
Packit 8cb997
        cli_realm = None
Packit 8cb997
        cli_kdc = None
Packit 8cb997
        client_domain = None
Packit 8cb997
        cli_basedn = None
Packit 8cb997
        # end of global variables
Packit 8cb997
Packit 8cb997
        # client.install_check
Packit 8cb997
Packit 8cb997
        logger.info("This program will set up FreeIPA client.")
Packit 8cb997
        logger.info("Version %s", version.VERSION)
Packit 8cb997
        logger.info("")
Packit 8cb997
Packit 8cb997
        cli_domain_source = 'Unknown source'
Packit 8cb997
        cli_server_source = 'Unknown source'
Packit 8cb997
Packit 8cb997
        # fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)
Packit 8cb997
Packit 8cb997
        if not os.getegid() == 0:
Packit 8cb997
            raise ScriptError(
Packit 8cb997
                "You must be root to run ipa-client-install.",
Packit 8cb997
                rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
        tasks.check_selinux_status()
Packit 8cb997
Packit 8cb997
        # if is_ipa_client_installed(fstore, on_master=options.on_master):
Packit 8cb997
        #     logger.error("IPA client is already configured on this system.")
Packit 8cb997
        #     logger.info(
Packit 8cb997
        #       "If you want to reinstall the IPA client, uninstall it first "
Packit 8cb997
        #       "using 'ipa-client-install --uninstall'.")
Packit 8cb997
        #     raise ScriptError(
Packit 8cb997
        #         "IPA client is already configured on this system.",
Packit 8cb997
        #         rval=CLIENT_ALREADY_CONFIGURED)
Packit 8cb997
Packit 8cb997
        if check_ldap_conf is not None:
Packit 8cb997
            check_ldap_conf()
Packit 8cb997
Packit 8cb997
        if options.conf_ntp:
Packit 8cb997
            try:
Packit 8cb997
                timeconf.check_timedate_services()
Packit 8cb997
            except timeconf.NTPConflictingService as e:
Packit 8cb997
                logger.info(
Packit 8cb997
                    "WARNING: conflicting time&date synchronization service "
Packit 8cb997
                    "'%s' will be disabled in favor of chronyd",
Packit 8cb997
                    e.conflicting_service)
Packit 8cb997
                logger.info("")
Packit 8cb997
            except timeconf.NTPConfigurationError:
Packit 8cb997
                pass
Packit 8cb997
Packit 8cb997
        # password, principal and keytab are checked in tasks/install.yml
Packit 8cb997
        # if options.unattended and (
Packit 8cb997
        #     options.password is None and
Packit 8cb997
        #     options.principal is None and
Packit 8cb997
        #     options.keytab is None and
Packit 8cb997
        #     options.prompt_password is False and
Packit 8cb997
        #     not options.on_master
Packit 8cb997
        # ):
Packit 8cb997
        #     raise ScriptError(
Packit 8cb997
        #         "One of password / principal / keytab is required.",
Packit 8cb997
        #         rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
        if options.hostname:
Packit 8cb997
            hostname = options.hostname
Packit 8cb997
            hostname_source = 'Provided as option'
Packit 8cb997
        else:
Packit 8cb997
            hostname = socket.getfqdn()
Packit 8cb997
            hostname_source = "Machine's FQDN"
Packit 8cb997
        if hostname != hostname.lower():
Packit 8cb997
            raise ScriptError(
Packit 8cb997
                "Invalid hostname '{}', must be lower-case.".format(hostname),
Packit 8cb997
                rval=CLIENT_INSTALL_ERROR
Packit 8cb997
            )
Packit 8cb997
Packit 8cb997
        if hostname in ('localhost', 'localhost.localdomain'):
Packit 8cb997
            raise ScriptError(
Packit 8cb997
                "Invalid hostname, '{}' must not be used.".format(hostname),
Packit 8cb997
                rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
        if hasattr(constants, "MAXHOSTNAMELEN"):
Packit 8cb997
            try:
Packit 8cb997
                validate_hostname(hostname, maxlen=constants.MAXHOSTNAMELEN)
Packit 8cb997
            except ValueError as e:
Packit 8cb997
                raise ScriptError(
Packit 8cb997
                    'invalid hostname: {}'.format(e),
Packit 8cb997
                    rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
        if hasattr(tasks, "is_nosssd_supported"):
Packit 8cb997
            # --no-sssd is not supported any more for rhel-based distros
Packit 8cb997
            if not tasks.is_nosssd_supported() and not options.sssd:
Packit 8cb997
                raise ScriptError(
Packit 8cb997
                    "Option '--no-sssd' is incompatible with the 'authselect' "
Packit 8cb997
                    "tool provided by this distribution for configuring "
Packit 8cb997
                    "system authentication resources",
Packit 8cb997
                    rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
            # --noac is not supported any more for rhel-based distros
Packit 8cb997
            if not tasks.is_nosssd_supported() and options.no_ac:
Packit 8cb997
                raise ScriptError(
Packit 8cb997
                    "Option '--noac' is incompatible with the 'authselect' "
Packit 8cb997
                    "tool provided by this distribution for configuring "
Packit 8cb997
                    "system authentication resources",
Packit 8cb997
                    rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
        # when installing with '--no-sssd' option, check whether nss-ldap is
Packit 8cb997
        # installed
Packit 8cb997
        if not options.sssd:
Packit 8cb997
            if not os.path.exists(paths.PAM_KRB5_SO):
Packit 8cb997
                raise ScriptError(
Packit 8cb997
                    "The pam_krb5 package must be installed",
Packit 8cb997
                    rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
            (nssldap_installed, nosssd_files) = nssldap_exists()
Packit 8cb997
            (nssldap_installed, __temp) = nssldap_exists()
Packit 8cb997
            if not nssldap_installed:
Packit 8cb997
                raise ScriptError(
Packit 8cb997
                    "One of these packages must be installed: nss_ldap or "
Packit 8cb997
                    "nss-pam-ldapd",
Packit 8cb997
                    rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
            # principal and keytab are checked in tasks/install.yml
Packit 8cb997
            # if options.keytab and options.principal:
Packit 8cb997
            #   raise ScriptError(
Packit 8cb997
            #     "Options 'principal' and 'keytab' cannot be used together.",
Packit 8cb997
            #     rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
            # keytab and force_join are checked in tasks/install.yml
Packit 8cb997
            # if options.keytab and options.force_join:
Packit 8cb997
            #   logger.warning("Option 'force-join' has no additional effect "
Packit 8cb997
            #                  "when used with together with option 'keytab'.")
Packit 8cb997
Packit 8cb997
        # Added with freeipa-4.7.1 >>>
Packit 8cb997
        # Remove invalid keytab file
Packit 8cb997
        try:
Packit 8cb997
            gssapi.Credentials(
Packit 8cb997
                store={'keytab': paths.KRB5_KEYTAB},
Packit 8cb997
                usage='accept',
Packit 8cb997
            )
Packit 8cb997
        except gssapi.exceptions.GSSError:
Packit 8cb997
            logger.debug("Deleting invalid keytab: '%s'.", paths.KRB5_KEYTAB)
Packit 8cb997
            remove_file(paths.KRB5_KEYTAB)
Packit 8cb997
        # Added with freeipa-4.7.1 <<<
Packit 8cb997
Packit 8cb997
        # Check if old certificate exist and show warning
Packit 8cb997
        if (
Packit 8cb997
            not options.ca_cert_file and
Packit 8cb997
            get_cert_path(options.ca_cert_file) == paths.IPA_CA_CRT
Packit 8cb997
        ):
Packit 8cb997
            logger.warning("Using existing certificate '%s'.",
Packit 8cb997
                           paths.IPA_CA_CRT)
Packit 8cb997
Packit 8cb997
        if not check_ip_addresses(options):
Packit 8cb997
            raise ScriptError(
Packit 8cb997
                "Failed to check ip addresses, check installation log",
Packit 8cb997
                rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
        # Create the discovery instance
Packit 8cb997
        ds = ipadiscovery.IPADiscovery()
Packit 8cb997
Packit 8cb997
        ret = ds.search(
Packit 8cb997
            domain=options.domain,
Packit 8cb997
            servers=options.server,
Packit 8cb997
            realm=options.realm_name,
Packit 8cb997
            hostname=hostname,
Packit 8cb997
            ca_cert_path=get_cert_path(options.ca_cert_file)
Packit 8cb997
        )
Packit 8cb997
Packit 8cb997
        if options.server and ret != 0:
Packit 8cb997
            # There is no point to continue with installation as server list
Packit 8cb997
            # was passed as a fixed list of server and thus we cannot discover
Packit 8cb997
            # any better result
Packit 8cb997
            logger.error(
Packit 8cb997
                "Failed to verify that %s is an IPA Server.",
Packit 8cb997
                ', '.join(options.server))
Packit 8cb997
            logger.error(
Packit 8cb997
                "This may mean that the remote server is not up "
Packit 8cb997
                "or is not reachable due to network or firewall settings.")
Packit 8cb997
            print_port_conf_info()
Packit 8cb997
            raise ScriptError("Failed to verify that %s is an IPA Server." %
Packit 8cb997
                              ', '.join(options.server),
Packit 8cb997
                              rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
        if ret == ipadiscovery.BAD_HOST_CONFIG:
Packit 8cb997
            logger.error("Can't get the fully qualified name of this host")
Packit 8cb997
            logger.info("Check that the client is properly configured")
Packit 8cb997
            raise ScriptError(
Packit 8cb997
                "Can't get the fully qualified name of this host",
Packit 8cb997
                rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
        if ret == ipadiscovery.NOT_FQDN:
Packit 8cb997
            raise ScriptError(
Packit 8cb997
                "{} is not a fully-qualified hostname".format(hostname),
Packit 8cb997
                rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
        if ret in (ipadiscovery.NO_LDAP_SERVER, ipadiscovery.NOT_IPA_SERVER) \
Packit 8cb997
                or not ds.domain:
Packit 8cb997
            if ret == ipadiscovery.NO_LDAP_SERVER:
Packit 8cb997
                if ds.server:
Packit 8cb997
                    logger.debug("%s is not an LDAP server", ds.server)
Packit 8cb997
                else:
Packit 8cb997
                    logger.debug("No LDAP server found")
Packit 8cb997
            elif ret == ipadiscovery.NOT_IPA_SERVER:
Packit 8cb997
                if ds.server:
Packit 8cb997
                    logger.debug("%s is not an IPA server", ds.server)
Packit 8cb997
                else:
Packit 8cb997
                    logger.debug("No IPA server found")
Packit 8cb997
            else:
Packit 8cb997
                logger.debug("Domain not found")
Packit 8cb997
            if options.domain:
Packit 8cb997
                cli_domain = options.domain
Packit 8cb997
                cli_domain_source = 'Provided as option'
Packit 8cb997
            elif options.unattended:
Packit 8cb997
                raise ScriptError(
Packit 8cb997
                    "Unable to discover domain, not provided on command line",
Packit 8cb997
                    rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
            else:
Packit 8cb997
                raise ScriptError("No interactive installation")
Packit 8cb997
            #    logger.info(
Packit 8cb997
            #        "DNS discovery failed to determine your DNS domain")
Packit 8cb997
            #    cli_domain = user_input(
Packit 8cb997
            #        "Provide the domain name of your IPA server "
Packit 8cb997
            #        "(ex: example.com)",
Packit 8cb997
            #        allow_empty=False)
Packit 8cb997
            #    cli_domain_source = 'Provided interactively'
Packit 8cb997
            #    logger.debug(
Packit 8cb997
            #        "will use interactively provided domain: %s", cli_domain)
Packit 8cb997
            ret = ds.search(
Packit 8cb997
                domain=cli_domain,
Packit 8cb997
                servers=options.server,
Packit 8cb997
                hostname=hostname,
Packit 8cb997
                ca_cert_path=get_cert_path(options.ca_cert_file))
Packit 8cb997
Packit 8cb997
        if not cli_domain:
Packit 8cb997
            if ds.domain:
Packit 8cb997
                cli_domain = ds.domain
Packit 8cb997
                cli_domain_source = ds.domain_source
Packit 8cb997
                logger.debug("will use discovered domain: %s", cli_domain)
Packit 8cb997
Packit 8cb997
        client_domain = hostname[hostname.find(".")+1:]
Packit 8cb997
Packit 8cb997
        if ret in (ipadiscovery.NO_LDAP_SERVER, ipadiscovery.NOT_IPA_SERVER) \
Packit 8cb997
                or not ds.server:
Packit 8cb997
            logger.debug("IPA Server not found")
Packit 8cb997
            if options.server:
Packit 8cb997
                cli_server = options.server
Packit 8cb997
                cli_server_source = 'Provided as option'
Packit 8cb997
            elif options.unattended:
Packit 8cb997
                raise ScriptError(
Packit 8cb997
                    "Unable to find IPA Server to join",
Packit 8cb997
                    rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
            else:
Packit 8cb997
                raise ScriptError("No interactive installation")
Packit 8cb997
            #    logger.debug("DNS discovery failed to find the IPA Server")
Packit 8cb997
            #    cli_server = [
Packit 8cb997
            #        user_input(
Packit 8cb997
            #            "Provide your IPA server name (ex: ipa.example.com)",
Packit 8cb997
            #            allow_empty=False)
Packit 8cb997
            #    ]
Packit 8cb997
            #    cli_server_source = 'Provided interactively'
Packit 8cb997
            #    logger.debug(
Packit 8cb997
            #      "will use interactively provided server: %s", cli_server[0])
Packit 8cb997
            ret = ds.search(
Packit 8cb997
                domain=cli_domain,
Packit 8cb997
                servers=cli_server,
Packit 8cb997
                hostname=hostname,
Packit 8cb997
                ca_cert_path=get_cert_path(options.ca_cert_file))
Packit 8cb997
Packit 8cb997
        else:
Packit 8cb997
            # Only set dnsok to True if we were not passed in one or more
Packit 8cb997
            # servers and if DNS discovery actually worked.
Packit 8cb997
            if not options.server:
Packit 8cb997
                (server, domain) = ds.check_domain(
Packit 8cb997
                    ds.domain, set(), "Validating DNS Discovery")
Packit 8cb997
                if server and domain:
Packit 8cb997
                    logger.debug("DNS validated, enabling discovery")
Packit 8cb997
                    dnsok = True
Packit 8cb997
                else:
Packit 8cb997
                    logger.debug("DNS discovery failed, disabling discovery")
Packit 8cb997
            else:
Packit 8cb997
                logger.debug(
Packit 8cb997
                    "Using servers from command line, disabling DNS discovery")
Packit 8cb997
Packit 8cb997
        if not cli_server:
Packit 8cb997
            if options.server:
Packit 8cb997
                cli_server = ds.servers
Packit 8cb997
                cli_server_source = 'Provided as option'
Packit 8cb997
                logger.debug(
Packit 8cb997
                    "will use provided server: %s", ', '.join(options.server))
Packit 8cb997
            elif ds.server:
Packit 8cb997
                cli_server = ds.servers
Packit 8cb997
                cli_server_source = ds.server_source
Packit 8cb997
                logger.debug("will use discovered server: %s", cli_server[0])
Packit 8cb997
Packit 8cb997
        if ret == ipadiscovery.NOT_IPA_SERVER:
Packit 8cb997
            logger.error("%s is not an IPA v2 Server.", cli_server[0])
Packit 8cb997
            print_port_conf_info()
Packit 8cb997
            logger.debug("(%s: %s)", cli_server[0], cli_server_source)
Packit 8cb997
            raise ScriptError("%s is not an IPA v2 Server." % cli_server[0],
Packit 8cb997
                              rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
        if ret == ipadiscovery.NO_ACCESS_TO_LDAP:
Packit 8cb997
            logger.warning("Anonymous access to the LDAP server is disabled.")
Packit 8cb997
            logger.info("Proceeding without strict verification.")
Packit 8cb997
            logger.info(
Packit 8cb997
                "Note: This is not an error if anonymous access "
Packit 8cb997
                "has been explicitly restricted.")
Packit 8cb997
            ret = 0
Packit 8cb997
Packit 8cb997
        if ret == ipadiscovery.NO_TLS_LDAP:
Packit 8cb997
            logger.warning(
Packit 8cb997
                "The LDAP server requires TLS is but we do not have the CA.")
Packit 8cb997
            logger.info("Proceeding without strict verification.")
Packit 8cb997
            ret = 0
Packit 8cb997
Packit 8cb997
        if ret != 0:
Packit 8cb997
            logger.error(
Packit 8cb997
                "Failed to verify that %s is an IPA Server.",
Packit 8cb997
                cli_server[0])
Packit 8cb997
            logger.error(
Packit 8cb997
                "This may mean that the remote server is not up "
Packit 8cb997
                "or is not reachable due to network or firewall settings.")
Packit 8cb997
            print_port_conf_info()
Packit 8cb997
            logger.debug("(%s: %s)", cli_server[0], cli_server_source)
Packit 8cb997
            raise ScriptError("Failed to verify that %s is an IPA Server." %
Packit 8cb997
                              cli_server[0],
Packit 8cb997
                              rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
        cli_kdc = ds.kdc
Packit 8cb997
        if dnsok and not cli_kdc:
Packit 8cb997
            logger.error(
Packit 8cb997
                "DNS domain '%s' is not configured for automatic "
Packit 8cb997
                "KDC address lookup.", ds.realm.lower())
Packit 8cb997
            logger.debug("(%s: %s)", ds.realm, ds.realm_source)
Packit 8cb997
            logger.error("KDC address will be set to fixed value.")
Packit 8cb997
Packit 8cb997
        if dnsok:
Packit 8cb997
            logger.info("Discovery was successful!")
Packit 8cb997
        elif not options.unattended:
Packit 8cb997
            raise ScriptError("No interactive installation")
Packit 8cb997
        # if not options.server:
Packit 8cb997
        #     logger.warning(
Packit 8cb997
        #       "The failure to use DNS to find your IPA "
Packit 8cb997
        #       "server indicates that your resolv.conf file is not properly "
Packit 8cb997
        #       "configured.")
Packit 8cb997
        # logger.info(
Packit 8cb997
        #     "Autodiscovery of servers for failover cannot work "
Packit 8cb997
        #     "with this configuration.")
Packit 8cb997
        # logger.info(
Packit 8cb997
        #   "If you proceed with the installation, services "
Packit 8cb997
        #   "will be configured to always access the discovered server for "
Packit 8cb997
        #   "all operations and will not fail over to other servers in case "
Packit 8cb997
        #   "of failure.")
Packit 8cb997
        # if not user_input(
Packit 8cb997
        #     "Proceed with fixed values and no DNS discovery?", False):
Packit 8cb997
        #     raise ScriptError(rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
        # Do not ask for time source
Packit 8cb997
        # if options.conf_ntp:
Packit 8cb997
        #     if not options.on_master and not options.unattended and not (
Packit 8cb997
        #             options.ntp_servers or options.ntp_pool):
Packit 8cb997
        #         options.ntp_servers, options.ntp_pool = \
Packit 8cb997
        #             timeconf.get_time_source()
Packit 8cb997
Packit 8cb997
        cli_realm = ds.realm
Packit 8cb997
        cli_realm_source = ds.realm_source
Packit 8cb997
        logger.debug("will use discovered realm: %s", cli_realm)
Packit 8cb997
Packit 8cb997
        if options.realm_name and options.realm_name != cli_realm:
Packit 8cb997
            logger.error(
Packit 8cb997
                "The provided realm name [%s] does not match discovered "
Packit 8cb997
                "one [%s]",
Packit 8cb997
                options.realm_name, cli_realm)
Packit 8cb997
            logger.debug("(%s: %s)", cli_realm, cli_realm_source)
Packit 8cb997
            raise ScriptError(
Packit 8cb997
                "The provided realm name [%s] does not match discovered "
Packit 8cb997
                "one [%s]" % (options.realm_name, cli_realm),
Packit 8cb997
                rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
        cli_basedn = ds.basedn
Packit 8cb997
        cli_basedn_source = ds.basedn_source
Packit 8cb997
        logger.debug("will use discovered basedn: %s", cli_basedn)
Packit 8cb997
        # subject_base = DN(('O', cli_realm))
Packit 8cb997
Packit 8cb997
        logger.info("Client hostname: %s", hostname)
Packit 8cb997
        logger.debug("Hostname source: %s", hostname_source)
Packit 8cb997
        logger.info("Realm: %s", cli_realm)
Packit 8cb997
        logger.debug("Realm source: %s", cli_realm_source)
Packit 8cb997
        logger.info("DNS Domain: %s", cli_domain)
Packit 8cb997
        logger.debug("DNS Domain source: %s", cli_domain_source)
Packit 8cb997
        logger.info("IPA Server: %s", ', '.join(cli_server))
Packit 8cb997
        logger.debug("IPA Server source: %s", cli_server_source)
Packit 8cb997
        logger.info("BaseDN: %s", cli_basedn)
Packit 8cb997
        logger.debug("BaseDN source: %s", cli_basedn_source)
Packit 8cb997
Packit 8cb997
        if not options.on_master:
Packit 8cb997
            if options.ntp_servers:
Packit 8cb997
                for server in options.ntp_servers:
Packit 8cb997
                    logger.info("NTP server: %s", server)
Packit 8cb997
Packit 8cb997
            if options.ntp_pool:
Packit 8cb997
                logger.info("NTP pool: %s", options.ntp_pool)
Packit 8cb997
Packit 8cb997
        # ipa-join would fail with IP address instead of a FQDN
Packit 8cb997
        for srv in cli_server:
Packit 8cb997
            try:
Packit 8cb997
                socket.inet_pton(socket.AF_INET, srv)
Packit 8cb997
                is_ipaddr = True
Packit 8cb997
            except socket.error:
Packit 8cb997
                try:
Packit 8cb997
                    socket.inet_pton(socket.AF_INET6, srv)
Packit 8cb997
                    is_ipaddr = True
Packit 8cb997
                except socket.error:
Packit 8cb997
                    is_ipaddr = False
Packit 8cb997
Packit 8cb997
            if is_ipaddr:
Packit 8cb997
                logger.info()
Packit 8cb997
                logger.warning(
Packit 8cb997
                    "It seems that you are using an IP address "
Packit 8cb997
                    "instead of FQDN as an argument to --server. The "
Packit 8cb997
                    "installation may fail.")
Packit 8cb997
                break
Packit 8cb997
Packit 8cb997
        # logger.info()
Packit 8cb997
        # if not options.unattended and not user_input(
Packit 8cb997
        #     "Continue to configure the system with these values?", False):
Packit 8cb997
        #     raise ScriptError(rval=CLIENT_INSTALL_ERROR)
Packit 8cb997
Packit 8cb997
    except ScriptError as e:
Packit 8cb997
        module.fail_json(msg=str(e))
Packit 8cb997
Packit 8cb997
    #########################################################################
Packit 8cb997
Packit 8cb997
    # client._install
Packit 8cb997
Packit 8cb997
    # May not happen in here at this time
Packit 8cb997
    # if not options.on_master:
Packit 8cb997
    #     # Try removing old principals from the keytab
Packit 8cb997
    #     purge_host_keytab(cli_realm)
Packit 8cb997
Packit 8cb997
    # Check if ipa client is already configured
Packit 8cb997
    if is_client_configured():
Packit 8cb997
        client_already_configured = True
Packit 8cb997
Packit 8cb997
        # Check that realm and domain match
Packit 8cb997
        current_config = get_ipa_conf()
Packit 8cb997
        if cli_domain != current_config.get('domain'):
Packit 8cb997
            module.fail_json(msg="IPA client already installed "
Packit 8cb997
                             "with a conflicting domain")
Packit 8cb997
        if cli_realm != current_config.get('realm'):
Packit 8cb997
            module.fail_json(msg="IPA client already installed "
Packit 8cb997
                             "with a conflicting realm")
Packit 8cb997
    else:
Packit 8cb997
        client_already_configured = False
Packit 8cb997
Packit 8cb997
    # Done
Packit 8cb997
    module.exit_json(changed=False,
Packit 8cb997
                     servers=cli_server,
Packit 8cb997
                     domain=cli_domain,
Packit 8cb997
                     realm=cli_realm,
Packit 8cb997
                     kdc=cli_kdc,
Packit 8cb997
                     basedn=str(cli_basedn),
Packit 8cb997
                     hostname=hostname,
Packit 8cb997
                     client_domain=client_domain,
Packit 8cb997
                     dnsok=dnsok,
Packit 8cb997
                     sssd=options.sssd,
Packit 8cb997
                     ntp_servers=options.ntp_servers,
Packit 8cb997
                     ntp_pool=options.ntp_pool,
Packit 8cb997
                     client_already_configured=client_already_configured,
Packit 8cb997
                     ipa_python_version=IPA_PYTHON_VERSION)
Packit 8cb997
Packit 8cb997
Packit 8cb997
if __name__ == '__main__':
Packit 8cb997
    main()