From 6dabe6ebb28c9972cedc3fb7cc1e59ddd8e5e5b6 Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Thu, 28 May 2015 06:05:28 +0200 Subject: install: Move ipa-server-install code into a module https://fedorahosted.org/freeipa/ticket/4468 Reviewed-By: Martin Basti --- install/tools/ipa-server-install | 1069 +----------------------------- ipaserver/install/server/__init__.py | 3 + ipaserver/install/server/install.py | 1209 ++++++++++++++++++++++++++++++++++ 3 files changed, 1239 insertions(+), 1042 deletions(-) create mode 100644 ipaserver/install/server/install.py diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install index c7d7c7bff..c7fa5ae17 100755 --- a/install/tools/ipa-server-install +++ b/install/tools/ipa-server-install @@ -28,63 +28,25 @@ import sys import os -import grp import signal -import shutil -import pickle import random -import tempfile -import nss.error -import base64 -import pwd -import textwrap from optparse import OptionGroup, OptionValueError, SUPPRESS_HELP -try: - from ipaserver.install import adtrustinstance - _server_trust_ad_installed = True -except ImportError: - _server_trust_ad_installed = False - -from ipaserver.install import dsinstance -from ipaserver.install import krbinstance from ipaserver.install import bindinstance -from ipaserver.install import httpinstance -from ipaserver.install import ntpinstance -from ipaserver.install import certs -from ipaserver.install import cainstance -from ipaserver.install import memcacheinstance -from ipaserver.install import otpdinstance -from ipaserver.install import sysupgrade -from ipaserver.install import replication -from ipaserver.install import dns as dns_installer -from ipaserver.install import service, installutils -from ipaserver.install import kra +from ipaserver.install import installutils +from ipaserver.install import server +from ipaserver.install.server import ( + validate_dm_password, validate_admin_password) from ipapython import version -from ipapython import certmonger -from ipapython import ipaldap -from ipaserver.install.installutils import * -from ipaserver.plugins.ldap2 import ldap2 -from ipapython import sysrestore -from ipapython.ipautil import * -from ipapython import ipautil -from ipapython import dogtag -from ipalib import api, errors, util, x509, constants +from ipalib import constants from ipapython.config import IPAOptionParser from ipalib.util import validate_domain_name -from ipalib.constants import CACERT -from ipapython.ipa_log_manager import * +from ipapython.ipa_log_manager import root_logger, standard_logging_setup from ipapython.dn import DN -import ipaclient.ntpconf -from ipaplatform.tasks import tasks -from ipaplatform import services from ipaplatform.paths import paths -uninstalling = False -installation_cleanup = True - VALID_SUBJECT_ATTRS = ['st', 'o', 'ou', 'dnqualifier', 'c', 'serialnumber', 'l', 'title', 'sn', 'givenname', 'initials', 'generationqualifier', 'dc', 'mail', @@ -93,7 +55,6 @@ VALID_SUBJECT_ATTRS = ['st', 'o', 'ou', 'dnqualifier', 'c', 'incorporationlocality', 'incorporationstate', 'incorporationcountry', 'businesscategory'] -SYSRESTORE_DIR_PATH = paths.SYSRESTORE def subject_callback(option, opt_str, value, parser): """ @@ -113,43 +74,6 @@ def subject_callback(option, opt_str, value, parser): raise OptionValueError('%s=%s has invalid subject base format: %s' % (opt_str, value, e)) parser.values.subject = dn -def validate_dm_password(password): - if len(password) < 8: - raise ValueError("Password must be at least 8 characters long") - if any(ord(c) < 0x20 for c in password): - raise ValueError("Password must not contain control characters") - if any(ord(c) >= 0x7F for c in password): - raise ValueError("Password must only contain ASCII characters") - - # Disallow characters that pkisilent doesn't process properly: - bad_characters = '\\' - if any(c in bad_characters for c in password): - raise ValueError('Password must not contain these characters: %s' % - ', '.join('"%s"' % c for c in bad_characters)) - - # TODO: Check https://fedorahosted.org/389/ticket/47849 - # Actual behavior of setup-ds.pl is that it does not accept white - # space characters in password when called interactively but does when - # provided such password in INF file. But it ignores leading and trailing - # white spaces in INF file. - - # Disallow leading/trailing whaitespaces - if password.strip() != password: - raise ValueError('Password must not start or end with whitespace.') - -def validate_admin_password(password): - if len(password) < 8: - raise ValueError("Password must be at least 8 characters long") - if any(ord(c) < 0x20 for c in password): - raise ValueError("Password must not contain control characters") - if any(ord(c) >= 0x7F for c in password): - raise ValueError("Password must only contain ASCII characters") - - # Disallow characters that pkisilent doesn't process properly: - bad_characters = '\\' - if any(c in bad_characters for c in password): - raise ValueError('Password must not contain these characters: %s' % - ', '.join('"%s"' % c for c in bad_characters)) def parse_options(): # Guaranteed to give a random 200k range below the 2G mark (uint32_t limit) @@ -418,986 +342,47 @@ def parse_options(): return safe_options, options -def signal_handler(signum, frame): - global ds - print "\nCleaning up..." - if ds: - print "Removing configuration for %s instance" % ds.serverid - ds.stop() - if ds.serverid: - try: - dsinstance.remove_ds_instance(ds.serverid) - except ipautil.CalledProcessError: - root_logger.error("Failed to remove DS instance. You may " - "need to remove instance data manually") - sys.exit(1) - -def read_cache(dm_password): - """ - Returns a dict of cached answers or empty dict if no cache file exists. - """ - if not ipautil.file_exists(paths.ROOT_IPA_CACHE): - return {} - - top_dir = tempfile.mkdtemp("ipa") - fname = "%s/cache" % top_dir - try: - decrypt_file(paths.ROOT_IPA_CACHE, fname, dm_password, top_dir) - except Exception, e: - shutil.rmtree(top_dir) - raise Exception("Decryption of answer cache in %s failed, please check your password." % paths.ROOT_IPA_CACHE) - - try: - with open(fname, 'rb') as f: - try: - optdict = pickle.load(f) - except Exception, e: - raise Exception("Parse error in %s: %s" % (paths.ROOT_IPA_CACHE, str(e))) - except IOError, e: - raise Exception("Read error in %s: %s" % (paths.ROOT_IPA_CACHE, str(e))) - finally: - shutil.rmtree(top_dir) - - # These are the only ones that may be overridden - try: - del optdict['external_cert_files'] - except KeyError: - pass - - return optdict - -def write_cache(options): - """ - Takes a dict as input and writes a cached file of answers - """ - top_dir = tempfile.mkdtemp("ipa") - fname = "%s/cache" % top_dir - try: - with open(fname, 'wb') as f: - pickle.dump(options, f) - ipautil.encrypt_file(fname, paths.ROOT_IPA_CACHE, options['dm_password'], top_dir) - except IOError, e: - raise Exception("Unable to cache command-line options %s" % str(e)) - finally: - shutil.rmtree(top_dir) - -def read_host_name(host_default,no_host_dns=False): - host_name = "" - - print "Enter the fully qualified domain name of the computer" - print "on which you're setting up server software. Using the form" - print "." - print "Example: master.example.com." - print "" - print "" - if host_default == "": - host_default = "master.example.com" - host_name = user_input("Server host name", host_default, allow_empty = False) - print "" - verify_fqdn(host_name,no_host_dns) - - return host_name - -def read_domain_name(domain_name, unattended): - print "The domain name has been determined based on the host name." - print "" - if not unattended: - domain_name = user_input("Please confirm the domain name", domain_name) - print "" - return domain_name - -def read_realm_name(domain_name, unattended): - print "The kerberos protocol requires a Realm name to be defined." - print "This is typically the domain name converted to uppercase." - print "" - - if unattended: - return domain_name.upper() - realm_name = user_input("Please provide a realm name", domain_name.upper()) - upper_dom = realm_name.upper() #pylint: disable=E1103 - if upper_dom != realm_name: - print "An upper-case realm name is required." - if not user_input("Do you want to use " + upper_dom + " as realm name?", True): - print "" - print "An upper-case realm name is required. Unable to continue." - sys.exit(1) - else: - realm_name = upper_dom - print "" - return realm_name - - -def read_dm_password(): - print "Certain directory server operations require an administrative user." - print "This user is referred to as the Directory Manager and has full access" - print "to the Directory for system management tasks and will be added to the" - print "instance of directory server created for IPA." - print "The password must be at least 8 characters long." - print "" - #TODO: provide the option of generating a random password - dm_password = read_password("Directory Manager", validator=validate_dm_password) - return dm_password - -def read_admin_password(): - print "The IPA server requires an administrative user, named 'admin'." - print "This user is a regular system account used for IPA server administration." - print "" - #TODO: provide the option of generating a random password - admin_password = read_password("IPA admin", validator=validate_admin_password) - return admin_password - -def check_dirsrv(unattended): - (ds_unsecure, ds_secure) = dsinstance.check_ports() - if not ds_unsecure or not ds_secure: - print "IPA requires ports 389 and 636 for the Directory Server." - print "These are currently in use:" - if not ds_unsecure: - print "\t389" - if not ds_secure: - print "\t636" - sys.exit(1) - -def uninstall(): - - rv = 0 - - print "Shutting down all IPA services" - try: - (stdout, stderr, rc) = run([paths.IPACTL, "stop"], raiseonerr=False) - except Exception, e: - pass - - # Need to get dogtag info before /etc/ipa/default.conf is removed - dogtag_constants = dogtag.configured_constants() - - print "Removing IPA client configuration" - try: - (stdout, stderr, rc) = run([paths.IPA_CLIENT_INSTALL, "--on-master", "--unattended", "--uninstall"], raiseonerr=False) - if rc not in [0,2]: - root_logger.debug("ipa-client-install returned %d" % rc) - raise RuntimeError(stdout) - except Exception, e: - rv = 1 - print "Uninstall of client side components failed!" - print "ipa-client-install returned: " + str(e) - - ntpinstance.NTPInstance(fstore).uninstall() - if not dogtag_constants.SHARED_DB: - cads_instance = cainstance.CADSInstance( - dogtag_constants=dogtag_constants) - if cads_instance.is_configured(): - cads_instance.uninstall() - - kra.uninstall() - - ca_instance = cainstance.CAInstance( - api.env.realm, certs.NSS_DIR, dogtag_constants=dogtag_constants) - ca_instance.stop_tracking_certificates() - if ca_instance.is_configured(): - ca_instance.uninstall() - - dns_installer.uninstall() - - httpinstance.HTTPInstance(fstore).uninstall() - krbinstance.KrbInstance(fstore).uninstall() - dsinstance.DsInstance(fstore=fstore).uninstall() - if _server_trust_ad_installed: - adtrustinstance.ADTRUSTInstance(fstore).uninstall() - memcacheinstance.MemcacheInstance().uninstall() - otpdinstance.OtpdInstance().uninstall() - tasks.restore_network_configuration(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.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() - - ipautil.restore_hostname(sstore) - - # 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, dogtag_constants.ALIAS_DIR, certs.NSS_DIR] - ids = certmonger.check_state(dirs) - if ids: - root_logger.error('Some certificates may still be tracked by certmonger.\nThis will cause re-installation to fail.\nStart the certmonger service and list the certificates being tracked\n # getcert list\nThese may be untracked by executing\n # getcert stop-tracking -i \nfor each id in: %s' % ', '.join(ids)) - - return rv - -def set_subject_in_config(realm_name, dm_password, suffix, subject_base): - ldapuri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % ( - installutils.realm_to_serverid(realm_name) - ) - try: - conn = ldap2(shared_instance=False, ldap_uri=ldapuri, base_dn=suffix) - conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=dm_password) - except errors.ExecutionError, e: - root_logger.critical("Could not connect to the Directory Server on %s" % realm_name) - raise e - entry_attrs = conn.get_ipa_config() - if 'ipacertificatesubjectbase' not in entry_attrs: - entry_attrs['ipacertificatesubjectbase'] = [str(subject_base)] - conn.update_entry(entry_attrs) - conn.disconnect() +def signal_handler(signum, frame): + raise KeyboardInterrupt def main(): - global ds - global uninstalling - global installation_cleanup - ds = None - safe_options, options = parse_options() if os.getegid() != 0: sys.exit("Must be root to set up server") - tasks.check_selinux_status() - signal.signal(signal.SIGTERM, signal_handler) signal.signal(signal.SIGINT, signal_handler) - if options.master_password: - msg = ("WARNING:\noption '-P/--master-password' is deprecated. " - "KDC master password of sufficient strength is autogenerated " - "during IPA server installation and should not be set " - "manually.") - print textwrap.fill(msg, width=79, replace_whitespace=False) - if options.uninstall: - uninstalling = True - standard_logging_setup(paths.IPASERVER_UNINSTALL_LOG, debug=options.debug) - installation_cleanup = False + if not options.uninstall: + standard_logging_setup(paths.IPASERVER_INSTALL_LOG, + debug=options.debug) else: - standard_logging_setup(paths.IPASERVER_INSTALL_LOG, debug=options.debug) - print "\nThe log file for this installation can be found in /var/log/ipaserver-install.log" - if not options.external_ca and not options.external_cert_files and is_ipa_configured(): - installation_cleanup = False - sys.exit("IPA server is already configured on this system.\n" + - "If you want to reinstall the IPA server, please uninstall " + - "it first using 'ipa-server-install --uninstall'.") - - client_fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE) - if client_fstore.has_files(): - installation_cleanup = False - sys.exit("IPA client is already configured on this system.\n" + - "Please uninstall it before configuring the IPA server, " + - "using 'ipa-client-install --uninstall'") + standard_logging_setup(paths.IPASERVER_UNINSTALL_LOG, + debug=options.debug) root_logger.debug('%s was invoked with options: %s' % (sys.argv[0], safe_options)) root_logger.debug("missing options might be asked for interactively later\n") root_logger.debug('IPA version %s' % version.VENDOR_VERSION) - global fstore - fstore = sysrestore.FileStore(SYSRESTORE_DIR_PATH) - global sstore - sstore = sysrestore.StateFile(SYSRESTORE_DIR_PATH) - - # Configuration for ipalib, we will bootstrap and finalize later, after - # we are sure we have the configuration file ready. - cfg = dict( - context='installer', - in_server=True, - debug=options.debug - ) - - if options.uninstall: - - # We will need at least api.env, finalize api now. This system is - # already installed, so the configuration file is there. - api.bootstrap(**cfg) - api.finalize() - - if not options.unattended: - print "\nThis is a NON REVERSIBLE operation and will delete all data and configuration!\n" - if not user_input("Are you sure you want to continue with the uninstall procedure?", False): - print "" - print "Aborting uninstall operation." - sys.exit(1) - - try: - conn = ipaldap.IPAdmin( - api.env.host, - ldapi=True, - realm=api.env.realm - ) - conn.do_external_bind(pwd.getpwuid(os.geteuid()).pw_name) - except Exception: - msg = ("\nWARNING: Failed to connect to Directory Server to find " - "information about replication agreements. Uninstallation " - "will continue despite the possible existing replication " - "agreements.\n\n") - print textwrap.fill(msg, width=80, replace_whitespace=False) - else: - api.Backend.ldap2.connect(autobind=True) - dns_installer.uninstall_check(options) - - rm = replication.ReplicationManager( - realm=api.env.realm, - hostname=api.env.host, - dirman_passwd=None, - conn=conn - ) - agreements = rm.find_ipa_replication_agreements() - - if agreements: - other_masters = [a.get('cn')[0][4:] for a in agreements] - msg = ( - "\nReplication agreements with the following IPA masters " - "found: %s. Removing any replication agreements before " - "uninstalling the server is strongly recommended. You can " - "remove replication agreements by running the following " - "command on any other IPA master:\n" % ", ".join( - other_masters) - ) - cmd = "$ ipa-replica-manage del %s\n" % api.env.host - print textwrap.fill(msg, width=80, replace_whitespace=False) - print cmd - if not (options.unattended or user_input("Are you sure you " - "want to continue " - "with the uninstall " - "procedure?", - False)): - print "" - print "Aborting uninstall operation." - sys.exit(1) - - return uninstall() - - if options.external_ca: - if cainstance.is_step_one_done(): - print ("CA is already installed.\nRun the installer with " - "--external-cert-file.") - sys.exit(1) - if ipautil.file_exists(paths.ROOT_IPA_CSR): - print ("CA CSR file %s already exists.\nIn order to continue " - "remove the file and run the installer again." % - paths.ROOT_IPA_CSR) - sys.exit(1) - elif options.external_cert_files: - if not cainstance.is_step_one_done(): - # This can happen if someone passes external_ca_file without - # already having done the first stage of the CA install. - print ("CA is not installed yet. To install with an external CA " - "is a two-stage process.\nFirst run the installer with " - "--external-ca.") - sys.exit(1) - - # This will override any settings passed in on the cmdline - if ipautil.file_exists(paths.ROOT_IPA_CACHE): - if options.dm_password is not None: - dm_password = options.dm_password - else: - dm_password = read_password("Directory Manager", confirm=False) - if dm_password is None: - sys.exit("Directory Manager password required") - try: - options._update_loose(read_cache(dm_password)) - except Exception, e: - sys.exit("Cannot process the cache file: %s" % str(e)) - - if options.external_cert_files: - external_cert_file, external_ca_file = load_external_cert( - options.external_cert_files, options.subject) - - # We only set up the CA if the PKCS#12 options are not given. - if options.dirsrv_cert_files: - setup_ca = False - setup_kra = False - else: - setup_ca = True - # setup_kra is set to False until Dogtag 10.2 is available for IPA to consume - # Until then users that want to install the KRA need to use ipa-install-kra - # TODO set setup_kra = True when Dogtag 10.2 is available - setup_kra = False - options.setup_ca = setup_ca - - # Figure out what external CA step we're in. See cainstance.py for more - # info on the 3 states. - if options.external_cert_files: - external = 2 - elif options.external_ca: - external = 1 - else: - external = 0 - - print "==============================================================================" - print "This program will set up the FreeIPA Server." - print "" - print "This includes:" - if setup_ca: - print " * Configure a stand-alone CA (dogtag) for certificate management" - if setup_kra: - print " * Configure a stand-alone KRA (dogtag) for key storage" - if options.conf_ntp: - print " * Configure the Network Time Daemon (ntpd)" - print " * Create and configure an instance of Directory Server" - print " * Create and configure a Kerberos Key Distribution Center (KDC)" - print " * Configure Apache (httpd)" - if options.setup_dns: - print " * Configure DNS (bind)" - if options.setup_pkinit: - print " * Configure the KDC to enable PKINIT" - if not options.conf_ntp: - print "" - print "Excluded by options:" - print " * Configure the Network Time Daemon (ntpd)" - if not options.unattended: - print "" - print "To accept the default shown in brackets, press the Enter key." - print "" - - if external != 2: - # Make sure the 389-ds ports are available - check_dirsrv(options.unattended) - - if setup_ca: - if not cainstance.check_port(): - print ("IPA requires port 8443 for PKI but it is currently in " - "use.") - sys.exit("Aborting installation") - - if options.conf_ntp: - try: - ipaclient.ntpconf.check_timedate_services() - except ipaclient.ntpconf.NTPConflictingService, e: - print "WARNING: conflicting time&date synchronization service '%s'" \ - " will be disabled" % e.conflicting_service - print "in favor of ntpd" - print "" - except ipaclient.ntpconf.NTPConfigurationError: - pass - - # Check to see if httpd is already configured to listen on 443 - if httpinstance.httpd_443_configured(): - sys.exit("Aborting installation") - - reverse_zones = [] - - if not options.setup_dns and not options.unattended: - if ipautil.user_input("Do you want to configure integrated DNS (BIND)?", False): - options.setup_dns = True - print "" - - # check bind packages are installed - if options.setup_dns: - # Don't require an external DNS to say who we are if we are - # setting up a local DNS server. - options.no_host_dns = True - - # check the hostname is correctly configured, it must be as the kldap - # utilities just use the hostname as returned by getaddrinfo to set - # up some of the standard entries - - host_default = "" - if options.host_name: - host_default = options.host_name - else: - host_default = get_fqdn() - - try: - if options.unattended or options.host_name: - verify_fqdn(host_default,options.no_host_dns) - host_name = host_default - else: - host_name = read_host_name(host_default,options.no_host_dns) - except BadHostError, e: - sys.exit(str(e) + "\n") - - host_name = host_name.lower() - root_logger.debug("will use host_name: %s\n" % host_name) - - system_hostname = get_fqdn() - if host_name != system_hostname: - print >>sys.stderr - print >>sys.stderr, "Warning: hostname %s does not match system hostname %s." \ - % (host_name, system_hostname) - print >>sys.stderr, "System hostname will be updated during the installation process" - print >>sys.stderr, "to prevent service failures." - print >>sys.stderr - - if not options.domain_name: - domain_name = read_domain_name(host_name[host_name.find(".")+1:], options.unattended) - root_logger.debug("read domain_name: %s\n" % domain_name) - try: - validate_domain_name(domain_name) - except ValueError, e: - sys.exit("Invalid domain name: %s" % unicode(e)) - else: - domain_name = options.domain_name - - domain_name = domain_name.lower() # pylint: disable=E1103 - - if not options.realm_name: - realm_name = read_realm_name(domain_name, options.unattended) - root_logger.debug("read realm_name: %s\n" % realm_name) - else: - realm_name = options.realm_name.upper() - - if not options.subject: - options.subject = DN(('O', realm_name)) - - if options.http_cert_files: - if options.http_pin is None: - options.http_pin = installutils.read_password( - "Enter Apache Server private key unlock", - confirm=False, validate=False) - if options.http_pin is None: - sys.exit( - "Apache Server private key unlock password required") - http_pkcs12_file, http_pin, http_ca_cert = load_pkcs12( - cert_files=options.http_cert_files, - key_password=options.http_pin, - key_nickname=options.http_cert_name, - ca_cert_files=options.ca_cert_files, - host_name=host_name) - http_pkcs12_info = (http_pkcs12_file.name, http_pin) - - if options.dirsrv_cert_files: - if options.dirsrv_pin is None: - options.dirsrv_pin = read_password( - "Enter Directory Server private key unlock", - confirm=False, validate=False) - if options.dirsrv_pin is None: - sys.exit( - "Directory Server private key unlock password required") - dirsrv_pkcs12_file, dirsrv_pin, dirsrv_ca_cert = load_pkcs12( - cert_files=options.dirsrv_cert_files, - key_password=options.dirsrv_pin, - key_nickname=options.dirsrv_cert_name, - ca_cert_files=options.ca_cert_files, - host_name=host_name) - dirsrv_pkcs12_info = (dirsrv_pkcs12_file.name, dirsrv_pin) - - if options.pkinit_cert_files: - if options.pkinit_pin is None: - options.pkinit_pin = read_password( - "Enter Kerberos KDC private key unlock", - confirm=False, validate=False) - if options.pkinit_pin is None: - sys.exit( - "Kerberos KDC private key unlock password required") - pkinit_pkcs12_file, pkinit_pin, pkinit_ca_cert = load_pkcs12( - cert_files=options.pkinit_cert_files, - key_password=options.pkinit_pin, - key_nickname=options.pkinit_cert_name, - ca_cert_files=options.ca_cert_files, - host_name=host_name) - pkinit_pkcs12_info = (pkinit_pkcs12_file.name, pkinit_pin) - - if (options.http_cert_files and options.dirsrv_cert_files and - http_ca_cert != dirsrv_ca_cert): - sys.exit("Apache Server SSL certificate and Directory Server SSL " - "certificate are not signed by the same CA certificate") - - if not options.dm_password: - dm_password = read_dm_password() - - if dm_password is None: - sys.exit("Directory Manager password required") - else: - dm_password = options.dm_password - - if not options.master_password: - master_password = ipa_generate_password() - else: - master_password = options.master_password - - if not options.admin_password: - admin_password = read_admin_password() - if admin_password is None: - sys.exit("IPA admin password required") - else: - admin_password = options.admin_password - - if setup_kra: - try: - kra.install_check(None, options, False, - dogtag.install_constants.DOGTAG_VERSION) - except RuntimeError as e: - print str(e) - exit(1) - - if options.setup_dns: - dns_installer.install_check(False, False, options, host_name) - ip_addresses = dns_installer.ip_addresses - else: - ip_addresses = get_server_ip_address(host_name, fstore, - options.unattended, False, options.ip_addresses) - - print - print "The IPA Master Server will be configured with:" - print "Hostname: %s" % host_name - print "IP address(es): %s" % ", ".join(str(ip) for ip in ip_addresses) - print "Domain name: %s" % domain_name - print "Realm name: %s" % realm_name - print - - if options.setup_dns: - print "BIND DNS server will be configured to serve IPA domain with:" - print "Forwarders: %s" % ( - "No forwarders" if not dns_installer.dns_forwarders - else ", ".join([str(ip) for ip in dns_installer.dns_forwarders]) - ) - print "Reverse zone(s): %s" % ( - "No reverse zone" if options.no_reverse - or not dns_installer.reverse_zones - else ", ".join(str(rz) for rz in dns_installer.reverse_zones) - ) - print - - # If domain name and realm does not match, IPA server will not be able - # to estabilish trust with Active Directory. Print big fat warning. - - realm_not_matching_domain = (domain_name.upper() != realm_name) - - if realm_not_matching_domain: - print("WARNING: Realm name does not match the domain name.\n" - "You will not be able to estabilish trusts with Active " - "Directory unless\nthe realm name of the IPA server matches " - "its domain name.\n\n") - - if not options.unattended and not user_input("Continue to configure the system with these values?", False): - sys.exit("Installation aborted") - - # Installation has started. No IPA sysrestore items are restored in case of - # failure to enable root cause investigation - installation_cleanup = False - - # Create the management framework config file and finalize api - target_fname = paths.IPA_DEFAULT_CONF - fd = open(target_fname, "w") - fd.write("[global]\n") - fd.write("host=%s\n" % host_name) - fd.write("basedn=%s\n" % ipautil.realm_to_suffix(realm_name)) - fd.write("realm=%s\n" % realm_name) - fd.write("domain=%s\n" % domain_name) - fd.write("xmlrpc_uri=https://%s/ipa/xml\n" % format_netloc(host_name)) - fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" % - installutils.realm_to_serverid(realm_name)) - if setup_ca: - fd.write("enable_ra=True\n") - fd.write("ra_plugin=dogtag\n") - fd.write("dogtag_version=%s\n" % - dogtag.install_constants.DOGTAG_VERSION) - else: - fd.write("enable_ra=False\n") - fd.write("ra_plugin=none\n") - fd.write("enable_kra=%s\n" % setup_kra) - fd.write("mode=production\n") - fd.close() - - # Must be readable for everyone - os.chmod(target_fname, 0644) - - if not options.unattended: - print "" - print "The following operations may take some minutes to complete." - print "Please wait until the prompt is returned." - print "" - - if host_name != system_hostname: - root_logger.debug("Chosen hostname (%s) differs from system hostname (%s) - change it" \ - % (host_name, system_hostname)) - # configure /etc/sysconfig/network to contain the custom hostname - tasks.backup_and_replace_hostname(fstore, sstore, host_name) - # update `api.env.ca_host` to correct hostname - # https://fedorahosted.org/freeipa/ticket/4936 - api.env.ca_host = host_name - - api.bootstrap(**cfg) - api.finalize() - - # Create DS user/group if it doesn't exist yet - dsinstance.create_ds_user() - - # Create a directory server instance - if external != 2: - # Configure ntpd - if options.conf_ntp: - ipaclient.ntpconf.force_ntpd(sstore) - ntp = ntpinstance.NTPInstance(fstore) - if not ntp.is_configured(): - ntp.create_instance() - - if options.dirsrv_cert_files: - ds = dsinstance.DsInstance(fstore=fstore, - domainlevel=options.domainlevel) - ds.create_instance(realm_name, host_name, domain_name, - dm_password, dirsrv_pkcs12_info, - idstart=options.idstart, idmax=options.idmax, - subject_base=options.subject, - hbac_allow=not options.hbac_allow) - else: - ds = dsinstance.DsInstance(fstore=fstore, - domainlevel=options.domainlevel) - ds.create_instance(realm_name, host_name, domain_name, - dm_password, - idstart=options.idstart, idmax=options.idmax, - subject_base=options.subject, - hbac_allow=not options.hbac_allow) - else: - ds = dsinstance.DsInstance(fstore=fstore, - domainlevel=options.domainlevel) - ds.init_info( - realm_name, host_name, domain_name, dm_password, - options.subject, 1101, 1100, None) - - - if setup_ca: - ca = cainstance.CAInstance(realm_name, certs.NSS_DIR, - dogtag_constants=dogtag.install_constants) - if external == 0: - ca.configure_instance(host_name, domain_name, dm_password, - dm_password, subject_base=options.subject, - ca_signing_algorithm=options.ca_signing_algorithm) - elif external == 1: - # stage 1 of external CA installation - options.realm_name = realm_name - options.domain_name = domain_name - options.master_password = master_password - options.dm_password = dm_password - options.admin_password = admin_password - options.host_name = host_name - options.unattended = True - options.forwarders = dns_installer.dns_forwarders - options.reverse_zones = reverse_zones - write_cache(vars(options)) - ca.configure_instance(host_name, domain_name, dm_password, - dm_password, csr_file=paths.ROOT_IPA_CSR, - subject_base=options.subject, - ca_signing_algorithm=options.ca_signing_algorithm, - ca_type=options.external_ca_type) - else: - # stage 2 of external CA installation - ca.configure_instance(host_name, domain_name, dm_password, - dm_password, - cert_file=external_cert_file.name, - cert_chain_file=external_ca_file.name, - subject_base=options.subject, - ca_signing_algorithm=options.ca_signing_algorithm) - - # Now put the CA cert where other instances exepct it - ca.publish_ca_cert(CACERT) - else: - # Put the CA cert where other instances expect it - x509.write_certificate(http_ca_cert, CACERT) - os.chmod(CACERT, 0444) - - # we now need to enable ssl on the ds - ds.enable_ssl() - - if setup_ca: - # We need to ldap_enable the CA now that DS is up and running - ca.ldap_enable('CA', host_name, dm_password, - ipautil.realm_to_suffix(realm_name), ['caRenewalMaster']) - - # This is done within stopped_service context, which restarts CA - ca.enable_client_auth_to_db(ca.dogtag_constants.CS_CFG_PATH) - - krb = krbinstance.KrbInstance(fstore) - if options.pkinit_cert_files: - krb.create_instance(realm_name, host_name, domain_name, - dm_password, master_password, - setup_pkinit=options.setup_pkinit, - pkcs12_info=pkinit_pkcs12_info, - subject_base=options.subject) - else: - krb.create_instance(realm_name, host_name, domain_name, - dm_password, master_password, - setup_pkinit=options.setup_pkinit, - subject_base=options.subject) - - # The DS instance is created before the keytab, add the SSL cert we - # generated - ds.add_cert_to_service() - - memcache = memcacheinstance.MemcacheInstance() - memcache.create_instance('MEMCACHE', host_name, dm_password, - ipautil.realm_to_suffix(realm_name)) - - otpd = otpdinstance.OtpdInstance() - otpd.create_instance('OTPD', host_name, dm_password, - ipautil.realm_to_suffix(realm_name)) - - # Create a HTTP instance - http = httpinstance.HTTPInstance(fstore) - if options.http_cert_files: - http.create_instance( - realm_name, host_name, domain_name, dm_password, - pkcs12_info=http_pkcs12_info, subject_base=options.subject, - auto_redirect=options.ui_redirect, - ca_is_configured=setup_ca) - else: - http.create_instance( - realm_name, host_name, domain_name, dm_password, - subject_base=options.subject, auto_redirect=options.ui_redirect, - ca_is_configured=setup_ca) - tasks.restore_context(paths.CACHE_IPA_SESSIONS) - - # Export full CA chain - ca_db = certs.CertDB(realm_name) - os.chmod(CACERT, 0644) - ca_db.publish_ca_cert(CACERT) - - set_subject_in_config(realm_name, dm_password, ipautil.realm_to_suffix(realm_name), options.subject) - - # Apply any LDAP updates. Needs to be done after the configuration file - # is created - service.print_msg("Applying LDAP updates") - ds.apply_updates() - - # Restart ds and krb after configurations have been changed - service.print_msg("Restarting the directory server") - ds.restart() - - service.print_msg("Restarting the KDC") - krb.restart() - - if setup_ca: - service.print_msg("Restarting the certificate server") - ca.restart(dogtag.configured_constants().PKI_INSTANCE_NAME) - - if options.setup_dns: - api.Backend.ldap2.connect(autobind=True) - dns_installer.install(False, False, options) - else: - # Create a BIND instance - bind = bindinstance.BindInstance(fstore, dm_password) - bind.setup(host_name, ip_addresses, realm_name, - domain_name, (), options.conf_ntp, (), - zonemgr=options.zonemgr, ca_configured=setup_ca, - no_dnssec_validation=options.no_dnssec_validation) - bind.create_sample_bind_zone() - - # Restart httpd to pick up the new IPA configuration - service.print_msg("Restarting the web server") - http.restart() - - if setup_kra: - kra.install(None, options, dm_password) - - # Set the admin user kerberos password - ds.change_admin_password(admin_password) - - # Call client install script - try: - args = [paths.IPA_CLIENT_INSTALL, "--on-master", "--unattended", "--domain", domain_name, "--server", host_name, "--realm", realm_name, "--hostname", host_name] - if not options.create_sshfp: - args.append("--no-dns-sshfp") - if options.trust_sshfp: - args.append("--ssh-trust-dns") - if not options.conf_ssh: - args.append("--no-ssh") - if not options.conf_sshd: - args.append("--no-sshd") - if options.mkhomedir: - args.append("--mkhomedir") - run(args) - except Exception, e: - sys.exit("Configuration of client side components failed!\nipa-client-install returned: " + str(e)) - - - #Everything installed properly, activate ipa service. - services.knownservices.ipa.enable() - - print "==============================================================================" - print "Setup complete" - print "" - print "Next steps:" - print "\t1. You must make sure these network ports are open:" - print "\t\tTCP Ports:" - print "\t\t * 80, 443: HTTP/HTTPS" - print "\t\t * 389, 636: LDAP/LDAPS" - print "\t\t * 88, 464: kerberos" - if options.setup_dns: - print "\t\t * 53: bind" - print "\t\tUDP Ports:" - print "\t\t * 88, 464: kerberos" - if options.setup_dns: - print "\t\t * 53: bind" - if options.conf_ntp: - print "\t\t * 123: ntp" - print "" - print "\t2. You can now obtain a kerberos ticket using the command: 'kinit admin'" - print "\t This ticket will allow you to use the IPA tools (e.g., ipa user-add)" - print "\t and the web user interface." - - if not services.knownservices.ntpd.is_running(): - print "\t3. Kerberos requires time synchronization between clients" - print "\t and servers for correct operation. You should consider enabling ntpd." - - print "" - if setup_ca: - print "Be sure to back up the CA certificates stored in " + paths.CACERT_P12 - if setup_kra: - print "and the KRA certificates stored in " + paths.KRACERT_P12 - print "These files are required to create replicas. The password for these" - print "files is the Directory Manager password" + if not options.uninstall: + server.install_check(options) + server.install(options) else: - print "In order for Firefox autoconfiguration to work you will need to" - print "use a SSL signing certificate. See the IPA documentation for more details." + server.uninstall_check(options) + server.uninstall(options) - if ipautil.file_exists(paths.ROOT_IPA_CACHE): - os.remove(paths.ROOT_IPA_CACHE) - return 0 if __name__ == '__main__': - success = False - - try: - # FIXME: Common option parsing, logging setup, etc should be factored - # out from all install scripts - safe_options, options = parse_options() - if options.uninstall: - log_file_name = paths.IPASERVER_UNINSTALL_LOG - else: - log_file_name = paths.IPASERVER_INSTALL_LOG - - # Use private ccache - with private_ccache(): - installutils.run_script(main, log_file_name=log_file_name, - operation_name='ipa-server-install') - success = True + # FIXME: Common option parsing, logging setup, etc should be factored + # out from all install scripts + safe_options, options = parse_options() + if options.uninstall: + log_file_name = paths.IPASERVER_UNINSTALL_LOG + else: + log_file_name = paths.IPASERVER_INSTALL_LOG - finally: - if not success and installation_cleanup: - # Do a cautious clean up as we don't know what failed and what is - # the state of the environment - try: - fstore.restore_file(paths.HOSTS) - except: - pass + installutils.run_script(main, log_file_name=log_file_name, + operation_name='ipa-server-install') diff --git a/ipaserver/install/server/__init__.py b/ipaserver/install/server/__init__.py index 82b551fcb..d4af4f248 100644 --- a/ipaserver/install/server/__init__.py +++ b/ipaserver/install/server/__init__.py @@ -2,4 +2,7 @@ # Copyright (C) 2015 FreeIPA Contributors see COPYING for license # +from .install import install_check, install, uninstall_check, uninstall + +from .install import validate_dm_password, validate_admin_password from .upgrade import upgrade_configuration diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py new file mode 100644 index 000000000..61137d2e9 --- /dev/null +++ b/ipaserver/install/server/install.py @@ -0,0 +1,1209 @@ +# +# Copyright (C) 2015 FreeIPA Contributors see COPYING for license +# + +import os +import pickle +import pwd +import shutil +import sys +import tempfile +import textwrap + +from ipapython import certmonger, dogtag, ipaldap, ipautil, sysrestore +from ipapython.dn import DN +from ipapython.ipa_log_manager import root_logger +from ipapython.ipautil import ( + decrypt_file, format_netloc, ipa_generate_password, run, user_input) +from ipaplatform import services +from ipaplatform.paths import paths +from ipaplatform.tasks import tasks +from ipalib import api, errors, x509 +from ipalib.constants import CACERT +from ipalib.util import validate_domain_name +import ipaclient.ntpconf +from ipaserver.install import ( + bindinstance, cainstance, certs, dns, dsinstance, httpinstance, + installutils, kra, krbinstance, memcacheinstance, ntpinstance, + otpdinstance, replication, service, sysupgrade) +from ipaserver.install.installutils import ( + IPA_MODULES, BadHostError, get_fqdn, get_server_ip_address, + is_ipa_configured, load_external_cert, load_pkcs12, private_ccache, + read_password, verify_fqdn) +from ipaserver.plugins.ldap2 import ldap2 +try: + from ipaserver.install import adtrustinstance + _server_trust_ad_installed = True +except ImportError: + _server_trust_ad_installed = False + +SYSRESTORE_DIR_PATH = paths.SYSRESTORE + +installation_cleanup = True +original_ccache = None + + +def validate_dm_password(password): + if len(password) < 8: + raise ValueError("Password must be at least 8 characters long") + if any(ord(c) < 0x20 for c in password): + raise ValueError("Password must not contain control characters") + if any(ord(c) >= 0x7F for c in password): + raise ValueError("Password must only contain ASCII characters") + + # Disallow characters that pkisilent doesn't process properly: + bad_characters = '\\' + if any(c in bad_characters for c in password): + raise ValueError('Password must not contain these characters: %s' % + ', '.join('"%s"' % c for c in bad_characters)) + + # TODO: Check https://fedorahosted.org/389/ticket/47849 + # Actual behavior of setup-ds.pl is that it does not accept white + # space characters in password when called interactively but does when + # provided such password in INF file. But it ignores leading and trailing + # white spaces in INF file. + + # Disallow leading/trailing whaitespaces + if password.strip() != password: + raise ValueError('Password must not start or end with whitespace.') + + +def validate_admin_password(password): + if len(password) < 8: + raise ValueError("Password must be at least 8 characters long") + if any(ord(c) < 0x20 for c in password): + raise ValueError("Password must not contain control characters") + if any(ord(c) >= 0x7F for c in password): + raise ValueError("Password must only contain ASCII characters") + + # Disallow characters that pkisilent doesn't process properly: + bad_characters = '\\' + if any(c in bad_characters for c in password): + raise ValueError('Password must not contain these characters: %s' % + ', '.join('"%s"' % c for c in bad_characters)) + + +def read_cache(dm_password): + """ + Returns a dict of cached answers or empty dict if no cache file exists. + """ + if not ipautil.file_exists(paths.ROOT_IPA_CACHE): + return {} + + top_dir = tempfile.mkdtemp("ipa") + fname = "%s/cache" % top_dir + try: + decrypt_file(paths.ROOT_IPA_CACHE, fname, dm_password, top_dir) + except Exception, e: + shutil.rmtree(top_dir) + raise Exception("Decryption of answer cache in %s failed, please " + "check your password." % paths.ROOT_IPA_CACHE) + + try: + with open(fname, 'rb') as f: + try: + optdict = pickle.load(f) + except Exception, e: + raise Exception("Parse error in %s: %s" % + (paths.ROOT_IPA_CACHE, str(e))) + except IOError, e: + raise Exception("Read error in %s: %s" % + (paths.ROOT_IPA_CACHE, str(e))) + finally: + shutil.rmtree(top_dir) + + # These are the only ones that may be overridden + try: + del optdict['external_cert_files'] + except KeyError: + pass + + return optdict + + +def write_cache(options): + """ + Takes a dict as input and writes a cached file of answers + """ + top_dir = tempfile.mkdtemp("ipa") + fname = "%s/cache" % top_dir + try: + with open(fname, 'wb') as f: + pickle.dump(options, f) + ipautil.encrypt_file(fname, paths.ROOT_IPA_CACHE, + options['dm_password'], top_dir) + except IOError, e: + raise Exception("Unable to cache command-line options %s" % str(e)) + finally: + shutil.rmtree(top_dir) + + +def read_host_name(host_default, no_host_dns=False): + host_name = "" + + print "Enter the fully qualified domain name of the computer" + print "on which you're setting up server software. Using the form" + print "." + print "Example: master.example.com." + print "" + print "" + if host_default == "": + host_default = "master.example.com" + host_name = user_input("Server host name", host_default, allow_empty=False) + print "" + verify_fqdn(host_name, no_host_dns) + + return host_name + + +def read_domain_name(domain_name, unattended): + print "The domain name has been determined based on the host name." + print "" + if not unattended: + domain_name = str(user_input("Please confirm the domain name", + domain_name)) + print "" + return domain_name + + +def read_realm_name(domain_name, unattended): + print "The kerberos protocol requires a Realm name to be defined." + print "This is typically the domain name converted to uppercase." + print "" + + if unattended: + return domain_name.upper() + realm_name = str(user_input("Please provide a realm name", + domain_name.upper())) + upper_dom = realm_name.upper() + if upper_dom != realm_name: + print "An upper-case realm name is required." + if not user_input("Do you want to use " + upper_dom + + " as realm name?", True): + print "" + print "An upper-case realm name is required. Unable to continue." + sys.exit(1) + else: + realm_name = upper_dom + print "" + return realm_name + + +def read_dm_password(): + print "Certain directory server operations require an administrative user." + print("This user is referred to as the Directory Manager and has full " + "access") + print("to the Directory for system management tasks and will be added to " + "the") + print "instance of directory server created for IPA." + print "The password must be at least 8 characters long." + print "" + # TODO: provide the option of generating a random password + dm_password = read_password("Directory Manager", + validator=validate_dm_password) + return dm_password + + +def read_admin_password(): + print "The IPA server requires an administrative user, named 'admin'." + print("This user is a regular system account used for IPA server " + "administration.") + print "" + # TODO: provide the option of generating a random password + admin_password = read_password("IPA admin", + validator=validate_admin_password) + return admin_password + + +def check_dirsrv(unattended): + (ds_unsecure, ds_secure) = dsinstance.check_ports() + if not ds_unsecure or not ds_secure: + print "IPA requires ports 389 and 636 for the Directory Server." + print "These are currently in use:" + if not ds_unsecure: + print "\t389" + if not ds_secure: + print "\t636" + sys.exit(1) + + +def set_subject_in_config(realm_name, dm_password, suffix, subject_base): + ldapuri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % ( + installutils.realm_to_serverid(realm_name) + ) + try: + conn = ldap2(shared_instance=False, ldap_uri=ldapuri, + base_dn=suffix) + conn.connect(bind_dn=DN(('cn', 'directory manager')), + bind_pw=dm_password) + except errors.ExecutionError, e: + root_logger.critical("Could not connect to the Directory Server " + "on %s" % realm_name) + raise e + entry_attrs = conn.get_ipa_config() + if 'ipacertificatesubjectbase' not in entry_attrs: + entry_attrs['ipacertificatesubjectbase'] = [str(subject_base)] + conn.update_entry(entry_attrs) + conn.disconnect() + + +def init_private_ccache(): + (desc, path) = tempfile.mkstemp(prefix='krbcc') + os.close(desc) + + original_ccache = os.environ.get('KRB5CCNAME', None) + + os.environ['KRB5CCNAME'] = path + + +def destroy_private_ccache(): + path = os.environ.get('KRB5CCNAME') + + if original_ccache is not None: + os.environ['KRB5CCNAME'] = original_ccache + else: + os.environ.pop('KRB5CCNAME', None) + + if os.path.exists(path): + os.remove(path) + + +def common_cleanup(func): + def decorated(*args, **kwargs): + success = False + + try: + try: + func(*args, **kwargs) + except BaseException: + destroy_private_ccache() + raise + success = True + except KeyboardInterrupt: + global ds + print "\nCleaning up..." + if ds: + print "Removing configuration for %s instance" % ds.serverid + ds.stop() + if ds.serverid: + try: + dsinstance.remove_ds_instance(ds.serverid) + except ipautil.CalledProcessError: + root_logger.error("Failed to remove DS instance. You " + "may need to remove instance data " + "manually") + sys.exit(1) + finally: + global installation_cleanup + if not success and installation_cleanup: + # Do a cautious clean up as we don't know what failed and + # what is the state of the environment + try: + fstore.restore_file(paths.HOSTS) + except: + pass + + return decorated + + +@common_cleanup +def install_check(options): + global dirsrv_pkcs12_info + global http_pkcs12_info + global pkinit_pkcs12_info + global external_cert_file + global external_ca_file + global http_ca_cert + + global ds + global installation_cleanup + + # Use private ccache + init_private_ccache() + + ds = None + + tasks.check_selinux_status() + + if options.master_password: + msg = ("WARNING:\noption '-P/--master-password' is deprecated. " + "KDC master password of sufficient strength is autogenerated " + "during IPA server installation and should not be set " + "manually.") + print textwrap.fill(msg, width=79, replace_whitespace=False) + + installation_cleanup = True + + print("\nThe log file for this installation can be found in " + "/var/log/ipaserver-install.log") + if (not options.external_ca and not options.external_cert_files and + is_ipa_configured()): + installation_cleanup = False + sys.exit("IPA server is already configured on this system.\n" + "If you want to reinstall the IPA server, please uninstall " + "it first using 'ipa-server-install --uninstall'.") + + client_fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE) + if client_fstore.has_files(): + installation_cleanup = False + sys.exit("IPA client is already configured on this system.\n" + "Please uninstall it before configuring the IPA server, " + "using 'ipa-client-install --uninstall'") + + global fstore + fstore = sysrestore.FileStore(SYSRESTORE_DIR_PATH) + global sstore + sstore = sysrestore.StateFile(SYSRESTORE_DIR_PATH) + + if options.external_ca: + if cainstance.is_step_one_done(): + print("CA is already installed.\nRun the installer with " + "--external-cert-file.") + sys.exit(1) + if ipautil.file_exists(paths.ROOT_IPA_CSR): + print("CA CSR file %s already exists.\nIn order to continue " + "remove the file and run the installer again." % + paths.ROOT_IPA_CSR) + sys.exit(1) + elif options.external_cert_files: + if not cainstance.is_step_one_done(): + # This can happen if someone passes external_ca_file without + # already having done the first stage of the CA install. + print("CA is not installed yet. To install with an external CA " + "is a two-stage process.\nFirst run the installer with " + "--external-ca.") + sys.exit(1) + + # This will override any settings passed in on the cmdline + if ipautil.file_exists(paths.ROOT_IPA_CACHE): + if options.dm_password is not None: + dm_password = options.dm_password + else: + dm_password = read_password("Directory Manager", confirm=False) + if dm_password is None: + sys.exit("Directory Manager password required") + try: + options._update_loose(read_cache(dm_password)) + except Exception, e: + sys.exit("Cannot process the cache file: %s" % str(e)) + + if options.external_cert_files: + external_cert_file, external_ca_file = load_external_cert( + options.external_cert_files, options.subject) + + # We only set up the CA if the PKCS#12 options are not given. + if options.dirsrv_cert_files: + setup_ca = False + setup_kra = False + else: + setup_ca = True + # setup_kra is set to False until Dogtag 10.2 is available for IPA to + # consume. Until then users that want to install the KRA need to use + # ipa-install-kra + # TODO set setup_kra = True when Dogtag 10.2 is available + setup_kra = False + options.setup_ca = setup_ca + options.setup_kra = setup_kra + + print("=======================================" + "=======================================") + print "This program will set up the FreeIPA Server." + print "" + print "This includes:" + if setup_ca: + print(" * Configure a stand-alone CA (dogtag) for certificate " + "management") + if setup_kra: + print " * Configure a stand-alone KRA (dogtag) for key storage" + if options.conf_ntp: + print " * Configure the Network Time Daemon (ntpd)" + print " * Create and configure an instance of Directory Server" + print " * Create and configure a Kerberos Key Distribution Center (KDC)" + print " * Configure Apache (httpd)" + if options.setup_dns: + print " * Configure DNS (bind)" + if options.setup_pkinit: + print " * Configure the KDC to enable PKINIT" + if not options.conf_ntp: + print "" + print "Excluded by options:" + print " * Configure the Network Time Daemon (ntpd)" + if not options.unattended: + print "" + print "To accept the default shown in brackets, press the Enter key." + print "" + + if not options.external_cert_files: + # Make sure the 389-ds ports are available + check_dirsrv(options.unattended) + + if setup_ca: + if not cainstance.check_port(): + print("IPA requires port 8443 for PKI but it is currently in " + "use.") + sys.exit("Aborting installation") + + if options.conf_ntp: + try: + ipaclient.ntpconf.check_timedate_services() + except ipaclient.ntpconf.NTPConflictingService, e: + print("WARNING: conflicting time&date synchronization service '%s'" + " will be disabled" % e.conflicting_service) + print "in favor of ntpd" + print "" + except ipaclient.ntpconf.NTPConfigurationError: + pass + + # Check to see if httpd is already configured to listen on 443 + if httpinstance.httpd_443_configured(): + sys.exit("Aborting installation") + + if not options.setup_dns and not options.unattended: + if ipautil.user_input("Do you want to configure integrated DNS " + "(BIND)?", False): + options.setup_dns = True + print "" + + # check bind packages are installed + if options.setup_dns: + # Don't require an external DNS to say who we are if we are + # setting up a local DNS server. + options.no_host_dns = True + + # check the hostname is correctly configured, it must be as the kldap + # utilities just use the hostname as returned by getaddrinfo to set + # up some of the standard entries + + host_default = "" + if options.host_name: + host_default = options.host_name + else: + host_default = get_fqdn() + + try: + if options.unattended or options.host_name: + verify_fqdn(host_default, options.no_host_dns) + host_name = host_default + else: + host_name = read_host_name(host_default, options.no_host_dns) + except BadHostError, e: + sys.exit(str(e) + "\n") + + host_name = host_name.lower() + root_logger.debug("will use host_name: %s\n" % host_name) + + system_hostname = get_fqdn() + if host_name != system_hostname: + print >>sys.stderr + print >>sys.stderr, ("Warning: hostname %s does not match system " + "hostname %s." % (host_name, system_hostname)) + print >>sys.stderr, ("System hostname will be updated during the " + "installation process") + print >>sys.stderr, "to prevent service failures." + print >>sys.stderr + + if not options.domain_name: + domain_name = read_domain_name(host_name[host_name.find(".")+1:], + options.unattended) + root_logger.debug("read domain_name: %s\n" % domain_name) + try: + validate_domain_name(domain_name) + except ValueError, e: + sys.exit("Invalid domain name: %s" % unicode(e)) + else: + domain_name = options.domain_name + + domain_name = domain_name.lower() + + if not options.realm_name: + realm_name = read_realm_name(domain_name, options.unattended) + root_logger.debug("read realm_name: %s\n" % realm_name) + else: + realm_name = options.realm_name.upper() + + if not options.subject: + options.subject = DN(('O', realm_name)) + + if options.http_cert_files: + if options.http_pin is None: + options.http_pin = installutils.read_password( + "Enter Apache Server private key unlock", + confirm=False, validate=False) + if options.http_pin is None: + sys.exit( + "Apache Server private key unlock password required") + http_pkcs12_file, http_pin, http_ca_cert = load_pkcs12( + cert_files=options.http_cert_files, + key_password=options.http_pin, + key_nickname=options.http_cert_name, + ca_cert_files=options.ca_cert_files, + host_name=host_name) + http_pkcs12_info = (http_pkcs12_file.name, http_pin) + + if options.dirsrv_cert_files: + if options.dirsrv_pin is None: + options.dirsrv_pin = read_password( + "Enter Directory Server private key unlock", + confirm=False, validate=False) + if options.dirsrv_pin is None: + sys.exit( + "Directory Server private key unlock password required") + dirsrv_pkcs12_file, dirsrv_pin, dirsrv_ca_cert = load_pkcs12( + cert_files=options.dirsrv_cert_files, + key_password=options.dirsrv_pin, + key_nickname=options.dirsrv_cert_name, + ca_cert_files=options.ca_cert_files, + host_name=host_name) + dirsrv_pkcs12_info = (dirsrv_pkcs12_file.name, dirsrv_pin) + + if options.pkinit_cert_files: + if options.pkinit_pin is None: + options.pkinit_pin = read_password( + "Enter Kerberos KDC private key unlock", + confirm=False, validate=False) + if options.pkinit_pin is None: + sys.exit( + "Kerberos KDC private key unlock password required") + pkinit_pkcs12_file, pkinit_pin, pkinit_ca_cert = load_pkcs12( + cert_files=options.pkinit_cert_files, + key_password=options.pkinit_pin, + key_nickname=options.pkinit_cert_name, + ca_cert_files=options.ca_cert_files, + host_name=host_name) + pkinit_pkcs12_info = (pkinit_pkcs12_file.name, pkinit_pin) + + if (options.http_cert_files and options.dirsrv_cert_files and + http_ca_cert != dirsrv_ca_cert): + sys.exit("Apache Server SSL certificate and Directory Server SSL " + "certificate are not signed by the same CA certificate") + + if not options.dm_password: + dm_password = read_dm_password() + + if dm_password is None: + sys.exit("Directory Manager password required") + else: + dm_password = options.dm_password + + if not options.master_password: + master_password = ipa_generate_password() + else: + master_password = options.master_password + + if not options.admin_password: + admin_password = read_admin_password() + if admin_password is None: + sys.exit("IPA admin password required") + else: + admin_password = options.admin_password + + if setup_kra: + try: + kra.install_check(None, options, False, + dogtag.install_constants.DOGTAG_VERSION) + except RuntimeError as e: + print str(e) + sys.exit(1) + + if options.setup_dns: + dns.install_check(False, False, options, host_name) + ip_addresses = dns.ip_addresses + else: + ip_addresses = get_server_ip_address(host_name, fstore, + options.unattended, False, + options.ip_addresses) + + print + print "The IPA Master Server will be configured with:" + print "Hostname: %s" % host_name + print "IP address(es): %s" % ", ".join(str(ip) for ip in ip_addresses) + print "Domain name: %s" % domain_name + print "Realm name: %s" % realm_name + print + + if options.setup_dns: + print "BIND DNS server will be configured to serve IPA domain with:" + print "Forwarders: %s" % ( + "No forwarders" if not dns.dns_forwarders + else ", ".join([str(ip) for ip in dns.dns_forwarders]) + ) + print "Reverse zone(s): %s" % ( + "No reverse zone" if options.no_reverse or not dns.reverse_zones + else ", ".join(str(rz) for rz in dns.reverse_zones) + ) + print + + # If domain name and realm does not match, IPA server will not be able + # to estabilish trust with Active Directory. Print big fat warning. + + realm_not_matching_domain = (domain_name.upper() != realm_name) + + if realm_not_matching_domain: + print("WARNING: Realm name does not match the domain name.\n" + "You will not be able to estabilish trusts with Active " + "Directory unless\nthe realm name of the IPA server matches " + "its domain name.\n\n") + + if not options.unattended and not user_input( + "Continue to configure the system with these values?", False): + sys.exit("Installation aborted") + + options.realm_name = realm_name + options.domain_name = domain_name + options.dm_password = dm_password + options.master_password = master_password + options.admin_password = admin_password + options.host_name = host_name + options.ip_address = ip_addresses + + +@common_cleanup +def install(options): + global dirsrv_pkcs12_info + global http_pkcs12_info + global pkinit_pkcs12_info + global external_cert_file + global external_ca_file + global http_ca_cert + + realm_name = options.realm_name + domain_name = options.domain_name + dm_password = options.dm_password + master_password = options.master_password + admin_password = options.admin_password + host_name = options.host_name + ip_addresses = options.ip_address + setup_ca = options.setup_ca + setup_kra = options.setup_kra + + global ds + global installation_cleanup + + # Installation has started. No IPA sysrestore items are restored in case of + # failure to enable root cause investigation + installation_cleanup = False + + # Configuration for ipalib, we will bootstrap and finalize later, after + # we are sure we have the configuration file ready. + cfg = dict( + context='installer', + in_server=True, + debug=options.debug + ) + + # Figure out what external CA step we're in. See cainstance.py for more + # info on the 3 states. + if options.external_cert_files: + external = 2 + elif options.external_ca: + external = 1 + else: + external = 0 + + # Create the management framework config file and finalize api + target_fname = paths.IPA_DEFAULT_CONF + fd = open(target_fname, "w") + fd.write("[global]\n") + fd.write("host=%s\n" % host_name) + fd.write("basedn=%s\n" % ipautil.realm_to_suffix(realm_name)) + fd.write("realm=%s\n" % realm_name) + fd.write("domain=%s\n" % domain_name) + fd.write("xmlrpc_uri=https://%s/ipa/xml\n" % format_netloc(host_name)) + fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" % + installutils.realm_to_serverid(realm_name)) + if setup_ca: + fd.write("enable_ra=True\n") + fd.write("ra_plugin=dogtag\n") + fd.write("dogtag_version=%s\n" % + dogtag.install_constants.DOGTAG_VERSION) + else: + fd.write("enable_ra=False\n") + fd.write("ra_plugin=none\n") + fd.write("enable_kra=%s\n" % setup_kra) + fd.write("mode=production\n") + fd.close() + + # Must be readable for everyone + os.chmod(target_fname, 0644) + + if not options.unattended: + print "" + print "The following operations may take some minutes to complete." + print "Please wait until the prompt is returned." + print "" + + system_hostname = get_fqdn() + if host_name != system_hostname: + root_logger.debug("Chosen hostname (%s) differs from system hostname " + "(%s) - change it" % (host_name, system_hostname)) + # configure /etc/sysconfig/network to contain the custom hostname + tasks.backup_and_replace_hostname(fstore, sstore, host_name) + # update `api.env.ca_host` to correct hostname + # https://fedorahosted.org/freeipa/ticket/4936 + api.env.ca_host = host_name + + api.bootstrap(**cfg) + api.finalize() + + # Create DS user/group if it doesn't exist yet + dsinstance.create_ds_user() + + # Create a directory server instance + if external != 2: + # Configure ntpd + if options.conf_ntp: + ipaclient.ntpconf.force_ntpd(sstore) + ntp = ntpinstance.NTPInstance(fstore) + if not ntp.is_configured(): + ntp.create_instance() + + if options.dirsrv_cert_files: + ds = dsinstance.DsInstance(fstore=fstore, + domainlevel=options.domainlevel) + ds.create_instance(realm_name, host_name, domain_name, + dm_password, dirsrv_pkcs12_info, + idstart=options.idstart, idmax=options.idmax, + subject_base=options.subject, + hbac_allow=not options.hbac_allow) + else: + ds = dsinstance.DsInstance(fstore=fstore, + domainlevel=options.domainlevel) + ds.create_instance(realm_name, host_name, domain_name, + dm_password, + idstart=options.idstart, idmax=options.idmax, + subject_base=options.subject, + hbac_allow=not options.hbac_allow) + else: + ds = dsinstance.DsInstance(fstore=fstore, + domainlevel=options.domainlevel) + ds.init_info( + realm_name, host_name, domain_name, dm_password, + options.subject, 1101, 1100, None) + + if setup_ca: + ca = cainstance.CAInstance(realm_name, certs.NSS_DIR, + dogtag_constants=dogtag.install_constants) + if external == 0: + ca.configure_instance( + host_name, domain_name, dm_password, dm_password, + subject_base=options.subject, + ca_signing_algorithm=options.ca_signing_algorithm) + elif external == 1: + # stage 1 of external CA installation + options.realm_name = realm_name + options.domain_name = domain_name + options.master_password = master_password + options.dm_password = dm_password + options.admin_password = admin_password + options.host_name = host_name + options.unattended = True + options.forwarders = dns.dns_forwarders + options.reverse_zones = dns.reverse_zones + write_cache(vars(options)) + ca.configure_instance( + host_name, domain_name, dm_password, dm_password, + csr_file=paths.ROOT_IPA_CSR, + subject_base=options.subject, + ca_signing_algorithm=options.ca_signing_algorithm, + ca_type=options.external_ca_type) + else: + # stage 2 of external CA installation + ca.configure_instance( + host_name, domain_name, dm_password, dm_password, + cert_file=external_cert_file.name, + cert_chain_file=external_ca_file.name, + subject_base=options.subject, + ca_signing_algorithm=options.ca_signing_algorithm) + + # Now put the CA cert where other instances exepct it + ca.publish_ca_cert(CACERT) + else: + # Put the CA cert where other instances expect it + x509.write_certificate(http_ca_cert, CACERT) + os.chmod(CACERT, 0444) + + # we now need to enable ssl on the ds + ds.enable_ssl() + + if setup_ca: + # We need to ldap_enable the CA now that DS is up and running + ca.ldap_enable('CA', host_name, dm_password, + ipautil.realm_to_suffix(realm_name), + ['caRenewalMaster']) + + # This is done within stopped_service context, which restarts CA + ca.enable_client_auth_to_db(ca.dogtag_constants.CS_CFG_PATH) + + krb = krbinstance.KrbInstance(fstore) + if options.pkinit_cert_files: + krb.create_instance(realm_name, host_name, domain_name, + dm_password, master_password, + setup_pkinit=options.setup_pkinit, + pkcs12_info=pkinit_pkcs12_info, + subject_base=options.subject) + else: + krb.create_instance(realm_name, host_name, domain_name, + dm_password, master_password, + setup_pkinit=options.setup_pkinit, + subject_base=options.subject) + + # The DS instance is created before the keytab, add the SSL cert we + # generated + ds.add_cert_to_service() + + memcache = memcacheinstance.MemcacheInstance() + memcache.create_instance('MEMCACHE', host_name, dm_password, + ipautil.realm_to_suffix(realm_name)) + + otpd = otpdinstance.OtpdInstance() + otpd.create_instance('OTPD', host_name, dm_password, + ipautil.realm_to_suffix(realm_name)) + + # Create a HTTP instance + http = httpinstance.HTTPInstance(fstore) + if options.http_cert_files: + http.create_instance( + realm_name, host_name, domain_name, dm_password, + pkcs12_info=http_pkcs12_info, subject_base=options.subject, + auto_redirect=options.ui_redirect, + ca_is_configured=setup_ca) + else: + http.create_instance( + realm_name, host_name, domain_name, dm_password, + subject_base=options.subject, auto_redirect=options.ui_redirect, + ca_is_configured=setup_ca) + tasks.restore_context(paths.CACHE_IPA_SESSIONS) + + # Export full CA chain + ca_db = certs.CertDB(realm_name) + os.chmod(CACERT, 0644) + ca_db.publish_ca_cert(CACERT) + + set_subject_in_config(realm_name, dm_password, + ipautil.realm_to_suffix(realm_name), options.subject) + + # Apply any LDAP updates. Needs to be done after the configuration file + # is created + service.print_msg("Applying LDAP updates") + ds.apply_updates() + + # Restart ds and krb after configurations have been changed + service.print_msg("Restarting the directory server") + ds.restart() + + service.print_msg("Restarting the KDC") + krb.restart() + + if setup_ca: + service.print_msg("Restarting the certificate server") + ca.restart(dogtag.configured_constants().PKI_INSTANCE_NAME) + + if options.setup_dns: + api.Backend.ldap2.connect(autobind=True) + dns.install(False, False, options) + else: + # Create a BIND instance + bind = bindinstance.BindInstance(fstore, dm_password) + bind.setup(host_name, ip_addresses, realm_name, + domain_name, (), options.conf_ntp, (), + zonemgr=options.zonemgr, ca_configured=setup_ca, + no_dnssec_validation=options.no_dnssec_validation) + bind.create_sample_bind_zone() + + # Restart httpd to pick up the new IPA configuration + service.print_msg("Restarting the web server") + http.restart() + + if setup_kra: + kra.install(None, options, dm_password) + + # Set the admin user kerberos password + ds.change_admin_password(admin_password) + + # Call client install script + try: + args = [paths.IPA_CLIENT_INSTALL, "--on-master", "--unattended", + "--domain", domain_name, "--server", host_name, + "--realm", realm_name, "--hostname", host_name] + if not options.create_sshfp: + args.append("--no-dns-sshfp") + if options.trust_sshfp: + args.append("--ssh-trust-dns") + if not options.conf_ssh: + args.append("--no-ssh") + if not options.conf_sshd: + args.append("--no-sshd") + if options.mkhomedir: + args.append("--mkhomedir") + run(args) + except Exception, e: + sys.exit("Configuration of client side components failed!\n" + "ipa-client-install returned: " + str(e)) + + # Everything installed properly, activate ipa service. + services.knownservices.ipa.enable() + + print("=======================================" + "=======================================") + print "Setup complete" + print "" + print "Next steps:" + print "\t1. You must make sure these network ports are open:" + print "\t\tTCP Ports:" + print "\t\t * 80, 443: HTTP/HTTPS" + print "\t\t * 389, 636: LDAP/LDAPS" + print "\t\t * 88, 464: kerberos" + if options.setup_dns: + print "\t\t * 53: bind" + print "\t\tUDP Ports:" + print "\t\t * 88, 464: kerberos" + if options.setup_dns: + print "\t\t * 53: bind" + if options.conf_ntp: + print "\t\t * 123: ntp" + print "" + print("\t2. You can now obtain a kerberos ticket using the command: " + "'kinit admin'") + print("\t This ticket will allow you to use the IPA tools (e.g., ipa " + "user-add)") + print "\t and the web user interface." + + if not services.knownservices.ntpd.is_running(): + print "\t3. Kerberos requires time synchronization between clients" + print("\t and servers for correct operation. You should consider " + "enabling ntpd.") + + print "" + if setup_ca: + print("Be sure to back up the CA certificates stored in " + + paths.CACERT_P12) + if setup_kra: + print "and the KRA certificates stored in " + paths.KRACERT_P12 + print("These files are required to create replicas. The password for " + "these") + print "files is the Directory Manager password" + else: + print "In order for Firefox autoconfiguration to work you will need to" + print("use a SSL signing certificate. See the IPA documentation for " + "more details.") + + if ipautil.file_exists(paths.ROOT_IPA_CACHE): + os.remove(paths.ROOT_IPA_CACHE) + + # Use private ccache + destroy_private_ccache() + + +@common_cleanup +def uninstall_check(options): + global ds + global installation_cleanup + + # Use private ccache + init_private_ccache() + + ds = None + + tasks.check_selinux_status() + + if options.master_password: + msg = ("WARNING:\noption '-P/--master-password' is deprecated. " + "KDC master password of sufficient strength is autogenerated " + "during IPA server installation and should not be set " + "manually.") + print textwrap.fill(msg, width=79, replace_whitespace=False) + + installation_cleanup = False + + global fstore + fstore = sysrestore.FileStore(SYSRESTORE_DIR_PATH) + global sstore + sstore = sysrestore.StateFile(SYSRESTORE_DIR_PATH) + + # Configuration for ipalib, we will bootstrap and finalize later, after + # we are sure we have the configuration file ready. + cfg = dict( + context='installer', + in_server=True, + debug=options.debug + ) + + # We will need at least api.env, finalize api now. This system is + # already installed, so the configuration file is there. + api.bootstrap(**cfg) + api.finalize() + + if not options.unattended: + print("\nThis is a NON REVERSIBLE operation and will delete all data " + "and configuration!\n") + if not user_input("Are you sure you want to continue with the " + "uninstall procedure?", False): + print "" + print "Aborting uninstall operation." + sys.exit(1) + + try: + conn = ipaldap.IPAdmin( + api.env.host, + ldapi=True, + realm=api.env.realm + ) + conn.do_external_bind(pwd.getpwuid(os.geteuid()).pw_name) + except Exception: + msg = ("\nWARNING: Failed to connect to Directory Server to find " + "information about replication agreements. Uninstallation " + "will continue despite the possible existing replication " + "agreements.\n\n") + print textwrap.fill(msg, width=80, replace_whitespace=False) + else: + api.Backend.ldap2.connect(autobind=True) + dns.uninstall_check(options) + + rm = replication.ReplicationManager( + realm=api.env.realm, + hostname=api.env.host, + dirman_passwd=None, + conn=conn + ) + agreements = rm.find_ipa_replication_agreements() + + if agreements: + other_masters = [a.get('cn')[0][4:] for a in agreements] + msg = ( + "\nReplication agreements with the following IPA masters " + "found: %s. Removing any replication agreements before " + "uninstalling the server is strongly recommended. You can " + "remove replication agreements by running the following " + "command on any other IPA master:\n" % ", ".join( + other_masters) + ) + cmd = "$ ipa-replica-manage del %s\n" % api.env.host + print textwrap.fill(msg, width=80, replace_whitespace=False) + print cmd + if not (options.unattended or user_input("Are you sure you " + "want to continue " + "with the uninstall " + "procedure?", + False)): + print "" + print "Aborting uninstall operation." + sys.exit(1) + + +@common_cleanup +def uninstall(options): + rv = 0 + + print "Shutting down all IPA services" + try: + (stdout, stderr, rc) = run([paths.IPACTL, "stop"], raiseonerr=False) + except Exception, e: + pass + + # Need to get dogtag info before /etc/ipa/default.conf is removed + dogtag_constants = dogtag.configured_constants() + + print "Removing IPA client configuration" + try: + (stdout, stderr, rc) = run([paths.IPA_CLIENT_INSTALL, "--on-master", + "--unattended", "--uninstall"], + raiseonerr=False) + if rc not in [0, 2]: + root_logger.debug("ipa-client-install returned %d" % rc) + raise RuntimeError(stdout) + except Exception, e: + rv = 1 + print "Uninstall of client side components failed!" + print "ipa-client-install returned: " + str(e) + + ntpinstance.NTPInstance(fstore).uninstall() + if not dogtag_constants.SHARED_DB: + cads_instance = cainstance.CADSInstance( + dogtag_constants=dogtag_constants) + if cads_instance.is_configured(): + cads_instance.uninstall() + + kra.uninstall() + + ca_instance = cainstance.CAInstance( + api.env.realm, certs.NSS_DIR, dogtag_constants=dogtag_constants) + ca_instance.stop_tracking_certificates() + if ca_instance.is_configured(): + ca_instance.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() + memcacheinstance.MemcacheInstance().uninstall() + otpdinstance.OtpdInstance().uninstall() + tasks.restore_network_configuration(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.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() + + ipautil.restore_hostname(sstore) + + # 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, dogtag_constants.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 \n' + 'for each id in: %s' % ', '.join(ids)) + + # Use private ccache + destroy_private_ccache() + + sys.exit(rv) -- cgit